test(firstleg): cover phase3 container loading flow
This commit is contained in:
@@ -314,7 +314,7 @@ public class SmartLoadingService {
|
||||
|| !Objects.equals(history.getActionType(), action)
|
||||
|| itemId != null && !Objects.equals(history.getLoadingPlanItemId(), itemId)
|
||||
|| history.getAfterSnapshot() == null
|
||||
|| !history.getAfterSnapshot().contains("\"requestHash\":\"" + requestHash + "\"")) {
|
||||
|| !sameRequestHash(history.getAfterSnapshot(), requestHash)) {
|
||||
throw conflict("operationId 已用于不同请求");
|
||||
}
|
||||
LoadingPlanEntity plan = repository.plan(planId);
|
||||
@@ -322,6 +322,15 @@ public class SmartLoadingService {
|
||||
return view(plan, requireBooking(plan.getContainerBookingId()));
|
||||
}
|
||||
|
||||
private boolean sameRequestHash(String snapshot, String requestHash) {
|
||||
try {
|
||||
var value = objectMapper.readTree(snapshot);
|
||||
return value != null && requestHash.equals(value.path("requestHash").asText());
|
||||
} catch (JsonProcessingException exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void history(long planId, Long itemId, String action, String from, String to,
|
||||
String operation, long operatorId, String operatorName) {
|
||||
history(planId, itemId, action, from, to, operation, null, null, operatorId, operatorName);
|
||||
|
||||
@@ -461,6 +461,92 @@ 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拣货幂等和操作审计历史';
|
||||
|
||||
DROP PROCEDURE IF EXISTS repair_phase3_loading_pick_task_foreign_keys;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE repair_phase3_loading_pick_task_foreign_keys()
|
||||
BEGIN
|
||||
DECLARE item_fk_count INT DEFAULT 0;
|
||||
DECLARE item_target_count INT DEFAULT 0;
|
||||
DECLARE history_fk_count INT DEFAULT 0;
|
||||
DECLARE history_target_count INT DEFAULT 0;
|
||||
DECLARE item_drop_clauses TEXT;
|
||||
DECLARE history_drop_clauses TEXT;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM fl_loading_pick_item item
|
||||
LEFT JOIN fl_loading_pick_task task ON task.id = item.pick_task_id
|
||||
WHERE task.id IS NULL
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '柜次PDA明细存在无法迁移到智能装柜任务的引用';
|
||||
END IF;
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM fl_loading_pick_history history
|
||||
LEFT JOIN fl_loading_pick_task task ON task.id = history.pick_task_id
|
||||
WHERE task.id IS NULL
|
||||
) THEN
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = '柜次PDA历史存在无法迁移到智能装柜任务的引用';
|
||||
END IF;
|
||||
|
||||
SELECT COUNT(*),
|
||||
SUM(k.referenced_table_name = 'fl_loading_pick_task'
|
||||
AND k.referenced_column_name = 'id'
|
||||
AND (SELECT COUNT(*) FROM information_schema.key_column_usage peer
|
||||
WHERE peer.constraint_schema = k.constraint_schema
|
||||
AND peer.table_name = k.table_name
|
||||
AND peer.constraint_name = k.constraint_name) = 1),
|
||||
GROUP_CONCAT(CONCAT('DROP FOREIGN KEY `', REPLACE(k.constraint_name, '`', '``'), '`')
|
||||
ORDER BY k.constraint_name SEPARATOR ', ')
|
||||
INTO item_fk_count, item_target_count, item_drop_clauses
|
||||
FROM information_schema.key_column_usage k
|
||||
WHERE k.constraint_schema = 'baiyue_firstleg'
|
||||
AND k.table_name = 'fl_loading_pick_item'
|
||||
AND k.column_name = 'pick_task_id'
|
||||
AND k.referenced_table_name IS NOT NULL;
|
||||
IF item_fk_count <> 1 OR item_target_count <> 1 THEN
|
||||
IF item_drop_clauses IS NOT NULL THEN
|
||||
SET @phase3_fk_ddl = CONCAT('ALTER TABLE fl_loading_pick_item ', item_drop_clauses);
|
||||
PREPARE phase3_fk_statement FROM @phase3_fk_ddl;
|
||||
EXECUTE phase3_fk_statement;
|
||||
DEALLOCATE PREPARE phase3_fk_statement;
|
||||
END IF;
|
||||
ALTER TABLE fl_loading_pick_item
|
||||
ADD CONSTRAINT fk_loading_pick_item_task
|
||||
FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id);
|
||||
END IF;
|
||||
|
||||
SELECT COUNT(*),
|
||||
SUM(k.referenced_table_name = 'fl_loading_pick_task'
|
||||
AND k.referenced_column_name = 'id'
|
||||
AND (SELECT COUNT(*) FROM information_schema.key_column_usage peer
|
||||
WHERE peer.constraint_schema = k.constraint_schema
|
||||
AND peer.table_name = k.table_name
|
||||
AND peer.constraint_name = k.constraint_name) = 1),
|
||||
GROUP_CONCAT(CONCAT('DROP FOREIGN KEY `', REPLACE(k.constraint_name, '`', '``'), '`')
|
||||
ORDER BY k.constraint_name SEPARATOR ', ')
|
||||
INTO history_fk_count, history_target_count, history_drop_clauses
|
||||
FROM information_schema.key_column_usage k
|
||||
WHERE k.constraint_schema = 'baiyue_firstleg'
|
||||
AND k.table_name = 'fl_loading_pick_history'
|
||||
AND k.column_name = 'pick_task_id'
|
||||
AND k.referenced_table_name IS NOT NULL;
|
||||
IF history_fk_count <> 1 OR history_target_count <> 1 THEN
|
||||
IF history_drop_clauses IS NOT NULL THEN
|
||||
SET @phase3_fk_ddl = CONCAT('ALTER TABLE fl_loading_pick_history ', history_drop_clauses);
|
||||
PREPARE phase3_fk_statement FROM @phase3_fk_ddl;
|
||||
EXECUTE phase3_fk_statement;
|
||||
DEALLOCATE PREPARE phase3_fk_statement;
|
||||
END IF;
|
||||
ALTER TABLE fl_loading_pick_history
|
||||
ADD CONSTRAINT fk_loading_pick_history_task
|
||||
FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL repair_phase3_loading_pick_task_foreign_keys();
|
||||
DROP PROCEDURE repair_phase3_loading_pick_task_foreign_keys;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_container_booking_before_update;
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER trg_container_booking_before_update
|
||||
@@ -1091,6 +1177,40 @@ BEGIN
|
||||
'uk_loading_pick_history_operation')) <> 3 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:PDA唯一索引缺失';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.key_column_usage
|
||||
WHERE constraint_schema = 'baiyue_firstleg'
|
||||
AND table_name = 'fl_loading_pick_item'
|
||||
AND column_name = 'pick_task_id'
|
||||
AND referenced_table_name IS NOT NULL) <> 1
|
||||
OR (SELECT COUNT(*) FROM information_schema.key_column_usage outer_fk
|
||||
WHERE outer_fk.constraint_schema = 'baiyue_firstleg'
|
||||
AND outer_fk.table_name = 'fl_loading_pick_item'
|
||||
AND outer_fk.column_name = 'pick_task_id'
|
||||
AND outer_fk.referenced_table_name = 'fl_loading_pick_task'
|
||||
AND outer_fk.referenced_column_name = 'id'
|
||||
AND (SELECT COUNT(*) FROM information_schema.key_column_usage peer
|
||||
WHERE peer.constraint_schema = outer_fk.constraint_schema
|
||||
AND peer.table_name = outer_fk.table_name
|
||||
AND peer.constraint_name = outer_fk.constraint_name) = 1) <> 1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:柜次PDA明细任务外键不唯一或指向错误';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.key_column_usage
|
||||
WHERE constraint_schema = 'baiyue_firstleg'
|
||||
AND table_name = 'fl_loading_pick_history'
|
||||
AND column_name = 'pick_task_id'
|
||||
AND referenced_table_name IS NOT NULL) <> 1
|
||||
OR (SELECT COUNT(*) FROM information_schema.key_column_usage outer_fk
|
||||
WHERE outer_fk.constraint_schema = 'baiyue_firstleg'
|
||||
AND outer_fk.table_name = 'fl_loading_pick_history'
|
||||
AND outer_fk.column_name = 'pick_task_id'
|
||||
AND outer_fk.referenced_table_name = 'fl_loading_pick_task'
|
||||
AND outer_fk.referenced_column_name = 'id'
|
||||
AND (SELECT COUNT(*) FROM information_schema.key_column_usage peer
|
||||
WHERE peer.constraint_schema = outer_fk.constraint_schema
|
||||
AND peer.table_name = outer_fk.table_name
|
||||
AND peer.constraint_name = outer_fk.constraint_name) = 1) <> 1 THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '智能装柜迁移失败:柜次PDA历史任务外键不唯一或指向错误';
|
||||
END IF;
|
||||
IF (SELECT COUNT(*) FROM information_schema.triggers
|
||||
WHERE trigger_schema = 'baiyue_firstleg'
|
||||
AND trigger_name IN ('trg_container_booking_before_update',
|
||||
|
||||
+12
-1
@@ -144,6 +144,16 @@ class SmartLoadingSqlContractTest {
|
||||
.contains("UNIQUE KEY uk_loading_pick_history_operation (operation_id)")
|
||||
.contains("上层拆分按业务规则向上取整")
|
||||
.contains("CONSTRAINT chk_loading_pick_item_planned CHECK (planned_package_count > 0)")
|
||||
.contains("CALL repair_phase3_loading_pick_task_foreign_keys()")
|
||||
.contains("GROUP_CONCAT(CONCAT('DROP FOREIGN KEY `'")
|
||||
.contains("item_fk_count <> 1 OR item_target_count <> 1")
|
||||
.contains("history_fk_count <> 1 OR history_target_count <> 1")
|
||||
.contains("FOREIGN KEY (pick_task_id) REFERENCES fl_loading_pick_task (id)")
|
||||
.contains("referenced_column_name = 'id'")
|
||||
.contains("柜次PDA明细任务外键不唯一或指向错误")
|
||||
.contains("柜次PDA历史任务外键不唯一或指向错误")
|
||||
.doesNotContain("DROP FOREIGN KEY fk_loading_pick_item_task")
|
||||
.doesNotContain("DROP FOREIGN KEY fk_loading_pick_history_task")
|
||||
.contains("trg_loading_pick_task_before_update")
|
||||
.contains("trg_loading_pick_item_before_update")
|
||||
.contains("trg_loading_pick_item_before_delete")
|
||||
@@ -171,7 +181,8 @@ class SmartLoadingSqlContractTest {
|
||||
.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'");
|
||||
.contains("5102129, 0, 'PLATFORM'")
|
||||
.contains("role.role_code IN ('PLATFORM_ADMIN', 'ORDER_OPERATOR')");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -311,7 +311,8 @@ class SmartLoadingServiceTest {
|
||||
value.setLoadingPlanId(planId);
|
||||
value.setLoadingPlanItemId(itemId);
|
||||
value.setActionType(action);
|
||||
value.setAfterSnapshot("{\"requestHash\":\"" + hash + "\"}");
|
||||
// MySQL JSON columns normalize a space after the colon; replay must parse structurally.
|
||||
value.setAfterSnapshot("{\"requestHash\": \"" + hash + "\"}");
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user