Files
baiyue-firstleg/scripts/db/recent-schema-incremental-20261008.sql
T

550 lines
34 KiB
SQL
Raw Normal View History

2026-10-08 15:55:47 +08:00
-- 2026-10-08 近期结构增量汇总(MySQL 8.0.16+)
-- 范围:2026-09-21 至 2026-10-08;用于已有业务库升级,不是空库初始化。
-- 按 USE 显式切换 baiyue_iam / baiyue_firstleg / baiyue_lastleg / baiyue_lastlag_warehouse。
-- 独立文件,无 SOURCE 或外部文件依赖;在目标 MySQL 连接中执行整个文件。
-- 不创建数据库、不写业务行、不含账号或密码;DDL 隐式提交,出错立即停止,不使用 --force。
-- 可重复执行,也支持仅部分新增字段已存在的情况。
-- 来源:recent-schema-incremental-20260923.sql、customs-two-file-incremental-20260926.sql、
-- return-receipt-box-count-incremental-20260929.sql、return-outbound-box-nullable-20260929.sql、
-- return-packing-incremental-20261008.sql 以及 incremental.sql 的 2026-09-29 追加项。
-- 2026-09-23 近期字段与表结构统一增量(MySQL 8.0+)
--
-- 范围:2026-09-21 至 2026-09-22 合入的结构变化。
-- 特性:显式切换到所属 schema;字段和索引均通过 information_schema 判断;可重复执行。
-- 边界:不创建数据库、不删除业务字段/表、不包含权限种子或业务数据修正。
-- 注意:DDL 在 MySQL 中会隐式提交;任一步失败后应停止执行并核对目标实例。
SET NAMES utf8mb4;
-- ============================================================================
-- IAM:国内头程 PDA 操作员绑定作业仓
-- ============================================================================
USE baiyue_iam;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'iam_membership'
)
AND NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'iam_membership'
AND column_name = 'domestic_warehouse_id'
),
'ALTER TABLE iam_membership ADD COLUMN domestic_warehouse_id BIGINT NULL COMMENT ''国内头程PDA操作员绑定的唯一国内作业仓ID'' AFTER overseas_warehouse_id',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @domestic_warehouse_index_columns = (
SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index SEPARATOR ',')
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'iam_membership'
AND index_name = 'idx_membership_domestic_warehouse'
);
SET @domestic_warehouse_index_non_unique = (
SELECT MIN(non_unique)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'iam_membership'
AND index_name = 'idx_membership_domestic_warehouse'
);
SET @ddl = CASE
WHEN NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'iam_membership'
AND column_name = 'domestic_warehouse_id'
) THEN 'SELECT 1'
WHEN @domestic_warehouse_index_columns IS NULL THEN
'ALTER TABLE iam_membership ADD KEY idx_membership_domestic_warehouse (tenant_id, domestic_warehouse_id, status)'
WHEN @domestic_warehouse_index_columns <> 'tenant_id,domestic_warehouse_id,status'
OR @domestic_warehouse_index_non_unique <> 1 THEN
'ALTER TABLE iam_membership DROP INDEX idx_membership_domestic_warehouse, ADD KEY idx_membership_domestic_warehouse (tenant_id, domestic_warehouse_id, status)'
ELSE 'SELECT 1'
END;
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
-- ============================================================================
-- Firstleg:人工 FBA 报价允许缺少船司价格快照
-- ============================================================================
USE baiyue_firstleg;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_fee'
AND column_name = 'carrier_rate_id' AND is_nullable = 'NO'
),
'ALTER TABLE fl_inbound_fee MODIFY COLUMN carrier_rate_id BIGINT UNSIGNED NULL COMMENT ''船司FBA价格ID;人工报价为空''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_fee'
AND column_name = 'carrier_rate_version' AND is_nullable = 'NO'
),
'ALTER TABLE fl_inbound_fee MODIFY COLUMN carrier_rate_version INT UNSIGNED NULL COMMENT ''船司价格版本快照;人工报价为空''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_fee'
AND column_name = 'rate_effective_from' AND is_nullable = 'NO'
),
'ALTER TABLE fl_inbound_fee MODIFY COLUMN rate_effective_from DATETIME(3) NULL COMMENT ''价格生效开始快照;人工报价为空''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
-- ============================================================================
-- Firstleg:墨家测量收件箱扩展为箱唛/SKU 双分流
-- ============================================================================
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'inbound_code'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN inbound_code VARCHAR(64) NULL COMMENT ''箱码命中后的权威入仓码;SKU记录为空'' AFTER box_code',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'measurement_kind'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN measurement_kind VARCHAR(16) NOT NULL DEFAULT ''BOX_LABEL'' COMMENT ''测量分流:BOX_LABEL箱唛;SKU一件代发SKU'' AFTER box_code',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'weight_kg'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN weight_kg DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT ''设备实测重量kg'' AFTER height_cm',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'weight_kg'
AND (column_type <> 'decimal(18,3)' OR is_nullable <> 'NO' OR column_default IS NOT NULL
OR column_comment <> '设备实测重量kg')
),
'ALTER TABLE fl_mojia_measurement_receipt MODIFY COLUMN weight_kg DECIMAL(18,3) NOT NULL COMMENT ''设备实测重量kg''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'sync_status'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN sync_status VARCHAR(24) NULL COMMENT ''SKU同步状态:PENDING/SYNCING/SUCCESS/FAILED'' AFTER status',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'sync_failure_code'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN sync_failure_code VARCHAR(64) NULL COMMENT ''SKU同步失败业务码'' AFTER sync_status',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'sync_failure_reason'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN sync_failure_reason VARCHAR(500) NULL COMMENT ''脱敏后的SKU同步失败原因'' AFTER sync_failure_code',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'lingxing_sku_id'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN lingxing_sku_id VARCHAR(128) NULL COMMENT ''领星SKU内部标识'' AFTER sync_failure_reason',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'revision'
),
'ALTER TABLE fl_mojia_measurement_receipt ADD COLUMN revision INT NOT NULL DEFAULT 1 COMMENT ''当前测量版本号'' AFTER lingxing_sku_id',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'match_failure_code' AND is_nullable = 'NO'
),
'ALTER TABLE fl_mojia_measurement_receipt MODIFY COLUMN match_failure_code VARCHAR(16) NULL COMMENT ''正式箱唛业务匹配失败码''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'match_failure_reason' AND is_nullable = 'NO'
),
'ALTER TABLE fl_mojia_measurement_receipt MODIFY COLUMN match_failure_reason VARCHAR(500) NULL COMMENT ''脱敏后的箱唛匹配失败原因''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'box_code'
AND column_comment <> '设备扫描的原始箱码或不带#的SKU'
),
'ALTER TABLE fl_mojia_measurement_receipt MODIFY COLUMN box_code VARCHAR(128) NOT NULL COMMENT ''设备扫描的原始箱码或不带#的SKU''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'fl_mojia_measurement_receipt'
AND column_name = 'status'
AND column_comment <> '原始收件状态;SKU记录使用SKU_PENDING_SYNC'
),
'ALTER TABLE fl_mojia_measurement_receipt MODIFY COLUMN status VARCHAR(24) NOT NULL DEFAULT ''UNMATCHED'' COMMENT ''原始收件状态;SKU记录使用SKU_PENDING_SYNC''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
-- ============================================================================
-- Lastleg:同一尾程单允许多次换标申请,订单关联由唯一索引改为普通索引
-- ============================================================================
USE baiyue_lastleg;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.statistics
WHERE table_schema = DATABASE() AND table_name = 'll_relabel_application'
AND index_name = 'uk_ll_relabel_application_order'
),
'ALTER TABLE ll_relabel_application DROP INDEX uk_ll_relabel_application_order',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @relabel_order_index_columns = (
SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index SEPARATOR ',')
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'll_relabel_application'
AND index_name = 'idx_ll_relabel_application_order'
);
SET @relabel_order_index_non_unique = (
SELECT MIN(non_unique)
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'll_relabel_application'
AND index_name = 'idx_ll_relabel_application_order'
);
SET @ddl = CASE
WHEN @relabel_order_index_columns IS NULL THEN
'ALTER TABLE ll_relabel_application ADD KEY idx_ll_relabel_application_order (lastleg_order_id)'
WHEN @relabel_order_index_columns <> 'lastleg_order_id'
OR @relabel_order_index_non_unique <> 1 THEN
'ALTER TABLE ll_relabel_application DROP INDEX idx_ll_relabel_application_order, ADD KEY idx_ll_relabel_application_order (lastleg_order_id)'
ELSE 'SELECT 1'
END;
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
-- ============================================================================
-- Overseas Warehouse:A0 系统共享溢出库位标记
-- 注意:正式 schema 名沿用项目现有拼写 baiyue_lastlag_warehouse。
-- ============================================================================
USE baiyue_lastlag_warehouse;
SET @ddl = IF(
NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'wh_location'
AND column_name = 'shared_overflow'
),
'ALTER TABLE wh_location ADD COLUMN shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否系统共享溢出库位(A0)'' AFTER location_type',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
SET @ddl = IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'wh_location'
AND column_name = 'shared_overflow'
AND (column_type <> 'tinyint(1)' OR is_nullable <> 'NO'
OR COALESCE(column_default, '') <> '0'
OR column_comment <> '是否系统共享溢出库位(A0)')
),
'ALTER TABLE wh_location MODIFY COLUMN shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否系统共享溢出库位(A0)''',
'SELECT 1'
);
PREPARE recent_schema_stmt FROM @ddl;
EXECUTE recent_schema_stmt;
DEALLOCATE PREPARE recent_schema_stmt;
-- 最终只读核对;四行均应返回 READY。
SELECT 'baiyue_iam' AS target_schema,
IF(
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = 'baiyue_iam' AND table_name = 'iam_membership' AND column_name = 'domestic_warehouse_id')
AND (SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index SEPARATOR ',') FROM information_schema.statistics WHERE table_schema = 'baiyue_iam' AND table_name = 'iam_membership' AND index_name = 'idx_membership_domestic_warehouse') = 'tenant_id,domestic_warehouse_id,status',
'READY', 'CHECK_REQUIRED'
) AS schema_status
UNION ALL
SELECT 'baiyue_firstleg',
IF(
(SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_mojia_measurement_receipt' AND column_name IN ('measurement_kind','weight_kg','sync_status','sync_failure_code','sync_failure_reason','lingxing_sku_id','revision')) = 7
AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_fee' AND column_name IN ('carrier_rate_id','carrier_rate_version','rate_effective_from') AND is_nullable = 'YES') = 3,
'READY', 'CHECK_REQUIRED'
)
UNION ALL
SELECT 'baiyue_lastleg',
IF(
NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = 'baiyue_lastleg' AND table_name = 'll_relabel_application' AND index_name = 'uk_ll_relabel_application_order')
AND (SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index SEPARATOR ',') FROM information_schema.statistics WHERE table_schema = 'baiyue_lastleg' AND table_name = 'll_relabel_application' AND index_name = 'idx_ll_relabel_application_order') = 'lastleg_order_id'
AND (SELECT MIN(non_unique) FROM information_schema.statistics WHERE table_schema = 'baiyue_lastleg' AND table_name = 'll_relabel_application' AND index_name = 'idx_ll_relabel_application_order') = 1,
'READY', 'CHECK_REQUIRED'
)
UNION ALL
SELECT 'baiyue_lastlag_warehouse',
IF(
EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'baiyue_lastlag_warehouse'
AND table_name = 'wh_location'
AND column_name = 'shared_overflow'
AND column_type = 'tinyint(1)'
AND is_nullable = 'NO'
AND COALESCE(column_default, '') = '0'
),
'READY', 'CHECK_REQUIRED'
);
-- 报关两文件流程:回执与真实报关完税文件分离。
-- 仅在已确认目标测试库后执行;所有 DDL 可重复执行,不创建数据库、不写业务数据。
USE baiyue_firstleg;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='fl_customs_container' AND column_name='broker_submitted_by'), 'ALTER TABLE fl_customs_container ADD COLUMN broker_submitted_by BIGINT UNSIGNED NULL COMMENT ''发送报关行执行的操作人ID''', 'SELECT 1');
PREPARE recent_customs_stmt FROM @ddl; EXECUTE recent_customs_stmt; DEALLOCATE PREPARE recent_customs_stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='fl_customs_container' AND column_name='broker_submitted_by_name'), 'ALTER TABLE fl_customs_container ADD COLUMN broker_submitted_by_name VARCHAR(64) NULL COMMENT ''发送报关行执行的操作人名称''', 'SELECT 1');
PREPARE recent_customs_stmt FROM @ddl; EXECUTE recent_customs_stmt; DEALLOCATE PREPARE recent_customs_stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='fl_customs_container' AND column_name='broker_submitted_at'), 'ALTER TABLE fl_customs_container ADD COLUMN broker_submitted_at DATETIME(3) NULL COMMENT ''发送报关行执行时间''', 'SELECT 1');
PREPARE recent_customs_stmt FROM @ddl; EXECUTE recent_customs_stmt; DEALLOCATE PREPARE recent_customs_stmt;
CREATE TABLE IF NOT EXISTS fl_customs_final_document (
id BIGINT UNSIGNED NOT NULL COMMENT '真实报关完税文件ID',
source_document_id BIGINT UNSIGNED NOT NULL COMMENT '对应冻结客户资料ID',
file_id BIGINT UNSIGNED NOT NULL COMMENT 'File服务文件ID',
file_name VARCHAR(255) NOT NULL COMMENT '真实报关完税文件名称快照',
file_hash CHAR(64) NOT NULL COMMENT '真实报关完税文件SHA-256摘要',
content_type VARCHAR(128) NULL COMMENT '真实报关完税文件媒体类型',
size_bytes BIGINT UNSIGNED NOT NULL COMMENT '真实报关完税文件大小(字节)',
uploaded_by BIGINT UNSIGNED NOT NULL COMMENT '上传操作人ID',
uploaded_by_name VARCHAR(64) NULL COMMENT '上传操作人名称快照',
uploaded_at DATETIME(3) NOT NULL COMMENT '上传时间',
version INT UNSIGNED NOT NULL DEFAULT 1 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_customs_final_source(source_document_id),
CONSTRAINT fk_customs_final_source FOREIGN KEY(source_document_id) REFERENCES fl_customs_customer_document(id)
) ENGINE=InnoDB COMMENT='真实报关完税文件当前版本';
-- 退货/换标近期结构增量汇总(MySQL 8.0+)
--
-- 目标数据库:baiyue_lastleg
-- 覆盖:退货箱级签收、箱级出库、退货合箱预占/追溯、换标箱唛总文件。
-- 本文件只执行 DDL,不写入业务数据;所有字段、索引和约束均按元数据判断,
-- 可在同一个目标库上重复执行。数据库不存在或基线表缺失时会立即报错并停止。
SET NAMES utf8mb4;
USE `baiyue_lastleg`;
-- 2026-09-29:箱维度退货出库不绑定托盘。
SET @ddl = IF(
EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'll_outbound_pallet_item')
AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_outbound_pallet_item' AND column_name = 'pallet_no' AND is_nullable = 'NO'),
'ALTER TABLE ll_outbound_pallet_item MODIFY COLUMN pallet_no VARCHAR(128) NULL COMMENT ''托盘号,箱维度出库为空''',
'SELECT 1'
);
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 2026-09-29:退货签收单元、SKU 箱数及来源实物追溯。
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'unit_type'), 'ALTER TABLE ll_return_receipt ADD COLUMN unit_type VARCHAR(16) NULL COMMENT ''签收类型 PALLET/BOX/PARCEL''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'unit_code'), 'ALTER TABLE ll_return_receipt ADD COLUMN unit_code VARCHAR(128) NULL COMMENT ''签收单元业务码''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'total_box_count'), 'ALTER TABLE ll_return_receipt ADD COLUMN total_box_count BIGINT NULL COMMENT ''签收 SKU 箱数汇总''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'length'), 'ALTER TABLE ll_return_receipt ADD COLUMN length DECIMAL(12,3) NULL COMMENT ''实测尺寸 cm''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'width'), 'ALTER TABLE ll_return_receipt ADD COLUMN width DECIMAL(12,3) NULL COMMENT ''实测尺寸 cm''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'height'), 'ALTER TABLE ll_return_receipt ADD COLUMN height DECIMAL(12,3) NULL COMMENT ''实测尺寸 cm''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name = 'weight'), 'ALTER TABLE ll_return_receipt ADD COLUMN weight DECIMAL(12,3) NULL COMMENT ''实测重量 kg''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt_item' AND column_name = 'box_count'), 'ALTER TABLE ll_return_receipt_item ADD COLUMN box_count BIGINT NULL COMMENT ''SKU 签收箱数''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND column_name = 'source_unit_type'), 'ALTER TABLE ll_return_inventory_carton ADD COLUMN source_unit_type VARCHAR(32) NULL COMMENT ''来源实物类型''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND column_name = 'source_unit_code'), 'ALTER TABLE ll_return_inventory_carton ADD COLUMN source_unit_code VARCHAR(128) NULL COMMENT ''来源实物业务码''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 2026-09-29:换标箱唛总文件。
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_relabel_application' AND column_name = 'carton_total_file_id'), 'ALTER TABLE ll_relabel_application ADD COLUMN carton_total_file_id VARCHAR(128) NULL COMMENT ''箱唛总文件 ID''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_relabel_application' AND column_name = 'carton_total_file_name'), 'ALTER TABLE ll_relabel_application ADD COLUMN carton_total_file_name VARCHAR(255) NULL COMMENT ''箱唛总文件名''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 合箱计划及精确来源/结果快照。
CREATE TABLE IF NOT EXISTS ll_return_packing_plan (
id BIGINT NOT NULL COMMENT '合箱计划 ID', plan_no VARCHAR(128) NOT NULL COMMENT '计划业务号',
customer_id VARCHAR(128) NOT NULL COMMENT '客户隔离键', overseas_warehouse_id VARCHAR(128) NOT NULL COMMENT '海外仓 ID',
return_nos_json JSON NOT NULL COMMENT '来源退货单范围', boxes_json JSON NOT NULL COMMENT '目标箱明细',
mode VARCHAR(32) NOT NULL COMMENT 'SKU 散件或 BOX 箱合并', status VARCHAR(32) NOT NULL COMMENT '计划状态',
remark VARCHAR(1000) NULL COMMENT '合箱备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '创建幂等键',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '更新时间',
pushed_at DATETIME(3) NULL COMMENT '审核推送时间', completed_at DATETIME(3) NULL COMMENT '作业完成时间',
PRIMARY KEY (id), UNIQUE KEY uk_ll_return_packing_plan_no (plan_no),
UNIQUE KEY uk_ll_return_packing_plan_key (customer_id, idempotency_key),
KEY idx_ll_return_packing_plan_warehouse (overseas_warehouse_id, status, pushed_at)
) ENGINE=InnoDB COMMENT='退货合箱计划';
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_plan' AND column_name = 'source_items_json'), 'ALTER TABLE ll_return_packing_plan ADD COLUMN source_items_json JSON NULL COMMENT ''精确来源箱和 SKU 锁定数量''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_plan' AND column_name = 'result_marks_json'), 'ALTER TABLE ll_return_packing_plan ADD COLUMN result_marks_json JSON NULL COMMENT ''完成生成或并入的目标箱唛''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_plan' AND column_name = 'request_hash'), 'ALTER TABLE ll_return_packing_plan ADD COLUMN request_hash VARCHAR(64) NULL COMMENT ''创建载荷摘要''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_plan' AND column_name = 'completion_hash'), 'ALTER TABLE ll_return_packing_plan ADD COLUMN completion_hash VARCHAR(64) NULL COMMENT ''完成载荷摘要''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_plan' AND column_name = 'result_labels_json'), 'ALTER TABLE ll_return_packing_plan ADD COLUMN result_labels_json JSON NULL COMMENT ''计划完工标签快照''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton_item' AND column_name = 'packing_reserved_quantity'), 'ALTER TABLE ll_return_inventory_carton_item ADD COLUMN packing_reserved_quantity BIGINT NOT NULL DEFAULT 0 COMMENT ''合箱计划预占件数''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND column_name = 'location_code'), 'ALTER TABLE ll_return_inventory_carton ADD COLUMN location_code VARCHAR(128) NULL COMMENT ''退货箱当前库位''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND column_name = 'putaway_at'), 'ALTER TABLE ll_return_inventory_carton ADD COLUMN putaway_at DATETIME(3) NULL COMMENT ''退货箱上架时间''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_operation' AND column_name = 'result_json'), 'ALTER TABLE ll_return_inventory_operation ADD COLUMN result_json JSON NULL COMMENT ''幂等操作不可变返回快照''', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS ll_return_packing_trace (
id BIGINT NOT NULL COMMENT '合箱追溯 ID', customer_id VARCHAR(128) NOT NULL COMMENT '原客户隔离键',
operation_id BIGINT NOT NULL COMMENT '合箱操作 ID', source_carton_mark VARCHAR(128) NOT NULL COMMENT '来源箱唛',
target_carton_mark VARCHAR(128) NOT NULL COMMENT '目标箱唛', return_no VARCHAR(128) NOT NULL COMMENT '原始退货单号',
sku_code VARCHAR(128) NOT NULL COMMENT 'SKU', quantity BIGINT NOT NULL COMMENT '本次移动件数',
created_at DATETIME(3) NOT NULL COMMENT '发生时间', PRIMARY KEY (id),
KEY idx_return_packing_trace_order (customer_id, return_no, created_at),
KEY idx_return_packing_trace_target (customer_id, target_carton_mark, sku_code),
KEY idx_return_packing_trace_source (customer_id, source_carton_mark, sku_code),
CONSTRAINT chk_return_packing_trace_quantity CHECK (quantity > 0)
) ENGINE=InnoDB COMMENT='退货合箱逐 SKU 原始退货单不可变追溯';
-- 原子替换两个 CHECK;新定义验证失败时原约束保留。
SET @recent_drop_check_0 = IF(EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND constraint_name='chk_ll_return_inventory_carton_quantity'), 'DROP CHECK chk_ll_return_inventory_carton_quantity, ', '');
SET @recent_drop_check_1 = IF(EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_schema=DATABASE() AND table_name='ll_return_inventory_carton' AND constraint_name='chk_ll_return_inventory_carton_status'), 'DROP CHECK chk_ll_return_inventory_carton_status, ', '');
SET @ddl = CONCAT('ALTER TABLE ll_return_inventory_carton ', @recent_drop_check_0, @recent_drop_check_1, 'ADD CONSTRAINT chk_ll_return_inventory_carton_quantity CHECK ((status IN (''AVAILABLE'',''PACKING_RESERVED'',''RELABEL_PENDING'',''OUTBOUND_PENDING'',''OUTBOUNDED'',''DISCARD_PENDING'') AND sku_types>0 AND total_quantity>0) OR (status IN (''MERGED'',''DISCARDED'') AND sku_types=0 AND total_quantity=0)), ADD CONSTRAINT chk_ll_return_inventory_carton_status CHECK (status IN (''AVAILABLE'',''PACKING_RESERVED'',''RELABEL_PENDING'',''OUTBOUND_PENDING'',''MERGED'',''OUTBOUNDED'',''DISCARD_PENDING'',''DISCARDED''))');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 同一签收批次可拆成多个退货箱:唯一约束改为普通索引。
SET @ddl = IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND index_name = 'uk_ll_return_inventory_carton_receipt'), 'ALTER TABLE ll_return_inventory_carton DROP INDEX uk_ll_return_inventory_carton_receipt', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = IF(NOT EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND index_name = 'idx_ll_return_inventory_carton_receipt'), 'ALTER TABLE ll_return_inventory_carton ADD INDEX idx_ll_return_inventory_carton_receipt (source_receipt_id)', 'SELECT 1');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SELECT DATABASE() AS target_database,
IF((SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_return_receipt' AND column_name IN ('unit_type','unit_code','total_box_count','length','width','height','weight')) = 7, 'READY', 'CHECK_REQUIRED') AS receipt_schema,
IF(EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_plan') AND EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'll_return_packing_trace'), 'READY', 'CHECK_REQUIRED') AS packing_schema,
IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'll_return_inventory_carton' AND index_name = 'idx_ll_return_inventory_carton_receipt'), 'READY', 'CHECK_REQUIRED') AS carton_index;