feat(expense): add persistent zero-entry receipt association

This commit is contained in:
caoxiaozhu
2026-07-16 10:23:23 +08:00
parent 54754b5502
commit ae3f02c35a
30 changed files with 4450 additions and 810 deletions

View File

@@ -1,6 +1,6 @@
# AI 费用闭环与价值证明 概念文档
更新时间2026-07-14
更新时间2026-07-16
文档路径document/development/2026-07-13/feature/ai-expense-closed-loop-and-value-proof/CONCEPT.md
@@ -113,6 +113,15 @@
- 每个 AI 填充字段显示来源、置信度和修改入口;低置信度字段集中进入“需要确认”区。
- 退回、补件和断点续办直接回到对应问题,不要求用户重新开始对话。
#### 零录入报销首个切片
- 用户在小财管家上传已完成 OCR 的票据并发送后,附件关联任务必须以当前租户、当前员工和 `Expense Case` 为边界,优先寻找已审批申请自动生成的可编辑报销草稿。
- 匹配信号首期使用费用事件关系、申请状态、票据日期、行程城市、费用场景和草稿状态;返回结构化分数、置信度和命中原因,不把模型自由文本作为授权依据。
- 只有唯一高置信候选允许自动归集。低置信、多个接近候选、申请缺少系统生成草稿、票据已属于其他单据或证据不足时,任务以 `requires_confirmation=true` 成功返回候选和异常,不修改任何报销单或票据关系。
- 自动归集成功后直接返回费用事件、申请、报销草稿、归集数量、跳过数量、风险项、缺失项和可解释原因;前端只展示完成结果或“需要确认”异常,不要求用户再次上传同一票据。
- 自动归集是 L3 可逆动作,只允许写入草稿、票据关系和业务事件;不自动提交、审批、付款或重建历史遗留申请缺失的草稿。
- 相同租户、用户、票据和目标草稿重试必须幂等;已归集到同一草稿的票据计入跳过数,不重复创建费用明细、附件或业务事件。
#### 移动端
- 把拍照、相册选票、报销列表、审批列表和 AI 助手接入真实后端。
@@ -144,6 +153,8 @@
- 新增 `ExpenseCaseService` 作为跨阶段编排入口,避免继续扩大万能 `ExpenseClaimService`
- `ExpenseCaseService` 只负责阶段协调,申请、票据、报销、审批、支付、入账、记忆和节省由独立协作者负责。
- 复用统一 AI 场景注册与 LangGraph 编排,前端只按后端返回的 plan/action 渲染,不再增加业务门控。
- 零录入票据归集由独立匹配器计算候选和证据,由独立关联编排器执行可逆写入;后台 Job 只负责身份绑定、状态保存和结果投影,不继续堆评分、附件和事件逻辑。
- 票据存储命名空间必须至少包含租户与用户;后台任务查看和执行同时校验租户及用户,平台管理员也不能跨租户读取任务结果。
#### 业务事件与 AI 决策
@@ -226,6 +237,14 @@
- `savings_opportunities` / `savings_realizations`:节省机会和实现结果。
- `usage_meter_events`租户、模块、模型、OCR、文档和分析用量。
#### 零录入附件关联任务契约
- 保留现有 `status``message``claim_id``claim_no``uploaded_count``skipped_count` 字段,追加字段保持前端向后兼容。
- 任务追加 `resolution``requires_confirmation``expense_case_id``application_claim_id``application_claim_no``confidence``confidence_score``match_reasons``exceptions``missing_fields``risk_items``candidates`
- `status=succeeded` 只表示匹配流程完成;`resolution=auto_associated` 表示已经完成可逆归集,`resolution=requires_confirmation` 表示没有业务写入,需要用户选择候选或处理异常。
- 候选最少返回目标类型、费用事件 ID、申请 ID/编号、草稿 ID/编号、分数、置信度和命中原因;不得返回其他租户或当前员工数据范围之外的候选。
- `receipt_received``attachment_associated` 使用票据 ID 与目标草稿组成稳定幂等键,并与票据 Link、附件写入在同一数据库事务中完成若文件存储写入失败数据库事务回滚且任务进入失败态。
#### 最小事件词典
- `expense_case_created`
@@ -556,3 +575,8 @@ docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv \
- 2026-07-14应用、抑制与遗忘个人记忆只补空白出行方式任何当前显式值都优先。命中后服务端重新计算交通与总额估算再签发 canonical decision记忆异常降级为无记忆不阻塞预览。反向或非白名单纠正抑制 active用户忘记后状态改为 revoked、清空可恢复值和指纹旧请求不可复活。
- 2026-07-14前端记忆解释申请核对表新增独立 `TravelReimbursementMemoryPanel`,展示已应用的常用出行方式、证据数量、学习回执和“忘记此偏好”入口;本地会话快照支持跨刷新恢复,忘记偏好不会篡改当前申请字段。
- 2026-07-14个人记忆验证容器内个人记忆专项 16 项、记忆/预览决策/迁移/所有权组合回归 56 项通过且 1 项条件跳过、前端申请与记忆组合 83 项通过;一次性 PostgreSQL 迁移循环、Ruff、Vite 生产构建和 `git diff --check` 均通过。当前规则中心尚不存在交通方式禁用维度,制度冲突守卫作为后续规则扩展的前置门禁保留,不以恒真占位判断冒充已实现。
- 2026-07-16零录入票据首个闭环附件后台任务从“大而全”的内存编排中拆出只读 `ExpenseReceiptMatcher` 与可逆 `ExpenseReceiptAssociationService`。系统按当前租户、员工、Expense Case、已审批申请、票据日期、城市、路线和场景选择草稿只有唯一高置信草稿自动归集低置信、多候选、无草稿及仅有申请时均以需要确认的安全终态返回并保持零业务写入。
- 2026-07-16事务、幂等与租户边界票据 Link、`receipt_received`、附件写入和 `attachment_associated` 由同一关联编排器提交,数据库快照与文件目录备份共同补偿中途失败,事件或文件元数据异常时恢复 Claim/Case/Link/Event/票据及旧附件目录相同票据任务按租户、owner 和票据集合持久去重。票据目录加入无碰撞租户摘要,任务、候选 Claim 和票据同时绑定租户与本人,平台管理员也不能跨租户读取任务。
- 2026-07-16持久任务与并发新增 migration-owned `attachment_association_jobs``20260716_0006`。任务状态、结构化结果、owner 上下文、attempt、租约与 generation 写入数据库GET 可恢复 queued 或租约过期任务,`attempt_count + running` 作为栅栏阻止旧 worker 或迟到回调覆盖新终态。同票据和同 Claim 分别使用进程锁与 PostgreSQL advisory lock 串行化Claim 锁内清理旧事务并重新匹配,避免不同票据并发选择同一空明细。待确认或失败任务保留原代历史,再次发起创建新 generation 并重新评估;已自动关联成功的代际继续幂等复用。评分改为纯只读查询,每份票据必须独立达到最小证据,避免无关票据被同批强证据带入。
- 2026-07-16小财管家交互与验证任务结果新增 Case、申请、置信度、原因、异常、缺失项、风险项、候选和草稿载荷前端可跨会话恢复自动完成直接查看草稿仅申请候选查看申请待确认不伪装成功幂等重放显示“已关联”成功结果仍展示风险和复核要求。容器内后端归集专项 20 项、归集与相邻服务/迁移所有权组合回归 71 项、前端关联链路组合回归 29 项、Ruff F/I/UP 和 Vite 生产构建通过;一次性 tmpfs PostgreSQL 17 的 0006 完整迁移循环 4 项通过并已清理,持久开发库未修改。既有大型报销服务与接口套件仍存在旧审批、删除和风控断言失败,未把这些基线问题误报为已解决。
- 2026-07-16保留边界预算、项目、成本中心和个人记忆偏好尚未接入票据候选评分任务已持久化并支持租约恢复但尚未建设独立消息队列、运维重试面板和死信治理完整 G2 与平台级异步任务治理仍未完成。

