fujian_water_biz_doc/docs/superpowers/specs/2026-06-19-rev004-unsold-preview-options-design.md

7.9 KiB

REV-004 未销调整预算参数正式化设计

文档信息

项目 内容
项目名称 福建水务营收系统
模块 REV-004 账务处理 / 未销调整
文档类型 实现前设计草案
编写日期 2026-06-19
状态 待实现

背景

未销调整页存在若干只在预算阶段生效的 checkbox 参数,例如水量调整的累计量、底码计算,以及价差调整的阶梯计费、垃圾费计算、累计量更新。当前后端现状是:部分参数参与预算,但没有完整进入正式提交、正式调整对象、审批回写和账单重算链路,导致“预算结果”和“正式入账结果”存在不一致风险。

本设计目标是将预算阶段的 checkbox 语义升级为正式调整参数,保证用户在预算页勾选的计算口径能够被正式提交、审计记录和最终回写一致承接。

设计目标

  1. 预算参数在正式提交时不丢失。
  2. 正式调整对象能够记录预算参数,形成审计轨迹。
  3. 审批或自动执行回写时使用与预算一致的计算开关。
  4. 未传 checkbox 时保持现有默认行为,避免破坏旧调用方。
  5. 只补齐未销调整相关链路,不扩大到已销、预存和其他 REV 场景。

非目标

  1. 不重构完整 REV-004 账务调整状态机。
  2. 不引入新的预算快照 token 机制。
  3. 不改变已收费、已开票、已结账等既有边界校验。
  4. 不在本轮统一改造前端 UI 布局,仅约束前后端字段语义。

推荐方案

采用“最小补链路”方案:沿用现有未销调整接口和正式对象结构,补齐缺失字段和默认值语义。

相比新增统一 adjustOptions 或预算快照机制,该方案改动范围较小,能快速解决当前预算与正式回写不一致的问题;后续如果 REV-004 进入全量对象化改造,再考虑统一参数模型。

水量调整设计

参数

水量预算已有参数:

字段 含义 当前预算行为 正式化要求
targetBillWater 调整后水量 参与费用重算 已支持,继续作为正式重算水量
updateAccumulated 是否计算累计量 返回调整前后累计量 正式提交需承接,并按水量差额更新账单累计量
updateBaseCode 是否计算底码 返回调整前后底码 正式提交需承接,并配合 currentReading 更新本次抄码/底码
currentReading 本次抄码 预算阶段不作为 checkbox 正式提交继续保留,作为底码正式值来源

正式行为

  1. targetBillWater 始终参与费用重算。
  2. updateAccumulated=true 时,正式回写按 targetBillWater - 原billWater 调整账单累计量字段。
  3. updateBaseCode=true 时,正式回写允许更新本次抄码;若未传 currentReading,应拒绝提交并提示“更新底码必须传入本次抄码”。
  4. 两个 checkbox 未传时默认 false,保持旧行为。
  5. 费用重算仍使用当前水价模板、费用组成、优惠方案和用水方案,不额外改变计费规则。

影响文件

后端需要补齐:

层级 文件/对象 改动
API VO AccountingAdjustUnsoldAdjustSubmitReqVO 增加 updateAccumulatedupdateBaseCode
统一 DTO AccountingAdjustSubmitReqVO 增加同名字段
Controller 映射 AccountingAdjustActionController 将字段映射到统一 DTO
核心调整 VO AccountingAdjustReqVO 增加同名字段
过程服务 AccountingAdjustProcessServiceImpl 将字段传入核心调整 VO
回写服务 ChargeServiceImpl 水量正式调整时执行累计量/底码更新
测试 相关 unit test 覆盖字段映射、底码必填、累计量更新

价差调整设计

参数

价差预算已有参数:

