首页 文章 精选 留言 我的

精选列表

搜索[openapi],共1445篇文章
优秀的个人博客,低调大师

用 WorkBuddy 打通金蝶云·星空旗舰版 OpenAPI:采购订单从建单到审核全流程实录

一、背景与目标 目标很明确:用 API 创建一张采购订单,并让它到达**已审核(C)**状态。 听起来简单,实际踩了整整一天。核心难点不在于"调接口",而在于: 1. 大量字段是**隐藏必填**,报错一个、补一个、再冒出下一个; 2. 部分字段**key 名与直觉完全不符**,写错了接口还返回成功,只是值不落库(静默失败); 3. 同一个语义的字段(如"货主")在不同实体类型下有**不同的枚举值**,用错类型同样静默失败。 二、环境准备 2.1 认证:OAuth2 取 token 苍穹网关的认证头字段名是 **`accessToken`**(驼峰、无下划线)。写成 `access_token` 或 `Authorization: Bearer` 一律返回 401。 ```python import httpx, uuid, datetime BASE_URL = "https:///kapi" payload = {     "client_id": "",     "client_secret": "",     "username": "",     "accountId": "",     "language": "zh_CN",     "nonce": str(uuid.uuid4()),     "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } headers = {"Content-Type": "application/json",            "x-acgw-identity": ""}   # 私有云需要 r = httpx.post(f"{BASE_URL}/oauth2/getToken", json=payload, headers=headers, timeout=30) token = r.json()["data"]["access_token"] ``` 后续所有请求都带这个头: ```python H = {"Content-Type": "application/json", "accessToken": token,      "x-acgw-identity": ""} ``` 2.2 返回码陷阱 **成功与否要看 `errorCode`(字符串 `"0"` 表示成功),不是 HTTP 状态码。** 而且完整错误信息藏在 `data.result[].errors[].rowMsg[]` 里,顶层的 `message` 会被截断成「……等 N 处错误」。排查时一定要打印完整响应体。 2.3 接口路径约定 ``` /v2/{appId}/{formId}/{操作} ``` 采购订单:`/v2/pm/pm_purorderbill/{add|query|getList|batchSubmit|batchAudit}` - 写操作是 **`add`**,不是 `save` / `create` / `submit`(这些全是 404) - 请求体格式:`{"data": [ {...} ]}`,`data` 必须是**数组** - 查询类接口必须带 `pageNo` / `pageSize`,否则返回 0 条 三、五个致命坑(本文最有价值的部分) 坑 1:含税单价的 key 是 `priceandtax`,不是 `taxprice` 最初按直觉写了 `"taxprice": 10`,接口返回 `ec=0`(成功!),但打开单据一看:**含税单价和税率都是空的**。 读回对比手工单才发现问题——所有金额字段全是 0: json { "price": 0.0, "priceandtax": 0.0, "taxrate": 0.0, "taxrateid_number": "" } **正确写法:** ```python "priceandtax": 10,           # 含税单价(不是 taxprice!) "taxrate": 6,                # 税率数值 "taxrateid_number": "V6",    # 税率档编码,必须显式传 ``` > **教训**:API 接受了无效 key 却不报错、也不赋值。这类"静默失败"必须靠**读回校验**才能发现,不能只看返回码。 坑 2:货主的 `ownertype` 是 `bos_org`,不是 `bd_supplier` 这是卡得最久的一个。提交时一直报: ``` 请填写"物料明细"第1行:"货主"。 ``` 直觉认为"采购订单的货主"应该是供应商,于是试了 `bd_supplier`、`bd_customer`、`bd_organization`、`bos_adminorg`——**全部失败**,而且都是 add 成功但 submit 报错。 **破局方法**:去读一张**手工在 GUI 建好并已审核**的单据,看它实际存了什么: ```python # query 接口能返回 ownertype(虽然不返回货主本体) r = call("/v2/pm/pm_purorderbill/query", {"data": {"billno": "CGDD-xxxx"}}) # 明细里:ownertype = 'bos_org' ``` **正确写法:** ```python "owner_number": "hmr",       # 货主 = 组织编码(好牧人) "ownertype": "bos_org",      # ★ 业务组织,不是 bd_supplier! ``` > **教训**:当一个字段怎么填都不对时,别再猜了——**找一张系统里已经成功的单据读回来对照**。这比任何文档都准。 坑 3:第三方业务编码 `trdbillno` 有唯一性约束 这个字段是租户自定义的 UDF,属于**只写字段**——`query` / `getList` / `getDetail` 都不返回它,所以无法从读回中推断 key(我盲猜了 32 个候选 key 全军覆没,最后是靠指定 key 名解决的)。 更坑的是它有**唯一性约束**,重复值直接报错: ``` 第三方单据业务编码重复:000121cs ``` **所以每次建单都要换一个值**: ```python suffix = str(int(time.time()) % 1000000) rec["trdbillno"] = f"{suffix}cs" rec["billno"]    = f"POF{suffix}" ``` ### 坑 4:物料必须用 GUI 手工创建的 API 创建的物料缺少"组织分配",在下游单据里引用会失败。必须使用**在金蝶界面手工保存过**的物料编码(手工保存会自动完成组织分配)。 ```python "material_number": "Item-00000001"   # 手工在 GUI 建的物料 ``` 坑 5:提交/审核用复数 `ids`,基础资料审核用单数 `id` ```python 单据(采购订单)提交/审核 —— 复数 ids,值为数组 {"data": {"ids": ["2563846890302997504"]}} 基础资料(供应商/客户/物料)审核 —— 单数 id,值为字符串 {"data": {"id": "2563180392454555648"}} ``` 写反了会报「参数【ids】必填」。 --- 四、最终可用代码 把上面所有坑都规避掉之后,完整脚本: ```python # -*- coding: utf-8 -*- """金蝶云·星空旗舰版 采购订单 建单→提交→审核 全链路""" import time, datetime, httpx def get_token(): ...  # 见 2.1 def call_full(path, body):     """返回完整响应(含 errorCode),用于判断写操作成败"""     H = {"Content-Type": "application/json", "accessToken": get_token(),          "x-acgw-identity": ""}     return httpx.post(f"{BASE_URL}{path}", json=body, headers=H, timeout=60).json() suffix = str(int(time.time()) % 1000000) rec = {     "billno": f"POF{suffix}",     "supplier_number": "01234",          # 供应商     "org_number": "hmr",                 # 组织     "biztime": "2026-09-07 00:00:00",     "currency_number": "CNY",     "settlecurrency_number": "CNY",     "creator_number": "administrator",     "modifier_number": "administrator",     "exchangerate": 1,     "paymode": "CASH",     "billtype_number": "pm_PurOrderBill_STD_BT_S",   # 标准采购订单     "biztype_number": "110",                          # 物料类采购     "exratetable_number": "ERT-01",                   # 固定汇率     "trdbillno": f"{suffix}cs",                       # ★ 唯一值     "billentry": [{                                   # ★ 明细数组 key 是这个         "material_number": "Item-00000001",           # ★ GUI 手工建的物料         "qty": 10,         "priceandtax": 10,                            # ★ 不是 taxprice         "taxrate": 6,         "taxrateid_number": "V6",                     # ★ 税率档         "entryrecorg_number": "hmr",         "entrysettleorg_number": "hmr",         "entryreqorg_number": "hmr",         "owner_number": "hmr",                        # ★ 货主=组织         "ownertype": "bos_org",                       # ★ 不是 bd_supplier         "unit_number": "jin",         "deliverdate": "2026-09-10 00:00:00",         "discounttype": "A",         "linetype_number": "010",                     # 物资     }], } 1) 建单 r = call_full("/v2/pm/pm_purorderbill/add", {"data": [rec]}) assert str(r.get("errorCode")) == "0", r rid = r["data"]["result"][0]["id"] 2) 提交(复数 ids) r2 = call_full("/v2/pm/pm_purorderbill/batchSubmit", {"data": {"ids": [rid]}}) assert str(r2.get("errorCode")) == "0", r2 3) 审核(复数 ids) r3 = call_full("/v2/pm/pm_purorderbill/batchAudit", {"data": {"ids": [rid]}}) assert str(r3.get("errorCode")) == "0", r3 print(f"✅ 采购订单 {rec['billno']} 已审核(C)") ``` **运行结果:** ``` add  ec=0  →  submit ec=0  →  audit ec=0 ✅ 采购订单 POF834365 已审核(C) 成功 ``` 系统自动完成价税计算:含税单价 10 → 不含税单价 9.434、金额 94.34、税额 5.66、价税合计 100.00。 五、固化成 MCP 工具,让能力可复用 调通之后,我把这套逻辑封装成了 MCP 工具 `flagship_add_po`,以后一句话就能建单。 > **注意**:MCP 服务端原有的 `_call` 封装只返回 `data` 内层,会**丢掉顶层的 `errorCode`**,导致无法判断写操作成败。必须新增一个返回完整响应的底层调用: ```python def _call_full(path: str, body: dict) -> dict:     """返回完整响应(含 errorCode),用于判断写操作成败"""     token = _get_token()     headers = {"Content-Type": "application/json", "accessToken": token}     r = httpx.post(f"{BASE_URL}{path}", json=body, headers=headers, timeout=60)     r.raise_for_status()     return r.json() @mcp.tool() async def flagship_add_po(linetype="010", material_number="Item-00000001",                           qty=10, priceandtax=10, ...):     """创建采购订单并自动提交+审核"""     ... ``` 工具已把所有陷阱写进 docstring,参数全带默认值,`billno`/`trdbillno` 自动生成唯一值。 六、复盘:四个可复用的方法论 1. **不要相信"返回成功"**。凡是金额/引用类字段,建完单一定要**读回校验**。这次两个最隐蔽的坑(`taxprice`、错误的 `ownertype`)都是靠读回才发现的。 2. **卡住时去读"已经成功的那张单"**。金蝶里手工建的单据是最好的参照物。用 `query` 读回来逐字段比对,比猜 key 名高效得多(我盲猜 32 个 key 全失败,读回一次就破局)。 3. **区分"枚举"与"基础资料"报错**。    - 枚举值错:`XX输入了未知的枚举值` → 可以暴力枚举试    - 基础资料错:`"XX"下"编码=YY"导入不成功` → 必须拿真实编码,猜是没用的 4. **每解决一个必填字段,可能冒出下一个**。行类型 → 第三方业务编码 → 货主,是串行的。要有心理准备,别指望一次通过。 --- 附:常用查询备忘 ```python # 查询(通配符是 * 不是 %;% 会被当字面量返回 0 条) {"data": {"billno": "*"}} # getList(需起止业务时间) {"data": {"start_biztime": "2020-01-01 00:00:00",           "end_biztime": "2030-01-01 00:00:00"}} ``` 单据状态:**A = 暂存**(API 新建后默认)、**B = 提交/待审**、**C = 已审核**。 --- *本文基于真实项目实践整理,涉及的企业域名、账套、密钥均已脱敏。*  

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册