From 4147a6960ff10d965a3ee4d1ad0807a67c83bf3c Mon Sep 17 00:00:00 2001 From: shunli Date: Mon, 27 Jul 2026 21:23:15 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=9C=9F=E5=AE=9E=E6=8A=A5?= =?UTF-8?q?=E9=94=80=E9=A6=96=E8=B7=91=E9=A3=8E=E9=99=A9=EF=BC=8807-27-yan?= =?UTF-8?q?g-jun-reimbursement-readiness=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .trellis/spec/hyb-oa/reimbursement-invoice-ocr.md | 14 ++++++++++++++ .../design.md | 9 +++++++++ .../implement.md | 4 ++++ 3 files changed, 27 insertions(+) diff --git a/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md b/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md index 0c495d4f..53e9663d 100644 --- a/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md +++ b/.trellis/spec/hyb-oa/reimbursement-invoice-ocr.md @@ -32,6 +32,8 @@ duplicate detection or attachment behavior. - Database: `InvoicePool.ocr_provider` is a non-null `OcrProvider` with schema default `tencent`; `ocr_attempts`, `ocr_last_requested_at`, `ocr_completed_at` and extracted invoice fields carry the execution evidence. +- Duplicate index: `@@unique([file_sha256, ocr_provider, ocr_type])` partitions + the SHA-256 namespace by provider and OCR type. ### 3. Contracts @@ -47,6 +49,13 @@ duplicate detection or attachment behavior. finance checks the PDF original manually. SHA-256 duplicate detection remains active; invoice-code/number duplicate detection is unavailable for blank metadata. +- A future nullable/off-provider migration must not change only the stored + provider value. Backfill historical rows to one canonical namespace or replace + the composite unique key with an intentional file-level uniqueness contract; + otherwise the same bytes can be uploaded once before and once after migration. +- Before changing provider semantics, count historical `mock` rows uploaded by + non-test employees. Any such rows need an explicit dedupe/review plan because + their provider namespace already differs from current default rows. - A config-only provider switch keeps `BUILD_SHA` unchanged. Recreate every process that actually loads OCR config: server only when `JOBS_ENABLED=true` and no worker exists; server plus worker when an independent worker already @@ -65,6 +74,8 @@ duplicate detection or attachment behavior. - `ocr_provider=tencent` with attempts `0`, null request/completion timestamps and null extracted fields -> historical schema-default finding, not evidence of a Tencent request. +- Provider enum/default or unique-key change without backfill/index redesign -> + block migration review because it splits the duplicate-detection namespace. - Blank metadata cannot bind or submit -> keep the test draft, clean it through normal APIs, then plan a code change; do not add an emergency production database edit. @@ -84,6 +95,9 @@ duplicate detection or attachment behavior. - Assert upload status is `available` under `OCR_PROVIDER=off`. - Assert invoice code, number, date, buyer, seller and all amount fields are null; assert attempts are `0` and request/completion timestamps are null. +- Migration tests for provider semantics must upload identical bytes on both + sides of the migration and assert that the second upload is still rejected or + reuses the canonical row. - Bind to a reimbursement with one valid item, submit through the real workflow, return instead of approve, delete the draft and archive the released invoice. - Final read-only checks: test accounts archived, active sessions `0`, test diff --git a/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/design.md b/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/design.md index 9976bc42..b879bb88 100644 --- a/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/design.md +++ b/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/design.md @@ -105,6 +105,7 @@ - 用户选择并批准关闭 mock。现场拓扑没有独立 worker,`JOBS_ENABLED=true`,因此只重建实际承载 Web 与后台任务的 server;不得为了“同时重启 worker”而凭空创建第二个作业执行器。 - `OCR_PROVIDER=off` 复验确认:新 PDF 直接进入 `available`,发票代码、号码、日期、购销方和金额字段均为空,OCR 尝试为 0、请求/完成时间为空;票据可以绑定到单明细 0.01 元测试报销并正常提交、退回和清理。 - `InvoicePool.ocr_provider` 是非空枚举且 schema 默认 `tencent`;off 路径传入 `undefined` 后数据库仍写入该默认值。该字段只是历史 schema 默认,不代表发生过 OCR 调用;当前 UI 不展示 provider。是否在后续迁移中改为 nullable 应与腾讯 OCR/人工录入产品决策一起规划,不阻断本次真实报销。 +- `InvoicePool` 当前使用 `@@unique([file_sha256, ocr_provider, ocr_type])`。后续若把 provider 改成 nullable 或新增 `off` 枚举,必须同步回填历史行或重设计唯一键;只改新行 provider 会把同一文件拆进两个查重命名空间。生产只读核查显示历史 `mock` 票据共 1 张且仅由测试账号上传,非测试员工上传数为 0。 - off 模式下发票号为空,基于 `invoice_code + invoice_number` 的查重不可用,但文件 SHA-256 查重仍生效;当前小团队短期由财务查看 PDF 原件并人工核对,不在本任务增加强制补录。 - 草稿删除成功后,详情页在导航完成前仍短暂请求已删除的详情与 precheck,浏览器产生预期 404 控制台噪声,但用户已回到空草稿列表。这是非阻断前端时序 finding,不影响数据清理结果。 @@ -135,3 +136,11 @@ - 不创建法体、不补银行账号、不导入其余成员。 - 不把首次真实业务扩成管理员代办的生产自动化测试。 - 不创建新的企微测试成员,不给测试主管财务或管理员权限,不让测试单通过审批或进入付款链路。 + +## 8. 真实首跑补充风险复核 + +- 生产三名真实参与人均 active 且企微绑定唯一,但尚无 `AUTH_WECOM_LOGIN_SUCCESS` 记录;企微客户端入口仍需本人首登验证。 +- 当前 active 费用标准为 0、杨俊部门适用预算池为 0;真实金额不会触发费用标准或预算阻断。active 法体为 0、杨俊未绑定法体,但现有报销提交和付款批次候选不以法体为硬门禁。 +- 金额审批规则不是同一条:`[0,500)` 为 `manager → finance`,`[500,5000)` 为 `manager → finance_mgr`,`[5000,+∞)` 为 `manager → ceo → finance_mgr`。 +- 当前 active 角色持有人:`finance=1`、`ceo=1`、`finance_mgr=0`。因此低于 500 元可路由到马建勇后再到王芝玲;达到 500 元的单据会生成无人可处理的 `finance_mgr` 角色待办。修复应调整审批规则到既有最小角色,不给王芝玲扩为权限过宽的 `finance_mgr`。 +- 最终审批只把报销置为 `approved`,不会自动创建付款批次或付款记录;付款批次仍由王芝玲主动创建并由马建勇复核。 diff --git a/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/implement.md b/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/implement.md index 6c0d7e3c..5a2b7808 100644 --- a/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/implement.md +++ b/.trellis/tasks/07-27-yang-jun-reimbursement-readiness/implement.md @@ -64,6 +64,8 @@ ## 6. 用户真实验收 +- [ ] 在杨俊提交前修正金额审批规则:`[500,5000)` 的末级由 `finance_mgr` 改为 `finance`,`[5000,+∞)` 保留 `ceo` 且末级由 `finance_mgr` 改为 `finance`;不得通过给王芝玲增加 `finance_mgr` 绕过。 +- [ ] 规则写入前后只读核对三档金额边界(499.99 / 500 / 5000)及 active 角色持有人,确认每个角色节点都至少有一名实际处理人。 - [ ] 请杨俊本人从企业微信进入 OA,确认身份解析成功并能看到报销入口。 - [ ] 杨俊使用真实业务数据创建报销,至少添加一条费用明细并上传/绑定状态有效的真实票据后提交。 - [ ] 确认马建勇能看到该真实审批待办并按业务事实处理。 @@ -92,3 +94,5 @@ - finding:生产 OCR 为 mock 且真实腾讯 OCR 未配置,合成 PDF 自动生成 Mock 字段;草稿删除后页面导航前产生已删除详情/precheck 的 404 控制台噪声。前者阻断杨俊真实票据上传,后者不阻断业务。 - OCR off 复验:配置切换后未改构建;三次有业务写入的复验/诊断均按“退回 → 删除 → 归档 → 停用”收口。累计 4 张合成测试票据(含第一轮)均已归档,未归档 0;测试报销与 pending 待办均为 0。 - OCR off 结论:空发票业务字段可以绑定并提交,主管退回成功;真实使用暂由财务查看 PDF 原件并人工核对。文件 SHA-256 查重仍有效,发票号查重暂不可用。 +- 真实首跑复核:三名参与人 active 且企微绑定唯一,但企微首登均未发生;费用标准 0、适用预算池 0、active 法体 0,法体不阻断当前报销。历史 mock 票据仅 1 张且为测试账号上传,非测试员工为 0。 +- 审批规则 finding:`[0,500)` 可由马建勇和唯一 finance 王芝玲处理;`[500,5000)` 与 `[5000,+∞)` 均以 `finance_mgr` 收尾,但 active `finance_mgr=0`,达到 500 元会形成无人处理待办。未修正规则前不得笼统通知杨俊可提交。