diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index e4c1ad467..7383de6ed 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -515,7 +515,7 @@ CREATE TABLE IF NOT EXISTS ord_order ( id BIGINT UNSIGNED NOT NULL COMMENT '订单ID(雪花ID)', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键', order_no VARCHAR(32) NOT NULL COMMENT '客户范围内唯一订单号', - inbound_code VARCHAR(40) NOT NULL COMMENT '订单创建时生成并固定的入仓码:物流前缀+YYMMDD+当天全平台票序', + inbound_code VARCHAR(40) NULL COMMENT '提交后生成并固定的入仓码;未提交草稿为空', customer_id BIGINT UNSIGNED NULL COMMENT '客户逻辑ID', customer_name VARCHAR(128) NOT NULL COMMENT '下单时客户名称快照', status VARCHAR(24) NOT NULL DEFAULT 'DRAFT' COMMENT '订单业务状态:DRAFT草稿、SUBMITTED已提交、APPROVED审核通过、ACCEPTED已接单、REJECTED审核驳回、PROCESSING履约中、COMPLETED已完成、CANCELLED已取消', @@ -562,6 +562,34 @@ CREATE TABLE IF NOT EXISTS ord_order ( KEY idx_order_tenant_warehouse (tenant_id, destination_warehouse_id) ) ENGINE=InnoDB COMMENT='头程订单主表:保存商户委托、目的仓、运输方式和订单当前状态'; +-- 既有开发库可能仍保留草稿入仓码 NOT NULL 约束;必须先放宽再清理草稿入仓码。 +SET @order_inbound_code_nullable_sql = IF( + EXISTS( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order' + AND column_name = 'inbound_code' AND is_nullable = 'NO' + ), + 'ALTER TABLE baiyue_order.ord_order MODIFY COLUMN inbound_code VARCHAR(40) NULL COMMENT ''提交后生成并固定的入仓码;未提交草稿为空''', + 'SELECT 1' +); +PREPARE order_inbound_code_nullable_stmt FROM @order_inbound_code_nullable_sql; +EXECUTE order_inbound_code_nullable_stmt; +DEALLOCATE PREPARE order_inbound_code_nullable_stmt; + +-- CREATE TABLE IF NOT EXISTS 不会给既有表补列,故显式幂等补齐预约提货时间。 +SET @order_requested_pickup_at_sql = IF( + EXISTS( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order' + AND column_name = 'requested_pickup_at' + ), + 'SELECT 1', + 'ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL COMMENT ''客户要求平台上门提货的预约时间'' AFTER pickup_method' +); +PREPARE order_requested_pickup_at_stmt FROM @order_requested_pickup_at_sql; +EXECUTE order_requested_pickup_at_stmt; +DEALLOCATE PREPARE order_requested_pickup_at_stmt; + CREATE TABLE IF NOT EXISTS ord_inbound_code_daily_sequence ( business_date DATE NOT NULL COMMENT '上海时区业务日期', current_value BIGINT UNSIGNED NOT NULL COMMENT '当天全平台已分配票数', diff --git a/order/src/main/resources/db/order.sql b/order/src/main/resources/db/order.sql index cbbe7ab69..463935f52 100644 --- a/order/src/main/resources/db/order.sql +++ b/order/src/main/resources/db/order.sql @@ -9,7 +9,7 @@ CREATE TABLE IF NOT EXISTS ord_order ( id BIGINT UNSIGNED NOT NULL COMMENT '订单ID(雪花ID)', tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键', order_no VARCHAR(32) NOT NULL COMMENT '客户范围内唯一订单号', - inbound_code VARCHAR(40) NOT NULL COMMENT '订单创建时生成并固定的入仓码:物流前缀+YYMMDD+当天全平台票序', + inbound_code VARCHAR(40) NULL COMMENT '提交后生成并固定的入仓码;未提交草稿为空', customer_id BIGINT UNSIGNED NULL COMMENT '客户逻辑ID', customer_name VARCHAR(128) NOT NULL COMMENT '下单时客户名称快照', status VARCHAR(24) NOT NULL DEFAULT 'DRAFT' COMMENT '订单业务状态:DRAFT草稿、SUBMITTED已提交、APPROVED审核通过、ACCEPTED已接单、REJECTED审核驳回、PROCESSING履约中、COMPLETED已完成、CANCELLED已取消', @@ -61,6 +61,33 @@ CREATE TABLE IF NOT EXISTS ord_order ( KEY idx_order_tenant_warehouse (tenant_id, destination_warehouse_id) ) ENGINE=InnoDB COMMENT='头程订单主表:保存商户委托、目的仓、运输方式和订单当前状态'; +-- Existing development databases may still have the former NOT NULL contract. +SET @order_inbound_code_nullable_sql = IF( + EXISTS( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order' + AND column_name = 'inbound_code' AND is_nullable = 'NO' + ), + 'ALTER TABLE baiyue_order.ord_order MODIFY COLUMN inbound_code VARCHAR(40) NULL COMMENT ''提交后生成并固定的入仓码;未提交草稿为空''', + 'SELECT 1' +); +PREPARE order_inbound_code_nullable_stmt FROM @order_inbound_code_nullable_sql; +EXECUTE order_inbound_code_nullable_stmt; +DEALLOCATE PREPARE order_inbound_code_nullable_stmt; + +SET @order_requested_pickup_at_sql = IF( + EXISTS( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'baiyue_order' AND table_name = 'ord_order' + AND column_name = 'requested_pickup_at' + ), + 'SELECT 1', + 'ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL COMMENT ''客户要求平台上门提货的预约时间'' AFTER pickup_method' +); +PREPARE order_requested_pickup_at_stmt FROM @order_requested_pickup_at_sql; +EXECUTE order_requested_pickup_at_stmt; +DEALLOCATE PREPARE order_requested_pickup_at_stmt; + CREATE TABLE IF NOT EXISTS ord_inbound_code_daily_sequence ( business_date DATE NOT NULL COMMENT '上海时区业务日期', current_value BIGINT UNSIGNED NOT NULL COMMENT '当天全平台已分配票数', diff --git a/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java b/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java new file mode 100644 index 000000000..3bd9b5e34 --- /dev/null +++ b/order/src/test/java/com/baiyue/order/repository/OrderPickupSqlContractTest.java @@ -0,0 +1,34 @@ +package com.baiyue.order.repository; + +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +class OrderPickupSqlContractTest { + @Test + void moduleSchemaSupportsDraftWithoutInboundCodeAndUpgradesExistingTablesIdempotently() throws Exception { + String sql = Files.readString(Path.of("src/main/resources/db/order.sql")); + assertThat(sql).contains( + "inbound_code VARCHAR(40) NULL", + "column_name = 'inbound_code' AND is_nullable = 'NO'", + "ALTER TABLE baiyue_order.ord_order MODIFY COLUMN inbound_code VARCHAR(40) NULL", + "column_name = 'requested_pickup_at'", + "ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL"); + } + + @Test + void unifiedScriptRelaxesInboundCodeBeforeClearingDraftsAndAddsPickupColumn() throws Exception { + Path direct = Path.of("deploy/sql/头程数据库统一增量-MySQL8.sql"); + Path path = Files.exists(direct) ? direct : Path.of("../deploy/sql/头程数据库统一增量-MySQL8.sql"); + String sql = Files.readString(path); + int relax = sql.indexOf("ALTER TABLE baiyue_order.ord_order MODIFY COLUMN inbound_code VARCHAR(40) NULL"); + int clearDraft = sql.indexOf("SET inbound_code = NULL"); + assertThat(relax).isGreaterThanOrEqualTo(0).isLessThan(clearDraft); + assertThat(sql).contains( + "column_name = 'requested_pickup_at'", + "ALTER TABLE baiyue_order.ord_order ADD COLUMN requested_pickup_at DATETIME(3) NULL"); + } +}