Files
baiyue-firstleg/lastleg-service/src/main/resources/openapi/overseas-pda-operations-v1.yaml
T

1078 lines
62 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绑定仓的排车PDA任务
description: 仅 OVERSEAS_WAREHOUSE_PDA_OPERATOR + lastleg:pda:operate;跨客户读取绑定仓任务,不接收customerId或warehouseId。
parameters: [{ name: status, in: query, required: false, schema: { type: string } }]
responses: { '200': { description: 排车任务列表 }, '403': { description: 角色、权限或仓库绑定缺失 } }
/api/pda/v1/last-leg/dispatches/{dispatchNo}:
get:
summary: 查询绑定仓排车任务详情
description: 返回 canDepart 与 departBlockReason;PDA 必须以服务端门禁决定是否开放发车,不得仅按本地拣货数量推断。
parameters: [{ name: dispatchNo, in: path, required: true, schema: { type: string } }]
responses: { '200': { description: 排车托盘、目的仓与库存位置详情 }, '404': { description: 当前绑定仓无此排车任务 } }
/api/pda/v1/last-leg/dispatches/{dispatchNo}/items/{itemId}/pick:
post:
summary: 扫码拣取排车托盘包裹
parameters:
- { name: dispatchNo, in: path, required: true, schema: { type: string } }
- { name: itemId, in: path, required: true, schema: { type: string, pattern: '^[0-9]+$' } }
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DispatchPick' } } } }
responses: { '200': { description: 本次及累计拣货结果;同键同请求重放既有结果 }, '409': { description: 跨仓、跨客户、库存、数量或幂等冲突 } }
/api/pda/v1/last-leg/dispatches/{dispatchNo}/complete:
post:
summary: 完成排车拣货
description: 每个要求托盘及全部包裹必须精确完成;不允许部分完成。
parameters: [{ name: dispatchNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/IdempotentAction' } } } }
responses: { '200': { description: READY_TO_DEPART结果 }, '409': { description: 未全部拣货或幂等冲突 } }
/api/pda/v1/last-leg/dispatches/{dispatchNo}/depart:
post:
summary: 排车发车并完成出库门禁
description: 仅完整拣货且存在待出库单时发车;同事务推进出库与排车状态、订单归属并释放托盘锁,不重复扣减扫码时已扣库存。
parameters: [{ name: dispatchNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DepartAction' } } } }
responses: { '200': { description: DEPARTED结果;同键同请求返回既有结果 }, '409': { description: 拣货、出库或幂等门禁未满足 } }
/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: 出库任务列表 } }
/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: 扫码拣取一件代发箱件
parameters: [{ name: taskNo, in: path, required: true, schema: { type: string } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/OutboundPick' } } } }
responses: { '200': { description: 更新后的统一出库任务 }, '409': { description: 库存、数量或幂等冲突 } }
/api/pda/v1/last-leg/outbound-tasks/{taskNo}/pallets/{palletNo}/pick:
post:
summary: 扫描一件代发托盘并原子拣取整托剩余箱件
description: 仅适用于一件代发出库;按托盘汇总本任务内全部 SKU 和未拣箱唛,任一库存校验失败则整托回滚。
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: 整托拣货后的任务 }, '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任务 }, '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的箱唛模式仍要求已有来源仓位一致。
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelPalletDisassemble' } } } }
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 }
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}/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: 提交现场任务到复核池并直接等待客户确认
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 }
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:
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] }
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作业已完成箱数,两项均完成才增加整箱已换标数 }
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 } }
DepartAction:
type: object
required: [idempotencyKey]
properties:
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
remark: { type: string, maxLength: 1000, nullable: true }
DispatchPick:
type: object
required: [positionId, packages, productQuantity, idempotencyKey]
properties:
positionId: { type: string, pattern: '^[0-9]+$' }
packages: { type: integer, format: int64, minimum: 1 }
productQuantity: { type: integer, format: int64, minimum: 0 }
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
remark: { type: string, maxLength: 1000, nullable: true }
OutboundPick:
type: object
required: [outboundPalletItemId, inventoryPositionId, packages, idempotencyKey]
properties:
outboundPalletItemId: { type: string, pattern: '^[0-9]+$' }
inventoryPositionId: { type: string, pattern: '^[0-9]+$' }
packages: { type: integer, format: int64, minimum: 1 }
idempotencyKey: { type: string, minLength: 1, maxLength: 255 }
cartonMarks:
type: array
maxItems: 500
description: 本次实际扫描的箱唛。一件代发指定箱唛任务分批拣货时必须提交本次子集,数量与 packages 一致;换标任务仍须提交全部指定箱唛。
items: { type: string, minLength: 1, maxLength: 255 }
PdaOutboundTaskDetail:
type: object
required: [task, items]
properties:
task:
type: object
required: [taskNo, status, outboundNo]
properties:
taskNo: { type: string }
status: { type: string }
outboundNo: { type: string }
pushedAt: { type: string, format: date-time, nullable: true }
completedAt: { type: string, format: date-time, nullable: true }
items:
type: array
items:
type: object
required: [outboundPalletItemId, palletNo, skuCode, inboundCode, packageCount, pickedPackageCount, status, positions]
properties:
outboundPalletItemId: { type: string, description: pick请求提交键,不作为用户展示编号 }
palletNo: { type: string, description: Warehouse 权威实物托盘码 }
skuCode: { type: string }
inboundCode: { type: string }
packageCount: { type: integer }
pickedPackageCount: { type: integer }
status: { type: string }
positions:
type: array
items:
type: object
required: [inventoryPositionId, palletNo, cartonMark, skuCode, inboundCode, availablePackages, pickedPackages]
properties:
inventoryPositionId: { type: string, description: pick请求提交键,不作为用户展示编号 }
palletNo: { type: string, description: Warehouse 权威实物托盘码 }
cartonMark: { type: string, nullable: true }
skuCode: { type: string }
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 } }
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 }