Merge origin/dev and resolve backend conflicts

This commit is contained in:
2026-09-08 20:50:28 +08:00
342 changed files with 13161 additions and 2296 deletions
+2 -2
View File
@@ -230,9 +230,9 @@ SELECT
## 海外排车、出库与派送权限
- 国内固定入口已在海外仓业务 `lastleg-permissions.sql` 权限段之后完整内联 `iam/src/main/resources/db/phase5-delivery-permissions.sql`;测试和部署只执行固定入口,不再单独执行模块脚本。
- 平台端固定使用排车列表/编辑/取消/转派送、出库列表/创建/取消、派送列表/退回/状态、异常订单列表/创建和客户回访列表/编辑十四项权限;列表权限包含详情及只读辅助接口,写操作保持独立授权。
- 平台端固定使用排车列表/编辑/取消/转派送、出库列表/创建/取消、派送列表/退回/状态、异常订单列表/创建/处理和客户回访列表/编辑十五项权限;列表权限包含详情及只读辅助接口,写操作保持独立授权。
- 客户端固定使用 `merchant:warehouse:delivery:list` 和 `merchant:warehouse:delivery:create`;客户默认管理员获得两项权限,其他客户角色不自动扩权。
- `WAREHOUSE_OPERATOR` 获得十四项后台作业权限,`WAREHOUSE_TALLY` 只获得排车、出库、派送、异常订单和客户回访五项列表只读;国内、海外 PDA 岗位不得获得上述后台权限。
- `WAREHOUSE_OPERATOR` 获得十五项后台作业权限,`WAREHOUSE_TALLY` 只获得排车、出库、派送、异常订单和客户回访五项列表只读;国内、海外 PDA 岗位不得获得上述后台权限。
## 海外排车与出库结构升级
+541 -82
View File
@@ -2860,6 +2860,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
cargo_item_no INT UNSIGNED NOT NULL COMMENT '订单货物明细序号快照',
cargo_name VARCHAR(255) NULL COMMENT '货物名称快照',
sku_code VARCHAR(128) NULL COMMENT '箱唛绑定的SKU快照;二维码内容不变',
units_per_carton INT UNSIGNED 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 '固定二维码内容:入仓码#总箱数-箱下标',
@@ -2877,7 +2878,6 @@ CREATE TABLE IF NOT EXISTS fl_inbound_carton_label (
PRIMARY KEY (id),
UNIQUE KEY uk_carton_label_box_code (tenant_id, box_code),
UNIQUE KEY uk_carton_label_index (tenant_id, inbound_id, label_version, carton_index),
KEY idx_carton_label_active (tenant_id, inbound_id, batch_status, label_version),
KEY idx_carton_label_detail (tenant_id, inbound_id, inbound_detail_id),
CONSTRAINT fk_carton_label_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order (id)
) ENGINE=InnoDB COMMENT='首次打印前冻结的实际箱号与订单货物明细映射';
@@ -3139,6 +3139,8 @@ CREATE TABLE IF NOT EXISTS fl_inbound_fee (
actual_weight_kg DECIMAL(18,3) NOT NULL COMMENT '试算时实际重量kg',
actual_volume_cbm DECIMAL(18,4) NOT NULL COMMENT '试算时实际体积m3',
converted_quantity DECIMAL(18,4) NOT NULL COMMENT '换算后的重量或体积',
baseline_chargeable_quantity DECIMAL(18,6) NOT NULL COMMENT '系统按权威测量与生效报价计算的原始计费量',
tolerance_percent DECIMAL(5,2) NOT NULL DEFAULT 10.00 COMMENT '人工调整允许的最大偏差百分比,边界包含',
chargeable_quantity DECIMAL(18,4) NOT NULL COMMENT '最终计费量',
charge_unit VARCHAR(16) NOT NULL COMMENT '计费单位',
currency CHAR(3) NOT NULL COMMENT '币种',
@@ -3172,6 +3174,32 @@ ALTER TABLE fl_inbound_fee
MODIFY COLUMN customer_id BIGINT UNSIGNED NULL
COMMENT '可选业务客户快照;平台公共渠道计费不依赖该字段';
SET @fee_baseline_quantity_sql = IF(
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='fl_inbound_fee' AND column_name='baseline_chargeable_quantity'),
'SELECT 1',
'ALTER TABLE fl_inbound_fee ADD COLUMN baseline_chargeable_quantity DECIMAL(18,6) NULL COMMENT ''系统按权威测量与生效报价计算的原始计费量'' AFTER converted_quantity'
);
PREPARE fee_baseline_quantity_stmt FROM @fee_baseline_quantity_sql;
EXECUTE fee_baseline_quantity_stmt;
DEALLOCATE PREPARE fee_baseline_quantity_stmt;
UPDATE fl_inbound_fee
SET baseline_chargeable_quantity = chargeable_quantity
WHERE baseline_chargeable_quantity IS NULL;
ALTER TABLE fl_inbound_fee
MODIFY COLUMN baseline_chargeable_quantity DECIMAL(18,6) NOT NULL
COMMENT '系统按权威测量与生效报价计算的原始计费量';
SET @fee_tolerance_percent_sql = IF(
EXISTS(SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='fl_inbound_fee' AND column_name='tolerance_percent'),
'SELECT 1',
'ALTER TABLE fl_inbound_fee ADD COLUMN tolerance_percent DECIMAL(5,2) NOT NULL DEFAULT 10.00 COMMENT ''人工调整允许的最大偏差百分比,边界包含'' AFTER baseline_chargeable_quantity'
);
PREPARE fee_tolerance_percent_stmt FROM @fee_tolerance_percent_sql;
EXECUTE fee_tolerance_percent_stmt;
DEALLOCATE PREPARE fee_tolerance_percent_stmt;
CREATE TABLE IF NOT EXISTS fl_inbound_fee_item (
id BIGINT UNSIGNED NOT NULL COMMENT '费用明细ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
@@ -3783,7 +3811,7 @@ CREATE TABLE IF NOT EXISTS fl_price_warehouse_mapping (
CREATE TABLE IF NOT EXISTS fl_price_book_version (
id BIGINT UNSIGNED NOT NULL COMMENT '整表价格版本ID',
tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '平台公共价格作用域固定为0',
tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '报价作用域:0平台公共,正数为客户专属',
version_no INT UNSIGNED NOT NULL COMMENT '整表版本号',
original_file_name VARCHAR(255) NOT NULL COMMENT '原始Excel文件名',
source_file_id BIGINT UNSIGNED NULL COMMENT 'File服务原始文件ID',
@@ -5190,6 +5218,10 @@ CREATE TABLE IF NOT EXISTS fl_loading_plan_item (
product_image_url VARCHAR(1000) NULL COMMENT '产品图片访问地址快照',
package_count INT UNSIGNED NOT NULL COMMENT '本次装柜箱数',
product_quantity INT UNSIGNED NULL COMMENT '产品总数量',
unit_type VARCHAR(24) NOT NULL DEFAULT 'PACKAGE' COMMENT '分配单元:PACKAGE普通箱、SEALED_PALLET一件代发封托',
pallet_id BIGINT UNSIGNED NULL COMMENT '一件代发封托ID;普通箱为空',
pallet_no VARCHAR(32) NULL COMMENT '一件代发系统托盘码快照',
indivisible TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否为不可拆整托单元',
units_per_carton INT UNSIGNED NULL COMMENT '每箱产品数',
pallet_count INT UNSIGNED NULL COMMENT '托盘数',
gross_weight_kg DECIMAL(18,3) NULL COMMENT '本次装柜毛重kg',
@@ -5210,24 +5242,23 @@ CREATE TABLE IF NOT EXISTS fl_loading_plan_item (
removed_by_name VARCHAR(64) NULL COMMENT '推送前逻辑删除操作人名称快照',
removed_at DATETIME(3) NULL COMMENT '推送前逻辑删除时间',
deleted TINYINT(1) NOT NULL DEFAULT 0 COMMENT '推送前逻辑删除标记;冻结后不可修改',
active_inbound_detail_id BIGINT UNSIGNED GENERATED ALWAYS AS (
CASE WHEN deleted = 0 THEN inbound_detail_id ELSE NULL END
) STORED COMMENT '未删除明细唯一锁;删除后返回NULL释放分配资格',
active_inbound_detail_id BIGINT UNSIGNED GENERATED ALWAYS AS (CASE WHEN deleted = 0 THEN inbound_detail_id ELSE NULL END) STORED COMMENT '未删除明细查询键;删除后返回NULL',
active_assignment_key VARCHAR(96) GENERATED ALWAYS AS (CASE WHEN deleted = 0 THEN CONCAT(CASE WHEN pallet_id IS NULL THEN 'D:0' ELSE CONCAT('P:', pallet_id) END, ':', inbound_detail_id) ELSE NULL END) STORED COMMENT '普通明细或已封托托盘明细的有效唯一锁',
created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID',
updated_by_name VARCHAR(64) NULL COMMENT '最后修改人名称快照',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
COMMENT '装柜明细最后更新时间',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '装柜明细最后更新时间',
version INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id),
UNIQUE KEY uk_loading_item_plan_detail (loading_plan_id, active_inbound_detail_id),
UNIQUE KEY uk_loading_item_plan_assignment (loading_plan_id, active_assignment_key),
KEY idx_loading_item_active_detail (account_id, active_inbound_detail_id),
KEY idx_loading_item_plan (loading_plan_id, deleted, load_sequence, id),
KEY idx_loading_item_account (account_id, created_at, id),
KEY idx_loading_item_inbound (account_id, inbound_id, deleted),
KEY idx_loading_item_candidate (account_id, inbound_id, inbound_detail_id, deleted),
KEY idx_loading_item_pallet (pallet_id, deleted),
KEY idx_loading_item_order (account_id, order_id, deleted),
CONSTRAINT fk_loading_item_plan FOREIGN KEY (loading_plan_id) REFERENCES fl_loading_plan (id),
CONSTRAINT chk_loading_item_account CHECK (account_id > 0),
@@ -5555,65 +5586,7 @@ 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 $$
@@ -6276,12 +6249,13 @@ BEGIN
'destination_warehouse_name', 'product_name_zh', 'product_name_en',
'product_image_file_id', 'pallet_count', 'net_weight_kg',
'dimensional_weight_kg', 'product_quantity', 'units_per_carton',
'fba_tracking_no', 'shipment_no', 'shipping_mark', 'version')) <> 17 THEN
'unit_type', 'pallet_id', 'pallet_no', 'indivisible', 'active_assignment_key',
'fba_tracking_no', 'shipment_no', 'shipping_mark', 'version')) <> 22 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_loading_plan_item'
AND index_name = 'uk_loading_item_plan_detail' AND non_unique = 0) <> 2 THEN
AND index_name = 'uk_loading_item_plan_assignment' AND non_unique = 0) <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:计划内唯一活动明细锁缺失';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns
@@ -7681,6 +7655,15 @@ SELECT 193000000001000111, 0, 'FBA_HEAD_FREIGHT', '头程运费', 'INTERNATIONAL
0, 'system', '2026-08-14 00:00:00.000', 0, 'system', '2026-08-14 00:00:00.000'
WHERE NOT EXISTS (SELECT 1 FROM fl_fee_item WHERE fee_code = 'FBA_HEAD_FREIGHT');
INSERT INTO fl_fee_item (id, tenant_id, fee_code, category, trade_scope, fee_type_name,
pickup_payable, pickup_receivable, warehouse_payable, warehouse_receivable,
allocation_fee, description, status, created_by, created_by_name, created_at,
updated_by, updated_by_name, updated_at, deleted, version)
SELECT 193000000001000112, 0, 'PRIVATE_LAST_MILE_DELIVERY', '尾程派送费', 'INTERNATIONAL',
'私人仓尾程派送费', 0, 0, 1, 1, 0, '仅用于destinationType=PRIVATE的入库单',
'ACTIVE', 0, 'SYSTEM', CURRENT_TIMESTAMP(3), 0, 'SYSTEM', CURRENT_TIMESTAMP(3), 0, 0
WHERE NOT EXISTS (SELECT 1 FROM fl_fee_item WHERE fee_code = 'PRIVATE_LAST_MILE_DELIVERY');
-- ============================================================================
-- 2026-08-06:三期分柜、预装、拣货、装柜和派送当前基线
-- ============================================================================
@@ -8045,6 +8028,57 @@ SELECT role.id, permission.id, role.tenant_id
)
WHERE role.tenant_id = 0 AND role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR');
-- 已存在库必须先把装柜分配唯一键收敛到“普通明细或封托托盘”,再执行三期断言。
USE baiyue_firstleg;
DROP PROCEDURE IF EXISTS converge_loading_assignment_schema;
DELIMITER $$
CREATE PROCEDURE converge_loading_assignment_schema()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND column_name='unit_type') THEN
ALTER TABLE fl_loading_plan_item
ADD COLUMN unit_type VARCHAR(24) NOT NULL DEFAULT 'PACKAGE'
COMMENT '分配单元:PACKAGE普通箱、SEALED_PALLET一件代发封托' AFTER product_quantity,
ADD COLUMN pallet_id BIGINT UNSIGNED NULL COMMENT '一件代发封托ID;普通箱为空' AFTER unit_type,
ADD COLUMN pallet_no VARCHAR(32) NULL COMMENT '一件代发系统托盘码快照' AFTER pallet_id,
ADD COLUMN indivisible TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否为不可拆整托单元' AFTER pallet_no;
END IF;
ALTER TABLE fl_loading_plan_item
MODIFY COLUMN unit_type VARCHAR(24) NOT NULL DEFAULT 'PACKAGE'
COMMENT '分配单元:PACKAGE普通箱、SEALED_PALLET一件代发封托',
MODIFY COLUMN pallet_id BIGINT UNSIGNED NULL COMMENT '一件代发封托ID;普通箱为空',
MODIFY COLUMN pallet_no VARCHAR(32) NULL COMMENT '一件代发系统托盘码快照',
MODIFY COLUMN indivisible TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否为不可拆整托单元';
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND column_name='active_assignment_key') THEN
ALTER TABLE fl_loading_plan_item
ADD COLUMN active_assignment_key VARCHAR(96)
GENERATED ALWAYS AS (CASE WHEN deleted=0 THEN CONCAT(CASE WHEN pallet_id IS NULL THEN 'D:0' ELSE CONCAT('P:',pallet_id) END,':',inbound_detail_id) ELSE NULL END) STORED
COMMENT '普通明细或已封托托盘明细的有效唯一锁' AFTER active_inbound_detail_id;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND index_name='uk_loading_item_plan_detail') THEN
ALTER TABLE fl_loading_plan_item DROP INDEX uk_loading_item_plan_detail;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND index_name='uk_loading_item_plan_assignment') THEN
ALTER TABLE fl_loading_plan_item
ADD UNIQUE KEY uk_loading_item_plan_assignment (loading_plan_id,active_assignment_key);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND index_name='idx_loading_item_pallet') THEN
ALTER TABLE fl_loading_plan_item ADD KEY idx_loading_item_pallet (pallet_id,deleted);
END IF;
END$$
DELIMITER ;
CALL converge_loading_assignment_schema();
DROP PROCEDURE IF EXISTS converge_loading_assignment_schema;
-- 污染存量库必须先完成旧入库权限搬迁和两类授权恢复,再校验智能装柜权限。
USE baiyue_firstleg;
CALL assert_phase3_smart_loading_schema();
@@ -13473,10 +13507,12 @@ CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'charge_rule_id',
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'charge_rule_version', '历史客户规则版本快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'charge_unit', '计费单位');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'chargeable_quantity', '最终计费量');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'baseline_chargeable_quantity', '系统按权威测量与生效报价计算的原始计费量');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'confirmed_at', '确认时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'confirmed_by', '确认人ID');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'conversion_factor', '历史客户规则使用的换算系数快照');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'converted_quantity', '换算后的重量或体积');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'tolerance_percent', '人工调整允许的最大偏差百分比,边界包含');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'created_at', '创建时间');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'currency', '币种');
CALL queue_column_comment('baiyue_firstleg', 'fl_inbound_fee', 'customer_id', '客户ID快照');
@@ -15153,6 +15189,15 @@ BEGIN
'baiyue_firstleg','baiyue_file','baiyue_audit','baiyue_event_bridge','baiyue_finance'))<>9 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_fee'
AND ((column_name='baseline_chargeable_quantity' AND is_nullable='NO'
AND numeric_precision=18 AND numeric_scale=6)
OR (column_name='tolerance_percent' AND is_nullable='NO'
AND numeric_precision=5 AND numeric_scale=2))) <> 2 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '统一迁移失败:入库费用基准计费量或容差字段不完整';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns
WHERE table_schema='baiyue_iam' AND table_name='iam_tenant'
AND column_name='dimension_initialization_status') <> 1
@@ -15607,6 +15652,11 @@ BEGIN
AND category = '头程运费' AND trade_scope = 'INTERNATIONAL' AND fee_type_name = 'FBA头程运费'
AND pickup_payable = 0 AND pickup_receivable = 0 AND warehouse_payable = 0
AND warehouse_receivable = 1 AND allocation_fee = 0 AND status = 'ACTIVE' AND deleted = 0) <> 1
OR (SELECT COUNT(*) FROM baiyue_firstleg.fl_fee_item
WHERE tenant_id = 0 AND fee_code = 'PRIVATE_LAST_MILE_DELIVERY'
AND category = '尾程派送费' AND trade_scope = 'INTERNATIONAL'
AND fee_type_name = '私人仓尾程派送费' AND warehouse_payable = 1
AND warehouse_receivable = 1 AND status = 'ACTIVE' AND deleted = 0) <> 1
OR EXISTS (
SELECT 1
FROM baiyue_firstleg.fl_inbound_fee_detail detail
@@ -16955,6 +17005,7 @@ BEGIN
OR (id = 5107093 AND permission_code <> 'platform:overseas-warehouse:outbound:cancel')
OR (id = 5107070 AND permission_code <> 'platform:overseas-warehouse:exception-order:list')
OR (id = 5107071 AND permission_code <> 'platform:overseas-warehouse:exception-order:create')
OR (id = 5107073 AND permission_code <> 'platform:overseas-warehouse:exception-order:process')
OR (id = 5107072 AND permission_code <> 'platform:overseas-warehouse:delivery:return')
OR (id = 5107080 AND permission_code <> 'platform:overseas-warehouse:customer-visit:list')
OR (id = 5107081 AND permission_code <> 'platform:overseas-warehouse:customer-visit:edit')
@@ -16973,6 +17024,7 @@ BEGIN
OR (permission_code = 'platform:overseas-warehouse:outbound:cancel' AND id <> 5107093)
OR (permission_code = 'platform:overseas-warehouse:exception-order:list' AND id <> 5107070)
OR (permission_code = 'platform:overseas-warehouse:exception-order:create' AND id <> 5107071)
OR (permission_code = 'platform:overseas-warehouse:exception-order:process' AND id <> 5107073)
OR (permission_code = 'platform:overseas-warehouse:delivery:return' AND id <> 5107072)
OR (permission_code = 'platform:overseas-warehouse:customer-visit:list' AND id <> 5107080)
OR (permission_code = 'platform:overseas-warehouse:customer-visit:edit' AND id <> 5107081)
@@ -16997,6 +17049,7 @@ VALUES
(5107018,0,'PLATFORM','BUTTON',5107064,'platform:overseas-warehouse:dispatch:transfer-delivery','排车转派送',NULL,'POST',718,'ACTIVE',1,0),
(5107070,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:exception-order:list','海外异常订单','/overseas-warehouse/exception-orders','GET',770,'ACTIVE',1,0),
(5107071,0,'PLATFORM','BUTTON',5107070,'platform:overseas-warehouse:exception-order:create','新增海外异常订单',NULL,'POST',771,'ACTIVE',1,0),
(5107073,0,'PLATFORM','BUTTON',5107070,'platform:overseas-warehouse:exception-order:process','处理海外异常订单',NULL,'POST',773,'ACTIVE',1,0),
(5107072,0,'PLATFORM','BUTTON',5107092,'platform:overseas-warehouse:delivery:return','派送单标记退货',NULL,'POST',772,'ACTIVE',1,0),
(5107080,0,'PLATFORM','MENU',0,'platform:overseas-warehouse:customer-visit:list','客户回访','/overseas-warehouse/customer-visits','GET',780,'ACTIVE',1,0),
(5107081,0,'PLATFORM','BUTTON',5107080,'platform:overseas-warehouse:customer-visit:edit','保存客户回访',NULL,'PUT',781,'ACTIVE',1,0),
@@ -17032,6 +17085,7 @@ SELECT 0, role.id, permission.id, CURRENT_TIMESTAMP(3)
'platform:overseas-warehouse:delivery:list',
'platform:overseas-warehouse:exception-order:list',
'platform:overseas-warehouse:exception-order:create',
'platform:overseas-warehouse:exception-order:process',
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
@@ -17056,6 +17110,7 @@ INSERT INTO tmp_phase5_delivery_role_permission (role_code, permission_code) VAL
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:list'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:create'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:exception-order:process'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:return'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:delivery:status'),
('WAREHOUSE_OPERATOR','platform:overseas-warehouse:customer-visit:list'),
@@ -17084,6 +17139,7 @@ WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
'platform:overseas-warehouse:delivery:list',
'platform:overseas-warehouse:exception-order:list',
'platform:overseas-warehouse:exception-order:create',
'platform:overseas-warehouse:exception-order:process',
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
@@ -17131,12 +17187,13 @@ BEGIN
'platform:overseas-warehouse:delivery:list',
'platform:overseas-warehouse:exception-order:list',
'platform:overseas-warehouse:exception-order:create',
'platform:overseas-warehouse:exception-order:process',
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
'platform:overseas-warehouse:customer-visit:edit',
'merchant:warehouse:delivery:list',
'merchant:warehouse:delivery:create')) <> 16 THEN
'merchant:warehouse:delivery:create')) <> 17 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:权限目录不完整';
END IF;
IF (SELECT COUNT(*) FROM iam_role_permission grant_row
@@ -17154,10 +17211,11 @@ BEGIN
'platform:overseas-warehouse:delivery:list',
'platform:overseas-warehouse:exception-order:list',
'platform:overseas-warehouse:exception-order:create',
'platform:overseas-warehouse:exception-order:process',
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN
'platform:overseas-warehouse:customer-visit:edit')) <> 15 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台管理员授权不完整';
END IF;
IF EXISTS (SELECT 1 FROM iam_role role
@@ -17178,17 +17236,18 @@ BEGIN
'platform:overseas-warehouse:delivery:list',
'platform:overseas-warehouse:exception-order:list',
'platform:overseas-warehouse:exception-order:create',
'platform:overseas-warehouse:exception-order:process',
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
'platform:overseas-warehouse:customer-visit:edit')) <> 14) THEN
'platform:overseas-warehouse:customer-visit:edit')) <> 15) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台自定义管理员授权不完整';
END IF;
SELECT COALESCE(SUM(role_code='WAREHOUSE_OPERATOR'),0),
COALESCE(SUM(role_code='WAREHOUSE_TALLY'),0)
INTO v_warehouse_operator_permission_count, v_warehouse_tally_permission_count
FROM tmp_phase5_delivery_role_permission;
IF v_warehouse_operator_permission_count <> 14
IF v_warehouse_operator_permission_count <> 15
OR v_warehouse_tally_permission_count <> 5 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:仓库岗位最小权限矩阵异常';
END IF;
@@ -17207,6 +17266,7 @@ BEGIN
'platform:overseas-warehouse:delivery:list',
'platform:overseas-warehouse:exception-order:list',
'platform:overseas-warehouse:exception-order:create',
'platform:overseas-warehouse:exception-order:process',
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
@@ -17393,7 +17453,9 @@ CREATE TABLE IF NOT EXISTS fl_dropship_pallet_task (
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '作业仓库ID',
task_status VARCHAR(24) NOT NULL COMMENT '任务状态:PENDING待领取、CLAIMED已领取、COMPLETED已完成',
total_cartons INT UNSIGNED NOT NULL COMMENT '测量确认总箱数',
counted_cartons INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '已逐箱确认实收数量的箱数',
allocated_cartons INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '已上托箱数',
discrepancy_cartons INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '已确认差异箱数',
assignee_id BIGINT UNSIGNED NULL COMMENT '任务领取人ID',
assignee_name VARCHAR(64) NULL COMMENT '任务领取人姓名快照',
claimed_at DATETIME(3) NULL COMMENT '任务领取时间',
@@ -17406,7 +17468,7 @@ CREATE TABLE IF NOT EXISTS fl_dropship_pallet_task (
KEY idx_dropship_task_operator (task_status,assignee_id,warehouse_id,created_at),
CONSTRAINT fk_dropship_task_inbound FOREIGN KEY (inbound_id) REFERENCES fl_inbound_order(id),
CONSTRAINT chk_dropship_task_status CHECK (task_status IN ('PENDING','CLAIMED','COMPLETED')),
CONSTRAINT chk_dropship_task_cartons CHECK (allocated_cartons<=total_cartons)
CONSTRAINT chk_dropship_task_cartons CHECK (allocated_cartons<=counted_cartons AND counted_cartons<=total_cartons)
) ENGINE=InnoDB COMMENT='一件代发测量后PDA合托任务';
CREATE TABLE IF NOT EXISTS fl_dropship_pallet (
@@ -17415,8 +17477,8 @@ CREATE TABLE IF NOT EXISTS fl_dropship_pallet (
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离键',
inbound_id BIGINT UNSIGNED NOT NULL COMMENT '一件代发入仓单ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '作业仓库ID',
pallet_no VARCHAR(32) NULL COMMENT '封托时生成的DP托盘号',
pallet_status VARCHAR(16) NOT NULL COMMENT '托盘状态:OPEN合托中、COMPLETED已封托',
pallet_no VARCHAR(32) NOT NULL COMMENT '现场扫描的系统DP托盘码',
pallet_status VARCHAR(16) NOT NULL COMMENT '托盘状态:OPEN组托中、SEALED已封托',
open_operation_id VARCHAR(128) NOT NULL COMMENT '创建托盘幂等操作ID',
seal_operation_id VARCHAR(128) NULL COMMENT '封托幂等操作ID',
created_by BIGINT UNSIGNED NOT NULL COMMENT '托盘创建人ID',
@@ -17433,7 +17495,7 @@ CREATE TABLE IF NOT EXISTS fl_dropship_pallet (
UNIQUE KEY uk_dropship_pallet_seal_op (seal_operation_id),
KEY idx_dropship_pallet_inbound (tenant_id,inbound_id,pallet_status),
CONSTRAINT fk_dropship_pallet_task FOREIGN KEY (task_id) REFERENCES fl_dropship_pallet_task(id),
CONSTRAINT chk_dropship_pallet_status CHECK (pallet_status IN ('OPEN','COMPLETED'))
CONSTRAINT chk_dropship_pallet_status CHECK (pallet_status IN ('OPEN','SEALED'))
) ENGINE=InnoDB COMMENT='一件代发合托形成的可打印托盘';
CALL queue_column_comment('baiyue_firstleg','fl_loading_cabinet_evidence','id','柜次证据记录ID');
@@ -17500,28 +17562,182 @@ DROP TEMPORARY TABLE IF EXISTS tmp_table_comment_target;
CREATE TABLE IF NOT EXISTS fl_dropship_pallet_carton (
id BIGINT UNSIGNED NOT NULL COMMENT '托盘箱明细ID',
task_id BIGINT UNSIGNED NOT NULL COMMENT '所属合托任务ID',
pallet_id BIGINT UNSIGNED NOT NULL COMMENT '所属合托托盘ID',
pallet_id BIGINT UNSIGNED NULL COMMENT '所属组托托盘ID;已清点待绑托时为空',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户隔离键',
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',
sku_code VARCHAR(128) NOT NULL COMMENT '箱唛冻结SKU编码',
cargo_name VARCHAR(255) NULL COMMENT '货物名称快照',
box_code VARCHAR(64) NOT NULL COMMENT '稳定箱码',
operation_id VARCHAR(128) NOT NULL COMMENT '上托幂等操作ID',
bound_by BIGINT UNSIGNED NOT NULL COMMENT '上托操作人ID',
box_code VARCHAR(80) NOT NULL COMMENT '稳定箱码',
expected_sku_quantity INT UNSIGNED NOT NULL COMMENT '箱唛冻结的应收SKU数量',
actual_sku_quantity INT UNSIGNED NOT NULL COMMENT 'PDA确认的实收SKU数量',
discrepancy_status VARCHAR(24) NOT NULL COMMENT '差异状态:MATCH或ACCEPTED_VARIANCE',
discrepancy_remark VARCHAR(500) NULL COMMENT '差异接受说明',
count_operation_id VARCHAR(128) NOT NULL COMMENT '逐箱清点幂等操作ID',
bind_operation_id VARCHAR(128) NULL COMMENT '批量绑托幂等操作ID',
last_operation_id VARCHAR(128) NOT NULL COMMENT '最后一次绑托或换托操作幂等号',
counted_by BIGINT UNSIGNED NOT NULL COMMENT '清点操作人ID',
counted_by_name VARCHAR(64) NULL COMMENT '清点操作人姓名快照',
counted_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '清点时间',
bound_by BIGINT UNSIGNED NULL COMMENT '上托操作人ID',
bound_by_name VARCHAR(64) NULL COMMENT '上托操作人姓名快照',
bound_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '上托时间',
bound_at DATETIME(3) NULL COMMENT '上托时间',
PRIMARY KEY (id),
UNIQUE KEY uk_dropship_carton_task_label (task_id,carton_label_id),
KEY idx_dropship_carton_pallet_sku (pallet_id,sku_code,id),
KEY idx_dropship_carton_inbound (tenant_id,inbound_id,pallet_id),
KEY idx_dropship_carton_operation (operation_id),
UNIQUE KEY uk_dropship_carton_count_operation (count_operation_id),
KEY idx_dropship_carton_bind_operation (task_id,bind_operation_id),
CONSTRAINT fk_dropship_carton_task FOREIGN KEY (task_id) REFERENCES fl_dropship_pallet_task(id),
CONSTRAINT fk_dropship_carton_pallet FOREIGN KEY (pallet_id) REFERENCES fl_dropship_pallet(id),
CONSTRAINT fk_dropship_carton_label FOREIGN KEY (carton_label_id) REFERENCES fl_inbound_carton_label(id)
) ENGINE=InnoDB COMMENT='一件代发托盘内逐箱SKU和入仓单明细';
-- 已存在开发库直接收敛到逐箱清点与整托分柜结构;新建库由上面的最新定义一次完成。
DROP PROCEDURE IF EXISTS converge_dropship_palletization_schema;
DELIMITER $$
CREATE PROCEDURE converge_dropship_palletization_schema()
BEGIN
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_inbound_carton_label'
AND column_name='units_per_carton') THEN
ALTER TABLE fl_inbound_carton_label
ADD COLUMN units_per_carton INT UNSIGNED NULL
COMMENT '每箱SKU数量快照;一件代发必须为正数' AFTER sku_code;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_task'
AND column_name='counted_cartons') THEN
ALTER TABLE fl_dropship_pallet_task
ADD COLUMN counted_cartons INT UNSIGNED NOT NULL DEFAULT 0
COMMENT '已逐箱确认实收数量的箱数' AFTER total_cartons;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_task'
AND column_name='discrepancy_cartons') THEN
ALTER TABLE fl_dropship_pallet_task
ADD COLUMN discrepancy_cartons INT UNSIGNED NOT NULL DEFAULT 0
COMMENT '已确认差异箱数' AFTER allocated_cartons;
END IF;
UPDATE fl_dropship_pallet_task
SET counted_cartons=GREATEST(counted_cartons,allocated_cartons);
IF EXISTS (SELECT 1 FROM information_schema.table_constraints
WHERE constraint_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_task'
AND constraint_name='chk_dropship_task_cartons') THEN
ALTER TABLE fl_dropship_pallet_task DROP CHECK chk_dropship_task_cartons;
END IF;
ALTER TABLE fl_dropship_pallet_task
ADD CONSTRAINT chk_dropship_task_cartons
CHECK (allocated_cartons<=counted_cartons AND counted_cartons<=total_cartons);
IF EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_carton'
AND column_name='operation_id')
AND NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_carton'
AND column_name='count_operation_id') THEN
ALTER TABLE fl_dropship_pallet_carton
CHANGE COLUMN operation_id count_operation_id VARCHAR(128) NOT NULL
COMMENT '逐箱清点幂等操作ID';
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_carton'
AND column_name='expected_sku_quantity') THEN
ALTER TABLE fl_dropship_pallet_carton
ADD COLUMN expected_sku_quantity INT UNSIGNED NULL AFTER box_code,
ADD COLUMN actual_sku_quantity INT UNSIGNED NULL AFTER expected_sku_quantity,
ADD COLUMN discrepancy_status VARCHAR(24) NULL AFTER actual_sku_quantity,
ADD COLUMN discrepancy_remark VARCHAR(500) NULL AFTER discrepancy_status,
ADD COLUMN bind_operation_id VARCHAR(128) NULL AFTER count_operation_id,
ADD COLUMN last_operation_id VARCHAR(128) NULL AFTER bind_operation_id,
ADD COLUMN counted_by BIGINT UNSIGNED NULL AFTER last_operation_id,
ADD COLUMN counted_by_name VARCHAR(64) NULL AFTER counted_by,
ADD COLUMN counted_at DATETIME(3) NULL AFTER counted_by_name;
END IF;
UPDATE fl_dropship_pallet_carton carton
LEFT JOIN fl_inbound_carton_label label ON label.id=carton.carton_label_id
SET carton.expected_sku_quantity=COALESCE(carton.expected_sku_quantity,label.units_per_carton,1),
carton.actual_sku_quantity=COALESCE(carton.actual_sku_quantity,label.units_per_carton,1),
carton.discrepancy_status=COALESCE(carton.discrepancy_status,'MATCH'),
carton.bind_operation_id=COALESCE(carton.bind_operation_id,carton.count_operation_id),
carton.last_operation_id=COALESCE(carton.last_operation_id,carton.count_operation_id),
carton.counted_by=COALESCE(carton.counted_by,carton.bound_by),
carton.counted_by_name=COALESCE(carton.counted_by_name,carton.bound_by_name),
carton.counted_at=COALESCE(carton.counted_at,carton.bound_at);
ALTER TABLE fl_dropship_pallet_carton
MODIFY COLUMN pallet_id BIGINT UNSIGNED NULL COMMENT '所属组托托盘ID;已清点待绑托时为空',
MODIFY COLUMN box_code VARCHAR(80) NOT NULL COMMENT '稳定箱码',
MODIFY COLUMN expected_sku_quantity INT UNSIGNED NOT NULL COMMENT '箱唛冻结的应收SKU数量',
MODIFY COLUMN actual_sku_quantity INT UNSIGNED NOT NULL COMMENT 'PDA确认的实收SKU数量',
MODIFY COLUMN discrepancy_status VARCHAR(24) NOT NULL COMMENT '差异状态:MATCH或ACCEPTED_VARIANCE',
MODIFY COLUMN discrepancy_remark VARCHAR(500) NULL COMMENT '差异接受说明',
MODIFY COLUMN bind_operation_id VARCHAR(128) NULL COMMENT '批量绑托幂等操作ID',
MODIFY COLUMN last_operation_id VARCHAR(128) NOT NULL COMMENT '最后一次绑托或换托操作幂等号',
MODIFY COLUMN counted_by BIGINT UNSIGNED NOT NULL COMMENT '清点操作人ID',
MODIFY COLUMN counted_by_name VARCHAR(64) NULL COMMENT '清点操作人姓名快照',
MODIFY COLUMN counted_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '清点时间',
MODIFY COLUMN bound_by BIGINT UNSIGNED NULL COMMENT '上托操作人ID',
MODIFY COLUMN bound_at DATETIME(3) NULL COMMENT '上托时间';
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_carton'
AND index_name='uk_dropship_carton_count_operation') THEN
ALTER TABLE fl_dropship_pallet_carton
ADD UNIQUE KEY uk_dropship_carton_count_operation (count_operation_id);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_dropship_pallet_carton'
AND index_name='idx_dropship_carton_bind_operation') THEN
ALTER TABLE fl_dropship_pallet_carton
ADD KEY idx_dropship_carton_bind_operation (task_id,bind_operation_id);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND column_name='unit_type') THEN
ALTER TABLE fl_loading_plan_item
ADD COLUMN unit_type VARCHAR(24) NOT NULL DEFAULT 'PACKAGE'
COMMENT '分配单元:PACKAGE普通箱、SEALED_PALLET一件代发封托' AFTER product_quantity,
ADD COLUMN pallet_id BIGINT UNSIGNED NULL COMMENT '一件代发封托ID;普通箱为空' AFTER unit_type,
ADD COLUMN pallet_no VARCHAR(32) NULL COMMENT '一件代发系统托盘码快照' AFTER pallet_id,
ADD COLUMN indivisible TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否为不可拆整托单元' AFTER pallet_no;
END IF;
ALTER TABLE fl_loading_plan_item
MODIFY COLUMN unit_type VARCHAR(24) NOT NULL DEFAULT 'PACKAGE'
COMMENT '分配单元:PACKAGE普通箱、SEALED_PALLET一件代发封托',
MODIFY COLUMN pallet_id BIGINT UNSIGNED NULL COMMENT '一件代发封托ID;普通箱为空',
MODIFY COLUMN pallet_no VARCHAR(32) NULL COMMENT '一件代发系统托盘码快照',
MODIFY COLUMN indivisible TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否为不可拆整托单元';
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND column_name='active_assignment_key') THEN
ALTER TABLE fl_loading_plan_item
ADD COLUMN active_assignment_key VARCHAR(96)
GENERATED ALWAYS AS (CASE WHEN deleted=0 THEN CONCAT(CASE WHEN pallet_id IS NULL THEN 'D:0' ELSE CONCAT('P:',pallet_id) END,':',inbound_detail_id) ELSE NULL END) STORED
COMMENT '普通明细或已封托托盘明细的有效唯一锁' AFTER active_inbound_detail_id;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND index_name='uk_loading_item_plan_detail') THEN
ALTER TABLE fl_loading_plan_item DROP INDEX uk_loading_item_plan_detail;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND index_name='uk_loading_item_plan_assignment') THEN
ALTER TABLE fl_loading_plan_item
ADD UNIQUE KEY uk_loading_item_plan_assignment (loading_plan_id,active_assignment_key);
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.statistics
WHERE table_schema='baiyue_firstleg' AND table_name='fl_loading_plan_item'
AND index_name='idx_loading_item_pallet') THEN
ALTER TABLE fl_loading_plan_item ADD KEY idx_loading_item_pallet (pallet_id,deleted);
END IF;
END$$
DELIMITER ;
CALL converge_dropship_palletization_schema();
DROP PROCEDURE IF EXISTS converge_dropship_palletization_schema;
-- Auth 登录手机号只从 IAM 中唯一归属的中国大陆手机号回填;存量重复号保持 NULL。
USE baiyue_auth;
DROP PROCEDURE IF EXISTS auth_add_login_phone;
@@ -18116,6 +18332,249 @@ END$$
DELIMITER ;
CALL migrate_merchant_return_inventory_permission();
DROP PROCEDURE IF EXISTS migrate_merchant_return_inventory_permission;
-- 目的港码头拖车、提柜与还空闭环(模块来源:phase3-terminal-drayage-schema.sql)
USE baiyue_firstleg;
CREATE TABLE IF NOT EXISTS fl_terminal_drayage (
id BIGINT UNSIGNED NOT NULL COMMENT '目的港码头拖车聚合ID', container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '唯一归属物理货柜ID',
fleet_supplier_id BIGINT UNSIGNED NOT NULL COMMENT 'Warehouse ACTIVE/TRUCKING供应商ID快照', fleet_supplier_name VARCHAR(128) NOT NULL COMMENT 'Warehouse供应商名称快照',
pickup_appointment_at DATETIME(3) NULL COMMENT '预约提柜时间', actual_pickup_at DATETIME(3) NULL COMMENT '实际提柜时间',
estimated_empty_return_at DATETIME(3) NULL COMMENT '服务端按卸柜完成时间加72小时计算的预计还柜时间', actual_empty_return_at DATETIME(3) NULL COMMENT '实际还空柜时间',
version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '乐观锁版本号', created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后更新人ID', updated_by_name VARCHAR(64) NULL COMMENT '最后更新人名称快照',
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_terminal_drayage_container(container_booking_id),
KEY idx_terminal_drayage_warning(actual_empty_return_at,estimated_empty_return_at),
CONSTRAINT fk_terminal_drayage_container FOREIGN KEY(container_booking_id) REFERENCES fl_container_booking(id),
CONSTRAINT chk_terminal_drayage_times CHECK((actual_pickup_at IS NULL OR pickup_appointment_at IS NOT NULL)
AND (actual_empty_return_at IS NULL OR actual_pickup_at IS NOT NULL)
AND (actual_empty_return_at IS NULL OR actual_empty_return_at >= actual_pickup_at))
) ENGINE=InnoDB COMMENT='目的港货柜级码头拖车与还空事实';
CREATE TABLE IF NOT EXISTS fl_terminal_drayage_history (
id BIGINT UNSIGNED NOT NULL COMMENT '历史ID', drayage_id BIGINT UNSIGNED NOT NULL COMMENT '码头拖车聚合ID',
container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜ID快照', action VARCHAR(32) NOT NULL COMMENT '业务动作',
from_status VARCHAR(32) NOT NULL COMMENT '操作前状态', to_status VARCHAR(32) NOT NULL COMMENT '操作后状态',
from_version INT UNSIGNED NOT NULL COMMENT '操作前版本', to_version INT UNSIGNED NOT NULL COMMENT '操作后版本',
reason VARCHAR(500) NULL COMMENT '操作说明', operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID', operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间', PRIMARY KEY(id),
KEY idx_terminal_drayage_history(container_booking_id,created_at,id),
CONSTRAINT fk_terminal_drayage_history FOREIGN KEY(drayage_id) REFERENCES fl_terminal_drayage(id),
CONSTRAINT chk_terminal_drayage_history_action CHECK(action IN
('SELECT_FLEET','SCHEDULE_PICKUP','RECORD_PICKUP','RECORD_EMPTY_RETURN'))
) ENGINE=InnoDB COMMENT='目的港码头拖车不可变操作历史';
CREATE TABLE IF NOT EXISTS fl_terminal_drayage_operation (
id BIGINT UNSIGNED NOT NULL COMMENT '幂等操作ID', container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜ID',
operation VARCHAR(32) NOT NULL COMMENT '业务动作', idempotency_key VARCHAR(255) NOT NULL COMMENT '客户端幂等键',
request_hash CHAR(64) NOT NULL COMMENT '请求载荷SHA-256', result_version INT UNSIGNED NOT NULL COMMENT '成功结果版本',
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '完成时间',
PRIMARY KEY(id), UNIQUE KEY uk_terminal_drayage_operation(container_booking_id,idempotency_key),
KEY idx_terminal_drayage_operation(container_booking_id,created_at),
CONSTRAINT fk_terminal_drayage_operation_container FOREIGN KEY(container_booking_id) REFERENCES fl_container_booking(id)
) ENGINE=InnoDB COMMENT='目的港码头拖车成功幂等操作';
-- MySQL DDL 会隐式提交;如果前次执行在末段校验失败,重跑时需把已创建表的列注释收敛到当前基线。
ALTER TABLE fl_terminal_drayage
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '目的港码头拖车聚合ID',
MODIFY COLUMN container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '唯一归属物理货柜ID',
MODIFY COLUMN fleet_supplier_id BIGINT UNSIGNED NOT NULL COMMENT 'Warehouse ACTIVE/TRUCKING供应商ID快照',
MODIFY COLUMN fleet_supplier_name VARCHAR(128) NOT NULL COMMENT 'Warehouse供应商名称快照',
MODIFY COLUMN pickup_appointment_at DATETIME(3) NULL COMMENT '预约提柜时间',
MODIFY COLUMN actual_pickup_at DATETIME(3) NULL COMMENT '实际提柜时间',
MODIFY COLUMN estimated_empty_return_at DATETIME(3) NULL COMMENT '服务端按卸柜完成时间加72小时计算的预计还柜时间',
MODIFY COLUMN actual_empty_return_at DATETIME(3) NULL COMMENT '实际还空柜时间',
MODIFY COLUMN version INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '乐观锁版本号',
MODIFY COLUMN created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID',
MODIFY COLUMN created_by_name VARCHAR(64) NULL COMMENT '创建人名称快照',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
MODIFY COLUMN updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后更新人ID',
MODIFY COLUMN updated_by_name VARCHAR(64) NULL COMMENT '最后更新人名称快照',
MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间';
ALTER TABLE fl_terminal_drayage_history
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '历史ID',
MODIFY COLUMN drayage_id BIGINT UNSIGNED NOT NULL COMMENT '码头拖车聚合ID',
MODIFY COLUMN container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜ID快照',
MODIFY COLUMN action VARCHAR(32) NOT NULL COMMENT '业务动作',
MODIFY COLUMN from_status VARCHAR(32) NOT NULL COMMENT '操作前状态',
MODIFY COLUMN to_status VARCHAR(32) NOT NULL COMMENT '操作后状态',
MODIFY COLUMN from_version INT UNSIGNED NOT NULL COMMENT '操作前版本',
MODIFY COLUMN to_version INT UNSIGNED NOT NULL COMMENT '操作后版本',
MODIFY COLUMN reason VARCHAR(500) NULL COMMENT '操作说明',
MODIFY COLUMN operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
MODIFY COLUMN operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间';
ALTER TABLE fl_terminal_drayage_operation
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '幂等操作ID',
MODIFY COLUMN container_booking_id BIGINT UNSIGNED NOT NULL COMMENT '货柜ID',
MODIFY COLUMN operation VARCHAR(32) NOT NULL COMMENT '业务动作',
MODIFY COLUMN idempotency_key VARCHAR(255) NOT NULL COMMENT '客户端幂等键',
MODIFY COLUMN request_hash CHAR(64) NOT NULL COMMENT '请求载荷SHA-256',
MODIFY COLUMN result_version INT UNSIGNED NOT NULL COMMENT '成功结果版本',
MODIFY COLUMN operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
MODIFY COLUMN created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '完成时间';
DROP PROCEDURE IF EXISTS assert_terminal_drayage_schema;
DELIMITER $$
CREATE PROCEDURE assert_terminal_drayage_schema()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='baiyue_firstleg'
AND TABLE_NAME IN ('fl_terminal_drayage','fl_terminal_drayage_history','fl_terminal_drayage_operation')) <> 3 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_terminal_drayage' AND INDEX_NAME='uk_terminal_drayage_container' AND NON_UNIQUE=0) <> 1
OR (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA='baiyue_firstleg'
AND TABLE_NAME='fl_terminal_drayage_operation' AND INDEX_NAME='uk_terminal_drayage_operation' AND NON_UNIQUE=0) <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='统一迁移失败:目的港码头拖车唯一约束不完整';
END IF;
END$$
DELIMITER ;
CALL assert_terminal_drayage_schema();
DROP PROCEDURE IF EXISTS assert_terminal_drayage_schema;
-- 货柜双工作台权限开始(与 iam/db/container-workspace-permissions.sql 保持一致)
-- 国内送柜报关与国外清关提柜双工作台权限;国内沿用现有货柜权限,国外直接收敛到独立权限族。
USE baiyue_iam;
SET NAMES utf8mb4;
DROP PROCEDURE IF EXISTS migrate_container_workspace_permissions;
DELIMITER $$
CREATE PROCEDURE migrate_container_workspace_permissions()
BEGIN
IF EXISTS (
SELECT 1 FROM iam_permission
WHERE (id = 5102090 AND permission_code <> 'platform:firstleg:container:list')
OR (id = 5102092 AND permission_code <> 'platform:firstleg:container:create')
OR (id = 5102093 AND permission_code <> 'platform:firstleg:container:edit')
OR (id = 5102200 AND permission_code <> 'platform:firstleg:terminal-drayage:list')
OR (id = 5102201 AND permission_code <> 'platform:firstleg:terminal-drayage:document:edit')
OR (id = 5102202 AND permission_code <> 'platform:firstleg:terminal-drayage:fleet:edit')
OR (id = 5102203 AND permission_code <> 'platform:firstleg:terminal-drayage:pickup-appointment:edit')
OR (id = 5102204 AND permission_code <> 'platform:firstleg:terminal-drayage:pickup:confirm')
OR (id = 5102205 AND permission_code <> 'platform:firstleg:terminal-drayage:empty-return:confirm')
) OR EXISTS (
SELECT 1 FROM iam_permission
WHERE (permission_code = 'platform:firstleg:container:list' AND id <> 5102090)
OR (permission_code = 'platform:firstleg:container:create' AND id <> 5102092)
OR (permission_code = 'platform:firstleg:container:edit' AND id <> 5102093)
OR (permission_code = 'platform:firstleg:terminal-drayage:list' AND id <> 5102200)
OR (permission_code = 'platform:firstleg:terminal-drayage:document:edit' AND id <> 5102201)
OR (permission_code = 'platform:firstleg:terminal-drayage:fleet:edit' AND id <> 5102202)
OR (permission_code = 'platform:firstleg:terminal-drayage:pickup-appointment:edit' AND id <> 5102203)
OR (permission_code = 'platform:firstleg:terminal-drayage:pickup:confirm' AND id <> 5102204)
OR (permission_code = 'platform:firstleg:terminal-drayage:empty-return:confirm' AND id <> 5102205)
) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='货柜双工作台权限初始化失败:权限ID或编码冲突';
END IF;
INSERT INTO iam_permission
(id, tenant_id, app_code, permission_type, parent_id, permission_code,
permission_name, route_path, http_method, sort_no, status, built_in, deleted)
VALUES
(5102090,0,'PLATFORM','MENU',5102000,'platform:firstleg:container:list',
'国内送柜报关','/container-loading/domestic','GET',40,'ACTIVE',1,0),
(5102092,0,'PLATFORM','BUTTON',5102090,'platform:firstleg:container:create',
'建立国内货柜',NULL,'POST',20,'ACTIVE',1,0),
(5102093,0,'PLATFORM','BUTTON',5102090,'platform:firstleg:container:edit',
'维护国内货柜资料',NULL,'PUT',30,'ACTIVE',1,0),
(5102200,0,'PLATFORM','MENU',5102000,'platform:firstleg:terminal-drayage:list',
'国外清关提柜','/container-loading/overseas','GET',41,'ACTIVE',1,0),
(5102201,0,'PLATFORM','BUTTON',5102200,'platform:firstleg:terminal-drayage:document:edit',
'维护目的港清关与DO/PU',NULL,'POST',10,'ACTIVE',1,0),
(5102202,0,'PLATFORM','BUTTON',5102200,'platform:firstleg:terminal-drayage:fleet:edit',
'维护目的港码头车队',NULL,'POST',20,'ACTIVE',1,0),
(5102203,0,'PLATFORM','BUTTON',5102200,'platform:firstleg:terminal-drayage:pickup-appointment:edit',
'预约目的港提柜',NULL,'POST',30,'ACTIVE',1,0),
(5102204,0,'PLATFORM','BUTTON',5102200,'platform:firstleg:terminal-drayage:pickup:confirm',
'确认目的港实际提柜',NULL,'POST',40,'ACTIVE',1,0),
(5102205,0,'PLATFORM','BUTTON',5102200,'platform:firstleg:terminal-drayage:empty-return:confirm',
'确认目的港实际还柜',NULL,'POST',50,'ACTIVE',1,0)
ON DUPLICATE KEY UPDATE
permission_type=VALUES(permission_type), parent_id=VALUES(parent_id),
permission_name=VALUES(permission_name), route_path=VALUES(route_path),
http_method=VALUES(http_method), sort_no=VALUES(sort_no), status='ACTIVE',
built_in=1, deleted=0;
-- list 已包含详情只读;旧 container:view 不再作为别名或双权限入口。
DELETE grant_row FROM iam_role_permission grant_row
JOIN iam_permission permission
ON permission.id=grant_row.permission_id AND permission.tenant_id=grant_row.tenant_id
WHERE permission.tenant_id=0
AND permission.permission_code='platform:firstleg:container:view';
UPDATE iam_permission
SET status='INACTIVE', deleted=1
WHERE tenant_id=0 AND permission_code='platform:firstleg:container:view';
-- 平台超级管理员和现有订单运营保持货柜全链路能力;其他角色按两个菜单独立授权。
INSERT IGNORE INTO iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, role.id, permission.id, CURRENT_TIMESTAMP(3)
FROM iam_role role
JOIN iam_permission permission
ON permission.tenant_id=0 AND permission.app_code='PLATFORM'
AND permission.permission_code IN (
'platform:firstleg:container:list',
'platform:firstleg:container:create',
'platform:firstleg:container:edit',
'platform:firstleg:terminal-drayage:list',
'platform:firstleg:terminal-drayage:document:edit',
'platform:firstleg:terminal-drayage:fleet:edit',
'platform:firstleg:terminal-drayage:pickup-appointment:edit',
'platform:firstleg:terminal-drayage:pickup:confirm',
'platform:firstleg:terminal-drayage:empty-return:confirm')
WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR')
AND role.status='ACTIVE' AND role.deleted=0
AND permission.status='ACTIVE' AND permission.deleted=0;
IF (SELECT COUNT(*) FROM iam_permission
WHERE tenant_id=0 AND app_code='PLATFORM' AND status='ACTIVE' AND deleted=0
AND permission_code IN (
'platform:firstleg:container:list',
'platform:firstleg:container:create',
'platform:firstleg:container:edit',
'platform:firstleg:terminal-drayage:list',
'platform:firstleg:terminal-drayage:document:edit',
'platform:firstleg:terminal-drayage:fleet:edit',
'platform:firstleg:terminal-drayage:pickup-appointment:edit',
'platform:firstleg:terminal-drayage:pickup:confirm',
'platform:firstleg:terminal-drayage:empty-return:confirm')) <> 9 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='货柜双工作台权限初始化失败:权限目录不完整';
END IF;
IF (SELECT COUNT(DISTINCT CONCAT(role.role_code, ':', permission.permission_code))
FROM iam_role_permission grant_row
JOIN iam_role role
ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id
JOIN iam_permission permission
ON permission.id=grant_row.permission_id AND permission.tenant_id=grant_row.tenant_id
WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
AND role.role_code IN ('PLATFORM_ADMIN','ORDER_OPERATOR')
AND permission.permission_code IN (
'platform:firstleg:container:list',
'platform:firstleg:container:create',
'platform:firstleg:container:edit',
'platform:firstleg:terminal-drayage:list',
'platform:firstleg:terminal-drayage:document:edit',
'platform:firstleg:terminal-drayage:fleet:edit',
'platform:firstleg:terminal-drayage:pickup-appointment:edit',
'platform:firstleg:terminal-drayage:pickup:confirm',
'platform:firstleg:terminal-drayage:empty-return:confirm')) <> 18 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='货柜双工作台权限初始化失败:平台默认角色授权不完整';
END IF;
IF EXISTS (SELECT 1 FROM iam_permission
WHERE tenant_id=0 AND permission_code='platform:firstleg:container:view'
AND (status='ACTIVE' OR deleted=0)) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='货柜双工作台权限初始化失败:旧查看权限仍然有效';
END IF;
END$$
DELIMITER ;
CALL migrate_container_workspace_permissions();
DROP PROCEDURE IF EXISTS migrate_container_workspace_permissions;
-- 货柜双工作台权限结束,恢复头程数据库上下文
USE baiyue_firstleg;
CALL baiyue_firstleg.assert_unified_final_schema();
DROP PROCEDURE IF EXISTS baiyue_firstleg.assert_unified_final_schema;
+205 -3
View File
@@ -219,6 +219,7 @@ SET @ddl = (SELECT IF(EXISTS (
WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='review_idempotency_key'
), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_idempotency_key VARCHAR(255) NULL COMMENT ''审核幂等键'' AFTER review_remark'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema=DATABASE() AND table_name='ll_overseas_procurement_order' AND column_name='review_request_hash'
@@ -517,6 +518,8 @@ SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE tab
'ALTER TABLE ll_order MODIFY COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码''',
'ALTER TABLE ll_order ADD COLUMN destination_type VARCHAR(32) NULL COMMENT ''目的类型:FBA按箱数接收、OVERSEAS逐箱扫码'' AFTER order_type'));
PREPARE phase4_destination_type_stmt FROM @ddl; EXECUTE phase4_destination_type_stmt; DEALLOCATE PREPARE phase4_destination_type_stmt;
ALTER TABLE ll_order
MODIFY COLUMN inbound_code VARCHAR(128) NULL COMMENT '真实来源入仓码;无入仓关系的海外本土业务为空';
CREATE TABLE IF NOT EXISTS ll_order_no_daily_sequence (
business_date DATE NOT NULL COMMENT '业务日期(Asia/Shanghai)',
@@ -1150,7 +1153,7 @@ CREATE TABLE IF NOT EXISTS ll_outbound_pallet_item (
destination_warehouse_id VARCHAR(128) NULL COMMENT '目的仓ID', destination_warehouse_code VARCHAR(128) NULL COMMENT '目的仓编码快照',
destination_warehouse_name VARCHAR(255) NULL COMMENT '目的仓名称快照', package_count INT NOT NULL DEFAULT 0 COMMENT '箱数',
picked_package_count INT NOT NULL DEFAULT 0 COMMENT '已拣箱数', status VARCHAR(32) NOT NULL DEFAULT 'WAIT_PICK' COMMENT '拣货状态',
sku_code VARCHAR(128) NULL COMMENT '一件代发SKU', order_refs VARCHAR(2000) NULL COMMENT '关联订单信息', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照',
sku_code VARCHAR(128) NULL COMMENT '一件代发SKU', carton_marks VARCHAR(4000) NULL COMMENT '本次出库指定箱唛,逗号分隔', order_refs VARCHAR(2000) NULL COMMENT '关联订单信息', inbound_code VARCHAR(128) NULL COMMENT '入仓单号快照',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_outbound_pallet(customer_id,outbound_order_id,warehouse_pallet_id),
KEY idx_ll_outbound_pallet_list(customer_id,outbound_order_id), KEY idx_ll_outbound_pallet_destination(customer_id,destination_warehouse_code)
@@ -1187,6 +1190,7 @@ CREATE TABLE IF NOT EXISTS ll_delivery_order (
planned_delivery_at DATETIME(3) NULL COMMENT '预计派送时间', dispatched_at DATETIME(3) NULL COMMENT '实际派送时间',
expected_arrival_at DATETIME(3) NULL COMMENT '预计到达时间', signed_at DATETIME(3) NULL COMMENT '签收时间', remark VARCHAR(1000) NULL COMMENT '派送备注',
idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', created_by VARCHAR(128) NULL COMMENT '创建人ID',
version BIGINT 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_ll_delivery_no(customer_id,delivery_no), UNIQUE KEY uk_ll_delivery_idempotency(customer_id,idempotency_key),
@@ -1287,13 +1291,33 @@ CREATE TABLE IF NOT EXISTS ll_exception_order (
delivery_order_id BIGINT NULL COMMENT '关联派送单ID', delivery_no VARCHAR(64) NULL COMMENT '关联派送单号', outbound_no VARCHAR(64) NULL COMMENT '关联出库单号',
customer_name VARCHAR(255) NULL COMMENT '客户名称快照', overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外仓ID快照', overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外仓名称快照',
sku_code VARCHAR(128) NULL COMMENT '异常货物SKU', package_count INT NULL COMMENT '异常箱数', return_direction VARCHAR(32) NULL COMMENT '退回方向', return_logistics_no VARCHAR(128) NULL COMMENT '退回物流单号',
handling_action VARCHAR(500) NULL COMMENT '异常处理措施', handler_id VARCHAR(128) NULL COMMENT '处理人ID', handler_name VARCHAR(128) NULL COMMENT '处理人名称',
handling_action VARCHAR(500) NULL COMMENT '异常处理措施', handling_result VARCHAR(2000) NULL COMMENT '异常处理结果',
evidence_file_ids_json JSON NULL COMMENT '异常处理证据文件ID列表', inventory_adjustment_id BIGINT NULL COMMENT '退回库存恢复操作ID',
handler_id VARCHAR(128) NULL COMMENT '处理人ID', handler_name VARCHAR(128) NULL COMMENT '处理人名称',
source_type VARCHAR(32) NOT NULL DEFAULT 'MANUAL' COMMENT '异常来源类型', created_by VARCHAR(128) NULL COMMENT '创建人ID',
exception_at DATETIME(3) NOT NULL COMMENT '异常发生时间', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
exception_at DATETIME(3) NOT NULL COMMENT '异常发生时间', completed_at DATETIME(3) NULL COMMENT '异常处理完成时间',
version BIGINT 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_ll_exception_no(customer_id,exception_no), UNIQUE KEY uk_ll_exception_delivery_return(customer_id,delivery_order_id,exception_type),
KEY idx_ll_exception_list(customer_id,status,exception_at), KEY idx_ll_exception_tail(customer_id,last_mile_order_no), KEY idx_ll_exception_inbound(customer_id,inbound_code)
) ENGINE=InnoDB COMMENT='海外仓异常订单';
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 '原出库托盘码快照',
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 '创建时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_exception_return_source(customer_id,exception_order_id,outbound_pallet_item_id,inventory_position_id),
KEY idx_ll_exception_return_order(customer_id,exception_order_id)
) ENGINE=InnoDB COMMENT='异常退回原出库库存冻结明细';
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 '异常处理动作',
idempotency_key VARCHAR(255) NOT NULL COMMENT '幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '请求内容SHA256哈希',
result_json JSON NOT NULL COMMENT '命令结果快照', created_at DATETIME(3) NOT NULL COMMENT '创建时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_exception_command_key(customer_id,action,idempotency_key),
KEY idx_ll_exception_command_order(customer_id,exception_order_id,created_at)
) ENGINE=InnoDB COMMENT='异常处理命令幂等审计';
CREATE TABLE IF NOT EXISTS ll_customer_visit (
id BIGINT NOT NULL COMMENT '客户回访记录ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', delivery_order_id BIGINT NOT NULL COMMENT '关联派送单ID',
delivery_no VARCHAR(64) NOT NULL COMMENT '关联派送单号', customer_name VARCHAR(255) NULL COMMENT '客户名称快照', contact_name VARCHAR(128) NULL COMMENT '客户联系人姓名快照',
@@ -1754,6 +1778,11 @@ SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE tab
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_error_code'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_error_code VARCHAR(64) NULL COMMENT ''资金错误码'' AFTER wallet_status')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_error_message'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_error_message VARCHAR(500) NULL COMMENT ''资金错误说明'' AFTER wallet_error_code')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_application' AND column_name='wallet_command_event_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_application ADD COLUMN wallet_command_event_id VARCHAR(64) NULL COMMENT ''当前资金指令事件ID'' AFTER wallet_error_message')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='remark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN remark VARCHAR(1000) NULL COMMENT ''货物明细备注'' AFTER label_requirement')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN carton_mark VARCHAR(255) NULL COMMENT ''客户自有箱唛'' AFTER relabel_file_url')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='fba_carton_mark'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN fba_carton_mark VARCHAR(255) NULL COMMENT ''关联FBA箱唛'' AFTER carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND column_name='destination_warehouse_id'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD COLUMN destination_warehouse_id VARCHAR(128) NULL COMMENT ''该箱目的海外仓ID'' AFTER fba_carton_mark')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='ll_relabel_item' AND index_name='idx_ll_relabel_item_destination'), 'SELECT 1', 'ALTER TABLE ll_relabel_item ADD KEY idx_ll_relabel_item_destination (customer_id,destination_warehouse_id,application_id)')); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
@@ -1786,3 +1815,176 @@ SET @ddl = (SELECT IF(
'SELECT 1',
'ALTER TABLE ll_relabel_item ADD COLUMN sku_relabel_items_json JSON NULL COMMENT ''同箱SKU换标子明细快照(数量按件)'''));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 海外接柜仓由平台在尾程建单时预分配;历史测试数据不回填,缺失事实由业务接口失败关闭。
USE baiyue_lastleg;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_order' AND column_name='overseas_warehouse_code'),
'ALTER TABLE ll_order MODIFY COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照''',
'ALTER TABLE ll_order ADD COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照'' AFTER overseas_warehouse_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_order' AND column_name='receiving_warehouse_version'),
'ALTER TABLE ll_order MODIFY COLUMN receiving_warehouse_version INT NOT NULL DEFAULT 0 COMMENT ''柜级接柜仓分配乐观锁版本''',
'ALTER TABLE ll_order ADD COLUMN receiving_warehouse_version INT NOT NULL DEFAULT 0 COMMENT ''柜级接柜仓分配乐观锁版本'' AFTER overseas_warehouse_name'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE ll_order
MODIFY COLUMN overseas_warehouse_id VARCHAR(128) NULL COMMENT '海外接柜仓ID;新建尾程订单默认洛杉矶仓',
MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NULL COMMENT '海外接柜仓名称快照';
ALTER TABLE ll_inbound_plan
MODIFY COLUMN overseas_warehouse_id BIGINT NULL COMMENT '从尾程订单继承的平台预分配海外接柜仓ID';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_code'),
'ALTER TABLE ll_receiving_container_session MODIFY COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照''',
'ALTER TABLE ll_receiving_container_session ADD COLUMN overseas_warehouse_code VARCHAR(128) NULL COMMENT ''海外接柜仓业务编码快照'' AFTER overseas_warehouse_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE ll_receiving_container_session
MODIFY COLUMN overseas_warehouse_id BIGINT NOT NULL COMMENT '平台预分配并由操作员Token匹配的海外接柜仓ID',
MODIFY COLUMN overseas_warehouse_name VARCHAR(255) NOT NULL COMMENT '仓库服务校验后的海外接柜仓名称快照';
CREATE TABLE IF NOT EXISTS ll_receiving_warehouse_operation (
id BIGINT NOT NULL COMMENT '柜级接柜仓修改操作ID',
source_container_booking_id VARCHAR(128) NOT NULL COMMENT '稳定来源柜预订ID',
idempotency_key VARCHAR(255) NOT NULL COMMENT '平台请求幂等键',
request_hash VARCHAR(64) NOT NULL COMMENT '规范化修改请求SHA-256摘要',
result_version INT NOT NULL COMMENT '修改成功后的柜级分配版本',
operator_name VARCHAR(128) NOT NULL COMMENT '平台操作人名称',
remark VARCHAR(500) NULL COMMENT '接柜仓修改备注',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '操作时间',
PRIMARY KEY(id),
UNIQUE KEY uk_ll_receiving_warehouse_idempotency(idempotency_key),
KEY idx_ll_receiving_warehouse_container(source_container_booking_id,created_at)
) ENGINE=InnoDB COMMENT='柜级海外接柜仓修改幂等审计记录';
DROP PROCEDURE IF EXISTS assert_receiving_warehouse_assignment_ready;
DELIMITER $$
CREATE PROCEDURE assert_receiving_warehouse_assignment_ready()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg'
AND table_name='ll_order' AND column_name IN ('overseas_warehouse_code','receiving_warehouse_version')) <> 2 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单海外接柜仓字段未完整部署';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg'
AND table_name='ll_receiving_container_session' AND column_name='overseas_warehouse_code') <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外PDA接柜会话仓库编码字段未部署';
END IF;
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg'
AND table_name='ll_receiving_warehouse_operation') <> 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='柜级海外接柜仓修改幂等审计表未部署';
END IF;
END$$
DELIMITER ;
CALL assert_receiving_warehouse_assignment_ready();
DROP PROCEDURE assert_receiving_warehouse_assignment_ready;
SELECT 'PASS' AS migration_status, '海外接柜仓预分配与柜级修改结构已就绪' AS message;
-- 一件代发来源托盘与海外仓实物托盘分离,实物绑定不得覆盖来源身份。
USE baiyue_lastleg;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_inbound_plan_pallet' AND column_name='source_pallet_no'),
'SELECT 1',
'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''一件代发不可变来源托盘号快照'' AFTER pallet_no'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE ll_inbound_plan_pallet
MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '当前托盘编号:分配前为计划占位码,分配后为海外仓实物托盘码';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE()
AND table_name='ll_inbound_stock_receipt' AND column_name='source_pallet_no'),
'SELECT 1',
'ALTER TABLE ll_inbound_stock_receipt ADD COLUMN source_pallet_no VARCHAR(128) NULL COMMENT ''一件代发不可变来源托盘号快照'' AFTER pallet_no'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE ll_inbound_stock_receipt
MODIFY COLUMN pallet_no VARCHAR(64) NOT NULL COMMENT '海外仓实物托盘码';
-- 尾程单票人工计划、暂扣与人工展示节点。
USE baiyue_lastleg;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='hold_chargeable'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN hold_chargeable TINYINT NOT NULL DEFAULT 0 COMMENT ''当前暂扣是否计费:0否1是'' AFTER detained'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='hold_reason'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN hold_reason VARCHAR(500) NULL COMMENT ''当前暂扣原因;解除后为空'' AFTER hold_chargeable'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='manual_node_override'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN manual_node_override TINYINT NOT NULL DEFAULT 0 COMMENT ''是否启用单票人工计划节点覆盖:0否1是'' AFTER hold_reason'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_order' AND column_name='version'), 'SELECT 1', 'ALTER TABLE ll_order ADD COLUMN version INT NOT NULL DEFAULT 0 COMMENT ''尾程订单命令乐观锁版本'' AFTER manual_node_override'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
CREATE TABLE IF NOT EXISTS ll_order_command_record (
id BIGINT NOT NULL COMMENT '尾程订单命令幂等记录ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键',
order_id BIGINT NOT NULL COMMENT '尾程订单ID', action VARCHAR(32) NOT NULL COMMENT '命令动作', operator_id VARCHAR(128) NOT NULL COMMENT '平台操作人ID',
idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', request_hash VARCHAR(64) NOT NULL COMMENT '规范化请求SHA-256摘要',
result_ref VARCHAR(128) NULL COMMENT '结果业务引用', result_json LONGTEXT NOT NULL COMMENT '首次成功响应JSON快照',
result_version INT NOT NULL COMMENT '命令成功后的订单版本', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '首次成功时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_order_command_key(customer_id,order_id,action,operator_id,idempotency_key),
KEY idx_ll_order_command_history(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='尾程订单写命令幂等与结果审计记录';
CREATE TABLE IF NOT EXISTS ll_order_hold_history (
id BIGINT NOT NULL COMMENT '尾程订单暂扣历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID',
held TINYINT NOT NULL COMMENT '操作后是否暂扣:0否1是', chargeable TINYINT NOT NULL COMMENT '本次暂扣是否计费:0否1是', reason VARCHAR(500) NOT NULL COMMENT '暂扣或解除原因',
order_version INT NOT NULL COMMENT '操作成功后的订单版本', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID', operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称',
idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', created_at DATETIME(3) NOT NULL COMMENT '操作时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_order_hold_key(customer_id,order_id,operator_id,idempotency_key), KEY idx_ll_order_hold_history(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='尾程订单暂扣与解除不可变历史';
CREATE TABLE IF NOT EXISTS ll_order_manual_node (
id BIGINT NOT NULL COMMENT '尾程订单人工节点ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID',
node_code VARCHAR(32) NOT NULL COMMENT '八行人工展示节点稳定代码', node_at DATETIME(3) NULL COMMENT '人工填写节点时间,允许为空',
source VARCHAR(16) NOT NULL DEFAULT 'MANUAL' COMMENT '节点来源,固定MANUAL', order_version INT NOT NULL COMMENT '最近编辑后的订单版本',
updated_by VARCHAR(128) NOT NULL COMMENT '最近操作人ID', updated_at DATETIME(3) NOT NULL COMMENT '最近编辑时间', PRIMARY KEY(id),
UNIQUE KEY uk_ll_order_manual_node(customer_id,order_id,node_code), KEY idx_ll_order_manual_node_order(customer_id,order_id,node_at)
) ENGINE=InnoDB COMMENT='尾程订单当前人工节点覆盖事实';
CREATE TABLE IF NOT EXISTS ll_order_manual_node_history (
id BIGINT NOT NULL COMMENT '尾程订单人工节点历史ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键', order_id BIGINT NOT NULL COMMENT '尾程订单ID',
nodes_json LONGTEXT NOT NULL COMMENT '本次全量人工节点JSON快照', order_version INT NOT NULL COMMENT '操作成功后的订单版本', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID',
operator_name VARCHAR(128) NOT NULL COMMENT '操作人名称', idempotency_key VARCHAR(128) NOT NULL COMMENT '客户端幂等键', created_at DATETIME(3) NOT NULL COMMENT '操作时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_order_manual_node_history_key(customer_id,order_id,operator_id,idempotency_key),
KEY idx_ll_order_manual_node_history(customer_id,order_id,created_at)
) ENGINE=InnoDB COMMENT='尾程订单人工节点覆盖不可变历史';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='planned_arrival_date'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN planned_arrival_date DATE NULL COMMENT ''人工计划预计到仓日期'' AFTER overseas_warehouse_id'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='pallet_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN pallet_type VARCHAR(32) NULL COMMENT ''人工计划托盘类型'' AFTER planned_arrival_date'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='assigned_flag'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN assigned_flag TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否已分配:0否1是'' AFTER pallet_type'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='merge_required'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN merge_required TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否要求合托:0否1是'' AFTER assigned_flag'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='urgent_flag'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN urgent_flag TINYINT NOT NULL DEFAULT 0 COMMENT ''人工计划是否加急:0否1是'' AFTER merge_required'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='creation_mode'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN creation_mode VARCHAR(16) NOT NULL DEFAULT ''AUTO'' COMMENT ''计划生成方式:AUTO柜级自动、MANUAL单票人工'' AFTER urgent_flag'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan' AND column_name='plan_remark'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan ADD COLUMN plan_remark VARCHAR(1000) NULL COMMENT ''入仓计划备注'' AFTER creation_mode'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='ll_inbound_plan_pallet' AND column_name='pallet_type'), 'SELECT 1', 'ALTER TABLE ll_inbound_plan_pallet ADD COLUMN pallet_type VARCHAR(32) NULL COMMENT ''人工计划托盘类型'' AFTER pallet_no'));
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
DROP PROCEDURE IF EXISTS assert_tail_order_commands_ready;
DELIMITER $$
CREATE PROCEDURE assert_tail_order_commands_ready()
BEGIN
IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg'
AND table_name='ll_order' AND column_name IN
('hold_chargeable','hold_reason','manual_node_override','version')) <> 4 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单人工计划、暂扣与人工节点字段未完整部署';
END IF;
IF (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='baiyue_lastleg'
AND table_name IN ('ll_order_command_record','ll_order_hold_history','ll_order_manual_node','ll_order_manual_node_history')) <> 4 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单命令审计表未完整部署';
END IF;
IF (SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='baiyue_lastleg'
AND table_name='ll_inbound_plan' AND column_name IN
('planned_arrival_date','pallet_type','assigned_flag','merge_required','urgent_flag','creation_mode','plan_remark')) <> 7 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程人工计划字段未完整部署';
END IF;
IF (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg'
AND table_name='ll_order_command_record' AND index_name='uk_ll_order_command_key' AND non_unique=0) <> 5
OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema='baiyue_lastleg'
AND table_name='ll_order_manual_node' AND index_name='uk_ll_order_manual_node' AND non_unique=0) <> 3 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='尾程订单命令幂等或人工节点唯一约束未完整部署';
END IF;
END$$
DELIMITER ;
CALL assert_tail_order_commands_ready();
DROP PROCEDURE IF EXISTS assert_tail_order_commands_ready;
SELECT 'PASS' AS migration_status, '海外尾程人工计划、暂扣与人工节点结构已就绪' AS message;