fix(lastleg): repair dispatch cancellation and return execution contracts
This commit is contained in:
@@ -2927,16 +2927,53 @@ CREATE TABLE IF NOT EXISTS ll_exception_order (
|
||||
CREATE TABLE IF NOT EXISTS ll_exception_return_item (
|
||||
id BIGINT NOT NULL COMMENT '异常退回明细ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
exception_order_id BIGINT NOT NULL COMMENT '异常订单ID', outbound_pallet_item_id BIGINT NOT NULL COMMENT '原出库托盘明细ID',
|
||||
inventory_position_id BIGINT NOT NULL COMMENT '原出库库存位置ID', pallet_no VARCHAR(128) NULL COMMENT '原出库托盘码快照',
|
||||
inventory_position_id BIGINT NULL COMMENT '普通原出库库存位置;与退货原箱互斥',
|
||||
return_carton_id BIGINT NULL COMMENT '原生退货箱标识;与普通库存位置互斥',
|
||||
return_carton_mark VARCHAR(128) NULL COMMENT '原生退货箱业务箱码快照',
|
||||
pallet_no VARCHAR(128) NULL COMMENT '原出库托盘码快照',
|
||||
sku_code VARCHAR(128) NULL COMMENT '原出库SKU快照', max_return_packages BIGINT NOT NULL COMMENT '原出库可退箱数上限',
|
||||
approved_return_packages BIGINT NOT NULL COMMENT '批准退回箱数', created_at DATETIME(3) NOT NULL COMMENT '创建时间',
|
||||
received_packages BIGINT NOT NULL DEFAULT 0 COMMENT '已实际退回入仓的累计箱数',
|
||||
CONSTRAINT chk_exception_return_received CHECK(received_packages>=0 AND received_packages<=approved_return_packages),
|
||||
CONSTRAINT chk_exception_return_source CHECK((inventory_position_id IS NOT NULL AND return_carton_id IS NULL) OR (inventory_position_id IS NULL AND return_carton_id IS NOT NULL)),
|
||||
|
||||
PRIMARY KEY(id), UNIQUE KEY uk_ll_exception_return_source(customer_id,exception_order_id,outbound_pallet_item_id,inventory_position_id),
|
||||
UNIQUE KEY uk_ll_exception_return_carton(customer_id,exception_order_id,outbound_pallet_item_id,return_carton_id),
|
||||
KEY idx_ll_exception_return_order(customer_id,exception_order_id)
|
||||
) ENGINE=InnoDB COMMENT='异常退回原出库库存冻结明细';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_return_carton_stock_receipt (
|
||||
id BIGINT NOT NULL COMMENT '原箱回仓凭据明细标识',
|
||||
customer_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '客户数据隔离键',
|
||||
receipt_no VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原箱回仓实收业务号',
|
||||
exception_order_id BIGINT NOT NULL COMMENT '本次异常退回订单',
|
||||
exception_return_item_id BIGINT NOT NULL COMMENT '本次冻结的原箱来源明细',
|
||||
delivery_order_id BIGINT NOT NULL COMMENT '原运输派送单',
|
||||
source_pick_id BIGINT NOT NULL COMMENT '原箱实际出库拣货凭据',
|
||||
source_outbound_no VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原出库单业务号',
|
||||
source_dispatch_item_id BIGINT NOT NULL COMMENT '原排车货物明细',
|
||||
source_outbound_pallet_item_id BIGINT NOT NULL COMMENT '原出库托盘明细',
|
||||
return_carton_id BIGINT NOT NULL COMMENT '真实退货原箱标识',
|
||||
carton_mark VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原箱业务箱码快照',
|
||||
overseas_warehouse_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '实际回仓海外仓标识',
|
||||
target_pallet_id BIGINT NOT NULL COMMENT '实际回仓目标实物托盘',
|
||||
target_pallet_no VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '实际目标托盘业务码',
|
||||
target_location_id BIGINT NOT NULL COMMENT '实际回仓目标库位',
|
||||
target_location_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '实际目标库位业务码',
|
||||
sku_code VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '原出库快照中的商品编码',
|
||||
product_name_zh VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '原出库快照中的中文品名',
|
||||
quantity BIGINT NOT NULL COMMENT '本次原SKU实际恢复件数',
|
||||
packages BIGINT NOT NULL COMMENT '本箱仅首条SKU记录计一箱其余为零',
|
||||
evidence_file_ids_json JSON NOT NULL COMMENT '本次实收证据文件引用',
|
||||
received_by VARCHAR(128) NOT NULL COMMENT '本次原箱实收确认操作人',
|
||||
received_at DATETIME(3) NOT NULL COMMENT '实际原箱回仓入账时间',
|
||||
PRIMARY KEY(id),
|
||||
UNIQUE KEY uk_return_carton_receipt_source(customer_id,source_pick_id,sku_code),
|
||||
KEY idx_return_carton_receipt_exception(customer_id,exception_order_id,received_at),
|
||||
KEY idx_return_carton_receipt_delivery(customer_id,delivery_order_id),
|
||||
CONSTRAINT chk_return_carton_receipt_quantity CHECK(quantity>0 AND packages IN (0,1))
|
||||
) ENGINE=InnoDB COMMENT='原生退货箱按原出库SKU实际回仓的不可变凭据';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ll_exception_order_command (
|
||||
id BIGINT NOT NULL COMMENT '异常处理命令ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
|
||||
exception_order_id BIGINT NOT NULL COMMENT '异常订单ID', action VARCHAR(32) NOT NULL COMMENT '异常处理动作',
|
||||
|
||||
@@ -167,7 +167,7 @@ paths:
|
||||
parameters: [{$ref: '#/components/parameters/TripNo'}, {$ref: '#/components/parameters/BookingNo'}]
|
||||
post:
|
||||
summary: 运营确认委托方实收货量与运费
|
||||
description: '权限:platform:fleet:trip:booking-confirm;实际来货已完成测量,receiptHash和实托集合一致,重新核算容量和约定金额,引用真实收货证据并确认原来货流程;不重复入库。差异必须显式确认,超容量回滚。'
|
||||
description: '权限:platform:fleet:trip:booking-confirm;CONFIRMED或尚未绑定排车的RECEIVED可核对。实际来货已完成测量,receiptHash和实托集合一致,重新核算容量和约定金额,引用真实收货证据并确认原来货流程;不重复入库。拆合托后先解除排车关联,再以新请求键及当前版本重新确认实收和运费,完整实收量与承诺车次限制不放宽。差异必须显式确认,超容量回滚。'
|
||||
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/BookingAcceptReceipt'}}}}
|
||||
responses: {'200': {$ref: '#/components/responses/BookingResult'}}
|
||||
/api/platform/v1/last-leg/fleet/trips/{tripNo}/bookings/{bookingNo}/dispatch:
|
||||
@@ -450,6 +450,8 @@ components:
|
||||
properties:
|
||||
warehousePalletId: {type: string}
|
||||
palletSpaces: {type: integer, minimum: 1}
|
||||
weightKg: {type: number, nullable: true, minimum: 0.001, description: 当前组成缺少可信测量时必填,为该票外接货实测毛重,不填整托其他来源重量}
|
||||
volumeCbm: {type: number, nullable: true, minimum: 0.001, description: 当前组成变化后重新实测的该票货体积;不沿用旧托盘或计费材积重}
|
||||
BookingAcceptReceipt:
|
||||
allOf:
|
||||
- {$ref: '#/components/schemas/BookingCommand'}
|
||||
|
||||
@@ -1044,7 +1044,7 @@ paths:
|
||||
/api/platform/v1/last-leg/exception-orders/{exceptionNo}/complete:
|
||||
post:
|
||||
summary: 完成异常处理并原子恢复退回库存
|
||||
description: 权限 platform:overseas-warehouse:exception-order:process;退回海外仓支持分批实收,每批使用新幂等键及当前版本,累计不得超过批准量。库存 RETURN_STOCK_IN 成功后累计实收,未收齐保留 PROCESSING,批准量收齐才转 COMPLETED。详情 returnSources 只返回剩余可收数量。派送仅在累计实际退回覆盖整单实发数量时写 RETURNED 和 RETURN_COMPLETED;非海外仓异常结案不证明货物交接完成。原 signedAt 保留,车次及资源不由工单关闭释放。
|
||||
description: 权限 platform:overseas-warehouse:exception-order:process;退回海外仓支持分批实收,每批使用新幂等键及当前版本,累计不得超过批准量。普通库存 RETURN_STOCK_IN 或原箱不可变回仓凭据成功落账后累计实收,未收齐保留 PROCESSING,批准量收齐才转 COMPLETED。详情 returnSources 只返回剩余可收数量。派送仅在累计实际退回覆盖整单实发数量时写 RETURNED 和 RETURN_COMPLETED;非海外仓异常结案不证明货物交接完成。原 signedAt 保留,车次及资源不由工单关闭释放。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters: [{ name: exceptionNo, in: path, required: true, schema: { type: string } }]
|
||||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/ExceptionComplete' } } } }
|
||||
@@ -1065,11 +1065,11 @@ paths:
|
||||
responses: { '200': { description: 关联关系 } }
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/return-inbound-options:
|
||||
get:
|
||||
summary: 查询派送退回候选入仓单
|
||||
description: 权限 platform:overseas-warehouse:exception-order:list;返回按原出库拣货事实解析的 returnSources,页面不得自由填写 SKU 或猜测库存位置。
|
||||
summary: 查询派送退回候选主单
|
||||
description: 权限 platform:overseas-warehouse:exception-order:list;每个候选以lastMileOrderId定位、lastMileOrderNo展示;inboundOrderId和inboundCode可空,换标主单不要求普通入仓单。返回按原出库拣货事实解析的 returnSources,页面不得自由填写 SKU 或猜测库存位置。每条来源返回outboundPalletItemId、inventoryPositionId、returnCartonId、cartonMark、palletNo、skuCode和maxReturnPackages;普通仓位与原箱互斥,箱码用于展示,内部标识仅作提交键。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }]
|
||||
responses: { '200': { description: 退回候选入仓单 } }
|
||||
responses: { '200': { description: 退回候选主单及真实出库来源 } }
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/mark-return:
|
||||
post:
|
||||
summary: 将派送单标记为退回入仓
|
||||
@@ -1081,7 +1081,7 @@ paths:
|
||||
/api/platform/v1/last-leg/delivery-orders/{deliveryNo}/status:
|
||||
put:
|
||||
summary: 更新派送状态
|
||||
description: 权限 platform:overseas-warehouse:delivery:status。人工只允许 WAIT_DELIVERY→DELIVERING/REJECTED/CANCELLED、DELIVERING→REJECTED;DELIVERED 仅由签收资料保存成功自动触发,同状态幂等,终态不可倒退。
|
||||
description: 权限 platform:overseas-warehouse:delivery:status。人工只允许实际出库后的 WAIT_DELIVERY→DELIVERING/REJECTED、DELIVERING→REJECTED;取消仅允许经未执行出库的聚合取消命令;DELIVERED 仅由签收资料保存成功自动触发,同状态幂等,终态不可倒退。
|
||||
security: [{ bearerAuth: [] }]
|
||||
parameters: [{ name: deliveryNo, in: path, required: true, schema: { type: string } }]
|
||||
requestBody: { required: true, content: { application/json: { schema: { $ref: '#/components/schemas/DeliveryStatusChange' } } } }
|
||||
@@ -2865,8 +2865,9 @@ components:
|
||||
dispatch: { $ref: '#/components/schemas/DispatchResponse' }
|
||||
SmartDispatchPreArrange:
|
||||
type: object
|
||||
description: planPalletIds与returnReceiptIds是两类正式来源,合计至少一项且最多500项。退回来源仅接受实际入账生成的实收记录,不得用退回实收ID冒充计划托盘ID;同一实物托盘不可重复选择。
|
||||
description: 普通来源使用planPalletIds或returnReceiptIds,合计至少一项且最多500项。指定relabelNo时planPalletIds必须是本换标申请全部已绑定实物托盘ID,普通与退货换标都不允许部分选择或混选其他来源;换标选择暂不持有统一草稿锁,仅提交时在申请锁内完整复核。退回来源仅接受实际入账生成的实收记录;同一实物托盘不可重复选择。
|
||||
properties:
|
||||
relabelNo: { type: string, nullable: true, description: 整单换标申请业务号;不与退回实收来源混选 }
|
||||
batchAllocations:
|
||||
type: array
|
||||
maxItems: 1000
|
||||
@@ -2992,18 +2993,19 @@ components:
|
||||
type: object
|
||||
required: [status, expectedVersion]
|
||||
properties:
|
||||
status: { type: string, enum: [WAIT_DELIVERY, DELIVERING, REJECTED, CANCELLED] }
|
||||
status: { type: string, enum: [WAIT_DELIVERY, DELIVERING, REJECTED] }
|
||||
expectedVersion: { type: integer, format: int64, minimum: 0 }
|
||||
remark: { type: string, nullable: true, maxLength: 500 }
|
||||
DeliveryAllowedAction:
|
||||
type: string
|
||||
enum: [START_DELIVERY, REJECT_DELIVERY, CANCEL_DELIVERY, MARK_RETURN]
|
||||
description: START/REJECT/CANCEL 使用通用 status 接口;MARK_RETURN 使用 mark-return 接口;派送完成由签收资料保存成功自动触发。
|
||||
enum: [START_DELIVERY, REJECT_DELIVERY, MARK_RETURN]
|
||||
description: START/REJECT 仅在关联出库已实际 OUTBOUNDED 后使用通用 status 接口;取消统一经未执行出库取消命令;MARK_RETURN 使用 mark-return 接口;派送完成由签收资料保存成功自动触发。
|
||||
DeliveryMarkReturn:
|
||||
type: object
|
||||
required: [inboundOrderId, reason, returnDirection, items, idempotencyKey]
|
||||
required: [lastMileOrderId, reason, returnDirection, items, idempotencyKey]
|
||||
description: 按候选中真实尾程主单定位;普通及退货换标主单无需普通入仓单,不接受虚构入仓关系。
|
||||
properties:
|
||||
inboundOrderId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
lastMileOrderId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
reason: { type: string, minLength: 1, maxLength: 1000 }
|
||||
returnDirection: { type: string, enum: [OVERSEAS_WAREHOUSE, CUSTOMER, OTHER] }
|
||||
returnLogisticsNo: { type: string, nullable: true, maxLength: 128 }
|
||||
@@ -3014,10 +3016,11 @@ components:
|
||||
maxItems: 200
|
||||
items:
|
||||
type: object
|
||||
required: [outboundPalletItemId, inventoryPositionId, packageCount]
|
||||
required: [outboundPalletItemId, packageCount]
|
||||
properties:
|
||||
outboundPalletItemId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
inventoryPositionId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
inventoryPositionId: { type: string, nullable: true, pattern: '^[1-9][0-9]*$', description: 普通库存来源;与returnCartonId必须二选一 }
|
||||
returnCartonId: { type: string, nullable: true, pattern: '^[1-9][0-9]*$', description: 原生退货箱来源;按整箱实收,不得虚构库存仓位 }
|
||||
packageCount: { type: integer, format: int64, minimum: 1 }
|
||||
ExceptionStartProcessing:
|
||||
type: object
|
||||
@@ -3046,10 +3049,11 @@ components:
|
||||
maxItems: 200
|
||||
items:
|
||||
type: object
|
||||
required: [outboundPalletItemId, inventoryPositionId, receivedPackages, targetPalletId, targetPalletNo, targetLocationId, targetLocationCode]
|
||||
required: [outboundPalletItemId, receivedPackages, targetPalletId, targetPalletNo, targetLocationId, targetLocationCode]
|
||||
properties:
|
||||
outboundPalletItemId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
inventoryPositionId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
inventoryPositionId: { type: string, nullable: true, pattern: '^[1-9][0-9]*$', description: 普通库存来源;与returnCartonId必须二选一 }
|
||||
returnCartonId: { type: string, nullable: true, pattern: '^[1-9][0-9]*$', description: 原生退货箱来源;按整箱实收,不得虚构库存仓位 }
|
||||
receivedPackages: { type: integer, format: int64, minimum: 1 }
|
||||
targetPalletId: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
targetPalletNo: { type: string, minLength: 1, maxLength: 128 }
|
||||
@@ -3122,8 +3126,9 @@ components:
|
||||
properties: { reason: { type: string, minLength: 1, maxLength: 1000 } }
|
||||
DispatchResponse:
|
||||
type: object
|
||||
required: [appointmentBatches]
|
||||
required: [appointmentBatches, actions]
|
||||
properties:
|
||||
actions: { $ref: '#/components/schemas/DispatchActions' }
|
||||
id: { type: string }
|
||||
dispatchNo: { type: string }
|
||||
vehiclePlate: { type: string, nullable: true }
|
||||
@@ -3155,12 +3160,27 @@ components:
|
||||
items: { type: array, items: { $ref: '#/components/schemas/DispatchItem' } }
|
||||
workflow:
|
||||
nullable: true
|
||||
description: 仅平台分页返回当前关联车次及两级审核;未关联为null。批量读取已有审核快照,不由执行状态推导;列表权限可读,审核操作仍需车次独立审核权限。
|
||||
description: 平台查询返回当前关联车次及两级审核;未关联为null。批量读取已有审核快照,不由执行状态推导;列表权限可读,审核操作仍需车次独立审核权限。
|
||||
allOf: [{ $ref: '#/components/schemas/DispatchWorkflow' }]
|
||||
bolLines:
|
||||
type: array
|
||||
description: 仅详情接口返回的BOL打印聚合行;分页接口返回空数组,避免列表查询放大
|
||||
items: { $ref: '#/components/schemas/DispatchBolLine' }
|
||||
DispatchActions:
|
||||
type: object
|
||||
required: [canEdit, canCancel, canRemovePallet, canTransfer]
|
||||
description: 服务端按执行事实计算;入口写权限仍需单独校验。取消按解除车次、取消出库、取消原排车顺序;取消单据保留,转派送原请求重放返回原取消结果。
|
||||
properties:
|
||||
canEdit: { type: boolean }
|
||||
editBlockReason: { type: string, nullable: true }
|
||||
canCancel: { type: boolean }
|
||||
cancelBlockReason: { type: string, nullable: true }
|
||||
canRemovePallet: { type: boolean }
|
||||
removePalletBlockReason: { type: string, nullable: true }
|
||||
canTransfer: { type: boolean }
|
||||
transferBlockReason: { type: string, nullable: true }
|
||||
outboundNo: { type: string, nullable: true }
|
||||
outboundStatus: { type: string, nullable: true }
|
||||
DispatchBatchSource:
|
||||
type: object
|
||||
required: [sourceKey, destinationKey, packageCount]
|
||||
|
||||
Reference in New Issue
Block a user