fix: 退回报销支持留痕删除(09-04-reimbursement-state-gap-finance-view)

这个提交包含在:
2026-09-10 16:38:37 +08:00
父节点 e5685f18b2
当前提交 73fcd5a65a
共修改 27 个文件,包含 696 行新增和 94 行删除
@@ -5,6 +5,37 @@
Read `docs/报销发票附件规则.md` before changing reimbursement, invoice, OCR,
duplicate detection or attachment behavior.
## Retained Reimbursement Deletion
- DELETE /reimbursements/:id requires expense.delete_own and owner/submitter
participation, including idempotent retries. Global reading or wildcard alone
never substitutes for participation.
- Only draft/rejected may be deleted, with no active workflow/task, non-cancelled
payment reservation, paid_at or non-bound associated invoice. Lock the form
before invoices, then release only invoices still bound to that form.
- A never-submitted draft may be physically deleted. Rejected or any draft with
workflow history must retain the form/items/workflow/attachments and set
cancelled + deleted_at/deleted_by. Never infer history absence from draft.
- Before release, preserve current invoice PDF object references/hash as invoice
attachments of the old form; use its existing material authorization, not the
invoice's future binding. Storage objects are immutable; any future physical
cleanup must account for retained reimbursement attachment references.
- Audit, evidence references, release and deletion are one transaction. Failed
audit must roll back every database effect. Historical invoices already
released before this change are not reconstructed or silently rebound.
- Normal reads exclude deleted_at records through shared visibility/ledger
filters; raw statistics, portal counts and project summaries must also exclude
them. Authorized historical detail/material reads remain, with deletedAt and
terminated next-action projection. No role-grant changes.
- Verify with RUN_ISOLATED_DB_TEST=1 RUN_RETAINED_DELETE_TEST=1 RUN_BROWSER_TEST=1
node scripts/qa/test-invoice-first-http.cjs after building the current client.
Uses disposable PostgreSQL, synthetic accounts/files and real auth/HTTP/browser;
OCR in this suite is mock-provider, not production Tencent evidence.
- Migration adds nullable fields and a deleted-state check. After retained
deletion exists, old code can redisplay it; image rollback alone is not
behavior-preserving. Prefer forward repair or an explicitly reviewed compatible
rollback; do not remove history or reverse current invoice bindings blindly.
## Rules
- 隔离串联的 `RUN_JOB_QUEUE=1` 必须运行真实 startPgBossJobs 与上传入口 enqueue,