845 lines
41 KiB
SQL
845 lines
41 KiB
SQL
SET NAMES utf8mb4;
|
|
USE baiyue_firstleg;
|
|
|
|
/*
|
|
* 三期主子入仓单结构迁移。
|
|
* 仅建立结构和数据库保护,不自动拆分或回填存量业务数据。
|
|
* 新写入采用“来源单承接实装、仅创建余量子单”;LOADED 子单和 loaded_child_inbound_id
|
|
* 仅为历史双子单读取保留,不删除、不清洗存量记录。
|
|
* tenant_id 继续表示客户隔离键;数量统一使用 package_count。
|
|
*/
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_column;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_add_column(
|
|
IN p_table_name VARCHAR(64),
|
|
IN p_column_name VARCHAR(64),
|
|
IN p_definition TEXT
|
|
)
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = p_table_name
|
|
AND column_name = p_column_name
|
|
) THEN
|
|
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` ADD COLUMN `',
|
|
p_column_name, '` ', p_definition);
|
|
PREPARE stmt FROM @ddl;
|
|
EXECUTE stmt;
|
|
DEALLOCATE PREPARE stmt;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'inbound_role',
|
|
"VARCHAR(16) NOT NULL DEFAULT 'MASTER' COMMENT '入仓单层级:MASTER主单、CHILD子单' AFTER inbound_code");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'parent_inbound_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '直属主入仓单ID;主单为空' AFTER inbound_role");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'root_inbound_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '根主入仓单ID;存量主单可为空,按自身ID解释' AFTER parent_inbound_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'split_sequence',
|
|
"INT UNSIGNED NULL COMMENT '同一主单下的子单顺序号' AFTER root_inbound_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'split_status',
|
|
"VARCHAR(24) NOT NULL DEFAULT 'NOT_SPLIT' COMMENT '拆分状态:NOT_SPLIT、PARTIALLY_SPLIT、FULLY_SPLIT' AFTER split_sequence");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'package_count',
|
|
"INT UNSIGNED NULL COMMENT '入仓单箱数;三期唯一数量口径' AFTER total_package_count");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'split_purpose',
|
|
"VARCHAR(16) NOT NULL DEFAULT 'MASTER' COMMENT '履约分片用途:MASTER、LOADED、REMAINDER' AFTER package_count");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'master_order_id',
|
|
"BIGINT UNSIGNED GENERATED ALWAYS AS (CASE WHEN inbound_role = 'MASTER' AND deleted = 0 THEN order_id ELSE NULL END) STORED COMMENT '仅用于约束有效主单订单唯一性'");
|
|
|
|
-- 旧实现只生成未装余量子单,可无歧义映射为 REMAINDER。
|
|
UPDATE fl_inbound_order
|
|
SET split_purpose = 'REMAINDER'
|
|
WHERE inbound_role = 'CHILD'
|
|
AND split_purpose = 'MASTER';
|
|
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_order', 'active_remainder_root_id',
|
|
"BIGINT UNSIGNED GENERATED ALWAYS AS (CASE WHEN inbound_role = 'CHILD' AND split_purpose = 'REMAINDER' AND split_status = 'NOT_SPLIT' AND deleted = 0 THEN root_inbound_id ELSE NULL END) STORED COMMENT '有效余量唯一约束键;历史已完成分片为空'");
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_column;
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_index;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_add_index(
|
|
IN p_table_name VARCHAR(64),
|
|
IN p_index_name VARCHAR(64),
|
|
IN p_definition TEXT
|
|
)
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = p_table_name
|
|
AND index_name = p_index_name
|
|
) THEN
|
|
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` ADD ', p_definition);
|
|
PREPARE stmt FROM @ddl;
|
|
EXECUTE stmt;
|
|
DEALLOCATE PREPARE stmt;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_order', 'uk_inbound_master_order',
|
|
'UNIQUE KEY `uk_inbound_master_order` (`tenant_id`, `master_order_id`)');
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_order', 'idx_inbound_root_role',
|
|
'KEY `idx_inbound_root_role` (`tenant_id`, `root_inbound_id`, `inbound_role`, `created_at`, `id`)');
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_assert_active_remainder_unique_ready;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_assert_active_remainder_unique_ready()
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM fl_inbound_order
|
|
WHERE inbound_role = 'CHILD'
|
|
AND split_purpose = 'REMAINDER'
|
|
AND split_status = 'NOT_SPLIT'
|
|
AND deleted = 0
|
|
AND root_inbound_id IS NOT NULL
|
|
GROUP BY tenant_id, root_inbound_id
|
|
HAVING COUNT(*) > 1
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '同一根入仓单存在多个有效余量,请先人工核对历史数据';
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_assert_active_remainder_unique_ready();
|
|
DROP PROCEDURE IF EXISTS phase3_assert_active_remainder_unique_ready;
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_order', 'uk_inbound_one_active_remainder',
|
|
'UNIQUE KEY `uk_inbound_one_active_remainder` (`tenant_id`, `active_remainder_root_id`)');
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_drop_legacy_index;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_drop_legacy_index()
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_order'
|
|
AND index_name = 'uk_inbound_tenant_order'
|
|
) THEN
|
|
ALTER TABLE fl_inbound_order DROP INDEX uk_inbound_tenant_order;
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_order'
|
|
AND index_name = 'uk_inbound_parent_sequence'
|
|
) THEN
|
|
ALTER TABLE fl_inbound_order DROP INDEX uk_inbound_parent_sequence;
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_order'
|
|
AND index_name = 'uk_inbound_one_child'
|
|
) THEN
|
|
ALTER TABLE fl_inbound_order DROP INDEX uk_inbound_one_child;
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_order'
|
|
AND index_name = 'uk_inbound_one_secondary'
|
|
) THEN
|
|
ALTER TABLE fl_inbound_order DROP INDEX uk_inbound_one_secondary;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_inbound_drop_legacy_index();
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_drop_legacy_index;
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_order', 'uk_inbound_parent_split_sequence',
|
|
'UNIQUE KEY `uk_inbound_parent_split_sequence` (`tenant_id`, `parent_inbound_id`, `split_sequence`)');
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_index;
|
|
|
|
CREATE TABLE IF NOT EXISTS fl_inbound_split_batch (
|
|
id BIGINT UNSIGNED NOT NULL COMMENT '拆分批次ID',
|
|
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
|
|
parent_inbound_id BIGINT UNSIGNED NOT NULL COMMENT '主入仓单ID',
|
|
operation_id VARCHAR(64) NOT NULL COMMENT '业务操作幂等号',
|
|
idempotency_key VARCHAR(128) NOT NULL COMMENT '请求幂等键',
|
|
expected_parent_version INT NOT NULL COMMENT '操作时主单乐观锁版本',
|
|
package_count INT UNSIGNED NOT NULL COMMENT '本批次拆分箱数',
|
|
status VARCHAR(16) NOT NULL DEFAULT 'PREPARED' COMMENT '拆分批次状态:PREPARED已准备、APPLIED已生效、CANCELLED已取消',
|
|
remark VARCHAR(500) NULL 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 '拆分批次创建时间',
|
|
applied_at DATETIME(3) NULL COMMENT '批次生效时间',
|
|
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号,每次更新递增',
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_inbound_split_operation (tenant_id, operation_id),
|
|
UNIQUE KEY uk_inbound_split_idempotency (tenant_id, parent_inbound_id, idempotency_key),
|
|
KEY idx_inbound_split_parent (tenant_id, parent_inbound_id, created_at, id),
|
|
CONSTRAINT chk_inbound_split_package CHECK (package_count > 0),
|
|
CONSTRAINT chk_inbound_split_status CHECK (status IN ('PREPARED', 'APPLIED', 'CANCELLED')),
|
|
CONSTRAINT fk_inbound_split_parent FOREIGN KEY (parent_inbound_id) REFERENCES fl_inbound_order (id)
|
|
) ENGINE=InnoDB COMMENT='主入仓单拆分批次;数量口径仅为箱数';
|
|
|
|
CREATE TABLE IF NOT EXISTS fl_inbound_split_item (
|
|
id BIGINT UNSIGNED NOT NULL COMMENT '拆分明细ID',
|
|
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
|
|
split_batch_id BIGINT UNSIGNED NOT NULL COMMENT '拆分批次ID',
|
|
parent_inbound_id BIGINT UNSIGNED NOT NULL COMMENT '主入仓单ID',
|
|
child_inbound_id BIGINT UNSIGNED NOT NULL COMMENT '子入仓单ID',
|
|
line_no INT UNSIGNED NOT NULL COMMENT '同一拆分批次内的行号',
|
|
source_inbound_detail_id BIGINT UNSIGNED NULL COMMENT '订单货物明细逻辑ID',
|
|
source_measurement_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量批次ID',
|
|
source_measurement_item_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量箱规明细ID',
|
|
package_count INT UNSIGNED NOT NULL COMMENT '分配给子单的箱数',
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '拆分数量台账创建时间',
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_inbound_split_batch_line (tenant_id, split_batch_id, line_no),
|
|
UNIQUE KEY uk_inbound_split_batch_source_child (tenant_id, split_batch_id, source_measurement_item_id, child_inbound_id),
|
|
KEY idx_inbound_split_detail (tenant_id, source_inbound_detail_id, created_at),
|
|
CONSTRAINT chk_inbound_split_item_package CHECK (package_count > 0),
|
|
CONSTRAINT fk_inbound_split_item_batch FOREIGN KEY (split_batch_id) REFERENCES fl_inbound_split_batch (id),
|
|
CONSTRAINT fk_inbound_split_item_parent FOREIGN KEY (parent_inbound_id) REFERENCES fl_inbound_order (id),
|
|
CONSTRAINT fk_inbound_split_item_child FOREIGN KEY (child_inbound_id) REFERENCES fl_inbound_order (id),
|
|
CONSTRAINT fk_inbound_split_item_measurement FOREIGN KEY (source_measurement_id) REFERENCES fl_inbound_measurement (id),
|
|
CONSTRAINT fk_inbound_split_item_measure_item FOREIGN KEY (source_measurement_item_id) REFERENCES fl_inbound_measurement_item (id)
|
|
) ENGINE=InnoDB COMMENT='主子入仓单拆分数量台账';
|
|
|
|
CREATE TABLE IF NOT EXISTS fl_inbound_split_history (
|
|
id BIGINT UNSIGNED NOT NULL COMMENT '拆分历史ID',
|
|
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
|
|
split_batch_id BIGINT UNSIGNED NOT NULL COMMENT '拆分批次ID',
|
|
operation_id VARCHAR(64) NOT NULL COMMENT '历史操作幂等号',
|
|
action_type VARCHAR(24) NOT NULL COMMENT '拆分动作:CREATE创建批次、APPLY生效、CANCEL取消',
|
|
before_snapshot JSON NULL COMMENT '操作前快照',
|
|
after_snapshot JSON NOT NULL COMMENT '操作后快照',
|
|
operator_id BIGINT UNSIGNED NOT NULL COMMENT '操作人ID',
|
|
operator_name VARCHAR(64) NULL COMMENT '操作人名称快照',
|
|
operation_reason VARCHAR(500) NULL COMMENT '操作原因',
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '不可变拆分历史创建时间',
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_inbound_split_history_operation (tenant_id, operation_id),
|
|
KEY idx_inbound_split_history (tenant_id, split_batch_id, created_at, id),
|
|
CONSTRAINT chk_inbound_split_action CHECK (action_type IN ('CREATE', 'APPLY', 'CANCEL')),
|
|
CONSTRAINT fk_inbound_split_history_batch FOREIGN KEY (split_batch_id) REFERENCES fl_inbound_split_batch (id)
|
|
) ENGINE=InnoDB COMMENT='不可变主子入仓单拆分审计历史';
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_column;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_add_column(
|
|
IN p_table_name VARCHAR(64),
|
|
IN p_column_name VARCHAR(64),
|
|
IN p_definition TEXT
|
|
)
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.columns
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = p_table_name
|
|
AND column_name = p_column_name
|
|
) THEN
|
|
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` ADD COLUMN `',
|
|
p_column_name, '` ', p_definition);
|
|
PREPARE stmt FROM @ddl;
|
|
EXECUTE stmt;
|
|
DEALLOCATE PREPARE stmt;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_measurement', 'split_batch_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '产生该测量批次的入仓拆分批次ID' AFTER inbound_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_measurement', 'source_measurement_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '子单继承或复核时的来源测量批次ID' AFTER split_batch_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_measurement_item', 'split_item_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '产生该子单测量明细的拆分台账ID' AFTER measurement_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_measurement_item', 'source_measurement_item_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '被拆分继承的来源测量箱规明细ID' AFTER split_item_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_item', 'line_no',
|
|
"INT UNSIGNED NOT NULL DEFAULT 1 COMMENT '同一拆分批次内的行号' AFTER child_inbound_id");
|
|
ALTER TABLE fl_inbound_split_item
|
|
MODIFY source_measurement_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量批次ID',
|
|
MODIFY source_measurement_item_id BIGINT UNSIGNED NOT NULL COMMENT '来源测量箱规明细ID';
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'loaded_child_inbound_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '本批次实装子单ID' AFTER package_count");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'source_inbound_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '本批次实际消耗的MASTER或REMAINDER分片ID' AFTER parent_inbound_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'remainder_child_inbound_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '本批次余量子单ID' AFTER loaded_child_inbound_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'loaded_package_count',
|
|
"INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '本批次实装箱数' AFTER remainder_child_inbound_id");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'remaining_package_count',
|
|
"INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '本批次未装箱数' AFTER loaded_package_count");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'loading_plan_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '关联装柜计划/柜次' AFTER remaining_package_count");
|
|
CALL phase3_inbound_add_column(
|
|
'fl_inbound_split_batch', 'container_booking_id',
|
|
"BIGINT UNSIGNED NULL COMMENT '关联柜次标识(兼容查询)' AFTER loading_plan_id");
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_column;
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_relation;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_add_relation(
|
|
IN p_table_name VARCHAR(64),
|
|
IN p_constraint_name VARCHAR(64),
|
|
IN p_definition TEXT
|
|
)
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.table_constraints
|
|
WHERE constraint_schema = DATABASE()
|
|
AND table_name = p_table_name
|
|
AND constraint_name = p_constraint_name
|
|
) THEN
|
|
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` ADD CONSTRAINT `',
|
|
p_constraint_name, '` ', p_definition);
|
|
PREPARE stmt FROM @ddl;
|
|
EXECUTE stmt;
|
|
DEALLOCATE PREPARE stmt;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_order', 'fk_inbound_parent_order',
|
|
'FOREIGN KEY (`parent_inbound_id`) REFERENCES `fl_inbound_order` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_order', 'fk_inbound_root_order',
|
|
'FOREIGN KEY (`root_inbound_id`) REFERENCES `fl_inbound_order` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_split_batch', 'fk_inbound_split_loaded_child',
|
|
'FOREIGN KEY (`loaded_child_inbound_id`) REFERENCES `fl_inbound_order` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_split_batch', 'fk_inbound_split_source',
|
|
'FOREIGN KEY (`source_inbound_id`) REFERENCES `fl_inbound_order` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_split_batch', 'fk_inbound_split_remainder_child',
|
|
'FOREIGN KEY (`remainder_child_inbound_id`) REFERENCES `fl_inbound_order` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_measurement', 'fk_measure_split_batch',
|
|
'FOREIGN KEY (`split_batch_id`) REFERENCES `fl_inbound_split_batch` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_measurement', 'fk_measure_source_batch',
|
|
'FOREIGN KEY (`source_measurement_id`) REFERENCES `fl_inbound_measurement` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_measurement_item', 'fk_measure_item_split_item',
|
|
'FOREIGN KEY (`split_item_id`) REFERENCES `fl_inbound_split_item` (`id`)');
|
|
CALL phase3_inbound_add_relation(
|
|
'fl_inbound_measurement_item', 'fk_measure_item_source_item',
|
|
'FOREIGN KEY (`source_measurement_item_id`) REFERENCES `fl_inbound_measurement_item` (`id`)');
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_relation;
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_index;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_add_index(
|
|
IN p_table_name VARCHAR(64),
|
|
IN p_index_name VARCHAR(64),
|
|
IN p_definition TEXT
|
|
)
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = p_table_name
|
|
AND index_name = p_index_name
|
|
) THEN
|
|
SET @ddl = CONCAT('ALTER TABLE `', p_table_name, '` ADD ', p_definition);
|
|
PREPARE stmt FROM @ddl;
|
|
EXECUTE stmt;
|
|
DEALLOCATE PREPARE stmt;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_measurement', 'idx_measure_split_source',
|
|
'KEY `idx_measure_split_source` (`tenant_id`, `split_batch_id`, `source_measurement_id`, `created_at`)');
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_measurement_item', 'idx_measure_item_split_source',
|
|
'KEY `idx_measure_item_split_source` (`tenant_id`, `split_item_id`, `source_measurement_item_id`)');
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_split_item', 'uk_inbound_split_batch_line',
|
|
'UNIQUE KEY `uk_inbound_split_batch_line` (`tenant_id`, `split_batch_id`, `line_no`)');
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_split_batch', 'idx_inbound_split_loading_plan',
|
|
'KEY `idx_inbound_split_loading_plan` (`tenant_id`, `loading_plan_id`, `container_booking_id`, `status`, `id`)');
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_split_batch', 'uk_inbound_split_source_once',
|
|
'UNIQUE KEY `uk_inbound_split_source_once` (`tenant_id`, `source_inbound_id`)');
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_drop_split_legacy_index;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_inbound_drop_split_legacy_index()
|
|
BEGIN
|
|
IF EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_split_item' AND index_name = 'uk_inbound_split_child') THEN
|
|
ALTER TABLE fl_inbound_split_item DROP INDEX uk_inbound_split_child;
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_split_item' AND index_name = 'uk_inbound_split_batch_child') THEN
|
|
ALTER TABLE fl_inbound_split_item DROP INDEX uk_inbound_split_batch_child;
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_split_item' AND index_name = 'uk_inbound_split_batch_source_item') THEN
|
|
ALTER TABLE fl_inbound_split_item DROP INDEX uk_inbound_split_batch_source_item;
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_inbound_drop_split_legacy_index();
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_drop_split_legacy_index;
|
|
CALL phase3_inbound_add_index(
|
|
'fl_inbound_split_item', 'uk_inbound_split_batch_source_child',
|
|
'UNIQUE KEY `uk_inbound_split_batch_source_child` (`tenant_id`, `split_batch_id`, `source_measurement_item_id`, `child_inbound_id`)');
|
|
DROP PROCEDURE IF EXISTS phase3_inbound_add_index;
|
|
|
|
DROP TRIGGER IF EXISTS trg_inbound_order_parent_before_insert;
|
|
DROP TRIGGER IF EXISTS trg_inbound_order_parent_before_update;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_item_before_insert;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_batch_before_insert;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_batch_before_update;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_item_before_update;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_item_before_delete;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_history_before_update;
|
|
DROP TRIGGER IF EXISTS trg_inbound_split_history_before_delete;
|
|
|
|
DELIMITER $$
|
|
CREATE TRIGGER trg_inbound_order_parent_before_insert
|
|
BEFORE INSERT ON fl_inbound_order
|
|
FOR EACH ROW
|
|
BEGIN
|
|
IF NEW.inbound_role NOT IN ('MASTER', 'CHILD') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单层级非法';
|
|
END IF;
|
|
IF NEW.split_status NOT IN ('NOT_SPLIT', 'PARTIALLY_SPLIT', 'FULLY_SPLIT') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单拆分状态非法';
|
|
END IF;
|
|
IF NEW.split_purpose NOT IN ('MASTER', 'LOADED', 'REMAINDER') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单分片用途非法';
|
|
END IF;
|
|
IF NEW.package_count IS NOT NULL AND NEW.package_count = 0 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单箱数必须大于0';
|
|
END IF;
|
|
IF NEW.inbound_role = 'MASTER' AND NEW.parent_inbound_id IS NOT NULL THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主入仓单不能绑定父单';
|
|
END IF;
|
|
IF NEW.inbound_role = 'MASTER' AND NEW.split_purpose <> 'MASTER' THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主入仓单用途必须为MASTER';
|
|
END IF;
|
|
IF NEW.inbound_role = 'CHILD' THEN
|
|
IF NEW.parent_inbound_id IS NULL OR NEW.root_inbound_id IS NULL
|
|
OR NEW.split_sequence IS NULL OR NEW.package_count IS NULL THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '子入仓单缺少主单、顺序号或箱数';
|
|
END IF;
|
|
IF NEW.split_purpose <> 'REMAINDER' THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '新建子入仓单只能作为余量分片';
|
|
END IF;
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order parent_order
|
|
WHERE parent_order.id = NEW.parent_inbound_id
|
|
AND parent_order.tenant_id = NEW.tenant_id
|
|
AND parent_order.inbound_role = 'MASTER'
|
|
AND parent_order.deleted = 0
|
|
) OR NEW.root_inbound_id <> NEW.parent_inbound_id THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '子入仓单必须绑定同一客户的有效主单';
|
|
END IF;
|
|
END IF;
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_order_parent_before_update
|
|
BEFORE UPDATE ON fl_inbound_order
|
|
FOR EACH ROW
|
|
BEGIN
|
|
IF NOT (OLD.tenant_id <=> NEW.tenant_id)
|
|
OR NOT (OLD.inbound_role <=> NEW.inbound_role)
|
|
OR NOT (OLD.parent_inbound_id <=> NEW.parent_inbound_id)
|
|
OR NOT (OLD.root_inbound_id <=> NEW.root_inbound_id)
|
|
OR NOT (OLD.split_sequence <=> NEW.split_sequence)
|
|
OR NOT (OLD.split_purpose <=> NEW.split_purpose) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单主子归属创建后不可修改';
|
|
END IF;
|
|
IF NEW.split_purpose NOT IN ('MASTER', 'LOADED', 'REMAINDER') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单分片用途非法';
|
|
END IF;
|
|
IF NEW.inbound_role = 'CHILD'
|
|
AND (NEW.package_count IS NULL OR NEW.package_count = 0) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '子入仓单箱数必须大于0';
|
|
END IF;
|
|
IF NEW.split_status NOT IN ('NOT_SPLIT', 'PARTIALLY_SPLIT', 'FULLY_SPLIT') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单拆分状态非法';
|
|
END IF;
|
|
IF (NEW.inbound_role = 'CHILD' AND NEW.split_purpose = 'MASTER')
|
|
OR (NEW.inbound_role = 'MASTER' AND NEW.split_purpose <> 'MASTER') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '入仓单层级与用途不一致';
|
|
END IF;
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_item_before_insert
|
|
BEFORE INSERT ON fl_inbound_split_item
|
|
FOR EACH ROW
|
|
BEGIN
|
|
IF NEW.source_measurement_id IS NULL OR NEW.source_measurement_item_id IS NULL THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分明细必须绑定真实测量来源';
|
|
END IF;
|
|
IF NOT EXISTS (
|
|
SELECT 1
|
|
FROM fl_inbound_split_batch batch
|
|
JOIN fl_inbound_order parent_order ON parent_order.id = batch.parent_inbound_id
|
|
JOIN fl_inbound_order child_order ON child_order.id = NEW.child_inbound_id
|
|
WHERE batch.id = NEW.split_batch_id
|
|
AND batch.tenant_id = NEW.tenant_id
|
|
AND batch.parent_inbound_id = NEW.parent_inbound_id
|
|
AND batch.status = 'PREPARED'
|
|
AND batch.loaded_child_inbound_id IS NULL
|
|
AND batch.remainder_child_inbound_id IS NOT NULL
|
|
AND NEW.child_inbound_id = batch.remainder_child_inbound_id
|
|
AND parent_order.tenant_id = NEW.tenant_id
|
|
AND parent_order.inbound_role = 'MASTER'
|
|
AND child_order.tenant_id = NEW.tenant_id
|
|
AND child_order.inbound_role = 'CHILD'
|
|
AND child_order.split_purpose = 'REMAINDER'
|
|
AND child_order.parent_inbound_id = NEW.parent_inbound_id
|
|
AND child_order.package_count >= NEW.package_count
|
|
AND child_order.deleted = 0
|
|
AND EXISTS (
|
|
SELECT 1
|
|
FROM fl_inbound_measurement_item source_item
|
|
JOIN fl_inbound_measurement source_batch ON source_batch.id = source_item.measurement_id
|
|
WHERE source_item.id = NEW.source_measurement_item_id
|
|
AND source_item.tenant_id = NEW.tenant_id
|
|
AND source_item.measurement_id = NEW.source_measurement_id
|
|
AND source_batch.inbound_id = COALESCE(batch.source_inbound_id, batch.parent_inbound_id)
|
|
)
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分明细与批次、主单或子单不一致';
|
|
END IF;
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_batch_before_insert
|
|
BEFORE INSERT ON fl_inbound_split_batch
|
|
FOR EACH ROW
|
|
BEGIN
|
|
IF NEW.status <> 'PREPARED' OR NEW.applied_at IS NOT NULL THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次必须从PREPARED创建';
|
|
END IF;
|
|
IF NEW.loaded_child_inbound_id IS NOT NULL
|
|
OR NEW.loaded_package_count = 0
|
|
OR NEW.loaded_package_count + NEW.remaining_package_count <> NEW.package_count
|
|
OR (NEW.remaining_package_count = 0 AND NEW.remainder_child_inbound_id IS NOT NULL)
|
|
OR (NEW.remaining_package_count > 0 AND NEW.remainder_child_inbound_id IS NULL) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '新拆分批次必须由来源单承接实装且最多创建一个余量子单';
|
|
END IF;
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order parent_order
|
|
WHERE parent_order.id = NEW.parent_inbound_id
|
|
AND parent_order.tenant_id = NEW.tenant_id
|
|
AND parent_order.inbound_role = 'MASTER'
|
|
AND parent_order.deleted = 0
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次主单不存在或客户归属不一致';
|
|
END IF;
|
|
IF NEW.source_inbound_id IS NULL OR NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order source_order
|
|
WHERE source_order.id = NEW.source_inbound_id
|
|
AND source_order.tenant_id = NEW.tenant_id
|
|
AND source_order.deleted = 0
|
|
AND ((source_order.id = NEW.parent_inbound_id
|
|
AND source_order.inbound_role = 'MASTER'
|
|
AND ((source_order.split_status = 'NOT_SPLIT'
|
|
AND COALESCE(source_order.package_count, source_order.total_package_count) = NEW.package_count)
|
|
OR (source_order.split_status = 'FULLY_SPLIT'
|
|
AND source_order.package_count = NEW.loaded_package_count))) OR
|
|
(source_order.inbound_role = 'CHILD'
|
|
AND source_order.parent_inbound_id = NEW.parent_inbound_id
|
|
AND source_order.split_purpose = 'REMAINDER'
|
|
AND ((source_order.split_status = 'NOT_SPLIT'
|
|
AND source_order.package_count = NEW.package_count)
|
|
OR (source_order.split_status = 'FULLY_SPLIT'
|
|
AND source_order.package_count = NEW.loaded_package_count))))
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次来源必须是箱数守恒的根主单或余量分片';
|
|
END IF;
|
|
IF NEW.loaded_package_count > 0 AND (
|
|
NEW.loading_plan_id IS NULL OR NEW.container_booking_id IS NULL OR NOT EXISTS (
|
|
SELECT 1 FROM fl_loading_plan plan
|
|
WHERE plan.id = NEW.loading_plan_id
|
|
AND plan.container_booking_id = NEW.container_booking_id
|
|
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
|
|
WHERE plan_item.loading_plan_id = plan.id
|
|
AND plan_item.account_id = NEW.tenant_id
|
|
AND plan_item.inbound_id = NEW.source_inbound_id
|
|
AND plan_item.deleted = 0)
|
|
)
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '实装拆分批次必须绑定匹配的装柜计划和柜次';
|
|
END IF;
|
|
IF NEW.remainder_child_inbound_id IS NOT NULL AND NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order remainder_order
|
|
WHERE remainder_order.id = NEW.remainder_child_inbound_id
|
|
AND remainder_order.tenant_id = NEW.tenant_id
|
|
AND remainder_order.parent_inbound_id = NEW.parent_inbound_id
|
|
AND remainder_order.root_inbound_id = NEW.parent_inbound_id
|
|
AND remainder_order.inbound_role = 'CHILD'
|
|
AND remainder_order.split_purpose = 'REMAINDER'
|
|
AND remainder_order.split_status = 'NOT_SPLIT'
|
|
AND remainder_order.package_count = NEW.remaining_package_count
|
|
AND remainder_order.deleted = 0
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '余量子入仓单与拆分批次数量或根归属不一致';
|
|
END IF;
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_batch_before_update
|
|
BEFORE UPDATE ON fl_inbound_split_batch
|
|
FOR EACH ROW
|
|
BEGIN
|
|
IF OLD.status IN ('APPLIED', 'CANCELLED') THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已结束拆分批次不可修改';
|
|
END IF;
|
|
IF NOT (OLD.parent_inbound_id <=> NEW.parent_inbound_id)
|
|
OR NOT (OLD.source_inbound_id <=> NEW.source_inbound_id)
|
|
OR NOT (OLD.loaded_child_inbound_id <=> NEW.loaded_child_inbound_id)
|
|
OR NOT (OLD.remainder_child_inbound_id <=> NEW.remainder_child_inbound_id)
|
|
OR NOT (OLD.package_count <=> NEW.package_count)
|
|
OR NOT (OLD.loaded_package_count <=> NEW.loaded_package_count)
|
|
OR NOT (OLD.remaining_package_count <=> NEW.remaining_package_count)
|
|
OR NOT (OLD.loading_plan_id <=> NEW.loading_plan_id)
|
|
OR NOT (OLD.container_booking_id <=> NEW.container_booking_id) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次来源、子单、柜次与数量创建后不可修改';
|
|
END IF;
|
|
IF NEW.status = 'APPLIED' THEN
|
|
IF NEW.applied_at IS NULL
|
|
OR (NEW.loaded_package_count > 0 AND (
|
|
NEW.loading_plan_id IS NULL OR NEW.container_booking_id IS NULL OR NOT EXISTS (
|
|
SELECT 1 FROM fl_loading_plan plan
|
|
WHERE plan.id = NEW.loading_plan_id
|
|
AND plan.container_booking_id = NEW.container_booking_id
|
|
AND EXISTS (SELECT 1 FROM fl_loading_plan_item plan_item
|
|
WHERE plan_item.loading_plan_id = plan.id
|
|
AND plan_item.account_id = NEW.tenant_id
|
|
AND plan_item.inbound_id = NEW.source_inbound_id
|
|
AND plan_item.deleted = 0))))
|
|
OR NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order parent_order
|
|
WHERE parent_order.id = NEW.parent_inbound_id
|
|
AND parent_order.tenant_id = NEW.tenant_id
|
|
AND parent_order.inbound_role = 'MASTER'
|
|
AND parent_order.version > NEW.expected_parent_version
|
|
) OR NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order source_order
|
|
WHERE source_order.id = NEW.source_inbound_id
|
|
AND source_order.tenant_id = NEW.tenant_id
|
|
AND source_order.split_status = 'FULLY_SPLIT'
|
|
AND source_order.package_count = NEW.loaded_package_count
|
|
) OR
|
|
(SELECT COALESCE(SUM(item.package_count), 0)
|
|
FROM fl_inbound_split_item item
|
|
WHERE item.tenant_id = NEW.tenant_id
|
|
AND item.split_batch_id = NEW.id) <> NEW.remaining_package_count OR
|
|
(SELECT COUNT(DISTINCT item.child_inbound_id)
|
|
FROM fl_inbound_split_item item
|
|
WHERE item.tenant_id = NEW.tenant_id
|
|
AND item.split_batch_id = NEW.id) <> CASE WHEN NEW.remaining_package_count > 0 THEN 1 ELSE 0 END OR
|
|
(NEW.loaded_child_inbound_id IS NOT NULL) OR
|
|
NEW.loaded_package_count + NEW.remaining_package_count <> NEW.package_count OR
|
|
(NEW.remaining_package_count > 0 AND NEW.remainder_child_inbound_id IS NULL) OR
|
|
(NEW.remainder_child_inbound_id IS NOT NULL AND NOT EXISTS (
|
|
SELECT 1 FROM fl_inbound_order c WHERE c.id = NEW.remainder_child_inbound_id
|
|
AND c.parent_inbound_id = NEW.parent_inbound_id AND c.root_inbound_id = NEW.parent_inbound_id
|
|
AND c.split_purpose = 'REMAINDER' AND c.split_status = 'NOT_SPLIT'
|
|
AND c.package_count = NEW.remaining_package_count AND c.deleted = 0)) OR
|
|
EXISTS (SELECT 1 FROM fl_inbound_split_item item
|
|
WHERE item.tenant_id = NEW.tenant_id
|
|
AND item.split_batch_id = NEW.id
|
|
AND item.child_inbound_id <> NEW.remainder_child_inbound_id) OR
|
|
EXISTS (SELECT 1
|
|
FROM fl_inbound_split_item item
|
|
JOIN fl_inbound_order child_order ON child_order.id = item.child_inbound_id
|
|
WHERE item.tenant_id = NEW.tenant_id
|
|
AND item.split_batch_id = NEW.id
|
|
GROUP BY child_order.id, child_order.package_count
|
|
HAVING child_order.package_count <> SUM(item.package_count)) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '二级子入仓单或拆分明细箱数合计不一致';
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM fl_inbound_split_item split_item
|
|
JOIN fl_inbound_measurement_item source_item
|
|
ON source_item.id = split_item.source_measurement_item_id
|
|
WHERE split_item.tenant_id = NEW.tenant_id
|
|
AND split_item.split_batch_id = NEW.id
|
|
GROUP BY split_item.source_measurement_item_id, source_item.package_count
|
|
HAVING SUM(split_item.package_count) > source_item.package_count
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '子单承接箱数超过来源测量箱规箱数';
|
|
END IF;
|
|
IF NOT EXISTS (
|
|
SELECT 1
|
|
FROM fl_inbound_order root_order
|
|
WHERE root_order.id = NEW.parent_inbound_id
|
|
AND root_order.tenant_id = NEW.tenant_id
|
|
AND root_order.inbound_role = 'MASTER'
|
|
AND root_order.deleted = 0
|
|
AND root_order.total_package_count =
|
|
COALESCE(root_order.package_count, 0) +
|
|
COALESCE((SELECT SUM(child.package_count)
|
|
FROM fl_inbound_order child
|
|
WHERE child.tenant_id = NEW.tenant_id
|
|
AND child.root_inbound_id = root_order.id
|
|
AND child.inbound_role = 'CHILD'
|
|
AND child.deleted = 0), 0)
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '根入仓单原始箱数与已完成分片及当前余量不守恒';
|
|
END IF;
|
|
ELSEIF NEW.status = 'CANCELLED' THEN
|
|
IF EXISTS (
|
|
SELECT 1 FROM fl_inbound_split_item item
|
|
WHERE item.tenant_id = NEW.tenant_id
|
|
AND item.split_batch_id = NEW.id
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '已有子单明细的拆分批次不可取消';
|
|
END IF;
|
|
ELSEIF NEW.status <> 'PREPARED' THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次状态流转非法';
|
|
END IF;
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_item_before_update
|
|
BEFORE UPDATE ON fl_inbound_split_item
|
|
FOR EACH ROW
|
|
BEGIN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分数量台账不可修改';
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_item_before_delete
|
|
BEFORE DELETE ON fl_inbound_split_item
|
|
FOR EACH ROW
|
|
BEGIN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分数量台账不可删除';
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_history_before_update
|
|
BEFORE UPDATE ON fl_inbound_split_history
|
|
FOR EACH ROW
|
|
BEGIN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分历史不可修改';
|
|
END$$
|
|
|
|
CREATE TRIGGER trg_inbound_split_history_before_delete
|
|
BEFORE DELETE ON fl_inbound_split_history
|
|
FOR EACH ROW
|
|
BEGIN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分历史不可删除';
|
|
END$$
|
|
DELIMITER ;
|
|
|
|
DROP PROCEDURE IF EXISTS phase3_assert_inbound_parent_child_schema;
|
|
DELIMITER $$
|
|
CREATE PROCEDURE phase3_assert_inbound_parent_child_schema()
|
|
BEGIN
|
|
IF (SELECT COUNT(*) FROM information_schema.tables
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name IN ('fl_inbound_split_batch', 'fl_inbound_split_item',
|
|
'fl_inbound_split_history')) <> 3 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主子入仓单拆分台账未完整创建';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_order'
|
|
AND column_name IN ('inbound_role', 'parent_inbound_id', 'root_inbound_id',
|
|
'split_sequence', 'split_status', 'package_count',
|
|
'master_order_id', 'split_purpose', 'active_remainder_root_id')) <> 9 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主子入仓单关系字段未完整创建';
|
|
END IF;
|
|
IF (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_order'
|
|
AND index_name IN ('uk_inbound_master_order', 'uk_inbound_parent_split_sequence',
|
|
'uk_inbound_one_active_remainder')) <> 3
|
|
OR (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_split_batch'
|
|
AND index_name IN ('uk_inbound_split_operation', 'uk_inbound_split_idempotency',
|
|
'uk_inbound_split_source_once')) <> 3
|
|
OR (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_split_item'
|
|
AND index_name IN ('uk_inbound_split_batch_line',
|
|
'uk_inbound_split_batch_source_child')) <> 2
|
|
OR (SELECT COUNT(DISTINCT index_name) FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_split_history'
|
|
AND index_name = 'uk_inbound_split_history_operation') <> 1 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主子入仓单唯一约束未完整创建';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
|
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_split_batch'
|
|
AND column_name IN ('source_inbound_id', 'loaded_child_inbound_id',
|
|
'remainder_child_inbound_id', 'loaded_package_count',
|
|
'remaining_package_count', 'loading_plan_id',
|
|
'container_booking_id')) <> 7 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分批次来源、子单、数量或柜次字段未完整创建';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.columns
|
|
WHERE table_schema = DATABASE() AND table_name = 'fl_inbound_split_item'
|
|
AND column_name IN ('source_measurement_id', 'source_measurement_item_id')
|
|
AND is_nullable = 'NO') <> 2 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拆分数量台账必须绑定非空测量来源';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.table_constraints
|
|
WHERE constraint_schema = DATABASE()
|
|
AND constraint_name IN ('fk_inbound_parent_order', 'fk_inbound_root_order',
|
|
'fk_inbound_split_source', 'fk_inbound_split_loaded_child', 'fk_inbound_split_remainder_child',
|
|
'fk_measure_split_batch', 'fk_measure_source_batch',
|
|
'fk_measure_item_split_item', 'fk_measure_item_source_item')) <> 9 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主子入仓单与测量关联约束未完整创建';
|
|
END IF;
|
|
IF (SELECT COUNT(*) FROM information_schema.triggers
|
|
WHERE trigger_schema = DATABASE()
|
|
AND trigger_name IN ('trg_inbound_order_parent_before_insert',
|
|
'trg_inbound_order_parent_before_update',
|
|
'trg_inbound_split_item_before_insert',
|
|
'trg_inbound_split_batch_before_insert',
|
|
'trg_inbound_split_batch_before_update',
|
|
'trg_inbound_split_item_before_update',
|
|
'trg_inbound_split_item_before_delete',
|
|
'trg_inbound_split_history_before_update',
|
|
'trg_inbound_split_history_before_delete')) <> 9 THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '主子入仓单数据库保护触发器未完整创建';
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_order'
|
|
AND index_name IN ('uk_inbound_tenant_order', 'uk_inbound_one_child',
|
|
'uk_inbound_one_secondary', 'uk_inbound_parent_sequence')
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '旧订单唯一索引仍阻止创建子入仓单';
|
|
END IF;
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.statistics
|
|
WHERE table_schema = DATABASE()
|
|
AND table_name = 'fl_inbound_split_item'
|
|
AND index_name IN ('uk_inbound_split_child', 'uk_inbound_split_batch_child',
|
|
'uk_inbound_split_batch_source_item')
|
|
) THEN
|
|
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '旧拆分明细唯一索引仍阻止数量守恒分配';
|
|
END IF;
|
|
END$$
|
|
DELIMITER ;
|
|
CALL phase3_assert_inbound_parent_child_schema();
|
|
DROP PROCEDURE IF EXISTS phase3_assert_inbound_parent_child_schema;
|