202 lines
13 KiB
SQL
202 lines
13 KiB
SQL
-- Firstleg费用来源事件消费模型存量升级(MySQL 8,可重复执行)
|
||
USE baiyue_finance;
|
||
|
||
DROP PROCEDURE IF EXISTS finance_fee_source_add_column;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE finance_fee_source_add_column(
|
||
IN target_table VARCHAR(64), IN target_column VARCHAR(64), IN column_definition TEXT
|
||
)
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = target_table AND column_name = target_column
|
||
) THEN
|
||
SET @ddl = CONCAT('ALTER TABLE `', target_table, '` ADD COLUMN `', target_column, '` ', column_definition);
|
||
PREPARE statement FROM @ddl;
|
||
EXECUTE statement;
|
||
DEALLOCATE PREPARE statement;
|
||
END IF;
|
||
END$$
|
||
DELIMITER ;
|
||
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'source_type',
|
||
"VARCHAR(32) NULL COMMENT '来源费用类型:INBOUND_FEE入库单费用、CONTAINER_FEE柜子费用' AFTER customer_id");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'source_no',
|
||
"VARCHAR(64) NULL COMMENT '来源入库单号或柜号快照,可为空' AFTER source_type");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'direction',
|
||
"VARCHAR(16) NULL COMMENT '费用方向:RECEIVABLE应收、PAYABLE应付' AFTER source_no");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'container_id',
|
||
"BIGINT UNSIGNED NULL COMMENT '来源Firstleg装柜计划ID,可为空' AFTER inbound_id");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'fee_item_code',
|
||
"VARCHAR(64) NULL COMMENT '来源费用项目编码快照' AFTER container_id");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'source_hash',
|
||
"CHAR(64) NULL COMMENT 'Firstleg费用来源完整快照SHA-256哈希' AFTER currency_code");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'settlement_mode',
|
||
"VARCHAR(16) NULL COMMENT '仅PAYABLE:ON_ACCOUNT账期应付、DIRECT_PAID业务已付;RECEIVABLE为空' AFTER currency_code");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'paid_at',
|
||
"DATETIME(3) NULL COMMENT 'DIRECT_PAID业务已付时间' AFTER settlement_mode");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'payment_method',
|
||
"VARCHAR(32) NULL COMMENT 'DIRECT_PAID付款方式' AFTER paid_at");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'payment_reference_no',
|
||
"VARCHAR(128) NULL COMMENT 'DIRECT_PAID付款流水号' AFTER payment_method");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'payment_voucher_file_ids',
|
||
"JSON NULL COMMENT 'DIRECT_PAID付款凭证File ID数组' AFTER payment_reference_no");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'source_snapshot',
|
||
"JSON NULL COMMENT 'Firstleg费用来源完整不可变JSON快照' AFTER source_hash");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'review_status',
|
||
"VARCHAR(16) NOT NULL DEFAULT 'DRAFT' COMMENT 'Finance费用状态:DRAFT草稿、PENDING待审核、APPROVED已通过、REJECTED已驳回' AFTER source_snapshot");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'review_reason',
|
||
"VARCHAR(500) NULL COMMENT 'Finance费用审核说明或驳回原因' AFTER review_status");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'operation_version',
|
||
"INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '费用编辑、提交、审核、调整和作废操作版本号' AFTER review_reason");
|
||
CALL finance_fee_source_add_column('fin_fee_source', 'updated_at',
|
||
"DATETIME(3) NULL COMMENT '来源状态最后更新时间,数据修改时自动刷新' AFTER created_at");
|
||
CALL finance_fee_source_add_column('fin_bill', 'customer_confirmation_status',
|
||
"VARCHAR(24) NOT NULL DEFAULT 'NOT_REQUIRED' COMMENT '客户确认状态:NOT_REQUIRED无需确认、PENDING_CONFIRMATION待确认、CONFIRMED已确认' AFTER issued_by");
|
||
CALL finance_fee_source_add_column('fin_bill', 'customer_confirmed_by',
|
||
"BIGINT UNSIGNED NULL COMMENT '客户确认人用户ID' AFTER customer_confirmation_status");
|
||
CALL finance_fee_source_add_column('fin_bill', 'customer_confirmed_by_name',
|
||
"VARCHAR(128) NULL COMMENT '客户确认人姓名快照' AFTER customer_confirmed_by");
|
||
CALL finance_fee_source_add_column('fin_bill', 'customer_confirmed_at',
|
||
"DATETIME(3) NULL COMMENT '客户确认时间' AFTER customer_confirmed_by_name");
|
||
CALL finance_fee_source_add_column('fin_inbox_event', 'payload_hash',
|
||
"CHAR(64) NULL COMMENT '规范化事件内容SHA-256哈希,用于同事件ID冲突检测' AFTER payload");
|
||
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'),
|
||
direction = COALESCE(direction, 'RECEIVABLE'),
|
||
fee_item_code = COALESCE(fee_item_code, 'LEGACY'),
|
||
source_hash = COALESCE(source_hash, SHA2(CONCAT_WS('|', source_system, source_fee_id, source_fee_version), 256)),
|
||
source_snapshot = COALESCE(source_snapshot, JSON_OBJECT('migrated', TRUE)),
|
||
updated_at = COALESCE(updated_at, created_at),
|
||
review_status = COALESCE(review_status, 'DRAFT'),
|
||
operation_version = COALESCE(operation_version, 0);
|
||
UPDATE fin_inbox_event
|
||
SET payload_hash = COALESCE(payload_hash, SHA2(CAST(payload AS CHAR), 256));
|
||
|
||
ALTER TABLE fin_fee_source
|
||
MODIFY COLUMN source_type VARCHAR(32) NOT NULL COMMENT '来源费用类型:INBOUND_FEE入库单费用、CONTAINER_FEE柜子费用',
|
||
MODIFY COLUMN direction VARCHAR(16) NOT NULL COMMENT '费用方向:RECEIVABLE应收、PAYABLE应付',
|
||
MODIFY COLUMN fee_item_code VARCHAR(64) NOT NULL COMMENT '来源费用项目编码快照',
|
||
MODIFY COLUMN source_hash CHAR(64) NOT NULL COMMENT 'Firstleg费用来源完整快照SHA-256哈希',
|
||
MODIFY COLUMN source_snapshot JSON NOT NULL COMMENT 'Firstleg费用来源完整不可变JSON快照',
|
||
MODIFY COLUMN status VARCHAR(16) NOT NULL DEFAULT 'AVAILABLE' COMMENT '费用来源状态:AVAILABLE可结算、SUPERSEDED已被新版本替代、VOIDED已作废',
|
||
MODIFY COLUMN updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '来源状态最后更新时间,数据修改时自动刷新';
|
||
ALTER TABLE fin_inbox_event
|
||
MODIFY COLUMN payload_hash CHAR(64) NOT NULL COMMENT '规范化事件内容SHA-256哈希,用于同事件ID冲突检测',
|
||
MODIFY COLUMN status VARCHAR(16) NOT NULL DEFAULT 'RECEIVED' COMMENT '事件处理状态:RECEIVED已接收、PROCESSED已完成、FAILED处理失败';
|
||
|
||
DROP PROCEDURE IF EXISTS finance_fee_source_assert_schema;
|
||
DELIMITER $$
|
||
CREATE PROCEDURE finance_fee_source_assert_schema()
|
||
BEGIN
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fin_fee_source'
|
||
AND column_name IN ('source_type','source_no','direction','container_id','fee_item_code',
|
||
'settlement_mode','paid_at','payment_method','payment_reference_no',
|
||
'payment_voucher_file_ids','source_hash','source_snapshot','review_status','review_reason',
|
||
'operation_version','updated_at')) <> 16 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_inbox_event'
|
||
AND column_name IN ('payload_hash','result_resource_id','error_code')) <> 3 THEN
|
||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Finance费用来源迁移失败:Inbox幂等字段不完整';
|
||
END IF;
|
||
IF (SELECT COUNT(*) FROM information_schema.columns
|
||
WHERE table_schema = DATABASE() AND table_name = 'fin_bill'
|
||
AND column_name IN ('customer_confirmation_status','customer_confirmed_by',
|
||
'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();
|
||
DROP PROCEDURE IF EXISTS finance_fee_source_assert_schema;
|