优化
This commit is contained in:
@@ -4491,6 +4491,96 @@ CREATE TABLE IF NOT EXISTS fl_loading_plan_history (
|
||||
|
||||
-- fl_loading_pick_task 曾被另一套入库汇总模型复用。先按字段签名识别并迁走,
|
||||
-- 再创建智能装柜任务表;未知或混合结构必须人工处理,禁止静默套用错误表型。
|
||||
DROP PROCEDURE IF EXISTS assert_loading_pick_task_shapes;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE assert_loading_pick_task_shapes(IN require_both TINYINT)
|
||||
BEGIN
|
||||
DECLARE source_exists INT DEFAULT 0;
|
||||
DECLARE target_exists INT DEFAULT 0;
|
||||
DECLARE source_total INT DEFAULT 0;
|
||||
DECLARE source_smart INT DEFAULT 0;
|
||||
DECLARE source_inbound INT DEFAULT 0;
|
||||
DECLARE target_total INT DEFAULT 0;
|
||||
DECLARE target_inbound INT DEFAULT 0;
|
||||
SELECT COUNT(*) INTO source_exists FROM information_schema.tables
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task';
|
||||
SELECT COUNT(*) INTO target_exists FROM information_schema.tables
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_loading_pick_task';
|
||||
IF source_exists = 1 THEN
|
||||
SELECT COUNT(*) INTO source_total FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task';
|
||||
SELECT COUNT(*) INTO source_smart FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND (
|
||||
(column_name = 'id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'loading_plan_id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'container_no' AND LOWER(column_type) = 'varchar(64)' AND is_nullable = 'NO')
|
||||
OR (column_name = 'task_status' AND LOWER(column_type) = 'varchar(16)' AND is_nullable = 'NO' AND column_default = 'LOADING')
|
||||
OR (column_name = 'started_by' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'started_by_name' AND LOWER(column_type) = 'varchar(64)' AND is_nullable = 'YES')
|
||||
OR (column_name = 'started_at' AND data_type = 'datetime' AND datetime_precision = 3 AND is_nullable = 'NO' AND LOWER(column_default) LIKE 'current_timestamp%')
|
||||
OR (column_name = 'completed_by' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'YES')
|
||||
OR (column_name = 'completed_by_name' AND LOWER(column_type) = 'varchar(64)' AND is_nullable = 'YES')
|
||||
OR (column_name = 'completed_at' AND data_type = 'datetime' AND datetime_precision = 3 AND is_nullable = 'YES')
|
||||
OR (column_name = 'version' AND LOWER(column_type) = 'int unsigned' AND is_nullable = 'NO' AND CAST(column_default AS CHAR) = '0'));
|
||||
SELECT COUNT(*) INTO source_inbound FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND (
|
||||
(column_name = 'id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'tenant_id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'inbound_id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'status' AND LOWER(column_type) = 'varchar(24)' AND is_nullable = 'NO' AND column_default = 'PENDING')
|
||||
OR (column_name = 'version' AND LOWER(column_type) = 'int' AND is_nullable = 'NO' AND CAST(column_default AS CHAR) = '0')
|
||||
OR (column_name = 'expected_count' AND LOWER(column_type) = 'int unsigned' AND is_nullable = 'YES')
|
||||
OR (column_name = 'picked_count' AND LOWER(column_type) = 'int unsigned' AND is_nullable = 'YES')
|
||||
OR (column_name = 'remark' AND LOWER(column_type) = 'varchar(1000)' AND is_nullable = 'YES')
|
||||
OR (column_name = 'updated_by' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'updated_by_name' AND LOWER(column_type) = 'varchar(64)' AND is_nullable = 'YES')
|
||||
OR (column_name = 'created_at' AND data_type = 'datetime' AND datetime_precision = 3 AND is_nullable = 'NO' AND LOWER(column_default) LIKE 'current_timestamp%')
|
||||
OR (column_name = 'updated_at' AND data_type = 'datetime' AND datetime_precision = 3 AND is_nullable = 'NO' AND LOWER(column_default) LIKE 'current_timestamp%' AND LOWER(extra) LIKE '%on update current_timestamp%'));
|
||||
IF NOT (
|
||||
(source_total = 11 AND source_smart = 11
|
||||
AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND index_name = 'uk_loading_pick_task_plan' AND non_unique = 0 AND seq_in_index = 1 AND column_name = 'loading_plan_id') = 1
|
||||
AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND index_name = 'idx_loading_pick_container' AND ((seq_in_index = 1 AND column_name = 'container_no') OR (seq_in_index = 2 AND column_name = 'task_status') OR (seq_in_index = 3 AND column_name = 'started_at'))) = 3
|
||||
AND (SELECT COUNT(*) FROM information_schema.key_column_usage WHERE constraint_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND column_name = 'loading_plan_id' AND referenced_table_name = 'fl_loading_plan' AND referenced_column_name = 'id') = 1)
|
||||
OR
|
||||
(source_total = 12 AND source_inbound = 12
|
||||
AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND index_name = 'uk_loading_pick_tenant_inbound' AND non_unique = 0 AND ((seq_in_index = 1 AND column_name = 'tenant_id') OR (seq_in_index = 2 AND column_name = 'inbound_id'))) = 2
|
||||
AND (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND index_name = 'idx_loading_pick_status' AND ((seq_in_index = 1 AND column_name = 'tenant_id') OR (seq_in_index = 2 AND column_name = 'status') OR (seq_in_index = 3 AND column_name = 'updated_at'))) = 3
|
||||
AND (SELECT COUNT(*) FROM information_schema.key_column_usage WHERE constraint_schema = 'baiyue_firstleg' AND table_name = 'fl_loading_pick_task' AND column_name = 'inbound_id' AND referenced_table_name = 'fl_inbound_order' AND referenced_column_name = 'id') = 1)
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拣货任务迁移失败:fl_loading_pick_task 不是完整 canonical 表型';
|
||||
END IF;
|
||||
END IF;
|
||||
IF target_exists = 1 THEN
|
||||
SELECT COUNT(*) INTO target_total FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_loading_pick_task';
|
||||
SELECT COUNT(*) INTO target_inbound FROM information_schema.columns
|
||||
WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_loading_pick_task' AND (
|
||||
(column_name = 'id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'tenant_id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'inbound_id' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'status' AND LOWER(column_type) = 'varchar(24)' AND is_nullable = 'NO' AND column_default = 'PENDING')
|
||||
OR (column_name = 'version' AND LOWER(column_type) = 'int' AND is_nullable = 'NO' AND CAST(column_default AS CHAR) = '0')
|
||||
OR (column_name = 'expected_count' AND LOWER(column_type) = 'int unsigned' AND is_nullable = 'YES')
|
||||
OR (column_name = 'picked_count' AND LOWER(column_type) = 'int unsigned' AND is_nullable = 'YES')
|
||||
OR (column_name = 'remark' AND LOWER(column_type) = 'varchar(1000)' AND is_nullable = 'YES')
|
||||
OR (column_name = 'updated_by' AND LOWER(column_type) = 'bigint unsigned' AND is_nullable = 'NO')
|
||||
OR (column_name = 'updated_by_name' AND LOWER(column_type) = 'varchar(64)' AND is_nullable = 'YES')
|
||||
OR (column_name = 'created_at' AND data_type = 'datetime' AND datetime_precision = 3 AND is_nullable = 'NO' AND LOWER(column_default) LIKE 'current_timestamp%')
|
||||
OR (column_name = 'updated_at' AND data_type = 'datetime' AND datetime_precision = 3 AND is_nullable = 'NO' AND LOWER(column_default) LIKE 'current_timestamp%' AND LOWER(extra) LIKE '%on update current_timestamp%'));
|
||||
IF target_total <> 12 OR target_inbound <> 12
|
||||
OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_loading_pick_task' AND index_name = 'uk_loading_pick_tenant_inbound' AND non_unique = 0 AND ((seq_in_index = 1 AND column_name = 'tenant_id') OR (seq_in_index = 2 AND column_name = 'inbound_id'))) <> 2
|
||||
OR (SELECT COUNT(*) FROM information_schema.statistics WHERE table_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_loading_pick_task' AND index_name = 'idx_loading_pick_status' AND ((seq_in_index = 1 AND column_name = 'tenant_id') OR (seq_in_index = 2 AND column_name = 'status') OR (seq_in_index = 3 AND column_name = 'updated_at'))) <> 3
|
||||
OR (SELECT COUNT(*) FROM information_schema.key_column_usage WHERE constraint_schema = 'baiyue_firstleg' AND table_name = 'fl_inbound_loading_pick_task' AND column_name = 'inbound_id' AND referenced_table_name = 'fl_inbound_order' AND referenced_column_name = 'id') <> 1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拣货任务迁移失败:fl_inbound_loading_pick_task 不是完整 canonical 表型';
|
||||
END IF;
|
||||
END IF;
|
||||
IF require_both = 1 AND (source_exists <> 1 OR target_exists <> 1 OR source_smart <> 11) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '拣货任务终验失败:两张 canonical 表未同时就绪';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_loading_pick_task_shapes(0);
|
||||
|
||||
DROP PROCEDURE IF EXISTS migrate_legacy_loading_pick_task;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE migrate_legacy_loading_pick_task()
|
||||
@@ -5037,6 +5127,32 @@ DELIMITER ;
|
||||
|
||||
-- 三期智能装柜、预装清单和装柜清单平台权限;与一期平台根菜单幂等合并。
|
||||
USE baiyue_iam;
|
||||
DROP PROCEDURE IF EXISTS assert_smart_loading_permission_ids_available;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE assert_smart_loading_permission_ids_available()
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM iam_permission
|
||||
WHERE id IN (5102091, 5102092, 5102093, 5102094, 5102096, 5102097, 5102098, 5102099)
|
||||
AND permission_code NOT IN (
|
||||
'platform:firstleg:container:view', 'platform:firstleg:container:create',
|
||||
'platform:firstleg:container:edit', 'platform:firstleg:smart-loading:list',
|
||||
'platform:firstleg:smart-loading:create', 'platform:firstleg:smart-loading:assign',
|
||||
'platform:firstleg:smart-loading:delete', 'platform:firstleg:smart-loading:push',
|
||||
'firstleg:inbound:split', 'firstleg:inbound:preload', 'firstleg:inbound:preload-view',
|
||||
'platform:firstleg:inbound:loading:edit', 'platform:firstleg:inbound:loading:view',
|
||||
'platform:firstleg:inbound:loading:complete', 'platform:firstleg:inbound:delivery:complete',
|
||||
'platform:firstleg:inbound:picking:edit', 'platform:firstleg:inbound:picking:view'
|
||||
)
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '三期权限迁移失败:5102091-5102099 存在未知权限占用';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_smart_loading_permission_ids_available();
|
||||
DROP PROCEDURE assert_smart_loading_permission_ids_available;
|
||||
|
||||
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)
|
||||
@@ -5207,8 +5323,6 @@ BEGIN
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL assert_phase3_smart_loading_schema();
|
||||
DROP PROCEDURE IF EXISTS assert_phase3_smart_loading_schema;
|
||||
|
||||
-- ============================================================
|
||||
|
||||
@@ -6242,6 +6356,11 @@ 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;
|
||||
CALL assert_phase3_smart_loading_schema();
|
||||
DROP PROCEDURE IF EXISTS assert_phase3_smart_loading_schema;
|
||||
|
||||
-- 兼容已经执行过旧单行配置模型的开发/测试库。仅精确识别旧结构时丢弃旧值并重建;
|
||||
-- 已是四箱规结构时不做 DDL,避免破坏 Admin 已编辑的数据。
|
||||
DROP PROCEDURE IF EXISTS unified_upgrade_legacy_customer_dimension_config;
|
||||
@@ -7109,11 +7228,27 @@ BEGIN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '统一迁移失败:三期入库装柜权限 ID 未完成迁移';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM baiyue_iam.iam_permission
|
||||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||||
AND ((id = 5102091 AND permission_code = 'platform:firstleg:container:view' AND parent_id = 5102090)
|
||||
OR (id = 5102092 AND permission_code = 'platform:firstleg:container:create' AND parent_id = 5102090)
|
||||
OR (id = 5102093 AND permission_code = 'platform:firstleg:container:edit' AND parent_id = 5102090)
|
||||
OR (id = 5102094 AND permission_code = 'platform:firstleg:smart-loading:list' AND parent_id = 5102000)
|
||||
OR (id = 5102096 AND permission_code = 'platform:firstleg:smart-loading:create' AND parent_id = 5102094)
|
||||
OR (id = 5102097 AND permission_code = 'platform:firstleg:smart-loading:assign' AND parent_id = 5102094)
|
||||
OR (id = 5102098 AND permission_code = 'platform:firstleg:smart-loading:delete' AND parent_id = 5102094)
|
||||
OR (id = 5102099 AND permission_code = 'platform:firstleg:smart-loading:push' AND parent_id = 5102094))) <> 8 THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '统一迁移失败:智能装柜权限 ID 或父子关系不正确';
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL phase3_assert_inbound_parent_child_schema();
|
||||
DROP PROCEDURE IF EXISTS phase3_assert_inbound_parent_child_schema;
|
||||
|
||||
CALL assert_loading_pick_task_shapes(1);
|
||||
DROP PROCEDURE IF EXISTS assert_loading_pick_task_shapes;
|
||||
|
||||
-- WAIT_SPLIT 是二期当前有效终点;统一迁移不得改写主表或历史状态。
|
||||
SELECT 'PASS' AS migration_status,
|
||||
'统一增量全部执行完成;箱号映射、单箱测量、三期出仓、费用、公共资源及可靠审计结构校验通过' AS message;
|
||||
|
||||
@@ -868,6 +868,23 @@ DELIMITER $$
|
||||
CREATE PROCEDURE relocate_legacy_inbound_loading_permissions()
|
||||
BEGIN
|
||||
DECLARE legacy_count INT DEFAULT 0;
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM iam_permission
|
||||
WHERE id IN (5102091, 5102092, 5102093, 5102094, 5102096, 5102097, 5102098, 5102099)
|
||||
AND permission_code NOT IN (
|
||||
'platform:firstleg:container:view', 'platform:firstleg:container:create',
|
||||
'platform:firstleg:container:edit', 'platform:firstleg:smart-loading:list',
|
||||
'platform:firstleg:smart-loading:create', 'platform:firstleg:smart-loading:assign',
|
||||
'platform:firstleg:smart-loading:delete', 'platform:firstleg:smart-loading:push',
|
||||
'firstleg:inbound:split', 'firstleg:inbound:preload', 'firstleg:inbound:preload-view',
|
||||
'platform:firstleg:inbound:loading:edit', 'platform:firstleg:inbound:loading:view',
|
||||
'platform:firstleg:inbound:loading:complete', 'platform:firstleg:inbound:delivery:complete',
|
||||
'platform:firstleg:inbound:picking:edit', 'platform:firstleg:inbound:picking:view'
|
||||
)
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '三期权限迁移失败:5102091-5102099 存在未知权限占用';
|
||||
END IF;
|
||||
SELECT COUNT(*) INTO legacy_count
|
||||
FROM iam_permission
|
||||
WHERE tenant_id = 0 AND app_code = 'PLATFORM'
|
||||
|
||||
+37
@@ -158,6 +158,15 @@ class SmartLoadingSqlContractTest {
|
||||
.isEqualTo(1);
|
||||
assertThat(count(unified, "SELECT 'PASS' AS migration_status"))
|
||||
.isEqualTo(1);
|
||||
int relocation = unified.indexOf("CALL unified_relocate_inbound_loading_permissions();");
|
||||
int assertion = unified.indexOf("CALL assert_phase3_smart_loading_schema();");
|
||||
assertThat(relocation).isGreaterThan(0);
|
||||
assertThat(assertion).isGreaterThan(relocation);
|
||||
assertThat(unified.substring(relocation, assertion))
|
||||
.contains("tmp_phase3_inbound_role_grant")
|
||||
.contains("DROP TEMPORARY TABLE IF EXISTS tmp_phase3_inbound_role_grant")
|
||||
.contains("5102121, 0, 'PLATFORM'")
|
||||
.contains("5102129, 0, 'PLATFORM'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -180,6 +189,13 @@ class SmartLoadingSqlContractTest {
|
||||
.contains("KEY idx_loading_pick_status (tenant_id, status, updated_at)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("迁移拒绝缺列错类型和混合拣货表型")
|
||||
void shouldRejectMalformedLegacyPickTaskShapes() throws Exception {
|
||||
assertMalformedShapeGuards(migration());
|
||||
assertMalformedShapeGuards(unifiedMigration());
|
||||
}
|
||||
|
||||
private static String migration() throws Exception {
|
||||
return new ClassPathResource("db/phase3-smart-loading-schema.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
@@ -213,6 +229,27 @@ class SmartLoadingSqlContractTest {
|
||||
return matcher.results().map(result -> result.group(1)).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static void assertMalformedShapeGuards(String sql) {
|
||||
assertThat(sql)
|
||||
.containsAnyOf("source_total_columns = 11", "source_total = 11")
|
||||
.containsAnyOf("source_smart_columns = 11", "source_smart = 11")
|
||||
.containsAnyOf("source_total_columns = 12", "source_total = 12")
|
||||
.containsAnyOf("source_inbound_columns = 12", "source_inbound = 12")
|
||||
.contains("column_name = 'version'")
|
||||
.contains("column_name = 'remark'")
|
||||
.contains("column_name = 'updated_by'")
|
||||
.contains("column_name = 'updated_by_name'")
|
||||
.contains("column_name = 'created_at'")
|
||||
.contains("column_name = 'updated_at'")
|
||||
.contains("LOWER(column_type) = 'int'")
|
||||
.contains("LOWER(column_type) = 'int unsigned'")
|
||||
.contains("LOWER(extra) LIKE '%on update current_timestamp%'")
|
||||
.contains("uk_loading_pick_tenant_inbound")
|
||||
.contains("idx_loading_pick_status")
|
||||
.contains("referenced_table_name = 'fl_inbound_order'")
|
||||
.contains("字段签名未知或混合");
|
||||
}
|
||||
|
||||
private static int count(String value, String token) {
|
||||
return (value.length() - value.replace(token, "").length()) / token.length();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user