字段 含义 当前预算行为 正式化要求
isLadder 是否阶梯计费 false 时使用第一档单价平铺 正式回写必须使用相同值
calculateGarbageFee 是否计算垃圾费 false 时排除费用项 103 正式回写必须使用相同值
updateAccumulatedVolume 是否更新客户累计量 提交 VO 已有字段,但正式对象链路不完整 正式对象和回写需保存并使用

正式行为

  1. isLadder=false 时,正式回写按非阶梯算法生成新账单,不能回退为阶梯算法。
  2. calculateGarbageFee=false 时,正式回写不生成垃圾费金额。
  3. updateAccumulatedVolume=true 时,生成新账单后同步累计量相关字段;为 false 时不更新累计量。
  4. 默认值必须与预算一致:
    • isLadder:未传时按 true 处理。
    • calculateGarbageFee:未传时按 true 处理。
    • updateAccumulatedVolume:未传时按现有前端默认值处理;后端建议默认 true,但需与前端确认。
  5. 禁止在正式回写阶段将缺失字段解释为 false

影响文件

后端需要补齐:

层级 文件/对象 改动
提交 VO AccountingAdjustUnsoldPriceDiffSubmitReqVO 已有字段,补测试确认不丢失
统一 DTO AccountingAdjustSubmitReqVO 已有字段,补映射测试
核心调整 VO AccountingAdjustReqVO 已有字段,校正默认值语义
正式创建 DTO PriceDiffAdjustCreateReqDTO 增加 calculateGarbageFeeupdateAccumulatedVolume
Internal API PriceDiffAdjustInternalApiImpl 将字段写入正式化 VO
正式明细 DO/表 PriceDiffAdjustDetailDO / biz_price_diff_adjust_detail 增加或复用可审计字段
正式化服务 PriceDiffFormalizationService 保存 isLaddercalculateGarbageFeeupdateAccumulatedVolume
回写服务 PriceDiffWriteBackService 使用一致默认值并执行回写
审批回写 AccountingAdjustActionServiceImpl 从正式明细或日志明细读取三项参数
测试 相关 unit test 覆盖预算参数到正式回写的一致性

数据持久化策略

优先在价差正式明细表增加明确字段:

字段建议 类型 含义
is_ladder smallint 是否阶梯计费
calculate_garbage_fee smallint 是否计算垃圾费
update_accumulated_volume smallint 是否更新累计量

如短期不便改表,可先将字段写入操作日志明细,但这只能作为过渡方案。正式审计与回写更推荐落入正式对象表。

水量调整当前走 legacy-only 即时回写,没有独立正式对象表;本轮可先通过操作日志明细记录 checkbox 参数,并在 ChargeServiceImpl 即时回写中使用。

错误处理

  1. 水量调整 updateBaseCode=truecurrentReading 为空时,拒绝提交。
  2. checkbox 字段为空时统一按场景默认值处理,不能因空值导致预算与正式回写默认相反。
  3. 正式回写读取不到价差参数时,按默认值补齐,并记录兼容说明。
  4. 已收费、已开票、已结账等既有拒绝规则不变。

测试策略

最小测试集:

  1. 水量预算允许 targetBillWater=0 且金额为 0。
  2. 水量正式提交携带 updateAccumulated=true 时,累计量按水量差额更新。
  3. 水量正式提交 updateBaseCode=true 且缺少 currentReading 时拒绝。
  4. 价差预算 calculateGarbageFee=false,正式回写后新账单垃圾费为 0。
  5. 价差预算 isLadder=false,正式回写后按第一档单价计算。
  6. 价差提交 updateAccumulatedVolume=false 时,正式回写不更新累计量。
  7. checkbox 未传时,旧测试保持通过。

验收标准

  1. 预算和正式回写使用同一组 checkbox 参数。
  2. 正式调整记录或操作日志可追溯 checkbox 入值。
  3. 价差回写不再因字段缺失将 calculateGarbageFee 默认成 false
  4. 水量调整的累计量、底码 checkbox 不再只停留在预算响应。
  5. 后端最小验证命令通过,并将验证结果记录到 docs/evidence/rev004-accounting/