Files
order_site/docs/README.md
T
yml2213andClaude Opus 4.5 fb679d76f6 refactor(finance): 人工成本收敛为「人工录单 → 扣备用金 → 写快照」
公司人工支出登记单与审批报销状态机整链下线,人工成本只留一条链路。

口径调整(2026-10-23 确认):
- 历史人工支出找不回来,直接放弃:不补录、不做样本校准、不做均价估算,
  只保证上线后的新单不丢。
- 人工成本逐单按实际金额,从客服备用金扣款,客服只能用本人账户;
  没有登记单、没有审批、没有报销,录入即计入毛利。

后端:
- 新增 services/finance/manual-order-cost-service.ts:扣备用金 + 写 actual
  成本快照,同一事务,余额不足直接拒绝不允许负余额。
- 成本快照主体从「人工支出登记单 id」改为「客服备用金支出单 id」
  (subject_type='manual_case',subject_id=manual_expenses.id)。
- 删除 services/finance/manual-expense-service.ts(1263 行)与
  routes/admin/finance.ts 下 /finance/manual-expenses* 全套接口。

前端:
- 删除 AdminManualExpensePage.tsx(778 行)与 /admin/manual-expenses 菜单页。
- ManualOrderCostModal 去掉「提交审核 / 立即计入成本」开关,录入即生效。
- 新增 services/admin/manual-order-cost.ts。

迁移:
- 106_manual_expense_records.sql → 106_fund_account_no_readable.sql,
  只保留备用金账户编号可读化。
- 108_drop_manual_expense_records.sql:删除 manual_expense_records 与
  manual_expense_events 两张表。
- 109_isolate_legacy_manual_snapshots.sql:把来源为旧登记链的历史孤儿快照
  subject_id 改为负数,与 manual_expenses.id 彻底隔离。

踩坑修复(E2E 实测发现):主体 id 换空间后与历史孤儿快照撞唯一索引
uq_cost_snapshots_active_subject_item,INSERT ... ON CONFLICT DO NOTHING
静默跳过,导致「钱从备用金扣了、成本快照却没写成」。修法是迁移 109 隔离
legacy 主体 + 后端快照写失败必须抛错回滚(409),杜绝账实不符。

文档:现行 5 篇 + README 基线校准为 dev @ 43f402cf + 迁移 103–109,
修正已删除的旧迁移号,删除「人工支出登记 + 审批 + 报销」口径,
已作废 DDL 草案移入 docs/archive/2026-10-23/。

校验:后端 765 项 / 0 失败(含 check:sql 迁移护栏),前端 143 项全通过;
E2E 实测两笔同订单项各自独立主体、余额扣减与快照金额一一对应;
本地库迁移 108/109 执行后数据量与改造前完全一致。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
2026-10-24 11:31:29 +08:00

