This commit is contained in:
2026-08-14 17:37:59 +08:00
parent 87e919f3c4
commit feced8eb92
40 changed files with 1142 additions and 244 deletions
+159 -52
View File
@@ -2000,9 +2000,8 @@ CREATE TABLE IF NOT EXISTS wh_pallet (
pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型',
pallet_name VARCHAR(100) NULL COMMENT '托盘名称',
capacity_cbm DECIMAL(18,6) NOT NULL COMMENT '托盘可用容积CBM',
weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '托盘重量kg',
weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '托盘皮重kg',
color VARCHAR(32) NOT NULL DEFAULT '' COMMENT '托盘颜色',
status VARCHAR(20) NOT NULL DEFAULT 'AVAILABLE' COMMENT '内部状态:AVAILABLE、RESERVED或OCCUPIED',
remark VARCHAR(500) NULL COMMENT '备注',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
@@ -2012,11 +2011,11 @@ CREATE TABLE IF NOT EXISTS wh_pallet (
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_pallet_tenant_code (tenant_id, pallet_code),
KEY idx_pallet_available (tenant_id, warehouse_id, status, deleted),
KEY idx_pallet_type (tenant_id, warehouse_id, pallet_type, status, deleted),
KEY idx_pallet_warehouse (tenant_id, warehouse_id, deleted, pallet_code),
KEY idx_pallet_type (tenant_id, warehouse_id, pallet_type, capacity_cbm, deleted),
CONSTRAINT fk_pallet_warehouse FOREIGN KEY (warehouse_id) REFERENCES wh_warehouse (id),
CONSTRAINT ck_pallet_capacity CHECK (capacity_cbm > 0)
) ENGINE=InnoDB COMMENT='二期托盘基础资料和物理托盘实例';
) ENGINE=InnoDB COMMENT='可复用托盘标识和称重主数据,不承载动态资源状态';
-- 存量库补齐托盘重量、颜色字段(可重复执行)。
SET @pallet_weight_sql = IF((SELECT COUNT(*) FROM information_schema.columns
@@ -2028,6 +2027,28 @@ SET @pallet_color_sql = IF((SELECT COUNT(*) FROM information_schema.columns
'ALTER TABLE wh_pallet ADD COLUMN color VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''托盘颜色'' AFTER weight_kg', 'SELECT 1');
PREPARE pallet_color_stmt FROM @pallet_color_sql; EXECUTE pallet_color_stmt; DEALLOCATE PREPARE pallet_color_stmt;
-- 托盘是可复用主数据,不再用状态或活动唯一约束模拟库存资源。
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND index_name = 'idx_pallet_available') > 0,
'ALTER TABLE wh_pallet DROP INDEX idx_pallet_available', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND index_name = 'idx_pallet_type') > 0,
'ALTER TABLE wh_pallet DROP INDEX idx_pallet_type', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND column_name = 'status') > 0,
'ALTER TABLE wh_pallet DROP COLUMN status', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND index_name = 'idx_pallet_warehouse') = 0,
'ALTER TABLE wh_pallet ADD KEY idx_pallet_warehouse (tenant_id, warehouse_id, deleted, pallet_code)', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'wh_pallet' AND index_name = 'idx_pallet_type') = 0,
'ALTER TABLE wh_pallet ADD KEY idx_pallet_type (tenant_id, warehouse_id, pallet_type, capacity_cbm, deleted)', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
CREATE TABLE IF NOT EXISTS wh_location (
id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '平台公共库位固定使用 tenant_id=0',
@@ -2079,19 +2100,17 @@ CREATE TABLE IF NOT EXISTS wh_location_reservation (
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
active_reservation TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = 'RESERVED' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT '普通库位活动预占唯一标记',
active_pallet_reservation TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = 'RESERVED' THEN 1 ELSE NULL END) STORED COMMENT '托盘活动预占唯一标记(包含A0)',
PRIMARY KEY (id),
UNIQUE KEY uk_location_reservation_no (tenant_id, reservation_no),
UNIQUE KEY uk_location_reservation_idempotency (tenant_id, source_service, idempotency_key),
UNIQUE KEY uk_location_active_reservation (tenant_id, location_id, active_reservation),
UNIQUE KEY uk_pallet_active_reservation (tenant_id, pallet_id, active_pallet_reservation),
KEY idx_location_reservation_business (tenant_id, source_service, business_id, reservation_status),
KEY idx_location_reservation_expire (reservation_status, expires_at),
KEY idx_location_reservation_target (tenant_id, warehouse_id, location_id, reservation_status),
CONSTRAINT fk_reservation_warehouse FOREIGN KEY (warehouse_id) REFERENCES wh_warehouse (id),
CONSTRAINT fk_reservation_pallet FOREIGN KEY (pallet_id) REFERENCES wh_pallet (id),
CONSTRAINT fk_reservation_location FOREIGN KEY (location_id) REFERENCES wh_location (id)
) ENGINE=InnoDB COMMENT='跨服务入库Saga的托盘和库位临时预占';
) ENGINE=InnoDB COMMENT='跨服务入库Saga的库位临时预占,托盘字段仅为主数据快照';
CREATE TABLE IF NOT EXISTS wh_location_occupancy (
id BIGINT UNSIGNED NOT NULL COMMENT '库位占用ID',
@@ -2118,12 +2137,10 @@ CREATE TABLE IF NOT EXISTS wh_location_occupancy (
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
active_location_occupancy TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = 'OCCUPIED' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT '普通库位活动占用唯一标记',
active_pallet_occupancy TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = 'OCCUPIED' THEN 1 ELSE NULL END) STORED COMMENT '托盘活动占用唯一标记(包含A0)',
PRIMARY KEY (id),
UNIQUE KEY uk_location_occupancy_no (tenant_id, occupancy_no),
UNIQUE KEY uk_occupancy_reservation (tenant_id, reservation_id),
UNIQUE KEY uk_location_active_occupancy (tenant_id, location_id, active_location_occupancy),
UNIQUE KEY uk_pallet_active_occupancy (tenant_id, pallet_id, active_pallet_occupancy),
KEY idx_occupancy_business (tenant_id, source_service, business_id, occupancy_status),
KEY idx_occupancy_warehouse (tenant_id, warehouse_id, occupancy_status, occupied_at),
CONSTRAINT fk_occupancy_reservation FOREIGN KEY (reservation_id) REFERENCES wh_location_reservation (id),
@@ -2131,7 +2148,7 @@ CREATE TABLE IF NOT EXISTS wh_location_occupancy (
CONSTRAINT fk_occupancy_pallet FOREIGN KEY (pallet_id) REFERENCES wh_pallet (id),
CONSTRAINT fk_occupancy_location FOREIGN KEY (location_id) REFERENCES wh_location (id),
CONSTRAINT ck_occupancy_volume CHECK (allocated_volume_cbm > 0)
) ENGINE=InnoDB COMMENT='已确认的一托一库位占用事实记录';
) ENGINE=InnoDB COMMENT='已确认的库位占用事实记录,托盘字段仅为主数据快照';
-- 头程入库单属于其他数据库,不建立跨库外键。
@@ -2211,10 +2228,6 @@ SET @reservation_needs_upgrade = IFNULL((
SET @sql = IF(@reservation_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_location_active_reservation') > 0,
'ALTER TABLE wh_location_reservation DROP INDEX uk_location_active_reservation', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF(@reservation_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_pallet_active_reservation') > 0,
'ALTER TABLE wh_location_reservation DROP INDEX uk_pallet_active_reservation', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF(@reservation_needs_upgrade = 1,
'ALTER TABLE wh_location_reservation MODIFY COLUMN active_reservation TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = ''RESERVED'' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT ''普通库位活动预占唯一标记,A0 返回 NULL''',
'SELECT 1');
@@ -2228,18 +2241,11 @@ SET @occupancy_needs_upgrade = IF(
EXISTS(SELECT 1 FROM information_schema.columns
WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy'
AND column_name = 'active_location_occupancy'
AND LOCATE('shared_overflow', generation_expression) > 0)
AND EXISTS(SELECT 1 FROM information_schema.columns
WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy'
AND column_name = 'active_pallet_occupancy'),
AND LOCATE('shared_overflow', generation_expression) > 0),
0, 1);
SET @sql = IF(@occupancy_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_location_active_occupancy') > 0,
'ALTER TABLE wh_location_occupancy DROP INDEX uk_location_active_occupancy', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF(@occupancy_needs_upgrade = 1 AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_pallet_active_occupancy') > 0,
'ALTER TABLE wh_location_occupancy DROP INDEX uk_pallet_active_occupancy', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
DROP PROCEDURE IF EXISTS add_location_overflow_column_if_missing;
DELIMITER $$
CREATE PROCEDURE add_location_overflow_column_if_missing(
@@ -2265,29 +2271,28 @@ BEGIN
END$$
DELIMITER ;
CALL add_location_overflow_column_if_missing(
'wh_location_reservation', 'active_pallet_reservation',
'TINYINT GENERATED ALWAYS AS (CASE WHEN reservation_status = ''RESERVED'' THEN 1 ELSE NULL END) STORED COMMENT ''托盘活动预占唯一标记(包含 A0)'''
);
CALL add_location_overflow_column_if_missing(
'wh_location_occupancy', 'active_location_occupancy',
'TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = ''OCCUPIED'' AND shared_overflow = 0 THEN 1 ELSE NULL END) STORED COMMENT ''普通库位活动占用唯一标记'''
);
CALL add_location_overflow_column_if_missing(
'wh_location_occupancy', 'active_pallet_occupancy',
'TINYINT GENERATED ALWAYS AS (CASE WHEN occupancy_status = ''OCCUPIED'' THEN 1 ELSE NULL END) STORED COMMENT ''托盘活动占用唯一标记(包含 A0)'''
);
DROP PROCEDURE IF EXISTS add_location_overflow_column_if_missing;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_pallet_active_reservation') = 0,
'ALTER TABLE wh_location_reservation ADD UNIQUE KEY uk_pallet_active_reservation (tenant_id, pallet_id, active_pallet_reservation)', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_location_active_occupancy') = 0,
'ALTER TABLE wh_location_occupancy ADD UNIQUE KEY uk_location_active_occupancy (tenant_id, location_id, active_location_occupancy)', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_pallet_active_occupancy') = 0,
'ALTER TABLE wh_location_occupancy ADD UNIQUE KEY uk_pallet_active_occupancy (tenant_id, pallet_id, active_pallet_occupancy)', 'SELECT 1');
-- 清理旧环境中的托盘活动资源约束;库位活动约束继续保留。
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND index_name = 'uk_pallet_active_reservation') > 0,
'ALTER TABLE wh_location_reservation DROP INDEX uk_pallet_active_reservation', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND index_name = 'uk_pallet_active_occupancy') > 0,
'ALTER TABLE wh_location_occupancy DROP INDEX uk_pallet_active_occupancy', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = @schema_name AND table_name = 'wh_location_reservation' AND column_name = 'active_pallet_reservation') > 0,
'ALTER TABLE wh_location_reservation DROP COLUMN active_pallet_reservation', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = @schema_name AND table_name = 'wh_location_occupancy' AND column_name = 'active_pallet_occupancy') > 0,
'ALTER TABLE wh_location_occupancy DROP COLUMN active_pallet_occupancy', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
-- 托盘、库位、预占和占用均为平台公共仓储资源,存量测试数据统一迁移到平台作用域 0。
@@ -2758,6 +2763,11 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '入库单ID',
file_id BIGINT UNSIGNED NOT NULL COMMENT '称重图片文件ID',
pallet_id BIGINT UNSIGNED NOT NULL COMMENT 'Warehouse托盘ID',
pallet_code VARCHAR(50) NOT NULL COMMENT '托盘编码快照',
pallet_type VARCHAR(32) NOT NULL COMMENT '托盘类型快照',
pallet_capacity_cbm DECIMAL(18,4) NOT NULL COMMENT '托盘容量CBM快照',
pallet_tare_weight_kg DECIMAL(18,3) NOT NULL COMMENT '托盘皮重KG快照',
ocr_provider VARCHAR(64) NULL COMMENT 'OCR服务商编码',
ocr_raw_text VARCHAR(1000) NULL COMMENT 'OCR原始文本',
ocr_weight_value DECIMAL(18,3) NULL COMMENT 'OCR识别原始重量值',
@@ -2765,7 +2775,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
confidence DECIMAL(6,5) NULL COMMENT '识别置信度',
adjusted_weight_value DECIMAL(18,3) NULL COMMENT '人工修正后的原单位重量',
adjusted_weight_unit VARCHAR(8) NULL COMMENT '人工修正后的单位',
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认并统一换算后的重量kg',
gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的含托盘毛重kg',
net_weight_kg DECIMAL(18,3) NULL COMMENT '确认毛重扣除托盘皮重后的货物净重kg',
recognition_status VARCHAR(24) NOT NULL DEFAULT 'PENDING' COMMENT '重量识别状态:PENDING待识别、PENDING_CONFIRM待确认、NEEDS_MANUAL需人工录入、CONFIRMED已确认',
adjustment_reason VARCHAR(500) NULL COMMENT '人工修正原因',
adjusted_by BIGINT UNSIGNED NULL COMMENT '修正人ID',
@@ -2781,8 +2792,9 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_result (
PRIMARY KEY (id),
UNIQUE KEY uk_weight_inbound_file (tenant_id, inbound_id, file_id),
KEY idx_weight_inbound_status (tenant_id, inbound_id, recognition_status),
KEY idx_weight_inbound_pallet (tenant_id, inbound_id, pallet_id),
CONSTRAINT fk_weight_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
) ENGINE=InnoDB COMMENT='称重图片OCR原值、人工修正值和确认重量';
) ENGINE=InnoDB COMMENT='称重图片、托盘皮重快照、OCR毛重和确认净重';
CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量修订记录ID',
@@ -2795,7 +2807,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
before_weight_unit VARCHAR(8) NULL COMMENT '变更前单位',
after_weight_value DECIMAL(18,3) NULL COMMENT '变更后原单位重量',
after_weight_unit VARCHAR(8) NULL COMMENT '变更后单位',
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的重量kg',
gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的含托盘毛重kg',
net_weight_kg DECIMAL(18,3) NULL COMMENT '确认毛重扣除托盘皮重后的货物净重kg',
reason VARCHAR(500) NULL COMMENT '人工修正原因',
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
@@ -3014,11 +3027,16 @@ CREATE TABLE IF NOT EXISTS fl_inbound_pallet_allocation (
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_pallet_allocation_no (tenant_id, inbound_id, allocation_no),
UNIQUE KEY uk_pallet_allocation_pallet (tenant_id, inbound_id, pallet_id),
KEY idx_allocation_location (tenant_id, warehouse_id, location_id, allocation_status),
CONSTRAINT fk_allocation_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
) ENGINE=InnoDB COMMENT='头程侧托盘、库位和仓库预占结果引用';
SET @sql = IF((SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_pallet_allocation'
AND index_name = 'uk_pallet_allocation_pallet') > 0,
'ALTER TABLE fl_inbound_pallet_allocation DROP INDEX uk_pallet_allocation_pallet', 'SELECT 1');
PREPARE statement FROM @sql; EXECUTE statement; DEALLOCATE PREPARE statement;
CREATE TABLE IF NOT EXISTS fl_inbound_file (
id BIGINT UNSIGNED NOT NULL COMMENT '入库单文件关系ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
@@ -3197,6 +3215,25 @@ CALL phase2_measure_add_column('fl_inbound_measurement_item', 'outer_height_cm',
CALL phase2_measure_add_column('fl_inbound_measurement_item', 'updated_at',
'DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT ''最后更新时间'' AFTER created_at');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'pallet_id',
'BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''Warehouse托盘ID'' AFTER file_id');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'pallet_code',
'VARCHAR(50) NOT NULL DEFAULT '''' COMMENT ''托盘编码快照'' AFTER pallet_id');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'pallet_type',
'VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''托盘类型快照'' AFTER pallet_code');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'pallet_capacity_cbm',
'DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT ''托盘容量CBM快照'' AFTER pallet_type');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'pallet_tare_weight_kg',
'DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT ''托盘皮重KG快照'' AFTER pallet_capacity_cbm');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'gross_weight_kg',
'DECIMAL(18,3) NULL COMMENT ''确认时统一换算后的含托盘毛重kg'' AFTER adjusted_weight_unit');
CALL phase2_measure_add_column('fl_inbound_weight_result', 'net_weight_kg',
'DECIMAL(18,3) NULL COMMENT ''确认毛重扣除托盘皮重后的货物净重kg'' AFTER gross_weight_kg');
CALL phase2_measure_add_column('fl_inbound_weight_revision', 'gross_weight_kg',
'DECIMAL(18,3) NULL COMMENT ''确认时统一换算后的含托盘毛重kg'' AFTER after_weight_unit');
CALL phase2_measure_add_column('fl_inbound_weight_revision', 'net_weight_kg',
'DECIMAL(18,3) NULL COMMENT ''确认毛重扣除托盘皮重后的货物净重kg'' AFTER gross_weight_kg');
SET @has_measure_box_code_index = (
SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE()
@@ -3217,6 +3254,30 @@ ALTER TABLE fl_inbound_measurement_item
DROP PROCEDURE IF EXISTS phase2_measure_add_column;
SET @phase2_measure_sql = IF((SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_weight_result'
AND index_name = 'idx_weight_inbound_pallet') = 0,
'ALTER TABLE fl_inbound_weight_result ADD KEY idx_weight_inbound_pallet (tenant_id, inbound_id, pallet_id)',
'SELECT 1');
PREPARE phase2_measure_statement FROM @phase2_measure_sql;
EXECUTE phase2_measure_statement;
DEALLOCATE PREPARE phase2_measure_statement;
SET @phase2_measure_sql = IF((SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_weight_result'
AND column_name = 'final_weight_kg') > 0,
'ALTER TABLE fl_inbound_weight_result DROP COLUMN final_weight_kg', 'SELECT 1');
PREPARE phase2_measure_statement FROM @phase2_measure_sql;
EXECUTE phase2_measure_statement;
DEALLOCATE PREPARE phase2_measure_statement;
SET @phase2_measure_sql = IF((SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_weight_revision'
AND column_name = 'final_weight_kg') > 0,
'ALTER TABLE fl_inbound_weight_revision DROP COLUMN final_weight_kg', 'SELECT 1');
PREPARE phase2_measure_statement FROM @phase2_measure_sql;
EXECUTE phase2_measure_statement;
DEALLOCATE PREPARE phase2_measure_statement;
CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
id BIGINT UNSIGNED NOT NULL COMMENT 'OCR重量修订记录ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
@@ -3228,7 +3289,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_weight_revision (
before_weight_unit VARCHAR(8) NULL COMMENT '变更前单位',
after_weight_value DECIMAL(18,3) NULL COMMENT '变更后原单位重量',
after_weight_unit VARCHAR(8) NULL COMMENT '变更后单位',
final_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的重量kg',
gross_weight_kg DECIMAL(18,3) NULL COMMENT '确认时统一换算后的含托盘毛重kg',
net_weight_kg DECIMAL(18,3) NULL COMMENT '确认毛重扣除托盘皮重后的货物净重kg',
reason VARCHAR(500) NULL COMMENT '人工修正原因',
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
@@ -11190,7 +11252,7 @@ CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_split_history', '不可
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_split_item', '主子入仓单拆分数量台账');
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_status_history', '入库单流程状态不可变历史');
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_transport_snapshot', '入库单关联运输信息只读快照');
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_weight_result', '称重图片OCR原值、人工修正值和确认重量');
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_weight_result', '称重图片、托盘皮重快照、OCR毛重和确认净重');
CALL queue_table_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'OCR重量人工修正和确认的不可变版本历史');
CALL queue_table_comment('baiyue_firstleg', 'fl_loading_evidence', '订单装柜空仓/半仓/满仓/锁仓/带锁码照证据');
CALL queue_table_comment('baiyue_firstleg', 'fl_loading_operation', '装柜与派送写操作幂等记录');
@@ -11256,11 +11318,11 @@ CALL queue_table_comment('baiyue_order', 'sys_audit_outbox', '可靠审计事件
CALL queue_table_comment('baiyue_warehouse', 'sys_audit_outbox', '可靠审计事件本地发送箱');
CALL queue_table_comment('baiyue_warehouse', 'wh_express_company', '平台公共快递公司主数据,固定归属 tenant_id=0');
CALL queue_table_comment('baiyue_warehouse', 'wh_location', '二期库位基础资料,默认一托盘对应一个库位且不作容量校验');
CALL queue_table_comment('baiyue_warehouse', 'wh_location_occupancy', '已确认的一托一库位占用事实记录');
CALL queue_table_comment('baiyue_warehouse', 'wh_location_reservation', '跨服务入库Saga的托盘和库位临时预占');
CALL queue_table_comment('baiyue_warehouse', 'wh_location_occupancy', '已确认的库位占用事实记录,托盘字段仅为主数据快照');
CALL queue_table_comment('baiyue_warehouse', 'wh_location_reservation', '跨服务入库Saga的库位临时预占,托盘字段仅为主数据快照');
CALL queue_table_comment('baiyue_warehouse', 'wh_overseas_storage_fee_rule', '客户海外仓费用规则');
CALL queue_table_comment('baiyue_warehouse', 'wh_overseas_storage_fee_tier', '客户海外仓费用阶梯');
CALL queue_table_comment('baiyue_warehouse', 'wh_pallet', '二期托盘基础资料和物理托盘实例');
CALL queue_table_comment('baiyue_warehouse', 'wh_pallet', '可复用托盘标识和称重主数据,不承载动态资源状态');
CALL queue_table_comment('baiyue_warehouse', 'wh_pallet_location_release_operation', 'PDA已拣满托盘库位精确释放的持久化幂等操作记录');
CALL queue_table_comment('baiyue_warehouse', 'wh_pallet_location_settlement_operation', 'PDA拣货资源原子结算的持久化幂等操作记录');
CALL queue_table_comment('baiyue_warehouse', 'wh_pallet_location_transfer_operation', '托盘库位归属转移的持久化幂等操作记录');
@@ -12536,13 +12598,19 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'create
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'created_by', '创建人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'deleted', '逻辑删除标记');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'file_id', '称重图片文件ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'final_weight_kg', '确认并统一换算后的重量kg');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'gross_weight_kg', '确认时统一换算后的含托盘毛重kg');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'id', 'OCR重量结果ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'inbound_id', '入库单ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'net_weight_kg', '确认毛重扣除托盘皮重后的货物净重kg');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'ocr_provider', 'OCR服务商编码');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'ocr_raw_text', 'OCR原始文本');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'ocr_weight_unit', 'OCR识别原始单位');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'ocr_weight_value', 'OCR识别原始重量值');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'pallet_capacity_cbm', '托盘容量CBM快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'pallet_code', '托盘编码快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'pallet_id', 'Warehouse托盘ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'pallet_tare_weight_kg', '托盘皮重KG快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'pallet_type', '托盘类型快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'recognition_status', '重量识别状态:PENDING待识别、PENDING_CONFIRM待确认、NEEDS_MANUAL需人工录入、CONFIRMED已确认');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'tenant_id', '客户ID和数据隔离键');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_result', 'updated_at', '更新时间');
@@ -12553,9 +12621,10 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'afte
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'after_weight_value', '变更后原单位重量');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'before_weight_unit', '变更前单位');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'before_weight_value', '变更前原单位重量');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'final_weight_kg', '确认时统一换算后的重量kg');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'gross_weight_kg', '确认时统一换算后的含托盘毛重kg');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'id', 'OCR重量修订记录ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'inbound_id', '入库单ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'net_weight_kg', '确认毛重扣除托盘皮重后的货物净重kg');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'operated_at', '操作时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'operator_id', '操作人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_weight_revision', 'operator_name', '操作人名称快照');
@@ -13527,7 +13596,6 @@ CALL queue_column_comment('baiyue_warehouse', 'wh_location', 'warehouse_id', '
CALL queue_column_comment('baiyue_warehouse', 'wh_location', 'zone_code', '库区编码');
CALL queue_column_comment('baiyue_warehouse', 'wh_location', 'zone_name', '库区名称');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'active_location_occupancy', '普通库位活动占用唯一标记');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'active_pallet_occupancy', '托盘活动占用唯一标记(包含A0)');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'allocated_package_count', '本托盘分配箱数');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'allocated_volume_cbm', '本托盘分配体积CBM');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'business_id', '来源服务入库单ID');
@@ -13551,7 +13619,6 @@ CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'tenant_i
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'updated_at', '更新时间');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'version', '乐观锁版本号');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_occupancy', 'warehouse_id', '仓库ID');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_reservation', 'active_pallet_reservation', '托盘活动预占唯一标记(包含A0)');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_reservation', 'active_reservation', '普通库位活动预占唯一标记,A0 返回 NULL');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_reservation', 'business_id', '来源服务入库单ID');
CALL queue_column_comment('baiyue_warehouse', 'wh_location_reservation', 'confirmed_at', '确认占用时间');
@@ -13613,13 +13680,12 @@ CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'pallet_code', '平
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'pallet_name', '托盘名称');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'pallet_type', '托盘类型');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'remark', '备注');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'status', '内部状态:AVAILABLE、RESERVED或OCCUPIED');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'tenant_id', '平台公共托盘固定使用 tenant_id=0');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'updated_at', '更新时间');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'updated_by', '最后修改人ID');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'version', '乐观锁版本号');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'warehouse_id', '所属仓库ID');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'weight_kg', '托盘重量kg');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet', 'weight_kg', '托盘皮重kg');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet_location_release_operation', 'business_id', '入库单ID');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet_location_release_operation', 'completed_at', '完成时间');
CALL queue_column_comment('baiyue_warehouse', 'wh_pallet_location_release_operation', 'created_at', '创建时间');
@@ -13815,6 +13881,47 @@ BEGIN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '统一迁移失败:Finance 来源事件或人工写操作幂等约束不完整';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = 'baiyue_warehouse'
AND ((table_name = 'wh_pallet' AND column_name = 'status')
OR (table_name = 'wh_location_reservation' AND column_name = 'active_pallet_reservation')
OR (table_name = 'wh_location_occupancy' AND column_name = 'active_pallet_occupancy'))) <> 0
OR (SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = 'baiyue_warehouse'
AND index_name IN ('uk_pallet_active_reservation', 'uk_pallet_active_occupancy')) <> 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '统一迁移失败:托盘动态资源状态或活动唯一约束仍存在';
END IF;
IF (SELECT COUNT(DISTINCT CONCAT(table_name, '.', index_name))
FROM information_schema.statistics
WHERE table_schema = 'baiyue_warehouse'
AND ((table_name = 'wh_location_reservation' AND index_name = 'uk_location_active_reservation')
OR (table_name = 'wh_location_occupancy' AND index_name = 'uk_location_active_occupancy'))
AND non_unique = 0) <> 2 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '统一迁移失败:库位活动预占或占用唯一约束不完整';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = 'baiyue_firstleg'
AND ((table_name = 'fl_inbound_weight_result' AND column_name IN (
'pallet_id', 'pallet_code', 'pallet_type', 'pallet_capacity_cbm',
'pallet_tare_weight_kg', 'gross_weight_kg', 'net_weight_kg'))
OR (table_name = 'fl_inbound_weight_revision'
AND column_name IN ('gross_weight_kg', 'net_weight_kg')))) <> 9
OR (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema = 'baiyue_firstleg'
AND table_name IN ('fl_inbound_weight_result', 'fl_inbound_weight_revision')
AND column_name = 'final_weight_kg') <> 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '统一迁移失败:称重托盘快照或毛重净重字段未正确收敛';
END IF;
IF (SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema = 'baiyue_firstleg'
AND table_name = 'fl_inbound_pallet_allocation'
AND index_name = 'uk_pallet_allocation_pallet') <> 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '统一迁移失败:同票托盘唯一约束仍阻止托盘主数据复用';
END IF;
IF (SELECT COUNT(*) FROM information_schema.tables
WHERE table_schema = 'baiyue_firstleg'
AND table_name = 'fl_inbound_carton_label') <> 1 THEN