From 34fb91baf69b17c77ef4e08487b3982d10172f7e Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 20 Aug 2026 19:10:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/sql/头程数据库统一增量-MySQL8.sql | 79 +++++++++++++++++++ .../db/fee-source-event-migration.sql | 32 ++++++++ ...FinanceFeeSourceMigrationContractTest.java | 2 + .../FinanceSqlCommentContractTest.java | 2 +- 4 files changed, 114 insertions(+), 1 deletion(-) diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index bd9433200..8220b788a 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -11435,9 +11435,76 @@ CALL finance_fee_source_add_column('fin_inbox_event', 'result_resource_id', "BIGINT UNSIGNED NULL COMMENT '成功处理生成或定位的费用来源快照ID' AFTER payload_hash"); CALL finance_fee_source_add_column('fin_inbox_event', 'error_code', "VARCHAR(64) NULL COMMENT '处理失败时的稳定FIN错误码' AFTER result_resource_id"); +CALL finance_fee_source_add_column('fin_cost', 'cost_origin', + "VARCHAR(24) NOT NULL DEFAULT 'MANUAL' COMMENT '成本来源:MANUAL人工补充、FIRSTLEG_DIRECT_PAID头程直接已付' AFTER cost_type"); +CALL finance_fee_source_add_column('fin_cost', 'source_system', + "VARCHAR(32) NULL COMMENT '来源系统,头程直接已付固定FIRSTLEG' AFTER cost_origin"); +CALL finance_fee_source_add_column('fin_cost', 'source_type', + "VARCHAR(32) NULL COMMENT '来源费用类型快照' AFTER source_system"); +CALL finance_fee_source_add_column('fin_cost', 'source_fee_id', + "BIGINT UNSIGNED NULL COMMENT '来源费用ID' AFTER source_type"); +CALL finance_fee_source_add_column('fin_cost', 'source_fee_version', + "INT UNSIGNED NULL COMMENT '来源费用版本' AFTER source_fee_id"); +CALL finance_fee_source_add_column('fin_cost', 'source_hash', + "CHAR(64) NULL COMMENT '来源不可变快照SHA-256' AFTER source_fee_version"); +CALL finance_fee_source_add_column('fin_cost', 'paid_at', + "DATETIME(3) NULL COMMENT '直接已付时间' AFTER voucher_file_ids"); +CALL finance_fee_source_add_column('fin_cost', 'payment_method', + "VARCHAR(32) NULL COMMENT '直接已付方式' AFTER paid_at"); +CALL finance_fee_source_add_column('fin_cost', 'payment_reference_no', + "VARCHAR(128) NULL COMMENT '直接已付流水号' AFTER payment_method"); DROP PROCEDURE IF EXISTS finance_fee_source_add_column; +DROP PROCEDURE IF EXISTS finance_fee_source_add_index; +DELIMITER $$ +CREATE PROCEDURE finance_fee_source_add_index() +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.statistics + WHERE table_schema=DATABASE() AND table_name='fin_cost' + AND index_name='uk_fin_cost_source_version' + ) THEN + ALTER TABLE fin_cost ADD UNIQUE KEY uk_fin_cost_source_version + (source_system, source_type, source_fee_id, source_fee_version); + END IF; +END$$ +DELIMITER ; +CALL finance_fee_source_add_index(); +DROP PROCEDURE IF EXISTS finance_fee_source_add_index; + +ALTER TABLE fin_cost + MODIFY COLUMN cost_type VARCHAR(24) NOT NULL COMMENT '成本归属类型:SINGLE_ORDER单票、CONTAINER_SHARED整柜公共、SOURCE_DIRECT_PAID来源直接已付'; +DROP PROCEDURE IF EXISTS finance_fee_source_replace_cost_checks; +DELIMITER $$ +CREATE PROCEDURE finance_fee_source_replace_cost_checks() +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.table_constraints + WHERE constraint_schema=DATABASE() AND table_name='fin_cost' AND constraint_name='chk_fin_cost_target') THEN + ALTER TABLE fin_cost DROP CHECK chk_fin_cost_target; + END IF; + IF EXISTS (SELECT 1 FROM information_schema.table_constraints + WHERE constraint_schema=DATABASE() AND table_name='fin_cost' AND constraint_name='chk_fin_cost_origin') THEN + ALTER TABLE fin_cost DROP CHECK chk_fin_cost_origin; + END IF; + ALTER TABLE fin_cost + ADD CONSTRAINT chk_fin_cost_target CHECK ( + (cost_type='SINGLE_ORDER' AND order_id IS NOT NULL AND container_id IS NULL) + OR (cost_type='CONTAINER_SHARED' AND container_id IS NOT NULL) + OR (cost_type='SOURCE_DIRECT_PAID' AND (order_id IS NOT NULL OR inbound_id IS NOT NULL OR container_id IS NOT NULL)) + ), + ADD CONSTRAINT chk_fin_cost_origin CHECK ( + (cost_origin='MANUAL' AND source_system IS NULL AND source_type IS NULL AND source_fee_id IS NULL AND source_fee_version IS NULL AND source_hash IS NULL) + OR (cost_origin='FIRSTLEG_DIRECT_PAID' AND source_system='FIRSTLEG' AND source_type IS NOT NULL + AND source_fee_id IS NOT NULL AND source_fee_version IS NOT NULL AND source_hash IS NOT NULL + AND status IN ('CONFIRMED','VOIDED') AND paid_at IS NOT NULL + AND payment_method IN ('ONLINE','BANK_TRANSFER','CASH','OTHER')) + ); +END$$ +DELIMITER ; +CALL finance_fee_source_replace_cost_checks(); +DROP PROCEDURE IF EXISTS finance_fee_source_replace_cost_checks; + -- 产品确认无历史财务数据;以下兼容值仅用于空环境重复迁移时保证结构收敛。 UPDATE fin_fee_source SET source_type = COALESCE(source_type, 'INBOUND_FEE'), @@ -11486,6 +11553,18 @@ BEGIN 'customer_confirmed_by_name','customer_confirmed_at')) <> 4 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Finance客户对账单确认字段不完整'; END IF; + IF (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema = DATABASE() AND table_name = 'fin_cost' + AND column_name IN ('cost_origin','source_system','source_type','source_fee_id', + 'source_fee_version','source_hash','paid_at','payment_method', + 'payment_reference_no')) <> 9 THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Finance直接已付成本字段不完整'; + END IF; + IF (SELECT COUNT(*) FROM information_schema.statistics + WHERE table_schema=DATABASE() AND table_name='fin_cost' + AND index_name='uk_fin_cost_source_version') <> 4 THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Finance直接已付成本唯一索引不完整'; + END IF; END$$ DELIMITER ; CALL finance_fee_source_assert_schema(); diff --git a/finance/src/main/resources/db/fee-source-event-migration.sql b/finance/src/main/resources/db/fee-source-event-migration.sql index b74ba03bd..d922551f8 100644 --- a/finance/src/main/resources/db/fee-source-event-migration.sql +++ b/finance/src/main/resources/db/fee-source-event-migration.sql @@ -103,6 +103,38 @@ DELIMITER ; CALL finance_fee_source_add_index(); DROP PROCEDURE IF EXISTS finance_fee_source_add_index; +ALTER TABLE fin_cost + MODIFY COLUMN cost_type VARCHAR(24) NOT NULL COMMENT '成本归属类型:SINGLE_ORDER单票、CONTAINER_SHARED整柜公共、SOURCE_DIRECT_PAID来源直接已付'; +DROP PROCEDURE IF EXISTS finance_fee_source_replace_cost_checks; +DELIMITER $$ +CREATE PROCEDURE finance_fee_source_replace_cost_checks() +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.table_constraints + WHERE constraint_schema=DATABASE() AND table_name='fin_cost' AND constraint_name='chk_fin_cost_target') THEN + ALTER TABLE fin_cost DROP CHECK chk_fin_cost_target; + END IF; + IF EXISTS (SELECT 1 FROM information_schema.table_constraints + WHERE constraint_schema=DATABASE() AND table_name='fin_cost' AND constraint_name='chk_fin_cost_origin') THEN + ALTER TABLE fin_cost DROP CHECK chk_fin_cost_origin; + END IF; + ALTER TABLE fin_cost + ADD CONSTRAINT chk_fin_cost_target CHECK ( + (cost_type='SINGLE_ORDER' AND order_id IS NOT NULL AND container_id IS NULL) + OR (cost_type='CONTAINER_SHARED' AND container_id IS NOT NULL) + OR (cost_type='SOURCE_DIRECT_PAID' AND (order_id IS NOT NULL OR inbound_id IS NOT NULL OR container_id IS NOT NULL)) + ), + ADD CONSTRAINT chk_fin_cost_origin CHECK ( + (cost_origin='MANUAL' AND source_system IS NULL AND source_type IS NULL AND source_fee_id IS NULL AND source_fee_version IS NULL AND source_hash IS NULL) + OR (cost_origin='FIRSTLEG_DIRECT_PAID' AND source_system='FIRSTLEG' AND source_type IS NOT NULL + AND source_fee_id IS NOT NULL AND source_fee_version IS NOT NULL AND source_hash IS NOT NULL + AND status IN ('CONFIRMED','VOIDED') AND paid_at IS NOT NULL + AND payment_method IN ('ONLINE','BANK_TRANSFER','CASH','OTHER')) + ); +END$$ +DELIMITER ; +CALL finance_fee_source_replace_cost_checks(); +DROP PROCEDURE IF EXISTS finance_fee_source_replace_cost_checks; + -- 产品确认无历史财务数据;以下兼容值仅用于空环境重复迁移时保证结构收敛。 UPDATE fin_fee_source SET source_type = COALESCE(source_type, 'INBOUND_FEE'), diff --git a/finance/src/test/java/com/baiyue/finance/FinanceFeeSourceMigrationContractTest.java b/finance/src/test/java/com/baiyue/finance/FinanceFeeSourceMigrationContractTest.java index 7761efb5c..8329eae7d 100644 --- a/finance/src/test/java/com/baiyue/finance/FinanceFeeSourceMigrationContractTest.java +++ b/finance/src/test/java/com/baiyue/finance/FinanceFeeSourceMigrationContractTest.java @@ -16,6 +16,8 @@ class FinanceFeeSourceMigrationContractTest { "source_hash", "source_snapshot", "payload_hash", "result_resource_id", "error_code"); assertThat(sql).contains("settlement_mode", "paid_at", "payment_method", "payment_reference_no", "payment_voucher_file_ids"); + assertThat(sql).contains("cost_origin", "FIRSTLEG_DIRECT_PAID", "source_fee_version", + "uk_fin_cost_source_version", "Finance直接已付成本字段不完整"); assertThat(sql).contains("AVAILABLE可结算", "SUPERSEDED已被新版本替代", "VOIDED已作废"); assertThat(sql).contains("finance_fee_source_assert_schema"); } diff --git a/finance/src/test/java/com/baiyue/finance/FinanceSqlCommentContractTest.java b/finance/src/test/java/com/baiyue/finance/FinanceSqlCommentContractTest.java index d51cf099d..38b19749b 100644 --- a/finance/src/test/java/com/baiyue/finance/FinanceSqlCommentContractTest.java +++ b/finance/src/test/java/com/baiyue/finance/FinanceSqlCommentContractTest.java @@ -44,7 +44,7 @@ class FinanceSqlCommentContractTest { } } assertThat(tableCount).isEqualTo(17); - assertThat(columnCount).isEqualTo(248); + assertThat(columnCount).isEqualTo(257); assertThat(missing).as("缺少中文业务注释的Finance字段").isEmpty(); }