This commit is contained in:
2026-09-01 11:09:14 +08:00
191 changed files with 6486 additions and 403 deletions
@@ -15,6 +15,7 @@ DELIMITER ;
CALL phase2_carton_label_add_column('label_version', 'INT UNSIGNED NOT NULL DEFAULT 1 COMMENT ''内部兼容批次字段,固定为1且不进入箱码'' AFTER carton_index');
CALL phase2_carton_label_add_column('batch_status', 'VARCHAR(16) NOT NULL DEFAULT ''ACTIVE'' COMMENT ''批次状态:ACTIVE有效、VOID已作废'' AFTER label_version');
CALL phase2_carton_label_add_column('cargo_fingerprint', 'CHAR(64) NULL COMMENT ''影响标签字段的SHA-256指纹'' AFTER batch_status');
CALL phase2_carton_label_add_column('sku_code', 'VARCHAR(128) NULL COMMENT ''箱唛绑定的SKU快照;二维码内容不变'' AFTER cargo_name');
CALL phase2_carton_label_add_column('voided_at', 'DATETIME(3) NULL COMMENT ''批次作废时间'' AFTER cargo_fingerprint');
DROP PROCEDURE phase2_carton_label_add_column;
@@ -10,6 +10,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
inbound_detail_id BIGINT UNSIGNED NOT NULL COMMENT '订单货物明细ID,不建立跨库外键',
cargo_item_no INT UNSIGNED NOT NULL COMMENT '订单货物明细序号快照',
cargo_name VARCHAR(255) NULL COMMENT '货物名称快照',
sku_code VARCHAR(128) NULL COMMENT '箱唛绑定的SKU快照;二维码内容不变',
detail_package_count INT UNSIGNED NOT NULL COMMENT '该订单货物明细箱数快照',
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
box_code VARCHAR(80) NOT NULL COMMENT '固定二维码内容:入仓码#总箱数-箱下标',
@@ -42,6 +42,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_order (
destination_name VARCHAR(128) NULL COMMENT '目的仓名称快照',
hold_flag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '当前是否扣货',
current_hold_reason VARCHAR(500) NULL COMMENT '当前扣货理由快照',
last_overseas_hold_version BIGINT UNSIGNED NULL COMMENT '海外暂扣事件最新聚合版本,用于阻止乱序覆盖',
total_package_count INT UNSIGNED NULL COMMENT '确认后的总箱数',
actual_gross_weight_kg DECIMAL(18,3) NULL COMMENT '已确认称重图片含托盘毛重汇总kg',
chargeable_weight_kg DECIMAL(18,3) NULL COMMENT '当前费用快照的计费重量kg',
@@ -196,6 +197,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
inbound_detail_id BIGINT UNSIGNED NOT NULL COMMENT '订单货物明细ID,不建立跨库外键',
cargo_item_no INT UNSIGNED NOT NULL COMMENT '订单货物明细序号快照',
cargo_name VARCHAR(255) NULL COMMENT '货物名称快照',
sku_code VARCHAR(128) NULL COMMENT '箱唛绑定的SKU快照;二维码内容不变',
detail_package_count INT UNSIGNED NOT NULL COMMENT '该订单货物明细箱数快照',
inbound_code VARCHAR(40) NOT NULL COMMENT '入仓码快照',
box_code VARCHAR(80) NOT NULL COMMENT '固定二维码内容:入仓码#总箱数-箱下标',
@@ -104,8 +104,8 @@ CREATE TABLE IF NOT EXISTS fl_container_event_inbox (
event_id VARCHAR(64) NOT NULL COMMENT '跨区事件全局唯一ID',
event_type VARCHAR(64) NOT NULL COMMENT '事件类型',
event_version INT UNSIGNED NOT NULL COMMENT '事件契约版本',
aggregate_id VARCHAR(64) NOT NULL COMMENT '货柜聚合ID',
aggregate_version BIGINT UNSIGNED NOT NULL COMMENT '货柜聚合版本',
aggregate_id VARCHAR(64) NOT NULL COMMENT '跨区业务聚合ID',
aggregate_version BIGINT UNSIGNED NOT NULL COMMENT '跨区业务聚合版本',
payload_hash VARCHAR(80) NOT NULL COMMENT '规范化负载SHA-256摘要',
payload_json JSON NOT NULL COMMENT '原始事件负载',
status VARCHAR(16) NOT NULL COMMENT 'RECEIVED或PROCESSED',
@@ -113,7 +113,7 @@ CREATE TABLE IF NOT EXISTS fl_container_event_inbox (
processed_at DATETIME(3) NULL COMMENT '处理完成时间(UTC)',
PRIMARY KEY (event_id),
KEY idx_container_event_aggregate (aggregate_id, aggregate_version)
) ENGINE=InnoDB COMMENT='海外货柜事件消费Inbox';
) ENGINE=InnoDB COMMENT='海外到国内业务事件消费Inbox';
DROP PROCEDURE IF EXISTS phase3_container_real_unit_columns;
DELIMITER $$
@@ -673,6 +673,66 @@ CREATE TABLE IF NOT EXISTS fl_loading_pick_history (
CONSTRAINT fk_loading_pick_history_item FOREIGN KEY (pick_item_id) REFERENCES fl_loading_pick_item (id)
) ENGINE=InnoDB COMMENT='PDA拣货幂等和操作审计历史';
CREATE TABLE IF NOT EXISTS fl_loading_work_pallet (
id BIGINT UNSIGNED NOT NULL COMMENT '一件代发现场作业托盘ID',
pick_task_id BIGINT UNSIGNED NOT NULL COMMENT 'PDA装柜拣货任务ID',
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '装柜计划ID快照',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '作业仓库ID',
warehouse_pallet_id BIGINT UNSIGNED NULL COMMENT '仓库实物托盘ID;未绑定仓库资源时为空',
pallet_code VARCHAR(64) NOT NULL COMMENT '现场托盘号',
open_operation_id VARCHAR(128) NOT NULL COMMENT '开托幂等操作号',
seal_operation_id VARCHAR(128) NULL COMMENT '封托幂等操作号',
pallet_status VARCHAR(16) NOT NULL DEFAULT 'OPEN' COMMENT '托盘状态:OPEN打托中、SEALED已封托、CANCELLED已取消',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建操作人ID',
created_by_name VARCHAR(64) NULL COMMENT '创建操作人名称快照',
sealed_by BIGINT UNSIGNED NULL COMMENT '封托操作人ID',
sealed_by_name VARCHAR(64) NULL COMMENT '封托操作人名称快照',
sealed_at DATETIME(3) NULL COMMENT '封托时间',
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_loading_work_pallet_code (pick_task_id, pallet_code),
UNIQUE KEY uk_loading_work_pallet_open_operation (open_operation_id),
UNIQUE KEY uk_loading_work_pallet_seal_operation (seal_operation_id),
KEY idx_loading_work_pallet_plan (loading_plan_id, pallet_status, id),
CONSTRAINT fk_loading_work_pallet_task FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id),
CONSTRAINT fk_loading_work_pallet_plan FOREIGN KEY (loading_plan_id) REFERENCES fl_loading_plan (id),
CONSTRAINT chk_loading_work_pallet_status CHECK (pallet_status IN ('OPEN','SEALED','CANCELLED'))
) ENGINE=InnoDB COMMENT='一件代发PDA现场实际托盘;允许同托盘承载多个客户订单';
CREATE TABLE IF NOT EXISTS fl_loading_work_pallet_carton (
id BIGINT UNSIGNED NOT NULL COMMENT '一件代发现场托盘箱唛绑定ID',
pick_task_id BIGINT UNSIGNED NOT NULL COMMENT 'PDA装柜拣货任务ID',
work_pallet_id BIGINT UNSIGNED NOT NULL COMMENT '现场作业托盘ID',
loading_plan_item_id BIGINT UNSIGNED NOT NULL COMMENT '装柜计划货物明细ID',
pick_item_id BIGINT UNSIGNED NOT NULL COMMENT 'PDA拣货明细ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '箱唛所属客户ID',
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '来源入仓单ID',
inbound_detail_id BIGINT UNSIGNED NOT NULL COMMENT '来源入仓货物明细ID',
carton_label_id BIGINT UNSIGNED NOT NULL COMMENT '稳定箱唛记录ID',
box_code VARCHAR(80) NOT NULL COMMENT '稳定箱唛箱码快照',
sku_code VARCHAR(128) NOT NULL COMMENT 'SKU编码快照',
units_per_carton INT UNSIGNED NULL COMMENT '每箱产品数量快照',
bound_by BIGINT UNSIGNED NOT NULL COMMENT '最后绑定操作人ID',
bound_by_name VARCHAR(64) NULL COMMENT '最后绑定操作人名称快照',
operation_id VARCHAR(128) NOT NULL COMMENT '最近一次绑定或移托幂等操作号',
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次上托时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '最后移托时间',
PRIMARY KEY (id),
UNIQUE KEY uk_loading_work_carton_task_label (pick_task_id, carton_label_id),
UNIQUE KEY uk_loading_work_carton_operation (operation_id),
KEY idx_loading_work_carton_pallet (work_pallet_id, sku_code, id),
KEY idx_loading_work_carton_plan_item (loading_plan_item_id, id),
CONSTRAINT fk_loading_work_carton_task FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id),
CONSTRAINT fk_loading_work_carton_pallet FOREIGN KEY (work_pallet_id) REFERENCES fl_loading_work_pallet (id),
CONSTRAINT fk_loading_work_carton_plan_item FOREIGN KEY (loading_plan_item_id) REFERENCES fl_loading_plan_item (id),
CONSTRAINT fk_loading_work_carton_pick_item FOREIGN KEY (pick_item_id) REFERENCES fl_loading_pick_item (id),
CONSTRAINT fk_loading_work_carton_label FOREIGN KEY (carton_label_id) REFERENCES fl_inbound_carton_label (id),
CONSTRAINT chk_loading_work_carton_units CHECK (units_per_carton IS NULL OR units_per_carton > 0)
) ENGINE=InnoDB COMMENT='一件代发PDA逐箱上托事实;客户订单不合并但实际托盘可混托';
DROP PROCEDURE IF EXISTS repair_phase3_loading_pick_task_foreign_keys;
DELIMITER $$
CREATE PROCEDURE repair_phase3_loading_pick_task_foreign_keys()
@@ -170,11 +170,104 @@ paths:
expectedVersion: {type: integer, minimum: 0}
reason: {type: string, minLength: 1, maxLength: 500}
responses: {'200': {description: 作废后柜级证据列表}}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/pallets:
get:
summary: 查询一件代发现场实际托盘、SKU汇总和逐箱明细
parameters:
- {$ref: '#/components/parameters/TaskId'}
- {name: warehouseId, in: query, required: true, schema: {type: integer, format: int64, minimum: 1}}
responses:
'200':
description: 当前任务未取消的现场托盘
content: {application/json: {schema: {type: array, items: {$ref: '#/components/schemas/WorkPallet'}}}}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/pallets/open:
post:
summary: 为已领取任务开启一个一件代发现场托盘
parameters: [{$ref: '#/components/parameters/TaskId'}]
requestBody:
required: true
content: {application/json: {schema: {$ref: '#/components/schemas/OpenPalletRequest'}}}
responses:
'200': {description: 已开启托盘或相同operationId的幂等结果}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/pallets/{palletId}/cartons/scan:
post:
summary: 扫描一件代发箱唛上托;箱唛已在其他未封托托盘时按箱移托
description: 本操作只记录实际箱到托关系,不推进既有拣货数量、订单状态或仓库资源结算。
parameters: [{$ref: '#/components/parameters/TaskId'}, {$ref: '#/components/parameters/PalletId'}]
requestBody:
required: true
content: {application/json: {schema: {$ref: '#/components/schemas/ScanCartonRequest'}}}
responses:
'200': {description: 包含最新SKU与箱唛汇总的目标托盘}
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/pallets/{palletId}/seal:
post:
summary: 封托并校验现场上托箱数未超过既有PDA已提交拣货箱数
parameters: [{$ref: '#/components/parameters/TaskId'}, {$ref: '#/components/parameters/PalletId'}]
requestBody:
required: true
content: {application/json: {schema: {$ref: '#/components/schemas/SealPalletRequest'}}}
responses:
'200': {description: 已封托托盘或A0409数量/版本冲突}
components:
parameters:
TaskId: {name: taskId, in: path, required: true, schema: {type: integer, format: int64, minimum: 1}}
ItemId: {name: itemId, in: path, required: true, schema: {type: integer, format: int64, minimum: 1}}
PalletId: {name: palletId, in: path, required: true, schema: {type: integer, format: int64, minimum: 1}}
schemas:
OpenPalletRequest:
type: object
required: [warehouseId, palletCode, operationId]
properties:
warehouseId: {type: integer, format: int64, minimum: 1}
warehousePalletId: {type: integer, format: int64, minimum: 1, nullable: true}
palletCode: {type: string, maxLength: 64}
operationId: {type: string, maxLength: 128}
ScanCartonRequest:
type: object
required: [warehouseId, boxCode, operationId]
properties:
warehouseId: {type: integer, format: int64, minimum: 1}
boxCode: {type: string, maxLength: 80}
operationId: {type: string, maxLength: 128}
SealPalletRequest:
type: object
required: [warehouseId, expectedVersion, operationId]
properties:
warehouseId: {type: integer, format: int64, minimum: 1}
expectedVersion: {type: integer, minimum: 0}
operationId: {type: string, maxLength: 128}
WorkPallet:
type: object
required: [id, palletCode, status, version, cartonCount, skuCount, customerCount, skus, cartons]
properties:
id: {type: integer, format: int64}
palletCode: {type: string}
warehousePalletId: {type: integer, format: int64, nullable: true}
status: {type: string, enum: [OPEN, SEALED]}
version: {type: integer, minimum: 0}
cartonCount: {type: integer, minimum: 0}
skuCount: {type: integer, minimum: 0}
customerCount: {type: integer, minimum: 0}
skus: {type: array, items: {$ref: '#/components/schemas/WorkPalletSku'}}
cartons: {type: array, items: {$ref: '#/components/schemas/WorkPalletCarton'}}
WorkPalletSku:
type: object
required: [skuCode, cartonCount, productQuantity]
properties:
skuCode: {type: string}
cartonCount: {type: integer, minimum: 1}
productQuantity: {type: integer, format: int64, minimum: 0}
WorkPalletCarton:
type: object
required: [id, boxCode, skuCode, tenantId, inboundId, inboundDetailId]
properties:
id: {type: integer, format: int64}
boxCode: {type: string}
skuCode: {type: string}
tenantId: {type: integer, format: int64}
inboundId: {type: integer, format: int64}
inboundDetailId: {type: integer, format: int64}
unitsPerCarton: {type: integer, minimum: 1, nullable: true}
Task:
type: object
required: [id, loadingPlanId, containerBookingId, inboundId, inboundVersion, loadingVersion, cabinetNo, sourceType, recordStatus, taskStatus, workflowStatus, version, items]