View File

@@ -1,6 +1,6 @@
# AI 费用闭环与价值证明 开发 TODO
更新时间2026-07-14
更新时间2026-07-16
文档路径document/development/2026-07-13/feature/ai-expense-closed-loop-and-value-proof/TODO.md
@@ -94,7 +94,16 @@
- [ ] [CONCEPT: 数据与契约] 补齐撤回、取消、驳回、作废、补件、支付失败、对账异常和归档状态。
- [ ] [CONCEPT: 连接器] 实现统一连接器基类、幂等、重试、错误状态和回执事件。
- [ ] [CONCEPT: 连接器] 实现支付批次、回执、重复付款防护、ERP 凭证和对账的内部契约,首期允许 mock connector 但不得再只写单一“已付款”状态。
- [ ] [CONCEPT: 降级策略] 将附件关联和关联报销草稿后台任务迁为可持久化、可恢复、可幂等的任务状态。
- [x] [CONCEPT: 降级策略] 将附件关联和关联报销草稿后台任务迁为可持久化、可恢复、可幂等的任务状态。
证据:新增 migration-owned `attachment_association_jobs``20260716_0006`任务使用租户、owner、票据集合和 generation 去重,运行态带租约与 `attempt_count + running` 栅栏GET 可恢复 queued/租约过期任务。同票据和同 Claim 均由进程锁与 PostgreSQL advisory lock 串行化Claim 锁内重新匹配;待确认或失败历史保留原代并以新 generation 重新评估,自动关联成功代继续幂等复用。进程状态清空、租约过期、旧 worker 回写、不同票据并发同 Claim 和代际重评估回归通过。
- [x] [CONCEPT: 零录入附件关联任务契约] 扩展附件关联任务的向后兼容结果契约,区分自动完成与需要确认,并返回 Case、申请、置信度、原因、异常、缺失项、风险项和候选。
证据:`attachment_association_job.py``attachmentAssociationJobModel.js` 保留旧字段并追加结构化结果;`status=succeeded + resolution=requires_confirmation` 明确表示匹配完成但零业务写入。
- [x] [CONCEPT: 零录入报销首个切片] 新增独立票据匹配器按当前租户、员工、Expense Case、已审批申请、日期、城市和场景计算候选唯一高置信才允许自动归集。
证据:`expense_receipt_matcher.py` 只读评分;覆盖唯一高置信、相近候选、无草稿、仅有已审批申请和已关联重放,申请缺少系统草稿时只返回 `approved_application` 候选。
- [x] [CONCEPT: 零录入报销首个切片] 新增独立归集编排器,把票据 Link、`receipt_received`、附件写入和 `attachment_associated` 纳入同一事务,并保证同票据重试不重复建明细或事件。
证据:`expense_receipt_association.py` 统一编排数据库写入,文件系统使用元数据快照和附件目录补偿;稳定幂等键保证相同票据重试只增加跳过数。事件写入失败回归证明 Claim、Case、Link、Event、票据元数据和附件最终状态均回退。
- [x] [CONCEPT: 权限与安全] 将票据夹存储命名空间和附件关联后台任务授权同时绑定租户与用户,补充同用户名跨租户隔离回归。
证据:`receipt_folder.py` 使用租户与用户联合命名空间,任务状态绑定 `owner_tenant_id + owner_username`;普通用户及平台管理员跨租户查询均返回 404同用户名跨租户不能读取票据。
## 5. P0 前端实现:一键报销与真实移动端
@@ -102,7 +111,13 @@
证据:`TravelRequestExpenseCaseTimeline.vue``useExpenseCaseTimeline.js``expenseCases.js``expenseCaseTimeline.js`保留原有横向进度404 与接口异常均安全降级,容器内 99 条定向前端回归和 Vite 生产构建通过。
- [ ] [CONCEPT: 统一费用事件] 补齐计划、消费/票据、入账、对账和复盘事件,并在真实迁移数据库上跑通完整时间线。
- [ ] [CONCEPT: 统一费用事件] 自动匹配申请、预算、票据、费用类型、项目、成本中心和常用字段。
首个切片先交付申请、票据、费用事件、日期、城市和费用场景匹配;预算、项目、成本中心和记忆偏好随后接入同一候选契约。
- [ ] [CONCEPT: 统一费用事件] 增加“需要确认”区,只展示低置信、缺失或冲突字段。
首个切片在小财管家附件关联结果中复用统一异常模型;后续再收口全屏助手和票据夹入口。
- [x] [CONCEPT: 零录入报销首个切片] 在小财管家实现“上传并发送 → 自动归集已审批申请生成的草稿 → 查看草稿”,不再次上传票据;低置信时只展示候选和异常卡片。
证据:附件任务 composable 将待确认视为安全终态,不发送伪成功通知;自动完成提供“查看草稿”,申请候选提供“查看候选申请”,不伪造报销草稿。
- [x] [CONCEPT: 零录入附件关联任务契约] 会话刷新后恢复新任务结果、候选和异常状态,旧任务结果仍可正常展示。
证据:`workbenchAiMessageModel.js` 持久化新协议,规范化层兼容旧字段;容器内前端票据关联、协议、卡片、幂等重放、风险复核和会话恢复组合回归 29 项通过。
- [ ] [CONCEPT: 风险与预审] 风险卡提供一键补件、修正、解释和重新预审入口。
- [ ] [CONCEPT: 统一费用事件] 退回后直接定位问题字段,支持断点续办,不要求重新发起对话。
- [ ] [CONCEPT: 移动端] 接通真实登录恢复、路由守卫、报销列表、详情、草稿、上传和审批 API。