refactor(db): 财务迁移收敛为 103–107

把 103–112 十个迁移收敛为五个,删除在「生产 102 → 当前」路径上的空操作与补丁:

- 108(下线人工支出登记)与 109(隔离历史快照主体)在生产库和重建库上都是空操作,
  口径注释并入 104;
- 111 是给 104 自身种子打的补丁,合并后 104 直接写入 active 0 元占位;
- 112 的 cost_exceptions.resolution_note 并入 104,退款表独立为 106;
- 106(备用金编号可读化)与 110(积分钱包)合并为 107(人工履约资金层);
- 107(履约方式列)并入 105,履约方式本就是销售事实的维度键。

配套调整:
- check-sql-guard 改为以 main 为基线校验迁移字节,删除 103–114 的永久豁免;
  未合并分支上的新迁移仍可重写,已发布迁移不可修改。
- 本地库原地改造脚本移入 docs/archive,禁止对新环境执行。

验证:清掉 schema_migrations 里 103–112 的记录后重跑,升级结果与全新构建的
schema 完全一致(pg_dump --schema-only 仅随机 token 不同),种子数据一致;
升级前后业务数据量不变(成本版本 713 → 712,差异来自删除占位草稿)。
This commit is contained in:
yml2213
2026-10-25 11:38:12 +08:00
parent 465a9f65dc
commit 472769a977
13 changed files with 206 additions and 333 deletions
-138
View File
@@ -1,138 +0,0 @@
-- ============================================================================
-- 原地改造脚本(本地库专用,2026-10-23 财务重写)
--
-- 目的:把本地库的旧派生表结构(carrier_type / cost_type)改造成新 schema
-- (cost_model / fulfillment_mode),不重建整库、不动源表。
--
-- 改造矩阵(列级 ALTER,不重建表):
-- product_catalog 删 carrier_type(来源改由 canonical_sku 前缀推导)
-- cost_items cost_type + carrier_type -> cost_model
-- cost_snapshots 删 carrier_type(履约方式 join order_items)
-- cost_exceptions 删 carrier_type(同上)
-- sales_daily_facts carrier_type -> fulfillment_mode(改名)
-- manual_expense_records cost_item_id 改 NOT NULL
-- work_product_rules 删 legacy_cost_source
-- order_items 不动(履约事实、收入固化、商品指向全部保留)
--
-- 约束:
-- 1. 源表(orders / order_items / work_orders / work_product_rules /
-- fulfillment_tasks / fund_accounts)一律不动;
-- 2. 派生表按新 schema 就地改造,历史快照与异常不重建(不丢审计痕迹);
-- 3. 执行前必须已有备份 backups/postgres/order_site_pre_rewrite_20261023.dump。
--
-- 执行:
-- docker exec -i order_site-postgres-1 psql -U postgres -d order_site \
-- -v ON_ERROR_STOP=1 < scripts/rewrite-local-db-2026-10-23.sql
-- ============================================================================
\set ON_ERROR_STOP on
BEGIN;
-- ---------------------------------------------------------------------------
-- 1. 清掉旧迁移记录(103–114),让新迁移 103–107 重新执行
-- ---------------------------------------------------------------------------
DELETE FROM schema_migrations
WHERE name IN (
'103_product_catalog',
'104_cost_center',
'105_cost_center_bootstrap_fix',
'106_product_mapping_match_keys',
'107_product_catalog_carrier',
'108_cost_snapshot_runtime',
'109_sales_daily_facts',
'110_system_cost_items',
'111_manual_expense_records',
'112_cost_reporting_indexes',
'113_fund_account_no_readable',
'114_order_item_fulfillment_mode'
);
-- ---------------------------------------------------------------------------
-- 2. product_catalog:删履约载体列
-- 来源改由 canonical_sku 前缀表达(aff: / tpl: / wo: / man:)。
-- ---------------------------------------------------------------------------
DROP INDEX IF EXISTS idx_product_catalog_status_carrier;
ALTER TABLE product_catalog DROP COLUMN IF EXISTS carrier_type;
-- ---------------------------------------------------------------------------
-- 3. cost_items:cost_type + carrier_type -> cost_model
-- 成本模型只表达「成本怎么算」,与履约方式正交。
-- ---------------------------------------------------------------------------
-- 3.1 先把编码统一到新口径,避免迁移 104 再插一条同义成本项。
UPDATE cost_items SET code = 'sys_affiliate_purchase' WHERE code = 'auto_purchase';
-- 3.2 新增 cost_model 并按旧 cost_type 映射。
ALTER TABLE cost_items ADD COLUMN IF NOT EXISTS cost_model TEXT;
UPDATE cost_items
SET cost_model = CASE cost_type
WHEN 'auto_purchase' THEN 'affiliate_purchase'
WHEN 'work_order_reward' THEN 'work_order_reward'
WHEN 'manual_service' THEN 'manual_actual'
WHEN 'platform_fee' THEN 'platform_fee'
WHEN 'payment_fee' THEN 'payment_fee'
WHEN 'after_sales_loss' THEN 'after_sales_loss'
WHEN 'shipping_other' THEN 'other'
WHEN 'other' THEN 'other'
ELSE 'other'
END
WHERE cost_model IS NULL;
-- 3.3 删旧列(CHECK 约束随列一起消失)。
ALTER TABLE cost_items DROP COLUMN IF EXISTS cost_type;
ALTER TABLE cost_items DROP COLUMN IF EXISTS carrier_type;
-- 3.4 删旧 CHECK,让迁移 104 按新枚举重建。
ALTER TABLE cost_items DROP CONSTRAINT IF EXISTS chk_cost_items_cost_type;
ALTER TABLE cost_items DROP CONSTRAINT IF EXISTS chk_cost_items_carrier_type;
ALTER TABLE cost_items DROP CONSTRAINT IF EXISTS chk_cost_items_pricing_mode;
-- 3.5 cost_model 必填。
-- 迁移 104 用 CREATE TABLE IF NOT EXISTS 建表,表已存在时不会补 NOT NULL,
-- 所以这里先补上,迁移 104 再补 CHECK 枚举。
ALTER TABLE cost_items ALTER COLUMN cost_model SET NOT NULL;
-- ---------------------------------------------------------------------------
-- 4. cost_snapshots:删履约载体列与未被使用的 manual_case_id
-- 履约方式由 order_items.fulfillment_mode 提供,join 即可。
-- ---------------------------------------------------------------------------
ALTER TABLE cost_snapshots DROP COLUMN IF EXISTS carrier_type;
ALTER TABLE cost_snapshots DROP COLUMN IF EXISTS manual_case_id;
-- ---------------------------------------------------------------------------
-- 5. cost_exceptions:删履约载体列
-- ---------------------------------------------------------------------------
ALTER TABLE cost_exceptions DROP COLUMN IF EXISTS carrier_type;
-- ---------------------------------------------------------------------------
-- 6. sales_daily_facts:carrier_type -> fulfillment_mode
-- ---------------------------------------------------------------------------
ALTER TABLE sales_daily_facts DROP CONSTRAINT IF EXISTS chk_sales_daily_facts_carrier;
DROP INDEX IF EXISTS uq_sales_daily_facts_key;
ALTER TABLE sales_daily_facts RENAME COLUMN carrier_type TO fulfillment_mode;
-- ---------------------------------------------------------------------------
-- 7. manual_expense_records:成本项必填
-- ---------------------------------------------------------------------------
ALTER TABLE manual_expense_records
ALTER COLUMN cost_item_id SET NOT NULL;
-- ---------------------------------------------------------------------------
-- 8. work_product_rules:删旧成本回退标记
-- ---------------------------------------------------------------------------
ALTER TABLE work_product_rules DROP COLUMN IF EXISTS legacy_cost_source;
-- ---------------------------------------------------------------------------
-- 9. 让迁移 104 按新定义重建同名索引
-- 旧 112 的两个覆盖索引定义与新 104 不同,先删后建。
-- ---------------------------------------------------------------------------
DROP INDEX IF EXISTS idx_work_orders_rule_cover;
DROP INDEX IF EXISTS idx_order_items_revenue_cover;
COMMIT;
-- ============================================================================
-- 以上是结构改造;接下来执行:
-- 1. npm run db:migrate —— 应用新迁移 103–107
-- 2. npm run fulfillment:backfill —— 重跑履约回填(幂等,NULL=0 时无操作)
-- 3. 回填脚本 / 同步脚本 —— 重跑商品、成本版本、快照与销售事实
-- ============================================================================