This commit is contained in:
曾志威
2026-07-10 14:44:54 +08:00
parent e8c1757d4e
commit 0cee884a04
28 changed files with 10604 additions and 70 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,7 +20,7 @@
| V1.0.4 | 2026-02-11 | Shopee WMS | 3.4.1 接口增加属性key说明<br>4.1接口字段urgent_flag变更到attr_list中<br>4.3状态码更新<br>4.7 接口字段urgent_flag future_order_qty future_sku_qty oos_order_qty 四个字段变更到attr_list中 |
| V1.0.5 | 2026-02-12 | Shopee WMS | 新增3.2.11对账接口 |
| V1.0.6 | 2026-02-25 | Shopee WMS | 2.1 接口返回putaway_qty字段说明<br>2.5 接口返回task_list说明<br>2.7 接口请求total_qty、putaway_qty、submit_qty字段说明<br>2.8 接口请求sku_list说明 |
| V1.0.7 | 2026-02-25 | Shopee WMS | 出库模块新增固定属性枚举说明(紫色标记)3.1.3 更新urgent flag批量接口新增批量返回参数 |
| V1.0.7 | 2026-02-25 | Shopee WMS | 出库模块新增固定属性枚举说明(紫色标记)<br>3.1.3 更新urgent flag批量接口新增批量返回参数 |
| v1.0.8 | 2026-02-26 | Shopee WMS | 4.1AttrList新增oos_order_qty字段<br>4.1和4.7AttrItem新增urgent_flag字段说明(红色标记)<br>出库模块 新增拣货明细id说明(橙色标记) |
| v1.0.9 | 2026-02-27 | Shopee WMS | 出库属性列表新增attr_value_type<br>3pl 属性key重命名为channel_id |
| v1.1.0 | 2026-02-28 | Shopee WMS | 入库2.7接口新增错误码-10001016 |
@@ -1207,20 +1207,20 @@ ErrSkuInfo
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段 |
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| sub_pickup_id | string | 是 | 32 | 拣货任务id,幂等hik的单据 | 202104220002_0,波次id | shipment_header.erpOrderCode<br>shipment_header.shopeeWave-新增字段,shopee波次号<br>同步接到两个字段中 |
| sub_pickup_id | string | 是 | 32 | 拣货任务id,幂等<br>hik的单据 | 202104220002_0,波次id | shipment_header.erpOrderCode<br>shipment_header_ext1.shopeeWaveCode<br>同步接到两个字段中 |
| urgent_flag | int | 是 | | 0~99 越大越紧急 | 1 | shipment_header.priority |
| cut_off_time | int | 是 | | 任务截止时间,秒级时间戳,越小越优先出库 | 1767837541 | shipment_header.cutOffTime-新增字段,截止时间 |
| ship_by_date | int | 是 | | Ship by DateTask中order最早的sbd),秒级 | 1767837541 | shipment_header.scheduledShipDate |
| purchase_time | int | 是 | | Purchase TimeTask中order最早的pt),秒级 | 1767837541 | shipment_header.purchaseTime-新增字段,购买时间 |
| order_time | int | 是 | | Create TimeTask中order最早的create time),秒级 | 1767837541 | shipment_header.orderTime-新增字段,订单创建时间 |
| ctime | int | 是 | | 创建时间,WMS创建的时间戳,秒级 | 1767751167 | shipment_header.ctime-新增字段,shopee wms创建时间 |
| can_group_picking | int | 是 | | 0: 不可混拣 | 0 | shipment_header.canGroupPicking<br>新增字段,是否混拣 |
| group_key | string | 是 | 128 | 特征值,若可混拣,则有值 | xxx_xx_xx_xx | shipment_header.groupKey<br>新增字段,混拣特征值 |
| cut_off_time | int | 是 | | 任务截止时间,秒级时间戳,越小越优先出库 | 1767837541 | shipment_header_ext1.cutOffTime |
| ship_by_date | int | 是 | | Ship by DateTask中order最早的sbd),秒级 | 1767837541 | shipment_header_ext1.shipByDate |
| purchase_time | int | 是 | | Purchase TimeTask中order最早的pt),秒级 | 1767837541 | shipment_header_ext1.purchaseTime |
| order_time | int | 是 | | Create TimeTask中order最早的create time),秒级 | 1767837541 | shipment_header_ext1.orderTime |
| ctime | int | 是 | | 创建时间,WMS创建的时间戳,秒级 | 1767751167 | shipment_header_ext1.ctime |
| can_group_picking | int | 是 | | 0: 不可混拣 | 0 | shipment_header_ext1.canGroupPicking |
| group_key | string | 是 | 128 | 特征值,若可混拣,则有值 | xxx_xx_xx_xx | shipment_header_ext1.groupKey |
| sku_info_list | List<SkuInfo> | 是 | | 期望拣货数量 | | 明细取值见下文 |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:<br>process_guide<br>spx_single_store<br>spx_store_group_template<br>spx_store_group_id<br>max_order_size | | max_order_size接到shipment_header.orderSize-新增字段 |
| multi_attr_list | List<MultiAttr> | 是 | | 属性列表(多属性)<br>当前attr_key有:<br>channel_id、fulfillment_chain_id | | channel_id接到shipment_header.channelId-新增字段<br>fulfillment_chain_id接到shipment_header.fulfillmentChainId-新增字段 |
| ticket_type | int | 是 | | 单据类型:<br>1: 销售出库下发task 2:销售出库下发order 3:rts需求池需求 4: mto需求池需求 5: mto下发任务 6: RT | 1 | shipment_header.ticketType-新增字段 |
| | | | | | | shipment_header.shipmentType<br>默认XSCK |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:<br>process_guide<br>spx_single_store<br>spx_store_group_template<br>spx_store_group_id<br>max_order_size | | max_order_size接到shipment_header_ext1.orderSize |
| multi_attr_list | List<MultiAttr> | 是 | | 属性列表(多属性)<br>当前attr_key有:<br>channel_id、fulfillment_chain_id | | channel_id接到shipment_header_ext1.channelId<br>fulfillment_chain_id接到shipment_header_ext1.fulfillmentChainId |
| ticket_type | int | 是 | | 单据类型:<br>1: 销售出库下发task 2:销售出库下发order 3:rts需求池需求 4: mto需求池需求 5: mto下发任务 6: RT | 1 | shipment_header_ext1.ticketType |
| | | | | | | shipment_header.shipmentType<br>ticket_type=1XSCK |
SkuInfo字段详情
@@ -1235,10 +1235,10 @@ SkuInfo字段详情
SingleAttr字段详情(WES需要展示吗?)
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段(需同步插入数据字典,shopee_field_dictionary,attr_key插入组类型,attr_value_id插入标识,attr_value_name插入名称,attr_value_type插入value1)接口下发时判断数据字典如果没有该组类型的标识需要插入数据字典 |
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段(需同步插入数据字典,需要插入数据字典的字段波次在出库集波wave rule表中列:Enum相对固定or变动,标变动的字段需要插入数据字典,shopee_field_dictionary, attr_key插入组类型,attr_value_id插入标识,attr_value_name插入名称,attr_value_type插入value1)接口下发时判断数据字典如果没有该组类型的标识需要插入数据字典 |
| --- | --- | --- | --- | --- | --- | --- |
| attr_key | string | 是 | 64 | 属性key | max_order_size | config_detail.groupType |
| attr_value_id | string | 是 | 128 | 属性value id(没有id的场景我们id和name传的是相同的值) | 1 | config_detail.identifier |
| attr_value_id | string | 是 | 128 | 属性value id<br>(没有id的场景我们id和name传的是相同的值) | 1 | config_detail.identifier |
| attr_value_type | string | 否 | 128 | 属性 type的枚举<br>(有些属性需要支持类型筛选) | 1 | config_detail.value1 |
| attr_value_name | string | 是 | 128 | 属性value 可读 | large | config_detail.description |
@@ -1302,7 +1302,7 @@ Attr字段详情
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段(取消WES走base标记cancel,标记的单子集波不抓) |
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| sub_pickup_id | string | 是 | 32 | 拣货任务id,幂等 | 202104220002_0 | shipment_header.erpOrderCode |
| sub_pickup_id | string | 是 | 32 | 拣货任务id,幂等 | 202104220002_0 | shipment_header.erpOrderCodeshipment_header.erpOrderCode |
###### 响应字段
@@ -1399,7 +1399,7 @@ Attr字段详情
| sub_pickup_id | string | 是 | 32 | 拣货任务id | 202104220002_0 | shipment_header.shopeeWave |
| station_type | int | 是 | | 工作站类型<br>单据分播流程、分播出库流程<br>1vendor pick to order<br>2vendor batch picking | 1 | 按照工作站选的类型取值 |
| pick_type | int | 是 | | 1: pick to order(wave_type=0) 对应vendor pick to order<br>2: pick to wave(wave_type=1\2\3\4\5) 对应vendor dynamic wave<br>3: flow pick(wave_type=1/5) | 1 | 如果工作站类型选的1vendor pick to order则传1<br>如果waveType=1或5则传3<br>否则传2 |
| wave_type | int | 是 | | 1: SingleSkuSingleQtyWave<br>2: SameSkuSameQtyWave3: MixWave 4: SingleSkuAndAnyQtyWave<br>5: MixSkuSingleQtyWave | | waveType |
| wave_type | int | 是 | | 1: SingleSkuSingleQtyWave<br>2: SameSkuSameQtyWave<br>3: MixWave<br>4: SingleSkuAndAnyQtyWave<br>5: MixSkuSingleQtyWave | | waveType |
| operator | string | 是 | 64 | operator邮箱<br>有场景没有(自动开班) | xxx@shopee.com | 取工作站登录用户表的邮箱 |
@@ -1476,7 +1476,7 @@ Attr字段详情
| -10002014 | 其他业务类错误 | 其他业务类错误 | 是 |
##### 3.1.7 Vendor增量拣货明细
##### 3.1.7 Vendor增量拣货明细(定时回传部分已拣货完成的明细)
| 接口URL | 接口描述 | 调用方 | 业务要求 |
@@ -1699,6 +1699,8 @@ UnitItem
##### 3.1.10 Vendor请求流程指引
(流程指引,下发任务的和下发订单的在不同节点请求该接口(下发任务是请求上游开始任务之后,下发订单是在换箱时请求该接口,具体看出库流程图请求接口的节点),请求接口上游返回流程下一步提示,界面上显示上游的返回提示即可,若上游接口无返回或接口请求失败之类的,wes不卡流程可以继续作业)
| 接口URL | 接口描述 | 调用方 | 业务要求 |
| --- | --- | --- | --- |
@@ -1849,18 +1851,18 @@ UnitItem
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| order_number | string | 是 | 32 | 订单号,幂等 | OBCNG000260101081110 | shipment_header.erpOrderCode |
| can_group_picking | int | 是 | | 1: 可混拣 | 1 | shipment_header. canGroupPicking<br>新增字段,是否混拣 |
| group_key | string | 是 | 128 | 特征值,若可混拣,则有值 | xxx_xx_xx_xx<br>相同group_key可以混拣 | shipment_header.groupKey<br>新增字段,混拣特征值 |
| can_group_picking | int | 是 | | 1: 可混拣 | 1 | shipment_header_ext1.canGroupPicking |
| group_key | string | 是 | 128 | 特征值,若可混拣,则有值 | xxx_xx_xx_xx<br>相同group_key可以混拣 | shipment_header_ext1.groupKey |
| urgent_flag | int | 是 | | 0~99 越大越紧急 | 99 | shipment_header.priority |
| cut_off_time | int | 是 | | 任务截止时间,秒级时间戳,越小越优先出库 | 1767837541 | shipment_header.cutOffTime-新增字段<br>截止时间 |
| ctime | int | 是 | | 创建时间,WMS创建的时间戳 | 1767751167 | shipment_header.ctime-新增字段,shopee wms创建时间 |
| ship_by_date | int | 是 | | 截运时间 | 1767751167 | shipment_header.scheduledShipDate |
| purchase_time | int | 是 | | 购买时间 | 1767751167 | shipment_header.purchaseTime-新增字段,购买时间 |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:service_code、channel_id、fulfillment_chain_id、order_structure、order_size、shop_group、store_id、parcel_id、lm_tracking_no、pickup_region、delivery_region、sls_tracking_no、actual_weight(单位:g)、lane_code、handover、zone_code_id、outer_packaging | | 插入数据字典逻辑与3.1.1同理<br>service_code接到shipment_header.serviceCode-新增字段<br>fulfillment_chain_id接到shipment_header.orderStructure-新增字段<br>order_size 接到shipment_header.orderSize-新增字段<br>shop_group接到shipment_header.shopGroup-新增字段<br>store_id接到<br>shipment_header.storeId-新增字段<br>delivery_region接到shipment_header.deliveryRegion-新增字段<br>lane_code接到shipment_header.laneCode-新增字段<br>outer_packaging接到shipment_header.outerPackaging-新增字段 |
| multi_attr_list | List<MultiAttr> | 是 | | 属性列表(多属性)<br>shop_id、shopee_order_sn、inner_packaging | | 插入数据字典逻辑与3.1.1同理<br>shop_id接到shipment_header.shopId-新增字段 |
| cut_off_time | int | 是 | | 任务截止时间,秒级时间戳,越小越优先出库 | 1767837541 | shipment_header_ext1.cutOffTime |
| ctime | int | 是 | | 创建时间,WMS创建的时间戳 | 1767751167 | shipment_header_ext1.ctime |
| ship_by_date | int | 是 | | 截运时间 | 1767751167 | shipment_header_ext1.shipByDate |
| purchase_time | int | 是 | | 购买时间 | 1767751167 | shipment_header_ext1.purchaseTime |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:service_code、channel_id、fulfillment_chain_id、order_structure、order_size、shop_group、store_id、parcel_id、lm_tracking_no、pickup_region、delivery_region、sls_tracking_no、actual_weight(单位:g)、lane_code、handover、zone_code_id、outer_packaging | | 插入数据字典逻辑与3.1.1同理<br>service_code接到shipment_header_ext1.serviceCode<br>channel_id接到shipment_header_ext1.channelId<br>fulfillment_chain_id接到shipment_header_ext1.fulfillmentChainId<br>order_structure接到shipment_header_ext1.orderStructure<br>order_size接到shipment_header_ext1.orderSize<br>shop_group接到shipment_header_ext1.shopGroup<br>store_id、parcel_id、lm_tracking_no、pickup_region、delivery_region、sls_tracking_no、actual_weight、lane_code、handover、zone_code_id、outer_packaging接到shipment_header_ext1,去掉下划线使用小驼峰命名<br>outer_packaging.attr_value_type接到shipment_header_ext1.outerPackagingType |
| multi_attr_list | List<MultiAttr> | 是 | | 属性列表(多属性)<br>shop_id、shopee_order_sn、inner_packaging | | 插入数据字典逻辑与3.1.1同理<br>shop_id、shopee_order_sn、inner_packaging接到shipment_header_ext1,去掉下划线使用小驼峰命名<br>inner_packaging.attr_value_type接到shipment_header_ext1.innerPackagingType |
| sku_info_list | List<SkuInfo> | 是 | | Sku信息 | | 明细取值见下文 |
| ticket_type | int | 是 | | 单据类型:<br>单据类型:<br>1: 销售出库下发task 2:销售出库下发order 3:rts需求池需求 4: mto需求池需求 5: mto下发任务 6: RT | 2 | shipment_header.ticketType-新增字段 |
| | | | | | | shipment_header.shipmentType默认XSCK |
| ticket_type | int | 是 | | 单据类型:<br>单据类型:<br>1: 销售出库下发task 2:销售出库下发order 3:rts需求池需求 4: mto需求池需求 5: mto下发任务 6: RT | 2 | shipment_header_ext1.ticketType |
| | | | | | | shipment_header.shipmentType<br>ticket_type=2XSCK |
SkuInfo字段详情
@@ -2053,7 +2055,7 @@ SkuInfo字段详情
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shopee_wave.warehouseCode |
| count | int | 是 | | 数量,最大100 | 100 | 100 |
| biz_type | int | 是 | | 1 - 销售出库2 - RTS3 - MTO | 1 | 3种类型每天取100个,当天集波用当天的波次 |
| biz_type | int | 是 | | 1 - 销售出库<br>2 - RTS<br>3 - MTO | 1 | 3种类型每天取100个,当天集波用当天的波次 |
###### 响应字段
@@ -2101,7 +2103,7 @@ SkuInfo字段详情
| sub_pickup_id | string | 是 | 32 | 拣货任务id | 202104220002_0 | 根据订单类型取得shopee_wave中的状态为100的波次号,取完就要更新状态为使用中,注意并发 |
| station_type | int | 是 | | 工作站类型<br>单据分播流程、分播出库流程<br>1vendor pick to order<br>2vendor batch picking | 1 | 按照工作站选的类型取值 |
| pick_type | int | 是 | | 1: pick to order(wave_type=0) 对应vendor pick to order<br>2: pick to wave(wave_type=1\2\3\4\5) 对应vendor dynamic wave<br>3: flow pick(wave_type=1/5) | 1 | 如果工作站类型选的1vendor pick to order则传1<br>如果waveType=1或5则传3<br>否则传2 |
| wave_type | int | 是 | | 1: SingleSkuSingleQtyWave<br>2: SameSkuSameQtyWave3: MixWave 4: SingleSkuAndAnyQtyWave<br>5: MixSkuSingleQtyWave | | waveType |
| wave_type | int | 是 | | 1: SingleSkuSingleQtyWave<br>2: SameSkuSameQtyWave<br>3: MixWave<br>4: SingleSkuAndAnyQtyWave<br>5: MixSkuSingleQtyWave | | waveType |
| order_number_list | List<string> | 是 | | 订单号列表 | [“OBCNG000260101081110”,”OBCNG000260101081112”] | shipment_header.erpOrderCode |
| operator | string | 是 | 64 | operator邮箱 | xxx@shopee.com | 取工作站登录用户表的邮箱 |
@@ -2450,27 +2452,27 @@ TaskAttrInfo字段详情-不处理
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| order_number | string | 是 | 32 | 订单号,幂等 | RTSWMSSGL00026010700001 | shipment_header.sourceOrderCode |
| biz_type | int | 是 | 16 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 16 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header_ext1.bizType<br>shipment_header.shipmentType<br>biz_type=1XSCKbiz_type=2RTSbiz_type=3MTO |
| res_list | List<ResInfo> | 是 | | 需求列表<br>Mar 9: 当前res list长度最大1000 | 详见下表 | |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:<br>to_whs<br>expected_ob_date<br>order_source<br>transported_by<br>biz_type<br>order_tag<br>supplier_id<br>delivery_method<br>return_date<br>rts_reason<br>order_source<br>04-14 新增: rts_type 20 - Real 30 - Virtual<br>04-21 新增: sku_biz_type | 0509补充RTS、MTO属性keysRTS<br>to_whs<br>expected_ob_date<br>order_source<br>supplier_id<br>delivery_method<br>return_date<br>rts_reason<br>rts_type<br>biz_type<br>MTO<br>from_whs<br>to_whs<br>biz_type<br>sku_biz_type<br>order_flag<br>urgent_flag<br>create_time<br>expected_ob_date<br>order_source<br>transfer_type<br>注意:两者order_source枚举RTS和MTO不一样 | |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:<br>to_whs<br>expected_ob_date<br>order_source<br>transported_by<br>biz_type<br>order_tag<br>supplier_id<br>delivery_method<br>return_date<br>rts_reason<br>order_source<br>04-14 新增: rts_type 20 - Real 30 - Virtual<br>04-21 新增: sku_biz_type | 0509补充RTS、MTO属性keys<br>RTS<br>to_whs<br>expected_ob_date<br>order_source<br>supplier_id<br>delivery_method<br>return_date<br>rts_reason<br>rts_type<br>biz_type<br>MTO<br>from_whs<br>to_whs<br>biz_type<br>sku_biz_type<br>order_flag<br>urgent_flag<br>create_time<br>expected_ob_date<br>order_source<br>transfer_type<br><br>注意:<br>两者order_source枚举RTS和MTO不一样<br> | 与3.2.1同理,接到shipment_header_ext1,小驼峰命名 |
| multi_attr_list | List<MultiAttr> | 是 | | 属性列表(多属性)<br>当前attr_key有: | | |
| ticket_type | int | 是 | | 单据类型:<br>单据类型:<br>1: 销售出库下发task 2: 销售出库下发order 3:rts需求池需求 4: mto 需求池需求 5: mto下发任务 6: RT | 3或者4 | shipment_header.ticketType |
| ticket_type | int | 是 | | 单据类型:<br>单据类型:<br>1: 销售出库下发task 2: 销售出库下发order 3:rts需求池需求 4: mto 需求池需求 5: mto下发任务 6: RT | 3或者4 | shipment_header_ext1.ticketType |
ResInfo字段详情
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段 |
| --- | --- | --- | --- | --- | --- | --- |
| res_number | string | 是 | 64 | RTS需求号 | RORWMSSGD00026010600003 | shipment_header.erpOrderCode<br>根据该字段进行拆分单据 |
| res_number | string | 是 | 64 | RTS需求号 | RORWMSSGD00026010600003 | shipment_header.erpOrderCode<br>shipment_header_ext1.resNumber<br>根据该字段进行拆分单据 |
| sku_id | string | 是 | 64 | sku_id | 1767751294820_08379 | shipment_detail.itemCode |
| qty | int | 是 | | 期望拣货数量 | 1 | shipment_detail.requestQty |
| block_type | int | 是 | | 指定冻结类型(Normal/临期/过期)<br>SKUBlockTypeNoNeed SKUBlockType = 0<br>SKUBlockTypeEXPIRING SKUBlockType = 1<br>SKUBlockTypeEXPIRED SKUBlockType = 3 | 0 | shipment_detail.shelfLifeSts<br>效期状态 |
| quality | int | 是 | | 0 好品<br>指定好/坏品<br>SkuQualityTypeGood SkuQualityType = 0<br>SkuQualityTypeDamage SkuQualityType = 1 | 0 | shipment_detail.inventorySts<br>库存状态 |
| group_key | string | 是 | | 特征值(包含 delivery_method supplier .. 决定是否能混拣) | | shipment_header. groupKey新增字段,混拣特征值 |
| can_group_picking | int | 是 | | 是否能和其他不一样特征值的需求混拣<br>0 - 不能混拣<br>1 - 可以混拣 | 默认0 | shipment_header. canGroupPicking<br>新增字段,是否混拣 |
| group_key | string | 是 | | 特征值(包含 delivery_method supplier .. 决定是否能混拣) | | shipment_header_ext1.groupKey |
| can_group_picking | int | 是 | | 是否能和其他不一样特征值的需求混拣<br>0 - 不能混拣<br>1 - 可以混拣 | 默认0 | shipment_header_ext1.canGroupPicking |
| urgent_flag | int | 是 | | 0~99 越大越紧急 | 99 | shipment_header.priority |
| demand_mode | int | 是 | | 2 : single 模式<br>1 : mix 模式<br>展示用 | 1 | shipment_header.demandMode |
| ctime | int | 是 | | 需求创建时间 | 1767751167 | shipment_header.ctime-新增字段,shopee wms创建时间 |
| demand_mode | int | 是 | | 2 : single 模式<br>1 : mix 模式<br>展示用 | 1 | shipment_header_ext1.demandMode |
| ctime | int | 是 | | 需求创建时间 | 1767751167 | shipment_header_ext1.ctime |
###### 响应字段
@@ -2515,7 +2517,7 @@ ResInfo字段详情
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段(取消WES走base标记cancel,标记的单子集波不抓) |
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| res_number_list | List<string> | 是 | 64 | RTS需求号列表 / MTO 需求号列表 | [RORWMSSGD00026010600003] | shipment_header.erpOrderCode |
@@ -2560,7 +2562,7 @@ ResInfo字段详情
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段 |
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| res_list | List<ResInfo> | 是 | | 需求列表,长度<2000 | 详见下表 | |
ResInfo字段详情
@@ -2622,7 +2624,7 @@ ResInfo字段详情
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| pickup_id | int64 | 是 | 64 | 拣货任务id | 202104220002 | 根据订单类型取得shopee_wave中的状态为100的波次号,取完就要更新状态为使用中,注意并发 |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| station_type | int | 是 | | 工作站类型<br>单据分播流程、分播出库流程<br>1vendor pick to order<br>2vendor batch picking | 1 | 按照工作站选的类型取值 |
| res_number_list | List<string> | 是 | | 需求号列表 | [“OBCNG000260101081110”,”OBCNG000260101081112”] | shipment_header.erpOrderCode |
| operator | string | 是 | 64 | operator邮箱 | xxx@shopee.com | 取工作站登录用户表的邮箱 |
@@ -2685,7 +2687,7 @@ ResTaskAttrInfo
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| pickup_id | int64 | 是 | 64 | 拣货任务id | 202104220002 | shipment_header.shopeeWave |
| device_id | string | 是 | 32 | 拣货设备id | OPBSK11873 | wcs_sorting_wall_cell.containerCode分拣墙格口绑定的目标容器号 |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| operator | string | 是 | 64 | operator邮箱 | xxx@shopee.com | 取工作站登录用户表的邮箱 |
@@ -2731,7 +2733,7 @@ ResTaskAttrInfo
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| pickup_id | int64 | 是 | 64 | 拣货任务id | 202104220002 | 追加到shopee的波次号 |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| res_number_list | List<string> | 是 | | 追加的需求列表,增量 | [“OBCNG000260101081110”,”OBCNG000260101081112”] | shipment_header.erpOrderCode |
@@ -2778,7 +2780,7 @@ ResTaskAttrInfo
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段 |
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| picking_task_list | List<PickingTaskList> | 是 | 100 | 拣货任务列表 | 详见下表 | |
PickingTaskList字段详情
@@ -2859,7 +2861,7 @@ UnitItem
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| pickup_id | int64 | 是 | 64 | 拣货任务id | 202104220002 | shipment_header.shopeeWave |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 1 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 1 | shipment_header.shipmentType |
| operator | string | 是 | 64 | operator邮箱 | xxx@shopee.com | 取工作站登录用户表的邮箱 |
| picked_order_number_list | List<PickedInfo> | 是 | | 满拣需求sku列表 | | 整单全拣货的单据<br>明细见下文 |
| shortage_order_info_list | List<PickedInfo> | 是 | | 缺拣需求sku列表 | 缺拣(未拣满或者因为缺货零拣) | 整单部分拣货的单据<br>明细见下文 |
@@ -2935,7 +2937,7 @@ UnitItem
| pickup_id | int64 | 是 | 64 | 拣货任务id | 202104220002 | shipment_header.shopeeWave换箱前的上游波次号 |
| new_pickup_id | int64 | 是 | 64 | 新的拣货任务id | 202104220002 | 取上游新的波次号段(也是rts和mto订单都是flow pick形式) |
| new_device_id | string | 是 | 32 | 设备id | OPBSK11873 | wcs_sorting_wall_cell.containerCode分拣墙格口绑定的目标容器号-换箱后的 |
| biz_type | int | 是 | 4 | 任务类型:1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| biz_type | int | 是 | 4 | 任务类型:<br>1 - 销售出库<br>2 - RTS<br>3 - MTO | 2 | shipment_header.shipmentType |
| station_type | int | 是 | | 工作站类型<br>单据分播流程、分播出库流程<br>1vendor pick to order<br>2vendor batch picking<br>注意:如果是BatchPicking,需求池模式只能走FLowPicking产生新任务的换箱模式 | 1 | 按照工作站选的类型取值 |
| operator | string | 是 | 64 | operator邮箱 | xxx@shopee.com | 取工作站登录用户表的邮箱 |
| picked_order_number_list | List<PickedOrderInfo> | 是 | | 满拣需求sku列表 | | 整单全拣货的单据<br>明细见下文 |
@@ -3021,16 +3023,16 @@ UnitItem
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 | WES表字段 |
| --- | --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL | shipment_header.warehouseCode |
| pickup_id | int64 | 是 | 64 | 拣货任务id,幂等 | 202104220002 | shipment_header.erpOrderCode<br>shipment_header.shopeeWave-新增字段,shopee波次号<br>同步接到两个字段中 |
| pickup_id | int64 | 是 | 64 | 拣货任务id,幂等 | 202104220002 | shipment_header.erpOrderCode<br>shipment_header_ext1.shopeeWaveCode<br>同步接到两个字段中 |
| urgent_flag | int | 是 | | 0~99 越大越紧急 | 99 | shipment_header.priority |
| ctime | int | 是 | | 创建时间,WMS创建的时间戳 | 1767751167 | shipment_header.ctime-新增字段,shopee wms创建时间 |
| can_group_picking | int | 是 | | 0: 不可混拣 | 0 | shipment_header. canGroupPicking<br>新增字段,是否混拣 |
| group_key | string | 是 | 128 | 特征值,若可混拣,则有值 | xxx_xx_xx_xx | shipment_header.groupKey<br>新增字段,混拣特征值 |
| ctime | int | 是 | | 创建时间,WMS创建的时间戳 | 1767751167 | shipment_header_ext1.ctime |
| can_group_picking | int | 是 | | 0: 不可混拣 | 0 | shipment_header_ext1.canGroupPicking |
| group_key | string | 是 | 128 | 特征值,若可混拣,则有值 | xxx_xx_xx_xx | shipment_header_ext1.groupKey |
| sku_info_list | List<SkuInfo> | 是 | | 期望拣货数量 | | |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:<br>to_whs<br>expected_ob_date<br>order_source<br>transported_by | | |
| single_attr_list | List<SingleAttr> | 是 | | 属性列表(单属性)<br>当前有:<br>to_whs<br>expected_ob_date<br>order_source<br>transported_by | | to_whs接到shipment_header_ext1.toWhs<br>expected_ob_date接到shipment_header_ext1.expectedObDate<br>order_source接到shipment_header_ext1.orderSource<br>transported_by接到shipment_header_ext1.transportedBy |
| multi_attr_list | List<MultiAttr> | 是 | | 属性列表(多属性)<br>当前attr_key有 | | |
| ticket_type | int | 是 | | 单据类型:<br>1: 销售出库下发task 2: 销售出库下发order 3:rts需求池需求 4: mto 需求池需求 5: mto下发任务 6: RT | 5 | shipment_header.ticketType |
| | | | | | | shipment_header.shipmentType默认为MTO |
| ticket_type | int | 是 | | 单据类型:<br>1: 销售出库下发task 2: 销售出库下发order 3:rts需求池需求 4: mto 需求池需求 5: mto下发任务 6: RT | 5 | shipment_header_ext1.ticketType |
| | | | | | | shipment_header.shipmentType<br>ticket_type=5MTO |
SkuInfo字段详情
@@ -3486,7 +3488,7 @@ SkuInfo
| device_id | string | 否 | 16 | 设备号(一个source_id/rt_order_id对应多个device_id 一次请求只给一个device) 0拣可不传 | B00013 |
| new_device_id | string | 否 | 16 | 新占用箱子,关箱时可以传一个新占用的箱子(对应系统页面是一次操作 但不允许关空箱)单据用过的device不允许上架完二次使用 | |
| grid_no | string | 是 | | 分拨墙的格口号 new_device_id有传的话必传 | 同3.1.6接口 |
| sku_info_list | List<SkuInfo> | 否 | NA | 缺拣时不传 关箱的时候传所有明细<br>另外WMS创建需要实时传明细(Vendor创建的可以只在关箱传一次) | |
| sku_info_list | List<SkuInfo> | 否 | NA | 缺拣时不传<br>关箱的时候传所有明细<br>另外WMS创建需要实时传明细(Vendor创建的可以只在关箱传一次) | |
| picking_flag | int | 是 | 1 | 1:整单完成 2:仅关箱(传所有明细) 3:换箱(传旧箱所有明细及new_device_id) | 1 |
SkuInfo
@@ -3776,7 +3778,7 @@ UnitItem
| --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | 16 | 仓库id | SGL |
| rt_order_list | List<RTOrderItem> | 是 | 1000 | 传的列表用于批量更新(最少传一个) | |
| update_event | int | 是 | NA | 取消单据(取消只处理status) 1其他单据信息更新2 | |
| update_event | int | 是 | NA | 取消单据(取消只处理status) 1<br>其他单据信息更新2 | |
RTOrderItem
@@ -3784,7 +3786,7 @@ RTOrderItem
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 |
| --- | --- | --- | --- | --- | --- |
| rt_order_id | string | 是 | 32 | WMS侧的移库单号 | RTSGL00020250102001 |
| status | int | 否 | | status和其他单据字段至少传一个目前只有6 代表取消 | |
| status | int | 否 | | status和其他单据字段至少传一个<br>目前只有6 代表取消 | |
| attr_list | List<AttrItem> | 否 | | update_event=2时必传<br>目前单据属性(后面新增不改协议)<br>urgent_flag(值范围0-99)<br>future_order_qty(整数 >= 0)<br>future_sku_qty(整数 >= 0)<br>oos_order_qty(整数 >= 0)<br>字段不一定都传(可能只传一个) | |
AttrItem(urgent_flag 值范围0-99 非枚举)
@@ -3886,7 +3888,7 @@ AttrItem(urgent_flag 值范围0-99 非枚举)
| 字段名 | 类型 | 是否必须 | 最大长度 | 说明 | 示例 |
| --- | --- | --- | --- | --- | --- |
| whs_id | string | 是 | | 仓库编号 | SGL |
| batch_list | List<BatchBlockType> | 是 | | 状态有变化的批次以及状态;最大1000个,超过1000个分多次调用。 | [<br>{<br>batch_no:12345<br>batch_status: 1<br>}<br>] |
| batch_list | List<BatchBlockType> | 是 | | 状态有变化的批次以及状态;<br>最大1000个,超过1000个分多次调用。 | [<br>{<br>batch_no:12345<br>batch_status: 1<br>}<br>] |
BatchBlockType
@@ -4381,3 +4383,4 @@ Staging环境:https://wms-automation.ssc.staging.shopee.{cid}
建议反馈请联系:tao.fu@shopee.com
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+420
View File
@@ -0,0 +1,420 @@
版本号␍
发布日期␍
发布人␍
版本说明␍
V1.0.0␍
初稿␍
V1.0.1␍
销售出库业务类型枚举统一␍
V1.0.2␍
vendor错误码更新␍
V1.0.3␍
3.3.1 需求池模式新增demand_mode字段␍
V1.0.4␍
3.4.1 接口增加属性key说明␍4.1接口字段urgent_flag变更到attr_list中␍4.3状态码更新␍4.7 接口字段urgent_flag future_order_qty future_sku_qty oos_order_qty 四个字段变更到attr_list中␍
V1.0.5␍
新增3.2.11对账接口␍␍
V1.0.6␍
2.1 接口返回putaway_qty字段说明␍2.5 接口返回task_list说明␍2.7 接口请求total_qty、putaway_qty、submit_qty字段说明␍2.8 接口请求sku_list说明␍
V1.0.7␍
出库模块新增固定属性枚举说明(紫色标记)
3.1.3 更新urgent flag批量接口新增批量返回参数␍
v1.0.8␍
4.1AttrList新增oos_order_qty字段␍4.1和4.7AttrItem新增urgent_flag字段说明(红色标记)␍出库模块 新增拣货明细id说明(橙色标记)␍
v1.0.9␍
出库属性列表新增attr_value_type␍3pl 属性key重命名为channel_id␍
v1.1.0␍
入库2.7接口新增错误码-10001016␍
v1.1.1 ␍
基础资料5.4 请求体新增reconciliation_date字段␍
v1.1.2␍
入库2.1 请求报文、2.5响应报文 批次信息 BatchInfo新增purchase_type␍
v1.1.3␍
库内4.5api路径改动 tovendor改为toshopee (已标记红色)␍
v1.1.4␍
入库2.4接口增加了关于反拣的search_key说明。␍
v1.1.5␍
库内4.3接口 remark增加传参说明␍
v1.1.6␍
出库(黄底标记)␍3.1.7增加校验说明、参数返回说明␍3.3.9 入参、出参与销售出库统一␍3.4.7 出参与销售出库统一␍3.1.11 增加参数说明␍
v1.1.7␍
3.1.1, 3.2.1, 3.3.1 3.4.1 新增下发参数ticket_type␍3.2.2 删除不可能返回的错误码␍
v1.1.8␍
2.6接口新增uid录入说明␍
v1.1.9␍
4.1接口新增ticket_type␍ticket_type枚举统一␍
v1.2.0␍
5.25.35.4接口block_type字段统一␍
v1.2.1␍
出库错误码补充␍
v1.2.2␍
废弃入库2.1、2.3、2.4、2.5、2.7、2.8接口sheet_id字段␍
v1.2.3␍
出库接口调用说明补充␍
v1.2.4␍
入库2.1、2.4接口BatchInfo新增sku_id␍
v1.2.5␍
基础资料 新增接口5.8;␍基础资料 接口5.3 去除响应体BatchInventory 中的uid_list字段;␍
v1.2.6␍
4.1接口新增sku_quality参数 (好坏品 0代表好品 1代表坏品)␍
v1.2.7␍
需求池返回值增加非必填说明(3.3.6、3.3.8、3.3.10、3.3.11)␍3.3.3 res_list增加最大长度说明␍3.1.7 过账相关接口的拣货id增加长度说明␍batch_no、pickup_id类型为int64␍3.3.1 补充ctime字段␍
v1.2.8␍
附录A.1 新增-10000005错误码␍
v1.2.9␍
新增接口失败重试策略说明␍
v1.3.0␍
4.2的device_id字段 4.3的new_device_id字段增加备注(不可二次使用)␍
v1.3.1␍
更新operator说明␍
v1.3.2␍
5.3修复sku business type枚举值说明␍
v1.3.3␍
5.7查询robot状态接口可选参数agv_id_list统一改为robot_id_list␍
v1.3.4␍
4.7增加更新失败的单据id列表␍4.5 接口增加一个需要重试的状态码␍
v1.3.5␍
新增DB字符集说明␍
v1.3.6␍
3.3.1 single_attr_list字段新增rts_type(20-Real 30-Virtual)␍3.3.1 新增supplier_id字段以及业务逻辑␍
v1.3.7␍
库内4.6新增参数wave_flag start_time end_time exclude_source_id_list␍
v1.3.8␍
ConsumableSpecialTypeNoneSuggested = -1␍新需求引入枚举␍
v1.3.9␍
新增3.1.12订单更新接口␍
v1.4.0␍
新增5.7 AgvStatus下的robot_model字段␍
包含wms和vendor都取消的订单␍
vendor侧,全部订单canceltask终态也要通知wms␍
包含vendorwms cancel的订单␍
vendor侧,全部订单canceltask终态也要通知wms␍
包含vendorwms cancel的订单␍
vendor侧,全部订单canceltask终态也要通知wms␍
包含vendorwms cancel的订单␍
是否保持一致␍
不需要传sku+qty的拣货明细。vendor保证一个订单不会在多个拣货任务中,wms用传的这些订单去预占auto zone的库存␍
去掉。complete接口给我们qty,零拣和缺拣,释放库存,都在complete处理即可␍
任务大小␍
暂定异步␍
与下发任务的cancel,用同一个接口␍
vendor侧的,xingyi之前说传过来我们记录下。␍␍xingyi说,vendor侧的pick to order仅仅只移库支持换箱,其他都不支持␍
vendor侧的,xingyi之前说传过来我们记录下。␍␍xingyi说,vendor侧的pick to order仅仅只移库支持换箱,其他都不支持␍
vendor侧的,xingyi之前说传过来我们记录下。␍␍xingyi说,vendor侧的pick to order仅仅只移库支持换箱,其他都不支持␍
vendor侧的,xingyi之前说传过来我们记录下。␍␍xingyi说,vendor侧的pick to order仅仅只移库支持换箱,其他都不支持␍
vendor侧的,xingyi之前说传过来我们记录下。␍␍xingyi说,vendor侧的pick to order仅仅只移库支持换箱,其他都不支持␍
不需要传sku+qty的拣货明细。vendor保证一个订单不会在多个拣货任务中,wms用传的这些订单去预占auto zone的库存␍。追加的场景都是单品单件的订单␍
0115:倾向于开始任务不做提前绑了,空绑/解绑/cancel后回到空绑的状态,这些流程就没了。␍关联device和task的本接口是同步␍
考虑不可换箱字段␍
vendor->wms的取消接口,wms擦除预命中结果␍
1、qty为0的,不用给wms;␍2、0拣的订单列表,不用传这个pickedorderinfo,只用传order list␍
包含wms取消,vendor没取消成功的订单␍
vendor释放device后依然占用着,WMS需要兼容释放为using空占␍
vendor要支持,上一个任务终态后,重复下单能成功␍
去掉了␍
接下来,调bind picking task的接口,绑定task和device开始任务␍
2月4号添加 Vendor创建的需要传 我们需要记录拣货的时候这个批次是冻结还是非冻结␍
改下名字?这个应该叫撤单␍
加个字段 传要更新的移库单号␍
这里有点奇怪,下面入参new_order_number_list为新追加的订单,那应该只追加订单3,传order3才对吧,为啥这里要写追加时追加order1,2,3,难道wms要支持已经在任务中的order再次传入?␍
list是拣货id维度␍
相同拣货id不同order,这里会有多条。wms调同步拣货明细时,要按拣货id汇聚一下。␍
sub_pickup_id维度,外层校验重复␍
哪些情况下可以变更为禁止上架␍
宋体:
新細明體:
␍MS 明朝:
宋体:
新細明體:
橙果依依:
橙果依依:
橙果依依:
橙果依依:
凡:
凡:
凡:
凡:
橙果依依:
橙果依依:
橙果依依:
橙果依依:
橙果依依:
橙果依依:
无可救药:
无可救药:
Shopee Automation Vendor 接入协议手册
文档版本信息
目录
概述
适用范围
术语定义
请求方式
1.1 Vendor请求Automation(北向请求)
请求协议
Authorization JWT Token加密规范
请求体格式
响应体格式
请求和响应示例(以5.1接口为例)
1.2 Automation请求Vendor(南向请求)
请求协议
Authorization JWT Token校验
请求体格式
响应体格式
请求和响应示例(以5.3接口为例)
接口失败重试策略
Vendor请求Automation失败场景
重试方法
入库模块接口协议
2.1 入库单据下发到Vendor
请求字段
响应字段
返回码
2.2 WMS给Vendor下发单据变更接口
请求字段
响应字段
返回码
2.3 WMS向Vendor下发单据查询接口
请求字段
响应字段
返回码
2.4 Vendor向WMS请求入库任务接口
请求字段
响应字段
返回码
2.5 Vendor向WMS反查入库任务接口
请求字段
响应字段
返回码
2.6 Vendor向WMS校验uid接口
请求字段
响应字段
返回码
2.7 Vendor向WMS提交库存过账接口
请求字段
响应字段
返回码
2.8 Vendor向WMS下发单据状态变更接口
请求字段
响应字段
返回码
出库模块接口协议
3.1 销售出库自动化SubPickingTask
3.1.1 WMS给Vendor下发拣货任务
请求字段
响应字段(和vendor对一下能提供什么字段给WMS)
返回码
3.1.2 WMS取消拣货任务
请求字段
响应字段
返回码
3.1.3 WMS向Vendor更新订单/task的urgent flag
请求字段
响应字段
返回码
3.1.4 Vendor绑定/解绑device(空占)【复用basic接口】
3.1.5 Vendor开始拣货任务
请求字段
响应字段
返回码
3.1.6 Vendor实绑拣货任务
请求字段
响应字段
返回码
3.1.7 Vendor增量拣货明细
请求字段
响应字段
返回码
3.1.8 Vendor发起换箱(不产生新任务)
请求字段
响应字段
返回码
3.1.9 Vendor完成拣货任务
请求字段
响应字段
返回码
3.1.10 Vendor请求流程指引
请求字段
响应字段
返回码
3.1.11 查询Vendor拣货任务列表【出库所有订单类型通用对账查询vendor接口】
请求字段
响应字段
返回码
3.2 销售出库自动化Order
3.2.1 WMS给Vendor下单
请求字段
响应字段
返回码
3.2.2 WMS向Vendor捞单
请求字段
响应字段
返回码
3.2.3 Vendor向WMS撤单
请求字段
响应字段
返回码
3.2.4 Wms向Vendor下发锁单/解锁请求
请求字段
响应字段
返回码
3.2.5 vendor向wms获取号段缓存
请求字段
响应字段
返回码
3.2.6 Vendor绑定解绑设备【复用basic接口】
3.2.7 Vendor向WMS创建picking task
请求字段
响应字段
返回码
3.2.8 Vendor向WMS追加明细
请求字段
响应字段
返回码
3.2.9 flow pick换箱
请求字段
响应字段
返回码
3.2.10 Vendor完成task
请求字段
响应字段
返回码
3.2.11 Wms向Vendor查询冻结状态订单列表(对账)
请求字段
响应字段
返回码
3.2.12 复用接口列表
3.3 RTS & MTO 需求池
3.3.1 WMS给Vendor下发需求
请求字段
响应字段
返回码
3.3.2 WMS向Vendor取消需求
请求字段
响应字段
返回码
3.3.3 Vendor 向 WMS 同步占用信息
请求字段
响应字段
返回码
3.3.4 Vendor绑定/解绑device【废弃】
3.3.5 Vendor向wms获取号段缓存【复用】
3.3.6 Vendor向WMS创建picking task
请求字段
响应字段
返回码
3.3.7 Vendor实绑拣货任务
请求字段
响应字段
返回码
3.3.8 Vendor向WMS追加明细
请求字段
响应字段
返回码
3.3.9 Vendor增量同步拣货明细
请求字段
响应字段
返回码
3.3.10 Vendor完成task
请求字段
响应字段
返回码
3.3.11 Vendor换箱接口
请求字段
响应字段
返回码
3.3.12 查询Vendor拣货任务列表【复用】
3.3.13 更新需求的urgent_flag【复用】
3.4 非需求池MTO
3.4.1 WMS给Vendor下发拣货任务
请求字段
响应字段
返回码
3.4.2 WMS取消拣货任务
请求字段
响应字段
返回码
3.4.3 WMS向Vendor更新task的urgent flag【复用3.1.3】
3.4.4 Vendor绑定/解绑device【复用basic接口】
3.4.5 Vendor开始拣货任务
请求字段
响应字段
返回码
3.4.6 Vendor真实绑定拣货任务
请求字段
响应字段
返回码
3.4.7 Vendor增量拣货明细
请求字段
响应字段
返回码
3.4.8 Vendor完成拣货任务
请求字段
响应字段
返回码
3.4.9 查询Vendor拣货任务列表【复用】
库内模块接口协议
4.1 库内移库同步占用库存给Vendor接口
请求字段
响应字段
返回码
4.2 库内移库Vendor占用PickingDevice接口
请求字段
响应字段
返回码
4.3 库内Vendor发起Picking明细整箱同步到WMS(WMS/Vendor创建)
请求字段
响应字段
返回码
4.4 库内Vendor发起Picking明细定时回传到WMS(只针对WMS创建)
请求字段
响应字段
返回码
4.5 库内Vendor发起盘点差异调减同步给WMS
请求字段
响应字段
返回码
4.6 库内发起Vendor查询拣货接口(用于对账)
请求字段
响应字段
返回码
4.7 库内更新(移库)单据(WMS创建的)
请求字段
响应字段
返回码
基础资料模块接口协议
5.1 vendor向WMS查询用户是否存在
请求字段
响应字段
返回码
5.2 WMS向Vendor同步批次状态
请求字段
响应字段
返回码
5.3 WMS向Vendor查询库存信息
请求字段
响应字段
返回码
5.4 WMS向Vendor同步对账结果
请求字段
响应字段
返回码
5.5 vendor向WMS查询sku信息
请求字段
响应字段
返回码
5.6 WMS向Vendor同步sku信息
请求字段
响应字段
返回码
5.7 WMS向Vendor查询AGV设备信息
请求字段
响应字段
返回码
5.8 WMS向Vendor查询Unit 信息
请求字段
响应字段
返回码
附录
A.1 返回码
A.2 测试环境
+62
View File
@@ -0,0 +1,62 @@
--- PAGE 1 ---
vendor视角-交互部分
vendor交互详细设计
vendor关心的名词
专有名词/ 说明
缩写
1 WMS-api WMS api服务
2 WMS- WMS automation服务
automation
3 WMS WMS 作业员
operator
4 iWMS vendor对接shopee的系统
5 vendor 自动化系统作业客户端系统
6 vendor 操作自动化系统作业客户端的作业员
operator
7 单据 RTS、MTO、销售出库、移库、需求等等,在vendor那边看都视为单据
8 波次ID 相当于WMS的拣货任务,一次只生成一个拣货任务
9 PickingTask WMS的拣货任务,一般一个拣货任务对应多个业务订单,一个拣货任务可以由多个拣货员拣货,即一个拣货任务有多个拣货员,v
endor不需要感知这一层
10 SubPickingTask 当拣货任务过大、跨区时,会拆分为多个SubPickingTask给多个拣货员拣货,本次交互中,一个销售出库的波次ID其实对应的是一
个SubPickingTask
11 Prehit 库存预占用,预命中库存
12 RTS 退供出库
13 MTO 调拨出库
14 sku_id shopee 商品条码
15 uid shopee 商品对应的item条码,表示唯一一件实物,一般高价值商品才会UID管理
16 item 表达sku需要多少数量使用item、件等名词
表达一个任务多少种sku使用个
交互流程范围
共梳理出5种需要与vendor交互的流程。
L0 业 业务L2 创 详细说明 owner
务 建
L1 源
出库 销售 自动化 shop RunWave生成的拣货任务中有部分库存占到自动化区,会拆分为两部分(一部分normal的拣货任务、一部分自动化的拣货 tangjian
出库 SubPicking ee 任务),其中自动化的拣货任务会下发任务给vendor,后续vendor执行WMS创建的拣货任务,不能混合拣货
Task
--- PAGE 2 ---
自动化 vend 当订单完全预命中到自动化区时,WMS会把该类订单下发给vendor,后续由vendor跑波混合多个订单,然后执行vendor jin.yang
Order or 创建的拣货任务
RTS RTS需求池 vend 有RTS需求至自动化区,下发需求给vendor,vendor按需求创建拣货任务,执行vendor创建的拣货任务 zhaoxin
模式 or
MTO MTO需求 vend 有MTO需求至自动化区,下发需求给vendor,vendor按需求创建拣货任务,执行vendor创建的拣货任务 jinfu
池模式 or
MTO非需 shop 有库存占用到自动化库位,拆分PickingTask,下发任务给vendor,不能混合拣货 jinfu
求池模式 ee
Vendor视角
出库(Shopee创建任务,包括销售出库SubPickingTask以及 非需求池MTO)
--- PAGE 3 ---
--- PAGE 4 ---
出库(Vendor创建任务,包括销售出库订单和RTS & MTO 需求池)
--- PAGE 5 ---
--- PAGE 6 ---
详细交互时序图及接口文档
接口文档: https://docs.qq.com/doc/DWUpRZ0ppd2pzbUpQ
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 MiB

