完善财务费用来源与柜级分摊

This commit is contained in:
2026-09-02 17:07:03 +08:00
parent 6cd477a037
commit 3bdaba2c60
34 changed files with 625 additions and 71 deletions
@@ -11408,6 +11408,12 @@ DROP PROCEDURE IF EXISTS firstleg_finance_add_index;
CREATE TABLE IF NOT EXISTS fl_container_fee_detail (
id BIGINT UNSIGNED NOT NULL COMMENT '柜次费用来源ID',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
allocation_group_id BIGINT UNSIGNED NULL COMMENT '柜级公共费用分摊组ID;单入仓直接费用为空',
allocation_order_id BIGINT UNSIGNED NULL COMMENT '本分摊行业务订单ID',
allocation_order_no VARCHAR(64) NULL COMMENT '本分摊行业务订单号',
allocation_inbound_id BIGINT UNSIGNED NULL COMMENT '本分摊行对应入仓单ID',
allocation_inbound_code VARCHAR(64) NULL COMMENT '本分摊行对应入仓码',
allocation_group_amount DECIMAL(18,2) NULL COMMENT '柜级原始费用总额快照',
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '柜次ID,对应fl_loading_plan.id',
container_booking_id BIGINT UNSIGNED NULL COMMENT '订舱柜ID快照',
container_no VARCHAR(64) NULL COMMENT '柜号快照',
@@ -11462,6 +11468,12 @@ CREATE TABLE IF NOT EXISTS fl_container_fee_source_snapshot (
source_fee_id BIGINT UNSIGNED NOT NULL COMMENT '柜次费用来源ID',
source_version INT UNSIGNED NOT NULL COMMENT '费用来源版本',
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID和数据隔离键',
allocation_group_id BIGINT UNSIGNED NULL COMMENT '柜级公共费用分摊组ID',
allocation_order_id BIGINT UNSIGNED NULL COMMENT '分摊业务订单ID快照',
allocation_order_no VARCHAR(64) NULL COMMENT '分摊业务订单号快照',
allocation_inbound_id BIGINT UNSIGNED NULL COMMENT '分摊入仓单ID快照',
allocation_inbound_code VARCHAR(64) NULL COMMENT '分摊入仓码快照',
allocation_group_amount DECIMAL(18,2) NULL COMMENT '柜级原始费用总额快照',
loading_plan_id BIGINT UNSIGNED NOT NULL COMMENT '柜次ID',
container_booking_id BIGINT UNSIGNED NULL COMMENT '订舱柜ID快照',
container_no VARCHAR(64) NULL COMMENT '柜号快照',
@@ -11530,6 +11542,18 @@ CALL firstleg_finance_add_column('fl_container_fee_detail', 'payment_reference_n
"VARCHAR(128) NULL COMMENT 'DIRECT_PAID付款流水号' AFTER payment_method");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'payment_voucher_file_ids',
"JSON NULL COMMENT 'DIRECT_PAID付款凭证File ID数组' AFTER payment_reference_no");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'allocation_group_id',
"BIGINT UNSIGNED NULL COMMENT '柜级公共费用分摊组ID;单入仓直接费用为空' AFTER tenant_id");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'allocation_order_id',
"BIGINT UNSIGNED NULL COMMENT '本分摊行业务订单ID' AFTER allocation_group_id");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'allocation_order_no',
"VARCHAR(64) NULL COMMENT '本分摊行业务订单号' AFTER allocation_order_id");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'allocation_inbound_id',
"BIGINT UNSIGNED NULL COMMENT '本分摊行对应入仓单ID' AFTER allocation_order_no");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'allocation_inbound_code',
"VARCHAR(64) NULL COMMENT '本分摊行对应入仓码' AFTER allocation_inbound_id");
CALL firstleg_finance_add_column('fl_container_fee_detail', 'allocation_group_amount',
"DECIMAL(18,2) NULL COMMENT '柜级原始费用总额快照' AFTER allocation_inbound_code");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'settlement_mode',
"VARCHAR(16) NULL COMMENT '仅PAYABLE:ON_ACCOUNT或DIRECT_PAID' AFTER supplier_category");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'paid_at',
@@ -11540,6 +11564,18 @@ CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'payment_re
"VARCHAR(128) NULL COMMENT 'DIRECT_PAID付款流水号' AFTER payment_method");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'payment_voucher_file_ids',
"JSON NULL COMMENT 'DIRECT_PAID付款凭证File ID数组' AFTER payment_reference_no");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'allocation_group_id',
"BIGINT UNSIGNED NULL COMMENT '柜级公共费用分摊组ID' AFTER tenant_id");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'allocation_order_id',
"BIGINT UNSIGNED NULL COMMENT '分摊业务订单ID快照' AFTER allocation_group_id");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'allocation_order_no',
"VARCHAR(64) NULL COMMENT '分摊业务订单号快照' AFTER allocation_order_id");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'allocation_inbound_id',
"BIGINT UNSIGNED NULL COMMENT '分摊入仓单ID快照' AFTER allocation_order_no");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'allocation_inbound_code',
"VARCHAR(64) NULL COMMENT '分摊入仓码快照' AFTER allocation_inbound_id");
CALL firstleg_finance_add_column('fl_container_fee_source_snapshot', 'allocation_group_amount',
"DECIMAL(18,2) NULL COMMENT '柜级原始费用总额快照' AFTER allocation_inbound_code");
CALL firstleg_finance_add_column('fl_inbound_fee_detail', 'supplier_id',
"BIGINT UNSIGNED NULL COMMENT '应付Warehouse供应商ID快照;应收为空' AFTER direction");
CALL firstleg_finance_add_column('fl_inbound_fee_detail', 'supplier_name',
@@ -11627,10 +11663,24 @@ 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', 'business_type',
"VARCHAR(32) NULL COMMENT '来源业务类型,如海外入仓、采购、卡车或柜级分摊' AFTER source_no");
CALL finance_fee_source_add_column('fin_fee_source', 'business_id',
"BIGINT UNSIGNED NULL COMMENT '来源业务记录ID,可为空' AFTER business_type");
CALL finance_fee_source_add_column('fin_fee_source', 'business_no',
"VARCHAR(128) NULL COMMENT '来源业务编号快照,可为空' AFTER business_id");
CALL finance_fee_source_add_column('fin_fee_source', 'inbound_code',
"VARCHAR(64) NULL COMMENT '来源入仓码快照;并非所有费用必填' AFTER business_no");
CALL finance_fee_source_add_column('fin_fee_source', 'warehouse_id',
"BIGINT UNSIGNED NULL COMMENT '来源海外仓或业务仓ID,可为空' AFTER inbound_code");
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', 'container_booking_id',
"BIGINT UNSIGNED NULL COMMENT '来源订舱柜ID,可为空' AFTER container_id");
CALL finance_fee_source_add_column('fin_fee_source', 'container_no',
"VARCHAR(64) NULL COMMENT '真实集装箱号快照,可为空' AFTER container_booking_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',
@@ -11681,6 +11731,8 @@ 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', 'warehouse_id',
"BIGINT UNSIGNED NULL COMMENT '业务直接已付成本关联仓库ID,可为空' AFTER container_id");
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',
@@ -11690,6 +11742,22 @@ CALL finance_fee_source_add_column('fin_cost', 'payment_reference_no',
DROP PROCEDURE IF EXISTS finance_fee_source_add_column;
SET @finance_fee_source_index_ddl = (
SELECT IF(
(SELECT COUNT(*) FROM information_schema.statistics
WHERE table_schema=DATABASE() AND table_name='fin_fee_source'
AND index_name='uk_fin_fee_source')=4,
'SELECT 1',
IF(EXISTS(SELECT 1 FROM information_schema.statistics
WHERE table_schema=DATABASE() AND table_name='fin_fee_source' AND index_name='uk_fin_fee_source'),
'ALTER TABLE fin_fee_source DROP INDEX uk_fin_fee_source, ADD UNIQUE KEY uk_fin_fee_source(source_system,source_type,source_fee_id,source_fee_version)',
'ALTER TABLE fin_fee_source ADD UNIQUE KEY uk_fin_fee_source(source_system,source_type,source_fee_id,source_fee_version)')
)
);
PREPARE finance_fee_source_index_stmt FROM @finance_fee_source_index_ddl;
EXECUTE finance_fee_source_index_stmt;
DEALLOCATE PREPARE finance_fee_source_index_stmt;
DROP PROCEDURE IF EXISTS finance_fee_source_add_index;
DELIMITER $$
CREATE PROCEDURE finance_fee_source_add_index()
@@ -11708,7 +11776,9 @@ 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来源直接已付';
MODIFY COLUMN cost_type VARCHAR(24) NOT NULL COMMENT '成本归属类型:SINGLE_ORDER单票、CONTAINER_SHARED整柜公共、SOURCE_DIRECT_PAID来源直接已付',
MODIFY COLUMN cost_origin VARCHAR(24) NOT NULL DEFAULT 'MANUAL' COMMENT '成本来源:MANUAL人工补充、FIRSTLEG_DIRECT_PAID头程直接已付、BUSINESS_DIRECT_PAID其他业务直接已付',
MODIFY COLUMN source_hash VARCHAR(71) NULL COMMENT '来源不可变快照SHA-256,兼容sha256前缀格式';
DROP PROCEDURE IF EXISTS finance_fee_source_replace_cost_checks;
DELIMITER $$
CREATE PROCEDURE finance_fee_source_replace_cost_checks()
@@ -11725,7 +11795,7 @@ BEGIN
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))
OR (cost_type='SOURCE_DIRECT_PAID' AND (order_id IS NOT NULL OR inbound_id IS NOT NULL OR container_id IS NOT NULL OR warehouse_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)
@@ -11733,6 +11803,10 @@ BEGIN
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'))
OR (cost_origin='BUSINESS_DIRECT_PAID' AND source_system NOT IN ('', '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 ;
@@ -11756,12 +11830,12 @@ 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 source_hash VARCHAR(71) NOT NULL COMMENT '业务费用来源完整快照SHA-256哈希,兼容sha256前缀格式',
MODIFY COLUMN source_snapshot JSON NOT NULL COMMENT '业务费用来源完整不可变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 payload_hash VARCHAR(71) NOT NULL COMMENT '规范化事件内容SHA-256哈希,兼容sha256前缀格式',
MODIFY COLUMN status VARCHAR(16) NOT NULL DEFAULT 'RECEIVED' COMMENT '事件处理状态:RECEIVED已接收、PROCESSED已完成、FAILED处理失败';
DROP PROCEDURE IF EXISTS finance_fee_source_assert_schema;
@@ -11791,7 +11865,7 @@ BEGIN
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
'payment_reference_no','warehouse_id')) <> 10 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Finance直接已付成本字段不完整';
END IF;
IF (SELECT COUNT(*) FROM information_schema.statistics
@@ -1116,4 +1116,43 @@ END$$
DELIMITER ;
CALL assert_lastleg_security_projection_ready();
DROP PROCEDURE assert_lastleg_security_projection_ready;
CREATE TABLE IF NOT EXISTS ll_finance_fee_source (
id BIGINT NOT NULL COMMENT '费用版本记录ID', source_fee_id BIGINT NOT NULL COMMENT '跨版本稳定费用来源ID',
source_version INT NOT NULL COMMENT '费用来源版本,从1递增', customer_id VARCHAR(128) NOT NULL COMMENT '客户ID和隔离键',
customer_name VARCHAR(200) NULL COMMENT '客户名称快照', source_type VARCHAR(64) NOT NULL COMMENT '海外费用来源类型',
source_no VARCHAR(128) NOT NULL COMMENT '来源业务编号或入仓码快照', business_type VARCHAR(32) NOT NULL COMMENT '来源业务类型',
business_id BIGINT NULL COMMENT '来源业务记录ID', business_no VARCHAR(128) NOT NULL COMMENT '来源业务编号',
order_id BIGINT NULL COMMENT '关联订单ID', inbound_id BIGINT NULL COMMENT '关联海外入仓计划或入仓记录ID',
inbound_code VARCHAR(64) NULL COMMENT '关联入仓码;并非所有费用必填', container_id BIGINT NULL COMMENT '关联柜次ID',
container_booking_id BIGINT NULL COMMENT '来源订舱柜ID', container_no VARCHAR(64) NULL COMMENT '真实集装箱号快照',
warehouse_id BIGINT NULL COMMENT '关联海外仓ID', fee_item_code VARCHAR(64) NOT NULL COMMENT '费用项目编码快照',
fee_item_name VARCHAR(200) NOT NULL COMMENT '费用项目名称快照', direction VARCHAR(16) NOT NULL COMMENT 'RECEIVABLE应收或PAYABLE应付',
supplier_id BIGINT NULL COMMENT '应付供应商ID', supplier_name VARCHAR(200) NULL COMMENT '应付供应商名称快照',
supplier_category VARCHAR(32) NULL COMMENT '应付供应商类别约束', settlement_mode VARCHAR(16) NULL COMMENT 'ON_ACCOUNT账期应付或DIRECT_PAID业务已付',
paid_at DATETIME(3) NULL COMMENT '直接已付时间', payment_method VARCHAR(32) NULL COMMENT '直接已付方式',
payment_reference_no VARCHAR(128) NULL COMMENT '直接已付流水号', payment_voucher_file_ids JSON NULL COMMENT '直接已付凭证文件ID快照',
business_date DATE NOT NULL COMMENT '费用业务日期', currency CHAR(3) NOT NULL DEFAULT 'CNY' COMMENT '财务结算币种,当前固定CNY',
amount DECIMAL(20,6) NOT NULL COMMENT '费用金额', review_status VARCHAR(16) NOT NULL COMMENT 'DRAFT、PENDING、APPROVED或REJECTED',
publication_status VARCHAR(16) NOT NULL COMMENT 'UNPUBLISHED或PUBLISHED', source_status VARCHAR(16) NOT NULL COMMENT 'ACTIVE、SUPERSEDED或VOIDED',
review_reason VARCHAR(500) NULL COMMENT '审核或作废原因', reviewer_id VARCHAR(128) NULL COMMENT '审核人ID', reviewed_at DATETIME(3) NULL COMMENT '审核时间',
created_by VARCHAR(128) NOT NULL COMMENT '创建人ID', updated_by VARCHAR(128) NOT NULL COMMENT '最后更新人ID',
created_at DATETIME(3) NOT NULL COMMENT '创建时间', updated_at DATETIME(3) NOT NULL COMMENT '最后更新时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_version(source_fee_id,source_version),
KEY idx_ll_finance_fee_customer(customer_id,source_status,created_at), KEY idx_ll_finance_fee_business(business_type,business_no,created_at),
CONSTRAINT chk_ll_finance_fee_amount CHECK(amount>0), CONSTRAINT chk_ll_finance_fee_currency CHECK(currency='CNY'),
CONSTRAINT chk_ll_finance_fee_direction CHECK(direction IN('RECEIVABLE','PAYABLE')),
CONSTRAINT chk_ll_finance_fee_review CHECK(review_status IN('DRAFT','PENDING','APPROVED','REJECTED')),
CONSTRAINT chk_ll_finance_fee_publication CHECK(publication_status IN('UNPUBLISHED','PUBLISHED')),
CONSTRAINT chk_ll_finance_fee_status CHECK(source_status IN('ACTIVE','SUPERSEDED','VOIDED'))
) ENGINE=InnoDB COMMENT='海外业务不可变费用来源版本;发布后经跨区事件进入Finance';
CREATE TABLE IF NOT EXISTS ll_finance_fee_command (
id BIGINT NOT NULL COMMENT '幂等命令ID', operator_id VARCHAR(128) NOT NULL COMMENT '操作人ID',
action VARCHAR(16) NOT NULL COMMENT 'CREATE、SUBMIT、REVIEW、ADJUST或VOID', idempotency_key VARCHAR(128) NOT NULL COMMENT '操作幂等键',
request_hash CHAR(64) NOT NULL COMMENT '请求内容SHA-256', source_fee_id BIGINT NOT NULL COMMENT '稳定费用来源ID',
source_version INT NOT NULL COMMENT '命令结果版本', created_at DATETIME(3) NOT NULL COMMENT '命令创建时间',
PRIMARY KEY(id), UNIQUE KEY uk_ll_finance_fee_command(operator_id,action,idempotency_key),
KEY idx_ll_finance_fee_command_source(source_fee_id,source_version)
) ENGINE=InnoDB COMMENT='海外费用来源写操作幂等审计';
SELECT 'PASS' AS migration_status, '海外仓业务、海外仓资源与IAM安全投影结构已就绪' AS message;