160 lines
7.7 KiB
Markdown
160 lines
7.7 KiB
Markdown
# 柜台预存持久回显与缴费历史修复设计
|
||
|
||
日期:2026-07-13
|
||
|
||
## 背景
|
||
|
||
柜台无欠费客户完成预存后,页面会临时插入一条“预存款 / 收讫”记录。该记录只存在于前端内存,重新查询客户时会被清除。与此同时,客户缴费记录接口虽然查询了多条有效支付主单,却只返回其中最新一条,导致较早的预存记录被后续缴费记录覆盖。缴费记录响应中的期初余额、期末余额字段也未从可靠的账务快照赋值。
|
||
|
||
本次修复以 `biz_payment_record` 为缴费记录主数据源,以 `biz_account_log` 的余额变动快照为余额证据,建立“预存成功后显示、重新查询后仍能从后端恢复、客户历史可完整分页查询”的闭环。
|
||
|
||
## 目标
|
||
|
||
1. 无欠费客户完成柜台预存后,当前页面继续展示“预存款 / 收讫”记录。
|
||
2. 重新查询同一无欠费客户时,页面从后端支付记录恢复最近一笔有效预存,不依赖前端缓存。
|
||
3. 客户详情的缴费记录按时间倒序返回全部有效历史,并保持正确分页、统计和导出语义。
|
||
4. 新产生的预存记录能够展示可追溯的期初余额和期末余额。
|
||
5. 已红冲支付记录不作为有效预存回显,也不进入正常缴费历史。
|
||
|
||
## 非目标
|
||
|
||
- 本次不修复主副卡付款户解析错误和柜台有效余额读取错误。
|
||
- 本次不对无法可靠关联账户流水的旧支付记录伪造期初、期末余额。
|
||
- 本次不把所有历史预存与当前待收费账单混合展示。
|
||
- 本次不引入浏览器本地缓存、`localStorage` 或跨会话前端状态作为账务记录来源。
|
||
|
||
## 方案选择
|
||
|
||
采用“后端持久记录回显”方案:
|
||
|
||
- 缴费历史接口返回全部符合条件的有效支付主单,再由现有分页参数截取当前页。
|
||
- 查询请求增加可选业务场景过滤;柜台页面用 `DEPOSIT_TOPUP` 精确查询最近一笔有效预存。
|
||
- 柜台页面仅在当前客户没有待缴账单时回显最近预存,避免历史记录进入可勾选的待收费账单集合。
|
||
- 新预存交易将支付主单 ID 写入对应账户流水来源字段,并由查询层映射余额变动前后值。
|
||
|
||
不采用以下方案:
|
||
|
||
- 仅保留前端临时数组或写入浏览器缓存:换页面、换设备或重新登录后仍会丢失,也不能作为账务证据。
|
||
- 无条件把最近预存和待缴账单混合展示:会让历史收款记录进入当前收费语境,增加误选和重复收费风险。
|
||
|
||
## 后端设计
|
||
|
||
### 缴费历史查询
|
||
|
||
将当前“查询全部候选记录后只保留第一条”的实现改为返回全部有效候选记录:
|
||
|
||
- 继续按 `payTime`、`id` 倒序排列。
|
||
- 继续使用现有可见性规则过滤已红冲及非正常记录。
|
||
- `skipCount`、`maxResultCount` 在过滤后的完整集合上分页。
|
||
- `totalCount`、`totalAmount`、`topUpCount`、`topUpTotalMoney` 均基于过滤后的完整集合计算。
|
||
- 导出使用与页面查询相同的过滤规则,但不受页面分页截断。
|
||
|
||
`PaymentRecordPageNewReqVO` 增加可选 `bizScene`:
|
||
|
||
- 未传时保持客户缴费历史的全场景查询。
|
||
- 传 `DEPOSIT_TOPUP` 时只返回柜台预存记录。
|
||
- 过滤由后端查询条件完成,不由前端拉取一页数据后自行猜测。
|
||
|
||
### 预存余额快照关联
|
||
|
||
柜台预存保持单事务执行,但调整事务内顺序:
|
||
|
||
1. 创建 `DEPOSIT_TOPUP` 支付主单,获得 `paymentRecordId`。
|
||
2. 增加实际付款账户预存余额。
|
||
3. 写入账户流水时,将 `paymentRecordId` 写入 `payDetailId`。
|
||
4. 返回支付主单信息和变更后余额。
|
||
|
||
任一步失败时整个事务回滚,不留下只有支付记录或只有余额变动的半成品。
|
||
|
||
查询缴费历史时,针对 `DEPOSIT_TOPUP` 通过 `payDetailId = paymentRecordId` 获取账户流水:
|
||
|
||
- `lastDeposit` 映射 `balanceBefore`。
|
||
- `deposit` 映射 `balanceAfter`。
|
||
|
||
旧数据如果没有 `payDetailId` 关联,不按金额和时间做模糊匹配,期初、期末余额显示为空值,由前端展示 `-`,避免错误余额成为账务证据。
|
||
|
||
### 红冲兼容
|
||
|
||
- 已红冲原支付主单继续由现有可见性规则排除。
|
||
- 红冲反向支付记录不作为正常 `DEPOSIT_TOPUP` 回显。
|
||
- 柜台页面查询最近预存时只取最新一笔有效、未红冲的收入记录。
|
||
|
||
## 前端设计
|
||
|
||
### 柜台预存成功展示
|
||
|
||
预存成功后仍可立即显示本次“预存款 / 收讫”记录,但显示内容以接口返回的支付主单 ID、支付时间、金额和收费方式为准,不再使用时间戳伪造记录 ID。
|
||
|
||
### 重新查询恢复
|
||
|
||
`loadCustomerChargeData(custId)` 完成待缴账单和统计查询后:
|
||
|
||
- 有待缴账单:按现有逻辑展示待缴账单,不混入历史预存。
|
||
- 无待缴账单:调用缴费历史接口,传入 `custId`、`bizScene=DEPOSIT_TOPUP`、`skipCount=0`、`maxResultCount=1`。
|
||
- 查询到有效预存:转换为不可勾选的“预存款 / 收讫”展示行。
|
||
- 没有有效预存:保持空表状态。
|
||
- 恢复查询失败:不影响客户和待缴账单主查询,记录错误并提示“最近预存记录加载失败”。
|
||
|
||
历史回显行只用于确认最近一次成功预存,不参与选中账单、应收统计或再次收费计算。
|
||
|
||
### 客户缴费记录
|
||
|
||
客户详情沿用现有分页组件和接口参数。后端返回完整结果后:
|
||
|
||
- 翻页能看到较早记录。
|
||
- 统计金额和笔数使用完整过滤结果。
|
||
- 有可靠账户流水关联的新预存显示期初、期末余额。
|
||
- 无可靠余额证据的旧记录继续显示 `-`,不得转成 `0`。
|
||
|
||
## 错误处理
|
||
|
||
- 支付主单创建或余额增加失败时事务整体回滚,前端不插入成功行。
|
||
- 最近预存查询失败不清空客户基本信息和待缴账单结果。
|
||
- 接口返回空记录时不沿用上一个客户的预存展示行。
|
||
- 已红冲记录不可通过页面刷新重新出现。
|
||
|
||
## 测试设计
|
||
|
||
### 后端单元测试
|
||
|
||
1. 两条有效支付记录均进入候选集合,分页返回正确记录和总数。
|
||
2. 最新记录已红冲时被过滤,较早有效记录仍可查询。
|
||
3. `bizScene=DEPOSIT_TOPUP` 时只返回预存记录。
|
||
4. 汇总金额、预存笔数和预存金额基于全部有效记录计算。
|
||
5. 新柜台预存先生成支付主单,再写入带 `paymentRecordId` 的账户流水。
|
||
6. 有账户流水关联时正确映射 `balanceBefore`、`balanceAfter`;无关联时余额字段为空。
|
||
7. 导出包含全部有效记录,不退化为只导出最新一条。
|
||
|
||
### 前端测试
|
||
|
||
1. 无欠费客户重新查询时调用 `DEPOSIT_TOPUP` 过滤接口并恢复最近预存行。
|
||
2. 有待缴账单时不把历史预存混入待收费列表。
|
||
3. 切换客户时清空上一客户的临时或持久回显行。
|
||
4. 最近预存加载失败时不破坏客户待缴账单查询结果。
|
||
5. 客户缴费记录翻页使用后端完整总数,余额空值显示 `-` 而不是 `0`。
|
||
|
||
## 验收标准
|
||
|
||
1. 无欠费客户预存成功后可立即看到“预存款 / 收讫”记录。
|
||
2. 刷新页面或重新输入同一客户查询,仍能从后端恢复最近一笔有效预存。
|
||
3. 新增另一笔缴费后,客户缴费记录仍可通过分页查到之前的预存记录。
|
||
4. 已红冲预存不再作为最近有效预存回显。
|
||
5. 新预存记录显示正确的期初、期末余额;无法可靠恢复余额的旧数据显示 `-`。
|
||
6. 历史预存回显不参与当前收费选择和金额统计。
|
||
|
||
## 影响文件
|
||
|
||
后端预计修改:
|
||
|
||
- `PaymentRecordPageNewReqVO.java`
|
||
- `PaymentQueryServiceImpl.java`
|
||
- `ChargeServiceImpl.java`
|
||
- `AccountLogMapper.java`
|
||
- 对应后端单元测试
|
||
|
||
前端预计修改:
|
||
|
||
- `src/api/operatingCharges/counterCharging/index.ts`
|
||
- `src/views/operatingCharges/counterCharging/index.vue`
|
||
- 对应前端源码契约或页面状态测试
|