前端对接包花厂集采
包花厂集采 11-04 接口变更
不参与等级免报价、货架按场次品种等级共用、供货单返回计划备注、盘点不再独占;覆盖供应商小程序、仓库 PDA、运营后台
Markdown 原文(给 AI 用):https://doc.xfun.fun/bulk-purchase-1104-api.md
总览
2026-11-04 包花厂集采四项改动里,需要前端对接的部分:
- 不参与的等级无需报价:报价只需传可供扎数大于 0 的等级;可供为 0 或不传的等级不填价格、不保存。调价只填参与的等级。
- 货架共用:同场次、同品种(二级分类)、同等级的货放同一个货架,不同供应商共用。货架码从「一张单一个」变成「一个等级一个」,展示要改读等级上的
shelfCode。 - 供货单返回采购计划备注:供应商端供货单列表、详情新增
demandRemark。 - 盘点不再独占:扫码不需要先「开始盘点」,任何仓库人员都能撤销任何人扫的码、都能提交盘点。
| # | 接口 | 端 | 变化 |
|---|---|---|---|
| ① | POST /bulkPurchase/quote/submit | 供应商小程序 | 只传参与的等级,不参与的等级不填价 |
| ② | POST /bulkPurchase/quote/update | 供应商小程序 | 同 ① |
| ③ | POST /bulkPurchase/quote/adjustPrice | 供应商小程序 | 只填参与的等级 |
| ④ | POST /bulkPurchase/demand/detail | 供应商小程序 | 不参与的等级 mySupplyLabelNum、myPrice 为 null |
| ⑤ | POST /bulkPurchase/quote/history | 供应商小程序 | 新版本 rankPrices 只含参与的等级 |
| ⑥ | POST /bulkPurchase/order/list | 供应商小程序 | 新增 demandRemark、ranks[].shelfCode |
| ⑦ | POST /bulkPurchase/order/detail | 供应商小程序 | 同 ⑥ |
| ⑧ | POST /wms/bulkPurchase/order/list | 仓库 PDA | 新增 shelfCodes;关键字可搜任一等级货架 |
| ⑨ | POST /wms/bulkPurchase/order/detail | 仓库 PDA | 新增 shelfCodes、ranks[].shelfCode |
| ⑩ | POST /wms/bulkPurchase/print/page | 仓库 PDA | 新增 ranks[].shelfCode;标签 shelfCode 改为等级货架 |
| ⑪ | POST /wms/bulkPurchase/print/normal、/print/reprint | 仓库 PDA | 返回标签的 shelfCode 改为等级货架 |
| ⑫ | POST /wms/bulkPurchase/label/resolve | 仓库 PDA | shelfCode 改为标签等级的货架;inventoryName 恒为 null |
| ⑬ | POST /wms/bulkPurchase/scan | 仓库 PDA | 不需要先开始盘点;按货架扫码时不传 orderId |
| ⑭ | POST /wms/bulkPurchase/inventory/start、/inventory/release | 仓库 PDA | 可以不再调用 |
| ⑮ | POST /wms/bulkPurchase/scan/revoke、/inventory/submit | 仓库 PDA | 不再限本人 |
| ⑯ | POST /bulkPurchase/order/detail | 运营后台 | 新增 ranks[].shelfCode |
| ⑰ | POST /bulkPurchase/confirm/quoteList | 运营后台 | 新报价的 rankPrices 只含参与的等级 |
通用约定
- 供应商小程序与仓库 PDA 走 supplier 服务(测试地址
https://api.xunmengvip.cn/xm-bulky-supplier),运营后台走 admin 服务。两边都有/bulkPurchase前缀,不要混用地址。 - 全部
POST+ JSON;请求头Authorization携带登录 token。 - supplier 返回
{ "code": 0, "msg": "success", "data": …, "message": "success", "valid": true };admin 返回{ "code": 0, "msg": "success", "data": … }。code != 0时msg直接 toast。 - supplier 分页入参
pageIndex(从 1 开始,默认 1)、pageSize(默认 10);出参{ current, size, total, records }。 - 金额单位元、最多两位小数;扎数为整数;时间
yyyy-MM-dd HH:mm:ss(北京时间)。 - 没有值的字段返回
null,不会省略。
枚举
| 枚举 | 取值 |
|---|---|
rankCode 等级 | 0 无等级 · 1 A · 2 B · 3 C · 4 D · 5 E · 6 O |
status 供货单状态 | 10 待签到 · 20 待盘点 · 30 待结算 · 40 已结算 · 90 已取消 |
rejectReason 扫码拒绝原因 | null 成功 · 2 重复扫码 · 3 标签已作废 · 4 属于其他供货单 · 5 标签不存在 · 6 供货单状态不允许盘点 |
货架码口径
后面接口里的 shelfCode、shelfCodes 都按这里的口径。
| 字段 | 含义 |
|---|---|
ranks[].shelfCode | 该等级的货架码,摆货、贴标看这个。同场次、同品种、同等级的所有供货单是同一个值,格式 JC + 4 位场次流水,如 JC0007 |
shelfCodes | 仓库端供货单列表、详情:这张单各等级的货架码,按等级顺序去重,如 ["JC0007","JC0008"] |
整单 shelfCode | 第一个中选等级的货架,只用于排序和兼容旧页面。一张单有多个等级时,不能只展示它 |
标签 shelfCode | 该标签等级的货架码 |
2026-11-04 下午上线前生成的供货单,等级上没有单独的货架码,后端已经回退成整单货架码返回,前端不用做兼容判断。
例:同场次两份玫瑰计划,供应商甲中选 A、B 级,乙中选 A 级:
甲的供货单:ranks[A].shelfCode = JC0001,ranks[B].shelfCode = JC0002,shelfCodes = ["JC0001","JC0002"]
乙的供货单:ranks[A].shelfCode = JC0001,shelfCodes = ["JC0001"]接口
POST/bulkPurchase/quote/submit首次提交报价
变更:不参与的等级可以不传;传了且可供扎数为 0 时不填价格
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
demandId | Long | 必填 | 采购计划 ID |
rankPrices | List | 必填 | 各等级报价,至少一个等级的可供扎数大于 0 |
rankPrices[].rankCode | Integer | 必填 | 等级,见枚举 rankCode;只能传计划开放的等级,同一等级不能重复 |
rankPrices[].supplyLabelNum | Integer | 可选 | 可供扎数。0 或不填表示不参与该等级 |
rankPrices[].price | BigDecimal | 可选 | 单价(元/扎)。可供扎数大于 0 时必填;可供为 0 时不填,传了也忽略 |
参与的等级(可供扎数大于 0)仍要满足:可供扎数 ≥ 该等级最小提交量、≤ 最大提交量、≤ 收购扎数(含追加);价格大于 0、最多两位小数、不高于该等级最高价、不超过 1000 元。
请求示例
计划开放 A、B、C 三个等级,只供 A、B:
{
"demandId": 58,
"rankPrices": [
{ "rankCode": 1, "supplyLabelNum": 600, "price": 2.50 },
{ "rankCode": 2, "supplyLabelNum": 200, "price": 1.80 }
]
}C 级也可以写成 { "rankCode": 3, "supplyLabelNum": 0 },效果相同。
响应
data 与改动前相同,本次不变。
响应示例
{ "code": 0, "msg": "success", "data": "报价提交成功", "message": "success", "valid": true }错误码 / 失败文案
| msg | 触发场景 | 前端处理 |
|---|---|---|
| 该需求不包含等级 C | 传了计划没开放的等级 | toast;表单只展示计划开放的等级 |
| 至少要有一个等级的可供扎数大于 0 | 全部等级都不参与 | toast |
| 同一等级不能重复出现 | rankCode 重复 | toast |
| A 级价格必须大于0 | 参与的等级没填价或填 0 | toast,定位到该等级 |
| A 级可供 50 扎,低于该等级最小提交量 100 扎;不供这个等级请填 0 | 参与的等级可供量不足 | toast |
| A 级报价 3.10 元/扎,超过该等级最高价 3.00 元/扎 | 价格超过最高价 | toast |
规则
- 表单交互建议:等级行「可供扎数」为空或 0 时,价格输入框置灰、不校验必填。
- 总可供扎数由后端按各等级求和,前端不用传。
POST/bulkPurchase/quote/update修改报价
变更:入参、规则、失败文案同「POST /bulkPurchase/quote/submit · 首次提交报价」
成功时 data 为 "报价修改成功"。内容与当前版本完全一致时不生成新版本。
POST/bulkPurchase/quote/adjustPrice定采前调价
变更:只需填当前报价中参与的等级(可供扎数大于 0)
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
demandId | Long | 必填 | 采购计划 ID |
reason | String | 必填 | 调价原因 |
rankPrices | List | 必填 | 必须包含当前报价中全部参与的等级;其他等级传了也忽略 |
rankPrices[].rankCode | Integer | 必填 | 等级,见枚举 rankCode |
rankPrices[].price | BigDecimal | 必填 | 新单价(元/扎) |
请求示例
{
"demandId": 58,
"reason": "市场价下调",
"rankPrices": [
{ "rankCode": 1, "price": 2.40 },
{ "rankCode": 2, "price": 1.70 }
]
}响应
data 与改动前相同,本次不变。
响应示例
{ "code": 0, "msg": "success", "data": "调价成功", "message": "success", "valid": true }错误码 / 失败文案
| msg | 触发场景 | 前端处理 |
|---|---|---|
| 需要对 A、B 全部参与供货的等级填写价格 | 漏填参与的等级 | toast |
| 您没有参与供货的等级,无法调价 | 当前报价没有可供扎数大于 0 的等级 | toast |
| 同一等级不能重复出现 | rankCode 重复 | toast |
POST/bulkPurchase/demand/detail集采需求详情
变更:不参与的等级我的报价为空
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | Long | 必填 | 采购计划 ID |
请求示例
{ "id": 58 }响应
只列本次有变化的字段,其余不变。
| 字段 | 类型 | 说明 |
|---|---|---|
ranks[].rankCode | Integer | 等级,列出计划开放的全部等级 |
ranks[].mySupplyLabelNum | Integer | 我在该等级报的可供扎数;不参与或未报为 null,表单回填为空 |
ranks[].myPrice | BigDecimal | 我在该等级报的单价;不参与或未报为 null |
响应示例
{
"code": 0, "msg": "success", "message": "success", "valid": true,
"data": {
"id": 58,
"ranks": [
{ "rankCode": 1, "mySupplyLabelNum": 600, "myPrice": 2.50 },
{ "rankCode": 2, "mySupplyLabelNum": 200, "myPrice": 1.80 },
{ "rankCode": 3, "mySupplyLabelNum": null, "myPrice": null }
]
}
}改动前报过「可供 0 + 价格」的老报价,回填时仍会有 mySupplyLabelNum = 0 和价格。前端按「可供为 0 或 null 即不参与」统一处理。
POST/bulkPurchase/quote/history我的报价版本历史
变更:新版本的 rankPrices 只含参与的等级
改动前的历史版本可能带可供 0 的等级行,新版本没有。同一份历史里各版本等级条数可能不同,按 rankCode 对齐展示,缺的等级显示「不参与」。
POST/bulkPurchase/order/list我的供货单列表
变更:新增 demandRemark、ranks[].shelfCode
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageIndex | Integer | 可选 | 页码,从 1 开始,默认 1 |
pageSize | Integer | 可选 | 每页条数,默认 10 |
status | Integer | 可选 | 见枚举 status;不传为全部 |
roundNo | String | 可选 | 场次 yyyy-MM-dd |
keyword | String | 可选 | 供货单号 / 需求编号 |
请求示例
{ "pageIndex": 1, "pageSize": 10, "status": 30 }响应
只列本次新增的字段。
| 字段 | 类型 | 说明 |
|---|---|---|
records[].demandRemark | String | 新增。采购计划备注(发布计划时填写);没填为 null,前端不展示该行 |
records[].shelfCode | String | 整单货架码,口径见「货架码口径」 |
records[].ranks[].shelfCode | String | 新增。该等级的货架码 |
demandRemark 是采购计划的备注。deliveryRemark(送货备注)、inventoryRemark(盘点备注)、overHandleRemark(超量处理备注)、settleRemark(结算备注)是供货单自己的备注,不要混用。
响应示例
{
"code": 0, "msg": "success", "message": "success", "valid": true,
"data": {
"current": 1, "size": 10, "total": 1,
"records": [
{
"id": 21,
"orderNo": "GH2026092710019000002",
"shelfCode": "JC0001",
"demandRemark": "Codex测试数据:超量待结算",
"ranks": [
{ "rankCode": 1, "rankName": "A", "shelfCode": "JC0001", "confirmLabelNum": 100 },
{ "rankCode": 2, "rankName": "B", "shelfCode": "JC0002", "confirmLabelNum": 0 }
]
}
]
}
}POST/bulkPurchase/order/detail我的供货单详情
变更:新增 demandRemark、ranks[].shelfCode,含义同「POST /bulkPurchase/order/list · 我的供货单列表」
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | Long | 必填 | 供货单 ID |
请求示例
{ "id": 21 }POST/wms/bulkPurchase/order/list待作业供货单列表
变更:新增 shelfCodes;关键字可搜任一等级的货架码;排序改为整单货架码 + ID
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
pageIndex | Integer | 可选 | 页码,从 1 开始,默认 1 |
pageSize | Integer | 可选 | 每页条数,默认 10 |
keyword | String | 可选 | 供货单号 / 货架码 / 供应商 / 品种 / 需求编号;输入任一等级的货架码都能搜到这张单,所以按货架找单直接搜货架码 |
roundNo | String | 可选 | 场次 yyyy-MM-dd |
status | Integer | 可选 | 见枚举 status |
请求示例
{ "pageIndex": 1, "pageSize": 10, "roundNo": "2026-11-05", "keyword": "JC0001" }响应
只列本次新增的字段。
| 字段 | 类型 | 说明 |
|---|---|---|
records[].shelfCodes | List | 新增。这张单各等级的货架码,按等级顺序去重;列表上展示这个,不要只展示整单 shelfCode |
响应示例
{
"code": 0, "msg": "success", "message": "success", "valid": true,
"data": {
"current": 1, "size": 10, "total": 2,
"records": [
{ "id": 31, "orderNo": "GH2026110510019000001", "supplierName": "甲花卉", "shelfCode": "JC0001", "shelfCodes": ["JC0001", "JC0002"] },
{ "id": 32, "orderNo": "GH2026110510019000002", "supplierName": "乙花卉", "shelfCode": "JC0001", "shelfCodes": ["JC0001"] }
]
}
}POST/wms/bulkPurchase/order/detail供货单详情
变更:新增 shelfCodes、ranks[].shelfCode,含义见「货架码口径」
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | Long | 必填 | 供货单 ID |
请求示例
{ "id": 31 }POST/wms/bulkPurchase/print/page打印页数据
变更:新增 ranks[].shelfCode;ranks[].labels[].shelfCode 改为该等级的货架码
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | Long | 必填 | 供货单 ID |
请求示例
{ "id": 31 }响应
| 字段 | 类型 | 说明 |
|---|---|---|
shelfCode | String | 整单货架码,口径见「货架码口径」 |
ranks[].shelfCode | String | 新增。该等级的货架码,打印页按等级分组展示 |
ranks[].labels[].shelfCode | String | 变更。标签上印的货架码,改为该标签等级的货架 |
响应示例
{
"code": 0, "msg": "success", "message": "success", "valid": true,
"data": {
"orderId": 31,
"orderNo": "GH2026110510019000001",
"shelfCode": "JC0001",
"ranks": [
{ "rankCode": 1, "rankName": "A", "shelfCode": "JC0001",
"labels": [ { "labelCode": "GH2026110510019000001-1-0001", "rankCode": 1, "seqNo": 1, "shelfCode": "JC0001" } ] },
{ "rankCode": 2, "rankName": "B", "shelfCode": "JC0002",
"labels": [ { "labelCode": "GH2026110510019000001-2-0001", "rankCode": 2, "seqNo": 1, "shelfCode": "JC0002" } ] }
]
}
}POST/wms/bulkPurchase/print/normal正常/增量打印
变更:返回标签的 shelfCode 改为该标签等级的货架码,入参不变
POST /wms/bulkPurchase/print/reprint(重打)返回的标签同样按等级货架码。
POST/wms/bulkPurchase/label/resolve首码识别供货单
变更:shelfCode 改为标签等级的货架;inventoryName 恒为 null
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
labelCode | String | 必填 | 标签码 |
请求示例
{ "labelCode": "GH2026110510019000001-2-0001" }响应
只列本次有变化的字段。
| 字段 | 类型 | 说明 |
|---|---|---|
shelfCode | String | 变更。该标签等级所在货架码 |
inventoryName | String | 变更。恒为 null,不再提示「某某正在盘点」 |
响应示例
{
"code": 0, "msg": "success", "message": "success", "valid": true,
"data": { "scannable": true, "orderId": 31, "orderNo": "GH2026110510019000001", "rankCode": 2, "seqNo": 1, "shelfCode": "JC0002", "inventoryName": null }
}POST/wms/bulkPurchase/scan扫码盘点
变更:不需要先调「开始盘点」;按货架连续扫码时不传 orderId
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
labelCode | String | 必填 | 标签码 |
orderId | Long | 可选 | 当前作业的供货单 ID。传了:扫到别家标签会被拒(rejectReason = 4),适合按单盘点;不传:扫到哪张单的标签就计入哪张单,适合按货架扫(一个货架上有多家的货) |
请求示例
按货架扫:
{ "labelCode": "GH2026110510019000002-1-0003" }响应
| 字段 | 类型 | 说明 |
|---|---|---|
success | Boolean | 是否计数成功 |
rejectReason | Integer | 拒绝原因,见枚举 rejectReason |
message | String | 提示文案,直接展示 |
actualLabelNum | Integer | 传了 orderId 时返回该单累计实际产出;不传为 null |
ranks | List | 传了 orderId 时返回该单各等级进度(含 ranks[].shelfCode);不传为 null |
响应示例
{
"code": 0, "msg": "success", "message": "success", "valid": true,
"data": { "success": true, "rejectReason": null, "message": "扫码成功", "actualLabelNum": null, "ranks": null }
}扫码响应外层 code 恒为 0,被拒时看 data.success = false 和 data.message,不能只看外层。
POST/wms/bulkPurchase/inventory/start开始盘点
变更:不再占用供货单,扫码不依赖它,可以不调
只校验供货单处于待盘点,返回 "已开始盘点"。POST /wms/bulkPurchase/inventory/release(暂停盘点)直接返回 "已暂停",没有任何作用。两个接口保留只为兼容旧版 PDA,新版可以去掉「开始 / 暂停盘点」按钮。
POST/wms/bulkPurchase/scan/revoke撤销扫码
变更:任何仓库人员都能撤销任何人扫的标签
入参 labelCode 不变。供货单须仍在待盘点。POST /wms/bulkPurchase/inventory/submit(提交盘点)同样不再限本人,任何仓库人员都能提交。
POST/bulkPurchase/order/detail运营后台供货单详情
变更:新增 ranks[].shelfCode
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id | Long | 必填 | 供货单 ID |
请求示例
{ "id": 31 }响应
| 字段 | 类型 | 说明 |
|---|---|---|
shelfCode | String | 整单货架码,口径见「货架码口径」 |
ranks[].shelfCode | String | 新增。该等级的货架码 |
响应示例
{
"code": 0, "msg": "success",
"data": {
"id": 31, "orderNo": "GH2026110510019000001", "shelfCode": "JC0001",
"ranks": [
{ "rankCode": 1, "rankName": "A", "shelfCode": "JC0001", "confirmLabelNum": 100 },
{ "rankCode": 2, "rankName": "B", "shelfCode": "JC0002", "confirmLabelNum": 0 }
]
}
}运营后台供货单列表 POST /bulkPurchase/order/list 只返回整单 shelfCode,不带等级货架,也不支持按货架码搜索。
POST/bulkPurchase/confirm/quoteList定采报价列表
变更:新报价的 rankPrices 只含参与的等级
改动后提交的报价不再带可供 0 的等级行。按计划等级画固定列时,缺的等级显示「不参与」或「-」,不要显示 0 元。
联调注意
- 测试环境:supplier
supplier/test、adminbulky-test/admin已部署;测试库 DDL 已执行。 - 造数:同一场次发两份同品种的采购计划,让不同供应商中选同一个等级,两张供货单该等级的
shelfCode应相同,打出的标签货架码也相同。 - 计划备注:供应商 10002 的供货单
GH2026092710019000002,demandRemark应为「Codex测试数据:超量待结算」。 - 改动前生成的供货单:可能带可供 0 的等级行,等级货架码都等于整单货架码,属正常。
一个货架上会有多家的货。PDA 如果「先选单再连续扫」并传了 orderId,扫到同货架别家的标签会提示「该标签属于其他供货单」。按货架扫码请不传 orderId。