97 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# REV-003 营业收费 P0 审计记录
## 1. 记录信息
- 审计日期2026-07-14 至 2026-07-15
- 后端基线:`5fa11d5392f759be8560b5c696ace2bc814b2faf`
- 前端基线:`bd515cc3ade9a95a5ccb884f87d5625ebe3131b9`
- 文档基线:`8617af66fd45e6889bc02bebb4ba5fa95fc93cde`
- 审计范围:柜台收费、预存充值与抵扣、支付主明细、柜员结账、红冲、银行冲正、预存审批回调、前端收费和结账页面
- 执行约束:未运行 `vue-tsc`
## 2. 总体结论
营业收费已有客户查询、欠费查询、柜台收费、预存充值、支付记录、柜员结账和红冲骨架,但当前不能按财务级闭环验收通过。问题集中在金额口径、跨账单事务、结账范围、渠道确认、余额并发、幂等和反向流水,必须先完成 P0 交易内核整改,再继续扩展打印、开票和更多支付渠道。
## 3. P0 缺陷清单
### P0-01 应收金额口径断裂
`biz_charge.extended_amount` 的实体定义是不含违约金的本金金额,`late_fee` 独立保存;现有柜台支付却以 `extended_amount` 作为支付总额,再在支付明细中执行 `extended_amount - late_fee`。真实开账后产生违约金时,存在漏收违约金并错误压缩本金的风险。
统一口径:
```text
应收总额 = 本金 + 违约金
渠道实收 + 预存抵扣 = 应收总额 + 多缴转预存
```
### P0-02 多账单收费与多缴转预存不原子
前端逐账单调用 `PUT /business/charge/update`,全部成功后才单独调用预存充值。任一中间请求失败会形成部分账单已缴、部分账单未缴,或者账单已销但多缴未进入预存的状态。
### P0-03 通用营业账更新可作为支付入口
通用 `ChargeSaveReqVO` 暴露支付状态、收费员、收费时间、收费途径和金额字段。后端对零付、负数、少付和绕过前端的直接请求缺少完整金额覆盖校验,且客户端可指定收费员和收费时间。
### P0-04 柜员结账确认范围与实际范围不一致
前端确认框按当前分页和当前筛选行计算金额,请求只传 `cashierId`;后端收到后结清该收费员全部未结支付记录。页面确认金额不能约束真实落账范围。
### P0-05 预存抵扣无法与柜员实交资金对账
支付主单的 `payment_amount` 记录整张账单金额,柜员结账直接汇总该字段,会把预存抵扣也计入柜员应交资金。支付事实未分别保存渠道实收、预存抵扣和多缴转预存。
### P0-06 余额和支付记录缺少并发、幂等保护
账户余额采用查询后计算再全行更新,没有行锁、版本号或条件原子更新。柜台充值没有业务请求号;同一请求重试可能重复充值。同一账单并发收费也缺少数据库唯一约束。
### P0-07 已结账预存红冲无法成功
已结账预存红冲调用只匹配 `CHARGE_PAYMENT` 的 Mapper 方法;`DEPOSIT_TOPUP` 记录更新数必为零。现有单元测试通过 mock 返回成功,未覆盖真实 SQL 条件。
### P0-08 银行冲正和业务支付状态可能分裂
银行冲正以非空营业账对象作为成功条件。营业账不是可冲状态时可能没有发生业务反向处理,但银行交易仍被标记为已冲正。银行交易状态和业务支付入账也没有可重放的统一状态机。
### P0-09 预存审批回调可重放
审批成功回调缺少完成状态门禁,余额修改发生在支付退款去重之前,并存在绕过账户流水服务直接写余额的路径。重复回调可能重复扣款或重复转账。
## 4. 当前相对正确的链路
- 单线程柜台预存正常路径处于同一事务,并写支付记录、余额和账户流水。
- 单线程单账单收费可以写支付主明细并投影营业账状态。
- 柜台账单收费红冲已有反向支付、预存恢复和账单状态恢复结构。
- 柜员结账已有结账主明细、条件更新和重复结账防护基础。
- 缴费历史主要从 `PaymentRecord` / `PaymentRecordDetail` 读取,而不是完全依赖营业账结果字段。
这些正确性只在合法金额、单线程、合法入口和数据库约束完整部署的条件下成立。
## 5. 基线验证
前端在隔离工作树执行以下相关源码契约测试:
```bash
node --test \
src/views/operatingCharges/counterCharging/counterTopup.contract.test.mjs \
tests/revenue-bugs/counterChargeAndCheckoutDisplay.contract.test.mjs \
tests/rev006/counterCheckoutOldPageInventory.test.mjs
```
结果30 项22 通过、8 失败。失败属于整改前基线,其中既有旧测试与当前代码漂移,也有结账聚合和预存展示契约未对齐。
后端聚合定向测试首次执行超过等待窗口后被中止,未形成通过结论;实施阶段必须按单测试类执行并记录明确退出码。
## 6. 数据排查建议
若当前环境已经存在真实收费数据,实施上线前至少核对:
1. 已收账单的 `extended_amount + late_fee` 是否等于支付分配金额。
2. 支付主单、支付明细与账单投影是否一一对应。
3. 柜员结账金额是否剔除了预存抵扣并包含真实渠道实收。
4. 同客户、同金额、相近时间的预存充值是否存在重复请求。
5. 账户当前余额是否等于期初余额加全部有效账户流水净额。
6. 已冲正银行交易是否都有对应业务反向支付及账单状态恢复。