docs: allow negative invoice wallet balance on reimburse submit

Record the approved design to drop the hard balance gate while keeping full debit_reimburse occupancy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-12 20:55:47 +08:00
1 parent 5fcdb03da1
commit 12e8cdaaf9
1 file changed
+131
@@ -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`)后回升。
- 删票:若冲减后余额将 &lt; 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. 余额 &lt; 报销合计时,Web 与 bx-mobile 均可成功提交审批。
2. 提交后余额减少(可为负);流水存在对应 `debit_reimburse`。
3. 申请页仍展示余额与合计;不足仅弱提示,无拦截文案。
4. 余额充足时行为与现网一致。
5. 驳回 / 撤回后占用释放,余额回升。
6. 删票在冲减后余额将 &lt; 0 时仍拒绝。
7. 后续补票可使负余额回到 ≥ 0。
---
## 五、文档同步(实现时)
- 更新 `docs/business-inventory/03-报销业务明细.md` 额度规则:「提交全额占用,余额可为负;不足不拦截」。
- 实现计划另见 `docs/superpowers/plans/`(实现前由 writing-plans 产出)。
---
## 六、非目标
- 审批/发放页负余额提醒
- 部分占用或延后扣账
- 关联发票必填 / 金额覆盖硬校验
- miniprogram 改造