重构:硬切履约状态唯一真源
This commit is contained in:
+72
-30
@@ -3,7 +3,7 @@ type: 权威架构与实施计划
|
||||
description: 订单、内部 SKU、履约路由、履约执行、商品、成本与财务的唯一权威口径及重构计划。
|
||||
tags: [订单, 内部SKU, 履约, 商品, 成本, 财务, 迁移]
|
||||
status: authoritative
|
||||
version: 1.0
|
||||
version: 2.0
|
||||
updated_at: 2026-11-08
|
||||
---
|
||||
|
||||
@@ -12,7 +12,7 @@ updated_at: 2026-11-08
|
||||
> 状态:**唯一权威文档**。
|
||||
> 最后校准:2026-11-08。
|
||||
> 生产基线:迁移 `146`。
|
||||
> 开发基线:迁移 `162`(仅本地,尚未部署生产)。
|
||||
> 开发基线:迁移 `166`(仅本地,尚未部署生产)。
|
||||
>
|
||||
> 从本文件生效起,订单、内部 SKU、履约渠道、履约载体、标准商品、成本和财务相关实现,
|
||||
> 只能以本文件为业务口径。其他旧分析只作为历史资料,不再具备设计或验收效力。
|
||||
@@ -76,7 +76,7 @@ updated_at: 2026-11-08
|
||||
成本、事实和总账不得反向修改订单、路由、载体或商品来源。
|
||||
|
||||
7. **派生数据必须可重建。**
|
||||
成本快照、销售事实、总账、异常队列、投影和影子履约模型都必须能够从原始订单、
|
||||
成本快照、销售事实、总账、异常队列和读模型都必须能够从原始订单、
|
||||
输入配置和事件重算。
|
||||
|
||||
8. **页面与统计使用同一读模型。**
|
||||
@@ -106,8 +106,10 @@ updated_at: 2026-11-08
|
||||
- 计算成本。
|
||||
- 决定标准商品。
|
||||
|
||||
订单项上的 `fulfillment_*`、`canonical_product_id` 等字段在过渡期保留,
|
||||
但只能由对应领域服务通过兼容投影维护,不允许入单服务自行猜测。
|
||||
`order_items` 只保存订单项与平台商品事实。迁移 `163` 后,重复的履约状态、
|
||||
渠道、配置关联和商品归一字段已改名为 `legacy_*` 冻结留档;
|
||||
运行时不得读取或写入这些旧列。订单项履约状态统一从 `v_order_item_current` 或
|
||||
`fulfillments` 读取。
|
||||
|
||||
### 3.2 商品身份域
|
||||
|
||||
@@ -185,18 +187,29 @@ on_account
|
||||
|
||||
### 3.4 履约执行域
|
||||
|
||||
当前 `order_items.fulfillment_channel/status` 和 `v_fulfillment_item_state`
|
||||
属于过渡读模型。目标模型使用:
|
||||
唯一真源为 `fulfillments`、`fulfillment_attempts`、`fulfillment_issues`。
|
||||
`v_order_item_current` 是订单项与正式履约的一对一读投影;
|
||||
`v_fulfillment_item_state` 是履约队列专用读模型。两者都不得回退 `order_items.legacy_*`。
|
||||
|
||||
```text
|
||||
fulfillments
|
||||
id
|
||||
order_item_id
|
||||
internal_sku_id
|
||||
route_status -- unrouted / configured / locked
|
||||
order_id
|
||||
internal_sku
|
||||
status -- pending / assigned / archived
|
||||
channel
|
||||
source
|
||||
locked
|
||||
pending_reason
|
||||
pending_detail
|
||||
fulfillment_config_id
|
||||
canonical_product_id
|
||||
route_status -- unrouted / configured
|
||||
carrier_status -- not_required / missing / creating / ready / failed / terminal
|
||||
current_attempt_id
|
||||
current_attempt_type -- task / work_order / 空
|
||||
current_attempt_source_id
|
||||
current_attempt_status
|
||||
issue_code
|
||||
issue_category
|
||||
retryable
|
||||
@@ -208,7 +221,7 @@ fulfillment_attempts
|
||||
id
|
||||
fulfillment_id
|
||||
attempt_no
|
||||
attempt_type -- task / work_order / manual
|
||||
attempt_type -- task / work_order
|
||||
source_id
|
||||
status
|
||||
result_code
|
||||
@@ -234,6 +247,14 @@ fulfillment_issues
|
||||
resolved_at
|
||||
```
|
||||
|
||||
状态写入规则:
|
||||
|
||||
- 状态服务锁 `fulfillments`,不再锁或更新 `order_items` 履约状态。
|
||||
- 配置关联写入 `fulfillments.fulfillment_config_id / canonical_product_id`。
|
||||
- 任务和工单只追加 `fulfillment_attempts`,由触发器刷新当前尝试摘要。
|
||||
- 状态变化写入 `fulfillment_state_events`;事件只禁止 UPDATE,父记录删除时允许级联清理。
|
||||
- `v_order_item_current` 以正式表字段覆盖订单项旧名,保证所有业务查询只有一个读口径。
|
||||
|
||||
状态必须正交:
|
||||
|
||||
```text
|
||||
@@ -311,7 +332,7 @@ finance_journal_* -- 总账凭证,可重建
|
||||
|
||||
2026-11-08 生产只读核对结果:
|
||||
|
||||
- 生产迁移 `146`,本地开发基线迁移 `162`。
|
||||
- 生产迁移 `146`,本地开发基线迁移 `166`。
|
||||
- 启用标准商品 `1127`:`aff:` 30、`tpl:` 903、`tpv:` 46、`man:` 148。
|
||||
- `man:` 商品中只有 105 个当前主渠道为人工;41 个已走其他主渠道,2 个无主渠道。
|
||||
- 人工页头部显示 `107`,商品列表显示 `148`,相差的 41 个就是跨渠道旧商品。
|
||||
@@ -348,6 +369,8 @@ finance_journal_* -- 总账凭证,可重建
|
||||
- 平台售后、退款、支付事实
|
||||
- `work_orders`、`work_order_shares`、`work_order_events`
|
||||
- `fulfillment_tasks` 中真实执行与结果记录
|
||||
- `fulfillments`、`fulfillment_attempts`、`fulfillment_issues`
|
||||
- `fulfillment_state_events`
|
||||
- `worker_wallet_ledgers`、`fund_accounts` 的真实资金流水
|
||||
- `admin_audit_logs`
|
||||
- 财务期间、已确认退款和真实资金账户
|
||||
@@ -373,7 +396,6 @@ A 级数据只能追加新事件或做字段兼容迁移,不能为了“模型
|
||||
- `cost_exceptions`
|
||||
- `sales_daily_facts`
|
||||
- `finance_journal_entries` / `finance_journal_lines`
|
||||
- `fulfillments` / `fulfillment_attempts` / `fulfillment_issues`
|
||||
- `v_fulfillment_item_state` 及其依赖投影
|
||||
- 商品统计投影、渠道统计投影、页面汇总缓存
|
||||
- 管道水位与失败重试状态
|
||||
@@ -386,7 +408,7 @@ A 级数据只能追加新事件或做字段兼容迁移,不能为了“模型
|
||||
- 已冻结的 `internal_sku_channels`
|
||||
- `sku_channel_rules` 中由 `internal_sku_mappings` 和 `sku_channel_routes` 取代的规则
|
||||
- `manual_sku_registry` 中可由配置重建的登记行
|
||||
- 订单项上的重复履约结果字段,在正式模型切换后删除
|
||||
- 订单项上的 `legacy_*` 重复履约结果字段,在审计留存期结束后删除
|
||||
- 商品表中的历史来源前缀判断代码
|
||||
- 旧路由补丁脚本和一次性迁移工具
|
||||
|
||||
@@ -505,12 +527,12 @@ has_active_cost
|
||||
| 阶段 | 状态 | 是否改生产数据 |
|
||||
| --- | --- | --- |
|
||||
| 0 口径冻结与文档收口 | 已完成 | 否 |
|
||||
| 1 只读审计与领域约束 | 本地进行中 | 否 |
|
||||
| 2 建立目标身份与投影 | 商品侧本地完成 | 只新增兼容结构 |
|
||||
| 1 只读审计与领域约束 | 本地完成 | 否 |
|
||||
| 2 建立目标身份与投影 | 本地完成 | 只新增结构 |
|
||||
| 3 迁移路由与商品配置 | 本地完成,生产未执行 | 是,需备份 |
|
||||
| 4 重建履约模型 | 本地准备中 | 是,需断代 |
|
||||
| 4 重建履约模型 | 本地完成,生产未执行 | 是,需备份 |
|
||||
| 5 重建财务派生数据 | 未开始 | 是,需备份与对账 |
|
||||
| 6 停止旧写路径并删除兼容层 | 未开始 | 是,需观察期结束 |
|
||||
| 6 停止旧写路径并删除兼容层 | 履约侧已完成,全局未开始 | 是,需观察期结束 |
|
||||
|
||||
### 阶段 0:口径冻结与文档收口
|
||||
|
||||
@@ -580,7 +602,13 @@ assigned 且 carrier_status=missing 必须进入异常队列
|
||||
- 迁移 `160`:商品身份全部补齐,运行硬切到 `sku_channel_routes`,删除旧同步触发器;
|
||||
`v_product_current` 不再回退 `source_kind`,`v_fulfillment_item_state` 不再读取旧表。
|
||||
- 迁移 `161`:履约影子同步触发器从旧表迁移到 `sku_channel_routes`。
|
||||
- 迁移 `162`:删除旧履约只读视图和旧表最后一个触发器。
|
||||
- 迁移 `162`:删除旧路由只读视图和旧表最后一个触发器。
|
||||
- 迁移 `163`:履约状态硬切到 `fulfillments`;新增正式状态、配置关联和商品字段;
|
||||
任务/工单只维护尝试历史;订单项旧状态列改名冻结;建立 `v_order_item_current`。
|
||||
- 迁移 `164`:履约事件外键改为随正式履约记录级联删除。
|
||||
- 迁移 `165`:履约事件只阻止 UPDATE,数据库级联删除不再被 append-only 触发器阻断。
|
||||
- 迁移 `166`:无法解析内部 SKU 时,正式履约行的 `internal_sku` 统一落空字符串,
|
||||
并进入 `missing_internal_sku` 异常,而不是触发非空约束。
|
||||
- 商品列表、总览、渠道映射和商品下拉统一读取商品当前渠道。
|
||||
- 运行期代码停止写入 `product_channel_capabilities`,该表仅保留到兼容期结束。
|
||||
- 只读审计:`npm run audit:product-routing -- --strict`。
|
||||
@@ -588,8 +616,7 @@ assigned 且 carrier_status=missing 必须进入异常队列
|
||||
- 自动/卡券/接单主渠道商品的人工配置均保留为显式 `fallback`,没有被误升为人工主渠道。
|
||||
- 1 个无主路由、无人工配置、无启用映射的 `man:` 商品已归档,未删除历史引用。
|
||||
- 旧 `internal_sku_channels` 已冻结:运行时不再读、不再写,也不再有视图或触发器依赖。
|
||||
- 空库从迁移 `001` 顺序执行到 `162` 已通过;新库只保留
|
||||
`sku_channel_routes` 影子同步触发器,旧表同步触发器不存在。
|
||||
- 空库从迁移 `001` 顺序执行到 `166` 已通过;新库不再保留任何旧履约影子同步触发器。
|
||||
- 无主路由的活动商品会进入“未路由”,不自动猜测渠道。
|
||||
|
||||
当前本地仍需业务处理的数据:
|
||||
@@ -630,20 +657,26 @@ assigned 且 carrier_status=missing 必须进入异常队列
|
||||
|
||||
### 阶段 4:重建履约模型
|
||||
|
||||
状态:本地完成,生产未执行。
|
||||
|
||||
目标:
|
||||
|
||||
- 以 A 级原始订单和真实载体为输入,重建 `fulfillments`、`fulfillment_attempts`、
|
||||
`fulfillment_issues`。
|
||||
- 停止写入过渡字段。
|
||||
- 旧订单项履约状态字段已停止读写并冻结留档。
|
||||
|
||||
工作:
|
||||
本地产出:
|
||||
|
||||
1. 清空旧影子履约和派生异常。
|
||||
2. 回填当前履约单。
|
||||
3. 回填当前尝试与历史尝试。
|
||||
4. 生成结构化 issue。
|
||||
5. 对比新旧读模型。
|
||||
6. 切换后台与调度读路径。
|
||||
1. `fulfillments` 增加 `status / source / locked / pending_* / config / canonical_product`
|
||||
等正式字段,并从订单项存量状态一次性回填。
|
||||
2. 历史任务和工单补齐到 `fulfillment_attempts`,不再从订单项回调状态。
|
||||
3. `transitionFulfillmentStateWithExecutor`、渠道分配和配置关联全部改写正式表。
|
||||
4. `v_fulfillment_item_state` 只投影 `fulfillments + fulfillment_attempts +
|
||||
fulfillment_issues + sku_channel_routes`。
|
||||
5. 全部业务读 SQL 切到 `v_order_item_current`,禁止直接读取订单项旧状态列。
|
||||
6. 状态事件、任务尝试、工单尝试和配置变化触发器统一围绕正式履约表工作。
|
||||
7. 真实 PostgreSQL 集成测试覆盖状态写入、幂等、事件留痕、当前尝试和配置关联。
|
||||
8. 本地存量库与空库 `001 → 166` 均完成硬切验证。
|
||||
|
||||
验收:
|
||||
|
||||
@@ -651,9 +684,16 @@ assigned 且 carrier_status=missing 必须进入异常队列
|
||||
- 所有 `assigned` 都有明确 `carrier_status` 或开放 issue。
|
||||
- 退款、取消进入售后队列。
|
||||
- 页面按钮作用域与后端动作一致。
|
||||
- 运行时对 `order_items.legacy_fulfillment_*` 和 `legacy_canonical_product_id`
|
||||
的读写点均为 `0`。
|
||||
- 旧 `sync_fulfillment_shadow*` 函数和旧影子同步触发器均为 `0`。
|
||||
|
||||
### 阶段 5:重建财务派生数据
|
||||
|
||||
本地提前发现并修复:销售凭证增量同步读取当日余额时,必须统计同一天全部
|
||||
`sales_revenue_adjustment / sales_refund_adjustment / sales_cost_adjustment`,
|
||||
不能只按原始凭证的 `ref_id = 日期` 读取,否则重复同步会累计重复补记。
|
||||
|
||||
目标:
|
||||
|
||||
- 保留 A 级订单、退款事实和 B 级配置。
|
||||
@@ -679,11 +719,13 @@ product normalization
|
||||
|
||||
### 阶段 6:停止旧写路径并删除兼容层
|
||||
|
||||
状态:履约域已在本地停止旧写路径;商品、成本、人工配置的全局兼容清理仍需后续完成。
|
||||
|
||||
只有前五个阶段持续稳定后才允许:
|
||||
|
||||
- 删除 `product_channel_capabilities`。
|
||||
- 删除 `manual_sku_registry` 的派生行。
|
||||
- 删除订单项重复渠道字段。
|
||||
- 删除订单项已冻结的 `legacy_*` 重复渠道字段。
|
||||
- 删除商品前缀业务判断。
|
||||
- 删除旧管道、旧同步脚本和兼容 API。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user