@@ -0,0 +1,813 @@
# 接口文档:反查 Shopee 入库任务列表
> 接口地址:`POST /api/wms/schedule/searchShopeeInboundOrderList`
> 模块:`wms-schedule`(计划任务入口)/ `wms-api`(异步消费)/ `wms-receiving`(业务处理)
> 业务域:Shopee 2.5 WES 反查入库任务
---
## 1. 功能概述
定时(或手工触发)反向调用 Shopee,按入库任务号查询 Shopee 侧**最新任务状态**,并将结果回写、应用到本地入库单(Receipt)。
适用场景:
- 本地存在未完成(未关闭)的 Shopee 入库单,需要周期性反查上游状态(如明细变更、任务被取消等)。
- 多仓库场景:不指定 `warehouseCode` 时,自动遍历所有启用仓库逐仓反查。
底层对接的 Shopee 协议:**`2_5_shopee_inbound_order_searchInboundOrderList`**。
---
## 2. 调用链(请求流转)
```
HTTP POST /api/wms/schedule/searchShopeeInboundOrderList
ScheduleApiController.process() ← 路由分发
通过反射调用方法名 == {type}(即 searchShopeeInboundOrderList
ScheduleApiController.searchShopeeInboundOrderList() ← 组装 AisMessage(异步)
msg.queue = "wms.api.searchShopeeInboundOrderList"
msgSender.sendMessage(msg) → 同步返回 success
▼ (异步消费队列)
SearchShopeeInboundOrderList.process() ← @AisConsumer(queue=...)
insertLog { shopeeInboundService.searchInboundOrderList(session, body) }
ShopeeInboundService.searchInboundOrderList() ← 入口:单仓/多仓分发
├─ 指定 warehouseCode → fetchAndApplyInboundTasks()
└─ 未指定 → 遍历所有启用仓库 → fetchAndApplyInboundTasks()
fetchInboundTasks() ← 决定要反查哪些 taskId
fetchInboundTasksFromShopee() ← 经 EDI 调用 Shopee 2.5
│ ediRouteReqService.routeShopeeReq(SEARCH_INBOUND_ORDER_LIST_API, ...)
applyFetchedInboundTaskResult() ← 结果落库
ReceiptInboundOrderService.applyFetchedInboundTaskResult()
```
> 设计要点:HTTP 层只做"投递异步消息",真正反查与落库在 AIS 消费端执行,避免计划任务 HTTP 请求长时间阻塞。
---
## 3. 涉及类与文件
| 角色 | 文件 |
|------|------|
| ControllerHTTP 入口 + 反射分发) | `wms-schedule/.../schedule/controller/ScheduleApiController.groovy` |
| AIS 消费者(异步处理) | `wms-api/.../api/endpoint/SearchShopeeInboundOrderList.groovy` |
| 业务服务(反查/应用主逻辑) | `wms-receiving/.../receiving/service/shopee/ShopeeInboundService.groovy` |
| 落库服务(Receipt 应用) | `wms-receiving/.../receiving/service/ReceiptInboundOrderService.groovy` |
| EDI 转发 | `wms-general/.../general/service/EdiRouteReqService.groovy` |
---
## 4. 入口:ScheduleApiController
### 4.1 路由分发机制
```groovy
@RestController
@RequestMapping('/api/wms/schedule')
class ScheduleApiController extends BaseController {
@RequestMapping(value = "{type}")
ResponseMessage process(HttpServletRequest request, @PathVariable String type,
@RequestParam(required = false) Map<String, String> params,
@RequestBody(required = false) Map body) {
// 用 type 作为方法名反射调用:this.getClass().getMethod(type, ...)
// 找不到方法 → 返回 MSG_INTF_0003(无法识别的接口操作类型)
// 调用异常 → 返回 MSG_GNRL_0000(通用错误)
}
}
```
- 访问 `/api/wms/schedule/searchShopeeInboundOrderList` 时,`type = "searchShopeeInboundOrderList"`,反射调用同名方法。
- `params`query 参数)和 `body`(请求体)都会传入。
### 4.2 searchShopeeInboundOrderList 方法
```groovy
ResponseMessage searchShopeeInboundOrderList(TtxSession session, Map<String, String> params, Map body) {
Map<String, Object> request = ((params ?: [:]) + (body ?: [:])) as Map<String, Object> // 合并 query + body
String warehouseCode = request.get('warehouseCode') as String
session.params[WmsConstants.CURRENT_WAREHOUSE] = warehouseCode
AisMessage<Map> msg = new AisMessage<>()
msg.session = session
msg.msgSubject = warehouseCode
msg.queue = "wms.api.searchShopeeInboundOrderList"
msg.body = request
msgSender.sendMessage(msg) // 异步投递
return ResponseMessageFactory.success() // 立即返回
}
```
> 该层仅完成"参数合并 + 仓库上下文设置 + 异步消息投递",HTTP 调用立即返回成功,不代表业务已处理完成。
---
## 5. 异步消费:SearchShopeeInboundOrderList
```groovy
@AisConsumer(queue = 'wms.api.searchShopeeInboundOrderList')
class SearchShopeeInboundOrderList extends AisService<AisMessage<Map>> implements SchedulerLogTrait {
@Autowired
ShopeeInboundService shopeeInboundService
@Override
void process(AisMessage<Map> msg) {
insertLog(msg.session) {
shopeeInboundService.searchInboundOrderList(msg.session, msg.body as Map<String, Object>)
}
}
}
```
- 监听队列 `wms.api.searchShopeeInboundOrderList`
- 通过 `insertLog``SchedulerLogTrait`)包裹执行,自动记录计划任务执行日志。
---
## 6. 核心业务:ShopeeInboundService
核心业务分两个阶段:**①反查 Shopee**(拿到上游最新任务)+ **②应用到本地 Receipt**(对账并落库)。下面逐方法展开到字段级、SQL 级。
---
### 6.1 searchInboundOrderList —— 单仓 / 多仓分发
```groovy
ResponseMessage searchInboundOrderList(TtxSession session, Map<String, Object> request) {
String warehouseCode = request.warehouseCode as String
if (warehouseCode) {
return fetchAndApplyInboundTasks(session, request) // 单仓
}
// 未指定 → 遍历所有启用仓库(status = 1)
List<Map> whs = whSvc.findMaps([status: 1], ['code'])
List<Map<String, Object>> results = []
for (Map wh : whs) {
String code = wh.code as String
Map warehouseRequest = (request + [warehouseCode: code]) as Map<String, Object>
session.params[CURRENT_WAREHOUSE] = code // 每仓切换上下文
ResponseMessage rsp = fetchAndApplyInboundTasks(session, warehouseRequest)
results << [warehouseCode: code, success: !rsp.hasError(), message: rsp.msg, data: rsp.data]
}
return ResponseMessageFactory.success(results)
}
```
要点:
- 多仓遍历时**任一仓库失败不会中断其它仓**,结果按仓库维度汇总;多仓总响应仍为 `success`,单仓错误体现在 `results[i].success/message`
- 单仓路径直接返回 `fetchAndApplyInboundTasks` 的结果(成功或失败)。
---
### 6.2 fetchAndApplyInboundTasks —— 反查 + 应用(公共入口)
```groovy
private ResponseMessage fetchAndApplyInboundTasks(TtxSession session, Map<String, Object> request) {
ResponseMessage rsp = fetchInboundTasks(session, request) // ① 反查 Shopee
if (rsp.hasError()) return rsp
return receiptInboundOrderSvc.applyFetchedInboundTaskResult( // ② 应用到本地
session, rsp.data, request.warehouseCode, request.companyCode)
}
```
> 反查失败直接短路返回,不进入落库阶段。
---
### 6.3 fetchInboundTasks —— 确定要反查哪些任务号
```groovy
ResponseMessage fetchInboundTasks(TtxSession session, Map<String, Object> request) {
String warehouseCode = request.get('warehouseCode')
String companyCode = request.get('companyCode')
if (!warehouseCode) return error('warehouseCode不能为空')
// 是否显式指定了 taskIdList
boolean searchByTaskIds = request.containsKey('taskIdList') && request.get('taskIdList') != null
List<String> taskIds = normalizeList(request.get('taskIdList')) // 去重 + 去空
if (searchByTaskIds && !taskIds) return error('taskIdList不能为空')
// 未指定 → 从本地未完成 Shopee 入库单中领取一批
if (!taskIds) {
Integer months = resolveCreatedWithinMonths(request.get('createdWithinMonths')) // 默认 6
taskIds = findUnfinishedReceiptCodes(warehouseCode, companyCode, 50 /*DEFAULT_CLAIM_TASK_COUNT*/, months)
}
if (!taskIds) return success([total: 0, results: []]) // 没有可反查的任务
if (taskIds.size() > 2000) return error(WmsMessages.MSG_BASE_0024) // 单次上限 2000
String ediBaseUrl = ediRouteReqService.resolveEdiBaseUrl(session, SHOPEE_EDI_SERVER_IDENTIFIER)
Map body = buildInboundTaskSearchRequestBody(warehouseCode, taskIds, request) // {whs_id, task_id_list}
return fetchInboundTasksFromShopee(session, companyCode, ediBaseUrl, body, searchByTaskIds)
}
```
`searchByTaskIds` 标志位贯穿后续逻辑:它决定"上游返回空"是否视为错误(见 6.5)。
`buildInboundTaskSearchRequestBody` 组装的 Shopee 2.5 请求体:
```json
{ "whs_id": "<warehouseCode>", "task_id_list": ["任务号1", "任务号2", ...] }
```
#### 6.3.1 findUnfinishedReceiptCodes —— 待反查任务的"领取"
从本地未完成的 Shopee 入库单中**领**出一批任务号,核心是 **Redis 分布式锁 + `customInboundSearchNextTime` 节流字段**
```groovy
private List<String> findUnfinishedReceiptCodes(String warehouseCode, String companyCode,
Integer limit, Integer createdWithinMonths) {
RLock lock = RedissonLockService.getAndTryLock(
getLockKey(ReceiptHeader.table, 'shopeeInboundSearch', warehouseCode, companyCode ?: ''))
if (!lock) return [] // 抢锁失败 → 直接放弃本轮,避免多实例重复领取
LocalDateTime now = LocalDateTime.now()
LocalDateTime createdFrom = now.minusMonths(createdWithinMonths)
// 选取条件:
// warehouseCode = ? [+ companyCode = ? 可选]
// AND sourceErp = SHOPEE
// AND trailingSts < CLOSED (未关闭)
// AND created >= createdFrom (近 N 个月,默认 6)
// AND (customInboundSearchNextTime IS NULL OR customInboundSearchNextTime <= now) ← 节流:未到下次反查时间
// 排序:
// CASE WHEN customInboundSearchNextTime IS NULL THEN 0 ELSE 1 END ← 从未反查过的优先
// customInboundSearchNextTime, id
// LIMIT :limit (默认 50
rows = namedTemplate().queryForList(SQL, params)
// 关键:领取后立即把 nextTime 推后,避免下一轮被重复选中
LocalDateTime nextTime = now.plusMinutes(DEFAULT_SEARCH_INTERVAL_MONTHS) // 常量名虽叫 MONTHS,实际 plusMinutes
rows.each { rhSvc.updateByCondition([customInboundSearchNextTime: nextTime], [id: it.id]) }
return rows.collect { it.code } // 返回入库单号(即 Shopee 任务号)
}
finally { if (lock) unlock(lock) }
```
设计要点:
- **Redis 锁粒度**`(表, 'shopeeInboundSearch', warehouseCode, companyCode)`。同仓同货主同一时间只有一个实例在领取,避免同一批单据被多节点并发反查。
- **节流字段 `customInboundSearchNextTime`**:领取即推后下次反查时间,降低单据被高频反查;从未反查过的单据(NULL)优先。
- **抢锁失败即返回空**:当前实例本轮不领取,等下轮再试,保证不重复。
#### 6.3.2 resolveCreatedWithinMonths —— 时间范围解析
```groovy
private Integer resolveCreatedWithinMonths(Object value) {
Integer months = value ? value as Integer : 6 // DEFAULT_CREATED_WITHIN_MONTHS
return months > 0 ? months : 6 // 非正数回退默认值,避免扫描范围异常
}
```
---
### 6.4 fetchInboundTasksFromShopee —— 经 EDI 调用 Shopee 2.5
```groovy
private ResponseMessage fetchInboundTasksFromShopee(session, companyCode, ediBaseUrl, requestBody, searchByTaskIds) {
logInboundTaskSearchStart(session, requestBody, companyCode) // ProcessHistory: "开始"
ResponseMessage remoteRsp = ediRouteReqService.routeShopeeReq(
session,
'2_5_shopee_inbound_order_searchInboundOrderList', // SEARCH_INBOUND_ORDER_LIST_API
requestBody,
receiptDataWrapperListType(), // List<ReceiptDataWrapper>
ediBaseUrl)
if (remoteRsp.hasError()) {
logInboundTaskSearchResult(session, requestBody, remoteRsp, companyCode, null) // "失败"
return remoteRsp
}
// 关键分支:显式按 taskIdList 查询,但上游无任何返回 → 判定为"任务在上游已不存在"
if (searchByTaskIds && !hasRemoteReceiptData(remoteRsp.data)) {
ResponseMessage rsp = error('未查询到入库任务')
logInboundTaskSearchResult(session, requestBody, rsp, companyCode, remoteRsp.data)
return rsp
}
logInboundTaskSearchResult(session, requestBody, remoteRsp, companyCode, remoteRsp.data) // "完成"
return remoteRsp
}
```
- 返回类型用 Jackson `List<ReceiptDataWrapper>` 泛型解析,EDI 侧返回的 JSON 直接映射成本地领域包装类。
- `searchByTaskIds` 与自动领取的差异:自动领取若上游返回空(任务可能已完成关闭),不报错;显式按 ID 查返回空则视为异常。
#### 6.4.1 日志埋点(logInboundTaskSearchStart / Result
通过 `ProcessHistoryService.logProcess` 写入处理历史,关键参数:
| 项 | 值 |
|----|----|
| `type` | `WmsConstants.ProcessHistoryType.RECEIPT` |
| `action` | `UPDATE` |
| `refType` | `'ShopeeInboundOrderSearch'` |
| `refId` | warehouseCode |
| `companyCode` | 货主 |
| `count` | `task_id_list.size()` |
| `result` | 成功为返回总数,失败为错误信息 |
| `level` | 成功 INFO / 失败 ERROR |
日志消息模板:
- 开始:`Shopee反查入库任务开始,仓库:{0},货主:{1},任务号数量:{2}`
- 成功:`Shopee反查入库任务完成,仓库:{0},货主:{1},任务号数量:{2},返回总数:{3}`
- 失败:`Shopee反查入库任务失败,仓库:{0},货主:{1},任务号数量:{2},错误信息:{3}`
> 日志写入用 try-catch 包裹,**日志失败绝不影响反查主流程**。
#### 6.4.2 EDI 转发(EdiRouteReqService.routeShopeeReq
```groovy
static final String SHOPEE_EDI_SERVER_IDENTIFIER = 'shopee-edi-wms'
static final String SHOPEE_ROUTE_REQ_PATH = 'api/edi/shopee/routeReq'
static final String SHOPEE_EDI_CUSTOMER_ID = 'shopee'
ResponseMessage routeShopeeReq(session, api, requestBody, JavaType dataType, baseUrl) {
return routeReq(session, SHOPEE_EDI_SERVER_IDENTIFIER, SHOPEE_ROUTE_REQ_PATH,
api, requestBody, SHOPEE_EDI_CUSTOMER_ID, baseUrl, dataType)
}
```
WES 只负责把请求体交给 EDI 的 `api/edi/shopee/routeReq`,由 EDI 完成 Shopee 平台协议转换、签名、HTTP 转发和响应解析。
---
## 7. 结果落库:ReceiptInboundOrderService
反查拿到 `List<ReceiptDataWrapper>` 后,进入对账落库阶段。这是最复杂的部分,涉及**三层锁、明细级对账、数量重算、UID 清理、整单删除**。
### 7.1 applyFetchedInboundTaskResult —— 列表层
```groovy
ResponseMessage applyFetchedInboundTaskResult(TtxSession session, Object data,
String warehouseCode, String companyCode) {
List<ReceiptDataWrapper> receipts = convertToReceiptDataWrapperList(data) // List 或单对象统一成列表
if (!receipts) return error('未查询到入库任务')
receipts.each { removeOutboundSerialNumbers(it) } // ★ 数据清洗:过滤已出库 UID
List<Map<String, Object>> results = []
StringBuilder errors = new StringBuilder()
for (ReceiptDataWrapper receipt : receipts) {
ReceiptHeader header = receipt?.header?.receiptHeader
fillFetchedInboundTaskHeaderDefaults(header, warehouseCode, companyCode) // 补默认仓/货主
ResponseMessage rsp = applyFetchedInboundTaskReceipt(session, receipt) // 单据级应用
results << [code: header?.code, success: !rsp.hasError(), message: rsp.msg]
if (rsp.hasError()) errors.append(rsp.msg)
}
if (errors) return error(errors.toString()) // 任一单据失败 → 整体失败,错误聚合
return success([total: receipts.size(), results: results])
}
```
#### 7.1.1 removeOutboundSerialNumbers —— UID 清洗
递归过滤掉状态为 `OUTBOUND`(已出库)的 UID,避免上游回传或本地缓存的脏 UID 被写回:
```groovy
private void removeOutboundSerialNumbers(ReceiptDataWrapper receipt) {
receipt?.serialNumbers = filterAvailable(receipt?.serialNumbers)
receipt?.details?.each { detail ->
detail.serialNumbers = filterAvailable(detail?.serialNumbers)
detail.containers?.each { container ->
container.serialNumbers = filterAvailable(container?.serialNumbers) // 头/明细/容器三层全清
}
}
}
// filterAvailable: findAll { it.status != SerialNumberStatus.OUTBOUND }
```
> 与列表层不同:多单据中**任一单据失败会导致整批返回 error**(错误信息拼接)。这是与 6.1 多仓遍历"单仓失败不影响其它仓"的显著区别。
---
### 7.2 applyFetchedInboundTaskReceipt —— 单据级(第二层锁)
```groovy
private ResponseMessage applyFetchedInboundTaskReceipt(TtxSession session, ReceiptDataWrapper receiptData) {
ReceiptHeader h = receiptData?.header?.receiptHeader
if (!h?.warehouseCode || !h.companyCode || !h.code) return error(INVALID_MESSAGE_BODY)
RLock lock = null
try {
lock = rhSvc.tryLockByCode(h.warehouseCode, h.companyCode, h.code) // ★ 按单号锁
if (!lock) return error(WmsMessages.MSG_GNRL_0003) // 锁占用 → 失败
return doApplyFetchedInboundTaskReceipt(session, receiptData, h)
} finally {
if (lock) unlock(lock)
}
}
```
锁粒度:`(warehouseCode, companyCode, code)`,即**按入库单号串行化**,防止同一单据被并发反查/收货/上架交叉修改。
---
### 7.3 doApplyFetchedInboundTaskReceipt —— 单据对账主流程
```groovy
private ResponseMessage doApplyFetchedInboundTaskReceipt(session, receiptData, incomingHeader) {
// 1. 定位本地入库单
Map cv = [warehouseCode: incomingHeader.warehouseCode, code: incomingHeader.code]
if (incomingHeader.companyCode) cv.companyCode = incomingHeader.companyCode
ReceiptHeader receipt = rhSvc.findFirstEntity(cv)
if (!receipt) return error(MSG_INBD_0003) // 本地无此单
// 2. 可用性校验(如是否被锁定/作废)
ResponseMessage availableRsp = rhSvc.checkIsAvailable(session, receipt)
if (availableRsp.hasError()) return availableRsp
// 3. 加载本地明细 + 上游明细,按键匹配
List<ReceiptDetail> localDetails = rdSvc.findEntities([receiptId: receipt.id])
Map<String, ReceiptDetailDataWrapper> incomingMap = buildFetchedTaskDetailMap(receiptData.details)
Map<String, ReceiptDetail> localMap = buildLocalFetchedTaskDetailMap(localDetails)
// ★ 上游有而本地没有的明细 → 直接整体失败(不允许凭空新增明细)
if (incomingMap.keySet().any { key -> !localMap.containsKey(key) }) {
return error(MSG_INBD_0004)
}
// 4. 逐明细对账
List<String> syncedDetailIds = [], deletedDetailIds = []
for (ReceiptDetail localDetail : localDetails) {
ReceiptDetailDataWrapper incoming = incomingMap[fetchedTaskDetailKey(localDetail)]
ResponseMessage<FetchedTaskApplyPlan> planRsp = buildFetchedTaskApplyPlan(receipt, localDetail, incoming)
if (planRsp.hasError()) return planRsp
if (!shouldApplyFetchedTaskDetail(planRsp.data)) continue // 无变化跳过
// ★ 第三层锁:明细级
RLock detailLock = getAndTryLock(rdSvc.getLockKey(session, localDetail.id))
if (!detailLock) return error(MSG_GNRL_0003)
try {
// 锁内重新加载,避免并发漂移(双重检查)
localDetail = rdSvc.getEntity(localDetail.id)
incoming = incomingMap[fetchedTaskDetailKey(localDetail)]
planRsp = buildFetchedTaskApplyPlan(receipt, localDetail, incoming)
if (planRsp.hasError()) return planRsp
if (!shouldApplyFetchedTaskDetail(planRsp.data)) continue
if (incoming?.receiptDetail) {
applyFetchedTaskReturnedDetail(receipt, localDetail, incoming, planRsp.data) // 上游有 → 同步
syncedDetailIds << localDetail.id
} else {
ResponseMessage rsp = applyFetchedTaskMissingDetail(receipt, localDetail, planRsp.data) // 上游无 → 删/调
if (rsp.hasError()) return rsp
if ((rsp.data as Map)?.deleted) deletedDetailIds << localDetail.id
}
} finally {
if (detailLock) unlock(detailLock)
}
}
// 5. 整单是否应删除(所有明细都没了)
if (shouldDeleteFetchedTaskReceipt(receipt.id)) {
deleteFetchedTaskReceiptRelatedData(receipt.id)
receipt = rhSvc.getEntity(receipt.id)
ResponseMessage rsp = rhSvc.deleteEntity(receipt)
if (rsp.hasError()) return rsp
return success([deleted: true, syncedDetailIds: syncedDetailIds, deletedDetailIds: deletedDetailIds])
}
// 6. 刷新单据状态 + 统计
rhSvc.updateStatus(session, receipt.id)
rhSvc.updateStatistics(session, receipt.id)
return success([syncedDetailIds: syncedDetailIds, deletedDetailIds: deletedDetailIds])
}
```
#### 7.3.1 明细匹配键 fetchedTaskDetailKey
```groovy
private String fetchedTaskDetailKey(ReceiptDetail detail) {
return detail?.itemCode ? "${detail.itemCode}|${detail.batch ?: ''}" : null
}
```
- **匹配维度 = itemCode + batch**。同一 itemCode + batch 视为同一明细行。
- map 构建时 `if (!result.containsKey(key))` 保证**首次出现优先**,重复键忽略。
#### 7.3.2 双重检查(锁外 + 锁内)
明细对账执行了两次 `buildFetchedTaskApplyPlan`
1. **锁外**:快速判断是否需要处理(`shouldApplyFetchedTaskDetail`),无需处理直接跳过,避免无谓加锁。
2. **锁内**:重新 `getEntity` 拉最新数据再算一次,防止加锁前被其它事务改动造成漂移。
这是典型的"先查后锁再查"并发安全模式。
---
### 7.4 buildFetchedTaskApplyPlan —— 对账计划(核心数量逻辑)
逐明细计算"应该怎么改",输出 `FetchedTaskApplyPlan`
```groovy
private static class FetchedTaskApplyPlan {
BigDecimal openQty = 0 // 重算后的待上架数量
Boolean remoteDetailMissing = false // 上游该明细是否已不存在
Boolean shouldUpdateQty = false // 是否需要更新数量
Boolean shouldCheckPendingSerialNumbers = false // 是否需要校验/清理 UID
}
```
构造逻辑:
```groovy
private ResponseMessage<FetchedTaskApplyPlan> buildFetchedTaskApplyPlan(
ReceiptHeader localHeader, ReceiptDetail localDetail, ReceiptDetailDataWrapper incoming) {
// 分支A:上游该明细已不存在
if (!incoming?.receiptDetail) {
FetchedTaskApplyPlan plan = new FetchedTaskApplyPlan(
openQty: 0,
remoteDetailMissing: true,
shouldUpdateQty: shouldUpdateFetchedTaskDetailQty(localDetail, plan_with_openQty_0)
)
return success(plan)
}
// 分支B:上游有该明细 → 算数量差额
BigDecimal remoteUnputawayQty = resolveRemoteUnputawayQty(incoming) // 上游"未上架数量"
BigDecimal localCheckedInNotPutawayQty = resolveLocalCheckedInNotPutawayQty(localDetail) // 本地"已收货未上架"
// ★ 核心保护:上游未上架数 < 本地已收货未上架数 → 数据矛盾,拒绝
if (remoteUnputawayQty < localCheckedInNotPutawayQty) {
return error(MSG_INBD_0040)
}
FetchedTaskApplyPlan plan = new FetchedTaskApplyPlan()
plan.openQty = remoteUnputawayQty - localCheckedInNotPutawayQty // 新的待上架量
plan.shouldUpdateQty = shouldUpdateFetchedTaskDetailQty(localDetail, plan)
// 指定UID模式(customSpecifyUid=1) 且上游带回了 UID 列表 → 需要校验
plan.shouldCheckPendingSerialNumbers =
(localHeader.customSpecifyUid == 1 && incoming?.serialNumbers != null)
return success(plan)
}
```
数量计算的两个关键函数:
```groovy
// 上游未上架数量 = 上游 totalQty - 上游 fulfillQty(已上架),负数归 0
private BigDecimal resolveRemoteUnputawayQty(ReceiptDetailDataWrapper incoming) {
BigDecimal remotePutawayQty = toBigDecimal(incoming.receiptDetail.fulfillQty)
BigDecimal remoteUnputawayQty = toBigDecimal(incoming.receiptDetail.totalQty) - remotePutawayQty
return remoteUnputawayQty < 0 ? 0 : remoteUnputawayQty
}
// 本地已收货未上架数量 = 本地 fulfillQty(已收货) - 已关闭容器数量(已上架),负数归 0
private BigDecimal resolveLocalCheckedInNotPutawayQty(ReceiptDetail localDetail) {
BigDecimal checkedInQty = toBigDecimal(localDetail.fulfillQty)
BigDecimal putawayQty = findClosedReceiptContainerQty(localDetail.id) // sum(receipt_container.quantity where status=CLOSED)
BigDecimal notPutawayQty = checkedInQty - putawayQty
return notPutawayQty < 0 ? 0 : notPutawayQty
}
```
`shouldUpdateFetchedTaskDetailQty` —— 判断数量是否真的变了:
```groovy
private Boolean shouldUpdateFetchedTaskDetailQty(ReceiptDetail localDetail, FetchedTaskApplyPlan plan) {
// 期望的 totalQty = 已收货 + 已拒收 + 新算出的待上架量
BigDecimal expectedQty = localDetail.fulfillQty + localDetail.rejectedQty + plan.openQty
// totalQty 或 openQty 任一不一致 → 需要更新
return !sameQty(localDetail.totalQty, expectedQty) || !sameQty(localDetail.openQty, plan.openQty)
}
```
`shouldApplyFetchedTaskDetail` —— 是否需要任何处理:
```groovy
private Boolean shouldApplyFetchedTaskDetail(FetchedTaskApplyPlan plan) {
return plan.remoteDetailMissing || plan.shouldUpdateQty || plan.shouldCheckPendingSerialNumbers
}
```
> 三个标志位任一为真才处理;若上游和本地完全一致,明细被跳过,减少无谓写入。
---
### 7.5 applyFetchedTaskReturnedDetail —— 上游有该明细:同步
```groovy
private void applyFetchedTaskReturnedDetail(receipt, localDetail, incoming, plan) {
if (plan.shouldUpdateQty) updateFetchedTaskDetailQty(localDetail.id, plan.openQty) // 改数量
if (plan.shouldCheckPendingSerialNumbers) {
clearFetchedTaskPendingSerialNumbers(receipt, localDetail, collectSerialNumbers(incoming.serialNumbers))
// 清理本地"待分配(CREATED)"状态的 UID,保留上游回传的 UID 列表
}
}
```
`updateFetchedTaskDetailQty` 的 SQL(一次性重算三个数量字段):
```sql
update receipt_detail
set totalQty = coalesce(fulfillQty,0) + coalesce(rejectedQty,0) + :openQty,
quantity = coalesce(fulfillQty,0) + coalesce(rejectedQty,0) + :openQty,
openQty = :openQty,
version = version + 1
where id = :receiptDetailId
```
> `totalQty` 与 `quantity` 同步保持一致,`openQty` 为新的待上架量,版本号自增防并发。
---
### 7.6 applyFetchedTaskMissingDetail —— 上游无该明细:删 / 调
```groovy
private ResponseMessage applyFetchedTaskMissingDetail(receipt, localDetail, plan) {
if (isFetchedTaskDetailUnworked(localDetail)) { // 该明细"完全没动过"
clearFetchedTaskPendingSerialNumbers(receipt, localDetail) // 先清 UID
ResponseMessage rsp = rdSvc.deleteEntity(localDetail) // 再删明细
if (rsp.hasError()) return rsp
return success([deleted: true])
}
// 已动过(收过货/有容器)→ 不能删,只能把 openQty 清零对齐上游
if (plan.shouldUpdateQty) updateFetchedTaskDetailQty(localDetail.id, plan.openQty) // openQty=0
return success([deleted: false])
}
```
`isFetchedTaskDetailUnworked` —— 判断明细是否"原封未动":
```groovy
private Boolean isFetchedTaskDetailUnworked(ReceiptDetail d) {
return sameQty(d.fulfillQty, 0) // 未收货
&& sameQty(d.totalQty, toBigDecimal(d.openQty)) // totalQty == openQty(没收过也没拒过)
&& !existsReceiptContainer(d.receiptId, d.id) // 没有任何收货容器记录
}
```
> 设计意图:上游把明细删了,本地若完全没处理过就跟着删;若已经收过货(有容器/有数量),只能把待上架量清零,保留已收货事实,避免库存凭空消失。
---
### 7.7 shouldDeleteFetchedTaskReceipt —— 整单删除判断
```groovy
private Boolean shouldDeleteFetchedTaskReceipt(Long receiptId) {
Integer count = template().queryForObject(
'SELECT COUNT(1) FROM receipt_detail WHERE receiptId = ?', Integer.class, receiptId) ?: 0
return count == 0 // 明细全被删光 → 整单也删
}
```
`deleteFetchedTaskReceiptRelatedData` —— 删单前清理关联数据(顺序很重要):
```sql
delete from receipt_container where receiptId = ?; -- 收货容器
delete from serial_number where receiptId = ?; -- 序列号
-- 池子里的不删记录,只解绑:
update serial_number_pool
set receiptId = 0, receiptDetailId = 0, receiptCode = null,
assignedAt = null, assignedBy = null, version = version + 1
where receiptId = ?;
```
> 容器、UID 先删,再删单头(`rhSvc.deleteEntity`)。`serial_number_pool` 采用**解绑而非删除**,保留池中 UID 供复用。
---
### 7.8 clearFetchedTaskPendingSerialNumbers —— UID 清理
清理本地 `CREATED`(待分配)状态的 UID,可选保留上游回传的 UID:
```groovy
private void clearFetchedTaskPendingSerialNumbers(receipt, localDetail, List<String> keepSerialNumbers = null) {
// 1. 查出要清的 UIDstatus=CREATED 且 非保留列表)
// keepCondition: 若 keepSerialNumbers 非空,加 "AND serialNumber NOT IN (:keep)"
List<String> clearSerialNumbers = query(...)
// 2. 物理删除
delete from serial_number
where receiptId = :receiptId and itemCode = :itemCode
and status = :createdStatus
and serialNumber in (:clearSerialNumbers)
}
```
只删 `CREATED` 状态,**不影响已收货/已上架的 UID**。
---
### 7.9 三层锁总览
| 层级 | 锁键 | 作用 |
|------|------|------|
| ① 任务领取 | `(receipt_header表, 'shopeeInboundSearch', whsCode, companyCode)` | 防多实例并发领取同一批单据 |
| ② 单据级 | `(warehouseCode, companyCode, code)` via `rhSvc.tryLockByCode` | 防同一入库单被并发反查/收货/上架 |
| ③ 明细级 | `rdSvc.getLockKey(session, detailId)` | 防同一明细被并发修改;锁内二次查证 |
任一层抢锁失败都直接返回 `MSG_GNRL_0003`(资源占用),不再继续。
---
### 7.10 落库结果数据流总结
```
List<ReceiptDataWrapper> (上游返回)
│ removeOutboundSerialNumbers 清洗
for each receipt:
├─ tryLockByCode (单据锁)
│ ├─ findFirstEntity → 本地无单? → MSG_INBD_0003
│ ├─ checkIsAvailable → 不可用? → 错误
│ ├─ 明细键匹配 → 上游多余明细? → MSG_INBD_0004
│ └─ for each localDetail:
│ ├─ buildPlan (锁外快判) → 无变化? continue
│ ├─ getAndTryLock (明细锁) → 抢不到? → MSG_GNRL_0003
│ │ ├─ getEntity 重载 + buildPlan (锁内复判)
│ │ ├─ 上游有 → applyReturnedDetail (改数量/清UID) → syncedDetailIds
│ │ └─ 上游无 → applyMissingDetail (删明细 or openQty=0) → deletedDetailIds?
│ └─ unlock
├─ 明细全删? → deleteFetchedTaskReceiptRelatedData + deleteEntity → deleted:true
└─ else → updateStatus + updateStatistics → synced/deleted ids
```
---
## 8. 请求 / 响应
### 8.1 HTTP 请求
`POST /api/wms/schedule/searchShopeeInboundOrderList`
请求体(JSON,query 参数同名亦可):
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `warehouseCode` | string | 否 | 仓库编码。**为空时遍历所有启用仓库**;指定时只处理单仓 |
| `companyCode` | string | 否 | 货主编码。用于过滤未完成任务领取范围 |
| `taskIdList` | array\<string\> | 否 | 显式指定要反查的任务号列表。**不传**则自动从本地未完成 Shopee 入库单中领取一批(默认 50 条) |
| `createdWithinMonths` | integer | 否 | 自动领取时只扫近 N 个月的单据,默认 6,非正数回退到 6 |
> 常见调用形态:
> - 定时任务:不传 `taskIdList`,由系统按节流策略自动领取。
> - 手工反查:传 `taskIdList` 精确反查某些任务号。
### 8.2 HTTP 响应
由于 Controller 仅投递异步消息,**HTTP 层固定立即返回成功**:
```json
{ "success": true, "code": "...", "msg": "..." }
```
> 实际反查/落库结果不会通过此 HTTP 响应返回,需通过 `ProcessHistory`(处理历史日志)或队列消费结果观察。日志类型 `ShopeeInboundOrderSearch`,级别 INFO/ERROR,内容包含仓库、货主、任务号数量、返回总数或错误信息。
### 8.3 业务层(消费端)返回结构(参考)
- 单仓成功:`applyFetchedInboundTaskResult` 返回 `{ total, results: [{code, success, message}] }`
- 多仓成功:`searchInboundOrderList` 返回 `[{warehouseCode, success, message, data}, ...]`
---
## 9. 关键设计点与约束
| 项 | 说明 |
|----|------|
| 异步化 | HTTP 入口只投递 `AisMessage`,重逻辑在 `wms.api.searchShopeeInboundOrderList` 队列消费端执行,避免计划任务超时 |
| 单次任务上限 | `MAX_SEARCH_TASK_COUNT = 2000`,超出返回 `MSG_BASE_0024` |
| 默认领取数 | `DEFAULT_CLAIM_TASK_COUNT = 50`(未指定 taskIdList 时每轮领取条数) |
| 反查节流 | 通过 `ReceiptHeader.customInboundSearchNextTime` 实现;领取后推进下次时间,降低重复反查 |
| 并发控制 | 三层锁:领取阶段 Redis 锁(按仓库+货主);应用阶段按入库单号锁;明细应用阶段按明细锁 |
| 数据来源 | `sourceErp = SHOPEE` 过滤;仅处理 Shopee 来源单据 |
| 数据清洗 | 落库前 `removeOutboundSerialNumbers` 过滤已出库 UID,避免脏数据回写 |
| 容错 | 反查过程日志失败不影响主流程(`logInboundTaskSearchProcess` 内部 catch Throwable |
| 上游协议 | Shopee `2_5_shopee_inbound_order_searchInboundOrderList`;请求体 `{whs_id, task_id_list}`;返回 `List<ReceiptDataWrapper>` |
| 边界 | 显式 `taskIdList` 查询且上游返回空 → 视为"未查询到入库任务"错误 |
---
## 10. 配套接口(同模块相关)
| 方法 | 用途 |
|------|------|
| `searchInboundOrderByCode` | 按单个本地入库单号反查并应用(封装成单元素 taskIdList |
| `fetchInboundOrder` | 按搜索码(容器号/单号)向 Shopee 拉单,**只查不存** |
| `requestInboundOrder` | `fetchInboundOrder` + `save`,拉取并落库 |
| `searchInboundOrderListToWms` | 反向:Shopee 查询 WES 本地任务(Shopee 2.3 协议),查本地 `ReceiptHeader/Detail` 返回 |
| `submitPutaway` | 上架确认回传 Shopee2.7 协议) |
| `checkUidList` | 批量校验待上架 UID(2.9 协议) |
| `applyUpdatedInboundOrder` | Shopee 下发入库单变更(2.2 协议) |
---
*文档基于源码生成,涉及类:`ScheduleApiController` / `SearchShopeeInboundOrderList` / `ShopeeInboundService` / `ReceiptInboundOrderService` / `EdiRouteReqService`。*
@@ -713,7 +713,7 @@ changeFlowPickWave(workstation, cell, rule):
`shipmentType`, `pickType`, `sourcePlatform`, `sourceErp`, `erpOrderType`, `route`, `carrierCode`, `shipmentSubType`, `shipmentCategory2~8`, `shipToCountry/State/City/District/Town(Code)`, `hostCompanyCode`, `storeCode`, `shipObjType`, `requestedDeliveryType`, `priority`, `userDef1~8`
**规则字段(16):**
`channelId`, `fulfillmentChainId`, `orderSize`, `skuSizeType`, `categoryLevel1Id`, `shopGroup`, `shopId`, `urgentFlag`, `outerPackaging`, `outerPackagingId`, `deliveryRegion`, `fragile`, `liquid`, `highValue`, `battery`, `danger`
`channelId`, `fulfillmentChainId`, `orderSize`, `skuSizeType`, `categoryLevel1Id`, `shopGroup`, `shopId`, `urgentFlag`, `outerPackagingType`, `outerPackagingId`, `deliveryRegion`, `fragile`, `liquid`, `highValue`, `battery`, `danger`
### 13.5 V1.4 新增/待确认匹单字段
@@ -261,7 +261,7 @@ POST /findBestMatchedRule
**字段白名单**(防 SQL 拼接注入):
- **出库单字段**30+):`shipmentType``ticketType``pickType``sourcePlatform``sourceErp``route``carrierCode``shipToCountry``userDef1-8`
- **规则字段**16):`channelId``fulfillmentChainId``orderSize``skuSizeType``categoryLevel1Id``shopGroup``shopId``urgentFlag``outerPackaging``deliveryRegion``fragile``liquid``highValue``battery``danger`
- **规则字段**16):`channelId``fulfillmentChainId``orderSize``skuSizeType``categoryLevel1Id``shopGroup``shopId``urgentFlag``outerPackagingType``deliveryRegion``fragile``liquid``highValue``battery``danger`
补充口径: