- 新增迁移 107_product_catalog_carrier:product_catalog 增加 carrier_type, 自动发货只认 fulfillment_tasks.executor_key='affiliate_dash' 的履约证据 (28 个上游 SKU),接单模板商品统一归为 work_order(662 个) - 页面按「全部 / 自动发货 / 接单平台 / 人工客服 / 共用成本」分区; 自动发货只展示自动发货 SKU 列表与采购成本,不展示商品目录/渠道映射 - 新增「同步自动发货商品」接口与按钮,按 aff:<skuCode> 幂等补建 - 列表统一接入公共分页 buildAdminTablePagination,支持 10/20/50/100 每页条数 - 标准商品、自动发货 SKU、渠道映射、成本项目、成本版本支持删除, 带引用保护(映射/版本/快照/订单/接单规则)与生效版本先停用约束
617 lines
25 KiB
Markdown
617 lines
25 KiB
Markdown
# 成本中心与三块履约模型
|
||
|
||
> 状态:**现行(P0 已实施)**。商品主数据、渠道映射、成本项目/版本/快照/异常已落地;销售事实仍为后续方案。
|
||
> 最后校准:2026-10-18
|
||
> 代码基线:`main @ 7542d547` + 未提交的商品/成本中心 P0
|
||
> 数据基线:2026-10-17 生产库只读聚合(`default_transaction_read_only=on`,仅 SELECT,无写入)
|
||
> 实施顺序以 [README.md](README.md) §三 为准;本文负责“商品、成本、销售事实”的数据模型,不重复总账与页面设计。
|
||
> 关联:
|
||
> - [项目全量分析报告-2026-10-17.md](项目全量分析报告-2026-10-17.md)
|
||
> - [影子总账说明.md](影子总账说明.md)
|
||
> - [财务系统集成方案.md](财务系统集成方案.md)
|
||
> - [人工支出登记落地方案-2026-10-17.md](人工支出登记落地方案-2026-10-17.md)
|
||
|
||
---
|
||
|
||
## 〇、当前进度与边界
|
||
|
||
| 能力 | 状态 |
|
||
| --- | --- |
|
||
| 客服备用金支出(`manual_expenses`) | **已实施**;只解决客服备用金余额与用途,不等于公司人工支出登记 |
|
||
| 商品主数据 / 渠道 SKU 映射 | **已实施 P0**;迁移 `102` + 匹配键修正 `105`,后台「商品与成本」页可批量初始化、维护与回填历史订单项 |
|
||
| `cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions` | **已实施 P0**;迁移 `103` + 修正 `104`,支持版本解析、预览、快照、异常队列 |
|
||
| 销售事实 / 订单毛利 | 未实施;`sales_daily_facts` 仍为草案 |
|
||
| 公司人工支出登记(`manual_expense_records`) | 未实施 |
|
||
| 影子总账 | 未实施;必须在本文件的成本与销售事实之后 |
|
||
|
||
### 0.1 本期已实现边界
|
||
|
||
已实现:
|
||
|
||
- `product_catalog`、`channel_product_mappings`,以及 `order_items.canonical_product_id` / `normalized_quantity`;
|
||
- 按 `provider + shop_id + platform_sku_code` 建映射,空 `shop_id` 为来源级映射、具体店铺优先;`provider` 必须与 `orders.provider` 一致(91 为 `91kaquan`,不是匹配层的 `kuaishou-91`,服务层会归一别名);
|
||
- 映射回填与 SKU 文本数量回填;
|
||
- `cost_items` / `cost_versions` / `cost_snapshots` / `cost_exceptions`;
|
||
- 成本版本优先级 `rule > product > shop > provider > global`;
|
||
- 订单项成本预览、成本快照、缺失成本异常;
|
||
- 后台「商品与成本」页、`finance.view` / `finance.config` 权限与审计。
|
||
|
||
本期不做:
|
||
|
||
- `sales_daily_facts` 与订单毛利报表;
|
||
- 订单进单时自动写 `canonical_product_id` / `normalized_quantity`;
|
||
- 自动发货、工单验收、人工 case 在业务事务内自动生成成本快照;
|
||
- 上游 `cost_amount` 自动同步为 `cost_versions`;
|
||
- 多订单项订单的收入分摊(当前按订单总额传给成本解析器);
|
||
- 公司人工支出登记与影子总账。
|
||
|
||
---
|
||
|
||
## 一、先纠正一个口径:三块不是“订单来源”,是“执行载体”
|
||
|
||
同一个来源的订单,可能走自动发货、接单平台或人工。正确的拆分维度是**订单项最终由谁履约**:
|
||
|
||
| 块 | 执行载体 | 成本特征 | 监管重点 |
|
||
| --- | --- | --- | --- |
|
||
| ① 自动发货 | `affiliate_dash` 履约任务 | 固定成本,按皮肤/SKU,很少变化 | 上游成本、店铺/日期/皮肤销量 |
|
||
| ② 接单平台 | `work_orders` + 拼单份额 | 变动成本,按模板/单价/固定价/拼单 | 发单价格、打手提现、售后追缴、毛利 |
|
||
| ③ 人工客服 | 目前**无载体** | 人工工时/按单服务成本 | 谁处理、何时完成、证据、成本、异常 |
|
||
|
||
硬不变式:
|
||
|
||
```text
|
||
一个订单项 = 订单骨架 + 买家凭证 + 一个执行载体
|
||
执行载体 ∈ { affiliate_dash, work_order, manual }
|
||
```
|
||
|
||
当前代码对抖音有 `snapshot.classification` 守卫,但 91/PDD 仍然主要靠 `isConfigured=false` 隐式表达“人工”。这会导致人工单在系统里没有显式状态,也没有处理记录。
|
||
|
||
---
|
||
|
||
## 二、生产数据证据(2026-10-17 只读)
|
||
|
||
### 2.1 最近 30 天无载体订单
|
||
|
||
“无载体”定义:已支付订单项,既没有 `fulfillment_tasks`,也没有 `work_orders`。
|
||
|
||
| 来源 | 无载体订单数 | 无载体金额 | 说明 |
|
||
| --- | ---: | ---: | --- |
|
||
| 91 | **42,391** | 约 ¥624 万 | 几乎全部 `snapshot.isConfigured=false` |
|
||
| PDD | **2,258** | 约 ¥39 万 | 几乎全部 `isConfigured=false` |
|
||
| 抖音 | **8** | 约 ¥595 | 仅 8 单未命中,抖音分流已基本收口 |
|
||
|
||
补充:
|
||
|
||
- 2026-09 无载体订单项约 **37,708**;2026-08 约 **46,322**。这不是历史遗留,是持续发生。
|
||
- `manual_dispatch` 任务全库只有 **6 条**,全部为 `manual_review`。
|
||
- 这些无载体订单的 `claim_status` 全部为 `active`,没有完成信号。
|
||
- 已验收工单对应的订单,`orders.order_status` 仍然是 `paid`:**订单主状态不能代表履约完成**。
|
||
|
||
结论:**人工块不是少量兜底,而是每天上千单、金额很大的主业务块,但基本没有进入系统任务与状态机。**
|
||
|
||
### 2.2 接单成本占比
|
||
|
||
最近 30 天已验收工单:
|
||
|
||
| 来源 | 工单数 | 打手报酬 | 订单金额口径 | 报酬/订单金额 |
|
||
| --- | ---: | ---: | ---: | ---: |
|
||
| 91 | 60,902 | ¥235.9 万 | ¥274.4 万 | 86.0% |
|
||
| PDD | 1,289 | ¥20.3 万 | ¥25.4 万 | 80.0% |
|
||
| 抖音 | 478 | ¥2.14 万 | ¥2.21 万 | 96.5% |
|
||
|
||
**注意:91 的 `orders.total_amount` 来自 `maxAmount`(91 给的可接受金额/结算口径),PDD 来自 `order_amount`,抖音来自 `pay_amount`。三者不是同一财务口径,不能直接相加当收入。**
|
||
|
||
### 2.3 SKU 口径问题
|
||
|
||
最近 30 天,同一个商品名会对应多个 `sku_code`:
|
||
|
||
- 「指挥官密钥1个」:**27 个** `sku_code`
|
||
- 「1个精致荣耀专属礼盒」:10 个
|
||
- 「苏尔南钻石100颗」:35 个
|
||
|
||
因此:
|
||
|
||
- 不能直接按 `sku_code` 做“什么皮肤卖了多少”;
|
||
- 必须先建 `product_catalog` + `channel_product_mappings`,把平台 SKU 归一到 `canonical_product_id`;
|
||
- 数量也不能只读 `order_items.quantity`,要从 SKU 文本解析(如「指挥官密钥5个」)。
|
||
|
||
### 2.4 当前订单结构
|
||
|
||
最近 30 天,三个来源的订单基本都是 **1 个订单 1 个订单项**。这让第一版销售统计可以做简化,但模型必须按“订单项”设计,不能把“一单一品”写死。
|
||
|
||
---
|
||
|
||
## 三、统一商品维度:先解决“什么皮肤”
|
||
|
||
### 3.1 商品主数据
|
||
|
||
```text
|
||
product_catalog
|
||
id
|
||
canonical_sku -- 内部标准编码,统计/成本/报表唯一口径
|
||
product_name -- 展示名
|
||
category -- 皮肤/礼包/密钥/改名卡/其他
|
||
game -- 和平精英等
|
||
carrier_type -- 默认履约载体:affiliate_dash / work_order / manual / shared
|
||
status
|
||
attributes_json
|
||
```
|
||
|
||
`carrier_type`(迁移 `107_product_catalog_carrier.sql`)是后台「商品与成本中心」的分区维度:自动发货 / 接单平台 / 人工 / 共用。回填口径(2026-10-22 修正):只把**真正走 affiliate-dash 执行器**的商品算作 `affiliate_dash`——以 `fulfillment_tasks.executor_key='affiliate_dash'` 的履约证据为准,按 `context_json.skuCode` 建标准商品(`aff:<skuCode>`,生产快照 41,676 条任务 / 28 个 SKU);接单模板初始化出来的 `tpl:*` 商品全部是 `work_order`(662 个)。**渠道映射只代表平台 SKU 能归一到标准商品,不代表自动发货**。人工/共用由后台按需手工调整;新增自动发货 SKU 可在页面点「同步自动发货商品」补建。
|
||
|
||
### 3.2 渠道 SKU 映射
|
||
|
||
```text
|
||
channel_product_mappings
|
||
id
|
||
provider -- 落库值:91kaquan / pdd / douyin_mashida
|
||
shop_id -- 空串 = 来源级;具体店铺优先
|
||
platform_sku_code -- 平台原始 sku_code / productNo / code
|
||
platform_sku_name
|
||
match_type -- sku_code / sku_code_name / sku_code_series / sku_name_series
|
||
platform_sku_name_key -- 归一后的精确名称或数量系列键
|
||
canonical_product_id
|
||
quantity_multiplier -- 数量已在归一数量中体现,系列 SKU 固定为 1
|
||
confidence -- exact / rule / manual
|
||
source -- manual / import / rule
|
||
enabled
|
||
```
|
||
|
||
匹配优先级:
|
||
|
||
```text
|
||
店铺 + SKU 编码
|
||
> 来源 + SKU 编码
|
||
> 店铺 + SKU 编码 + 精确名称
|
||
> 来源 + SKU 编码 + 精确名称
|
||
> 店铺 + SKU 编码 + 名称系列
|
||
> 来源 + SKU 编码 + 名称系列
|
||
> 店铺 + 名称系列
|
||
> 来源 + 名称系列
|
||
```
|
||
|
||
匹配不到的商品进入 `product_mapping_missing` 异常队列,**不能直接拿原始 `sku_code` 当报表维度**。
|
||
|
||
#### 3.2.1 接单模板批量初始化(2026-10-18 修正)
|
||
|
||
662 个接单模板不允许逐个手工建商品。后台「从接单模板初始化」按以下规则批量生成:
|
||
|
||
1. **每个启用模板生成 1 个标准商品**,内部编码 `tpl:<rule_key>`;暂时没有历史工单的模板也先建商品。
|
||
2. **91 与快手 send-code 的历史工单直接命中模板**,以 `work_orders.product_rule_id` 作为映射的第一手证据,不再只看原始 `sku_code`。
|
||
3. 同一 `provider + shop_id + sku_code` 只命中一个模板时,生成 `sku_code` 精确映射。
|
||
4. 同一编码被多个模板复用时,继续用“编码 + 归一名称系列”和“编码 + 精确名称”消歧;只有唯一归属才生成映射。
|
||
5. 同一编码 + 同一名称在历史上仍命中多个模板时,**不选最新、不按次数猜**;跳过并列入冲突清单,前端在初始化预览中展示候选模板与涉及订单项数。
|
||
6. 同一来源 + 店铺内名称系列唯一时,额外生成 `sku_name_series` 兜底,供后续出现新编码时使用;它永远排在编码类映射之后。
|
||
7. 数量系列(1个/2个/5个/10个,秘钥/密钥等等价写法)归为同一个标准商品;数量写入 `order_items.normalized_quantity`,不能把“5个”再写成 `quantity_multiplier=5`,否则会重复乘算。
|
||
8. 重跑初始化时只清理 `source='import'` 且备注为“接单模板 … 自动初始化”的映射,并重置由这些映射带出的订单项 `canonical_product_id`;人工映射、成本版本、快照和真实订单/工单不删除。
|
||
|
||
本地生产快照验证结果(2026-10-18):
|
||
|
||
- 启用模板 662 个,自动生成/复用标准商品 662 个;
|
||
- 历史工单证据 112,451 个订单项;
|
||
- 分层映射 4,311 条,其中编码精确 2,302、编码 + 精确名称 325、编码 + 名称系列 160、名称系列兜底 1,524;
|
||
- 可唯一归一 86,533 个有证据订单项;另有 25,918 个订单项属于 32 组真实冲突,保持未映射;
|
||
- 全库实际归一 103,143 个订单项(包含可由名称系列兜底命中的无工单订单项)。
|
||
|
||
### 3.3 店铺维度
|
||
|
||
`shop_id` 是稳定键;`shop_name` 会变。报表以 `shop_id` 为准,展示名取最新或按时间快照。
|
||
|
||
---
|
||
|
||
## 四、统一成本中心
|
||
|
||
### 4.1 当前成本散落点
|
||
|
||
| 成本 | 当前来源 | 问题 |
|
||
| --- | --- | --- |
|
||
| 自动发货采购成本 | `affiliate-dash` 商品接口 `cost_amount` | 代码已映射,但没有落库/展示/快照 |
|
||
| 工单报酬 | `work_product_rules.reward_amount` / `unit_price_fen` / `sharing_unit_reward` | 价格与匹配规则混在一张表,改价无版本 |
|
||
| 工单实际成本 | `work_orders.reward_amount`、`share_reward` | 实际值有了,但没有统一成本项/版本 |
|
||
| 人工成本 | 无 | 完全缺失 |
|
||
| 平台费/支付费/售后损失 | 分散或未建模 | 无法算真实毛利 |
|
||
|
||
### 4.2 成本类型
|
||
|
||
| 类型 | 说明 | 典型单位 |
|
||
| --- | --- | --- |
|
||
| `auto_purchase` | 自动发货上游采购成本 | 按件 |
|
||
| `work_order_reward` | 接单平台打手报酬 | 按件/按单/按份 |
|
||
| `manual_service` | 人工客服成本 | 按单/按小时 |
|
||
| `platform_fee` | 平台服务费/佣金 | 按单/按比例 |
|
||
| `payment_fee` | 支付通道费 | 按单/按比例 |
|
||
| `after_sales_loss` | 售后损失/赔付 | 按单 |
|
||
| `shipping_other` | 其他履约费用 | 按单 |
|
||
|
||
### 4.3 成本表
|
||
|
||
```text
|
||
cost_items
|
||
id
|
||
cost_key
|
||
cost_type
|
||
name
|
||
unit -- per_item / per_order / per_hour / percent
|
||
currency
|
||
status
|
||
|
||
cost_versions
|
||
id
|
||
cost_item_id
|
||
amount_fen -- 固定金额;percent 类型用 rate_bps
|
||
rate_bps
|
||
effective_from
|
||
effective_to
|
||
scope_type -- global / provider / shop / product / rule
|
||
provider
|
||
shop_id
|
||
canonical_product_id
|
||
work_product_rule_id
|
||
source -- manual / upstream_sync / import
|
||
status -- draft / active / retired
|
||
change_reason
|
||
created_by
|
||
approved_by
|
||
```
|
||
|
||
### 4.4 成本快照
|
||
|
||
```text
|
||
cost_snapshots
|
||
id
|
||
order_id
|
||
order_item_id
|
||
work_order_id
|
||
manual_case_id
|
||
cost_item_id
|
||
cost_version_id
|
||
cost_type
|
||
quantity
|
||
unit_amount_fen
|
||
total_amount_fen
|
||
snapshot_stage -- estimated / actual / adjustment
|
||
resolved_at
|
||
metadata_json
|
||
```
|
||
|
||
规则:
|
||
|
||
- 改价只新增 `cost_versions`,不覆盖历史;
|
||
- 订单/工单/人工单创建或完成时写 `cost_snapshot`;
|
||
- 匹配不到成本时写 `cost_missing`,**不能默认 0**;
|
||
- 历史成本永远从快照读,不从当前成本表倒推。
|
||
|
||
### 4.5 “只改一个地方”的过渡方案
|
||
|
||
目标状态:
|
||
|
||
- 金额只在 `cost_versions` 改;
|
||
- `work_product_rules` 只保留匹配条件 + 计价方式 + `cost_item_id`;
|
||
- `channel_product_mappings` 引用自动发货 `cost_item_id`;
|
||
- 人工成本引用 `manual_service` 成本项;
|
||
- 业务表只保存 `cost_snapshot_id`。
|
||
|
||
过渡:
|
||
|
||
1. 给 `work_product_rules` 增加可空 `cost_item_id`;
|
||
2. 有 `cost_item_id` 走成本中心;
|
||
3. 没有则回退旧 `reward_amount/unit_price_fen`,标记 `legacy_cost_source`;
|
||
4. 659 条规则逐步迁移;
|
||
5. 全部迁移后旧字段变只读/删除。
|
||
|
||
这样不会一次性打断发单,又能逐步做到“成本改动只在一个地方”。
|
||
|
||
---
|
||
|
||
## 五、销售事实与店铺日报
|
||
|
||
### 5.1 销售事实表
|
||
|
||
```text
|
||
sales_daily_facts
|
||
stat_date -- Asia/Shanghai
|
||
provider
|
||
shop_id
|
||
canonical_product_id
|
||
sales_channel -- auto / work_order / manual
|
||
order_count
|
||
item_count
|
||
quantity -- 归一化件数(SKU 文本解析后)
|
||
gross_revenue_fen
|
||
refund_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_missing_count
|
||
```
|
||
|
||
### 5.2 三个必须统一的字段
|
||
|
||
1. **商品**:`canonical_product_id`,不是原始 `sku_code`。
|
||
2. **数量**:`normalized_quantity`,不是简单的 `order_items.quantity`。
|
||
3. **收入**:`revenue_amount_fen` + `revenue_basis`,不是直接 `orders.total_amount`。
|
||
|
||
收入口径建议:
|
||
|
||
| 来源 | 当前字段 | 建议 |
|
||
| --- | --- | --- |
|
||
| 91 | `maxAmount` | 明确是结算收入还是成本上限,再归一 |
|
||
| PDD | `order_amount` | 作为订单收入候选 |
|
||
| 抖音 | `pay_amount` | 作为买家支付收入候选 |
|
||
|
||
### 5.3 退款日期
|
||
|
||
现在只有 `pay_status=refunded` 和 `updated_at`,不足以做按日净销售。建议补 `refunded_at` / `refund_amount_fen`,或从退款事件表聚合。
|
||
|
||
### 5.4 统计实现
|
||
|
||
第一版可以用物化视图:
|
||
|
||
```text
|
||
orders + order_items + channel_product_mappings + cost_snapshots
|
||
-> sales_daily_facts
|
||
```
|
||
|
||
数据量目前约 35 万订单、每天 4k+ 单,物化视图 + 索引足够;后续再改增量表。
|
||
|
||
---
|
||
|
||
## 六、自动发货块
|
||
|
||
```text
|
||
订单项 -> 命中 affiliate_dash SKU 映射 -> fulfillment_task
|
||
-> 上游商品成本 cost_amount -> cost_snapshot
|
||
-> 履约完成 -> sales_daily_facts
|
||
```
|
||
|
||
要点:
|
||
|
||
- 上游商品接口已有 `price_amount` / `cost_amount`,但当前只映射、不落库;需要同步到成本中心。
|
||
- `price_amount` 是售价/积分,`cost_amount` 是成本,不能混用。
|
||
- 成本变化生成新版本;变动超阈值告警/审批。
|
||
- 店铺/日期/皮肤统计必须走 `canonical_product_id`,不能按原始 `sku_code`。
|
||
- 统计件数要解析 SKU 文本中的数量。
|
||
|
||
---
|
||
|
||
## 七、接单平台块
|
||
|
||
```text
|
||
订单项 -> 命中接单模板 -> work_order
|
||
-> 创建/发布/抢单/验收 -> 工单报酬 -> cost_snapshot
|
||
-> 押金冻结/释放/没收 -> 影子总账(负债,不直接进成本)
|
||
-> 提现/售后/欠款 -> 影子总账
|
||
```
|
||
|
||
要点:
|
||
|
||
- 工单报酬是主成本;押金是负债,不是成本。
|
||
- 模板改价必须生成 `cost_versions`,不能直接改历史工单。
|
||
- 工单实际结算金额写入 `cost_snapshot(actual)`。
|
||
- 影子总账负责收入/成本/押金/提现/售后的复式记录;成本中心负责“金额是多少、用了哪个版本”。
|
||
|
||
生产数据提示:91/PDD/抖音已验收工单的报酬/订单金额分别约 86%/80%/96.5%。在收入口径未确认前,这个比例只能作为量级参考,不能直接当毛利率。
|
||
|
||
---
|
||
|
||
## 八、人工客服块(当前最需要补的)
|
||
|
||
> **口径确认(2026-10-17)**:业务明确人工块当前**不以 SLA 监管为目标**,第一优先级是
|
||
> **人工支出可追溯** ——「主要是把流程搞清楚:哪个人处理了哪些东西、付了多少钱。现在人工完全监管不到,
|
||
> 很多地方需要人工付款,也不知道付款项目、金额、订单号」。
|
||
> 因此本章顺序调整为:**① 人工支出登记 → ② 处理人可见(轻量 case) → ③ SLA 与监管指标(延后)**。
|
||
> DDL 见 [drafts/2026-10-17-人工支出登记-DDL草案.sql](drafts/2026-10-17-人工支出登记-DDL草案.sql)。
|
||
>
|
||
> **2026-10-18 进度**:客服备用金支出已实施(`fund.manual_expenses`),解决“客服手里有多少钱、这笔钱花到哪”;
|
||
> 但公司口径的人工支出登记(`manual_expense_records`)仍未实施。后者通过 `fund_expense_id` 关联前者,不重复做客服余额系统。
|
||
|
||
### 8.1 问题本质
|
||
|
||
不是“客服效率低”,而是**人工单没有进入系统状态机**,且**人工付款完全没有台账**:
|
||
|
||
- 没有 case;
|
||
- 没有处理人;
|
||
- 没有开始/完成时间;
|
||
- 没有交付证据;
|
||
- 没有人工成本;
|
||
- 订单完成状态无法回写;
|
||
- **付款项目、金额、关联订单号、付款人、凭证全部缺失** —— 这是当前最直接的损失点。
|
||
|
||
### 8.2 载体判定
|
||
|
||
建议在订单项上增加显式字段:
|
||
|
||
```text
|
||
carrier_type: affiliate_dash / work_order / manual
|
||
carrier_status: pending / active / completed / failed / cancelled
|
||
carrier_decided_at
|
||
carrier_reason
|
||
```
|
||
|
||
判定:
|
||
|
||
1. 命中自动发货 -> `affiliate_dash`
|
||
2. 命中接单模板 -> `work_order`
|
||
3. 都没有 -> `manual`
|
||
4. 宽限期后仍无载体 -> 自动创建人工 case
|
||
|
||
### 8.3 人工 case 模型
|
||
|
||
> 落地版见 [drafts/2026-10-17-人工支出登记-DDL草案.sql](drafts/2026-10-17-人工支出登记-DDL草案.sql):已去掉 `due_at`/优先级等 SLA 字段,先只保留「谁在处理哪个订单项 + 结果 + 证据 + 支出登记」。下表为完整形态(阶段③)。
|
||
|
||
```text
|
||
manual_fulfillment_cases
|
||
id
|
||
case_no
|
||
order_id
|
||
order_item_id
|
||
provider
|
||
shop_id
|
||
canonical_product_id
|
||
quantity
|
||
priority
|
||
status
|
||
assignee_admin_user_id
|
||
assigned_at
|
||
due_at
|
||
started_at
|
||
completed_at
|
||
outcome -- delivered / refunded / failed / cancelled
|
||
delivery_reference
|
||
evidence_json
|
||
cost_snapshot_id
|
||
notes
|
||
|
||
manual_case_events
|
||
id
|
||
case_id
|
||
event_type
|
||
actor_type
|
||
actor_id
|
||
payload_json
|
||
created_at
|
||
```
|
||
|
||
状态:
|
||
|
||
```text
|
||
pending_assign -> assigned -> processing -> waiting_customer
|
||
-> pending_review -> completed / failed / cancelled
|
||
```
|
||
|
||
### 8.4 监管规则(阶段③,延后)
|
||
|
||
- 每个无载体订单必须有 case;
|
||
- 完成必须填 outcome + 交付凭证/参考号;
|
||
- 失败必须填原因并决定重试/退款/升级;
|
||
- 高价值订单主管复核;
|
||
- 超时自动升级;
|
||
- 所有状态变更写 `manual_case_events`,不可改;
|
||
- 客服不能私下改价/退款,必须走审批。
|
||
|
||
### 8.5 人工成本
|
||
|
||
- 按单固定成本:简单,先落地;
|
||
- 按小时:`agent_hourly_rate × (completed_at - started_at)`;
|
||
- 建议两者都记录:固定服务成本 + 工时,便于后续校准;
|
||
- 完成时写 `cost_snapshot`;缺失进入 `cost_missing`。
|
||
|
||
### 8.6 监管指标(阶段③,延后)
|
||
|
||
- 待处理量、平均等待、最长挂起;
|
||
- 客服处理量、平均处理时长、完成率;
|
||
- 退款率、投诉率、返工率;
|
||
- 单均人工成本;
|
||
- 无凭证完成率;
|
||
- 同一买家/客服异常重复;
|
||
- 高价值订单抽样复核。
|
||
|
||
### 8.7 与现有任务系统的关系
|
||
|
||
现有 `manual_dispatch` 任务只有 6 条,且缺少 assignee/SLA/证据/成本字段。建议:
|
||
|
||
- 新人工 case 作为主模型;
|
||
- 如果存在对应 `manual_dispatch` 任务,完成时桥接现有完成接口;
|
||
- 不把所有人工作业强行塞进 `fulfillment_tasks`。
|
||
|
||
---
|
||
|
||
## 九、三块统一数据流
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
O["订单项"] --> C["载体判定"]
|
||
C -->|命中自动| A["affiliate_dash 任务"]
|
||
C -->|命中模板| W["work_order"]
|
||
C -->|都没有| M["manual_case"]
|
||
|
||
A --> CS["cost_snapshots"]
|
||
W --> CS
|
||
M --> CS
|
||
|
||
CS --> F["sales_daily_facts / 毛利"]
|
||
A --> L["影子总账"]
|
||
W --> L
|
||
M --> L
|
||
|
||
P["product_catalog + channel_product_mappings"] --> F
|
||
V["cost_items + cost_versions"] --> CS
|
||
```
|
||
|
||
---
|
||
|
||
## 十、分期落地
|
||
|
||
### P0:商品与销售事实(先能做报表)
|
||
|
||
- `product_catalog`
|
||
- `channel_product_mappings`
|
||
- `sales_daily_facts`(可先物化视图)
|
||
- 数量归一、收入口径、退款日期补齐
|
||
|
||
### P1:成本中心影子期
|
||
|
||
- `cost_items` / `cost_versions` / `cost_snapshots`
|
||
- 自动发货先接固定成本
|
||
- 工单先接现有规则金额
|
||
- 人工先接按单/按小时成本
|
||
- 缺失成本进异常队列
|
||
|
||
### P2:公司人工支出登记 + 轻量处理记录
|
||
|
||
- 载体判定(`carrier_type`)
|
||
- 无载体自动建轻量 case(谁在处理哪个订单项)
|
||
- **公司人工支出登记**:付款项目 / 金额 / 订单号 / 付款人 / 收款人 / 付款方式 / 凭证 / 审批
|
||
- 通过 `fund_expense_id` 关联客服备用金支出,避免重复记账
|
||
- 人工支出进成本快照与影子总账(借:履约成本-人工,贷:其他应付-垫付人)
|
||
- 延后(阶段③):SLA、超时升级、主管复核阈值、监管指标
|
||
|
||
### P3:影子总账
|
||
|
||
- 订单收入、工单成本、押金、提现、寄卖、售后
|
||
- 日对账、差异清单
|
||
- 连续对平后转正
|
||
|
||
---
|
||
|
||
## 十一、业务口径确认结果(2026-10-17)
|
||
|
||
### 11.1 已确认
|
||
|
||
| # | 问题 | 结论 | 依据 |
|
||
| --- | --- | --- | --- |
|
||
| 1 | 91 的 `orders.total_amount` 是收入还是成本上限? | **收入**:`total_amount` 就是用户付款金额,与快手发码配合,计入收入 | 业务确认;数据核验:91 已支付 312,569 笔中 235,271 笔含快手 `paymentFen`,其中 235,268 笔与 `total_amount` **完全一致(100.00%)**,仅 3 笔差 ¥1.80~2.00 |
|
||
| 2 | 打手报酬是成本还是代收代付? | **支出/成本**:工单结算后打手会提现,我方实际付款给他们 → 按**总额法**(收入记用户实付全额,报酬记履约成本) | 业务确认 |
|
||
| 3 | 人工块的目标是什么? | **先做流程可见与支出可追溯**(谁处理了哪些、付了多少钱、什么项目、关联订单号、凭证),SLA/监管指标延后 | 业务确认 |
|
||
| 4 | 退款/仲裁怎么冲减? | **暂未接入,先预留**:字段、反向冲正关系与事件类型先留好,本轮不实现逻辑 | 业务确认 |
|
||
|
||
### 11.2 仍待确认
|
||
|
||
1. 收入确认时点:付款 / 发货 / 验收 / 售后期结束?(金额口径已定 = 用户实付)
|
||
2. 自动发货的 `cost_amount` 是否稳定、是否含平台积分/汇率?
|
||
3. 人工支出按单还是按小时归集?(先按单登记,工时字段后续再加)
|
||
4. 平台服务费/支付通道费由谁承担、结算周期与账单口径?
|
||
5. 寄卖货款的采购成本确认时点?
|
||
|
||
---
|
||
|
||
## 十二、分析基线与克隆现状(2026-10-17 更新)
|
||
|
||
生产只读聚合(`SET default_transaction_read_only = on`)已完成,无写入、无改表、无改数据。
|
||
|
||
**现有基线**:本机已存在可反复使用的**生产快照克隆**(本地 docker `order_site-postgres-1`,`orders` 316,597 行,数据截至 2026-10-14),
|
||
因此**后续 SQL 迭代一律打本地克隆,不必再连生产**;需要更新时再取新快照。
|
||
|
||
本机备份目录已收敛:`backups/` 及子目录 `700`、两份 dump `600`,并删除了一个残留临时 dump(137 MB)。
|
||
如需长期保留留档,建议只保留一份最新 dump,并确认磁盘加密。
|
||
|
||
---
|
||
|
||
## 十三、一句话结论
|
||
|
||
**自动发货解决“固定成本 + 店铺/日期/皮肤销量”,接单平台解决“变动成本 + 影子总账”,人工客服解决“支出可追溯(谁付的、什么项目、多少钱、哪个订单)+ 处理人可见 + 人工成本”;三者共用一套商品主数据、成本中心和销售事实表,成本改价只发生在 `cost_versions` 一个地方。**
|