B-43: 双边流水归并与规范事件层——迁移5、匹配引擎、个人过账映射与事件API

This commit is contained in:
腾讯WorkBuddy
2026-08-18 21:06:08 +08:00
parent 486842963e
commit df517d4a68
10 changed files with 4565 additions and 49 deletions
@@ -0,0 +1,62 @@
# 005 规范转账事件与双边归并技术决策
对应 IssueB-43/B-83/B-114`docs/issues/006-p1-canonical-transfer-matching.md`)。
## 分层模型
- 银行源行是不可变观察;匹配层从不修改 `source_rows`
- 新增“不可变决定日志 + 可重建当前投影”的规范事件层:
- `transfer_match_decisions` 等证据表只增不改(UPDATE/DELETE 被触发器拒绝)。
- `current_transfer_decisions``transfer_observation_claims` 是可更新、可重建的
当前投影,`source_row_id` 主键保证一条观察不可能同时属于两个当前事件。
- B-44 余额计算只读 `eligible_intercompany_events` 视图,只含
`active + current + classification='intercompany'`;单边内部、待审、同公司调拨、
外部事件全部排除。
## 已确认业务口径(B-114
1. 单边流水即使双方公司都能由批准账号唯一确认,也先进入未决金额,不进入 B-44
已确认往来余额;只有完成双边归并(`intercompany` + `paired`)或管理员按证据确认
`intercompany` + locked 单边)后才可计算。
2. 跨日事件经济日期取付款方 outgoing 银行入账时间,与导入顺序无关。
3. 自动窗口 v1:非空参考号相同且账号镜像 <= 3 自然日(M1);无参考号精确账号镜像
<= 1 自然日(M2);别名/个人映射镜像 <= 1 自然日且参考号或摘要相等(M3)。
超窗或同层多候选全部进入人工审核,禁止按行号、导入顺序或名字破平局。
4. 个人过账映射绑定具体账号、生效区间、允许方向和代表公司,必须管理员批准;
姓名只作辅助证据,不能单独定案。
## 参与方解析
- 本方:源行 `own_account` 精确命中生效期内已批准账户(`own_exact`);缺失时才用
上传时持久化的批准上传账户(`upload_account`),且必须与批次公司一致。冲突进入
审核,不以 `company_id` 或户名反推。
- 对方:严格按账号层解析——精确账号 -> 已审核账号别名 -> 已批准且在窗口内、方向
允许的个人过账映射;每层唯一最佳结果才继续。户名/户名别名只用于一致性/冲突证据,
冲突降级到审核。
- 方向:`expense > 0 且 income = 0` 为 outgoing`income > 0 且 expense = 0`
incoming;双正/双零/负数/缺币种进入 `unresolved`。金额用 `Decimal` 精确相等,
不设手续费容差。
## 匹配与状态机
- 候选硬门槛:双方工作表 confirmed、方向相反、金额与币种相等、公司端点互为反向。
- M1/M2/M3 唯一候选自动 paired;R1(端点可确认但镜像/参考号证据不足)与 R2(同层
多候选)进入 `needs_review`;待审行不能被其他自动匹配抢占。
- 状态:`unresolved -> internal_single -> matched`、`needs_review -> matched |
same_company_transfer | external`;单边确认两端同公司立即为同公司调拨。
- 幂等:rule_version + 当前观察集合 + 证据未变时零写入;locked 人工决定自动重跑
跳过;纠错只能通过 `reverse``mode='reversal'` 新记录)+ 原因,之后允许重跑。
## 事务、并发与回滚
- “确认工作表 + 为新增确认行建立/更新事件 + audit”在同一个服务事务,任一失败整体
回滚,不存在 confirmed 但未匹配的半成品。
- 独立重跑使用 `BEGIN IMMEDIATE`,按 `source_row_id` 升序写,SQLite 30 秒 busy
timeout 保留;投影可从只增日志重建(`rebuild_current_projection`)。
- migration down 只用于测试/上线前回退;生产产生决定后默认保留 migration 5 与审计
数据,不执行破坏性 down。
## Decimal
金额全程以规范十进制字符串存储和比较,任何路径都不转 `float``100.0` 与 `100.00`
视为相等,`100.00` 与 `100.01` 不匹配。