Files
baiyue-firstleg/lastleg-service/src/main/resources/openapi/overseas-pda-operations-v1.yaml
T
2026-10-19 17:56:36 +08:00

1460 lines
80 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.0.3
info:
title: Lastleg Overseas PDA Warehouse Operations API
version: 1.1.0
description: 海外仓PDA排车拣货发车、一件代发出库、盘点、同仓整托移库、托盘与换标作业;全部范围从PDA Token解析,派送不进入PDA。
security:
- bearerAuth: []
paths:
/api/pda/v1/last-leg/dispatches:
get:
summary: 读取Token绑定仓五阶段整车任务
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。不接收客户或仓库范围参数;真实客户归属保留在items,整车公共版本及Gate由服务端返回。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- type: array
items:
$ref: overseas-business-v1.yaml#/components/schemas/DispatchPdaTask
nullable: true
parameters:
- name: stage
in: query
schema:
$ref: overseas-business-v1.yaml#/components/schemas/DispatchStage
/api/pda/v1/last-leg/dispatches/{dispatchNo}:
get:
summary: 读取本仓整车任务及真实货物
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- $ref: overseas-business-v1.yaml#/components/schemas/DispatchPdaTask
nullable: true
parameters:
- name: dispatchNo
in: path
required: true
schema:
type: string
/api/pda/v1/last-leg/dispatches/{dispatchNo}/loading:
get:
summary: 读取本车拣货核平和实际测量依据
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- $ref: overseas-business-v1.yaml#/components/schemas/DispatchLoadingPreview
nullable: true
parameters:
- name: dispatchNo
in: path
required: true
schema:
type: string
/api/pda/v1/last-leg/dispatches/{dispatchNo}/commands/{idempotencyKey}:
get:
summary: 核对本人本仓原命令结果
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- $ref: overseas-business-v1.yaml#/components/schemas/DispatchCommandResult
nullable: true
parameters:
- name: dispatchNo
in: path
required: true
schema:
type: string
- name: idempotencyKey
in: path
required: true
schema:
type: string
/api/pda/v1/last-leg/dispatches/{dispatchNo}/items/{itemId}/pick:
post:
summary: 按本车真实货物来源执行扫码拣货
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。只用整车recordVersion和全载荷幂等键;扫码执行真实库存SHIP,装车完成和发车不重复SHIP。错误或结果未知保留原请求核对。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- $ref: overseas-business-v1.yaml#/components/schemas/DispatchCommandResult
nullable: true
requestBody:
required: true
content:
application/json:
schema:
$ref: overseas-business-v1.yaml#/components/schemas/DispatchPick
parameters:
- name: dispatchNo
in: path
required: true
schema:
type: string
- name: itemId
in: path
required: true
schema:
type: string
/api/pda/v1/last-leg/dispatches/{dispatchNo}/loading-complete:
post:
summary: 真实拣货核平后显式确认装车完成
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。只用整车recordVersion和全载荷幂等键;扫码执行真实库存SHIP,装车完成和发车不重复SHIP。错误或结果未知保留原请求核对。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- $ref: overseas-business-v1.yaml#/components/schemas/DispatchCommandResult
nullable: true
requestBody:
required: true
content:
application/json:
schema:
$ref: overseas-business-v1.yaml#/components/schemas/DispatchLoadingComplete
parameters:
- name: dispatchNo
in: path
required: true
schema:
type: string
/api/pda/v1/last-leg/dispatches/{dispatchNo}/depart:
post:
summary: 完整安排派送后确认实际发车
description: 权限 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate。只用整车recordVersion和全载荷幂等键;扫码执行真实库存SHIP,装车完成和发车不重复SHIP。错误或结果未知保留原请求核对。
security:
- bearerAuth: []
responses:
'200':
description: 统一ApiResponse;业务失败通过code返回,不能仅凭HTTP200判断成功。
content:
application/json:
schema:
type: object
properties:
code:
type: string
message:
type: string
requestId:
type: string
nullable: true
traceId:
type: string
nullable: true
timestamp:
type: string
format: date-time
data:
allOf:
- $ref: overseas-business-v1.yaml#/components/schemas/DispatchCommandResult
nullable: true
requestBody:
required: true
content:
application/json:
schema:
$ref: overseas-business-v1.yaml#/components/schemas/DispatchDepart
parameters:
- name: dispatchNo
in: path
required: true
schema:
type: string
/api/pda/v1/last-leg/outbound-tasks:
get:
summary: 查询Token绑定仓的一件代发出库任务
description: 一件代发复用统一出库任务模型;不接收customerId或warehouseId,派送不进入PDA。
parameters: [{ name: status, in: query, required: false, schema: { type: string } }]
responses:
'200':
description: 出库任务列表;每项包含服务端出库类型 outboundType
content:
application/json:
schema:
type: object
properties:
data: { type: array, items: { $ref: '#/components/schemas/PdaOutboundTask' } }
/api/pda/v1/last-leg/outbound-tasks/resolve/{businessNo}:
get:
summary: 解析出库作业扫码业务号
description: 接受一件代发任务号、出库单号或排车单号;按Token绑定仓返回 OUTBOUND 的 taskNo 或 DISPATCH 的 dispatchNo,PDA据此进入正确作业页。
parameters: [{ name: businessNo, in: path, required: true, schema: { type: string } }]
responses:
'200': { description: 正确作业类型及稳定业务编号 }
'404': { description: 当前绑定仓无此出库或排车任务 }
/api/pda/v1/last-leg/outbound-tasks/{taskNo}:
get:
summary: 查询一件代发出库任务详情
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
responses:
'200':
description: 出库任务、出库项及每条可拣库存位置;inventoryPositionId仅作为pick提交键,不作为用户展示编号
content: { application/json: { schema: { $ref: '#/components/schemas/PdaOutboundTaskDetail' } } }
'404': { description: 当前绑定仓无此任务 }
/api/pda/v1/last-leg/outbound-tasks/{taskNo}/pick:
post:
summary: 按当前出库任务扫码拣货
description: 退货散箱按指定箱唛或SKU提交;选择整托出库的退货任务必须扫描托盘码,不允许逐箱提交。
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/OutboundPick' } } } }
responses: { '200': { description: 更新后的统一出库任务, content: { application/json: { schema: { $ref: '#/components/schemas/PdaOutboundTaskResponse' } } } }, '409': { description: 库存、数量或幂等冲突 } }
/api/pda/v1/last-leg/outbound-tasks/{taskNo}/pallets/{palletNo}/pick:
post:
summary: 扫描出库托盘并原子拣取整托剩余箱件
description: 适用于一件代发、换标、仓储转运和退货整托出库;退货按每箱一条冻结明细核对整托全部预留箱、客户和状态,内容变化拒绝提交。任一库存校验失败则整托回滚。
parameters:
- { name: taskNo, in: path, required: true, schema: { type: string } }
- { name: palletNo, in: path, required: true, schema: { type: string } }
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/IdempotentAction' } } } }
responses: { '200': { description: 整托拣货后的任务, content: { application/json: { schema: { $ref: '#/components/schemas/PdaOutboundTaskResponse' } } } }, '404': { description: 当前任务没有该托盘 }, '409': { description: 出库类型不支持、托盘内容变化、库存不足或幂等冲突 } }
/api/pda/v1/last-leg/outbound-tasks/{taskNo}/complete:
post:
summary: 完成一件代发出库任务
description: 全部托盘及箱件精确拣完后完成;同一完成幂等键返回既有结果,其他键明确冲突。
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/IdempotentAction' } } } }
responses: { '200': { description: COMPLETED任务, content: { application/json: { schema: { $ref: '#/components/schemas/PdaOutboundTaskResponse' } } } }, '409': { description: 未全部拣货或幂等冲突 } }
/api/pda/v1/last-leg/stocktakes:
get:
summary: 查询Token绑定仓盘点任务
parameters:
- { name: page, in: query, schema: { type: integer, minimum: 1, default: 1 } }
- { name: size, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 20 } }
- { name: status, in: query, schema: { type: string, enum: [IN_PROGRESS, SUBMITTED] } }
responses:
'200': { description: 盘点任务分页, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeSummaryPageResponse' } } } }
post:
summary: 按库位或托盘创建盘点任务
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeCreate' } } } }
responses:
'200': { description: 创建后的完整盘点任务, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeDetailResponse' } } } }
/api/pda/v1/last-leg/stocktakes/{taskNo}:
get:
summary: 查询盘点任务详情
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
responses:
'200': { description: 盘点任务及冻结库存位置, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeDetailResponse' } } } }
/api/pda/v1/last-leg/stocktakes/{taskNo}/counts:
post:
summary: 提交一个库存位置的实盘箱数
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeCount' } } } }
responses:
'200': { description: 已计数明细, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeItemResponse' } } } }
'409': { description: 版本或幂等冲突 }
/api/pda/v1/last-leg/stocktakes/{taskNo}/submit:
post:
summary: 提交盘点并按差异调整库存
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeSubmit' } } } }
responses:
'200': { description: 已提交盘点任务, content: { application/json: { schema: { $ref: '#/components/schemas/StocktakeDetailResponse' } } } }
'409': { description: 未全盘、库存版本变化或负库存风险 }
/api/pda/v1/last-leg/inventory-moves:
post:
summary: 同仓整托移库
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/InventoryMove' } } } }
responses:
'200': { description: 移库结果, content: { application/json: { schema: { $ref: '#/components/schemas/InventoryMoveResponse' } } } }
'404': { description: 来源托盘不存在(统一响应实际 HTTP 200,body.code=A0404), content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } }
'409': { description: 跨仓、资源或库存版本冲突 }
/api/platform/v1/last-leg/inventory-moves:
post:
summary: 平台发起海外仓整托移库
description: 平台按海外仓业务标识执行普通库位或 A0 共享溢出位移库;目标虚拟收货位、跨仓和版本冲突均拒绝。
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PlatformInventoryMove' } } } }
responses:
'200': { description: 移库结果, content: { application/json: { schema: { $ref: '#/components/schemas/InventoryMoveResponse' } } } }
'409': { description: 物理资源或本地版本冲突 }
/api/pda/v1/last-leg/inventory/resolve:
post:
summary: 扫码查询Token绑定仓库存
description: 支持箱唛、SKU、入仓码、托盘码或库位码;不接收customerId或warehouseId。
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ScanCode' } } } }
responses:
'200': { description: 匹配的库存位置列表, content: { application/json: { schema: { $ref: '#/components/schemas/InventoryScanResponse' } } } }
/api/pda/v1/last-leg/locations/resolve:
post:
summary: 扫码查询Token绑定仓库位
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ScanCode' } } } }
responses:
'200': { description: 库位及占用摘要, content: { application/json: { schema: { $ref: '#/components/schemas/LocationResponse' } } } }
/api/pda/v1/last-leg/pallets/resolve:
post:
summary: 扫码查询Token绑定仓托盘
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ScanCode' } } } }
responses:
'200': { description: 托盘及其库存内容, content: { application/json: { schema: { $ref: '#/components/schemas/PalletResponse' } } } }
'404': { description: 托盘不存在(统一响应实际 HTTP 200,body.code=A0404), content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } }
/api/pda/v1/last-leg/operations:
get:
summary: 查询当前操作人的仓内操作历史
parameters:
- { name: page, in: query, schema: { type: integer, minimum: 1, default: 1 } }
- { name: size, in: query, schema: { type: integer, minimum: 1, maximum: 200, default: 20 } }
- { name: operationType, in: query, required: false, schema: { type: string } }
responses:
'200': { description: 当前Token绑定仓及操作人的历史分页, content: { application/json: { schema: { $ref: '#/components/schemas/OperationPageResponse' } } } }
/api/pda/v1/last-leg/pallet-operations/pallets/resolve:
post:
summary: 扫码查询托盘及库存内容
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ScanCode' } } } }
responses: { '200': { description: Token绑定仓托盘内容 }, '404': { description: 托盘不存在(统一响应实际 HTTP 200,body.code=A0404), content: { application/json: { schema: { $ref: '#/components/schemas/ApiResponse' } } } } }
/api/pda/v1/last-leg/pallet-operations/relabel-sources:
post:
summary: 查询换标原入仓单在各托盘上的库存数量
description: 范围取Token冻结仓和换标单客户;返回库存组成而非历史箱唛定位。movablePackages不包括其他单据冻结、已分配或已拣货箱数。cartonMarks为同来源库存池候选,不代表这些箱历史上位于该托盘。
requestBody:
required: true
content:
application/json:
schema: { type: object, required: [relabelNo], properties: { relabelNo: { type: string, maxLength: 64 } } }
responses:
'200':
description: 原入仓单托盘组成
content:
application/json:
schema:
type: object
properties:
code: { type: string }
data: { type: array, items: { $ref: '#/components/schemas/RelabelSource' } }
'409': { description: 状态、认领人或仓库不符 }
/api/pda/v1/last-leg/pallet-operations/relabel-pallet-label:
post:
summary: 为换标拆托幂等生成并返回可打印的新托盘标签
description: 返回空托盘编码、初始版本和打印HTML;随后可将该托盘作为relabel-disassemble的target。库存移入后仍继承原库存余额对应的客户和入库单。
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/NewRelabelPallet' } } } }
responses: { '200': { description: 新托盘及可打印标签,已认领处理中无需客户确认即可创建 }, '409': { description: 状态、认领人或Token绑定仓不符 } }
/api/pda/v1/last-leg/pallet-operations/assemble:
post:
summary: 将多个来源托盘的指定库存行组到目标托盘
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PalletAssemble' } } } }
responses: { '200': { description: 组托及实物托盘状态结果 }, '409': { description: 目的仓、库存或资源版本冲突 } }
/api/pda/v1/last-leg/pallet-operations/disassemble:
post:
summary: 将来源托盘库存拆到一个或多个目标托盘
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PalletDisassemble' } } } }
responses: { '200': { description: 拆托结果 }, '409': { description: 库存或资源版本冲突 } }
/api/pda/v1/last-leg/pallet-operations/relabel-disassemble:
post:
summary: 按换标箱唛拆托并绑定目标托盘
description: PDA选择原入仓单库存行并扫描实际来源托盘,输入拆出箱数,核对本批cartonMarks后扫描目标托盘。传actualSource时以其数量和版本为准,同入仓余额及批次内原子调整本单冻结记账位置,再移动冻结库存和换标明细;不新增入库、不改变库存归属、不占用其他单据冻结量。每次一个来源库存行,可分批处理多个托盘。已有出库单时不允许此数量重分配。未传actualSource的箱唛模式仍要求已有来源仓位一致。普通库存整托全部换标允许目标与来源为同一托盘,校验整托数量和本单冻结归属后仅记录绑定、不搬移库存;部分换标必须使用新托盘。按箱实测的仓储转运按实测箱追踪移托:来源扣除移出箱体积重量,目标增加同箱数据;同规格自动分配,混合箱规通过measuredCartons选择实际箱,改绑保留首次来源箱身份。其他整托测量来源仍按原规则补测。
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelPalletDisassemble' } } } }
responses: { '200': { description: 箱唛级拆托绑定结果 }, '409': { description: 箱唛、库存或托盘版本冲突 } }
/api/pda/v1/last-leg/pallet-operations/relabel-pallet-measurements:
post:
summary: 查询仓储转运换标涉及托盘的最终测量及库存版本
description: 权限 lastleg:pda:operate 及海外PDA角色;仅Token绑定仓。按箱实测的仓储转运返回cartonAggregated=true,按当前实测箱自动汇总,不要求整托长宽高或人工确认;箱数与当前库存必须一致且每箱尺寸重量有效。其他整托测量来源沿用原始测量或补测。测量保存为PALLET_MEASURE作业历史,库存版本变化后失效。
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [relabelNo]
properties:
relabelNo: { type: string, maxLength: 64 }
responses: { '200': { description: '托盘业务码、箱数、stockVersion、长宽高cm、毛重kg、体积m³及inherited;按箱测量的原托盘不虚构整托尺寸,长宽高为null,sourceCartonSpecs返回按箱规分组的lengthCm/widthCm/heightCm/grossWeightKg(每箱)/cartons;cartonAggregated表示按箱自动汇总,cartons返回当前托盘实测箱的cartonMark、customerCartonMark及尺寸重量,移托后自动重新汇总。其他来源换标返回空列表' }, '409': { description: 不属于当前仓 } }
/api/pda/v1/last-leg/pallet-operations/relabel-pallet-measure:
post:
summary: 确认仓储转运换标托盘最终实测
description: 已认领的操作员可在处理中保存;待出库但未排车亦可补测。保存当前stockVersion及实测长宽高、毛重,服务端计算体积;相同幂等键异载荷拒绝,库存变化要求刷新。按箱实测托盘拒绝手动整托测量,直接使用箱数据。排车前核验所有相关非空托盘,包括原托盘余货。
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [relabelNo, palletCode, stockVersion, idempotencyKey, lengthCm, widthCm, heightCm, grossWeightKg]
properties:
relabelNo: { type: string, maxLength: 64 }
palletCode: { type: string, maxLength: 128 }
stockVersion: { type: string, description: 查询返回的当前库存版本指纹 }
idempotencyKey: { type: string, maxLength: 128 }
lengthCm: { type: number, minimum: 0.01, multipleOf: 0.01 }
widthCm: { type: number, minimum: 0.01, multipleOf: 0.01 }
heightCm: { type: number, minimum: 0.01, multipleOf: 0.01 }
grossWeightKg: { type: number, minimum: 0.01, multipleOf: 0.001 }
responses: { '200': { description: 已保存并返回全部相关托盘测量 }, '409': { description: 版本、归属、状态、认领人或幂等载荷冲突 } }
/api/pda/v1/last-leg/pallet-operations/swap:
post:
summary: 将整托库存更换到空目标托盘
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PalletSwap' } } } }
responses: { '200': { description: 换托结果 }, '409': { description: 目标托盘非空或版本冲突 } }
/api/pda/v1/last-leg/pallet-operations/unbind:
post:
summary: 解除整托库存与实物托盘绑定
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/PalletUnbind' } } } }
responses: { '200': { description: 解绑结果 }, '409': { description: 库存或资源版本冲突 } }
/api/pda/v1/last-leg/relabel-tasks/candidates:
get:
summary: 查询Token绑定仓可执行换标任务
responses:
'200': { description: 待认领、处理中或待复核换标任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelCandidatesResponse' } } } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}:
get:
summary: 查询换标现场任务详情
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
responses:
'200': { description: 申请明细、逐件事实、照片与历史, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/claim:
post:
summary: 认领换标任务并推进申请至处理中
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/IdempotentAction' } } } }
responses: { '200': { description: 已认领任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } }, '409': { description: 仓库、状态或幂等冲突 } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/units:
post:
summary: 扫描我方箱唛并登记整箱正常换标事实;可只传oldLabel由服务端定位箱唛任务
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelUnit' } } } }
responses: { '200': { description: 更新后的任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } }, '409': { description: 旧标重复、新标不符或版本冲突 } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/skus/scan:
post:
summary: 仅扫描旧SKU完成当前箱的一条SKU换标明细
description: itemId与skuIndex精确指定一条明细,服务端验证旧SKU并读取已批准的新SKU及件数;同旧SKU多箱由PDA选择目标,不批量隐式完成。逐条写SKU_SCAN历史并按轮次防重,全部SKU处理后完成SKU阶段,混合单仍须完成箱唛阶段。响应history包含旧新SKU、件数及索引,供提示与隐藏已处理明细。
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [itemId, skuIndex, oldSku, expectedVersion, idempotencyKey]
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
skuIndex: { type: integer, minimum: 0 }
oldSku: { type: string, maxLength: 255 }
cartonMark: { type: string, maxLength: 128, description: 退货SKU作业必填,须扫描当前实体来源包裹或箱 }
newSkuCode: { type: string, maxLength: 128, description: 退货SKU作业必填,须与批准的目标标签一致 }
quantity: { type: integer, minimum: 1, description: 退货SKU作业必填,须与本明细批准件数一致 }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
responses:
'200': { description: 更新后的任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } }
'409': { description: 已处理、映射不符、认领人或版本冲突 }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/return-skus/complete:
post:
summary: 扫描来源包裹或箱及SKU登记退货按件换标实际完成量
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [itemId, quantity, expectedVersion, idempotencyKey, cartonMark, skuCode]
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
quantity: { type: integer, minimum: 1 }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
cartonMark: { type: string, maxLength: 128 }
skuCode: { type: string, maxLength: 128 }
responses: { '200': { description: 更新后Detail;同键同请求重放 }, '409': { description: 来源、SKU、剩余件数或版本冲突 } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/return-skus/complete-total:
post:
summary: 单一来源的退货SKU按件完成
description: 同SKU涉及多个来源包裹或箱时拒绝自动分配,必须逐来源扫码。
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [skuCode, quantity, expectedVersion, idempotencyKey]
properties:
skuCode: { type: string }
quantity: { type: integer, minimum: 1 }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string }
responses: { '200': { description: 更新后Detail }, '409': { description: 多来源或数量冲突 } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/return-cartons/pack:
post:
summary: 将本任务已完成的退货SKU件数隔离合箱为独立新箱
description: 必须由认领人在PROCESSING阶段完成所有申请明细后执行;原包裹余量守恒,保留跨退货单追溯。响应Detail的items切换为新箱,history的RETURN_PACK.detail JSON含round、sourceCartonMarks、sourceDeductions、cartonMark、quantity和label.printableHtml。标签为仓库识别标签,与商品换标资料分开。同键重放原结果。
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [sourceCartonMarks, idempotencyKey, length, width, height, weight]
properties:
sourceCartonMarks: { type: array, minItems: 1, maxItems: 100, items: { type: string } }
targetCartonMark: { type: string, nullable: true, description: 必须为空,由系统生成独立新箱 }
idempotencyKey: { type: string, maxLength: 255 }
sourceDeductions:
type: array
description: 可省略由服务端生成;填写时按来源箱和SKU汇总必须与本任务完成明细一致
items:
type: object
required: [cartonMark, skuCode, quantity]
properties:
cartonMark: { type: string }
skuCode: { type: string }
quantity: { type: integer, format: int64, minimum: 1 }
length: { type: number, exclusiveMinimum: true, minimum: 0 }
width: { type: number, exclusiveMinimum: true, minimum: 0 }
height: { type: number, exclusiveMinimum: true, minimum: 0 }
weight: { type: number, exclusiveMinimum: true, minimum: 0 }
responses: { '200': { description: 更新后Detail含新箱识别标签 }, '409': { description: 未完成申请、来源变动或数量冲突 } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/units/skip:
post:
summary: 登记一件有原因的跳过事实
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelSkip' } } } }
responses: { '200': { description: 更新后的任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/exceptions:
post:
summary: 登记一件换标异常事实
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelException' } } } }
responses: { '200': { description: 更新后的任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/photos/files:
post:
summary: 上传换标完成现场照片
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { multipart/form-data: { schema: { type: object, required: [file], properties: { file: { type: string, format: binary } } } } } }
responses: { '200': { description: OVERSEAS_RELABEL_PHOTO文件元数据, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelPhotoResponse' } } } } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/photos/files/{fileId}/download:
get:
summary: 读取当前操作人处理中任务的已上传照片,用于缩略图和大图预览
description: 校验 Token 绑定仓、任务认领人和文件的客户及任务归属;移除和重拍只替换待提交文件引用,不删除历史文件。
parameters:
- { name: relabelNo, in: path, required: true, schema: { type: string } }
- { name: fileId, in: path, required: true, schema: { type: integer, format: int64 } }
responses:
'200': { description: 作业照片内容, content: { 'image/*': { schema: { type: string, format: binary } } } }
'404': { description: 照片不属于当前任务或仓库 }
'409': { description: 当前操作人未认领任务或任务不在处理中 }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/complete:
post:
summary: 提交现场任务到复核池并直接等待客户确认
description: 按箱测量的仓储转运换标自动汇总各托盘剩余实测箱的体积重量,无需确认整托实测;箱数据不全或库存箱数不符时拒绝完成。其他整托来源仍校验有效实测尺寸和重量;手动完成也不能跳过校验。缺失或库存版本变化导致实测失效时,保持处理中并提示补测。
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelComplete' } } } }
responses: { '200': { description: WAIT_REVIEW任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } }, '409': { description: 托盘实测缺失或失效、箱数未核平、照片或版本冲突 } }
/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/review:
post:
summary: 已停用;客户确认完成复核,退回重贴由平台执行
deprecated: true
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelReview' } } } }
responses: { '200': { description: COMPLETED或PROCESSING任务, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelDetailResponse' } } } }, '409': { description: 状态或版本冲突 } }
/api/pda/v1/last-leg/warehouse-transfers/candidates:
get:
summary: 查询Token绑定仓待测量的仓储转运单
description: 仅返回当前PDA冻结海外仓内已审核且等待测量打托的转运单;不接收customerId或warehouseId。
responses:
'200':
description: 待测量转运单列表
content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferSummaryListResponse' } } }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}:
get:
summary: 查询当前仓仓储转运测量详情
parameters: [{ name: transferNo, in: path, required: true, schema: { type: string } }]
responses:
'200':
description: 转运申报、已生成的新托盘及测量照片;items仅为服务端自动分摊结果,PDA不提交每托SKU。
content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferDetailResponse' } } }
'404': { description: 当前Token绑定仓无此转运单 }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/measurement-photos/files:
get:
summary: 查询当前转运单已上传的测量现场照片
parameters: [{ name: transferNo, in: path, required: true, schema: { type: string } }]
responses:
'200': { description: 照片元数据列表 }
post:
summary: 上传仓储转运测量现场照片
parameters: [{ name: transferNo, in: path, required: true, schema: { type: string } }]
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file]
properties: { file: { type: string, format: binary } }
responses:
'200': { description: 已绑定当前转运单的照片元数据 }
'404': { description: 当前Token绑定仓无此转运单 }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/measurement-photos/files/{fileId}/download:
get:
summary: 鉴权下载仓储转运测量现场照片
parameters:
- { name: transferNo, in: path, required: true, schema: { type: string } }
- { name: fileId, in: path, required: true, schema: { type: integer, format: int64 } }
responses:
'200': { description: 照片内容, content: { 'image/*': { schema: { type: string, format: binary } } } }
'404': { description: 照片不属于当前转运单或绑定仓 }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/palletize:
post:
summary: 完成仓储转运整单测量打托
description: 只提交当前转运单照片和整单幂等键;所有托盘必须已逐托生成并扫码绑定,箱数必须核平。此接口不接收测量字段、托盘码或每托SKU,也绝不再次生成托盘。
parameters: [{ name: transferNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferPalletize' } } } }
responses:
'200':
description: WAIT_CUSTOMER_CONFIRMATION详情
content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferDetailResponse' } } }
'409': { description: 状态、照片归属、箱数核平或幂等冲突 }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/pallets/drafts:
post:
summary: 新建或更新一个转运测量托盘草稿
description: palletId为空时创建DRAFT;传入既有DRAFT的palletId时更新。GENERATED及以后测量字段锁定,必须拒绝修改。
parameters: [{ name: transferNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferPalletDraft' } } } }
responses: { '200': { description: 包含持久化草稿的最新整单详情 }, '409': { description: 草稿已生成、状态或幂等冲突 } }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/pallets/{palletId}:
delete:
summary: 删除未生成的转运托盘草稿
description: 只允许删除DRAFT;GENERATED、BOUND和COMPLETED不得删除。
parameters:
- { name: transferNo, in: path, required: true, schema: { type: string } }
- { name: palletId, in: path, required: true, schema: { type: integer, format: int64 } }
responses: { '200': { description: 删除后的整单详情 }, '409': { description: 本托已经生成真实托盘 } }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/pallets/{palletId}/generate:
post:
summary: 为测量草稿生成一个全新实物托盘
description: 只允许DRAFT调用一次;服务端始终向Warehouse Overseas传空palletCode,不能复用已有托盘。有FBA则写入目的仓,无FBA则标签显示“目的仓待定”。成功后实测字段锁定且可立即下载PDF标签。
parameters:
- { name: transferNo, in: path, required: true, schema: { type: string } }
- { name: palletId, in: path, required: true, schema: { type: integer, format: int64 } }
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferPalletAction' } } } }
responses: { '200': { description: 包含GENERATED新托盘号和标签路径的最新详情 }, '409': { description: 已生成或资源生成冲突 } }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/pallets/{palletId}/bind:
post:
summary: 扫描并确认本托新生成的托盘码
description: 扫描码必须精确等于本草稿服务端生成码,同时验证Warehouse Overseas物理托盘ID和Token冻结仓一致;其他已有托盘不得冒充。
parameters:
- { name: transferNo, in: path, required: true, schema: { type: string } }
- { name: palletId, in: path, required: true, schema: { type: integer, format: int64 } }
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/WarehouseTransferPalletBind' } } } }
responses: { '200': { description: 包含BOUND事实和boundAt的最新详情 }, '409': { description: 扫描码、归属、仓库或状态不匹配 } }
/api/pda/v1/last-leg/warehouse-transfers/{transferNo}/pallets/{warehousePalletId}/label:
get:
summary: 下载仓储转运实物托盘PDF标签
description: 校验Token冻结仓、转运单和托盘归属后,代理Warehouse Overseas使用统一托盘标签打印服务生成真实PDF。已知FBA显示目的仓编码,未知FBA显示“目的仓待定”。
parameters:
- { name: transferNo, in: path, required: true, schema: { type: string } }
- { name: warehousePalletId, in: path, required: true, schema: { type: integer, format: int64 } }
- { name: X-Request-Id, in: header, required: false, schema: { type: string } }
responses:
'200': { description: 托盘标签PDF, content: { application/pdf: { schema: { type: string, format: binary } } } }
'404': { description: 转运单或托盘不属于当前Token绑定仓 }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer, bearerFormat: JWT }
schemas:
ApiResponse:
type: object
required: [code, data]
properties:
code: { type: string, example: '200' }
message: { type: string, nullable: true }
data: { nullable: true }
requestId: { type: string, nullable: true }
traceId: { type: string, nullable: true }
timestamp: { type: string, format: date-time, nullable: true }
WarehouseTransferSummaryListResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties:
data: { type: array, items: { $ref: '#/components/schemas/WarehouseTransferSummary' } }
WarehouseTransferDetailResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/WarehouseTransferDetail' } }
WarehouseTransferSummary:
type: object
required: [id, transferNo, operatingWarehouseId, packageCount, deliveryMethod, needRelabel, status]
properties:
id: { type: integer, format: int64 }
transferNo: { type: string }
inboundCode: { type: string, nullable: true }
operatingWarehouseId: { type: string }
fbaWarehouseCode: { type: string, nullable: true, description: 为空表示目的仓待定 }
packageCount: { type: integer, minimum: 1 }
deliveryMethod: { type: string }
needRelabel: { type: boolean }
relabelNo: { type: string, nullable: true }
status: { type: string }
estimatedArrivalAt: { type: string, format: date-time, nullable: true }
createdAt: { type: string, format: date-time, nullable: true }
WarehouseTransferDetail:
type: object
required: [id, transferNo, operatingWarehouseId, packageCount, status, pallets, measurementPhotos]
properties:
id: { type: integer, format: int64 }
transferNo: { type: string }
operatingWarehouseId: { type: string }
fbaWarehouseCode: { type: string, nullable: true, description: 为空表示目的仓待定 }
pickupContactName: { type: string, nullable: true }
pickupContactPhone: { type: string, nullable: true }
packageCount: { type: integer, minimum: 1 }
status: { type: string }
pallets: { type: array, items: { $ref: '#/components/schemas/WarehouseTransferPallet' } }
measurementPhotos: { type: array, items: { $ref: '#/components/schemas/WarehouseTransferMeasurementPhoto' } }
WarehouseTransferPalletize:
type: object
required: [idempotencyKey, photoFileIds]
properties:
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
discrepancyReason: { type: string, maxLength: 1000, nullable: true, description: 任一SKU实收件数与预报不同时完成测量必填,原因随完成事务保存 }
photoFileIds:
type: array
minItems: 1
maxItems: 20
uniqueItems: true
items: { type: integer, format: int64, minimum: 1 }
WarehouseTransferPalletDraft:
type: object
required: [idempotencyKey, cartonCount, lengthCm, widthCm, heightCm, volumeCbm, grossWeightKg]
properties:
palletId: { type: integer, format: int64, nullable: true, description: 更新现有DRAFT时传入;创建时不传 }
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
cartonCount: { type: integer, minimum: 1 }
lengthCm: { type: number, format: double, minimum: 0.01 }
widthCm: { type: number, format: double, minimum: 0.01 }
heightCm: { type: number, format: double, minimum: 0.01 }
volumeCbm: { type: number, format: double, minimum: 0.000001 }
grossWeightKg: { type: number, format: double, minimum: 0.01 }
WarehouseTransferPalletAction:
type: object
required: [idempotencyKey]
properties: { idempotencyKey: { type: string, minLength: 1, maxLength: 255 } }
WarehouseTransferPalletBind:
type: object
required: [palletCode, idempotencyKey]
properties:
palletCode: { type: string, minLength: 1, maxLength: 128 }
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
WarehouseTransferPallet:
type: object
required: [id, sequenceNo, cartonCount, lengthCm, widthCm, heightCm, volumeCbm, grossWeightKg, status]
properties:
id: { type: integer, format: int64 }
sequenceNo: { type: integer, minimum: 1 }
warehousePalletId: { type: integer, format: int64, nullable: true }
palletNo: { type: string, nullable: true, description: GENERATED后由Warehouse Overseas为本次测量新生成 }
cartonCount: { type: integer, minimum: 1 }
lengthCm: { type: number, format: double }
widthCm: { type: number, format: double }
heightCm: { type: number, format: double }
volumeCbm: { type: number, format: double }
grossWeightKg: { type: number, format: double }
status: { type: string, enum: [DRAFT, GENERATED, BOUND, COMPLETED] }
fbaWarehouseCode: { type: string, nullable: true, description: 为空时标签显示目的仓待定 }
labelDownloadPath: { type: string, nullable: true, description: GENERATED后返回当前PDA鉴权下的真实PDF下载路径 }
boundAt: { type: string, format: date-time, nullable: true }
WarehouseTransferMeasurementPhoto:
type: object
required: [fileId, sizeBytes, uploadedAt]
properties:
fileId: { type: integer, format: int64 }
fileName: { type: string, nullable: true }
contentType: { type: string, nullable: true }
sizeBytes: { type: integer, format: int64, minimum: 0 }
uploadedAt: { type: string, format: date-time }
StocktakeSummaryPageResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/StocktakeSummaryPage' } }
StocktakeDetailResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/StocktakeDetail' } }
StocktakeItemResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/StocktakeItem' } }
InventoryMoveResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/InventoryMoveResult' } }
InventoryScanResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/InventoryScan' } }
LocationResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/WarehouseLocation' } }
PalletResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/WarehousePallet' } }
OperationPageResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/OperationPage' } }
RelabelCandidatesResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties:
data: { type: array, items: { $ref: '#/components/schemas/RelabelCandidate' } }
RelabelDetailResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/RelabelDetail' } }
RelabelPhotoResponse:
allOf:
- { $ref: '#/components/schemas/ApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/RelabelPhoto' } }
StocktakeSummaryPage:
type: object
required: [records, page, size, total, pages]
properties:
records: { type: array, items: { $ref: '#/components/schemas/StocktakeSummary' } }
page: { type: integer, format: int64 }
size: { type: integer, format: int64 }
total: { type: integer, format: int64 }
pages: { type: integer, format: int64 }
StocktakeSummary:
type: object
required: [taskNo, scopeType, scopeCode, status, positionCount, countedCount, differenceCount, version, createdAt]
properties:
taskNo: { type: string }
scopeType: { type: string, enum: [LOCATION, PALLET] }
scopeCode: { type: string }
status: { type: string, enum: [IN_PROGRESS, SUBMITTED] }
positionCount: { type: integer }
countedCount: { type: integer }
differenceCount: { type: integer }
version: { type: integer, format: int64 }
createdAt: { type: string, format: date-time }
submittedAt: { type: string, format: date-time, nullable: true }
StocktakeItem:
type: object
required: [itemId, customerId, balanceId, positionId, skuCode, inboundCode, palletId, palletCode, locationId, locationCode, bookPackages, status, positionVersion, version]
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
customerId: { type: string }
balanceId: { type: string, pattern: '^[0-9]+$' }
positionId: { type: string, pattern: '^[0-9]+$' }
skuCode: { type: string }
productName: { type: string, nullable: true }
inboundCode: { type: string }
palletId: { type: string, pattern: '^[0-9]+$' }
palletCode: { type: string }
locationId: { type: string, pattern: '^[0-9]+$' }
locationCode: { type: string }
bookPackages: { type: integer, format: int64 }
actualPackages: { type: integer, format: int64, nullable: true }
differencePackages: { type: integer, format: int64, nullable: true }
status: { type: string }
positionVersion: { type: integer, format: int64 }
version: { type: integer, format: int64 }
StocktakeDetail:
type: object
required: [task, items]
properties:
task: { $ref: '#/components/schemas/StocktakeSummary' }
items: { type: array, items: { $ref: '#/components/schemas/StocktakeItem' } }
InventoryMoveResult:
type: object
required: [moveNo, palletId, palletCode, sourceLocationId, sourceLocationCode, targetLocationId, targetLocationCode, customerCount, positionCount, packageCount, palletVersion, status, completedAt, replayed]
properties:
moveNo: { type: string }
palletId: { type: string, pattern: '^[0-9]+$' }
palletCode: { type: string }
sourceLocationId: { type: string, pattern: '^[0-9]+$' }
sourceLocationCode: { type: string }
targetLocationId: { type: string, pattern: '^[0-9]+$' }
targetLocationCode: { type: string }
customerCount: { type: integer }
positionCount: { type: integer }
packageCount: { type: integer, format: int64 }
palletVersion: { type: integer }
status: { type: string }
completedAt: { type: string, format: date-time }
replayed: { type: boolean }
InventoryScan:
type: object
required: [queryCode, items]
properties:
queryCode: { type: string }
items: { type: array, items: { $ref: '#/components/schemas/InventoryItem' } }
InventoryItem:
type: object
required: [customerId, balanceId, positionId, skuCode, inboundCode, palletId, palletCode, availablePackages, holdPackages, receivingPackages, status, version]
properties:
customerId: { type: string }
customerName: { type: string, nullable: true }
balanceId: { type: string, pattern: '^[0-9]+$' }
positionId: { type: string, pattern: '^[0-9]+$' }
skuCode: { type: string }
productName: { type: string, nullable: true }
inboundCode: { type: string }
cartonMark: { type: string, nullable: true }
palletId: { type: string, pattern: '^[0-9]+$' }
palletCode: { type: string }
locationId: { type: string, pattern: '^[0-9]+$', nullable: true }
locationCode: { type: string, nullable: true }
availablePackages: { type: integer, format: int64 }
holdPackages: { type: integer, format: int64 }
receivingPackages: { type: integer, format: int64 }
status: { type: string }
version: { type: integer, format: int64 }
WarehouseLocation:
type: object
required: [locationId, locationCode, locationType, status, occupiedPackages, inventoryPositionCount]
properties:
locationId: { type: string, pattern: '^[0-9]+$' }
locationCode: { type: string }
locationType: { type: string }
maxLoadKg: { type: number, nullable: true }
status: { type: string }
occupiedPackages: { type: integer, format: int64 }
inventoryPositionCount: { type: integer }
WarehousePallet:
type: object
required: [palletId, palletCode, status, version, occupiedPackages, inventoryPositionCount, inventory]
properties:
palletId: { type: string, pattern: '^[0-9]+$' }
palletCode: { type: string }
status: { type: string }
version: { type: integer }
locationId: { type: string, pattern: '^[0-9]+$', nullable: true }
locationCode: { type: string, nullable: true }
occupiedPackages: { type: integer, format: int64 }
inventoryPositionCount: { type: integer }
inventory: { type: array, items: { $ref: '#/components/schemas/InventoryItem' } }
OperationPage:
type: object
required: [records, page, size, total, pages]
properties:
records: { type: array, items: { $ref: '#/components/schemas/WarehouseOperation' } }
page: { type: integer, format: int64 }
size: { type: integer, format: int64 }
total: { type: integer, format: int64 }
pages: { type: integer, format: int64 }
WarehouseOperation:
type: object
required: [operationId, operationType, businessKey, status, occurredAt]
properties:
operationId: { type: string, pattern: '^[0-9]+$' }
operationType: { type: string }
businessKey: { type: string }
status: { type: string }
summary: { type: string, nullable: true }
customerId: { type: string, nullable: true }
occurredAt: { type: string, format: date-time }
RelabelCandidate:
type: object
required: [relabelNo, applicationStatus, taskStatus, operationType, itemCount, expectedPackages, relabelledPackages, skippedPackages, exceptionPackages, version, claimedByCurrentOperator]
properties:
relabelNo: { type: string }
customerOrderNo: { type: string, nullable: true }
labelDeadline: { type: string, format: date-time, nullable: true }
applicationStatus: { type: string }
taskStatus: { type: string }
operationType: { type: string, enum: [SKU_LABEL, CARTON_LABEL, CARTON_AND_SKU] }
itemCount: { type: integer }
expectedPackages: { type: integer }
relabelledPackages: { type: integer }
skippedPackages: { type: integer }
exceptionPackages: { type: integer }
version: { type: integer }
claimedByCurrentOperator: { type: boolean }
RelabelDetail:
type: object
required: [relabelNo, applicationStatus, operationType, taskStatus, expectedPackages, relabelledPackages, skippedPackages, exceptionPackages, version, completionPhotoFileIds, items, unitFacts, history]
properties:
deliveryMethod: { type: string, nullable: true, enum: [TRUCK, EXPRESS, PICKUP, AMAZON_PICKUP, CUSTOMER_PICKUP], description: 申请真实运输方式,纯SKU留仓为空;只有平台卡车TRUCK进入预排车,快递和所有自提直接创建出库任务 }
requiresPalletBinding: { type: boolean, description: 普通库存箱唛或混合换标须实际托盘绑定;退货整箱EXPRESS、PICKUP、AMAZON_PICKUP、CUSTOMER_PICKUP不要求排车组托,TRUCK要求;纯SKU留仓为空派送方式时不要求组托 }
relabelNo: { type: string }
customerOrderNo: { type: string, nullable: true }
labelDeadline: { type: string, format: date-time, nullable: true }
contactName: { type: string, nullable: true }
contactPhone: { type: string, nullable: true }
applicationStatus: { type: string }
operationType: { type: string, enum: [SKU_LABEL, CARTON_LABEL, CARTON_AND_SKU] }
taskStatus: { type: string }
expectedPackages: { type: integer }
relabelledPackages: { type: integer }
skippedPackages: { type: integer }
exceptionPackages: { type: integer }
version: { type: integer }
operatorName: { type: string, nullable: true }
reviewerName: { type: string, nullable: true }
completionPhotoFileIds: { type: array, items: { type: string, pattern: '^[0-9]+$' } }
completionRemark: { type: string, nullable: true }
reviewDecision: { type: string, nullable: true }
reviewRemark: { type: string, nullable: true }
claimedAt: { type: string, format: date-time, nullable: true }
submittedAt: { type: string, format: date-time, nullable: true }
reviewedAt: { type: string, format: date-time, nullable: true }
items: { type: array, items: { $ref: '#/components/schemas/RelabelItem' } }
unitFacts: { type: array, items: { $ref: '#/components/schemas/RelabelUnitFact' } }
history: { type: array, items: { $ref: '#/components/schemas/RelabelHistory' } }
RelabelItem:
type: object
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
skuCode: { type: string, nullable: true }
productNameZh: { type: string, nullable: true }
shipmentNo: { type: string, nullable: true }
trackingCode: { type: string, nullable: true }
newSkuCode: { type: string, nullable: true }
labelRequirement: { type: string, nullable: true }
relabelFileId: { type: string, nullable: true }
relabelFileName: { type: string, nullable: true }
relabelFileUrl: { type: string, nullable: true }
cartonMark: { type: string, nullable: true, description: 我方箱唛 }
fbaCartonMark: { type: string, nullable: true, description: 新FBA箱唛 }
operationType: { type: string, enum: [CARTON_LABEL, SKU_LABEL, CARTON_AND_SKU, RETURN_BULK_SKU_LABEL] }
skuItems: { type: array, items: { $ref: '#/components/schemas/RelabelSkuItem' } }
expectedPackages: { type: integer }
relabelledPackages: { type: integer }
skippedPackages: { type: integer }
exceptionPackages: { type: integer }
cartonProcessedPackages: { type: integer, description: 本轮箱唛作业已完成箱数,混合单独立计数 }
skuProcessedPackages: { type: integer, description: 本轮SKU作业已完成箱数,两项均完成才增加整箱已换标数 }
returnCartonId: { type: string, nullable: true, description: 真实退货包裹或箱ID }
returnQuantity: { type: integer, format: int64, minimum: 0, description: 当前实物包裹或箱全部件数;不是申请量 }
RelabelSkuItem:
type: object
required: [skuCode, newSkuCode, quantity]
properties:
skuCode: { type: string }
newSkuCode: { type: string }
quantity: { type: integer, description: 换标件数 }
remark: { type: string, nullable: true }
RelabelUnitFact:
type: object
properties:
factId: { type: string, pattern: '^[0-9]+$' }
itemId: { type: string, pattern: '^[0-9]+$' }
oldLabel: { type: string, nullable: true }
newLabel: { type: string, nullable: true }
result: { type: string }
exceptionCode: { type: string, nullable: true }
reason: { type: string, nullable: true }
operatorName: { type: string, nullable: true }
occurredAt: { type: string, format: date-time }
RelabelHistory:
type: object
properties:
action: { type: string }
fromStatus: { type: string, nullable: true }
toStatus: { type: string, nullable: true }
operatorName: { type: string, nullable: true }
detail: { type: string, nullable: true }
createdAt: { type: string, format: date-time }
RelabelPhoto:
type: object
required: [fileId, fileName, contentType, sizeBytes]
properties:
fileId: { type: string, pattern: '^[0-9]+$' }
fileName: { type: string }
contentType: { type: string }
sizeBytes: { type: integer, format: int64 }
ScanCode:
type: object
required: [code]
properties: { code: { type: string, minLength: 1, maxLength: 128 } }
NewRelabelPallet:
type: object
required: [relabelNo, idempotencyKey]
properties:
relabelNo: { type: string, minLength: 1, maxLength: 64 }
idempotencyKey: { type: string, minLength: 1, maxLength: 128 }
IdempotentAction:
type: object
required: [idempotencyKey]
properties: { idempotencyKey: { type: string, minLength: 1, maxLength: 255 } }
OutboundPick:
type: object
required: [outboundPalletItemId, packages, idempotencyKey]
properties:
outboundPalletItemId: { type: string, pattern: '^[0-9]+$' }
inventoryPositionId: { type: string, nullable: true, pattern: '^[0-9]+$', description: 普通库存使用真实仓位键;退货箱库存没有该仓位,提交 null,不提交空字符串或退货库存内部ID }
packages: { type: integer, format: int64, minimum: 1 }
productQuantity: { type: integer, format: int64, minimum: 1, nullable: true, description: 单SKU退货明细存在returnSkuQuantity时必填且必须等于计划件数;不接受小数。历史无快照明细可省略 }
skuCode: { type: string, maxLength: 128, nullable: true, description: 仅遗留已创建SKU任务使用;新退货任务必须扫描包裹或箱标签 }
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
cartonMarks:
type: array
maxItems: 500
description: 本次实际扫描的箱唛。退货出库每条明细对应一个真实退货箱,必须提交该箱的 cartonMark,packages 为 1;相同幂等键改传其他箱唛同样拒绝,执行时重新核对客户、仓库及来源退货单。一件代发指定箱唛任务分批拣货时必须提交本次子集,数量与 packages 一致;换标任务仍须提交全部指定箱唛。
items: { type: string, minLength: 1, maxLength: 255 }
PdaOutboundTaskResponse:
type: object
properties:
code: { type: string }
data: { $ref: '#/components/schemas/PdaOutboundTask' }
PdaOutboundTask:
type: object
required: [taskNo, status, outboundNo, outboundType]
properties:
id: { type: string, description: 内部任务键,不作为用户展示编号 }
taskNo: { type: string }
status: { type: string }
outboundNo: { type: string }
outboundType: { type: string, enum: [ONE_CLICK_DROPSHIP, RETURN_OUTBOUND, RELABEL_OUTBOUND, WAREHOUSE_TRANSFER_OUTBOUND, DISPATCH_DELIVERY], description: 正式出库单类型;列表、详情及写操作结果共用此响应 }
pushedAt: { type: string, format: date-time, nullable: true }
completedAt: { type: string, format: date-time, nullable: true }
PdaOutboundTaskDetail:
type: object
required: [task, items]
properties:
task: { $ref: '#/components/schemas/PdaOutboundTask' }
items:
type: array
items:
type: object
required: [outboundPalletItemId, inboundCode, packageCount, pickedPackageCount, status, positions]
properties:
outboundPalletItemId: { type: string, description: pick请求提交键,不作为用户展示编号 }
palletNo: { type: string, nullable: true, description: Warehouse 权威实物托盘码;退货箱明细不伪造托盘码 }
skuCode: { type: string, nullable: true }
returnSkuQuantity: { type: integer, format: int64, nullable: true, minimum: 1, description: 本来源计划出库件数快照;部分拣货后余数保留原箱,PDA不得改变计划件数 }
inboundCode: { type: string }
packageCount: { type: integer }
pickedPackageCount: { type: integer }
status: { type: string }
positions:
type: array
description: 普通出库为真实库存仓位;退货出库为已冻结真实箱的扫码行,inventoryPositionId 与 palletNo 为空,cartonMark 为扫码业务码、inboundCode 为退货单号,按箱计数。已拣或已完成时 availablePackages 为 0,详情查询不写库存。
items:
type: object
required: [inboundCode, availablePackages, pickedPackages]
properties:
inventoryPositionId: { type: string, nullable: true, description: 普通库存的pick提交键;退货箱无仓位键,不得以其内部ID替代 }
palletNo: { type: string, nullable: true, description: Warehouse 权威实物托盘码;退货箱不提供伪造托盘号 }
cartonMark: { type: string, nullable: true }
skuCode: { type: string, nullable: true }
inboundCode: { type: string }
availablePackages: { type: integer, format: int64, minimum: 0 }
pickedPackages: { type: integer, format: int64, minimum: 0 }
StocktakeCreate:
type: object
required: [scopeType, scopeCode, idempotencyKey]
properties:
scopeType: { type: string, enum: [LOCATION, PALLET] }
scopeCode: { type: string, maxLength: 128 }
idempotencyKey: { type: string, maxLength: 128 }
StocktakeCount:
type: object
required: [positionId, actualPackages, expectedVersion, idempotencyKey]
properties:
positionId: { type: string, pattern: '^[0-9]+$' }
actualPackages: { type: integer, format: int64, minimum: 0 }
expectedVersion: { type: integer, format: int64, minimum: 0 }
idempotencyKey: { type: string, maxLength: 128 }
StocktakeSubmit:
type: object
required: [expectedVersion, reason, idempotencyKey]
properties:
expectedVersion: { type: integer, format: int64, minimum: 0 }
reason: { type: string, minLength: 1, maxLength: 500 }
idempotencyKey: { type: string, maxLength: 128 }
InventoryMove:
type: object
required: [sourcePalletCode, targetLocationCode, expectedPalletVersion, idempotencyKey, reason]
properties:
sourcePalletCode: { type: string, maxLength: 128 }
targetLocationCode: { type: string, maxLength: 128 }
expectedPalletVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 128 }
reason: { type: string, minLength: 1, maxLength: 500 }
PlatformInventoryMove:
type: object
required: [overseasWarehouseId, sourcePalletCode, targetLocationCode, expectedPalletVersion, idempotencyKey, reason]
properties:
overseasWarehouseId: { type: string, pattern: '^[0-9]+$' }
sourcePalletCode: { type: string, maxLength: 128 }
targetLocationCode: { type: string, maxLength: 128 }
expectedPalletVersion: { type: integer, format: int64, minimum: 0 }
idempotencyKey: { type: string, maxLength: 128 }
reason: { type: string, minLength: 1, maxLength: 500 }
PalletExpectation:
type: object
required: [palletCode, expectedVersion]
properties:
palletCode: { type: string, maxLength: 128 }
expectedVersion: { type: integer, minimum: 0 }
PalletMoveLine:
type: object
required: [positionId, packages, expectedPositionVersion]
properties:
positionId: { type: string, pattern: '^[0-9]+$' }
packages: { type: integer, format: int64, minimum: 1 }
expectedPositionVersion: { type: integer, format: int64, minimum: 0 }
PalletAssemble:
type: object
required: [idempotencyKey, target, sources, lines]
properties:
idempotencyKey: { type: string, maxLength: 128 }
target: { $ref: '#/components/schemas/PalletExpectation' }
sources: { type: array, minItems: 1, maxItems: 20, items: { $ref: '#/components/schemas/PalletExpectation' } }
lines: { type: array, minItems: 1, maxItems: 200, items: { $ref: '#/components/schemas/PalletMoveLine' } }
reason: { type: string, maxLength: 500 }
PalletTargetMove:
type: object
required: [target, lines]
properties:
target: { $ref: '#/components/schemas/PalletExpectation' }
lines: { type: array, minItems: 1, maxItems: 200, items: { $ref: '#/components/schemas/PalletMoveLine' } }
PalletDisassemble:
type: object
required: [idempotencyKey, source, targets]
properties:
idempotencyKey: { type: string, maxLength: 128 }
source: { $ref: '#/components/schemas/PalletExpectation' }
targets: { type: array, minItems: 1, maxItems: 20, items: { $ref: '#/components/schemas/PalletTargetMove' } }
reason: { type: string, maxLength: 500 }
RelabelPalletDisassemble:
type: object
required: [idempotencyKey, relabelNo, source, target, cartonMarks]
properties:
idempotencyKey: { type: string, maxLength: 128 }
relabelNo: { type: string, maxLength: 64 }
source: { $ref: '#/components/schemas/PalletExpectation' }
target: { $ref: '#/components/schemas/PalletExpectation' }
cartonMarks: { type: array, minItems: 1, maxItems: 500, uniqueItems: true, items: { type: string, maxLength: 255 } }
measuredCartons:
type: array
maxItems: 500
description: 混合箱规选择实际移出箱;同规格可省略,改绑自动沿用首次绑定
items:
type: object
required: [cartonMark, sourceCartonMark]
properties:
cartonMark: { type: string, maxLength: 255, description: 本次换标明细箱唛 }
sourceCartonMark: { type: string, maxLength: 255, description: 来源实测箱的系统箱号 }
actualSource: { $ref: '#/components/schemas/PalletMoveLine' }
reason: { type: string, maxLength: 500 }
RelabelSource:
type: object
properties:
positionId: { type: string, pattern: '^[0-9]+$' }
positionVersion: { type: integer, format: int64 }
palletCode: { type: string }
locationCode: { type: string, nullable: true }
inboundCode: { type: string }
stockPackages: { type: integer, format: int64 }
movablePackages: { type: integer, format: int64 }
cartonMarks: { type: array, items: { type: string } }
PalletSwap:
type: object
required: [idempotencyKey, source, target]
properties:
idempotencyKey: { type: string, maxLength: 128 }
source: { $ref: '#/components/schemas/PalletExpectation' }
target: { $ref: '#/components/schemas/PalletExpectation' }
reason: { type: string, maxLength: 500 }
PalletUnbind:
type: object
required: [idempotencyKey, source]
properties:
idempotencyKey: { type: string, maxLength: 128 }
source: { $ref: '#/components/schemas/PalletExpectation' }
reason: { type: string, maxLength: 500 }
RelabelUnit:
type: object
required: [itemId, oldLabel, newLabel, expectedVersion, idempotencyKey]
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
oldLabel: { type: string, maxLength: 255, description: 当前箱的仓库唛头,用于逐箱防重复 }
newLabel: { type: string, maxLength: 255, description: 新FBA箱唛,SKU-only不得提交SKU到此字段 }
skuVerifications:
type: array
description: SKU及组合换标必须提交该箱全部旧新SKU和件数核对结果
items:
type: object
required: [skuCode, newSkuCode, quantity]
properties:
skuCode: { type: string }
newSkuCode: { type: string }
quantity: { type: integer, minimum: 1 }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
RelabelSkip:
type: object
required: [itemId, oldLabel, reason, expectedVersion, idempotencyKey]
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
oldLabel: { type: string, maxLength: 255 }
reason: { type: string, maxLength: 1000 }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
RelabelException:
type: object
required: [itemId, exceptionCode, reason, expectedVersion, idempotencyKey]
properties:
itemId: { type: string, pattern: '^[0-9]+$' }
oldLabel: { type: string, maxLength: 255, nullable: true }
exceptionCode: { type: string, enum: [DAMAGED, MISSING_LABEL, LABEL_MISMATCH, UNREADABLE, OTHER] }
reason: { type: string, maxLength: 1000 }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
RelabelComplete:
type: object
required: [photoFileIds, expectedVersion, idempotencyKey]
properties:
photoFileIds: { type: array, minItems: 1, maxItems: 20, items: { type: string, pattern: '^[0-9]+$' } }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
remark: { type: string, maxLength: 1000, nullable: true }
RelabelReview:
type: object
required: [decision, expectedVersion, idempotencyKey]
properties:
decision: { type: string, enum: [APPROVE, REWORK] }
expectedVersion: { type: integer, minimum: 0 }
idempotencyKey: { type: string, maxLength: 255 }
remark: { type: string, maxLength: 1000, nullable: true }