11 KiB
11 KiB
报销状态空隙与财务处理视角:实施计划
2026-09-10 退回删除接续
- 用户要求继续剩余任务,先退回删除、后付款体验;沿既有 task,不新增管理任务。独立副本
artifacts/isolated-worktrees/20260910-rejected-delete基线 e5685f1,官方 current 已对齐,无新分支,未混入其他工作树未提交内容。 - 已核对最新 PRD 追加范围及付款 task 综合方案。现有 DELETE 会级联删除 workflow 历史;draft 本身不是可物理删除的充分条件。当前模型没有专用删除标记,不能只放开 rejected。
- design 顶部补充 deleted_at/deleted_by 最小迁移、审计与材料引用、参与人授权、查询排除、锁顺序及旧应用回滚风险;行业调研后用户确认实施,本轮已编写迁移并仅在一次性合成数据库执行,未运行生产写入。
- 当前实现与历史级联风险核查。
- 用户在行业调研后确认本地实施,生产操作与提交仍另批。
- 实施服务端删除/材料历史/查询边界和双端入口,补充针对性单测及真实隔离场景;没有声称新增测试先在旧代码上完整跑红。
- 完成真实隔离流程、并发/权限反例与前端回归,保留独立副本作为只读复核入口。
- 独立只读复核(当前 inline,仅主会话自审,不冒充独立 reviewer)。
- 通过后再按授权提交发布;付款体验在独立副本与原 task 承接,不一并提交。
实现与证据
- 运行时:仅 draft/rejected + 删除权限 + owner/submitter 可删;拒绝活动流程/待办、非取消付款占用、paid_at、异常关联票据。重复留痕删除先授权,再幂等返回。
- 无流程历史的 draft 原样物理删除;历史 draft/rejected 保留 form/items/workflow/attachments,写 cancelled + deleted_at/deleted_by,并保留票据 PDF 引用/摘要;删除审计与释放同事务。
- 查询:共享报销可读条件、财务台账、原始 SQL 统计、门户计数及项目汇总排除删除标记。详情、材料按既有权限只读,进度不再要求继续处理。
- 并发补口:附件上传落库时重取单锁校验状态;项目关联使用条件 updateMany,防止读到可编辑状态后越过删除继续写入。
- 双端详情/列表允许退回删除,确认不填理由;手机删除位于“更多”,删除成功提示使用“报销单”而非“草稿”。历史详情及打印有删除标识。
- Prisma validate、相关 node --check、前端 typecheck/build 已通过。
- 后端最终 focused:22 文件、279/279,通过记录在 artifacts/qa-flow/20260910-rejected-delete/unit-final.log。运行目录为本副本 server;命令为 PAYMENT_ORDER_PYTHON_BIN=<既有 BIFF8 虚拟环境解释器> npx vitest run tests/unit/routes/reimbursements*.test.js tests/unit/routes/reimbursement.submit-side-effects.test.js tests/unit/routes/paymentBatches.reimbursement.test.js tests/unit/services/reimbursementVisibility.test.js tests/unit/services/financeLedger.test.js tests/unit/routes/exports*.test.js tests/unit/routes/search.test.js tests/unit/routes/portal.test.js tests/unit/routes/projects.test.js。
- 页面回归:本地构建产物 preview,system-action-confirmation.spec.ts --grep '报销',6/6;ui-preview.log。与真实隔离 HTTP/browser 分开计,不把 mock 页面回归当真实服务验收。
- 隔离:RUN_ISOLATED_DB_TEST=1 RUN_RETAINED_DELETE_TEST=1 RUN_BROWSER_TEST=1 node scripts/qa/test-invoice-first-http.cjs;真实 PostgreSQL、密码登录/JWT、HTTP、桌面/手机;合成票据,OCR 为手动调度真实 worker + mock provider。涵盖退回/驳回/撤回→删除→原历史/凭证可读→票据重用→新单提交;删除与 submit/bind/delete 锁屏障;审计异常全事务回滚。
- 增补原始统计/台账排除的最终复跑记录:final-isolated.log,PASS_REAL_DB_HTTP,退出 0;临时容器、合成文件和浏览器已清理。不以之前只输出 PASS 但退出 143 的管道运行替代完整退出结果。
- UI strict/self-test、错误解释 strict、process contract baseline、Trellis governance、git diff --check 通过;文档 registry 为 errors=0、warnings=1(既有 22 项未注册文件),不扩修。
调试与证据边界
- 首轮 BIFF8 回归 1 项失败为系统 python 缺 xlwt,使用既有专用解释器后 76 项付款相关测试通过;未修改付款产品逻辑。
- 隔离 fixture 最初复用了同一文件摘要,被真实重复发票门禁正确拒绝;改为每个场景独立合成 PDF,不通过假摘要/放宽去重绕过测试。
- 一轮新手机“更多”定位与旧构建产物不一致而超时;重建后真实双端通过。原日志留存,不把测试器问题写成业务通过。
- Vite dev 冷启动首项停在登录控件加载,终止该 mock 运行后改用构建产物 preview,6 项重跑通过;没有要求真实用户代测,也没有修改生产登录。
- 本轮保留删除时实际存在的流程、明细和凭证,不回填历史已释放票据、不补造过去提交版本。不可承诺完整重建原本未留存的历史快照。
- 当前状态:代码已实现、本地验证完成;发布未执行;真实业务删除未执行;等待独立复核及提交/部署授权。数据库 nullable 增量不等于旧应用可无损回滚:旧应用可能重新显示删除记录,需前向修复或经过审查的兼容回退。
- 主会话已只读检查任务 diff 的状态/参与人守卫、释放锁顺序、材料授权、查询旁路、迁移和回滚边界;独立 reviewer 尚未执行。复核包 artifacts/qa-flow/20260910-rejected-delete/changes.diff 包含本副本全部任务改动及未跟踪的迁移/测试文件,不含其他副本或生产数据。
下文是原 R1/R2 阶段清单,不能继承其无 migration 前提或勾选为本追加阶段的验收结果。
0. 启动门
- 用户批准本版
prd.md、design.md、implement.md后,才运行task.py start。 - 实施前使用
trellis-before-dev读取 frontend、backend、approval/workflow 和测试规约。 - 保持 inline 模式;不派 implement/check sub-agent。涉及权限和 workflow,编码完成后主会话执行只读 review。
1. R1 独立实现单元:待组批与付款阶段
- 为付款页增加 URL 驱动的
pending/batches/detail视图投影;锁定 manage/review 角色默认视图和直达边界。 - 把现有候选搜索、选择、分页和最小创建表单提升为唯一“待组批”主体,删除旧的重复入口/休眠 DOM。
- 候选标签展示服务端
total;实现加载、错误、空态、搜索、分页和选择后的组建动作。 - 报销详情 approved/no-batch 下一步改为“等待财务组建付款批次”;仅 manage 权限注入带编号搜索的深链。
- 调整报销处理进度组装,加入
payment_batch_created的报销专属“组建付款批次”投影;批次存在后继续完全复用共享付款语义。 - 创建成功刷新候选及批次查询,不做乐观业务状态写入。
- 完成 R1 focused 测试并形成第一个独立提交;不回填最终 task commit,直到整个任务候选提交完成。
R1 重点文件预计包括:
client/src/pages/PaymentBatchesPage.tsxclient/src/pages/ReimbursementDetailPage.tsxclient/src/api/paymentBatches.tsserver/src/routes/reimbursements.jsserver/src/services/paymentProcessingProgress.js(仅在共享阶段接口确需调整时)- 对应 server unit 与 client Playwright specs
2. R2 独立实现单元:草稿读取授权
- 提取“既有角色范围 + 报销业务事实”的服务端条件构建器,表驱动验证 global/team/own 边界。
- 应用于
/reimbursements列表并保证items/total同源。 - 应用于全局搜索、报销 CSV/XLSX 导出、报销统计/看板;原始 SQL 使用等价
EXISTS条件并验证不放大聚合。 - 收紧
ensureOwnCanViewAllOrWorkflowReviewer/ensureOwnOrCanViewAll或合并为等价统一 helper,使详情、附件文件、preview URL、完整材料 preview 和precheck对他人未提交 draft fail closed。 - 审计 helper 的所有调用方,确认写接口不因读取授权重构而放宽;保持 workflow reviewer 和本人路径,并增加审批人读取自己待办报销的负向保护。
- 增加 returned 与 withdrawn/cancelled workflow fixture,证明两类历史 draft 仍可见、可由申请人按既有规则继续处理。
- 完成 R2 focused 测试并形成第二个独立提交。
R2 重点文件预计包括:
server/src/routes/reimbursements.jsserver/src/routes/search.jsserver/src/routes/exports.jsserver/src/routes/dashboard.js- 可复用的报销 scope helper(优先放现有模块,不为单一条件新建过度抽象)
- 对应权限、详情、附件、搜索、导出与统计测试
3. Focused 验证
按实际测试文件补齐精确命令,最低包括:
cd server && node --check src/routes/reimbursements.js
cd server && node --check src/routes/paymentBatches.js
cd server && node --check src/routes/search.js
cd server && node --check src/routes/exports.js
cd server && node --check src/routes/dashboard.js
cd server && npm run prisma:validate
cd server && npx vitest run tests/unit/routes/reimbursements.detail.test.js tests/unit/routes/reimbursements.withdraw.test.js tests/unit/routes/paymentBatches.reimbursement.test.js
cd client && npm run typecheck
cd client && npm run build
node scripts/qa/check-ui-design-rules.mjs --strict
node scripts/qa/check-ui-design-rules.self-test.mjs
node scripts/qa/check-trellis-governance.mjs
git diff --check
还必须新增并执行:
- R1:候选 eligibility、manage/review 权限、视图 URL、搜索/分页/空态、创建后刷新、无批次/有批次三阶段进度矩阵。
- R2:角色 × owner/submitter/team × status × workflow-exists 表驱动矩阵;列表/详情/材料/precheck/搜索/导出/统计旁路一致性;workflow reviewer 待办读取不受误伤。
- 回归:付款批次
draft/reviewed/executed/failed/cancelled、maker-checker、报销退回/撤回/重提、B1/B2 和非报销 workflow 动作投影不变。
4. 只读 Review 门
提交前逐项只读复核:
- 候选资格是否仍只有服务端一处来源,前端没有复制
approved/unpaid/unbatched/gate判断。 - 无 batch 与 batch draft 的阶段是否分别为“待组批”和“待付款复核”,没有同义混用。
- 未提交他人 draft 是否在所有 record-level 旁路 fail closed,而 returned/withdrawn draft 仍按原范围可见。
- R2 是否没有放宽任何写能力、没有改变角色授权、没有引入 schema 或历史数据修正。
- R1/R2 是否可分别 revert 并各自构建、测试,不存在交叉 import 或数据前置。
5. 提交、部署与回滚
- Commit 1:中文提交信息引用
[09-04-reimbursement-state-gap-finance-view][R1]。 - Commit 2:中文提交信息引用
[09-04-reimbursement-state-gap-finance-view][R2]。 - 最终元数据提交把
task.json.commit指向最后一个业务提交;push、部署继续分别获得授权。 - 部署前紧邻执行
git status --porcelain --untracked-files=all、UI strict 和 provenance 核验。 - 部署后检查 PRD AC11;真实创建批次仍由财务执行。
- R1 回滚:revert R1 提交;已创建批次继续按原付款状态机处理。
- R2 回滚:revert R2 提交;不做数据库恢复。若只发现某一旁路遗漏,R2 整体不得宣称完成。