refactor(finance): 成本模型与履约方式正交,拆分成本中心巨型文件

后端:
- 删除 services/admin/admin-cost-center-service.ts(4,248 行),拆为
  services/cost-center/ 下 5 个模块:
  cost-center-shared(类型/枚举/归一化/映射/costModelScopeSql)、
  cost-center-overview(总览与选项)、
  product-catalog(商品与渠道映射)、
  template-bootstrap(模板引导、自动发货同步、工单证据回填)、
  cost-definition(成本项/版本/异常/预览/快照)
- cost_items.carrier_type / cost_type 改为单一 cost_model;专属模型只对
  对应履约方式生效,通用模型对所有履约方式生效
- cost_snapshots / cost_exceptions 删除载体列;按履约方式筛异常改用
  IN 半连接(248k 异常下 EXISTS 逐行回表 2.7s -> 170ms)
- sales_daily_facts.carrier_type -> fulfillment_mode
- 人工支出按 cost_model 归类;履约方式只读 order_items.fulfillment_mode
- 移除 syncOpenCostExceptionCarrierTypes:异常表已无载体列可同步

前端:
- AdminCostCenterPage.tsx(2,887 行 -> 18 行转发),拆为
  pages/admin/cost-center/ 下 8 个 Panel + shared + CostCenterContext
- CostCarrierType 删除;新增 FulfillmentMode / ProductSource / CostModel
- 销售毛利页 carrierType -> fulfillmentMode

同步补两个索引:idx_order_items_fulfillment_id(异常半连接)、
idx_work_categories_name(商品目录分类 lateral join)。
This commit is contained in:
yml2213
2026-10-23 16:06:25 +08:00
parent 5c549a2dc5
commit 63ae32d18c
33 changed files with 8107 additions and 7335 deletions
+138
View File
@@ -0,0 +1,138 @@
-- ============================================================================
-- 原地改造脚本(本地库专用,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. 回填脚本 / 同步脚本 —— 重跑商品、成本版本、快照与销售事实
-- ============================================================================