This commit is contained in:
2026-09-10 17:11:33 +08:00
parent 1ee32b7a6f
commit 2e6a18c58e
54 changed files with 2094 additions and 167 deletions
@@ -1166,7 +1166,7 @@ paths:
/api/platform/v1/last-leg/relabel-applications/{relabelNo}/status:
put:
summary: 变更海外换标单状态
description: 权限 platform:overseas-warehouse:relabel-order:status;状态按 PENDING_PROCESSING→PROCESSING→COMPLETED/REJECTED/CANCELLED 流转。
description: 权限 platform:overseas-warehouse:relabel-order:status;PDA复核通过后进入CUSTOMER_CONFIRM_PENDING,客户确认后进入READY_FOR_OUTBOUND,再由排车或直接出库履约。
security: [{ bearerAuth: [] }]
parameters:
- { name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } }
@@ -1204,6 +1204,94 @@ paths:
responses:
'200': { description: PDF字节, content: { application/pdf: { schema: { type: string, format: binary } } } }
'404': { description: 资料未绑定或归属不匹配 }
/api/merchant/v1/last-leg/relabel-applications/inventory-candidates:
get:
summary: 查询客户可换标库存候选
description: 权限 merchant:warehouse:relabel;仅返回当前客户在指定海外中转仓仍有可用箱数的历史入仓单和库位摘要。候选按客户 Token 隔离,不接收 customerId;inboundCode 可选精确筛选。
security: [{ bearerAuth: [] }]
parameters:
- { name: operationWarehouseId, in: query, required: true, schema: { type: string, maxLength: 128 } }
- { name: inboundCode, in: query, required: false, schema: { type: string, maxLength: 128 } }
responses:
'200': { description: 可换标库存候选, content: { application/json: { schema: { type: object, properties: { code: { type: string, example: '200' }, data: { type: array, items: { $ref: '#/components/schemas/RelabelInventoryCandidate' } } } } } } }
'403': { description: 缺少客户换标权限 }
/api/merchant/v1/last-leg/relabel-applications:
get:
summary: 分页查询客户换标申请
description: 权限 merchant:warehouse:relabel;客户范围只取认证 Token,不接收 customerId。
security: [{ bearerAuth: [] }]
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: relabelNo, in: query, schema: { type: string, maxLength: 64 } }
- { name: customerOrderNo, in: query, schema: { type: string, maxLength: 128 } }
- { name: skuCode, in: query, schema: { type: string, maxLength: 128 } }
- { name: status, in: query, schema: { $ref: '#/components/schemas/RelabelStatus' } }
- { name: overseasWarehouseId, in: query, schema: { type: string, maxLength: 128 } }
- { name: createdFrom, in: query, schema: { type: string, format: date-time } }
- { name: createdTo, in: query, schema: { type: string, format: date-time } }
responses:
'200': { description: 客户换标申请分页, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelMerchantPageResponse' } } } }
post:
summary: 创建客户换标申请
description: 权限 merchant:warehouse:relabel;申请创建即冻结对应库存。SKU_LABEL 不要求派送方式;CARTON_LABEL/CARTON_AND_SKU 必须指定 TRUCK、PICKUP 或 EXPRESS。
security: [{ bearerAuth: [] }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelCreate' } } } }
responses:
'200': { description: 换标申请详情, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelMerchantDetailResponse' } } } }
'409': { description: 幂等键、库存或状态冲突 }
/api/merchant/v1/last-leg/relabel-applications/{relabelNo}:
get:
summary: 查询客户换标申请详情
description: 权限 merchant:warehouse:relabel;客户范围只取认证 Token。
security: [{ bearerAuth: [] }]
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } }]
responses:
'200': { description: 换标申请详情, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelMerchantDetailResponse' } } } }
'404': { description: 申请不存在或不属于当前客户 }
/api/merchant/v1/last-leg/relabel-applications/{relabelNo}/shipping-label:
post:
summary: 上传换标快递面单
description: 权限 merchant:warehouse:relabel;仅 EXPRESS 且申请尚未客户确认时允许上传,文件由服务端绑定到申请单。
security: [{ bearerAuth: [] }]
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } }]
requestBody: { required: true, content: { multipart/form-data: { schema: { type: object, required: [file], properties: { file: { type: string, format: binary } } } } } }
responses:
'200': { description: 更新后的换标详情, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelMerchantDetailResponse' } } } }
'400': { description: 文件类型或大小不合法 }
'409': { description: 当前状态不允许上传 }
/api/merchant/v1/last-leg/relabel-applications/{relabelNo}/shipping-label/{fileId}/download:
get:
summary: 下载换标快递面单
description: 权限 merchant:warehouse:relabel;仅允许下载当前申请已绑定的面单文件。
security: [{ bearerAuth: [] }]
parameters:
- { name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } }
- { name: fileId, in: path, required: true, schema: { type: integer, format: int64, minimum: 1 } }
responses:
'200': { description: 面单文件, content: { application/pdf: { schema: { type: string, format: binary } }, image/jpeg: { schema: { type: string, format: binary } }, image/png: { schema: { type: string, format: binary } } } }
'404': { description: 文件未绑定或不属于当前客户 }
/api/merchant/v1/last-leg/relabel-applications/{relabelNo}/completion-photos/{fileId}/download:
get:
summary: 下载换标完成照片
description: 权限 merchant:warehouse:relabel;仅允许下载该申请 PDA 完工证据中的照片。
security: [{ bearerAuth: [] }]
parameters:
- { name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } }
- { name: fileId, in: path, required: true, schema: { type: integer, format: int64, minimum: 1 } }
responses:
'200': { description: 完工照片, content: { image/jpeg: { schema: { type: string, format: binary } }, image/png: { schema: { type: string, format: binary } } } }
'404': { description: 照片不存在或不属于当前客户 }
/api/merchant/v1/last-leg/relabel-applications/{relabelNo}/confirm-completion:
post:
summary: 客户确认换标完成
description: 权限 merchant:warehouse:relabel;仅 CUSTOMER_CONFIRM_PENDING 可确认。TRUCK 进入 WAIT_PRE_DISPATCH,PICKUP/EXPRESS 幂等生成 RELABEL_OUTBOUND 出库单;EXPRESS 且要求打印面单时必须先上传面单。
security: [{ bearerAuth: [] }]
parameters: [{ name: relabelNo, in: path, required: true, schema: { type: string, maxLength: 64 } }]
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelCustomerConfirm' } } } }
responses:
'200': { description: 更新后的换标详情, content: { application/json: { schema: { $ref: '#/components/schemas/RelabelMerchantDetailResponse' } } } }
'409': { description: 状态、面单、库存或幂等冲突 }
/api/merchant/v1/last-leg/return-orders:
get:
summary: 客户分页查询退货签收订单
@@ -1315,6 +1403,8 @@ components:
required: [overseasWarehouseId, needRelabel, idempotencyKey, items]
properties:
overseasWarehouseId: { type: string, maxLength: 128 }
warehouseContactName: { type: string, maxLength: 128, description: 中转仓联系人快照;仓库未维护时可由客户填写 }
warehouseContactPhone: { type: string, maxLength: 64, description: 中转仓联系电话快照;仓库未维护时可由客户填写 }
customerReferenceNo: { type: string, maxLength: 128 }
needRelabel: { type: boolean, default: false, description: 是否需要换标 }
remark: { type: string, maxLength: 1000 }
@@ -2127,7 +2217,101 @@ components:
packageCount: { type: integer }
volumeCbm: { type: number }
sourceStage: { type: string, enum: [PLAN, RECEIVED] }
RelabelStatus: { type: string, enum: [PENDING_PROCESSING, PROCESSING, COMPLETED, REJECTED, CANCELLED] }
RelabelStatus: { type: string, enum: [PENDING_PROCESSING, PROCESSING, CUSTOMER_CONFIRM_PENDING, READY_FOR_OUTBOUND, COMPLETED, REJECTED, CANCELLED] }
RelabelMerchantPageResponse:
allOf:
- { $ref: '#/components/schemas/MerchantApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/RelabelMerchantPage' } }
RelabelMerchantPage:
type: object
properties:
page: { type: integer }
size: { type: integer }
total: { type: integer, format: int64 }
records: { type: array, items: { $ref: '#/components/schemas/RelabelSummary' } }
RelabelMerchantDetailResponse:
allOf:
- { $ref: '#/components/schemas/MerchantApiResponse' }
- type: object
properties: { data: { $ref: '#/components/schemas/RelabelDetail' } }
RelabelSummary:
type: object
properties:
id: { type: string }
relabelNo: { type: string }
lastlegOrderNo: { type: string, nullable: true }
customerOrderNo: { type: string }
overseasWarehouseId: { type: string }
labelDeadline: { type: string, format: date-time }
status: { $ref: '#/components/schemas/RelabelStatus' }
itemCount: { type: integer }
totalPackageCount: { type: integer }
notifiedPackageCount: { type: integer }
deliveryMethod: { type: string, nullable: true, enum: [TRUCK, PICKUP, EXPRESS] }
printShippingLabel: { type: boolean }
shippingLabelFileId: { type: string, nullable: true }
fulfillmentStatus: { type: string, nullable: true, enum: [WAIT_RELABEL, WAIT_PRE_DISPATCH, READY_FOR_OUTBOUND, OUTBOUND_CREATED, COMPLETED] }
outboundOrderNo: { type: string, nullable: true }
customerConfirmedAt: { type: string, format: date-time, nullable: true }
createdAt: { type: string, format: date-time }
RelabelDetail:
type: object
properties:
application: { $ref: '#/components/schemas/RelabelSummary' }
remark: { type: string, nullable: true }
items: { type: array, items: { $ref: '#/components/schemas/RelabelItem' } }
history: { type: array, items: { $ref: '#/components/schemas/RelabelHistory' } }
completionEvidence: { $ref: '#/components/schemas/RelabelCompletionEvidence' }
RelabelHistory:
type: object
properties:
fromStatus: { type: string, nullable: true }
toStatus: { type: string }
operatorId: { type: string }
remark: { type: string, nullable: true }
createdAt: { type: string, format: date-time }
RelabelCompletionEvidence:
type: object
nullable: true
properties:
taskId: { type: string, nullable: true }
photoFileIds: { type: array, items: { type: string } }
completionRemark: { type: string, nullable: true }
reviewerName: { type: string, nullable: true }
reviewRemark: { type: string, nullable: true }
completedAt: { type: string, format: date-time, nullable: true }
RelabelInventoryCandidate:
type: object
properties:
inventoryBalanceId: { type: string }
inboundOrderId: { type: string }
inboundOrderNo: { type: string }
inboundCode: { type: string }
overseasWarehouseId: { type: string }
overseasWarehouseCode: { type: string }
overseasWarehouseName: { type: string }
destinationFbaWarehouseCode: { type: string, nullable: true }
destinationFbaWarehouseName: { type: string, nullable: true }
skuCode: { type: string, nullable: true }
productNameZh: { type: string }
availablePackages: { type: integer, format: int64 }
version: { type: integer, format: int64 }
positions: { type: array, items: { $ref: '#/components/schemas/RelabelInventoryPosition' } }
RelabelInventoryPosition:
type: object
properties:
positionId: { type: string }
palletNo: { type: string, nullable: true }
batchNo: { type: string, nullable: true }
warehouseLocationCode: { type: string, nullable: true }
availablePackages: { type: integer, format: int64 }
RelabelCustomerConfirm:
type: object
required: [idempotencyKey]
properties:
idempotencyKey: { type: string, maxLength: 255 }
remark: { type: string, nullable: true, maxLength: 1000 }
RelabelCreate:
type: object
required: [customerOrderNo, labelDeadline, contactName, contactPhone, chargeAmount, idempotencyKey, items]
@@ -2140,6 +2324,8 @@ components:
chargeAmount: { type: number, minimum: 0.01, description: 本次贴标费用(CNY) }
remark: { type: string, nullable: true, maxLength: 1000 }
idempotencyKey: { type: string, maxLength: 255 }
deliveryMethod: { type: string, nullable: true, enum: [TRUCK, EXPRESS, TRUCK_PICKUP, EXPRESS_PICKUP, PICKUP], description: 只换箱唛或SKU与箱唛同时换时必填;只换SKU时不传 }
printShippingLabel: { type: boolean, default: false, description: 仅快递派送可选,客户确认前必须已上传面单 }
items: { type: array, minItems: 1, maxItems: 500, items: { $ref: '#/components/schemas/RelabelItem' } }
RelabelItem:
type: object
@@ -164,6 +164,12 @@ paths:
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先扫描原托盘,再扫描换标单指定箱唛;服务端按换标单库存快照解析仓位,在同一事务中扣减原托盘并绑定目标托盘。目标托盘须先由仓储服务创建后扫码确认。
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: 将整托库存更换到空目标托盘
@@ -675,6 +681,16 @@ components:
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 } }
reason: { type: string, maxLength: 500 }
PalletSwap:
type: object
required: [idempotencyKey, source, target]