diff --git a/deploy/sql/海外区域统一增量-MySQL8.sql b/deploy/sql/海外区域统一增量-MySQL8.sql index a64450395..afb0c1055 100644 --- a/deploy/sql/海外区域统一增量-MySQL8.sql +++ b/deploy/sql/海外区域统一增量-MySQL8.sql @@ -95,7 +95,8 @@ CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order ( status VARCHAR(32) NOT NULL DEFAULT 'PENDING_REVIEW' COMMENT '业务状态', remark VARCHAR(1000) NULL COMMENT '备注', idempotency_key VARCHAR(255) NOT NULL COMMENT '业务幂等键', request_hash CHAR(64) NOT NULL COMMENT '请求内容哈希', created_by VARCHAR(128) NULL COMMENT '创建人ID', reviewed_by VARCHAR(128) NULL COMMENT '审核人ID', - review_remark VARCHAR(1000) NULL COMMENT '审核备注', reviewed_at DATETIME(3) NULL COMMENT '审核时间', + review_remark VARCHAR(1000) NULL COMMENT '审核备注', review_idempotency_key VARCHAR(255) NULL COMMENT '审核幂等键', + review_request_hash CHAR(64) NULL COMMENT '审核请求内容哈希', reviewed_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_overseas_procurement_order_no(customer_id,order_no), @@ -104,15 +105,32 @@ CREATE TABLE IF NOT EXISTS ll_overseas_procurement_order ( KEY idx_ll_overseas_procurement_warehouse(customer_id,purchase_warehouse_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_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' +), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_request_hash CHAR(64) NULL COMMENT ''审核请求内容哈希'' AFTER review_idempotency_key')); +PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; + CREATE TABLE IF NOT EXISTS ll_overseas_procurement_status_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、REVIEW或UPDATE', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', - change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '备注', + idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_overseas_procurement_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_overseas_procurement_status_history' AND column_name='idempotency_key' +), 'SELECT 1', 'ALTER TABLE ll_overseas_procurement_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id')); +PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; + CREATE TABLE IF NOT EXISTS ll_us_truck_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', order_no VARCHAR(64) NOT NULL COMMENT '订单号', transport_type VARCHAR(32) NOT NULL COMMENT '运输类型', origin VARCHAR(255) NOT NULL COMMENT '起运地', origin_address VARCHAR(500) NULL COMMENT '起运地址', @@ -146,11 +164,32 @@ CREATE TABLE IF NOT EXISTS ll_us_truck_order_pallet ( CREATE TABLE IF NOT EXISTS ll_us_truck_order_status_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', - from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', + operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', from_status VARCHAR(32) NULL COMMENT '变更前状态', + to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', + idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', remark VARCHAR(1000) NULL COMMENT '备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_us_truck_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_us_truck_order_status_history' AND column_name='operation_type'), 'SELECT 1', + 'ALTER TABLE ll_us_truck_order_status_history ADD COLUMN operation_type VARCHAR(64) NOT NULL DEFAULT ''UPDATE'' COMMENT ''具名操作类型'' AFTER customer_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_us_truck_order_status_history' AND column_name='idempotency_key'), 'SELECT 1', + 'ALTER TABLE ll_us_truck_order_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id')); +PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +CREATE TABLE IF NOT EXISTS ll_us_truck_order_operation ( + id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '美国卡车订单ID', + customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(64) NOT NULL COMMENT '具名操作类型', + idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希', + result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), + UNIQUE KEY uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key), + KEY idx_ll_us_truck_operation_order(customer_id,order_id,created_at) +) ENGINE=InnoDB COMMENT='美国卡车订单幂等操作账'; + CREATE TABLE IF NOT EXISTS ll_local_looseboard_order ( id BIGINT NOT NULL COMMENT '主键ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', lastleg_order_id BIGINT NULL COMMENT '关联尾程主订单ID', order_no VARCHAR(64) NOT NULL COMMENT '本土散板订单号', transport_mode VARCHAR(32) NOT NULL COMMENT '运输方式:拼车或优先拼载', pallet_required VARCHAR(8) NOT NULL COMMENT '是否需要打盘:YES或NO', @@ -182,11 +221,26 @@ CREATE TABLE IF NOT EXISTS ll_local_looseboard_history ( id BIGINT NOT NULL COMMENT '主键ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型:CREATE、UPDATE或STATUS', from_status VARCHAR(32) NULL COMMENT '变更前状态', to_status VARCHAR(32) NOT NULL COMMENT '变更后状态', operator_id VARCHAR(128) NULL COMMENT '操作人ID', - change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '操作备注', + idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键', change_detail JSON NULL COMMENT '字段变更前后值JSON', remark VARCHAR(1000) NULL COMMENT '操作备注', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), KEY idx_ll_local_looseboard_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_local_looseboard_history' AND column_name='idempotency_key'), 'SELECT 1', + 'ALTER TABLE ll_local_looseboard_history ADD COLUMN idempotency_key VARCHAR(255) NULL COMMENT ''操作幂等键'' AFTER operator_id')); +PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; + +CREATE TABLE IF NOT EXISTS ll_local_looseboard_operation ( + id BIGINT NOT NULL COMMENT '操作记录ID', order_id BIGINT NOT NULL COMMENT '本土散板订单ID', + customer_id VARCHAR(128) NOT NULL COMMENT '客户租户ID', operation_type VARCHAR(32) NOT NULL COMMENT '操作类型', + idempotency_key VARCHAR(255) NOT NULL COMMENT '操作幂等键', request_hash CHAR(64) NOT NULL COMMENT '操作请求内容哈希', + result_version BIGINT NOT NULL COMMENT '操作完成后的订单版本', created_by VARCHAR(128) NULL COMMENT '操作人ID', + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间', PRIMARY KEY(id), + UNIQUE KEY uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key), + KEY idx_ll_local_looseboard_operation_order(customer_id,order_id,created_at) +) ENGINE=InnoDB COMMENT='本土散板订单幂等操作账'; + -- 尾程主订单状态历史补齐客户隔离键。代码写入 customer_id,已有表需显式升级; -- 先允许 NULL 以便从主订单回填,再收紧为 NOT NULL,脚本可重复执行。 SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/looseboard/LocalLooseboardSchemaContractTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/looseboard/LocalLooseboardSchemaContractTest.java index b67cd7f22..90f0a93c5 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/looseboard/LocalLooseboardSchemaContractTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/looseboard/LocalLooseboardSchemaContractTest.java @@ -2,6 +2,8 @@ package com.baiyue.lastleg.looseboard; import org.junit.jupiter.api.Test; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -24,4 +26,13 @@ class LocalLooseboardSchemaContractTest { assertTrue(sql.contains("customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键'")); assertTrue(sql.contains("idx_ll_loading_history_customer_order(customer_id,order_id,created_at)")); } + + @Test + void unifiedIncrementalContainsHistoryIdempotencyAndOperationLedger() throws Exception { + String sql = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"), + StandardCharsets.UTF_8); + assertTrue(sql.contains("CREATE TABLE IF NOT EXISTS ll_local_looseboard_operation")); + assertTrue(sql.contains("uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key)")); + assertTrue(sql.contains("table_name='ll_local_looseboard_history' AND column_name='idempotency_key'")); + } } diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/procurement/OverseasProcurementSchemaContractTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/procurement/OverseasProcurementSchemaContractTest.java index a90369d8f..b6c1159a0 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/procurement/OverseasProcurementSchemaContractTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/procurement/OverseasProcurementSchemaContractTest.java @@ -2,6 +2,8 @@ package com.baiyue.lastleg.procurement; import org.junit.jupiter.api.Test; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -23,4 +25,21 @@ class OverseasProcurementSchemaContractTest { org.junit.jupiter.api.Assertions.assertFalse(sql.contains("CREATE TABLE IF NOT EXISTS ll_overseas_procurement_outbound")); org.junit.jupiter.api.Assertions.assertFalse(sql.contains("outbound_quantity BIGINT")); } + + @Test + void unifiedIncrementalContainsHistoryIdempotencyKeyForNewAndExistingDatabases() throws Exception { + String sql = Files.readString( + Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"), + StandardCharsets.UTF_8); + + assertTrue(sql.contains("idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键'")); + assertTrue(sql.contains( + "ALTER TABLE ll_overseas_procurement_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL")); + assertTrue(sql.contains( + "ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_idempotency_key VARCHAR(255) NULL")); + assertTrue(sql.contains( + "ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_request_hash CHAR(64) NULL")); + assertTrue(sql.contains( + "table_name='ll_overseas_procurement_status_history' AND column_name='idempotency_key'")); + } } diff --git a/lastleg-service/src/test/java/com/baiyue/lastleg/trucking/UsTruckOrderSchemaContractTest.java b/lastleg-service/src/test/java/com/baiyue/lastleg/trucking/UsTruckOrderSchemaContractTest.java index 8dd0a31d7..a3bc9d3d8 100644 --- a/lastleg-service/src/test/java/com/baiyue/lastleg/trucking/UsTruckOrderSchemaContractTest.java +++ b/lastleg-service/src/test/java/com/baiyue/lastleg/trucking/UsTruckOrderSchemaContractTest.java @@ -2,6 +2,8 @@ package com.baiyue.lastleg.trucking; import org.junit.jupiter.api.Test; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -26,4 +28,14 @@ class UsTruckOrderSchemaContractTest { assertTrue(sql.contains("UNIQUE KEY uk_ll_us_truck_order_key(customer_id,idempotency_key)")); assertTrue(sql.contains("KEY idx_ll_us_truck_history(customer_id,order_id,created_at)")); } + + @Test + void unifiedIncrementalContainsOperationLedgerAndHistoryColumns() throws Exception { + String sql = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"), + StandardCharsets.UTF_8); + assertTrue(sql.contains("CREATE TABLE IF NOT EXISTS ll_us_truck_order_operation")); + assertTrue(sql.contains("uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key)")); + assertTrue(sql.contains("table_name='ll_us_truck_order_status_history' AND column_name='operation_type'")); + assertTrue(sql.contains("table_name='ll_us_truck_order_status_history' AND column_name='idempotency_key'")); + } }