docs: record REV-003 charging P0 verification
This commit is contained in:
parent
e08c4a8e71
commit
17d0d07605
@ -227,17 +227,14 @@ flowchart TD
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[查询客户及待缴账单] --> B[选择账单与核销方式]
|
||||
B --> C[选择支付渠道]
|
||||
C --> D{支付方式}
|
||||
D -->|柜台现金/POS/扫码| E[现场收费]
|
||||
D -->|微信/支付宝/聚合支付| F[渠道下单]
|
||||
D -->|预存款/余额抵扣| G[账户余额核销]
|
||||
E --> H[更新营业账状态]
|
||||
F --> I[等待异步回调确认]
|
||||
G --> H
|
||||
I --> H
|
||||
H --> J[生成收费记录与凭证]
|
||||
J --> K[进入发票/对账流程]
|
||||
B --> C[服务端锁定账单与账户]
|
||||
C --> D[重算本金、违约金、预存抵扣和渠道实收]
|
||||
D --> E{支付渠道是否已确认}
|
||||
E -->|现金柜台| F[原子写支付主明细、账户流水和账单投影]
|
||||
E -->|未接通的非现金渠道| G[阻断直接销账]
|
||||
F --> H[返回支付批次与金额拆分]
|
||||
H --> I[按显式支付记录结账]
|
||||
I --> J[进入红冲、发票和对账流程]
|
||||
```
|
||||
|
||||
### 关键规则
|
||||
@ -247,10 +244,17 @@ flowchart TD
|
||||
3. 线上支付必须以回调或查询确认结果为准,不得以发起状态直接记账。
|
||||
4. 支付能力由 `SYS-009` 提供,SYS-002 负责账单核销与业务状态回写。
|
||||
5. 当前实现侧已确认 `PayCeb` 的欠费查询、缴费处理基础闭环可用,但代理收费对账仍为预留能力;正式文档不得将实时收费对账写成已闭环能力。
|
||||
6. 柜台收费必须通过 `POST /business/charge/counter-charge/submit` 一次提交全部账单;通用营业账更新不得把未收账单改为已收。
|
||||
7. 柜台应收固定按“本金 + 违约金”计算;支付事实分别保存渠道实收、预存抵扣和多缴转预存,柜员结账只汇总渠道实收。
|
||||
8. 客户端只提供业务请求号、账单范围和金额意图;收费员、收费时间和权限范围由服务端登录上下文确定。
|
||||
9. 当前新链路只允许现金直接完成。POS、扫码和其他非现金方式必须在真实渠道确认接通后再开放,不得仅凭前端选择销账。
|
||||
|
||||
### 核心数据
|
||||
|
||||
- `biz_charge`、`biz_charge_detail`:待缴与已缴账单主明细。
|
||||
- `biz_payment_record`、`biz_payment_record_detail`:支付事实、批次、幂等请求与金额拆分。
|
||||
- `biz_account`、`biz_account_log`:预存余额和不可缺失的账户变动流水。
|
||||
- `biz_settle_record`、`biz_settle_record_detail`:柜员结账主明细和红冲状态源。
|
||||
- `biz_collection`:托收/代收主表。
|
||||
- `biz_withholding`:代扣/托收主表。
|
||||
- `bk_transaction`:渠道交易流水。
|
||||
@ -262,12 +266,13 @@ flowchart TD
|
||||
#### 柜台结账
|
||||
|
||||
- 旧系统将“柜台收费”和“柜台结账”拆分为两个菜单,结账阶段包含未结/已结查询、结账红冲、追加抄表和打印动作。
|
||||
- 当前设计可继续采用统一收费核销模型,但必须补出“收费记录 → 班结结果 → 打印/红冲/查询”的业务闭环,避免柜面日终处理缺口。
|
||||
- 当前实现已形成“收费记录 → 显式选择结账 → 已结/未结红冲 → 查询”的主闭环;打印、补打和现金盘点仍按后续工作包补齐。
|
||||
- 迁移时需保留结账时间、结账人、网点、收费汇总口径和结账后红冲痕迹,保证财务对账与审计连续。
|
||||
- 当前正式实现中,柜台红冲分为已结账红冲与未结账红冲两条路径:
|
||||
- 已结账红冲以 `biz_settle_record_detail` 为红冲状态源,要求收费记录已结账且结账明细为正常状态,红冲后同步更新结账明细、支付主单和营业账结清状态。
|
||||
- 未结账红冲仅允许柜台收费、账单缴费、收款方向、未结账且未绑定结账单的收费记录;执行正式反向支付流水后,将原支付主单标记为 `REVERSED`,将营业账恢复为未收费,并写入未结账红冲投影表用于红冲记录查询。
|
||||
- 未结账红冲允许 `CHARGE_PAYMENT` 账单收费和 `DEPOSIT_TOPUP` 预存充值两类柜台收款记录。前者恢复营业账和预存抵扣,后者扣减账户余额;两类都写正式反向支付流水,原支付主单标记为 `REVERSED`,并写入未结账红冲投影用于查询。
|
||||
- 已结账与未结账收费记录不得混批红冲,前端应在未结账列表提供单笔红冲入口,后端仍以支付主单状态进行最终校验。
|
||||
- `DEPOSIT_TOPUP` 预存记录按已结账/未结账状态进入各自更新路径,扣减账户余额并写 `DEPOSIT_REFUND/OUT` 反向流水;原因必填且重复红冲由唯一约束和状态条件共同阻断。
|
||||
|
||||
#### 账单打印服务
|
||||
|
||||
@ -289,8 +294,8 @@ flowchart TD
|
||||
|
||||
### 落地边界
|
||||
|
||||
- **已落地**:营业账主明细、交易流水、回调、异常、托收/代扣主对象。
|
||||
- **部分落地**:柜台班结、部分收费汇总类对象可能通过业务流程与报表实现,不一定存在独立表;柜台未结账红冲已落地为正式反向支付流水 + 状态回写 + 查询投影。
|
||||
- **已落地**:营业账主明细、支付主明细、原子多账单柜台收费、幂等预存充值、账户行锁与流水、显式支付记录结账、已结/未结账单与预存红冲、支付汇总和历史查询。
|
||||
- **部分落地**:非现金柜台渠道仍需真实渠道确认后开放;打印、补打、柜员现金盘点和更完整的支付域 outbox 状态机尚未纳入本轮 P0。
|
||||
- **文档先行**:实时收费汇总类台账暂不表述为已确认独立实体表。
|
||||
|
||||
<a id="mod-rev-004"></a>
|
||||
|
||||
@ -430,9 +430,37 @@ retrieval_priority: P0
|
||||
| 接口编号 | IF-REV-006 |
|
||||
| 归属模块 | REV-003 |
|
||||
| 请求方式 | POST |
|
||||
| 请求路径 | `/admin-api/revenue/collection/create` |
|
||||
| 请求路径 | `/business/charge/counter-charge/submit` |
|
||||
| 功能描述 | 处理柜台收费、预存抵扣、渠道收款确认与账单核销 |
|
||||
| 核心表 | `biz_collection`、`biz_charge`、`bk_transaction` |
|
||||
| 核心表 | `biz_charge*`、`biz_payment_record*`、`biz_account*`、`biz_settle_record*` |
|
||||
|
||||
当前柜台子接口:
|
||||
|
||||
| 场景 | 方法与路径 | 请求关键字段 | 服务端约束 |
|
||||
|------|------------|--------------|------------|
|
||||
| 多账单柜台收费 | `POST /business/charge/counter-charge/submit` | `requestId`、`chargeIds`、`expectedReceivableAmount`、`actualPayAmount`、`usePrepay`、`chargeWay` | 同一事务锁账单和账户、重算金额、写支付批次、余额流水和账单投影;当前只允许现金直接完成 |
|
||||
| 无欠费预存充值 | `POST /business/charge/counter-topup` | `requestId`、`custId`、`amount`、`chargeWay`、`remark` | 以请求号幂等;收费员和时间由服务端生成;账户加锁后写余额和流水 |
|
||||
| 柜员结账 | `POST /business/charge/counter-settle/confirm` | `paymentRecordIds`、`settleTime`、`remark` | 只结清显式 ID;记录必须属于当前登录收费员且保持未结账;金额汇总 `channel_amount`,历史空值回退 `payment_amount` |
|
||||
| 柜台红冲 | `POST /business/charge/counter-settle/red-flush` | `paymentRecordIds`、必填 `reason` | 按已结/未结和账单收费/预存充值分流,写正式反向支付及账户流水,不允许混批或重复红冲 |
|
||||
| 收费汇总 | `GET /business/charge/payment-summary` | 收费员/网点与时间范围 | 分别返回渠道实收、预存抵扣、本金、违约金及按收费方式汇总 |
|
||||
|
||||
柜台收费请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"requestId": "0f70be44-7182-4f69-a4af-8aa7c43548b1",
|
||||
"chargeIds": [1001, 1002],
|
||||
"expectedReceivableAmount": 120.50,
|
||||
"actualPayAmount": 70.50,
|
||||
"usePrepay": true,
|
||||
"chargeWay": 1,
|
||||
"remark": "柜台收费"
|
||||
}
|
||||
```
|
||||
|
||||
返回的金额口径固定为:`totalReceivableAmount = channelAmount + prepayAmount - overpayTopupAmount`。`paymentRecordIds` 为后续结账、红冲和审计的权威范围,`paymentBatchNo` 用于关联一次多账单收费。
|
||||
|
||||
通用 `PUT /business/charge/update` 不再接受未收转已收、已收转未收等财务状态迁移;通用账户更新也不得直接改变预存余额。客户端提供的收费员、收费时间或账户余额不作为交易权威数据。
|
||||
|
||||
### IF-REV-007 账务调整接口
|
||||
|
||||
@ -1786,18 +1814,18 @@ sequenceDiagram
|
||||
| 场景 | 请求约束 | 状态变化 | 查询出口 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 已结账红冲 | 所有 `paymentRecordIds` 必须存在正常 `biz_settle_record_detail`,支付主单为 `SETTLED` | 写正式反向支付流水;结账明细标记红冲;原支付主单标记 `REVERSED`;营业账清除结账态 | 红冲记录页从结账明细读取 |
|
||||
| 未结账红冲 | 所有 `paymentRecordIds` 必须为柜台收费、账单缴费、收款方向、`UNSETTLED`、未绑定 `settle_id` | 写正式反向支付流水;原支付主单标记 `REVERSED`;营业账恢复未收费;写入 `biz_counter_unsettled_red_flush_record` | 红冲记录页从未结账红冲投影读取 |
|
||||
| 未结账红冲 | 所有 `paymentRecordIds` 必须为柜台收款方向、`UNSETTLED`、未绑定 `settle_id`,业务场景为 `CHARGE_PAYMENT` 或 `DEPOSIT_TOPUP` | 写正式反向支付流水并将原支付主单标记 `REVERSED`;账单收费恢复营业账和预存抵扣,预存充值扣减账户余额;写入 `biz_counter_unsettled_red_flush_record` | 红冲记录页从未结账红冲投影读取 |
|
||||
|
||||
接口拒绝以下情况:
|
||||
|
||||
- 已结账与未结账支付主单混批提交。
|
||||
- 未结账记录不是柜台账单缴费,或缺少可恢复的营业账。
|
||||
- 未结账记录不是允许的柜台账单缴费/预存充值,或缺少对应的可恢复营业账/可扣减账户余额。
|
||||
- 原支付主单已红冲、已结账状态并发变化,或已存在未结账红冲投影。
|
||||
- 当前登录收费员尝试红冲其他收费员的收费记录。
|
||||
|
||||
前端约束:
|
||||
|
||||
- 柜台结账“未结账”列表对单笔可红冲收费记录提供红冲按钮,仅对有 `paymentRecordId`、有 `chargeId` 且业务场景为 `CHARGE_PAYMENT` 的行启用。
|
||||
- 柜台结账“未结账”列表对有 `paymentRecordId` 且业务场景为 `CHARGE_PAYMENT` 或 `DEPOSIT_TOPUP` 的记录提供红冲入口,最终资格仍由服务端状态校验决定。
|
||||
- 柜台结账“已结账”明细继续提供已结账红冲入口。
|
||||
- 两类入口都必须采集非空红冲原因后再提交。
|
||||
|
||||
|
||||
@ -11,7 +11,9 @@
|
||||
|
||||
## 2. 总体结论
|
||||
|
||||
营业收费已有客户查询、欠费查询、柜台收费、预存充值、支付记录、柜员结账和红冲骨架,但当前不能按财务级闭环验收通过。问题集中在金额口径、跨账单事务、结账范围、渠道确认、余额并发、幂等和反向流水,必须先完成 P0 交易内核整改,再继续扩展打印、开票和更多支付渠道。
|
||||
基线审计时,营业收费虽已有客户查询、欠费查询、柜台收费、预存充值、支付记录、柜员结账和红冲骨架,但不能按财务级闭环验收通过。问题集中在金额口径、跨账单事务、结账范围、渠道确认、余额并发、幂等和反向流水。
|
||||
|
||||
截至 2026-07-15,本记录列出的 9 项 P0 已完成代码整改并通过定向测试、后端编译和前端 Vite 构建。新的柜台收费主链路达到“服务端原子提交、请求幂等、账户与账单加锁、金额拆分可对账、显式记录结账、账单与预存可红冲”的首批上线条件;非现金渠道、打印/补打和柜员现金盘点仍不在本轮 P0 范围内。
|
||||
|
||||
## 3. P0 缺陷清单
|
||||
|
||||
@ -94,3 +96,18 @@ node --test \
|
||||
5. 账户当前余额是否等于期初余额加全部有效账户流水净额。
|
||||
6. 已冲正银行交易是否都有对应业务反向支付及账单状态恢复。
|
||||
|
||||
## 7. P0 整改结果
|
||||
|
||||
| 缺陷 | 整改结果 |
|
||||
|------|----------|
|
||||
| P0-01 金额口径 | 服务端和前端统一按本金 + 违约金计算;支付主单显式保存渠道实收、预存抵扣和多缴转预存 |
|
||||
| P0-02 非原子收费 | 新增 `POST /business/charge/counter-charge/submit`,多账单、预存抵扣和多缴转预存在单事务内完成 |
|
||||
| P0-03 通用支付旁路 | 通用营业账更新禁止财务状态迁移,通用账户更新禁止直接改余额 |
|
||||
| P0-04 结账范围漂移 | 前端真实维护选择状态,后端只结清请求中的 `paymentRecordIds` |
|
||||
| P0-05 柜员实交失真 | 结账与汇总优先使用 `channel_amount`,预存抵扣单独展示 |
|
||||
| P0-06 并发与幂等 | 支付记录增加请求号/批次/唯一约束;账单与账户按序加锁并条件更新 |
|
||||
| P0-07 预存红冲 | 已结和未结 `DEPOSIT_TOPUP` 分别进入正确状态路径并写反向账户流水 |
|
||||
| P0-08 银行冲正分裂 | 业务反向未成功时银行交易不再标记已冲正 |
|
||||
| P0-09 回调重放 | 预存审批完成回调增加状态门禁、正式记录锁和账户服务幂等变更 |
|
||||
|
||||
详细命令、退出结果、提交清单和剩余风险见 `docs/evidence/rev003-charging/2026-07-15-p0-verification.md`。
|
||||
|
||||
123
docs/evidence/rev003-charging/2026-07-15-p0-verification.md
Normal file
123
docs/evidence/rev003-charging/2026-07-15-p0-verification.md
Normal file
@ -0,0 +1,123 @@
|
||||
# REV-003 营业收费 P0 验证证据
|
||||
|
||||
## 1. 验证结论
|
||||
|
||||
2026-07-15 完成营业收费 P0 代码整改和定向验收。后端营业模块 106 项测试、银行冲正 1 项测试、29 个 Maven reactor 模块编译、前端 38 项 Node 契约测试及 Vite 全量构建均通过。
|
||||
|
||||
验证期间未运行 `vue-tsc`。
|
||||
|
||||
## 2. 实施提交
|
||||
|
||||
### 后端 `fix/rev003-charging-p0`
|
||||
|
||||
| 提交 | 内容 |
|
||||
|------|------|
|
||||
| `098749d58` | 增加柜台支付幂等和金额拆分字段 |
|
||||
| `04a5247a2` | 统一本金与违约金口径 |
|
||||
| `d72a360f2` | 账户加锁并去重柜台预存充值 |
|
||||
| `276d90df7` | 新增原子多账单柜台收费命令 |
|
||||
| `25c385c27` | 封堵通用财务状态和余额修改旁路 |
|
||||
| `f0b906048` | 按显式支付记录执行柜员结账 |
|
||||
| `6c2e4850c` | 修复已结/未结预存红冲状态路径 |
|
||||
| `a4d3cc0cc` | 防止银行假冲正和预存回调重放 |
|
||||
|
||||
### 前端 `fix/rev003-charging-p0`
|
||||
|
||||
| 提交 | 内容 |
|
||||
|------|------|
|
||||
| `fe21be95` | 柜台收费切换为单次原子批量提交 |
|
||||
| `06a5d70a` | 柜台结账只提交显式勾选的支付记录 |
|
||||
|
||||
## 3. 后端验证
|
||||
|
||||
### 营业模块定向测试
|
||||
|
||||
```bash
|
||||
mvn -pl sw-business/sw-business-server \
|
||||
-Dtest=CounterChargeAmountCalculatorTest,CounterChargeApplicationServiceImplTest,PaymentRecordServiceImplTest,ChargeServiceCounterPaymentTest,AccountServiceImplConcurrencyTest,CounterSettleApplicationServiceImplTest,PaymentQueryServiceTest,PrestorageBpmCallbackServiceTest \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false test
|
||||
```
|
||||
|
||||
结果:退出码 0,`Tests run: 106, Failures: 0, Errors: 0, Skipped: 0`,`BUILD SUCCESS`。
|
||||
|
||||
### 银行冲正测试
|
||||
|
||||
```bash
|
||||
mvn -pl sw-business-bank/sw-business-bank-server \
|
||||
-Dtest=PayInvalidServiceImplTest \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false test
|
||||
```
|
||||
|
||||
结果:退出码 0,`Tests run: 1, Failures: 0, Errors: 0, Skipped: 0`,`BUILD SUCCESS`。测试日志中的异常栈为用例主动模拟业务红冲失败,用于验证银行原交易不会被错误标记为已冲正。
|
||||
|
||||
### 后端编译
|
||||
|
||||
```bash
|
||||
mvn -pl sw-business/sw-business-server,sw-business-bank/sw-business-bank-server \
|
||||
-am -DskipTests compile
|
||||
```
|
||||
|
||||
结果:退出码 0,29 个 reactor 模块全部 `SUCCESS`,最终 `BUILD SUCCESS`。
|
||||
|
||||
## 4. 前端验证
|
||||
|
||||
### P0 契约测试
|
||||
|
||||
```bash
|
||||
node --test \
|
||||
tests/operatingCharges/counterChargingP0Flow.test.mjs \
|
||||
tests/operatingCharges/counterCheckoutExplicitSelection.test.mjs \
|
||||
src/views/operatingCharges/counterCharging/counterTopup.contract.test.mjs \
|
||||
src/views/operatingCharges/counterCheckout/redFlushReason.contract.test.mjs \
|
||||
tests/operatingCharges/counterChargingZeroAmount.contract.test.mjs \
|
||||
tests/revenue-bugs/counterChargeAndCheckoutDisplay.contract.test.mjs \
|
||||
tests/rev006/counterCheckoutOldPageInventory.test.mjs
|
||||
```
|
||||
|
||||
结果:退出码 0,`tests 38`、`pass 38`、`fail 0`。
|
||||
|
||||
覆盖点包括:
|
||||
|
||||
- 本金与违约金按分计算,拒绝非法和负数金额。
|
||||
- 同一批次只调用一次原子收费接口,重试期间复用请求号。
|
||||
- 无欠费预存可连续操作,零金额账单不会误进入预存模式。
|
||||
- 当前仅现金渠道可直接提交,配置异常时仍回退现金安全项。
|
||||
- 结账只提交明确勾选且去重后的支付记录 ID;切换支付方式或刷新数据时清除选择。
|
||||
- 结账金额和展示优先使用渠道实收,预存抵扣独立表达。
|
||||
- 已结、未结红冲原因均为必填。
|
||||
|
||||
### Vite 全量构建
|
||||
|
||||
`build:dev` 脚本已确认仅执行 `vite build --mode dev`,不包含 `vue-tsc`。
|
||||
|
||||
第一次按 Node 默认堆上限执行时,在 Rollup 大体量打包阶段触发约 4GB 堆上限,报 `JavaScript heap out of memory`。随后不修改源码和构建配置,仅提高本次 Node 堆上限复验:
|
||||
|
||||
```bash
|
||||
NODE_OPTIONS=--max-old-space-size=8192 \
|
||||
node ./node_modules/vite/bin/vite.js build --mode dev
|
||||
```
|
||||
|
||||
结果:退出码 0,输出 `Build successful. Please see dist directory`。
|
||||
|
||||
构建仍会输出项目既有的中文 SVG `symbolId` 命名警告和 Rollup `PURE` 注释警告,本轮未新增相关资源,也不影响构建成功。
|
||||
|
||||
## 5. 数据库集成门禁
|
||||
|
||||
当前环境未设置 `REV004_IT_DB_URL`,因此未执行依赖真实数据库的可选集成测试。上线前仍需在目标 PostgreSQL 环境验证:
|
||||
|
||||
1. 新增列、条件唯一索引和历史空值兼容 DDL 已完整部署。
|
||||
2. 同一 `requestId` 重试不重复收费或充值。
|
||||
3. 同一账单并发收费只有一个请求成功,失败批次不留下部分支付或余额变化。
|
||||
4. 柜员结账金额等于所选记录的渠道实收之和。
|
||||
5. 已结/未结预存红冲正确扣减余额并生成唯一反向流水。
|
||||
|
||||
## 6. 已知非本轮问题
|
||||
|
||||
实施期间单独运行完整 `ChargeServiceAccountingAdjustTest` 时,既有用例 `testAdjustAccounting_usageGarbageFeeUsesCustomerBasicNumberOnly` 出现期望 `12.34`、实际 `1221.66` 的失败。该用例属于用量垃圾费账务调整,不在 REV-003 P0 范围;本轮涉及的通用财务旁路定向方法测试和上述 106 项收费测试均已通过。该问题应作为 REV-004 独立缺陷继续处理。
|
||||
|
||||
## 7. 发布约束
|
||||
|
||||
1. 先部署数据库 DDL,再部署后端,最后部署前端。
|
||||
2. 不回退通用营业账/账户更新的财务旁路封堵。
|
||||
3. 首批只开放现金柜台收费;非现金渠道接入真实确认前保持禁用。
|
||||
4. 上线后按 `payment_batch_no`、`request_id`、账户流水和结账差异持续观察。
|
||||
@ -1,5 +1,12 @@
|
||||
# REV-003 Charging P0 Remediation Implementation Plan
|
||||
|
||||
## Execution status (2026-07-15)
|
||||
|
||||
- Backend Tasks 1-8 are implemented and committed; 106 focused business tests, 1 bank-reversal test, and the 29-module compile passed.
|
||||
- Frontend Tasks 9-10 are implemented and committed; 38 Node contract tests and the full Vite build passed.
|
||||
- Task 11 formal design, audit update, and verification evidence are complete. `vue-tsc` was not run.
|
||||
- `REV004_IT_DB_URL` is unset in this environment, so real-database integration remains a release gate rather than a local completion result.
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Replace the unsafe per-bill generic update flow with an atomic, idempotent counter-charge command and make amounts, settlement, top-up reversal, account concurrency, bank reversal, and callback replay financially consistent.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user