185 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# order_site 文档索引
> 最后校准:2026-10-23,代码基线 `dev @ 43f402cf + 迁移 103–109`(已合并到 `dev`,**未推送、未部署生产**)。
> 本文是 `docs/` 的唯一入口。**财务与履约口径以 [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) 为准**;数据模型看 [成本中心与履约模型.md](成本中心与履约模型.md),接口看 [成本中心API契约.md](成本中心API契约.md)。
> 新增文档必须在下表登记状态;过期文档不再直接改写结论,统一移入 `docs/archive/`。
## 一、先记住六条口径
### 1. 来源只有三个,不是四个
| sourceKey | 包含的数据通道 | 说明 |
| --- | --- | --- |
| `kuaishou-91` | 91 回调 + 快手 send-code | **同一个来源的两条通道**:91 是订单骨架权威源,快手 send-code 是数据补全源与兜底源;共享店铺键空间与同一套匹配上下文 |
| `pdd` | 拼多多订单同步 | 两段式 `pdd_raw_orders → orders` |
| `douyin-mashida` | 抖音码速达推送 | 抖店订单、DYC 券、H5/兑换页 |
**不要把 91 与快手 send-code 拆成两个来源、两个适配器或两条业务线。** 产品匹配层的唯一来源键是 `kuaishou-91`(`apps/backend/src/services/product-match/types.ts`),适配器是 `adapters/kuaishou-91.ts`。但订单表与成本映射里存储的 `provider` 仍是 `orders.provider = 91kaquan`;成本中心会把 `91 / open_91 / kuaishou-91` 这些别名归一为 `91kaquan`,映射键必须按落库值建。
### 2. 一个订单 = 骨架 + 买家凭证 + 一个履约方式
- 骨架:`orders` + `order_items`
- 买家凭证:快手电子凭证(`kuaishou_industry_vouchers`)或抖音券(`redeem_certificates`)
- 履约方式只有四种:`affiliate_dash` 自动发货、`work_orders` 接单平台、`legacy_platform` 已下线历史平台、`manual` 人工
- **电子凭证只是核销码,不参与履约方式判定**;有核销码的订单仍可能是自动发货/接单平台/人工
- 判定顺序固定:工单 → 自动发货任务 → 历史平台任务 → 其余为人工
- 人工块必须进入人工支出与成本快照,不能静默消失
### 3. 履约方式与成本模型必须分开
- `fulfillment_mode` 回答“谁执行”;`cost_model` 回答“成本怎么算”
- 自动发货:`affiliate_purchase`
- 接单平台:`work_order_reward`
- 人工:`manual_actual`(逐单实际金额)
- 历史平台:`legacy_cost`(历史未采集则显式标记)
- 电子凭证不建成本项,也不作为成本类型
- 未确认成本时保持 `cost_missing`,不默认 0
### 4. 成本只在一个地方改
- 商品主数据:`product_catalog`
- 渠道 SKU 映射:`channel_product_mappings`
- 成本金额:只在 `cost_versions` 改,按生效日期新增版本
- 订单/工单/人工单只保存 `cost_snapshot_id`,历史成本永不回写
- 自动发货、接单平台、人工客服共用同一个成本解析器;匹配不到成本进入 `cost_missing`,不默认 0
### 5. 人工成本只有一条链路
```text
订单页「人工录单」→ 扣客服备用金(manual_expenses)→ 写 cost_snapshots(manual_case)
```
| 名称 | 业务含义 | 当前状态 |
| --- | --- | --- |
| `manual_expenses` | **客服备用金支出明细**:客服从自己的备用金里充值/采购/赔偿,减少客服余额 | 已实施(迁移 100);人工录单也写这里 |
| `cost_snapshots` | **人工成本的唯一落点**:`subject_type='manual_case'`,`subject_id=manual_expenses.id` | 已实施(迁移 104) |
**没有独立的登记单,也没有审批与报销环节。** `manual_expense_records` / `manual_expense_events` 已随迁移 `108` 删除。后续做财务系统时,人工成本的钱与账都从这条链路走,不要再另造一张人工支出表。
### 6. 历史人工直接放弃,上线后必须全覆盖
- 历史人工支出找不回来,**直接放弃**:不补录、不做样本校准、不阻塞上线;
- 上线后每一笔人工单必须有处理人、实际金额、备用金支出与成本快照;
- 人工单无成本记录、人工单未扣备用金、金额与备用金流水不一致,均不允许关账。
### 7. 文档状态
| 状态 | 含义 |
| --- | --- |
| 现行 | 与当前代码一致,改动代码时必须同步更新 |
| 方案 | 尚未实施,但作为下一阶段实现依据 |
| 参考 | 外部协议、历史数据或解释性材料,不作为实现依据 |
| 历史 | 只用于追溯,不得作为实现依据;位于 `docs/archive/` |
## 二、财务系统当前进度
| 模块 | 状态 | 事实 |
| --- | --- | --- |
| 客服备用金台账 | **已实施 P0** | 迁移 `100/101/106`;账户、流水、支出、对账;编号 `FA-<用户名>`;客服只能使用本人账户 |
| 后台用户中文显示名 | **已实施** | `admin_users.display_name`,备用金姓名触发器同步;审计、登录记录、任务处理人优先显示中文名 |
| 商品主数据 + 渠道 SKU 映射 | **已实施 P0** | 745 个标准商品、4,426 条映射;只覆盖自动发货 38 个 + 接单平台 707 个。人工 11,349 项虽已归一但全部挂 `tpl:*` 模板商品,需在 P1 复核;人工专用商品尚未建立 |
| 成本中心 | **已实施 P0** | 迁移 `104`;`cost_items.cost_model` 取代 `cost_type + carrier_type`;38 个商品级版本 + 662 个规则级版本;人工走 `sys_manual_service` 实际快照 |
| 销售事实 / 订单毛利 | **已实施 P0** | 迁移 `105`;94 天事实收入 ¥2,650.87 万、成本 ¥950.27 万;`sales_daily_facts.fulfillment_mode` |
| 人工成本录入(人工录单) | **已实施 P0** | 迁移 `106/108`;录入即扣客服备用金并写 `actual` 快照;无登记单/审批/报销;客服只能使用本人账户 |
| 履约方式统一 | **已实施 P0** | 迁移 `107`;316,585 项已回填,四项计数与总纲 §二 一致;订单页、成本快照、销售事实只读 `fulfillment_mode` |
| 人工商品归一 | **未实施(P1)** | 人工单按 `spec.skuId` 建 `man:<skuId>`;历史 11,349 项 `tpl:*` 商品待复核 |
| 影子总账 | 未实施 | 现有财务页仍是 `UNION ALL` 业务事件拼装,不是复式总账 |
| 退款冲减 / 平台对账 / 期间关账 | 未实施 | 仅方案 |
> 分支状态(2026-10-23):原 `103–114` 十二个迁移已合并为 `103–107` 五个,另加 `108` 清理迁移(删人工支出登记两表);已快进合并到 `dev`(tip `43f402cf`),本地库已按新 schema 改造并重跑回填,**未推送远端、未部署生产**;生产口径仍以 `main` 为准。
> 财务与履约口径以 [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) 为准。
## 三、统一实施顺序
```text
0. 统一履约事实(fulfillment_mode + 成本模型正交) 已完成 P0(迁移 107)
1. 商品主数据 + 渠道 SKU 映射 已完成 P0(仅自动发货/接单平台)
2. 成本中心 + 销售事实 已完成 P0
2.5 人工成本链路收敛(人工录单 → 扣备用金 → 写快照) 已完成 P0(迁移 106/108)
3. 人工商品归一与上线后人工成本全覆盖 未实施(下一阶段)
4. 退款冲减与异常队列 未实施
5. 影子总账(订单、工单、押金、提现、寄卖、售后) 未实施
6. 平台对账、报表、期间关账 未实施
```
**第 0 步已完成。** 迁移、回填、代码改造与验收结果见 [成本中心与履约模型](成本中心与履约模型.md) §六、§八。下一步只做第 3 步人工商品归一,不要同时改退款或总账。
## 四、当前必须拍板
| # | 问题 | 当前结论 | 影响 |
| --- | --- | --- | --- |
| 1 | 收入金额口径 | ✅ 用户实付(`orders.total_amount`) | 收入基数 |
| 2 | 收入确认时点 | ✅ 先按 `paid_at` 归属销售日;成本在快照生成后回填 | 利润表与预收账款 |
| 3 | 打手报酬 | ✅ 支出/成本,总额法 | 履约成本 |
| 4 | 退款/仲裁 | ✅ 暂不实现,只预留反向凭证 | 后续冲减 |
| 5 | 人工支出如何入账 | ✅ 逐单实际金额;从客服备用金扣款;客服只能用本人账户 | 人工成本与备用金 |
| 6 | 历史人工支出 | ✅ **不补录**,只取少量样本校准 | 上线范围 |
| 7 | 电子凭证是否作为分类 | ✅ **不作为履约/成本分类**,只是核销码状态 | 报表口径 |
| 8 | 平台服务费/支付通道费 | ⏳ 待定 | 费用科目与对账 |
| 9 | 寄卖货款成本确认时点 | ⏳ 待定 | 存货/采购成本 |
| 10 | 是否需要发票/税务、是否多币种 | ⏳ 待定 | 当前按 CNY、无税务实现 |
## 五、现行与参考文档
| 文档 | 状态 | 用途 |
| --- | --- | --- |
| [财务与履约口径总纲-2026-10-23.md](财务与履约口径总纲-2026-10-23.md) | **现行唯一口径** | 履约方式、成本模型、人工全覆盖、历史策略、实施顺序、运营日检与验收 SQL |
| [成本中心与履约模型.md](成本中心与履约模型.md) | 现行 | 商品、成本版本、快照、异常、销售事实的数据模型;迁移 `103–107`;履约回填;本地库原地改造;索引与性能 |
| [成本中心API契约.md](成本中心API契约.md) | 现行 | 成本中心接口字段替换总表、枚举、模块边界(后端 5 模块 + 前端 8 面板) |
| [人工支出与备用金.md](人工支出与备用金.md) | 现行(P0 已实施) | 人工录单字段/流程/权限、客服备用金台账、本人账户与编号规则 |
| [财务系统集成方案.md](财务系统集成方案.md) | 现行方案(总账未实施) | 复式记账、总账表、对账、关账 |
| [影子总账说明.md](影子总账说明.md) | 现行说明(未实施) | 影子总账是什么、和钱包流水的区别、对账与转正标准 |
| [项目全量分析报告-2026-10-17.md](项目全量分析报告-2026-10-17.md) | 历史参考 | 2026-10-17 架构与风险;财务口径以总纲为准 |
| [接单模板匹配引擎重构设计.md](接单模板匹配引擎重构设计.md) | 现行(P0/P1 已实施) | `kuaishou-91 / pdd / douyin-mashida` 三来源匹配引擎 |
| [履约配置/多发货平台与电子凭证整体链路.md](履约配置/多发货平台与电子凭证整体链路.md) | 现行 | 进单、履约、领取、电子凭证的整体链路 |
| [affiliate-dash-发货平台/affiliate-dash对接.md](affiliate-dash-发货平台/affiliate-dash对接.md) | 现行 | affiliate-dash 自动履约接口与字段 |
| [履约配置/cloudtentacles发货平台.md](履约配置/cloudtentacles发货平台.md) | 历史参考 | 已下线通道的第三方接口样例,不代表现行实现 |
| [91卡券/6.开发设计.md](91卡券/6.开发设计.md) | 现行 | `kuaishou-91` 来源的 91 侧接入设计 |
| [抖音-码速达/00-总览.md](抖音-码速达/00-总览.md) | 现行 | 抖音码速达接入总览与增量记录 |
| [抖音-码速达/12-按SKU分类改造总设计.md](抖音-码速达/12-按SKU分类改造总设计.md) | 现行 | 抖音三层分流与载体唯一 |
| [部署启动与数据库重建.md](部署启动与数据库重建.md) | 现行 | 本地/生产启动、迁移、重建 |
| [数据库备份与恢复.md](数据库备份与恢复.md) | 现行 | 备份、恢复、OSS |
| [数据库SQL约束与运维.md](数据库SQL约束与运维.md) | 现行 | SQL 护栏与生产观测 |
### SQL 草案(未接入迁移)
草案只作设计与复盘依据;接入 `apps/backend/src/db/migrations/` 时再拆成 `NNN_slug.sql`,并先跑 `npm run check:sql`。
| 文件 | 用途 | 接入前必须处理 |
| --- | --- | --- |
| [drafts/2026-10-17-载体判定与人工块量化.sql](drafts/2026-10-17-载体判定与人工块量化.sql) | 载体分布/人工块量化查询、`carrier_type` 判定与回填 | **已过时**:`carrier_type` 已从商品/成本/快照/异常表删除;只读查询里的口径结论已吸收进总纲 §二 |
| [drafts/2026-10-17-成本中心与销售事实-DDL草案.sql](drafts/2026-10-17-成本中心与销售事实-DDL草案.sql) | `product_catalog`、`channel_product_mappings`、`cost_items/versions/snapshots/exceptions`、`sales_daily_facts` | 已落地为 `103`–`105`;草案里的 `carrier_type` 已被 `cost_model` / `fulfillment_mode` 取代,仅作设计追溯 |
| [archive/2026-10-23/2026-10-17-人工支出登记-DDL草案.sql](archive/2026-10-23/2026-10-17-人工支出登记-DDL草案.sql) | `manual_fulfillment_cases`、`manual_expense_records`、`manual_expense_events` | **已作废**:`manual_expense_records` / `manual_expense_events` 已随迁移 `108` 删除,人工成本改走「人工录单 → 扣备用金 → 写快照」;文件已移入 archive |
## 六、厂商协议与外部资料
这些目录是平台方文档或抓取资料,**不作为本项目实现说明**:
| 目录 | 内容 |
| --- | --- |
| `91卡券/` | 91 卡券公开接口、签名、加密示例(项目接入结论见 `91卡券/6.开发设计.md`) |
| `行业电子凭证/` | 快手电子凭证接口、售后、测试指南 |
| `发货平台-2/` | 早期发货平台协议,现行为 `affiliate_dash`;保留作历史接口对照 |
| `抖音-码速达/接口API/` | 抖音码速达出网接口 |
| `抖音-码速达/消息推送/` | 抖音码速达推送消息字段与签名 |
## 七、历史文档
| 位置 | 说明 |
| --- | --- |
| [archive/README.md](archive/README.md) | 2026-10-08 及更早的阶段分析、寄卖方案、性能快照、一次性迁移检查脚本;2026-10-17 复核文档 |
| [archive/2026-10-17/载体判定与成本中心落地-复核与草案.md](archive/2026-10-17/载体判定与成本中心落地-复核与草案.md) | 2026-10-17 第二轮复核与数据量化;结论已吸收进现行成本中心文档,仅作历史追溯 |
| [archive/2026-10-23/](archive/2026-10-23/) | 2026-10-23 重写前的四篇:`成本中心与三块履约模型`、`人工支出登记落地方案`、`客服备用金台账实施方案`、`财务履约改造交接总结`;结论已分别并入现行 5 篇文档 |
## 八、维护规则
1. 改代码影响业务口径时,先改现行文档,再提交代码。
2. 文档头部必须写「状态 + 最后校准日期 + 代码基线」。
3. 旧分析不要在原文件上继续堆结论;新建当期报告,旧文件移入 `docs/archive/<日期>/`。
4. 行号只用于当期基线;跨版本引用优先写文件与函数名。
5. 新增来源时只加一个 `ProductMatchSourceKey` + 一个适配器;**91 + 快手 send-code 永远算一个 `kuaishou-91`**。
6. 成本金额只改 `cost_versions`,不要在多个业务表直接改价;历史订单只读 `cost_snapshots`。
7. 报表维度统一用 `canonical_product_id + shop_id + stat_date`,不要直接用原始 `sku_code` 或 `orders.total_amount`。
8. 新增 SQL 草案放 `docs/drafts/`,命名 `<日期>-<主题>.sql`;**不得**直接放进 `apps/backend/src/db/migrations/`(后端启动会自动迁移),接入时再拆编号并先跑 `npm run check:sql`。
9. 财务系统实现顺序以本索引 §三 为准;单篇文档里的分期若与本索引冲突,以本索引为准。