diff --git a/docs/superpowers/specs/2026-08-12-reimburse-allow-negative-invoice-balance-design.md b/docs/superpowers/specs/2026-08-12-reimburse-allow-negative-invoice-balance-design.md new file mode 100644 index 000000000..e96c58ec1 --- /dev/null +++ b/docs/superpowers/specs/2026-08-12-reimburse-allow-negative-invoice-balance-design.md @@ -0,0 +1,131 @@ +# 报销提交允许发票夹余额为负 — 设计文档 + +> **日期**: 2026-08-12 +> **状态**: 待实现 +> **仓库**: shanxia2.0(`backend/` + `web-admin/` + `bx-mobile/`) +> **前置 / 修订**: +> - `docs/superpowers/specs/2026-07-25-invoice-wallet-reimburse-design.md`(原规则:余额不足不可提交) +> - `docs/business-inventory/03-报销业务明细.md` + +## 背景与问题 + +发票夹上线后,报销「提交审批」要求申请人发票夹余额 ≥ 报销合计;不足则前后端均拦截。业务方希望:额度不足也可提交,因为申请人会**后续独立在发票夹补票**。 + +## 已确认决策 + +| # | 决策 | 说明 | +|---|------|------| +| D1 | **仍全额占用** | 提交时照常写 `debit_reimburse`;允许 `balance` 变为负 | +| D2 | **全端一致** | 后端 + Web 报销申请 + `bx-mobile` 统一放开;小程序当前无此校验,本期不改 | +| D3 | **弱提示、不拦截** | 保留「当前余额 / 本次合计」;不足时提示「余额不足,提交后余额将为负,请后续补发票」 | +| D4 | **删票保护不变** | 删票冲减后余额不得为负(`assert_can_delete_invoice`) | +| D5 | **不做** | 审批/发放页负余额二次提醒;提交部分占用;延后扣账;关联发票金额覆盖校验 | + +相对 `2026-07-25-invoice-wallet-reimburse-design`:**硬门槛「余额 ≥ 申请金额」废止**;扣/退时机与流水类型不变。冲突时以本文为准。 + +--- + +## 一、目标与范围 + +### 目标 + +报销提交审批不再因发票夹余额不足失败。提交仍按合计全额占用;申请人后续补票使余额回升。 + +### 范围内 + +- 后端:`InvoiceLedgerService.debit_reimburse` 去掉余额不足拦截 +- Web:`web-admin/src/views/bx/reimburse/apply/index.vue` 去掉提交拦截与强警告文案 +- 移动:`bx-mobile/src/views/reimburse/ReimburseApplyPage.vue` 同上 +- 文档:业务清单与相关表述同步 + +### 范围外 + +- 不改扣账时机(仍在 submit) +- 不改驳回/撤回释放、submit 幂等 +- 不加审批/发放提醒 +- 不改 miniprogram +- 不做补票后差额自动核销等新能力 + +--- + +## 二、行为规则 + +### 2.1 提交占用 + +1. 业务校验通过后,按报销合计写全额 `debit_reimburse`。 +2. **不再**因 `balance < amount` 抛错或前端拦截。 +3. 驳回 / 撤回仍写 `credit_release`(现有逻辑)。 +4. 同一单已有有效占用则跳过再扣(现有幂等)。 + +### 2.2 余额语义 + +``` +balance = Σ(credit_upload) − Σ(debit_delete) − Σ(debit_reimburse) + Σ(credit_release) +``` + +- 允许 `balance < 0`。 +- 负余额含义:已提交占用超过已上传发票总额;补票(`credit_upload`)后回升。 +- 删票:若冲减后余额将 < 0,仍拒绝(防止用删票抵消占用)。 + +### 2.3 关联发票 + +仍为可选;不要求关联票面金额覆盖报销合计。 + +### 2.4 并发 + +仍对 `BxInvoiceWalletSummary` 使用 `with_for_update()`;仅取消「余额不足拒绝」条件。 + +--- + +## 三、改动点 + +### 3.1 后端 + +| 位置 | 改动 | +|------|------| +| `backend/app/services/bx/invoice_ledger.py` → `debit_reimburse` | 删除 `if balance < amt: raise HTTPException(...)` | +| `release_reimburse` / `assert_can_delete_invoice` / `calc_summary` | 不改 | + +### 3.2 Web(`web-admin`) + +| 位置 | 改动 | +|------|------| +| 申请弹窗余额区 | 保留余额与合计;不足时弱提示改为「余额不足,提交后余额将为负,请后续补发票」;删除「提交时将被拦截」 | +| `handleToolbarSubmit` / `handleSubmit` | 删除提交前余额不足 `return` | +| `submitAdd`(存草稿) | 本就不拦,无需改逻辑 | + +### 3.3 bx-mobile + +| 位置 | 改动 | +|------|------| +| 申请页余额提示 | 去掉「无法提交」类文案;改为与 Web 一致的弱提示 | +| 保存成功对话框 | 去掉「请先充值发票夹后再提交」;不足时仍可点「提交审批」 | +| 确认提交分支 | 删除 `balanceInsufficient` 时 toast「余额不足,无法提交」并 return | + +--- + +## 四、验收标准 + +1. 余额 < 报销合计时,Web 与 bx-mobile 均可成功提交审批。 +2. 提交后余额减少(可为负);流水存在对应 `debit_reimburse`。 +3. 申请页仍展示余额与合计;不足仅弱提示,无拦截文案。 +4. 余额充足时行为与现网一致。 +5. 驳回 / 撤回后占用释放,余额回升。 +6. 删票在冲减后余额将 < 0 时仍拒绝。 +7. 后续补票可使负余额回到 ≥ 0。 + +--- + +## 五、文档同步(实现时) + +- 更新 `docs/business-inventory/03-报销业务明细.md` 额度规则:「提交全额占用,余额可为负;不足不拦截」。 +- 实现计划另见 `docs/superpowers/plans/`(实现前由 writing-plans 产出)。 + +--- + +## 六、非目标 + +- 审批/发放页负余额提醒 +- 部分占用或延后扣账 +- 关联发票必填 / 金额覆盖硬校验 +- miniprogram 改造