feat(finance): 完成成本快照运行层、销售事实与人工支出登记

迁移 108-111:快照业务时间与预估转实际、销售事实表、系统成本项、公司人工支出登记。接单平台按工单实际 reward 入账;人工支出支持登记/审批/驳回/报销并写 actual 快照。新增销售毛利页、人工支出页与订单入口。
This commit is contained in:
yml2213
2026-10-22 16:41:03 +08:00
parent 15989af87c
commit 0889235870
39 changed files with 4824 additions and 143 deletions
+15 -15
View File
@@ -1,6 +1,6 @@
# order_site 文档索引
> 最后校准:2026-10-18,代码基线 `main @ 7542d547`。
> 最后校准:2026-10-22,代码基线 `dev @ 15989af8 + 财务 103–111`。
> 本文是 `docs/` 的唯一入口。新增文档必须在上表登记状态;过期文档不再直接改写结论,统一移入 `docs/archive/`。
## 一、先记住五条口径
@@ -35,7 +35,7 @@
| 名称 | 业务含义 | 当前状态 |
| --- | --- | --- |
| `manual_expenses` | **客服备用金支出明细**:客服从自己的备用金里充值/采购/赔偿,减少客服余额 | 已实施(迁移 100) |
| `manual_expense_records` | **公司人工支出/垫付登记**:按订单/成本项记录公司实际付出去的钱、付款人、收款人、凭证、审批 | 仅草案,未实施 |
| `manual_expense_records` | **公司人工支出/垫付登记**:按订单/成本项记录公司实际付出去的钱、付款人、收款人、凭证、审批 | 已实施 P0(迁移 111) |
后续做财务系统时,**不要把 `manual_expenses` 直接改名或复用为 `manual_expense_records`**。两者业务含义、审批链和报表口径不同,应通过 `fund_expense_id` 建立关联。
@@ -54,22 +54,22 @@
| --- | --- | --- |
| 客服备用金台账 | **已实施 P0** | `fund_accounts` / `fund_entries` / `manual_expenses` / `fund_reconciliations`;后台页面、权限、审计已完成 |
| 后台用户中文显示名 | **已实施** | `admin_users.display_name`,备用金姓名触发器同步;审计、登录记录、任务处理人优先显示中文名 |
| 商品主数据 + 渠道 SKU 映射 | **已实施 P0(feat 分支)** | 迁移 `103`(映射消歧在 `106`);`product_catalog` / `channel_product_mappings`,后台「商品与成本」页支持维护、历史订单项回填与按载体分区 |
| 成本中心 | **已实施 P0(feat 分支)** | 迁移 `104` + 修正 `105`;`107` 增加商品履约载体。`cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions` 支持版本、预览、快照、异常队列、自动发货价格导入 |
| 销售事实 / 订单毛利 | 未实施 | `sales_daily_facts` 仍是 DDL 草案;现有财务页不能按商品/店铺/载体算真实毛利 |
| 公司人工支出登记 | 未实施 | 与已实施的客服备用金支出不是同一张表 |
| 商品主数据 + 渠道 SKU 映射 | **已实施 P0(dev 分支)** | 迁移 `103`(映射消歧在 `106`);`product_catalog` / `channel_product_mappings`,后台「商品与成本」页支持维护、历史订单项回填与按载体分区 |
| 成本中心 | **已实施 P0(dev 分支)** | 迁移 `104/105/107/108/110`;`cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions` 支持版本、预览、快照、异常队列、自动发货价格导入;接单平台按工单实际报酬、人工按支出登记写入实际快照 |
| 销售事实 / 订单毛利 | **已实施 P0(dev 分支)** | 迁移 `109`;`sales_daily_facts` 按店铺×日期×标准商品×载体汇总,未归一商品单独成行;后台新增「销售毛利」页,成本缺失会显式告警 |
| 公司人工支出登记 | **已实施 P0(dev 分支)** | 迁移 `111`;`manual_expense_records` / `manual_expense_events`,后台「人工支出」页支持登记、审批、驳回、报销;与客服备用金 `manual_expenses` 通过 `fund_expense_id` 关联 |
| 影子总账 | 未实施 | 现有财务页仍是 `UNION ALL` 业务事件拼装,不是复式总账 |
| 平台对账 / 期间关账 | 未实施 | 仅方案 |
> 分支状态(2026-10-22):商品主数据、渠道映射、成本中心与自动发货价格在 `feat/cost-center-wip`,尚未合并 `main`、未部署生产;生产口径仍以 `main` 为准。
> 分支状态(2026-10-22):商品主数据、渠道映射、成本中心、成本快照运行层、销售事实与公司人工支出登记在 `dev` 分支(原 `feat/cost-center-wip` 已合并),**尚未合并 `main`、未部署生产**;生产口径仍以 `main` 为准。
## 三、统一实施顺序
```text
1. 商品主数据 + 渠道 SKU 映射 已完成 P0
2. 成本中心 + 销售事实(先接收入与标准成本) 成本中心已完成 P0;销售事实未实施
3. 订单毛利 / 店铺日报 未实施
4. 公司人工支出登记(桥接现有客服备用金支出) 未实施
2. 成本中心 + 销售事实(先接收入与标准成本) 已完成 P0(迁移 108/109)
3. 订单毛利 / 店铺日报 已完成 P0(销售毛利页,成本缺失显式告警)
4. 公司人工支出登记(桥接现有客服备用金支出) 已完成 P0(迁移 111)
5. 影子总账(订单、工单、押金、提现、寄卖、售后) 未实施
6. 平台对账、报表、期间关账 未实施
```
@@ -81,7 +81,7 @@
| # | 问题 | 当前结论 | 影响 |
| --- | --- | --- | --- |
| 1 | 收入金额口径 | ✅ 用户实付(`orders.total_amount`) | 收入基数 |
| 2 | 收入确认时点 | ⏳ 待定:付款 / 发货 / 验收 / 售后期结束 | 利润表与预收账款 |
| 2 | 收入确认时点 | ✅ 先按 `paid_at` 归属销售日;成本在快照生成后回填 | 利润表与预收账款 |
| 3 | 打手报酬 | ✅ 支出/成本,总额法 | 履约成本 |
| 4 | 退款/仲裁 | ✅ 暂不实现,只预留反向凭证 | 后续冲减 |
| 5 | 人工支出如何入账 | ✅ 以人工支出登记为入口;需与客服备用金支出桥接 | 人工成本与应付垫付人 |
@@ -95,8 +95,8 @@
| --- | --- | --- |
| [项目全量分析报告-2026-10-17.md](项目全量分析报告-2026-10-17.md) | 参考 | 当前架构、业务链路、风险与改进路线;代码基线早于备用金实现,涉及财务部分以本索引为准 |
| [财务系统集成方案.md](财务系统集成方案.md) | 现行方案(未实施) | 财务系统边界、复式记账模型、核心表、API、分期落地 |
| [成本中心与三块履约模型.md](成本中心与三块履约模型.md) | 现行(P0 已实施) | 自动发货/接单平台/人工客服三块、商品映射与成本中心;销售事实仍为方案 |
| [人工支出登记落地方案-2026-10-17.md](人工支出登记落地方案-2026-10-17.md) | 现行方案(未实施) | 公司人工支出登记:字段、入口、状态机、权限、与备用金/成本中心/总账的衔接 |
| [成本中心与三块履约模型.md](成本中心与三块履约模型.md) | 现行(P0 已实施) | 自动发货/接单平台/人工客服三块、商品映射、成本中心与销售事实 |
| [人工支出登记落地方案-2026-10-17.md](人工支出登记落地方案-2026-10-17.md) | 现行(P0 已实施) | 公司人工支出登记:字段、入口、状态机、权限、与备用金/成本中心/总账的衔接 |
| [影子总账说明.md](影子总账说明.md) | 现行说明(未实施) | 影子总账是什么、和钱包流水的区别、对账与转正标准 |
| [客服备用金台账实施方案-2026-10-18.md](客服备用金台账实施方案-2026-10-18.md) | **已实施 P0** | 客服备用金账户、流水、支出、对账、权限与上线记录 |
| [接单模板匹配引擎重构设计.md](接单模板匹配引擎重构设计.md) | 现行(P0/P1 已实施) | `kuaishou-91 / pdd / douyin-mashida` 三来源匹配引擎 |
@@ -117,8 +117,8 @@
| 文件 | 用途 | 接入前必须处理 |
| --- | --- | --- |
| [drafts/2026-10-17-载体判定与人工块量化.sql](drafts/2026-10-17-载体判定与人工块量化.sql) | 载体分布/人工块量化查询、`carrier_type` 判定与回填 | 只读查询可直接用;DDL 部分按当前迁移号顺延,不占用 100/101 |
| [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` | 商品与成本部分已落地为 `102/103/104`;剩余销售事实按新迁移号继续,草案不再作为建表依据 |
| [drafts/2026-10-17-人工支出登记-DDL草案.sql](drafts/2026-10-17-人工支出登记-DDL草案.sql) | `manual_fulfillment_cases`、`manual_expense_records`、`manual_expense_events` | 已改用 `*_manual_expense_records_*` 命名,并补 `fund_expense_id`;接入前仍需复核与迁移号 |
| [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–109`);系统成本项在 `110`;草案仅作设计追溯,不再作为建表依据 |
| [drafts/2026-10-17-人工支出登记-DDL草案.sql](drafts/2026-10-17-人工支出登记-DDL草案.sql) | `manual_fulfillment_cases`、`manual_expense_records`、`manual_expense_events` | 人工支出登记已落地为 `111`;轻量人工 case 仍为草案 |
## 六、厂商协议与外部资料
@@ -1,12 +1,10 @@
-- ============================================================================
-- 人工支出登记 + 轻量人工处理记录(建表草案)
-- ----------------------------------------------------------------------------
-- 状态:草案(DRAFT)。**未接入** apps/backend/src/db/migrations。
-- 依赖:本文引用 product_catalog / cost_items / cost_snapshots / manual_expenses,
-- 必须**在** `2026-10-17-成本中心与销售事实-DDL草案.sql` **之后**应用;
-- `manual_expenses` 已由迁移 100 创建(客服备用金支出)。
-- 当前已使用迁移至 107(成本中心落在 103–107);本文建议顺延为
-- `108_manual_cases.sql`、`109_manual_expenses.sql`,接入时按实际最大号调整并先跑 `npm run check:sql`。
-- 状态:已实施 P0。`manual_expense_records` / `manual_expense_events` 已接入
-- `111_manual_expense_records.sql`;`manual_fulfillment_cases` 仍未实施。
-- 依赖:product_catalog / cost_items / cost_snapshots / manual_expenses。
-- 当前已使用迁移至 111(成本中心 103–108,系统成本项 110,人工支出 111)。
-- 基线:main @ 7542d547;依据:2026-10-17 业务口径确认 + 2026-10-18 备用金落地复核。
--
-- 重要命名边界:
@@ -1,13 +1,14 @@
-- ============================================================================
-- 通用成本中心 + 标准商品 + 销售事实(建表草案)
-- ----------------------------------------------------------------------------
-- 状态:部分落地。商品主数据 + 渠道映射 + 成本中心已接入 `103_product_catalog.sql`、
-- `104_cost_center.sql`、`105_cost_center_bootstrap_fix.sql`;本文件仅保留设计追溯。
-- 尚未实施的 `sales_daily_facts` 等后续内容,接入时从新迁移号继续,并先跑 `npm run check:sql`。
-- 状态:商品、成本、销售事实均已落地。商品主数据 + 渠道映射接入 `103_product_catalog.sql`,
-- 成本中心接入 `104_cost_center.sql` / `105_cost_center_bootstrap_fix.sql` / `108_cost_snapshot_runtime.sql`,
-- 销售事实接入 `109_sales_daily_facts.sql`;本文件仅保留设计追溯。
-- 注意:实际 `sales_daily_facts.canonical_product_id` 允许为空(未归一桶),与下方草案的 NOT NULL 不同。
-- 基线:main @ 7542d547;数据依据:本地只读克隆(生产快照,orders 316,597,数据截至 2026-10-14)。
-- 金额单位:分(BIGINT)。本文件所有 *_fen 列均为分。
-- 设计依据:docs/成本中心与三块履约模型.md(三块载体、成本版本与快照)、docs/财务系统集成方案.md。
-- 当前状态:商品主数据、渠道映射、成本中心已实施 P0;销售事实未实施。客服备用金支出已实施,但不是本文件的成本中心。
-- 当前状态:商品主数据、渠道映射、成本中心、销售事实均已实施 P0。
--
-- 目标(业务原话):以后改成本只在一个地方。
-- -> 所有成本金额只写 cost_versions;业务表只保存 cost_snapshot_id 与派生金额,永不回写历史。
@@ -1,11 +1,11 @@
# 人工支出登记落地方案(2026-10-18 修订)
> 状态:**现行方案(未实施)**
> 最后校准:2026-10-18
> 代码基线:`main @ 7542d547`
> 状态:**已实施 P0(`dev` 分支,迁移 111)**
> 最后校准:2026-10-22
> 代码基线:`dev @ 15989af8 + 财务 108/109/110/111`
> 依据:业务口径「人工块当前不以 SLA 监管为目标,先把流程搞清楚:哪个客服处理了哪些东西、付了多少钱、什么项目、关联哪个订单」。
> 数据来源:本地只读克隆(生产快照,数据截至 2026-10-14)+ 现有代码盘点。
> 重要:**客服备用金支出已经实施**(`manual_expenses`),但本文的**公司人工支出登记**(`manual_expense_records`)尚未实施;两张表不是一回事,不能直接复用或改名。
> 重要:**客服备用金支出已经实施**(`manual_expenses`);**公司人工支出登记**(`manual_expense_records`)也已实施,两张表通过 `fund_expense_id` 关联,不是同一张表。
> 相关文档:[成本中心与三块履约模型.md](成本中心与三块履约模型.md) §8 · [财务系统集成方案.md](财务系统集成方案.md) §八 · [客服备用金台账实施方案](客服备用金台账实施方案-2026-10-18.md) ·
> DDL 草案 [drafts/2026-10-17-人工支出登记-DDL草案.sql](drafts/2026-10-17-人工支出登记-DDL草案.sql)
@@ -16,22 +16,32 @@
| 表 | 业务含义 | 当前状态 | 关键字段 |
| --- | --- | --- | --- |
| `manual_expenses` | **客服备用金支出**:客服从自己的备用金账户里充值/采购/赔偿 | **已实施** | `account_id` / `fund_entry_id` / `category` / `payee_*` / `evidence_json` |
| `manual_expense_records` | **公司人工支出/垫付登记**:按订单/成本项记录公司实际付出去的钱 | 仅草案 | `order_id` / `order_item_id` / `cost_item_id` / `paid_by_admin_user_id` / `status` / `cost_snapshot_id` |
| `manual_expense_records` | **公司人工支出/垫付登记**:按订单/成本项记录公司实际付出去的钱 | **已实施 P0(迁移 111)** | `order_id` / `order_item_id` / `cost_item_id` / `paid_by_admin_user_id` / `status` / `cost_snapshot_id` |
结论:
1. 客服侧已经收口的是“备用金余额与用途”,解决“客服手里有多少钱、这笔钱花到哪”。
2. 财务侧还缺的是“公司口径的实际支出/垫付”,解决“公司为哪个订单、哪个成本项、付给谁、谁垫的、有没有审批和凭证”。
2. **公司口径的实际支出/垫付已落地**:后台「人工支出」页(`/admin/manual-expenses`)支持登记、审批、驳回、报销;通过后按成本项写 `cost_snapshots`,没有有效成本版本时进入异常队列。
3. 两张表通过 `fund_expense_id` 关联:如果这笔公司支出来源于客服备用金,就填;公司直付则留空。
4. **不要**把 `manual_expenses` 直接改名为 `manual_expense_records`,也不要让两张表共用索引/约束名。
实现落点(2026-10-22):
- 迁移:`apps/backend/src/db/migrations/111_manual_expense_records.sql`
- 服务:`apps/backend/src/services/finance/manual-expense-service.ts`
- 接口:`apps/backend/src/routes/admin/finance.ts` 的 `/finance/manual-expenses*`
- 页面:`apps/frontend/src/pages/admin/AdminManualExpensePage.tsx`,入口 `/admin/manual-expenses`
- 订单入口:订单详情「登记人工支出」按钮,自动带入订单 ID
- 权限:查看 `finance.view` / `fund.view`,登记 `fund.expense` / `finance.config`,审核 `finance.review`
- 成本快照:通过后以 `subject_type='manual_case'`、`subject_id=expense.id` 写 `actual` 快照;同一订单项多笔支出可累加,不会互相覆盖
---
## 一、结论先行
1. **订单里的数据足够预填 90%**:店铺、商品、规格、数量、用户实付、支付时间、平台单号、履约标签、状态,后台订单列表/详情已经全部具备。客服实际只需要补 **4 件事**:渠道/项目、金额、收款方、凭证(外加默认带出的「谁、什么时候」)。
2. **现有财务页没有“支出”这一侧**。财务页现有 7 个账目类别(订单收款、订单退款、打手报酬、打手提现、打手充值、打手资金回收、售后追缴退还)**全部是收款或打手侧资金**;客服备用金支出已经落在 `fund` 模块,但还没有汇总进财务页,也没有公司口径的人工支出/垫付登记。
2. **原有财务页没有“支出”这一侧**:7 个账目类别全部是收款或打手侧资金。现在公司人工支出已有独立「人工支出」页;客服备用金支出仍在 `fund` 模块,两者通过 `fund_expense_id` 桥接。
3. **落地成本低、风险小**:不需要改订单主表,不需要新角色体系(现有 `admin/finance/operator/support` 四角色 + `finance.*` 权限即可覆盖),只需新增「公司人工支出登记」表 + 订单侧入口 + 财务侧新类别。
4. **登记必须“发生在垫付当天”**才有监管价值;事后补记只能算账,不能算监管。
5. **本轮只补公司口径**:客服备用金台账已完成,不重复做一套客服余额系统;通过 `fund_expense_id` 关联即可。
+1 -1
View File
@@ -9,7 +9,7 @@
>
> 边界:影子总账解决“钱怎么记、怎么对”,不负责“商品是什么、成本是多少、人工谁处理”。商品与成本见 [成本中心与三块履约模型.md](成本中心与三块履约模型.md),人工履约见同一文档第八节。
> 当前进度:客服备用金已实施;`finance_*` 表、分录、对账、转正均未实施。
> 当前进度:客服备用金、商品与成本中心、成本快照运行层、销售事实、公司人工支出登记已实施;`finance_*` 表、分录、对账、转正均未实施。
---
+61 -54
View File
@@ -1,8 +1,8 @@
# 成本中心与三块履约模型
> 状态:**现行(P0 已实施)**。商品主数据、渠道映射、成本项目/版本/快照/异常已落地;销售事实仍为后续方案。
> 最后校准:2026-10-18
> 代码基线:`main @ 7542d547` + 未提交的商品/成本中心 P0
> 状态:**现行(P0 已实施)**。商品主数据、渠道映射、成本中心、成本快照运行层、销售事实与公司人工支出登记已落地;轻量人工 case 与影子总账仍为后续方案。
> 最后校准:2026-10-22
> 代码基线:`dev @ 15989af8 + 财务 108/109/110/111`
> 数据基线:2026-10-17 生产库只读聚合(`default_transaction_read_only=on`,仅 SELECT,无写入)
> 实施顺序以 [README.md](README.md) §三 为准;本文负责“商品、成本、销售事实”的数据模型,不重复总账与页面设计。
> 关联:
@@ -18,32 +18,33 @@
| 能力 | 状态 |
| --- | --- |
| 客服备用金支出(`manual_expenses`) | **已实施**;只解决客服备用金余额与用途,不等于公司人工支出登记 |
| 商品主数据 / 渠道 SKU 映射 | **已实施 P0**;迁移 `102` + 匹配键修正 `105`,后台「商品与成本」页可批量初始化、维护与回填历史订单项 |
| `cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions` | **已实施 P0**;迁移 `103` + 修正 `104`,支持版本解析、预览、快照、异常队列 |
| 销售事实 / 订单毛利 | 未实施;`sales_daily_facts` 仍为草案 |
| 公司人工支出登记(`manual_expense_records`) | 未实施 |
| 商品主数据 / 渠道 SKU 映射 | **已实施 P0**;迁移 `103` + 匹配键修正 `106`,后台「商品与成本」页可批量初始化、维护与回填历史订单项 |
| `cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions` | **已实施 P0**;迁移 `104` + 修正 `105`,`107` 增加商品载体,`108` 增加业务时间与预估/实际替代 |
| 销售事实 / 订单毛利 | **已实施 P0**;迁移 `109`,`sales_daily_facts` + 后台「销售毛利」页,未归一商品单独成行 |
| 公司人工支出登记(`manual_expense_records`) | **已实施 P0**;迁移 `111`,支持登记/审批/驳回/报销;轻量人工 case 尚未实施 |
| 影子总账 | 未实施;必须在本文件的成本与销售事实之后 |
### 0.1 本期已实现边界
已实现:
- `product_catalog`、`channel_product_mappings`,以及 `order_items.canonical_product_id` / `normalized_quantity`;
- `product_catalog`、`channel_product_mappings`,以及 `order_items.canonical_product_id` / `normalized_quantity` / `revenue_amount_fen` / `revenue_basis`;
- 按 `provider + shop_id + platform_sku_code` 建映射,空 `shop_id` 为来源级映射、具体店铺优先;`provider` 必须与 `orders.provider` 一致(91 为 `91kaquan`,不是匹配层的 `kuaishou-91`,服务层会归一别名);
- 映射回填与 SKU 文本数量回填;
- 映射回填、SKU 文本数量回填与订单项收入固化(一单一品归整单,多品按等额拆分并标 `equal_split`);
- `cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions`;
- 成本版本优先级 `rule > product > shop > provider > global`;
- 订单项成本预览、成本快照、缺失成本异常;
- 成本版本优先级 `rule > product > shop > provider > global`,按 `paid_at` / `accepted_at` 等业务时间解析;
- 订单项成本预览、预估快照、工单验收实际快照、缺失成本异常;
- `sync-cost-finance` 脚本与定时任务:批量回填快照并重算销售事实;
- `sales_daily_facts` 与后台「销售毛利」页,未归一商品单独成行,成本缺失显式告警;
- 后台「商品与成本」页、`finance.view` / `finance.config` 权限与审计。
本期不做:
- `sales_daily_facts` 与订单毛利报表;
- 订单进单时自动写 `canonical_product_id` / `normalized_quantity`;
- 自动发货、工单验收、人工 case 在业务事务内自动生成成本快照;
- 上游 `cost_amount` 自动同步为 `cost_versions`;
- 多订单项订单的收入分摊(当前按订单总额传给成本解析器);
- 公司人工支出登记与影子总账。
- 订单进单时自动写 `canonical_product_id` / `normalized_quantity`(目前用后台回填);
- 上游 `cost_amount` 实时自动同步为 `cost_versions`(目前用价格导入脚本);
- 人工 case 在业务事务内自动生成成本快照;
- 退款按日冲减与退款金额字段;
- 影子总账。
---
@@ -141,6 +142,11 @@ product_catalog
上游自动发货商品价格用 `apps/backend/scripts/sync-affiliate-dash-prices.ts` 批量导入(价格清单见 `apps/backend/scripts/data/affiliate-dash-prices.json`):按 `aff:<skuCode>` 补建/更新商品,并给指定成本项生成 `scope=product` 的按件版本;金额取上游 `cost_amount`(分),价格变化时先停用旧版本再插入新版本,历史快照不变。示例:`npx tsx scripts/sync-affiliate-dash-prices.ts --cost-item-id=5`。
接单平台与人工客服各有一个系统成本项(迁移 `110_system_cost_items.sql`):
- `sys_work_order_reward`:工单验收后直接按 `work_orders.reward_amount` 写 `actual` 快照,版本金额 0 只是占位,不进入预估阶段;本地最近 30 天已回填 38,023 条实际快照,金额与工单 reward 逐条一致。
- `sys_manual_service`:人工支出登记通过后按登记金额写 `actual` 快照;成本版本先为 `draft` 占位,不参与预估,但允许人工支出使用实际金额入账。财务填写正式按单单价后可将版本改为 `active`。
### 3.2 渠道 SKU 映射
```text
@@ -311,54 +317,54 @@ cost_snapshots
```text
sales_daily_facts
stat_date -- Asia/Shanghai
stat_date -- Asia/Shanghai,按 paid_at 归属
provider
shop_id
canonical_product_id
sales_channel -- auto / work_order / manual
canonical_product_id -- 允许为空:未归一桶
carrier_type -- affiliate_dash / work_order / manual / shared / unknown
order_count
item_count
quantity -- 归一化件数(SKU 文本解析后)
gross_revenue_fen
refund_fen
refund_amount_fen
net_revenue_fen
auto_cost_fen
work_order_cost_fen
manual_cost_fen
platform_fee_fen
after_sales_loss_fen
gross_profit_fen
cost_amount_fen
cost_missing_count
cost_stage -- missing / partial / estimated / actual
gross_profit_fen
```
### 5.2 三个必须统一的字段
1. **商品**:`canonical_product_id`,不是原始 `sku_code`。
1. **商品**:`canonical_product_id`,不是原始 `sku_code`;为空表示未归一,报表单独成行,不能丢。
2. **数量**:`normalized_quantity`,不是简单的 `order_items.quantity`。
3. **收入**:`revenue_amount_fen` + `revenue_basis`,不是直接 `orders.total_amount`。
3. **收入**:`revenue_amount_fen` + `revenue_basis`,不是直接 `orders.total_amount`。一单一品归整单;多品当前按等额拆分,余数给最后一项。
收入口径建议:
收入口径(2026-10-22 已确认):
| 来源 | 当前字段 | 建议 |
| 来源 | 当前字段 | 口径 |
| --- | --- | --- |
| 91 | `maxAmount` | 明确是结算收入还是成本上限,再归一 |
| PDD | `order_amount` | 作为订单收入候选 |
| 抖音 | `pay_amount` | 作为买家支付收入候选 |
| 91 | `orders.total_amount` | 用户实付,已与快手 `paymentFen` 核验一致 |
| PDD | `orders.total_amount` | 用户实付 |
| 抖音 | `orders.total_amount` | 用户实付 |
### 5.3 退款日期
现在只有 `pay_status=refunded` 和 `updated_at`,不足以做按日净销售。建议补 `refunded_at` / `refund_amount_fen`,或从退款事件表聚合。
现在只有 `pay_status=refunded` 和 `updated_at`,不足以做按日净销售。`sales_daily_facts` 已预留 `refund_amount_fen`,但退款逻辑仍未接入;后续补 `refunded_at` / `refund_amount_fen` 或退款事件表。
### 5.4 统计实现
第一版可以用物化视图:
当前是增量重算表,不是物化视图:
```text
orders + order_items + channel_product_mappings + cost_snapshots
-> sales_daily_facts
-> sales_daily_facts(按日期范围 DELETE + INSERT)
```
数据量目前约 35 万订单、每天 4k+ 单,物化视图 + 索引足够;后续再改增量表。
后台入口:`/admin/sales-profit`。回填脚本:`npm run finance:sync -- --days=14 --mode=all`;定时任务 `cost-finance-sync` 每 5 分钟处理最近 7 天。成本缺失会写入 `cost_missing_count`,毛利在补齐成本前只作参考。
数据校验:本地 2026-07-10 ~ 2026-10-14 共 316,597 个已支付订单,其中 12 单没有订单项(¥2,480.60),无法归集到商品/成本,销售事实会排除并在页面单独提示;其余 316,585 个订单项收入与订单总额完全对平。
最近 30 天回填后,接单平台实际成本快照 38,023 条、金额 1,633,917.74 元;其中落在销售事实日期范围内的成本 1,563,232.98 元,与工单 reward 逐条一致;自动发货与人工客服仍因缺少映射/正式单价显示成本缺失。
---
@@ -548,22 +554,22 @@ flowchart LR
## 十、分期落地
### P0:商品与销售事实(先能做报表)
### P0:商品与销售事实(先能做报表)——已实施
- `product_catalog`
- `channel_product_mappings`
- `sales_daily_facts`(可先物化视图)
- 数量归一、收入口径、退款日期补齐
- `product_catalog`(迁移 `103/107`)
- `channel_product_mappings`(迁移 `103/106`)
- `sales_daily_facts`(迁移 `109`,日期范围重算表)
- 数量归一、收入固化;退款日期字段仍待补
### P1:成本中心影子期
### P1:成本中心影子期——已实施运行层
- `cost_items` / `cost_versions` / `cost_snapshots`
- 自动发货先接固定成本
- 工单先接现有规则金额
- 人工先接按单/按小时成本
- `cost_items` / `cost_versions` / `cost_snapshots`(迁移 `104/105/108`)
- 自动发货接固定成本与价格导入
- 接单平台:系统成本项 `sys_work_order_reward` 在工单验收后按 `reward_amount` 直接写实际快照
- 人工客服:系统成本项 `sys_manual_service` + 人工支出登记通过后写实际快照;正式单价版本待财务填写
- 缺失成本进异常队列
### P2:公司人工支出登记 + 轻量处理记录
### P2:公司人工支出登记 + 轻量处理记录——支出登记已完成,轻量 case 未实施
- 载体判定(`carrier_type`)
- 无载体自动建轻量 case(谁在处理哪个订单项)
@@ -590,14 +596,15 @@ flowchart LR
| 2 | 打手报酬是成本还是代收代付? | **支出/成本**:工单结算后打手会提现,我方实际付款给他们 → 按**总额法**(收入记用户实付全额,报酬记履约成本) | 业务确认 |
| 3 | 人工块的目标是什么? | **先做流程可见与支出可追溯**(谁处理了哪些、付了多少钱、什么项目、关联订单号、凭证),SLA/监管指标延后 | 业务确认 |
| 4 | 退款/仲裁怎么冲减? | **暂未接入,先预留**:字段、反向冲正关系与事件类型先留好,本轮不实现逻辑 | 业务确认 |
| 5 | 收入确认时点? | **2026-10-22 确认:先按 `paid_at` 归属销售日**;成本在快照生成后回填到同一销售日,后续再评估验收/售后期口径 | 业务确认 |
| 6 | 未归一商品怎么进报表? | **2026-10-22 确认:允许 `canonical_product_id` 为空,单独成“未归一”行**,保证总收入与订单总额对平 | 业务确认 |
### 11.2 仍待确认
1. 收入确认时点:付款 / 发货 / 验收 / 售后期结束?(金额口径已定 = 用户实付)
2. 自动发货的 `cost_amount` 是否稳定、是否含平台积分/汇率?
3. 人工支出按单还是按小时归集?(先按单登记,工时字段后续再加)
4. 平台服务费/支付通道费由谁承担、结算周期与账单口径?
5. 寄卖货款的采购成本确认时点?
1. 自动发货的 `cost_amount` 是否稳定、是否含平台积分/汇率?
2. 人工支出按单还是按小时归集?(先按单登记,工时字段后续再加)
3. 平台服务费/支付通道费由谁承担、结算周期与账单口径?
4. 寄卖货款的采购成本确认时点?
---
+25 -9
View File
@@ -1,9 +1,9 @@
# 财务系统集成方案
> 状态:**现行方案(未实施)**。本文描述 `finance_*` 总账层;当前代码尚未建表,现有财务页仍是 `UNION ALL` 业务事件拼装。
> 最后校准:2026-10-18
> 代码基线:`main @ 7542d547`
> 前置:商品主数据、渠道 SKU 映射、成本中心与销售事实必须先完成;商品映射与成本中心已完成 P0,销售事实仍待实施。实施顺序以 [README.md](README.md) §三 为准。
> 状态:**现行方案(总账层未实施)**。本文描述 `finance_*` 总账层;当前 `finance_*` 尚未建表,现有财务页仍是 `UNION ALL` 业务事件拼装。商品、成本中心、销售事实与公司人工支出登记已完成 P0。
> 最后校准:2026-10-22
> 代码基线:`dev @ 15989af8 + 财务 108/109/110/111`
> 前置:商品主数据、渠道 SKU 映射、成本中心、销售事实与公司人工支出登记必须先完成;这些前置已完成 P0。实施顺序以 [README.md](README.md) §三 为准。
> 目标:在**不破坏现有抢单、押金、结算、寄卖、提现链路**的前提下,为 order_site 增加一套可对账、可关账、可追溯的财务系统。
> 结论先说:**不要直接在 `worker_wallets` / `worker_wallet_ledgers` 上继续加字段。** 现有表是业务钱包与流水,不是会计总账;正确做法是新增复式记账底座,让现有钱包成为它的“余额投影”。
>
@@ -16,10 +16,11 @@
| 能力 | 状态 |
| --- | --- |
| 客服备用金台账(`fund_*` / 备用金 `manual_expenses`) | **已实施 P0**,见 [客服备用金台账实施方案](客服备用金台账实施方案-2026-10-18.md) |
| 商品主数据 / 渠道 SKU 映射 / 成本中心 | **已实施 P0(`feat/cost-center-wip`)**,迁移 `103/104/105/106/107`,含商品履约载体与自动发货价格版本,见 [成本中心与三块履约模型](成本中心与三块履约模型.md) |
| 商品主数据 / 渠道 SKU 映射 / 成本中心 | **已实施 P0(`dev` 分支)**,迁移 `103/104/105/106/107/108`,含商品履约载体、自动发货价格版本与成本快照运行层,见 [成本中心与三块履约模型](成本中心与三块履约模型.md) |
| `sales_daily_facts` / 订单级毛利 | **已实施 P0(`dev` 分支)**,迁移 `109`;后台「销售毛利」页按店铺/商品/载体汇总,未归一商品单独成行 |
| 公司人工支出登记 `manual_expense_records` | **已实施 P0(`dev` 分支)**,迁移 `111`;后台「人工支出」页支持登记、审批、驳回、报销,通过后写 `cost_snapshots` |
| `finance_accounts` / `finance_business_events` / `finance_journal_*` | 未实施 |
| `finance_settlements` / `finance_reconciliations` | 未实施 |
| 订单级收入/成本/毛利 | 未实施;成本中心已完成,仍需销售事实与收入分摊 |
| 现有 `admin-finance-service.ts` | 仍是业务事件 `UNION ALL`,不是总账 |
**不要复用客服备用金的 `manual_expenses` 作为公司人工支出表。** 两者口径不同;公司人工支出应使用 `manual_expense_records`,并通过 `fund_expense_id` 关联备用金支出。
@@ -384,7 +385,22 @@ postBusinessEvent({
### 5.2 API
建议新增前缀 `/api/v1/admin/finance`:
已实现(P0,销售事实、成本快照与人工支出):
```text
GET /api/v1/admin/finance/sales-profit/overview
GET /api/v1/admin/finance/sales-facts
POST /api/v1/admin/finance/sales-facts/rebuild
POST /api/v1/admin/cost-center/snapshots/sync
GET /api/v1/admin/finance/manual-expenses
GET /api/v1/admin/finance/manual-expenses/overview
POST /api/v1/admin/finance/manual-expenses
POST /api/v1/admin/finance/manual-expenses/:id/approve
POST /api/v1/admin/finance/manual-expenses/:id/reject
POST /api/v1/admin/finance/manual-expenses/:id/reimburse
```
总账层建议新增前缀 `/api/v1/admin/finance`:
```text
GET /accounts
@@ -474,12 +490,12 @@ POST /periods/:key/close
## 八、需要业务拍板的问题
> 2026-10-17 已确认 4 条口径,明细见 [成本中心与三块履约模型.md](成本中心与三块履约模型.md) §11。
> 2026-10-17 已确认 4 条口径,2026-10-22 追加确认收入时点与未归一商品口径;明细见 [成本中心与三块履约模型.md](成本中心与三块履约模型.md) §11。
| # | 问题 | 状态 | 影响 |
| --- | --- | --- | --- |
| 1 | 收入金额口径 | ✅ **已确认:收入 = 用户实付(`orders.total_amount`)**,与快手 `paymentFen` 数据核验 100% 一致 | 收入基数 |
| 2 | 收入确认时点:付款 / 发货 / 验收 / 售后期结束? | ⏳ 待定(金额口径已定) | 决定利润表与预收账款 |
| 2 | 收入确认时点:付款 / 发货 / 验收 / 售后期结束? | ✅ **先按 `paid_at` 归属销售日**;成本快照生成后回填到同一销售日 | 决定利润表与预收账款 |
| 3 | 平台结算周期与账单口径(91、快手、PDD、抖音、affiliate-dash) | ⏳ 待定 | 决定对账与应收 |
| 4 | 打手报酬是“成本”还是“代收代付”? | ✅ **已确认:支出/成本**(最终提现打款),按**总额法** | 收入总额法/净额法 |
| 5 | 寄卖货款的采购成本确认时点 | ⏳ 待定 | 决定存货/成本 |