From 55b44a585c9710180a9a5b3b959903f734d49d5b Mon Sep 17 00:00:00 2001 From: tangweijie <877588133@qq.com> Date: Fri, 19 Jun 2026 11:00:52 +0800 Subject: [PATCH] docs(accounting): design unsold preview option formalization --- ...19-rev004-unsold-preview-options-design.md | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-19-rev004-unsold-preview-options-design.md diff --git a/docs/superpowers/specs/2026-06-19-rev004-unsold-preview-options-design.md b/docs/superpowers/specs/2026-06-19-rev004-unsold-preview-options-design.md new file mode 100644 index 0000000..81c2a05 --- /dev/null +++ b/docs/superpowers/specs/2026-06-19-rev004-unsold-preview-options-design.md @@ -0,0 +1,155 @@ +# 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` | 增加 `updateAccumulated`、`updateBaseCode` | +| 统一 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` | 增加 `calculateGarbageFee`、`updateAccumulatedVolume` | +| Internal API | `PriceDiffAdjustInternalApiImpl` | 将字段写入正式化 VO | +| 正式明细 DO/表 | `PriceDiffAdjustDetailDO` / `biz_price_diff_adjust_detail` | 增加或复用可审计字段 | +| 正式化服务 | `PriceDiffFormalizationService` | 保存 `isLadder`、`calculateGarbageFee`、`updateAccumulatedVolume` | +| 回写服务 | `PriceDiffWriteBackService` | 使用一致默认值并执行回写 | +| 审批回写 | `AccountingAdjustActionServiceImpl` | 从正式明细或日志明细读取三项参数 | +| 测试 | 相关 unit test | 覆盖预算参数到正式回写的一致性 | + +## 数据持久化策略 + +优先在价差正式明细表增加明确字段: + +| 字段建议 | 类型 | 含义 | +| --- | --- | --- | +| `is_ladder` | smallint | 是否阶梯计费 | +| `calculate_garbage_fee` | smallint | 是否计算垃圾费 | +| `update_accumulated_volume` | smallint | 是否更新累计量 | + +如短期不便改表,可先将字段写入操作日志明细,但这只能作为过渡方案。正式审计与回写更推荐落入正式对象表。 + +水量调整当前走 legacy-only 即时回写,没有独立正式对象表;本轮可先通过操作日志明细记录 checkbox 参数,并在 `ChargeServiceImpl` 即时回写中使用。 + +## 错误处理 + +1. 水量调整 `updateBaseCode=true` 且 `currentReading` 为空时,拒绝提交。 +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/`。 +