docs(rev004): add development evidence records

This commit is contained in:
tangweijie 2026-05-18 17:37:51 +08:00
parent 7d3472fe8a
commit fca2d54566
27 changed files with 4164 additions and 0 deletions

View File

@ -0,0 +1,22 @@
# REV004 账务调整统一化改造 — 第一批开发入口2026-04-15
## 说明
基于已完成的 P0 标准层工件,本轮已进一步拆出第一批可执行开发任务单,作为后续真正进入代码实现的入口。
## 第一批试点对象
- `late-fee reduce`(违约金减免)
## 第一批任务单
- `.omx/plans/first-batch-dev-tasklist-rev004-accounting-adjust-unification.md`
## 核心内容
1. 最小标准层 helper 落地
2. late-fee reduce 字典统一
3. late-fee reduce 状态映射冻结
4. formal-table 申请态写入
5. date-mode 最小执行闭环
6. page/log-page 摘要字段补齐
7. 测试闭环建立
## 用途
该任务单用于把“标准层规划”正式推进到“试点对象实现”。

View File

@ -0,0 +1,23 @@
# REV004 账务调整统一化改造 — P0 标准层启动证据2026-04-15
## 已完成
本轮已将统一化改造的 P0 标准层拆分成独立工件,供后续直接执行:
- `.omx/plans/standard-layer/rev004-accounting-adjust-semantic-map.md`
- `.omx/plans/standard-layer/rev004-accounting-adjust-dict-and-status-strategy.md`
- `.omx/plans/standard-layer/rev004-accounting-adjust-readmodel-matrix.md`
- `.omx/plans/standard-layer/rev004-accounting-adjust-canonical-semantic-layer.md`
- `.omx/plans/standard-layer/rev004-accounting-adjust-test-matrix.md`
- `.omx/plans/p0-tasklist-rev004-accounting-adjust-unification-standard-layer.md`
## 收口原则
- REV004 当前接口模型为主真值
- legacy 仅作映射与迁移参考
- 不强制前端改字段名
- 先做标准层,再做多对象 runtime 与迁移
## 本轮用途
这些工件用于:
1. 统一字段语义
2. 统一字典与状态口径
3. 统一读模型输出
4. 为 runtime 正式落库和历史迁移提供统一语义层

View File

@ -0,0 +1,47 @@
# REV004 accountLog 操作链接线说明2026-04-13
## 结论
当前 `accountLog` 的 4 条操作链在后端契约层已具备接线条件,不需要继续补新的稳定字段;前端主要做提交映射即可。
## 1. 查看流程 `log-process`
- 前端来源:`handleProcess(row)`
- 后端接口:`GET /business/accounting-adjust/log-process`
- 后端入参:`adjustmentNo`
- 当前行数据可用字段:`row.adjustmentNo`
- 接线结论:可直接接
## 2. 查看附件 `log-attachments`
- 前端来源:`handleAttachment(row)`
- 后端接口:`GET /business/accounting-adjust/log-attachments`
- 后端入参:`adjustmentNo`
- 当前行数据可用字段:`row.adjustmentNo`
- 接线结论:可直接接
## 3. 转退款 `log-refund`
- 前端来源:`RefundForm`
- 后端接口:`POST /business/accounting-adjust/log-refund`
- 后端请求对象:`AccountingAdjustSecondaryActionReqVO`
- 推荐映射:
- `adjustmentNo = row.adjustmentNo`
- `reason = form.remark`
- `collectionMethod = form.collectionMethod`
- `refundUser = form.refundUser`
- `attachmentRefs` = 前端上传结果(如有)
- 说明:前端 `refundAmount` 当前仅用于展示,不是后端必填字段
- 接线结论:可接,主要是前端提交映射
## 4. 转预存 `log-prestorage`
- 前端来源:`TransferPrestoreForm`
- 后端接口:`POST /business/accounting-adjust/log-prestorage`
- 后端请求对象:`AccountingAdjustSecondaryActionReqVO`
- 推荐映射:
- `adjustmentNo = row.adjustmentNo`
- `targetCustCode = form.targetCustCode`
- `reason = form.remark`
- `attachmentRefs` = 前端上传结果(如有)
- 说明:前端 `transferAmount` 当前仅用于展示,不是后端必填字段
- 接线结论:可接,主要是前端提交映射
## 补充说明
- 本轮后端新增的 `accountLog.custId` 已可支撑前端客户编号点击后稳定跳客户详情。
- `sold` 当前列表/弹窗展示字段已基本满足,不建议继续为展示字段扩充后端响应。

View File

@ -0,0 +1,148 @@
# REV004 / accountProcess 字典 label 与 UI 文案一致性摘要2026-04-13
## 1. 目的
本摘要用于收敛 `accountProcess` 当前涉及的状态/标签类字段,确认:
- 代码侧字典 type 是否已统一
- 正式文档口径是否与代码一致
- 是否仍存在旧快照 / 旧产出中的历史口径残留
---
## 2. 当前已确认一致的口径
### A. 工单状态 `work_status`
代码侧:
- `DictTypeConstants.WORK_STATUS = "work_status"`
- 口径:`0-未处理 / 1-已审核 / 2-已完成 / 3-已撤销`
正式 SQL seed
- `../water-docs/sql/rev004_account_adjust_dict_seed.sql`
- 已定义:
- `0 -> 未处理`
- `1 -> 已审核`
- `2 -> 已完成`
- `3 -> 已撤销`
正式数据库设计文档:
- `../water-docs/docs/design/03_Technical_Design/01_Database_Design.md`
- 当前已同步为四态:
- `0-未处理(工单创建,待审核/待处理)`
- `1-已审核(审核通过/无需审批,待完成)`
- `2-已完成(处理成功且已回写完成)`
- `3-已撤销(工单已撤销)`
结论:
- **代码 / seed SQL / 正式设计文档:已一致**
### B. REV004 账务调整核心状态字典
已确认存在统一 type
- `account_adjust_object_type`
- `account_adjust_result_status`
- `account_adjust_approval_status`
- `account_adjust_writeback_status`
代码侧使用:
- `AccountingAdjustLogProcessServiceImpl`
- `AccountingAdjustSoldProcessServiceImpl`
中均已通过 `DictFrameworkUtils.parseDictDataLabel(...)` 或统一映射读取 label
正式 SQL seed
- `../water-docs/sql/rev004_account_adjust_dict_seed.sql`
- 已定义:
- objectType`PREPAID_REFUND / REDINK_RECORD / BAD_DEBT_RECORD / WRITTENOFF_ADJUST / PRICE_DIFF_ADJUST / LATE_FEE_REDUCE / SPLIT_ADJUST`
- resultStatus`SUCCESS / PENDING_APPROVAL / FAIL`
- approvalStatus`NOT_REQUIRED / PENDING_APPROVAL / APPROVED / REJECTED`
- writeBackStatus`UPDATED / PENDING / SKIPPED`
结论:
- **REV004 核心状态字典类型与值域已成套收口**
### C. 收费方式 `charge_method`
代码侧:
- `DictTypeConstants.CHARGE_METHOD = "charge_method"`
- 已在 `AccountingAdjustSoldProcessServiceImpl` 中作为列表展示 label 来源
正式文档:
- `../water-docs/sql/lhc_数据库设计.md`
- `../water-docs/docs/design/04_Appendix/Archive/03_Design_Docs/数据库设计.md`
中可见 `charge_method` 语义为收费途径/收费方式
结论:
- **当前 sold 查询页“收费方式”展示依赖路径明确,代码口径稳定**
---
## 3. 当前已确认的“动态原因字典”绑定口径
参考:
- `../water-docs/docs/guides/REV004_DICT_BINDING_MATRIX.md`
当前已明确:
- `PREPAID_REFUND -> deposit_reason`
- `REDINK_RECORD -> redink_reason`
- `BAD_DEBT_RECORD -> knotty_reason`
- `WRITTENOFF_ADJUST -> payment_reason`(过渡复用)
- `PRICE_DIFF_ADJUST -> price_reason`
- `LATE_FEE_REDUCE -> late_fee_reason`
- `SPLIT_ADJUST -> separate_reason`
结论:
- **前端原因下拉不应绑定一个统一 reason 字典,而应按 objectType 动态切换**
---
## 4. 当前仍存在的不一致 / 残留风险
### A. 历史快照文档仍残留旧三态 `work_status`
在旧归档快照中,仍能看到:
- `../water-docs/docs/design/04_Appendix/Archive/08_Formal_Doc_Snapshots/RWB-02/2026-04-03-RWB-02-01_Database_Design.md`
- 其中 `work_status` 仍写作:`0-待处理 / 1-处理中 / 2-已完成`
这与当前正式口径不一致。
结论:
- **历史快照存在旧口径残留,但不应再作为当前真值来源**
### B. output 产物也有旧口径残留
例如:
- `../water-docs/output/01_Database_Design_processed.md`
中仍可见旧三态 `work_status`
结论:
- **产出型文件存在滞后,需要明确“正式设计文档 + REV004 seed + 代码”为真值源**
### C. UI 文案一致性尚未逐页核验
虽然字典 type / 值域已统一,但还没有逐页确认:
- 页面上显示的是字典 label 还是代码 fallback 值
- 页面文案是否与字典 label 完全一致
- 历史页面是否仍在用旧文案(例如“处理中”)
结论:
- **字典结构已较稳定,但 UI 最终展示一致性仍需前端/UAT 联合核验**
---
## 5. 当前建议真值源优先级
建议按以下优先级使用:
1. **后端代码中的 DictTypeConstants + Service 映射逻辑**
2. **`rev004_account_adjust_dict_seed.sql`**
3. **正式技术设计文档 `01_Database_Design.md`**
4. 历史快照 / output 产物(仅供追溯,不作为当前真值)
---
## 6. 对前端 / UAT 的建议
1. `work_status` 统一按四态使用:
- 0 未处理
- 1 已审核
- 2 已完成
- 3 已撤销
2. `objectType / resultStatus / approvalStatus / writeBackStatus` 使用 REV004 新字典,不再依赖旧业务大类字段硬编码。
3. “原因”下拉必须按 `objectType` 动态切换,不要做单字典通配。
4. 若页面仍显示“处理中”等旧文案,应优先视为前端展示遗留,而不是后端当前真值。
---
## 7. 当前结论
- **核心字典 type 与值域已基本收口**
- **正式文档与 seed SQL 已与代码当前口径对齐**
- **残留风险主要在旧快照/旧输出文件与前端展示层,而不在当前后端主实现**

View File

@ -0,0 +1,257 @@
# REV004 / accountProcess 最终评审摘要2026-04-13
## 1. 评审目的
本摘要用于对外汇报 `REV004 / accountProcess` 当前后端交付状态,统一回答以下问题:
- 这一块后端接口是否已形成可联调的稳定口径?
- 关键页面/弹窗对应的接口是否已经落地?
- 真实数据库条件下,主链路是否已经被证明可运行?
- 当前仍有哪些剩余风险与建议后续动作?
---
## 2. 结论摘要
### 结论
`REV004 / accountProcess` 当前已经达到:
- **接口口径已基本收口**
- **页面/弹窗映射已梳理清楚**
- **主链路已完成真实数据库验证**
- **可进入联调 / 评审 / 阶段性验收**
### 当前结论边界
这里的“通过”是指:
- 后端接口已存在并按当前代码口径稳定返回
- 关键提交流程、撤销流程、日志二次动作、主要查询面均有真实库证据
- 不代表已经完成 UI 层面的最终视觉/交互验收
- 不代表所有页面文案、字典 label、边角筛选条件都已逐项核验
---
## 3. 当前已沉淀产物
### A. 集成测试累计证据
- `docs/evidence/rev004-accountprocess-integration-testing-bootstrap-2026-04-13.md`
### B. 接口真值矩阵
- `docs/evidence/rev004-accountprocess-interface-truth-matrix-2026-04-13.md`
### C. 页面元素勾稽矩阵
- `docs/evidence/rev004-accountprocess-ui-element-matrix-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-dict-ui-consistency-summary-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-page-label-audit-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-ui-orchestration-checklist-2026-04-13.md`
### D. 真实库集成测试代码
- `sw-business-server/src/test/java/.../integration/rev004/accountprocess/Rev004AccountProcessCanaryQueryIntegrationTest.java`
---
## 4. 范围说明
本轮范围仅覆盖:
- `REV004/accountProcess`
具体包括四类页面/域:
- 预存调整prestorage
- 已销调整sold
- 未销调整unsold
- 账务日志accountLog / log
本轮明确不扩散到:
- accountProcess 之外的其它业务模块
- 全项目通用测试框架治理
- UI 自动化或前端渲染层验证
---
## 5. 环境口径
### 测试策略
- **数据库:真实 PostgreSQL**
- **数据库外依赖:替身化 / MockBean**
### 已明确替身边界
例如:
- `TransactionApi`
- `ApiErrorLogCommonApi`
- `DictDataCommonApi`
- `OperateLogCommonApi`
- `RedissonClient`
### 当前价值
这意味着:
- 账务状态变化、operat_log 留痕、查询回看等核心真值来自真实数据库
- 外部交易/缓存/公共 RPC 不会干扰主链路验证
---
## 6. 最新验证结果
### 最新 surefire 结果
- `Rev004AccountProcessCanaryQueryIntegrationTest`
- **21 tests / 0 fail / 0 skip**
- `Rev004AccountProcessIntegrationFixtureAssetsTest`
- **1 pass**
- `Rev004AccountProcessLiveDbReadinessTest`
- **1 pass**
### 最新整体验证结果
- `Rev004AccountProcess*`
- **总计 23 tests / 0 fail / 0 skip**
这代表当前仓库内,至少在真实数据库 + 外部依赖替身化前提下,主链路验证是通过的。
---
## 7. 主链路覆盖概览
### 7.1 prestorage
已验证:
- `prestorage-page`
- `prestorage-stat`
- `prestorage-detail`
- `prestorage-submit`
- `prestorage-revoke`
- `prestorage-process`
- `prestorage-attachments`
- 提交后 page/stat/detail/process/attachments 联动回看
已证明能力:
- 预存退款提交成功
- 余额真实回写
- 记录可回看
- 撤销后余额可恢复
### 7.2 sold
已验证:
- `sold-page`
- `sold-stat`
- `sold-submit`
- `sold-batch-revoke`
- 提交后 page/stat 能反映撤销能力
已证明能力:
- 已销调整申请可成功落日志
- 状态为 `PENDING_APPROVAL`
- 批量撤销以 `chargeIds[]` 可执行
### 7.3 unsold
已验证:
- `unsold-page`
- `unsold-stat`
- `unsold-adjust-submit`
- `unsold-split-submit`
- `unsold-late-fee-reduce-submit`
- `unsold-price-diff-submit`
- `unsold-bad-debt-submit`
- 调整后 page/stat 可回看金额变化
已证明能力:
- 五类未销动作 happy path 都可跑通
- 查询面能反映初始数据与提交后的更新结果
### 7.4 log / accountLog
已验证:
- `log-page`
- `log-stat`
- `log-detail`
- `log-process`
- `log-attachments`
- `log-refund`
- `log-prestorage`
- `log-revoke`
- 日志页 page/stat/detail/process/attachments 联动回看
已证明能力:
- 日志链路是当前最完整的一组闭环
- 支持二次动作(退款/转预存/撤销)
- 可查看流程摘要与附件引用
---
## 8. 页面 / 弹窗映射结论
### 已收口
目前页面与后端接口映射已经可明确回答:
- 哪个页面查哪个 `page/stat/detail`
- 哪个弹窗调哪个 `submit/revoke/process/attachments`
- 哪些动作依赖 `adjustmentNo`
- 哪些动作依赖 `chargeId/chargeIds`
### 特别提醒
- **已销批量撤销**:当前后端口径是 `chargeIds[]`,不是 `adjustmentNo[]`
- **日志页二次动作**:当前统一以 `adjustmentNo` 为主键
- **已销查询页** 本身不返回 `adjustmentNo`,若前端要保留申请单号,应使用提交返回值或转到日志视角查看
---
## 9. 接口字段口径结论
### 前端建议优先读取
对于动作提交类接口,前端建议主读:
- `adjustmentNo`
- `resultStatus`
- `approvalStatus`
- `writeBackStatus`
- `msg`
### 兼容字段
- `status`
- `message`
这些保留给旧调用方或兼容逻辑,不建议新页面作为主读来源。
### 预存工单状态口径
- `0 = 未处理`
- `1 = 已审核`
- `2 = 已完成`
- `3 = 已撤销`
### 页面状态与工单状态不要混用
- `prestorage-page.workOrderStatus` 是预存工单状态
- `log-page.statusCode/status` 是日志页状态投影
- 两者不是同一套语义
---
## 10. 当前最可信的证据类型
从强到弱排序:
1. **真实数据库 + MockMvc canary 测试**
2. **Controller / ReqVO / RespVO / Service 代码口径**
3. **矩阵文档归纳**
因此当前对外说法应以:
- 已跑通真实库的场景 = 强证据
- 仅代码里存在但未单独断言的字段 = 次强证据
---
## 11. 剩余风险 / 空白
### 仍未完全补齐
1. 字典 type / 值域已基本收口,剩余是页面文案逐页核对
2. 前端弹窗 A/B/C 切换路径尚未做 UI 编排级验证
3. 边角筛选条件并未全部逐项做真实库穷尽验证
### 风险等级判断
- **主功能联调风险:中低**
- **页面展示细节风险:中**
- **最终 UI 验收风险:中**
---
## 12. 对外建议说法
建议对前端 / 产品 / 评审会的说法:
> `REV004/accountProcess` 后端接口已基本收口四条主链prestorage / sold / unsold / log均已有真实数据库验证证据
> 当前可进入稳定联调和阶段性验收。
> 剩余工作主要集中在页面文案/字典展示的一致性核验,以及更贴近前端的 UI 编排级验证。
---
## 13. 建议下一步
按优先级建议:
1. 做页面文案 / 字典 label 的逐页验收核对
2. 已提供 UI 编排级验收清单,若需要再补自动化/UI录屏级验证
3. 评审会可直接使用本摘要 + 两份矩阵文档 + 集成测试证据 + 字典一致性摘要 + 页面文案核对表 + UI 编排验收清单
---
## 14. 关联文档
- `docs/evidence/rev004-accountprocess-integration-testing-bootstrap-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-interface-truth-matrix-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-ui-element-matrix-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-dict-ui-consistency-summary-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-page-label-audit-2026-04-13.md`
- `docs/evidence/rev004-accountprocess-ui-orchestration-checklist-2026-04-13.md`

View File

@ -0,0 +1,124 @@
# REV004 accountProcess gap remediation — 2026-04-13 验证记录
## 本轮改动
- accountProcess 查询 ReqVO 补前端原型 range 参数兼容:
- `sold`: `accountMonth` / `collectionTime`
- `log`: `accountMonth` / `createTime` / `handleTime` / `paymentDate`
- `unsold`: `accountMonth`
- `prestorage`: `acceptTime`
- 查询 Controller 增加 query-normalize兼容多值 query param 传入
- `accountLog` 状态筛选补兼容值:`1=正常``2=已撤销`
## 验证结果
### 1. 主代码编译
命令:
```bash
cd sw-business/sw-business-server && mvn -q -DskipTests compile
```
结果:通过。
### 2. 变更相关测试(手动定向执行)
由于模块内存在与本次改动无关的存量 testCompile 问题(`ChargeService` / `ChargeDO` 相关旧测试编译失败),本轮对变更相关测试采用定向手动编译 + JUnit Console 执行。
执行类:
- `AccountingAdjustActionControllerTest`
- `AccountingAdjustRouteSmokeTest`
- `AccountingAdjustLogProcessServiceImplTest`
- `AccountingAdjustPrestorageProcessServiceImplTest`
- `AccountingAdjustSoldQueryProcessServiceImplTest`
- `AccountingAdjustUnsoldProcessServiceImplTest`
结果:
- 34 tests found
- 34 tests started
- 34 tests successful
- 0 tests failed
关键覆盖点:
- accountProcess 路由 smoke 正常
- query range 参数兼容归一化正常
- `accountLog``status=2` 已撤销兼容筛选正常
- `prestorage adjustmentNo` 闭环仍保持通过
- `sold` 查询过滤与 `unsold` / `prestorage` 主流程回归通过
### 3. 说明
直接执行:
```bash
cd sw-business/sw-business-server && mvn -Dtest='...' test
```
仍会被仓库内历史遗留的 testCompile 问题阻断;该问题与本轮 accountProcess 修复无直接关系。
## 4. `sold.isHistory` 语义收口(追加)
### 语义定义
- `isHistory=false`:查询当前已收记录(`payState=PAID`),保留调整/批量撤销能力
- `isHistory=true`:查询历史已结记录(`payState=SETTLED`),按只读口径返回,不开放调整/批量撤销
### 追加验证
命令:
- `cd sw-business/sw-business-server && mvn -q -DskipTests compile`
- 手动定向执行:`AccountingAdjustRouteSmokeTest` + `AccountingAdjustSoldQueryProcessServiceImplTest`
结果:
- 6 tests found
- 6 tests started
- 6 tests successful
- 0 tests failed
## 5. 完整相关回归(追加)
`sold.isHistory` 收口后,再次对本轮相关 6 个 accountProcess 测试类做完整定向回归。
执行类:
- `AccountingAdjustActionControllerTest`
- `AccountingAdjustRouteSmokeTest`
- `AccountingAdjustLogProcessServiceImplTest`
- `AccountingAdjustPrestorageProcessServiceImplTest`
- `AccountingAdjustSoldQueryProcessServiceImplTest`
- `AccountingAdjustUnsoldProcessServiceImplTest`
结果:
- 35 tests found
- 35 tests started
- 35 tests successful
- 0 tests failed
## 6. sold / accountLog 展示字段复核(追加)
### 复核结论
- `sold`:当前前端列表/弹窗所需展示字段已基本满足,暂不需要额外补展示字段
- `accountLog`:补 `custId`,用于前端客户编号点击后稳定跳转客户详情
### 追加验证
- `mvn -q -DskipTests compile` 通过
- 手动定向执行:`AccountingAdjustRouteSmokeTest` + `AccountingAdjustLogProcessServiceImplTest`
- 结果5 tests found / 5 tests successful / 0 failed
## 7. accountLog `custId` 补齐后的回归(追加)
### 变更目的
- 补 `accountLog` 列表/详情响应中的 `custId`
- 支撑前端客户编号点击后稳定跳客户详情
### 追加验证
- 手动定向编译:`AccountingAdjustRouteSmokeTest``AccountingAdjustLogProcessServiceImplTest``AccountingAdjustSoldQueryProcessServiceImplTest`
- JUnit Console 执行结果9 tests found / 9 tests successful / 0 failed
## 8. work_status 字典与正式文档同步(追加)
### 本轮结果
- 已在 `../water-docs/sql/rev004_account_adjust_dict_seed.sql` 中补充 `work_status` 字典 type/data幂等
- 已将 `../water-docs/docs/design/03_Technical_Design/01_Database_Design.md` 中的 `work_status` 口径同步为代码四态:`0-未处理 / 1-已审核 / 2-已完成 / 3-已撤销`
- 本轮仍无业务表 schema 变更,仅涉及字典 seed 与正式文档同步
### 业务解释补充
- `0 未处理`:工单创建,待审核/待处理
- `1 已审核`:审核通过(或无需审批),待完成
- `2 已完成`:处理成功且已回写完成
- `3 已撤销`:工单已撤销
- 说明:`钱到账``带红冲操作` 更偏业务侧解释;当前代码稳定判定仍以 `approvalStatus / resultStatus / writeBackStatus / revokeOfAdjustmentNo` 为准。
### 剩余风险
- 当前 seed SQL 采用幂等补缺策略,不会纠正**环境中已存在但口径错误**的 `work_status` 数据;若某环境已落旧三态字典,仍需后续补一条存量纠偏 SQL 或人工核查。
- Archive/历史快照与 processed/output 产物可能仍保留旧三态,它们属于历史资料/派生产物,不作为当前正式口径。

View File

@ -0,0 +1,422 @@
# REV004 accountProcess 集成测试方案 bootstrap2026-04-13
## 本轮已落地 bootstrap
- 新增 `AbstractRev004AccountProcessIntegrationTest`:定义真实数据库 + 外部依赖默认替身化的测试基类
- 新增 `Rev004AccountProcessLiveDbReadinessTest`:在提供 `REV004_IT_DB_*` 环境变量时,检查真实数据库所需表是否可见
- 新增 `Rev004AccountProcessIntegrationFixtureAssetsTest`:校验 fixture 资源文件存在
- 新增 `src/test/resources/sql/rev004/accountprocess/*.sql`:为 prestorage/sold/unsold/accountLog 预留 fixture 分层入口
## 当前价值
- 把“真实数据库 + 外部依赖替身化”的执行边界固化到测试骨架
- 把场景矩阵的 fixture 入口落到仓库,便于后续继续实现 query/action/close-loop 场景
- 在未提供真实数据库环境变量时,不强行执行 live DB readiness 测试
## 下一步建议
1. 补 `prestorage` 第 1 条全闭环场景
2. 补 `sold``isHistory` + submit/撤销场景
3. 补 `accountLog` 的 refund/prestorage 二次动作场景
## Canary 补充
- 新增 `Rev004AccountProcessCanaryQueryIntegrationTest`:在提供 `REV004_IT_DB_*` 环境变量时,真正启动 Spring + MockMvc打通 `prestorage-page` 只读 query 作为最小 canary。
- 当前 fixture 仍是 bootstrap 占位,因此该 canary 的目标是“验活骨架”,不是验证完整业务数据闭环。
## Fresh verification
- 执行:`mvn -Dtest='Rev004AccountProcessIntegrationFixtureAssetsTest,Rev004AccountProcessLiveDbReadinessTest,Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果BUILD SUCCESS
- 细项:
- Fixture assets: 1 pass
- Live DB readiness: 1 skipped未提供 `REV004_IT_DB_*` 环境变量时跳过)
- Canary query: 1 skipped未提供 `REV004_IT_DB_*` 环境变量时跳过)
## Real DB canary verification
- 执行环境:使用 `application-local.yaml` 中 PostgreSQL 连接参数,以 `REV004_IT_DB_*` 环境变量注入
- 执行:`mvn -Dtest='Rev004AccountProcessIntegrationFixtureAssetsTest,Rev004AccountProcessLiveDbReadinessTest,Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果BUILD SUCCESS
- 明细:
- Fixture assets: 1 pass
- Live DB readiness: 1 pass
- Canary query (`/admin-api/business/accounting-adjust/prestorage-page`): 1 pass
- 说明:当前 canary 证明了真实数据库 + Spring context + MockMvc + route wiring 可启动并返回成功包装;但 fixture 仍是最小占位,尚未证明完整业务数据闭环。
## Real DB full bootstrap verification
- 执行环境:使用 `application-local.yaml` 中 PostgreSQL 连接参数,经 `REV004_IT_DB_*` 环境变量注入
- 执行:`mvn -Dtest='Rev004AccountProcessIntegrationFixtureAssetsTest,Rev004AccountProcessLiveDbReadinessTest,Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果BUILD SUCCESS
- 明细:
- Fixture assets: 1 pass
- Live DB readiness: 1 pass
- Canary query (`/admin-api/business/accounting-adjust/prestorage-page`): 1 pass
- 说明:当前已经从“资产存在”推进到“真实数据库 + Spring context + MockMvc + canary query 验活成功”。
- 剩余缺口fixture 仍是最小占位,尚未验证完整业务数据闭环。
## First real close-loop scenario
- 场景:`prestorage-submit` 预存退款
- 测试文件:`Rev004AccountProcessCanaryQueryIntegrationTest`
- 使用真实数据库中的独立测试数据(`REV004_IT_SRC` / `biz_account.id=900001`
- 断言:
- `POST /admin-api/business/accounting-adjust/prestorage-submit` 返回成功包装
- 账户余额由 `100.00` 变为 `90.00`
- `biz_operat_log` 写入 1 条 `旧预存调整` 日志
- `biz_operat_log_detail` 中存在与返回 `adjustmentNo` 对应的明细记录
- 执行:`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果BUILD SUCCESS2 tests / 0 fail / 0 skip
## Sold close-loop scenario
- 场景:`sold-submit` 已销调整申请
- 测试文件:`Rev004AccountProcessCanaryQueryIntegrationTest`
- 使用真实数据库中的独立测试营业账数据(`biz_charge.id=900002``pay_state=1`
- 断言:
- `POST /admin-api/business/accounting-adjust/sold-submit` 返回成功包装
- 返回 `resultStatus = PENDING_APPROVAL`
- `biz_operat_log` 写入 1 条 `旧账务兼容动作` 日志
- `biz_operat_log_detail` 中存在与返回 `adjustmentNo` 对应的明细记录
- 结果:与 prestorage canary 一起执行,`Rev004AccountProcessCanaryQueryIntegrationTest` 当前为 3 tests / 0 fail / 0 skip
## AccountLog close-loop scenario
- 场景:`log-prestorage` 二次动作
- 测试文件:`Rev004AccountProcessCanaryQueryIntegrationTest`
- 使用真实数据库中的独立源记录(`adjustmentNo=REV004-LOG-900003``biz_charge.id=900003`)与目标账户(`REV004_IT_TGT` / `biz_account.id=900004`
- 断言:
- `POST /admin-api/business/accounting-adjust/log-prestorage` 返回成功包装
- 源营业账 `pay_state` 被清为 `0`(未收)
- 目标账户余额增加到 `20.00`
- `biz_operat_log` 写入 1 条 `旧账务兼容动作` 日志
- `biz_operat_log_detail` 中存在与返回 `adjustmentNo` 对应的明细记录
- 结果:与 prestorage/sold 场景一起执行时,`Rev004AccountProcessCanaryQueryIntegrationTest` 当前为 4 tests / 0 fail / 0 skip
## AccountLog process query scenario
- 场景:`log-process` 读取已有调整记录流程摘要
- 测试文件:`Rev004AccountProcessCanaryQueryIntegrationTest`
- 使用真实数据库中的独立源记录(`adjustmentNo=REV004-LOG-900003`
- 断言:
- `GET /admin-api/business/accounting-adjust/log-process` 返回成功包装
- `processState = UPDATED`
- `resultStatus = SUCCESS`
## Current canary suite status
- `Rev004AccountProcessCanaryQueryIntegrationTest` 当前为 5 tests / 0 fail / 0 skip
- 已覆盖query canary、prestorage-submit、sold-submit、log-prestorage、log-process
## 2026-04-13 最新推进accountLog refund 闭环补齐
- 新增 `TransactionApi``@MockBean` 注入到 `AbstractRev004AccountProcessIntegrationTest`,确保真实数据库之外的交易后续流水依赖保持替身化。
- 更新 `40_accountlog_seed.sql`:为 `REV004-LOG-900003` 补入 `originalTranSeq=T-900003``originalSysTranSeq=SYS-900003`,使 `log-refund` 路径具备真实可执行前置数据。
- 新增 canary 闭环用例:`logRefund_shouldClearChargePaymentAndWriteFollowupLog`
### 新增闭环断言
- `POST /admin-api/business/accounting-adjust/log-refund`
- 返回:`resultStatus=SUCCESS``objectType=PREPAID_REFUND``writeBackStatus=UPDATED`
- 数据库断言:
- `biz_charge.id=900003``pay_state` 从已收改为 `0`
- `biz_operat_log` 中新增 1 条 `账务调整` 日志,`operat_content` 含返回的 `adjustmentNo`
- `biz_operat_log_detail` 中存在 `bankTranSeq=RF-900003`
- 替身断言:`TransactionApi.createFollowupTransaction(...)` 被调用
### 本次真实库验证
- 执行 1`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果 1BUILD SUCCESS
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 7 tests / 0 fail / 0 skip
- 执行 2`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcess*' test`
- 结果 2BUILD SUCCESS
- `Rev004AccountProcessLiveDbReadinessTest`: 1 pass
- `Rev004AccountProcessIntegrationFixtureAssetsTest`: 1 pass
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 7 pass
- 总计9 tests / 0 fail / 0 skip
### 当前 canary 套件真实覆盖
- `prestorage-page_shouldReturnSuccessEnvelope`
- `prestorageSubmit_shouldChangeBalanceAndWriteOperatLog`
- `soldSubmit_shouldWritePendingOperatLog`
- `logPrestorage_shouldClearChargePaymentAndIncreaseTargetDeposit`
- `logProcess_shouldReturnUpdatedProcessSummary`
- `logAttachments_shouldReturnUnresolvedAttachmentRef`
- `logRefund_shouldClearChargePaymentAndWriteFollowupLog`
### 仍待继续
- `unsold` 五类 happy path 真实库闭环
- `revoke/log-revoke/sold-batch-revoke` 的真实库撤销链验证
- 更高一层的“提交 -> 查询页回看 -> detail/process/attachments 全链联动”场景编排
## 2026-04-13 继续推进:撤销链真实库闭环补齐
- 新增真实库撤销链 canary
- `prestorageRevoke_shouldRestoreBalanceAndWriteRevokeLog`
- `soldBatchRevoke_shouldWriteRevokeLogForPendingSyntheticRecord`
- `logRevoke_shouldRestoreChargePaymentAndRollbackTransferredDeposit`
- 为支持旧兼容动作撤销,本轮同时修正 `AccountingAdjustProcessServiceImpl.findSyntheticSnapshot(...)`
- 改为按 `adjustmentNo` 直接回查 operat_log / operat_log_detail
- 避免旧预存调整 / 旧日志转预存 场景在撤销时误落入 unified snapshot 分支
### 新增闭环断言
1. `prestorage-revoke`
- 先发起 `prestorage-submit`
- 再调用 `POST /admin-api/business/accounting-adjust/prestorage-revoke`
- 断言:
- 返回 `actionType=REVOKE`
- `biz_account.id=900001.deposit``90.00` 恢复到 `100.00`
- 存在 `revokeOfAdjustmentNo=<原adjustmentNo>` 明细
2. `sold-batch-revoke`
- 先发起 `sold-submit`
- 再调用 `POST /admin-api/business/accounting-adjust/sold-batch-revoke`
- 断言:
- `successCount=1`
- 存在 `revokeOfAdjustmentNo=<原adjustmentNo>` 明细
3. `log-revoke`
- 先发起 `log-prestorage`
- 再调用 `POST /admin-api/business/accounting-adjust/log-revoke`
- 断言:
- 返回 `actionType=REVOKE`
- `biz_charge.id=900003.pay_state` 恢复为 `1`
- `charge_method` 恢复为 `2`
- `charge_way` 恢复为 `6`
- `biz_account.id=900004.deposit``20.00` 回退到 `0.00`
- 存在 `revokeOfAdjustmentNo=<原adjustmentNo>` 明细
### 本次真实库验证
- 执行 1`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果 1BUILD SUCCESS
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 10 tests / 0 fail / 0 skip
- 执行 2`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcess*' test`
- 结果 2BUILD SUCCESS
- `Rev004AccountProcessLiveDbReadinessTest`: 1 pass
- `Rev004AccountProcessIntegrationFixtureAssetsTest`: 1 pass
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 10 pass
- 总计12 tests / 0 fail / 0 skip
### 当前 canary 套件真实覆盖10 条)
- `prestoragePage_shouldReturnSuccessEnvelope`
- `prestorageSubmit_shouldChangeBalanceAndWriteOperatLog`
- `prestorageRevoke_shouldRestoreBalanceAndWriteRevokeLog`
- `soldSubmit_shouldWritePendingOperatLog`
- `soldBatchRevoke_shouldWriteRevokeLogForPendingSyntheticRecord`
- `logPrestorage_shouldClearChargePaymentAndIncreaseTargetDeposit`
- `logRevoke_shouldRestoreChargePaymentAndRollbackTransferredDeposit`
- `logProcess_shouldReturnUpdatedProcessSummary`
- `logAttachments_shouldReturnUnresolvedAttachmentRef`
- `logRefund_shouldClearChargePaymentAndWriteFollowupLog`
## 2026-04-13 继续推进unsold 五类真实库 happy path 补齐
- 新增 `30_unsold_seed.sql` 真实库 fixture
- `biz_cust.id=900005 / code=REV004_IT_UNSOLD`
- `biz_charge.id=900005 / pay_state=0 / bill_amount=120.00 / extended_amount=120.00 / late_fee=30.00`
- 扩展 `00_reset.sql`,纳入 `900005 / REV004_IT_UNSOLD` 清理范围
- 新增 5 条真实库 canary
- `unsoldAdjustSubmit_shouldUpdateAmountsAndWriteOperatLog`
- `unsoldSplitSubmit_shouldCreatePendingApprovalRecord`
- `unsoldLateFeeReduceSubmit_shouldCreatePendingApprovalRecord`
- `unsoldPriceDiffSubmit_shouldCreatePendingApprovalRecord`
- `unsoldBadDebtSubmit_shouldCreatePendingApprovalRecord`
### 新增闭环断言
1. `unsold-adjust-submit`
- 返回 `SUCCESS`
- `biz_charge.id=900005.extended_amount` 更新为 `88.88`
- `bill_amount` 更新为 `80.00`
- `biz_operat_log.operat_content` 含返回 `adjustmentNo`
2. `unsold-split-submit`
- 返回 `PENDING_APPROVAL`
- `objectType=SPLIT_ADJUST`
- `biz_operat_log.operat_content` 含返回 `adjustmentNo`
3. `unsold-late-fee-reduce-submit`
- 返回 `PENDING_APPROVAL`
- `objectType=LATE_FEE_REDUCE`
- `biz_operat_log.operat_content` 含返回 `adjustmentNo`
4. `unsold-price-diff-submit`
- 返回 `PENDING_APPROVAL`
- `objectType=PRICE_DIFF_ADJUST`
- `biz_operat_log.operat_content` 含返回 `adjustmentNo`
5. `unsold-bad-debt-submit`
- 返回 `PENDING_APPROVAL`
- `objectType=BAD_DEBT_RECORD`
- `biz_operat_log.operat_content` 含返回 `adjustmentNo`
### 本次真实库验证
- 执行 1`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果 1BUILD SUCCESS
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 15 tests / 0 fail / 0 skip
- 执行 2`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcess*' test`
- 结果 2BUILD SUCCESS
- `Rev004AccountProcessLiveDbReadinessTest`: 1 pass
- `Rev004AccountProcessIntegrationFixtureAssetsTest`: 1 pass
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 15 pass
- 总计17 tests / 0 fail / 0 skip
### 当前 canary 套件真实覆盖15 条)
- `prestoragePage_shouldReturnSuccessEnvelope`
- `prestorageSubmit_shouldChangeBalanceAndWriteOperatLog`
- `prestorageRevoke_shouldRestoreBalanceAndWriteRevokeLog`
- `soldSubmit_shouldWritePendingOperatLog`
- `soldBatchRevoke_shouldWriteRevokeLogForPendingSyntheticRecord`
- `unsoldAdjustSubmit_shouldUpdateAmountsAndWriteOperatLog`
- `unsoldSplitSubmit_shouldCreatePendingApprovalRecord`
- `unsoldLateFeeReduceSubmit_shouldCreatePendingApprovalRecord`
- `unsoldPriceDiffSubmit_shouldCreatePendingApprovalRecord`
- `unsoldBadDebtSubmit_shouldCreatePendingApprovalRecord`
- `logPrestorage_shouldClearChargePaymentAndIncreaseTargetDeposit`
- `logRevoke_shouldRestoreChargePaymentAndRollbackTransferredDeposit`
- `logProcess_shouldReturnUpdatedProcessSummary`
- `logAttachments_shouldReturnUnresolvedAttachmentRef`
- `logRefund_shouldClearChargePaymentAndWriteFollowupLog`
### 剩余待补
- 更高一层的“提交 -> page/stat/detail/process/attachments 联动回看”场景编排
- 若要进一步贴近前端验收,可再补一轮按弹窗功能分组的端到端查询/动作串联用例
## 2026-04-13 继续推进:提交后联动回看场景补齐
- 新增 3 条更贴近前端验收的联动回看 canary
- `prestorageSubmit_thenPageStatAndDetailShouldExposeNewRecord`
- `soldSubmit_thenSoldPageAndStatShouldExposePendingRevokeCapability`
- `logSeed_thenPageStatDetailProcessAndAttachmentsShouldStayConsistent`
### 新增联动断言
1. `prestorage` 提交后联动回看
- 提交 `prestorage-submit`
- 再查:
- `prestorage-page`
- `prestorage-stat`
- `prestorage-detail`
- 断言:
- page 能看到新 `adjustmentNo`
- stat 的 `totalCount=1 / refundCount=1`
- detail 返回 `resultStatus=SUCCESS / writeBackStatus=UPDATED`
2. `sold` 提交后联动回看
- 提交 `sold-submit`
- 再查:
- `sold-page`
- `sold-stat`
- 断言:
- page 仍能看到 `biz_charge.id=900002`
- `canBatchRevoke=true`
- stat 的 `totalCount=1 / totalActualAmount=80.00`
3. `log` 全链回看
- 基于 `40_accountlog_seed.sql` 中的 `REV004-LOG-900003`
- 依次验证:
- `log-page`
- `log-stat`
- `log-detail`
- `log-process`
- `log-attachments`
- 断言:
- page 可见 `adjustmentNo=REV004-LOG-900003`
- stat `completedCount=1`
- detail 包含 `originalTranSeq=T-900003``attachmentRefs[0]=mock-ref-1`
- process `processState=UPDATED`
- attachments 可返回 `mock-ref-1`
### 本次真实库验证
- 执行 1`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果 1BUILD SUCCESS
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 18 tests / 0 fail / 0 skip
- 执行 2`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcess*' test`
- 结果 2BUILD SUCCESS
- `Rev004AccountProcessLiveDbReadinessTest`: 1 pass
- `Rev004AccountProcessIntegrationFixtureAssetsTest`: 1 pass
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 18 pass
- 总计20 tests / 0 fail / 0 skip
### 当前真实库 canary 覆盖18 条)
- `prestoragePage_shouldReturnSuccessEnvelope`
- `prestorageSubmit_shouldChangeBalanceAndWriteOperatLog`
- `prestorageRevoke_shouldRestoreBalanceAndWriteRevokeLog`
- `prestorageSubmit_thenPageStatAndDetailShouldExposeNewRecord`
- `soldSubmit_shouldWritePendingOperatLog`
- `soldBatchRevoke_shouldWriteRevokeLogForPendingSyntheticRecord`
- `soldSubmit_thenSoldPageAndStatShouldExposePendingRevokeCapability`
- `unsoldAdjustSubmit_shouldUpdateAmountsAndWriteOperatLog`
- `unsoldSplitSubmit_shouldCreatePendingApprovalRecord`
- `unsoldLateFeeReduceSubmit_shouldCreatePendingApprovalRecord`
- `unsoldPriceDiffSubmit_shouldCreatePendingApprovalRecord`
- `unsoldBadDebtSubmit_shouldCreatePendingApprovalRecord`
- `logPrestorage_shouldClearChargePaymentAndIncreaseTargetDeposit`
- `logRevoke_shouldRestoreChargePaymentAndRollbackTransferredDeposit`
- `logSeed_thenPageStatDetailProcessAndAttachmentsShouldStayConsistent`
- `logProcess_shouldReturnUpdatedProcessSummary`
- `logAttachments_shouldReturnUnresolvedAttachmentRef`
- `logRefund_shouldClearChargePaymentAndWriteFollowupLog`
### 当前剩余缺口
- 若要进一步逼近前端验收,可继续补“弹窗 A/B/C 对应多接口切换”的编排式测试摘要
- 以及基于接口返回字段做一版更面向页面的 contract/assertion matrix
## 2026-04-13 继续推进unsold 查询面真实库回看补齐
- 新增 2 条真实库查询联动 canary
- `unsoldSeed_thenPageAndStatShouldExposeChargeSnapshot`
- `unsoldAdjustSubmit_thenPageAndStatShouldReflectUpdatedAmounts`
### 新增断言
1. `unsold` 初始查询面
- `GET /admin-api/business/accounting-adjust/unsold-page`
- `GET /admin-api/business/accounting-adjust/unsold-stat`
- 断言:
- `biz_charge.id=900005` 可见
- `totalAmount=120.00`
- `billAmount=120.00`
- `penaltyAmount=30.00`
- `canAdjust/canSplit/canLateFeeReduce/canPriceDiffAdjust/canBadDebtAdjust=true`
- stat`sumWaterVolume=5.000 / sumTotalAmount=120.00 / sumBillAmount=120.00 / sumPenaltyAmount=30.00`
2. `unsold-adjust-submit` 后查询面回看
- 先提交 `unsold-adjust-submit`
- 再查 `unsold-page / unsold-stat`
- 断言:
- page 中 `totalAmount=88.88`
- page 中 `billAmount=80.00`
- stat 中 `sumTotalAmount=88.88`
- stat 中 `sumBillAmount=80.00`
### 本次真实库验证
- 执行 1`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcessCanaryQueryIntegrationTest' test`
- 结果 1BUILD SUCCESS
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 20 tests / 0 fail / 0 skip
- 执行 2`REV004_IT_DB_URL=... REV004_IT_DB_USERNAME=... REV004_IT_DB_PASSWORD=... mvn -Dtest='Rev004AccountProcess*' test`
- 结果 2BUILD SUCCESS
- `Rev004AccountProcessLiveDbReadinessTest`: 1 pass
- `Rev004AccountProcessIntegrationFixtureAssetsTest`: 1 pass
- `Rev004AccountProcessCanaryQueryIntegrationTest`: 20 pass
- 总计22 tests / 0 fail / 0 skip
### 影响
- `prestorage / sold / unsold / log` 四条主查询面现在都至少有一组真实库回看证据
- 剩余未补重点从“主链查询缺口”收敛为“预存页流程/附件链路 + 字典/UI文案展示一致性”
## 2026-04-13 继续推进prestorage process / attachments 真实库补齐
- 新增 canary`prestorageSubmit_thenProcessAndAttachmentsShouldExposeReturnedAdjustmentNo`
- 在 `prestorage-submit` 场景中附带 `attachmentRefs=[pre-proof-2, pre-proof-3]`
- 提交后继续验证:
- `GET /admin-api/business/accounting-adjust/prestorage-process`
- `GET /admin-api/business/accounting-adjust/prestorage-attachments`
### 新增断言
- process
- `adjustmentNo` 与提交返回一致
- `resultStatus=SUCCESS`
- `approvalStatus=NOT_REQUIRED`
- `writeBackStatus=UPDATED`
- `processState=UPDATED`
- `stages[0].message` 存在
- attachments
- 返回两条附件引用
- `ref=pre-proof-2 / pre-proof-3`
- `resolved=false`
### 本次真实库验证
- `Rev004AccountProcessCanaryQueryIntegrationTest`: **21 tests / 0 fail / 0 skip**
- `Rev004AccountProcess*`: **总计 23 tests / 0 fail / 0 skip**
### 影响
- `prestorage` 查询/提交流程/撤销/流程查看/附件查看 这一组链路现在都已有真实库证据
- 剩余缺口进一步收敛到:字典 label / UI 文案一致性、边角筛选条件穷尽、UI 编排级验证

View File

@ -0,0 +1,315 @@
# REV004 / accountProcess 接口真值矩阵2026-04-13
## 目的
给前端/联调/验收一个“当前代码真实口径”矩阵:
- 哪个页面/弹窗对应哪些接口
- 每个接口当前稳定返回哪些关键字段
- 哪些字段已经被真实库测试覆盖
- 哪些地方仍然是页面编排层面的剩余缺口
> 口径来源:`water-backend` 当前控制器 + Req/RespVO + 已落地真实库 canary。
---
## 一、页面 / 弹窗 -> 接口映射
### 1. 预存调整页
#### 查询区
- `GET /admin-api/business/accounting-adjust/prestorage-page`
- `GET /admin-api/business/accounting-adjust/prestorage-stat`
- `GET /admin-api/business/accounting-adjust/prestorage-detail?id={id}`
#### 动作区
- `POST /admin-api/business/accounting-adjust/prestorage-submit`
- `POST /admin-api/business/accounting-adjust/prestorage-revoke`
- `GET /admin-api/business/accounting-adjust/prestorage-process?adjustmentNo=...`
- `GET /admin-api/business/accounting-adjust/prestorage-attachments?adjustmentNo=...`
#### 维护区
- `POST /prestorage-customer-update`
- `POST /prestorage-meter-update`
- `POST /prestorage-billing-update`
- `POST /prestorage-discount-update`
- `POST /prestorage-cost-component-update`
### 2. 已销调整页
#### 查询区
- `GET /admin-api/business/accounting-adjust/sold-page`
- `GET /admin-api/business/accounting-adjust/sold-stat`
#### 动作区
- `POST /admin-api/business/accounting-adjust/sold-submit`
- `POST /admin-api/business/accounting-adjust/sold-batch-revoke`
### 3. 未销调整页
#### 查询区
- `GET /admin-api/business/accounting-adjust/unsold-page`
- `GET /admin-api/business/accounting-adjust/unsold-stat`
#### 动作区(按弹窗切换)
- 调整:`POST /unsold-adjust-submit`
- 分账:`POST /unsold-split-submit`
- 违约金减免:`POST /unsold-late-fee-reduce-submit`
- 价差调整:`POST /unsold-price-diff-submit`
- 呆坏账:`POST /unsold-bad-debt-submit`
#### 批量区
- `POST /unsold-adjust-batch-submit`
- `POST /unsold-split-batch-submit`
- `POST /unsold-late-fee-reduce-batch-submit`
- `POST /unsold-price-diff-batch-submit`
- `POST /unsold-bad-debt-batch-submit`
### 4. 账务日志页
#### 查询区
- `GET /admin-api/business/accounting-adjust/log-page`
- `GET /admin-api/business/accounting-adjust/log-stat`
- `GET /admin-api/business/accounting-adjust/log-detail?adjustmentNo=...`
#### 二次动作弹窗
- 转退款:`POST /admin-api/business/accounting-adjust/log-refund`
- 转预存:`POST /admin-api/business/accounting-adjust/log-prestorage`
- 撤销:`POST /admin-api/business/accounting-adjust/log-revoke`
#### 辅助弹窗
- `GET /admin-api/business/accounting-adjust/log-process?adjustmentNo=...`
- `GET /admin-api/business/accounting-adjust/log-attachments?adjustmentNo=...`
---
## 二、关键返回字段真值
### A. 通用动作返回 `AccountingAdjustRespVO`
适用:
- `prestorage-submit`
- `sold-submit`
- `unsold-*submit`
- `log-refund`
- `log-prestorage`
当前稳定字段:
- `adjustmentNo`:主联调键
- `objectType`:对象类型;未销调整 AMOUNT/USAGE 场景可能为空,其他场景一般有值
- `resultStatus`:推荐前端主读字段
- `approvalStatus`
- `writeBackStatus`
- `approvalRequired`
- `resultObjectNo`
- `msg`
- `status`:兼容旧字段
- `message`:兼容旧字段
前端推荐:
- **优先读** `resultStatus / approvalStatus / writeBackStatus / msg`
- `status / message` 仅做兼容保底
### B. 撤销 / 审批动作返回 `AccountingAdjustActionRespVO`
适用:
- `prestorage-revoke`
- `log-revoke`
当前稳定字段:
- `adjustmentNo`
- `objectType`
- `actionType`(当前撤销返回 `REVOKE`
- `approvalStatus`
- `resultStatus`
- `writeBackStatus`
- `message`
- `actionTime`
### C. 预存分页 `AccountingAdjustPrestoragePageRespVO`
关键字段:
- `id`
- `adjustmentNo`
- `custId`
- `workOrderStatus`
- `adjustmentType`
- `custCode / custName / custAddress`
- `targetCustCode`
- `adjustAmount / preBalance / postBalance`
- `adjustReason / remark`
- `createTime / creatorName`
- `canRevoke / canViewAttachment`
补充:
- `prestorage-detail` 在上面基础上增加:
- `objectType`
- `resultStatus`
- `approvalStatus`
- `writeBackStatus`
- `processInstanceId`
- `attachmentRefs`
### D. 已销分页 `AccountingAdjustSoldPageRespVO`
关键字段:
- `id`
- `custId`
- `accountMonth`
- `custCode / custName / custAddress`
- `waterNature`
- `billedWaterVolume`
- `actualAmount`
- `billedAmount`
- `penaltyAmount`
- `collectionMethod`
- `collector`
- `collectionDate`
- `canAdjust`
- `canBatchRevoke`
注意:
- 已销查询页**不是调整日志页**,所以这里没有 `adjustmentNo`
- `sold-submit` 提交后,前端若要看申请单号,应跳到 `log-*` 维度或使用提交返回值保存的 `adjustmentNo`
### E. 未销分页 `AccountingAdjustUnsoldPageRespVO`
关键字段:
- `id`
- `custId`
- `custCode / custName / custAddress`
- `waterType`
- `accountMonth`
- `waterVolume`
- `totalAmount / billAmount / penaltyAmount`
- `waterFee / sewageFee / garbageFee / resourcesFee / overPlanFee / seasonalSupplement`
- `canAdjust / canSplit / canLateFeeReduce / canPriceDiffAdjust / canBadDebtAdjust`
### F. 日志分页 `AccountingAdjustLogPageRespVO`
关键字段:
- `id`
- `adjustmentNo`
- `accountMonth`
- `custId / custCode / custName / custAddress`
- `accountTypeCode / accountType`
- `processMethodCode / processMethod`
- `amount`
- `description`
- `registrant / handler`
- `handleTime / createTime`
- `statusCode / status`
- `targetCustCode`
- `originalPrestore / newPrestore`
- `originalBill / newBill`
- `originalWaterVolume / newWaterVolume`
- `originalPenalty / newPenalty`
- `billChange / waterVolumeChange / penaltyChange`
- `canRevoke / canRefund / canPrestore`
### G. 日志详情 `AccountingAdjustLogDetailRespVO`
在日志分页基础上增加:
- `objectType`
- `resultStatus`
- `approvalStatus`
- `writeBackStatus`
- `originalTranSeq`
- `originalSysTranSeq`
- `attachmentRefs`
- `details[]`
### H. 流程 / 附件
#### `AccountingAdjustProcessRespVO`
关键字段:
- `adjustmentNo`
- `objectType`
- `adjustType`
- `chargeId`
- `actionAmount`
- `resultStatus`
- `approvalStatus`
- `writeBackStatus`
- `taskId`
- `processState`
- `latestMessage`
- `latestOperationTime`
- `stages[]`
#### `AccountingAdjustAttachmentRespVO`
关键字段:
- `adjustmentNo`
- `ref`
- `resolved`
- `id / name / link / size / extension`
- `message`
---
## 三、当前已经被真实库测试证明的字段/链路
### 已证明
#### 预存
- `prestorage-submit` 返回 `adjustmentNo/resultStatus/writeBackStatus`
- `prestorage-page` 可见新记录
- `prestorage-stat` 可统计到 `refundCount`
- `prestorage-detail` 可按 `id` 回看 `resultStatus/writeBackStatus`
- `prestorage-revoke` 可回滚余额并生成撤销日志
#### 已销
- `sold-submit` 返回 `adjustmentNo/resultStatus=PENDING_APPROVAL`
- `sold-page` 可见原账单,且 `canBatchRevoke=true`
- `sold-stat` 可统计 `totalCount / totalActualAmount`
- `sold-batch-revoke` 可按营业账 ID 执行撤销
#### 未销
- 五类 submit 均已跑通真实库 happy path
- adjust
- split
- late-fee-reduce
- price-diff
- bad-debt
- 动作返回值与 operat_log 写入已被验证
#### 日志
- `log-page / log-stat / log-detail / log-process / log-attachments` 已形成一组真实库联动回看
- `log-refund``log-prestorage``log-revoke` 已打通闭环
- `log-detail``originalTranSeq / attachmentRefs` 已被验证
---
## 四、前端使用建议(当前真值口径)
### 1. 提交后立即展示
提交类动作完成后,前端应优先使用提交响应里的:
- `adjustmentNo`
- `resultStatus`
- `approvalStatus`
- `writeBackStatus`
- `msg`
### 2. 页面列表回看
- 预存页:查 `prestorage-page`
- 已销页:查 `sold-page`
- 未销页:查 `unsold-page`
- 若要看“申请/动作留痕”,查 `log-page`
### 3. 二次动作弹窗
- 日志页弹窗(退款/转预存/撤销)都应以 `adjustmentNo` 作为主键
- 已销批量撤销当前以 `chargeIds[]` 为入参,不是 `adjustmentNo[]`
### 4. 状态口径
- 预存页 `workOrderStatus`0未处理 / 1已审核 / 2已完成 / 3已撤销
- 通用动作结果:
- `resultStatus`
- `approvalStatus`
- `writeBackStatus`
- 日志页状态:
- `statusCode/status` 为页面状态投影,不等于 `workOrderStatus`
---
## 五、剩余缺口
1. 还没有做“前端弹窗 A/B/C 切换路径”的 UI 级编排,只做到了接口级真实库链路。
2. 还没有把所有字段做成“页面元素 -> 字段 -> 接口 -> 证据”的逐项勾稽表。
3. 若后续要做最终验收,建议再补一版:
- 弹窗功能分组矩阵
- 字段级 contract/assertion matrix
---
## 六、证据索引
- 集成测试 bootstrap 与累计验证:
- `docs/evidence/rev004-accountprocess-integration-testing-bootstrap-2026-04-13.md`
- 代码位置:
- `sw-business-server/src/main/java/.../accountProcess/*Controller.java`
- `sw-business-server/src/main/java/.../accountProcess/vo/*ReqVO.java`
- `sw-business-server/src/main/java/.../accountProcess/vo/*RespVO.java`
- `sw-business-server/src/test/java/.../integration/rev004/accountprocess/Rev004AccountProcessCanaryQueryIntegrationTest.java`

View File

@ -0,0 +1,104 @@
# REV004 / accountProcess 页面文案与字典 label 核对表2026-04-13
## 1. 目的
本表站在前端/UAT 视角,回答:
- 页面上显示的文案/标签,当前应从哪个字段读取?
- 该字段是原始编码、字典 label还是代码 fallback 值?
- 当前是否已具备稳定真值来源?
> 说明:本表是“字段/label 来源核对”,不是视觉稿验收。
---
## 2. 预存调整页
| 页面展示项 | 建议展示来源 | 类型 | 当前真值来源 | 状态 |
|---|---|---|---|---|
| 工单状态 | `workOrderStatus` -> `work_status` label | 字典 label | `DictTypeConstants.WORK_STATUS` + 正式设计文档 + seed SQL | 已确认 |
| 调整类型 | `adjustmentType` | 业务枚举/旧口径 | 代码已有字段,但 label 映射未单列文档 | 待前端确认展示文案 |
| 客户编号/名称/地址 | `custCode/custName/custAddress` | 直接值 | DB 真值 | 已确认 |
| 调整余额/期初/期末余额 | `adjustAmount/preBalance/postBalance` | 直接值 | DB 真值 | 已确认 |
| 是否可撤销 | `canRevoke` | 布尔能力 | Service 推导 | 已确认 |
| 是否可查看附件 | `canViewAttachment` | 布尔能力 | Service 推导 | 已确认 |
| 提交成功提示 | `msg` | 文本 | Action 返回 | 已确认 |
| 详情结果状态 | `resultStatus` | 字典 label 候选 | 当前后端主要返回 code前端如需文案应绑 `account_adjust_result_status` | 已确认 |
| 详情审批状态 | `approvalStatus` | 字典 label 候选 | 绑 `account_adjust_approval_status` | 已确认 |
| 详情回写状态 | `writeBackStatus` | 字典 label 候选 | 绑 `account_adjust_writeback_status` | 已确认 |
### 预存页当前结论
- 工单状态四态已稳定:`0未处理 / 1已审核 / 2已完成 / 3已撤销`
- 详情三状态字段推荐前端统一走 REV004 新字典做 label 显示
- `prestorage-process / prestorage-attachments` 已有真实库证据,页面已具备展示基础
---
## 3. 已销调整页
| 页面展示项 | 建议展示来源 | 类型 | 当前真值来源 | 状态 |
|---|---|---|---|---|
| 用水性质 | `waterNature` | 当前为模板名/编码映射 | `PriceTemplate` 名称映射 | 已确认 |
| 收费方式 | `collectionMethod` | 字典 label | `charge_method` | 已确认 |
| 收费员 | `collector` | 直接值 | DB 字段 | 已确认 |
| 是否可调整 | `canAdjust` | 布尔能力 | Service 推导 | 已确认 |
| 是否可批量撤销 | `canBatchRevoke` | 布尔能力 | Service 推导 | 已确认 |
| 提交结果状态 | `resultStatus` | 字典 label 候选 | `account_adjust_result_status` | 已确认 |
| 提交审批状态 | `approvalStatus` | 字典 label 候选 | `account_adjust_approval_status` | 已确认 |
### 已销页当前结论
- 收费方式文案应以后端经 `charge_method` 解析后的 `collectionMethod` 为准
- 已销提交后的审批态展示建议直接使用返回 code + 新字典映射 label
- 批量撤销按钮能力应以后端 `canBatchRevoke``chargeIds[]` 入参约束为准
---
## 4. 未销调整页
| 页面展示项 | 建议展示来源 | 类型 | 当前真值来源 | 状态 |
|---|---|---|---|---|
| 用水性质 | `waterType` | 当前为模板编码 | 代码直接回 `priceTemplateCode` | 待前端决定是否需要 label 化 |
| 合计金额/账单金额/违约金 | `totalAmount/billAmount/penaltyAmount` | 直接值 | DB 真值 | 已确认 |
| 五类按钮显隐 | `canAdjust/canSplit/canLateFeeReduce/canPriceDiffAdjust/canBadDebtAdjust` | 布尔能力 | Service 推导 | 已确认 |
| 调整原因 | `applyReason -> 动态 reason 字典` | 字典 label | 见 REV004_DICT_BINDING_MATRIX | 已确认 |
| 分账原因 | `applyReason -> separate_reason` | 字典 label | 见 REV004_DICT_BINDING_MATRIX | 已确认 |
| 违约金减免原因 | `applyReason -> late_fee_reason` | 字典 label | 见 REV004_DICT_BINDING_MATRIX | 已确认 |
| 价差调整原因 | `applyReason -> price_reason` | 字典 label | 见 REV004_DICT_BINDING_MATRIX | 已确认 |
| 呆坏账原因 | `applyReason -> knotty_reason` | 字典 label | 见 REV004_DICT_BINDING_MATRIX | 已确认 |
### 未销页当前结论
- 五类弹窗的“原因”不能共用一个字典,应按 objectType/弹窗类型动态切换
- `waterType` 当前更像编码字段,如果前端要展示“中文用水性质”,需要确认是否再做模板名映射
---
## 5. 账务日志页
| 页面展示项 | 建议展示来源 | 类型 | 当前真值来源 | 状态 |
|---|---|---|---|---|
| 账务类型 | `accountType` | 字典 label | `account_adjust_object_type` | 已确认 |
| 处理方式 | `processMethod` | 代码映射 label | Service 内 legacy 映射 | 已确认 |
| 页面状态 | `status/statusCode` | 字典/兼容投影 | success/pending/rejected 由 Service 投影 | 已确认 |
| 目标户号 | `targetCustCode` | 直接值 | 日志明细/业务上下文 | 已确认 |
| 原/新预存、账单、水量、违约金 | 对应 original/new 字段 | 直接值 | DB + log detail 推导 | 已确认 |
| 是否可撤销/退款/预转存 | `canRevoke/canRefund/canPrestore` | 布尔能力 | Service 推导 | 已确认 |
| 结果状态 | `resultStatus` | 字典 label 候选 | `account_adjust_result_status` | 已确认 |
| 审批状态 | `approvalStatus` | 字典 label 候选 | `account_adjust_approval_status` | 已确认 |
| 回写状态 | `writeBackStatus` | 字典 label 候选 | `account_adjust_writeback_status` | 已确认 |
| 附件状态 | `resolved/message` | 直接值 | Attachment 解析逻辑 | 已确认 |
### 日志页当前结论
- `accountType``resultStatus/approvalStatus/writeBackStatus` 已有稳定字典来源
- `processMethod` 目前是代码映射,不完全等于字典 label需要前端按当前返回文案展示不建议自行二次翻译
- 日志页是当前最适合承接“状态展示 / 二次动作 / 留痕回看”的页面
---
## 6. 当前仍需前端/UAT逐页确认的点
1. 未销页 `waterType` 是否需要从编码升级为可读 label。
2. 预存页 `adjustmentType` 的页面中文文案是否已有既定口径。
3. 日志页 `processMethod/status` 是否与现有页面视觉稿/原型文案完全一致。
4. 历史页面或旧截图中若还出现“处理中”这类旧三态文案,应以后端新四态口径为准重新校对。
---
## 7. 结论
- 当前**状态字典与核心文案来源已经收口**,后端没有明显“真值不清”的问题。
- 剩余问题主要不在后端结构,而在:
- 页面展示是否直接使用后端返回文案
- 前端是否仍残留旧页面文案/旧字典绑定
- 某些编码字段是否还需要做前端可读化处理

View File

@ -0,0 +1,85 @@
# REV004 / 分账短版说明(给产品 / 前端2026-04-14
## 一句话结论
**分账** 不是退款,也不是减免。
它的业务含义是:
> 把一笔原账单按规则拆成多笔可独立处理的结果,便于分别收费、分别开票、分别承担。
当前 REV004 后端已经支持:
- **发起分账申请**
- **进入待审批**
- **被日志/查询/审批状态承接**
当前还不支持:
- **审批通过后真正执行拆账,生成多张目标账单**
---
## 当前可以怎么理解
### 业务上
老系统分账支持两种方式:
1. **按水量分账**
2. **按费用组成分账**
它适用于:
- 客户需要开多张发票
- 客户不能一次缴清
- 一张账单需要按规则拆给多个结果对象
### 后端当前落地到哪里
当前后端实现的是:
- `SPLIT_ADJUST` 分账申请
- 提交后状态:`PENDING_APPROVAL`
- 可以查询、留痕、审批承接
但还没有做到:
- 真的把一张原账单拆成多张目标账单
- 真的生成拆分明细
- 真的进入收费/开票承接执行态
---
## 为什么还没做到执行态
因为“真正分账执行”不是普通字段修改,而是一个独立正式业务对象级能力,至少涉及:
- 原账单与目标账单关系
- 分摊规则
- 分摊明细
- 审批通过后的执行流程
- 执行失败回滚
- 与收费/开票的后续承接
所以当前先落的是:
> **申请态 / 受理态**
而不是:
> **执行态 / 拆账落地态**
---
## 现在前端该怎么处理
### 当前前端可以做的
- 把“分账”当成一种**待审批业务申请**来用
- 提交后展示:
- `adjustmentNo`
- `resultStatus = PENDING_APPROVAL`
- `approvalStatus = PENDING_APPROVAL`
- `writeBackStatus = PENDING`
- 在日志/列表中查看这笔申请的留痕与状态
### 当前前端不要假设的
- 不要假设提交分账后会立刻生成多张新账单
- 不要假设已经存在完整的“分账结果明细页”可直接读取目标账单集合
---
## 如果后续要继续做
建议后续按这个顺序推进:
1. 明确业务真值:分账结果到底是“多张子账单”为主,还是“多笔待收费结果”为主
2. 明确数据模型:`SplitAdjust / SplitAdjustDetail`
3. 明确审批后执行:真正拆账、重算、留痕、回看
4. 再补前端执行态页面
---
## 当前最适合对外的话术
> 当前 REV004 已支持“分账申请”的统一受理、审批与查询回看,但尚未落到“审批通过后真正拆账生成多张子账单”的执行态。若后续要继续建设,需要按独立正式业务对象方式展开,而不是把它当成普通账单字段修改处理。

View File

@ -0,0 +1,195 @@
# REV004 / 分账为什么还没做到执行态2026-04-14
## 1. 目的
本摘要用于解释:
为什么当前 `REV004/accountProcess` 后端已经支持 `SPLIT_ADJUST` 分账申请,
但还没有做到“审批通过后真正把一张原账单拆成多张目标账单”的执行态能力。
---
## 2. 当前结论
### 结论一句话
当前后端实现的是:
- **分账申请态**
尚未实现的是:
- **分账执行态**
也就是:
- 现在可以提交分账申请、进入待审批、被日志与查询承接;
- 但还没有真正生成多张目标账单、分摊明细和后续收费/开票承接结果。
---
## 3. 代码证据
### 3.1 当前入口
当前分账在 `accountProcess` 中的入口是:
- `POST /admin-api/business/accounting-adjust/unsold-split-submit`
对应代码:
- `AccountingAdjustProcessServiceImpl.createUnsoldSplit(...)`
其行为是把分账提交统一转成:
- `objectType = SPLIT_ADJUST`
- `adjustType = SPLIT`
然后交给统一账务处理入口:
- `chargeService.adjustAccounting(...)`
### 3.2 当前真正处理逻辑
`ChargeServiceImpl.handleSplitAdjust(...)` 中,当前逻辑只有:
- `approvalRequired = true`
- `resultStatus = PENDING_APPROVAL`
- `approvalStatus = PENDING_APPROVAL`
- `writeBackStatus = PENDING`
- `message = 账单拆分申请已提交,待审批`
- `needUpdate = false`
这说明:
1. 只受理申请;
2. 不改原账单;
3. 不生成目标账单;
4. 不生成拆分明细;
5. 不进入真正执行态。
### 3.3 当前校验逻辑
当前只做了最小申请校验:
- 仅未收费账单允许发起分账申请
- `splitCount >= 2`
- `splitCount <= 12`
- 必须填写原因编码
- 必须填写调整原因
这也进一步说明:
- 当前实现重心是“能不能发起分账申请”
- 不是“如何执行真正的分账结果落地”
---
## 4. 业务复杂度为什么高
真正的分账执行态,不是普通字段修改,而是**结构性重分摊**。
### 4.1 文档中的两类策略
老系统与文档明确支持:
- **按水量分账**
- **按费用组成分账**
### 4.2 按水量分账需要解决的问题
- 原账单总水量拆成多笔
- 拆分水量之和必须等于原水量
- 拆分后重新按水价重算金额
- 可能影响违约金、阶梯、费用明细
### 4.3 按费用组成分账需要解决的问题
- 原账单费用项按规则拆分
- 拆分后金额总额必须与原账单一致
- 目标账单 / 目标客户 / 金额分摊关系需要明确
- 费用项粒度如何绑定目标结果也需要独立明细结构
### 4.4 执行态至少需要的能力
若真正落地执行态,后端至少需要:
- 原账单与目标账单关系模型
- 分摊规则模型
- 分摊明细模型
- 审批通过后的执行流程
- 执行失败回滚
- 与收费/开票/日志/查询的后续承接
因此,这不是“小补丁”能力,而是**独立正式业务对象级别**的建设。
---
## 5. 文档证据
### 5.1 需求与手册口径
文档明确说明:
- 分账是“由一笔账单分成两笔独立账单信息”
- 可按“按水量”“按费用组成”进行分账调整
- 适用于:
- 客户开多张发票
- 不能一次缴清等场景
这说明业务真值更接近:
- **账单拆分 + 分摊结果重建**
不是单纯加一条审批记录。
### 5.2 REV004 正式对象口径
`REV004_FULL_ACCOUNTING_DOMAIN_DESIGN.md` 中已将:
- `SplitAdjust`
- `SplitAdjustDetail`
视为独立正式业务对象,并建议存在:
- `split_adjust_no`
- `split_rule_type`
- `source_charge_id`
- `target_charge_id`
- `target_cust_id`
- `split_amount`
- `split_ratio / split_basis`
这表明:
- 正式执行态设计方向已经明确;
- 但当前代码还没有真正落成这套模型。
### 5.3 文档中的关键冻结判断
文档还明确给出:
- 当前先冻结设计方向
- 分账调整后续应补规则表或规则字段组
这意味着:
- “申请态先落、执行态后补”是有设计背景的,
- 不是单纯遗漏开发。
---
## 6. 当前这轮 REV004 的实现目标
从当前整体 accountProcess 收口策略看,这轮优先解决的是:
- 统一提交入口
- 统一状态表达
- 审批边界
- 日志留痕
- 查询回看
也就是先做到:
- 用户能发起
- 系统能记录
- 前端能查看
- 审批流能承接
因此分账也被纳入了这套统一账务调整框架,先实现:
- **申请态可用**
而没有直接推进到:
- **执行态拆账**
---
## 7. 最终判断
### 当前已经做到
- `SPLIT_ADJUST` 已进入统一账务调整对象体系
- 可提交申请
- 返回 `PENDING_APPROVAL`
- 可被日志/查询/审批状态承接
### 当前还没做到
- 审批通过后真正生成多张目标账单
- 原账单与目标账单的主从关系落库
- 按水量/按费用组成的拆分明细落库
- 执行态后的收费/开票联动承接
### 最准确的一句话
> 当前 REV004 后端已经实现“分账申请态”,但由于真正的分账执行态涉及分摊规则、目标账单生成、拆分明细、重算与后续收费/开票承接,属于独立正式对象级能力,因此尚未在 `accountProcess` 这一层落地。
---
## 8. 建议下一步
如果后续要继续推进“分账执行态”,建议按顺序展开:
1. 先明确业务真值:
- 结果对象到底是多张子账单、还是多笔待收费结果、还是两者同时存在
2. 再明确数据模型:
- `SplitAdjust` / `SplitAdjustDetail` 主表、明细表、规则字段组
3. 再明确执行流程:
- 审批通过 -> 拆账执行 -> 重算 -> 留痕 -> 查询回看
4. 最后补前端:
- 按水量 / 按费用组成 两种弹窗的真实执行态交互

View File

@ -0,0 +1,250 @@
# REV004 / accountProcess 页面元素勾稽矩阵2026-04-13
## 目的
`accountProcess` 当前后端真实口径进一步整理成:
**页面元素 / 弹窗能力 -> 字段 -> 接口 -> 当前证据状态**
便于:
- 前端逐项对表
- UAT 做验收勾稽
- 后端明确哪些已被真实库证实,哪些仍属于页面编排层缺口
> 本表基于当前 `water-backend` 代码、Req/RespVO、已落地真实库 canary 测试结果整理。
---
## 证据状态说明
- **已真实库验证**:已有真实 PostgreSQL + Spring + MockMvc canary 覆盖
- **已代码确认**:可从当前 Controller/RespVO/Service 明确确认,但尚未单独做真实库断言
- **待补证据**:当前还缺更细粒度验证或 UI 编排验证
---
## 一、预存调整页
### A. 列表区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 列表记录主键 | `id` | `GET /prestorage-page` | 已真实库验证 | 提交后可回查 detail |
| 调整单号 | `adjustmentNo` | `GET /prestorage-page` | 已真实库验证 | 提交后 page 可见 |
| 客户ID | `custId` | `GET /prestorage-page` | 已代码确认 | Response VO 已定义 |
| 工单状态 | `workOrderStatus` | `GET /prestorage-page` | 已真实库验证 | 已验证提交后为 `2=已完成` |
| 调整类型 | `adjustmentType` | `GET /prestorage-page` | 已代码确认 | page/detail 都有 |
| 客户编号 | `custCode` | `GET /prestorage-page` | 已真实库验证 | `REV004_IT_SRC` 已验证 |
| 目标户号 | `targetCustCode` | `GET /prestorage-page` | 已代码确认 | 转账/转预存场景使用 |
| 客户名称 | `custName` | `GET /prestorage-page` | 已代码确认 | |
| 客户地址 | `custAddress` | `GET /prestorage-page` | 已代码确认 | |
| 调整余额 | `adjustAmount` | `GET /prestorage-page` | 已代码确认 | |
| 期初余额 | `preBalance` | `GET /prestorage-page` | 已代码确认 | |
| 期末余额 | `postBalance` | `GET /prestorage-page` | 已代码确认 | |
| 调整原因 | `adjustReason` | `GET /prestorage-page` | 已代码确认 | |
| 备注 | `remark` | `GET /prestorage-page` | 已代码确认 | |
| 登记时间 | `createTime` | `GET /prestorage-page` | 已代码确认 | |
| 登记人员 | `creatorName` | `GET /prestorage-page` | 已代码确认 | |
| 是否可撤销 | `canRevoke` | `GET /prestorage-page` | 已代码确认 | 撤销能力由状态推导 |
| 是否可查看附件 | `canViewAttachment` | `GET /prestorage-page` | 已代码确认 | |
### B. 统计区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 总条数 | `totalCount` | `GET /prestorage-stat` | 已真实库验证 | |
| 调整余额合计 | `totalAdjustAmount` | `GET /prestorage-stat` | 已代码确认 | |
| 期初余额合计 | `totalPreBalance` | `GET /prestorage-stat` | 已代码确认 | |
| 期末余额合计 | `totalPostBalance` | `GET /prestorage-stat` | 已代码确认 | |
| 预存转账数量 | `transferCount` | `GET /prestorage-stat` | 已真实库验证 | 已验证退款场景下为 0 |
| 预存退款数量 | `refundCount` | `GET /prestorage-stat` | 已真实库验证 | 已验证退款场景下为 1 |
### C. 提交弹窗
| 页面元素 | 入参/出参字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 源客户编号 | `custCode` | `POST /prestorage-submit` | 已真实库验证 | |
| 目标户号 | `targetCustCode` | `POST /prestorage-submit` | 已真实库验证 | 转账场景可用;退款场景未单独验证 |
| 退款金额 | `refundAmount` | `POST /prestorage-submit` | 已真实库验证 | |
| 转账金额 | `transferAmount` | `POST /prestorage-submit` | 已代码确认 | 未单独真实库验证 |
| 原因 | `applyReason` | `POST /prestorage-submit` | 已真实库验证 | |
| 备注 | `remark` | `POST /prestorage-submit` | 已真实库验证 | |
| 附件引用 | `attachmentRefs` | `POST /prestorage-submit` | 已代码确认 | 未单独真实库验证 |
| 调整单号回显 | `adjustmentNo` | `POST /prestorage-submit` 返回 | 已真实库验证 | |
| 结果状态 | `resultStatus` | `POST /prestorage-submit` 返回 | 已真实库验证 | `SUCCESS` |
| 回写状态 | `writeBackStatus` | `POST /prestorage-submit` 返回 | 已真实库验证 | `UPDATED` |
| 提示文案 | `msg/message` | `POST /prestorage-submit` 返回 | 已代码确认 | |
### D. 详情 / 附件 / 流程 / 撤销
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 详情对象类型 | `objectType` | `GET /prestorage-detail` | 已代码确认 | |
| 详情结果状态 | `resultStatus` | `GET /prestorage-detail` | 已真实库验证 | |
| 详情审批状态 | `approvalStatus` | `GET /prestorage-detail` | 已代码确认 | |
| 详情回写状态 | `writeBackStatus` | `GET /prestorage-detail` | 已真实库验证 | |
| 流程任务ID | `processInstanceId` | `GET /prestorage-detail` | 已代码确认 | |
| 附件引用 | `attachmentRefs` | `GET /prestorage-detail` | 已代码确认 | |
| 查看流程 | `processState/stages[]` | `GET /prestorage-process` | 已代码确认 | 预存页流程接口存在,未单独真实库验证 |
| 查看附件 | `ref/resolved/...` | `GET /prestorage-attachments` | 已代码确认 | 预存页附件接口存在,未单独真实库验证 |
| 撤销动作 | `actionType/resultStatus/writeBackStatus` | `POST /prestorage-revoke` | 已真实库验证 | 余额恢复已验证 |
---
## 二、已销调整页
### A. 列表区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 账单ID | `id` | `GET /sold-page` | 已真实库验证 | |
| 客户ID | `custId` | `GET /sold-page` | 已代码确认 | |
| 账务年月 | `accountMonth` | `GET /sold-page` | 已代码确认 | |
| 客户编号 | `custCode` | `GET /sold-page` | 已真实库验证 | |
| 客户名称 | `custName` | `GET /sold-page` | 已代码确认 | |
| 客户地址 | `custAddress` | `GET /sold-page` | 已代码确认 | |
| 用水性质 | `waterNature` | `GET /sold-page` | 已代码确认 | |
| 开账水量 | `billedWaterVolume` | `GET /sold-page` | 已代码确认 | |
| 实收金额 | `actualAmount` | `GET /sold-page` | 已真实库验证 | stat 已验证 80.00 |
| 开账金额 | `billedAmount` | `GET /sold-page` | 已代码确认 | |
| 违约金 | `penaltyAmount` | `GET /sold-page` | 已代码确认 | |
| 收费方式 | `collectionMethod` | `GET /sold-page` | 已代码确认 | |
| 收费员 | `collector` | `GET /sold-page` | 已代码确认 | |
| 收费日期 | `collectionDate` | `GET /sold-page` | 已代码确认 | |
| 是否可调整 | `canAdjust` | `GET /sold-page` | 已代码确认 | |
| 是否可批量撤销 | `canBatchRevoke` | `GET /sold-page` | 已真实库验证 | 提交后仍可撤销 |
### B. 统计区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 总条数 | `totalCount` | `GET /sold-stat` | 已真实库验证 | |
| 开账水量合计 | `totalBilledWaterVolume` | `GET /sold-stat` | 已代码确认 | |
| 实收金额合计 | `totalActualAmount` | `GET /sold-stat` | 已真实库验证 | 80.00 |
| 开账金额合计 | `totalBilledAmount` | `GET /sold-stat` | 已代码确认 | |
| 违约金合计 | `totalPenaltyAmount` | `GET /sold-stat` | 已代码确认 | |
### C. 提交 / 批量撤销
| 页面元素 | 入参/出参字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 营业账ID | `chargeId` | `POST /sold-submit` | 已真实库验证 | |
| 原因 | `applyReason` | `POST /sold-submit` | 已真实库验证 | |
| 是否红冲发票 | `redInvoice` | `POST /sold-submit` | 已代码确认 | |
| 备注 | `remark` | `POST /sold-submit` | 已真实库验证 | |
| 附件引用 | `attachmentRefs` | `POST /sold-submit` | 已代码确认 | |
| 调整单号 | `adjustmentNo` | `POST /sold-submit` 返回 | 已真实库验证 | |
| 结果状态 | `resultStatus` | `POST /sold-submit` 返回 | 已真实库验证 | `PENDING_APPROVAL` |
| 审批状态 | `approvalStatus` | `POST /sold-submit` 返回 | 已真实库验证 | `PENDING_APPROVAL` |
| 批量撤销入参 | `chargeIds[]` | `POST /sold-batch-revoke` | 已真实库验证 | 不是 `adjustmentNo[]` |
| 批量撤销结果 | `successCount/failCount/items[]` | `POST /sold-batch-revoke` | 已真实库验证 | |
---
## 三、未销调整页
### A. 列表区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 账单ID | `id` | `GET /unsold-page` | 已代码确认 | |
| 客户ID | `custId` | `GET /unsold-page` | 已代码确认 | |
| 客户编号 | `custCode` | `GET /unsold-page` | 已代码确认 | |
| 客户名称 | `custName` | `GET /unsold-page` | 已代码确认 | |
| 客户地址 | `custAddress` | `GET /unsold-page` | 已代码确认 | |
| 用水性质 | `waterType` | `GET /unsold-page` | 已代码确认 | |
| 账务年月 | `accountMonth` | `GET /unsold-page` | 已代码确认 | |
| 用水量 | `waterVolume` | `GET /unsold-page` | 已代码确认 | |
| 合计金额 | `totalAmount` | `GET /unsold-page` | 已代码确认 | |
| 账单金额 | `billAmount` | `GET /unsold-page` | 已代码确认 | |
| 违约金 | `penaltyAmount` | `GET /unsold-page` | 已代码确认 | |
| 用水费/污水/垃圾/资源税/超定额/季节性 | 对应费用字段 | `GET /unsold-page` | 已代码确认 | |
| 是否可调整 | `canAdjust` | `GET /unsold-page` | 已代码确认 | |
| 是否可分账 | `canSplit` | `GET /unsold-page` | 已代码确认 | |
| 是否可违约金减免 | `canLateFeeReduce` | `GET /unsold-page` | 已代码确认 | |
| 是否可价差调整 | `canPriceDiffAdjust` | `GET /unsold-page` | 已代码确认 | |
| 是否可呆坏账调整 | `canBadDebtAdjust` | `GET /unsold-page` | 已代码确认 | |
### B. 统计区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 用水量合计 | `sumWaterVolume` | `GET /unsold-stat` | 已代码确认 | |
| 合计金额 | `sumTotalAmount` | `GET /unsold-stat` | 已代码确认 | |
| 账单金额 | `sumBillAmount` | `GET /unsold-stat` | 已代码确认 | |
| 违约金 | `sumPenaltyAmount` | `GET /unsold-stat` | 已代码确认 | |
| 费用组成合计 | `sumWaterFee/...` | `GET /unsold-stat` | 已代码确认 | |
### C. 五类弹窗动作
| 弹窗 | 关键入参 | 返回口径 | 当前状态 | 说明 |
|---|---|---|---|---|
| 调整 | `chargeId/applyReason/remark/targetBillWater/targetExtendedAmount/targetBillAmount` | `adjustmentNo/resultStatus/writeBackStatus` | 已真实库验证 | AMOUNT happy path 已验证 |
| 分账 | `chargeId/applyReason/remark/splitCount` | `adjustmentNo/objectType/resultStatus=PENDING_APPROVAL` | 已真实库验证 | |
| 违约金减免 | `chargeId/applyReason/remark/lateFeeReduceAmount` | `adjustmentNo/objectType/resultStatus=PENDING_APPROVAL` | 已真实库验证 | |
| 价差调整 | `chargeId/applyReason/remark/priceDiffAmount` | `adjustmentNo/objectType/resultStatus=PENDING_APPROVAL` | 已真实库验证 | |
| 呆坏账 | `chargeId/applyReason/remark/badDebtAmount` | `adjustmentNo/objectType=result BAD_DEBT_RECORD / PENDING_APPROVAL` | 已真实库验证 | |
---
## 四、账务日志页
### A. 列表区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 日志ID | `id` | `GET /log-page` | 已代码确认 | |
| 调整单号 | `adjustmentNo` | `GET /log-page` | 已真实库验证 | |
| 账务年月 | `accountMonth` | `GET /log-page` | 已代码确认 | |
| 客户ID/编号/名称/地址 | `custId/custCode/custName/custAddress` | `GET /log-page` | 部分已真实库验证 | `custCode` 已验证 |
| 账务类型 | `accountTypeCode/accountType` | `GET /log-page` | 已代码确认 | |
| 处理方式 | `processMethodCode/processMethod` | `GET /log-page` | 已代码确认 | |
| 金额 | `amount` | `GET /log-page` | 已代码确认 | |
| 描述 | `description` | `GET /log-page` | 已代码确认 | |
| 登记人/处理人 | `registrant/handler` | `GET /log-page` | 已代码确认 | |
| 处理时间/创建时间 | `handleTime/createTime` | `GET /log-page` | 已代码确认 | |
| 页面状态 | `statusCode/status` | `GET /log-page` | 已真实库验证 | `SUCCESS` 场景已验证 |
| 目标户号 | `targetCustCode` | `GET /log-page` | 已代码确认 | |
| 原/新预存 | `originalPrestore/newPrestore` | `GET /log-page` | 已代码确认 | |
| 原/新账单 | `originalBill/newBill` | `GET /log-page` | 已代码确认 | |
| 原/新水量 | `originalWaterVolume/newWaterVolume` | `GET /log-page` | 已代码确认 | |
| 原/新违约金 | `originalPenalty/newPenalty` | `GET /log-page` | 已代码确认 | |
| 变化量 | `billChange/waterVolumeChange/penaltyChange` | `GET /log-page` | 已代码确认 | |
| 是否可撤销/退款/转预存 | `canRevoke/canRefund/canPrestore` | `GET /log-page` | 已代码确认 | |
### B. 统计区
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 总条数 | `totalCount` | `GET /log-stat` | 已真实库验证 | |
| 调整金额 | `totalAmount` | `GET /log-stat` | 已代码确认 | |
| 调整水量 | `totalWaterVolume` | `GET /log-stat` | 已代码确认 | |
| 已完成数量 | `completedCount` | `GET /log-stat` | 已真实库验证 | |
| 未完成数量 | `pendingCount` | `GET /log-stat` | 已真实库验证 | sold 提交后场景已间接证明 pending |
| 已撤销数量 | `cancelledCount` | `GET /log-stat` | 已代码确认 | |
### C. 详情 / 流程 / 附件
| 页面元素 | 后端字段 | 接口 | 当前状态 | 说明 |
|---|---|---|---|---|
| 详情调整单号 | `adjustmentNo` | `GET /log-detail` | 已真实库验证 | |
| 对象类型 | `objectType` | `GET /log-detail` | 已代码确认 | |
| 结果状态 | `resultStatus` | `GET /log-detail` | 已真实库验证 | |
| 审批状态 | `approvalStatus` | `GET /log-detail` | 已代码确认 | |
| 回写状态 | `writeBackStatus` | `GET /log-detail` | 已代码确认 | |
| 原交易流水号 | `originalTranSeq` | `GET /log-detail` | 已真实库验证 | |
| 原系统流水号 | `originalSysTranSeq` | `GET /log-detail` | 已代码确认 | |
| 附件引用 | `attachmentRefs[]` | `GET /log-detail` | 已真实库验证 | |
| 详情明细 | `details[]` | `GET /log-detail` | 已代码确认 | |
| 流程状态 | `processState` | `GET /log-process` | 已真实库验证 | |
| 流程阶段 | `stages[]` | `GET /log-process` | 已代码确认 | |
| 附件原始引用 | `ref` | `GET /log-attachments` | 已真实库验证 | |
| 附件解析状态 | `resolved` | `GET /log-attachments` | 已真实库验证 | |
| 附件元数据 | `id/name/link/size/extension` | `GET /log-attachments` | 已代码确认 | 当前 mock-ref 未解析为真实附件 |
### D. 日志页二次动作弹窗
| 弹窗 | 关键入参 | 返回口径 | 当前状态 | 说明 |
|---|---|---|---|---|
| 转退款 | `adjustmentNo/reasonCode/reason` | `adjustmentNo/objectType/resultStatus/writeBackStatus` | 已真实库验证 | 且 bank 后续流水已验证 |
| 转预存 | `adjustmentNo/targetCustCode/reason` | `adjustmentNo/resultStatus` | 已真实库验证 | 目标余额变化已验证 |
| 撤销 | `adjustmentNo/comment` | `actionType/resultStatus/writeBackStatus` | 已真实库验证 | 回滚账单状态/余额已验证 |
---
## 五、当前最适合前端/UAT对表的使用方式
1. **动作成功后的即时展示**:直接用 `AccountingAdjustRespVO / AccountingAdjustActionRespVO`
2. **页面列表展示**:按页面查各自 `*-page / *-stat`
3. **动作留痕与二次操作**:统一以 `log-*` 视角看 `adjustmentNo`
4. **已销批量撤销特别注意**:当前后端口径是 `chargeIds[]`,不是 `adjustmentNo[]`
---
## 六、仍待补的更细证据
- `unsold-page / unsold-stat` 的真实库回看断言还未单独补
- 预存页 `attachments/process` 还未像 log 页一样做完整真实库链路断言
- 页面元素到字典标签展示(例如名称 label 是否完全满足 UI 文案)还缺单独验收

View File

@ -0,0 +1,222 @@
# REV004 / accountProcess UI 编排级验收清单2026-04-13
## 1. 目的
本清单面向前端 / UAT / 联调验收人员,回答:
- 某个页面有哪些核心弹窗/动作入口
- 提交后应该回看哪些区域/接口
- 当前这些链路是否已有后端真实库证据支撑
> 本清单不替代自动化测试,而是给人工联调 / 验收一份“按页面操作”的顺序脚本。
---
## 2. 使用说明
每条清单包含:
- **入口**:从哪个页面/按钮进入
- **动作**:调哪个后端接口
- **回看**:操作成功后应检查哪些页面区域
- **后端证据状态**:当前是否已有真实库证据
状态说明:
- **已真实库覆盖**:已有后端集成测试证明主链可运行
- **已代码确认**:后端接口与字段存在,但尚未专门做该页面编排级回看
---
## 3. 预存调整页
### 场景 P1预存退款提交 -> 列表/统计/详情回看
- 入口:预存调整页“预存退款”弹窗
- 动作接口:`POST /prestorage-submit`
- 提交后应回看:
- 列表:`GET /prestorage-page`
- 统计:`GET /prestorage-stat`
- 详情:`GET /prestorage-detail?id=...`
- 应确认:
- 新 `adjustmentNo` 出现在列表中
- 工单状态为“已完成”
- `refundCount` 增加
- detail 中 `resultStatus=SUCCESS`
- 后端证据状态:**已真实库覆盖**
### 场景 P2预存退款提交 -> 流程/附件回看
- 入口:预存调整页提交成功后,点“查看流程 / 查看附件”
- 动作接口:
- `GET /prestorage-process?adjustmentNo=...`
- `GET /prestorage-attachments?adjustmentNo=...`
- 应确认:
- process 可返回 `processState=UPDATED`
- attachments 返回提交时带入的附件引用
- 后端证据状态:**已真实库覆盖**
### 场景 P3预存记录撤销 -> 列表/余额回退
- 入口:预存调整页列表“撤销”按钮
- 动作接口:`POST /prestorage-revoke`
- 回看:
- 列表撤销状态
- 账户余额恢复
- 关联撤销日志
- 后端证据状态:**已真实库覆盖**
### 场景 P4预存转账提交
- 入口:预存调整页“预存转账”弹窗
- 动作接口:`POST /prestorage-submit`(传 `targetCustCode + transferAmount`
- 回看:
- 列表记录
- 目标户号
- 期初/期末余额变化
- 后端证据状态:**已代码确认 / 部分真实库覆盖**
- 说明:转账字段链路存在,但当前主证据仍以退款场景为主
---
## 4. 已销调整页
### 场景 S1已销调整提交 -> 已销列表/统计回看
- 入口:已销调整页“提交”弹窗
- 动作接口:`POST /sold-submit`
- 回看:
- `GET /sold-page`
- `GET /sold-stat`
- 应确认:
- 原账单仍可见
- `canBatchRevoke=true`
- 统计金额仍符合账单真值
- 后端证据状态:**已真实库覆盖**
### 场景 S2已销调整提交 -> 日志页留痕回看
- 入口:已销调整提交成功后,使用返回的 `adjustmentNo` 在日志页查询
- 动作接口:
- `GET /log-detail?adjustmentNo=...`
- `GET /log-process?adjustmentNo=...`
- 应确认:
- 日志详情存在
- 状态为待审批
- 后端证据状态:**已代码确认 / 部分真实库覆盖**
- 说明:已销提交本身和日志链主字段已证实,但“提交后页面跳日志”的 UI 编排尚未专门做一条端到端脚本
### 场景 S3已销批量撤销
- 入口:已销调整页列表批量勾选 -> “批量撤销”
- 动作接口:`POST /sold-batch-revoke`
- 入参特点:`chargeIds[]`
- 回看:
- 列表可撤销状态变化
- 撤销日志存在
- 后端证据状态:**已真实库覆盖**
---
## 5. 未销调整页
### 场景 U1未销调整金额/水量)提交 -> 列表/统计回看
- 入口:未销调整页“调整”弹窗
- 动作接口:`POST /unsold-adjust-submit`
- 回看:
- `GET /unsold-page`
- `GET /unsold-stat`
- 应确认:
- `totalAmount/billAmount` 更新
- 统计金额同步变化
- 后端证据状态:**已真实库覆盖**
### 场景 U2未销分账提交
- 入口:未销调整页“分账”弹窗
- 动作接口:`POST /unsold-split-submit`
- 回看:
- 提交结果为待审批
- 如页面有日志联动入口,可再看日志留痕
- 后端证据状态:**已真实库覆盖(动作)**
### 场景 U3未销违约金减免提交
- 入口:未销调整页“违约金减免”弹窗
- 动作接口:`POST /unsold-late-fee-reduce-submit`
- 回看:提交结果状态 / 待审批标识
- 后端证据状态:**已真实库覆盖(动作)**
### 场景 U4未销价差调整提交
- 入口:未销调整页“价差调整”弹窗
- 动作接口:`POST /unsold-price-diff-submit`
- 回看:提交结果状态 / 待审批标识
- 后端证据状态:**已真实库覆盖(动作)**
### 场景 U5未销呆坏账提交
- 入口:未销调整页“呆坏账调整”弹窗
- 动作接口:`POST /unsold-bad-debt-submit`
- 回看:提交结果状态 / 待审批标识
- 后端证据状态:**已真实库覆盖(动作)**
### 场景 U6未销查询页初始态
- 入口:未销调整页默认查询
- 动作接口:
- `GET /unsold-page`
- `GET /unsold-stat`
- 应确认:
- 初始未销账单金额与违约金展示正确
- 五类按钮能力显隐正确
- 后端证据状态:**已真实库覆盖**
---
## 6. 账务日志页
### 场景 L1日志页默认查询 -> page/stat/detail 联动
- 入口:账务日志页查询
- 动作接口:
- `GET /log-page`
- `GET /log-stat`
- `GET /log-detail?adjustmentNo=...`
- 应确认:
- 列表、统计、详情三处状态一致
- 后端证据状态:**已真实库覆盖**
### 场景 L2日志页查看流程 / 附件
- 入口:日志页“查看流程 / 查看附件”
- 动作接口:
- `GET /log-process?adjustmentNo=...`
- `GET /log-attachments?adjustmentNo=...`
- 应确认:
- process 返回阶段与状态摘要
- attachments 返回引用及解析状态
- 后端证据状态:**已真实库覆盖**
### 场景 L3日志页转退款
- 入口:日志页“转退款”弹窗
- 动作接口:`POST /log-refund`
- 回看:
- 日志状态变化
- 账单收费状态变化
- bank follow-up 留痕
- 后端证据状态:**已真实库覆盖**
### 场景 L4日志页转预存
- 入口:日志页“转预存”弹窗
- 动作接口:`POST /log-prestorage`
- 回看:
- 日志状态变化
- 目标账户余额变化
- 可继续查看 process / attachments
- 后端证据状态:**已真实库覆盖**
### 场景 L5日志页撤销
- 入口:日志页“撤销”按钮
- 动作接口:`POST /log-revoke`
- 回看:
- 原账单支付状态恢复
- 目标预存余额回退
- 日志中出现撤销链记录
- 后端证据状态:**已真实库覆盖**
---
## 7. 当前对前端/UAT最重要的提醒
1. 已销批量撤销使用 `chargeIds[]`,不要误用 `adjustmentNo[]`
2. 日志页所有二次动作统一以 `adjustmentNo` 作为主键。
3. 未销页五类弹窗“原因”应动态切字典,不要共用一个原因下拉。
4. 若页面仍显示旧三态文案(如“处理中”),应以后端当前四态真值为准重新对齐。
---
## 8. 当前仍未通过本清单覆盖的点
1. 纯 UI 级交互(禁用态、二次确认提示、按钮联动)尚未自动化验证。
2. 边角筛选条件还未做完整穷尽。
3. 某些编码字段是否需要前端额外 label 化(如 `waterType`)仍需页面确认。

View File

@ -0,0 +1,156 @@
# REV004 未销违约金减免批量契约补齐实施记录2026-04-14
## 目标
补齐 `unsold-late-fee-reduce-batch-submit` 的批量 outer 契约,使其能够承接前端页面公共表单字段,并把字段真实透传到后端执行主链,而不是只停留在 controller VO。
## 本次实现
### 1. 批量 outer 契约补齐
文件:
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/accountingadjust/accountProcess/vo/AccountingAdjustUnsoldLateFeeReduceBatchSubmitReqVO.java`
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/accountingadjust/accountProcess/vo/AccountingAdjustUnsoldLateFeeReduceBatchItemReqVO.java`
新增 outer 字段:
- `lateFeeType`
- `applicant`
- `contactMobile`
- `applyReason`
- `remark`
- `attachmentRefs`
明细 item 独立为专用 VO
- `chargeId`
- `adjustmentNo`
- `applyReason`(兼容旧逐项提交)
- `remark`(兼容旧逐项提交)
- `attachmentRefs`(兼容旧逐项提交)
- `lateFeeReduceAmount`
- `startDate`
- `endDate`
### 2. 共享 batch 主链承接 outer 字段
文件:
- `.../AccountingAdjustBatchSubmitReqVO.java`
- `.../AccountingAdjustActionController.java`
- `.../AccountingAdjustProcessServiceImpl.java`
处理方式:
- controller 先把 late-fee batch outer 字段规范化映射到 generic batch DTO
- process 主链在 `executeBatchSubmit` 中统一执行 outer -> item 合并
- 统一 batch 主链承接字段:
- `reasonCode`
- `reason`
- `applicant`
- `contactMobile`
- `attachmentRefs`
- `lateFeeType`
这避免了“专用 VO 上有字段,但 generic batch 主链吃不到”的伪完成。
### 3. amount / date 模式校验补齐
文件:
- `.../AccountingAdjustProcessServiceImpl.java`
- `.../AccountingAdjustReqVO.java`
- `.../ChargeServiceImpl.java`
规则:
- `lateFeeType=1`(按金额)
- 要求 `lateFeeReduceAmount > 0`
- 不允许同时传 `startDate/endDate`
- `lateFeeType=2`(按日期)
- 要求 `startDate/endDate` 同时存在,且 `endDate >= startDate`
- 不允许同时传 `lateFeeReduceAmount`
- 未显式传 `lateFeeType` 时:
- 若存在日期字段,推导为 `2`
- 否则默认 `1`
### 4. 执行日志落地字段补齐
文件:
- `.../AccountingAdjustReqVO.java`
- `.../ChargeServiceImpl.java`
新增写入 operat log detail 的字段:
- `lateFeeType`
- `applicant`
- `contactMobile`
- `startDate`
- `endDate`
## 验证结果
### 编译
命令:
```bash
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
### 定向单测
命令:
```bash
mvn -pl sw-business/sw-business-server \
-Dtest=AccountingAdjustActionControllerTest#batchCreateUnsoldLateFeeReduce_shouldReturnWrappedSuccess,AccountingAdjustProcessServiceImplTest#createUnsoldLateFeeReduce_shouldPassDateModeFieldsToUnifiedChargeService+createUnsoldLateFeeReduce_shouldRejectMixedAmountAndDateMode+batchCreateUnsoldLateFeeReduce_shouldMergeBatchOuterFieldsIntoItems \
test
```
结果:**PASS4 tests, 0 fail, 0 error**
### 真实 DB 定向集成
命令:
```bash
REV004_IT_DB_URL=jdbc:postgresql://192.168.10.130:5436/sw_system \
REV004_IT_DB_USERNAME=sw_system \
REV004_IT_DB_PASSWORD='Em@123456' \
mvn -pl sw-business/sw-business-server \
-Dtest=Rev004AccountProcessCanaryQueryIntegrationTest#unsoldLateFeeReduceBatchSubmit_shouldAcceptOuterFieldsAndDateModeContract \
test
```
结果:**PASS1 test, 0 fail, 0 error**
集成验证确认:
- batch outer 字段可提交
- `lateFeeType=2` date-mode 契约可进入主链
- operat log detail 中可看到:
- `lateFeeType=2`
- `applicant`
- `contactMobile`
- `startDate`
- `endDate`
- `attachmentRefs`
## 当前边界与剩余风险
1. **本轮重点是“提交契约 + 主链承接 + 日志落地”**
2. `lateFeeType=2` 的“按日期执行态/审批回写态”尚未展开为完整金额计算逻辑;当前已确保申请态与提交链路可用。
3. 由于仓库当前还存在其他在制改动,本轮只做了定向验证,没有把整个相关测试类全部拉绿。
## 结论
本轮已完成 REV004 未销违约金减免批量提交接口的主契约补齐,并把前端页面公共字段正式落到共享 batch 主链与日志记录中;可以支撑前端继续联调“按金额/按日期”两种提交形态。
## 追加收口(读模型展示字段)
### 本轮补齐
- `AccountingAdjustDetailRespVO` 新增:
- `lateFeeType`
- `applicant`
- `contactMobile`
- `startDate`
- `endDate`
- `AccountingAdjustLogDetailRespVO` 新增同名字段
- `AccountingAdjustProcessRespVO` 新增:
- `reasonCode`
- `attachmentRefs`
- `lateFeeType`
- `applicant`
- `contactMobile`
- `startDate`
- `endDate`
### 读取链路
- `AccountingAdjustQueryServiceImpl`:从 operat log detail 读取 late-fee 扩展字段并映射到 detail response
- `AccountingAdjustLogProcessServiceImpl`:从 request/action log detail 读取 late-fee 扩展字段并映射到 log-detail response
- `AccountingAdjustProcessServiceImpl#getProcess`:从 unified snapshot 读取并投影到 process response
### 追加验证
#### 定向读模型单测
```bash
mvn -pl sw-business/sw-business-server \
-Dtest=AccountingAdjustQueryServiceImplTest,AccountingAdjustLogProcessServiceImplTest,AccountingAdjustProcessServiceImplTest#getProcess_shouldExposeLateFeeDisplayFieldsFromUnifiedSnapshot \
test
```
结果:**PASS7 tests, 0 fail, 0 error**

View File

@ -0,0 +1,84 @@
# REV004 违约金规则确认2026-04-15
## 结论
当前后续实现应以以下业务规则作为真值:
> **违约金 = 欠缴水费金额 × 0.1‰ × 逾期天数**
该规则意味着:
- **按日计收**,不是按月滚动
- 计算基数是**欠缴水费金额**
- **不含违约金本身**
- **不得利滚利**
## 业务前提
违约金产生需满足:
1. 逾期未缴
2. 经供水单位通知后仍未缴
## 对 REV004 的实现影响
### 1. 计算模型
后续 `late-fee reduce` 的设计与实现,应以“按日计收”模型展开,而不是“按月滚动”模型。
### 2. date-mode 减免理解
`lateFeeType=2`(按日期)应理解为:
- 对指定日期区间内对应的逾期天数区间做减免
- 先计算该区间理论应收违约金
- 再形成:
- `lateFeeBefore`
- `reduceAmount`
- `lateFeeAfter`
### 3. 需要补齐/确认的系统要素
除现有:
- `lateFeeBeginDate`
- `lateFee`
- `penaltyCoefficient`
还应确认或补齐:
- 欠缴本金
- 通知状态 / 通知时间
- 逾期起算日
- 逾期天数
- 上限规则(如部分地区 30%
- 60 日后续处置边界
## 与当前仓库现状的关系
### 当前已确认存在的模型字段
- `ChargeDO.lateFeeBeginDate`
- `ChargeDO.lateFee`
- `CostComponentDO.penaltyCoefficient`
### 当前未确认存在的现成实现
仓库中尚未确认存在:
- 明确的“按日计收违约金”统一计算器
- 明确的“按日期区间重算违约金”统一服务
因此,当前应将该规则视为:
- **业务规则真值输入**
- 后续需要据此补正式实现
## 使用建议
后续 PRD / 设计稿 / 代码实现,不建议再使用“按月滚动”表述;应统一表述为:
> **按日计收、按区间减免、按期累计结果**
## 追加确认2026-04-15
### 系数来源模型
已进一步确认:
- 逐项重算违约金时,系数来源为 `CostComponentDO.penaltyCoefficient`
- 取数链路为:`ChargeDetailDO.costComponentCode -> CostComponentDO.code -> penaltyCoefficient`
### 参与计算范围
- 所有未缴费用项都参与。
- 不收违约金的费用项,不做额外白名单过滤,而是通过 `penaltyCoefficient = 0` 自然贡献 0。
### 汇总口径
- 每个费用项先单独计算违约金;
- 每项先四舍五入到分;
- 最后再求和。
### 当前仓库状态
- 已确认存在上述模型链路;
- 但尚未发现现成“逐项按日期重算违约金”的统一实现。

View File

@ -0,0 +1,27 @@
# REV004 late-fee formal table 部署 SQL 说明2026-04-15
## 新增脚本
- `sql/rev004/REV004_latefee_formal_tables_deploy.sql`
## 作用
为 late-fee reduce 的新 formal table 提供单独部署脚本,覆盖:
- `biz_latefee_reduce`
- `biz_latefee_reduce_detail`
- 对应 sequence
- 主键 / 唯一索引 / 常用索引
- 明细表外键
## 适用场景
1. 测试库 / 联调库先补表
2. 为真实 DB canary 排除“缺表”阻塞
3. 为后续 formal-table 路线提供独立部署入口
## 注意事项
- 当前脚本按 PostgreSQL / 测试环境风格编写
- 若正式环境不是 PostgreSQL需先做方言适配
- 此脚本只覆盖 late-fee 两张表,不包含坏账 / 核销 / 价差等对象
## 建议使用顺序
1. 先在目标库执行 `REV004_latefee_formal_tables_deploy.sql`
2. 再重跑 late-fee date-mode canary
3. 若通过,再考虑推广 formal-table 到其他对象

View File

@ -0,0 +1,122 @@
# REV004 违约金减免现结构与老字典差异摘要2026-04-14
## 结论
当前 REV004 违约金减免结构已经对齐老字典/老表结构的核心骨架:
- `LateFeeType` 仍保持 `1=按金额 / 2=按日期`
- 已承接申请人、联系电话、备注
- 已承接 `StartDate/EndDate`
- 已承接账单维度 `chargeId(FeeId)`
但当前更偏**申请契约 + 日志/读模型承接**,并未完整复刻老系统执行态表模型。
## 老字典/老表结构证据
### 主表 `PM_LATEFEE_RECORDS`
来源:`营收数据字典.md:3117-3126`
- `Applicant`
- `Mobile`
- `ApplyType`
- `LateFeeType`
- `State`
- `Remark`
- `TaskId`
- `StepId`
- `FlowRemark`
- `BusinessType`
### 明细表 `PM_LATEFEE_RECORD_DETAILS`
来源:`营收数据字典.md:3143-3158`
- `CustId/CustCode/CustName/CustAddress`
- `BillMonth`
- `LateFee`
- `ReduceMoney`
- `NewLateFee`
- `StartDate`
- `EndDate`
- `ProcType/ProcPerson/ProcDate/ProcRemark`
- `State`
- `FeeId`
### 老字典枚举
来源:`营收数据字典.md:5683-5697`
- `LateFeeReason`: `1=用户协商`, `2=其它`
- `LateFeeType`: `1=按金额`, `2=按日期`
## 当前结构证据
### DDL 草案
来源:`sql/rev004/REV004_accounting_adjustments_ddl.sql:289-403`
- 主表 `biz_latefee_reduce`
- `applicant_name`
- `applicant_mobile`
- `late_fee_type`
- `apply_reason_code`
- `remark`
- `approval_status`
- `reduce_status`
- 明细表 `biz_latefee_reduce_detail`
- `charge_id`
- `cust_id/cust_code/cust_name/cust_address`
- `bill_month`
- `start_date/end_date`
- `late_fee_before`
- `reduce_amount`
- `late_fee_after`
- `proc_type/proc_person/proc_time/proc_remark`
### 当前批量提交契约
来源:
- `AccountingAdjustUnsoldLateFeeReduceBatchSubmitReqVO`
- `AccountingAdjustUnsoldLateFeeReduceBatchItemReqVO`
当前 outer
- `lateFeeType`
- `applicant`
- `contactMobile`
- `applyReason`
- `remark`
- `attachmentRefs`
- `items`
当前 item
- `chargeId`
- `adjustmentNo`
- `lateFeeReduceAmount`
- `startDate`
- `endDate`
- 兼容项:`applyReason/remark/attachmentRefs`
## 已对齐项
1. `LateFeeType` 语义已对齐老字典
2. `Applicant/Mobile` 已有对应字段
3. `Remark` 已有对应字段
4. `StartDate/EndDate` 已有对应字段
5. `FeeId -> chargeId` 已有明确对应
6. `ReduceMoney -> lateFeeReduceAmount/reduce_amount` 语义已对齐
7. detail / log-detail / process 已可读出 late-fee 扩展字段
## 未完全落地项
1. **ApplyType / LateFeeReason 字典口径未完全统一**
- 老字典:`1=用户协商, 2=其它`
- 当前前端历史口径曾使用不同原因值
2. **State 未按老系统单字段口径落地**
- 当前主要使用 `approvalStatus/resultStatus/writeBackStatus`
3. **按日期模式仍偏申请态**
- 还未形成完整审批执行/计算回写
4. **执行结果落表未完整 runtime 化**
- DDL 草案已具备 `late_fee_before/reduce_amount/late_fee_after`
- 但当前核心还是契约 + 日志承接
5. **处理过程字段未完整 runtime 落地**
- `ProcType/ProcPerson/ProcDate/ProcRemark`
6. **老流程字段未完整复刻**
- `StepId/FlowRemark/BusinessType`
## 优先级建议
### P0
- 统一 `applyReason``LateFeeReason` 口径
- 给出老 `State` 与当前审批/回写状态映射表
### P1
- 补齐 `lateFeeType=2` 按日期模式执行态
- 审批通过后把结果正式落到 `biz_latefee_reduce / biz_latefee_reduce_detail`
### P2
- 再决定是否需要复刻 `StepId/FlowRemark/BusinessType/applicant_id`

View File

@ -0,0 +1,119 @@
# REV004 prestorage BPM 字段已应用到 application-dev 测试库2026-04-24
## 目标库
依据:
- `sw-business/sw-business-server/src/main/resources/application-dev.yaml`
解析结果:
- Host`192.168.10.130`
- Port`5436`
- DB`sw_system`
- User`sw_system`
## 本次目的
在既有 `biz_prestorage_adjust` / `biz_prestorage_adjust_detail` formal-table 基础上,补齐“保存即提审 / BPM 回写”所需的主表字段与索引。
## 实际执行
执行增量 DDL
- `ALTER TABLE biz_prestorage_adjust ADD COLUMN IF NOT EXISTS ...`
- 新增索引:
- `idx_biz_prestorage_adjust_process_instance`
- `idx_biz_prestorage_adjust_business_status`
- `idx_biz_prestorage_adjust_business_key`
同步更新本地脚本:
- `sql/rev004/REV004_prestorage_formal_tables_deploy.sql`
## 已补字段
- `business_status`
- `approval_result`
- `approval_comment`
- `execution_status`
- `execution_message`
- `approved_at`
- `rejected_at`
- `cancelled_at`
- `rolled_back_at`
- `process_instance_id`
- `process_definition_key`
- `business_key`
- `current_task_id`
- `current_task_name`
## 回读校验
### 字段回读
已确认上述 14 个字段均已存在于:
- `public.biz_prestorage_adjust`
### 索引回读
已确认以下索引存在:
- `idx_biz_prestorage_adjust_process_instance`
- `idx_biz_prestorage_adjust_business_status`
- `idx_biz_prestorage_adjust_business_key`
## DB smoke
在测试库中开启事务,插入一条带 BPM 字段的 `biz_prestorage_adjust` 记录并回读,随后回滚。
验证结果:
- 插入成功
- `business_status=IN_APPROVAL`
- `approval_status=PROCESSING`
- `execution_status=PENDING`
- `process_instance_id=PI-SMOKE-001`
- `current_task_name=预存调整审批`
- 回滚后 `left_count=0`
结果:**PASS**
## 当前结论
`application-dev` 指向的测试库已经具备 REV004 prestorage BPM 接线所需的数据库字段基础,可以继续进行:
1. 保存即发起 BPM
2. 审批回写业务状态
3. 审批中改类型重启流程
4. 审批中撤销终止流程
## 当前仍未覆盖
1. 真实 BPM 流程定义 `prestorage_adjust` 是否已在环境中部署,尚未验证;
2. 真实业务服务 + 真实 BPM 流程实例联调尚未完成;
3. 本次仅完成数据库结构到位与最小 smoke。
## 补充复核2026-04-24 11:05 +08:00
### 1. 部署脚本幂等重放
再次执行:
```bash
PGPASSWORD='Em@123456' \
psql -h 192.168.10.130 -p 5436 -U sw_system -d sw_system \
-v ON_ERROR_STOP=1 \
-f sql/rev004/REV004_prestorage_formal_tables_deploy.sql
```
结果:**PASS**
关键现象:
- 已存在 sequence / table / index 均以 `already exists, skipping` 跳过;
- 已存在 BPM 字段均以 `column ... already exists, skipping` 跳过;
- 脚本可重复执行,不会因本次增量字段而破坏既有库结构。
### 2. 相关模块回归测试
执行:
```bash
mvn -pl sw-business/sw-business-server,sw-module-bpm/sw-module-bpm-server -am \
-Dtest=AccountingAdjustProcessServiceImplTest,PrestorageBpmBridgeServiceTest,PrestorageBpmCallbackServiceTest,BpmPrestorageAdjustStatusListenerTest \
-Dsurefire.failIfNoSpecifiedTests=false test
```
结果:**BUILD SUCCESS**
测试汇总:
- `AccountingAdjustProcessServiceImplTest`27 通过
- `PrestorageBpmBridgeServiceTest`2 通过
- `PrestorageBpmCallbackServiceTest`3 通过
- `BpmPrestorageAdjustStatusListenerTest`1 通过
- 合计:**32/32 通过**
## 最新结论
截至 2026-04-24 11:05 +08:00
1. 测试库 BPM 字段已补齐;
2. 部署脚本可幂等重放;
3. 预存 BPM 相关业务/BPM 单测已通过;
4. 仍待真实 BPM 流程定义与真实流程实例联调验证。

View File

@ -0,0 +1,70 @@
# REV004 prestorage BPM 部署后集成检查2026-04-24
## 环境
- 主机:`root@192.168.10.130`
- 数据库:`jdbc:postgresql://192.168.10.130:5436/sw_system`
- 参考配置:
- `sw-business/sw-business-server/src/main/resources/application-dev.yaml`
- `sw-gateway/src/main/resources/application-dev.yaml`
## 检查目标
验证部署后的 REV004 预存调整 BPM 接口是否可通过网关/业务服务完成真实 HTTP 集成测试。
## 运行态探测
### 容器状态
- `sw-gateway`: Up
- `sw-module-bpm`: Up
- `sw-business-server`: `Up (health: starting)`,且 `RestartCount=7`
### 端口
- 网关:`48080`
- 业务服务映射:`48081 -> container 48090`
## HTTP 实测
### 1. 网关健康
`GET http://127.0.0.1:48080/actuator/health`
- 返回:`{"status":"UP"}`
- 结果PASS
### 2. 网关预存接口
`GET /admin-api/business/accounting-adjust/prestorage-page`
- 未登录:`401 账号未登录`
- 使用 `Authorization: emsoft1` 仍返回 `401`
- 结论:网关侧不支持直接使用 business 服务的 mock token 调测
### 3. 业务服务预存接口
`GET http://127.0.0.1:48081/admin-api/business/accounting-adjust/prestorage-page?pageNo=1&pageSize=1`
- `Authorization: emsoft1, tenant-id:0`:返回 `500 系统异常`
- `Authorization: emsoft1, tenant-id:1`:返回 `404 请求地址不存在`
## 日志根因
`docker logs sw-business-server` 明确显示:
- Spring 启动失败点:`Error creating bean with name 'accountingAdjustActionController': Injection of resource dependencies failed`
- 最终失败原因:
- `A component required a bean of type 'cn.com.emsoft.sw.module.bpm.api.task.BpmProcessInstanceApi' that could not be found.`
## 结论
当前 **不是接口联调数据问题**,而是 **部署后的 business 服务启动失败 / controller 未成功装配**,因此无法继续完成真实接口集成测试。
## 影响判断
本次预存 BPM 变更不仅修改了 business 模块,也修改了 BPM 相关模块:
- `sw-module-bpm-api/.../BpmProcessInstanceApi.java`
- `sw-module-bpm-api/.../dto/BpmProcessInstanceCancelReqDTO.java`
- `sw-module-bpm-server/.../BpmProcessInstanceApiImpl.java`
- `sw-module-bpm-server/.../RpcConfiguration.java`
- `sw-module-bpm-server/.../BpmPrestorageAdjustStatusListener.java`
因此若仅更新 `sw-business-server`,或 `sw-module-bpm` 未按同版本一并部署,就会出现当前缺少 `BpmProcessInstanceApi` Bean 的启动失败。
## 建议下一步
1. 同版本重新部署:
- `sw-business-server`
- `sw-module-bpm`
2. 部署后先验证:
- `sw-business-server` 健康状态变为 healthy / restart count 停止增长
- 业务服务日志不再出现 `BpmProcessInstanceApi` 缺失
3. 然后再执行预存 BPM 真实 HTTP 集成测试:
- save 即提审
- page/detail/process 查询
- revoke
- BPM 审批回写链路

View File

@ -0,0 +1,94 @@
# REV004 prestorage process/attachments strict formal-first2026-04-17
## 目标
收口:
- `GET /admin-api/business/accounting-adjust/prestorage-process`
- `GET /admin-api/business/accounting-adjust/prestorage-attachments`
使其优先读取 prestorage formal-table而不是继续主要依赖 legacy/unified fallback。
## 代码变更
核心变更位于:
- `AccountingAdjustProcessServiceImpl`
- `AccountingAdjustProcessServiceImplTest`
策略:
1. `getProcess(adjustmentNo)` 先尝试 `PrestorageFormalizationService.getView(adjustmentNo)`
2. 命中 formal view 时,直接组装 `AccountingAdjustProcessRespVO`
3. `getAttachments(adjustmentNo)` 先尝试读取 formal `attachmentRefs`
4. 仅在 formal 不存在时才回退到 synthetic / unified 口径
## 验证
### compile
```bash
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
### targeted tests
```bash
mvn -pl sw-business/sw-business-server -Dtest=AccountingAdjustProcessServiceImplTest,AccountingAdjustPrestorageProcessServiceImplTest test
```
结果:**PASS**
- Tests run: 23
- Failures: 0
- Errors: 0
## fresh jar smokeport 48098
### health
- `GET /actuator/health` -> `{"status":"UP"}`
### smoke 数据
手工 seed
- `adjustmentNo = REV004-PTR-993001-SEED`
- formal main`biz_prestorage_adjust`
- formal detail`biz_prestorage_adjust_detail`
- attachment refs`101,proof-raw`
### process
调用:
- `GET /admin-api/business/accounting-adjust/prestorage-process?adjustmentNo=REV004-PTR-993001-SEED`
结果:**PASS**
返回关键字段:
- `objectType = LEGACY_PRESTORAGE_TRANSFER`
- `adjustType = TRANSFER`
- `actionAmount = 20.0`
- `resultStatus = SUCCESS`
- `approvalStatus = NOT_REQUIRED`
- `writeBackStatus = UPDATED`
- `attachmentRefs = ["101", "proof-raw"]`
- `applicant = 王五`
- `contactMobile = 13700000000`
- `latestMessage = 预存转账成功,目标户号=C-993002`
说明process 已命中 formal main而不是再走 unified detail 兜底。
### attachments
调用:
- `GET /admin-api/business/accounting-adjust/prestorage-attachments?adjustmentNo=REV004-PTR-993001-SEED`
结果:**PASS**
返回:
- ref=`101` -> 数值 ID 解析,当前附件实体不存在,返回 `resolved=false, message=附件不存在`
- ref=`proof-raw` -> 非数值引用,返回 `resolved=false, message=附件引用不是数值ID保留原始引用`
说明attachments 已优先读取 formal `attachmentRefs`,并保留现有解析策略。
## 清理
已删除:
- `biz_prestorage_adjust / detail` seed 数据
回读结果:
- `prestorage_main_left=0`
- `prestorage_detail_left=0`
运行态:
- `48098` 已停止
## 当前结论
本轮 prestorage 剩余查询缺口已完成 strict formal-first 收口:
1. `prestorage-process` 优先命中 formal
2. `prestorage-attachments` 优先命中 formal attachment refs
3. formal 缺失时仍可继续 fallback
4. 主链路 schema / 写路径无变更

View File

@ -0,0 +1,119 @@
# REV004 预存调整 prestorage-submit 开发环境调用记录2026-04-23
- 验证日期2026-04-23
- 后端仓基线:`21714d64822268d8dcb7cd1296656b4c19ff95fa`
- 前端仓基线:`d2698e1f5d107422f64928086d89d4b803cd12ae`
- 目标环境:`root@192.168.10.130`
- 服务端口:`sw-gateway -> 127.0.0.1:48080``sw-business-server -> 127.0.0.1:48090`
- 配置依据:
- `water-backend/sw-gateway/src/main/resources/application-dev.yaml`
- `water-backend/sw-business/sw-business-server/src/main/resources/application-dev.yaml`
- 鉴权方式:开发环境 `sw.security.mock-enable=true`,使用 `Authorization: Bearer emsoft1` + `tenant-id: 1`
## 1. 实际调用 payload
```json
{
"applicant": "李四",
"applyReason": "充值错误",
"attachmentRefs": [],
"contactMobile": "19928382738",
"custCode": "26041011111",
"refundAmount": 2,
"remark": "ssa"
}
```
## 2. 实际调用命令
### 2.1 直连 business
```bash
curl -X POST 'http://127.0.0.1:48090/admin-api/business/accounting-adjust/prestorage-submit' \
-H 'Authorization: Bearer emsoft1' \
-H 'tenant-id: 1' \
-H 'Content-Type: application/json' \
--data '{"applicant":"李四","applyReason":"充值错误","attachmentRefs":[],"contactMobile":"19928382738","custCode":"26041011111","refundAmount":2,"remark":"ssa"}'
```
### 2.2 走 gateway
```bash
curl -X POST 'http://127.0.0.1:48080/admin-api/business/accounting-adjust/prestorage-submit' \
-H 'Authorization: Bearer emsoft1' \
-H 'tenant-id: 1' \
-H 'Content-Type: application/json' \
--data '{"applicant":"李四","applyReason":"充值错误","attachmentRefs":[],"contactMobile":"19928382738","custCode":"26041011111","refundAmount":2,"remark":"ssa"}'
```
## 3. 调用结果
直连 business 与走 gateway 返回一致:
```json
{"code":500,"data":null,"msg":"系统异常"}
```
## 4. 后端日志根因
`sw-business-server` 日志显示真实异常为:
```text
java.lang.IllegalArgumentException: 账户预存余额不足
at cn.com.emsoft.sw.business.service.accountingadjust.accountProcess.AccountingAdjustProcessServiceImpl.createPrestorageAction(AccountingAdjustProcessServiceImpl.java:213)
```
对应代码位置:
- `water-backend/sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/accountingadjust/accountProcess/AccountingAdjustProcessServiceImpl.java`
关键逻辑:
- 读取客户与账户
- 将 `deposit == null` 视为 `0`
- 校验 `deposit < refundAmount` 时抛出 `IllegalArgumentException("账户预存余额不足")`
## 5. 数据库核验
开发库(`sw_system`)中当前客户与账户数据:
```sql
select id, code, name, population, address, status, tenant_id
from biz_cust
where deleted = 0 and code = '26041011111';
select id, cust_id, deposit, uncheck_money, overdraft, status, deleted, tenant_id
from biz_account
where cust_id = 67 and deleted = 0;
```
结果:
```text
biz_cust:
67 | 26041011111 | liao | 3 | 11 | 0 | 1
biz_account:
65 | 67 | null | null | 0.0000 | 0 | 0 | 1
```
结论:当前测试客户 `26041011111``biz_account.deposit` 为空,业务侧按 `0` 处理,因此退款金额 `2` 会命中“账户预存余额不足”。
## 6. 结论
本次 `prestorage-submit` 调用链路本身可达,鉴权可用,接口也已命中后端业务逻辑。
失败原因不是网关/路由/权限,而是当前测试数据不满足退款校验条件:
- 客户存在
- 账户存在
- 账户预存余额为空(按 0 处理)
- `refundAmount = 2`,因此提交失败
## 7. 后续建议
二选一:
1. 修正该测试客户的 `biz_account.deposit`,使其大于等于 `2`
2. 改用当前开发库中预存余额充足的客户进行 `prestorage-submit` 联调
附带观察:当前前端收到的是泛化后的 `系统异常`,而非后端真实业务提示 `账户预存余额不足`。如果需要提升联调效率,可后续评估是否将该类参数/业务校验异常以明确业务消息返回前端。

View File

@ -0,0 +1,135 @@
# REV004 price-diff formal-table 已应用到 application-dev 测试库2026-04-17
## 目标库
依据:
- `sw-business/sw-business-server/src/main/resources/application-dev.yaml`
解析结果:
- Host`192.168.10.130`
- Port`5436`
- DB`sw_system`
- User`sw_system`
## 已执行脚本
- `sql/rev004/REV004_price_diff_formal_tables_deploy.sql`
## DDL 执行结果
结果:**PASS**
已确认存在:
- `biz_price_diff_adjust`
- `biz_price_diff_adjust_detail`
- `biz_price_diff_adjust_seq`
- `biz_price_diff_adjust_detail_seq`
已确认幂等重放通过:
- second apply 输出 `already exists, skipping`
- 无重复约束/重复索引异常
## 代码验证
### compile
```bash
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
说明:
- 先顺手修复 develop 基线 compile blocker
- `CustApiImpl.java` 去掉 `updateCustPriceTemplateCode` 上多余 `@Override`
- `CustServiceImpl.java` 去掉 `dept.getCode()` 调用
- 之后串行重跑 compile 成功
- 曾出现一次 `NoSuchFileException ... target/generated-sources/...`,确认为 compile 与 test 并行访问同一 `target/` 目录导致的竞态,不属于业务代码错误
### targeted tests
```bash
mvn -pl sw-business/sw-business-server -Dtest=AccountingAdjustActionServiceImplTest,AccountingAdjustProcessServiceImplTest,AccountingAdjustQueryServiceImplTest,PriceDiffFormalizationServiceTest test
```
结果:**PASS**
- Tests run: 43
- Failures: 0
- Errors: 0
## HTTP smokefresh jar, port 48095
### health
- `GET /actuator/health` -> `{"status":"UP"}`
### submit
- `unsold-price-diff-submit` on charge `992205` -> `REV004-992205-20260417153413`
- `unsold-price-diff-submit` on charge `992206` -> `REV004-992206-20260417153414`
- 返回统一为:
- `objectType = PRICE_DIFF_ADJUST`
- `approvalStatus = PENDING_APPROVAL`
- `resultStatus = PENDING_APPROVAL`
- `writeBackStatus = PENDING`
### get / page
- `GET /admin-api/business/accounting-adjust/get?adjustmentNo=REV004-992205-20260417153413`
- 可返回 formal detail
- `priceDiffAmount=15.50`
- `billAmountBefore=100.00`
- `billAmountAfter=115.50`
- `extendedAmountBefore=100.00`
- `extendedAmountAfter=115.50`
- `GET /admin-api/business/accounting-adjust/page?...objectType=PRICE_DIFF_ADJUST`
- 可返回 2 条 fresh smoke formal-first 记录
- `reasonCodeLabel` 已能解析为字典文本(如 `用户协商` / `定价错误`
### approve / reject
- approve`/admin-api/business/accounting-adjust/approve`
- 返回 `APPROVED / SUCCESS / UPDATED`
- reject`/admin-api/business/accounting-adjust/reject`
- 返回 `REJECTED / FAIL / SKIPPED`
## DB 回读
`biz_price_diff_adjust`
- `REV004-992205-20260417153413 -> APPROVED | UPDATED | SUCCESS`
- `REV004-992206-20260417153414 -> REJECTED | SKIPPED | FAIL`
`biz_price_diff_adjust_detail`
- approve 明细:`SUCCESS | APPROVE_EXECUTE | approve price diff smoke`
- reject 明细:`REJECTED | REJECT | reject price diff smoke`
- approve 样例金额前后值:
- `bill_amount_before=100.00 -> bill_amount_after=115.50`
- `extended_amount_before=100.00 -> extended_amount_after=115.50`
`biz_charge`
- `992205 -> bill_amount=115.5000, extended_amount=115.5000, original_money=115.5000`
- `992206 -> bill_amount=80.0000, extended_amount=80.0000, original_money=80.0000`
## 测试数据清理
smoke 完成后已删除:
- `biz_operat_log / detail`identify_value = `992205`, `992206`
- `biz_price_diff_adjust / detail`
- `biz_charge``992205`, `992206`
- `biz_cust``REV004_PD_SMOKE_A`, `REV004_PD_SMOKE_B`
回读结果:
- `pricediff_main_left=0`
- `pricediff_detail_left=0`
- `operat_log_left=0`
- `charge_left=0`
- `cust_left=0`
## 运行态清理
用于 fresh-jar HTTP smoke 的临时实例:
- port `48095`
已停止,当前无残留 LISTEN 进程。
## 当前结论
本轮 price-diff formal-table 已达到:
1. DDL 可落库且可幂等重放;
2. unsold price-diff submit 能落 pending formal main/detail
3. approve/reject 会同步 formal 状态;
4. detail/page 对 `PRICE_DIFF_ADJUST` 已能返回 formal-first 结果;
5. 账单回写与当前 `applyPriceDiffWriteBack(...)` 口径一致;
6. fresh smoke / cleanup 证据完整。
## 当前仍需收口
- 这批尚未提交 commit / PR
- 如果后续要更贴近原系统 `PM_PRICE_RECORDS / DETAILS` 语义,可继续补:
- `PriceListId`
- `PriceCode`
- `IsLadder`
- `NewFeeId`
- 更细颗粒的 old/new late fee 与账单差额字段来源收口。

View File

@ -0,0 +1,212 @@
# REV004 redink formal-table 已应用到 application-dev 测试库2026-04-17
## 目标库
依据:
- `sw-business/sw-business-server/src/main/resources/application-dev.yaml`
解析结果:
- Host`192.168.10.130`
- Port`5436`
- DB`sw_system`
- User`sw_system`
## 已执行脚本
- `sql/rev004/REV004_redink_formal_tables_deploy.sql`
## DDL 执行结果
结果:**PASS**
已确认存在:
- `biz_redink_record`
- `biz_redink_record_detail`
- `biz_redink_record_seq`
- `biz_redink_record_detail_seq`
已确认幂等重放通过:
- second apply 输出 existing/skip 结果
- 本轮顺手把 sequence 创建方式从 `CREATE SEQUENCE IF NOT EXISTS` 收口为显式 `pg_class` 检查,规避 replay 时 sequence 级重复键异常
## 代码验证
### compile
```bash
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果:**PASS**
### targeted tests
```bash
mvn -pl sw-business/sw-business-server -Dtest=ChargeServiceAccountingAdjustTest,AccountingAdjustQueryServiceImplTest,RedinkFormalizationServiceTest test
```
结果:**PASS**
- Tests run: 34
- Failures: 0
- Errors: 0
## fresh query smokefresh jar, port 48096
### health
- `GET /actuator/health` -> `{"status":"UP"}`
### smoke 方式说明
REDINK_RECORD 当前依赖原交易定位 / bank follow-up 逻辑;本轮先采用:
1. application-dev 手工 seed 一条 redink formal 主表/明细表记录;
2. fresh jar 验证 `get/page` 是否已 formal-first 命中;
3. 不在本轮直接伪造 live bank follow-up 交易。
### seed 记录
- `adjustmentNo = REV004-RI-992305-SEED`
- `chargeId = 992305`
- formal 主表状态:
- `approvalStatus = NOT_REQUIRED`
- `executeStatus = UPDATED`
- `resultStatus = SUCCESS`
- bank follow-up 样例:`BK-992305`
### get / page
- `GET /admin-api/business/accounting-adjust/get?adjustmentNo=REV004-RI-992305-SEED`
- 返回:
- `objectType = REDINK_RECORD`
- `resultStatus = SUCCESS`
- `approvalStatus = NOT_REQUIRED`
- `writeBackStatus = UPDATED`
- `originalTranSeq = T-992305`
- `originalSysTranSeq = SYS-992305`
- detail 中包含:
- `bankTranSeq`
- `redinkAmount`
- `payStateBefore`
- `payStateAfter`
- `GET /admin-api/business/accounting-adjust/page?...objectType=REDINK_RECORD`
- 返回 1 条 formal-first 记录
- `reasonCodeLabel` 已能解析为字典文本(如 `收费错误`
## 当前结论
本轮 redink formal-table 已达到:
1. DDL 可落库且可幂等重放;
2. 结果型 formal-table 主从表已建模;
3. query detail/page 对 `REDINK_RECORD` 已能返回 formal-first
4. compile / targeted tests 通过;
5. fresh jar query smoke 已验证 formal-first 查询链路可用。
## 当前仍未完全覆盖
- 尚未完成“真实 redink 执行成功后自动落 formal 结果”的 live HTTP smoke
- 原因是当前红冲依赖原交易与 bank follow-up 外部链路,需要在下一轮补真实可复现数据后再做完整 execute smoke。
## 测试数据清理
已删除:
- `biz_redink_record / detail`
- `biz_charge`
- `biz_cust`
回读结果:
- `redink_main_left=0`
- `redink_detail_left=0`
- `charge_left=0`
- `cust_left=0`
## 运行态清理
用于 fresh-jar query smoke 的临时实例:
- port `48096`
已停止,当前无残留 LISTEN 进程。
## live execute smoke 阻塞证据2026-04-17 16:50 +08:00
本轮额外尝试了真实 redink 执行链路:
- fresh jar`48097`
- 请求:`POST /admin-api/business/charge/accounting-adjust`
- `objectType = REDINK_RECORD`
- `chargeId = 992306`
- `originalTranSeq = T-REDINK-NOPE`
接口响应:
```json
{"code":500,"data":null,"msg":"系统异常"}
```
从应用日志定位到的精确异常:
- `FeignException$ServiceUnavailable: [503]`
- `Load balancer does not contain an instance for the service business-bank-server`
- 失败位置:`TransactionApi#getTransactionByTranSeq(...)`
结论:
- 当前 live execute smoke 未能完成的直接原因是 **外部依赖 `business-bank-server` 在当前环境无可用实例**
- 这不是 redink formal-table 本身的 DDL / 查询接线问题。
因此本批已完成:
- compile
- targeted tests
- DDL apply / replay
- fresh query smoke
但“真实 redink 执行成功后自动落 formal”的端到端 smoke 仍需在 `business-bank-server` 可用时补跑。
## live execute smoke 成功补证2026-04-17 17:51 +08:00
在本轮额外启动本地 `business-bank-server`dev profile, port `48092`)并向测试库预置原交易后,重新完成了 REDINK_RECORD 的真实端到端执行 smoke。
### 前置
- 本地启动 `business-bank-server`,并成功注册到 Nacos dev`business-bank-server 192.168.9.109:48092 register finished`
- 向 `bk_transaction` seed 原交易:
- `tran_seq = T-REDINK-NOPE`
- `sys_tran_seq = SYS-REDINK-NOPE`
- `tran_type = PAY`
- `status = SUCCESS`
- `contract_no = 992306`
- `amount = 12000`
- 准备已收费营业账:`chargeId = 992306`
### execute 请求
`POST /admin-api/business/charge/accounting-adjust`
```json
{
"chargeId": 992306,
"objectType": "REDINK_RECORD",
"reasonCode": "1",
"reason": "redink execute smoke",
"originalTranSeq": "T-REDINK-NOPE"
}
```
### execute 响应
结果:**PASS**
返回:
- `adjustmentNo = REV004-992306-20260417175109`
- `objectType = REDINK_RECORD`
- `resultStatus = SUCCESS`
- `approvalStatus = NOT_REQUIRED`
- `writeBackStatus = UPDATED`
- `message = 冲正处理成功bank流水号=RV9923062026041717511073C805`
### DB 回读
`biz_redink_record`
- `adjustment_no = REV004-992306-20260417175109`
- `approval_status = NOT_REQUIRED`
- `execute_status = UPDATED`
- `result_status = SUCCESS`
- `bank_tran_seq = RV9923062026041717511073C805`
- `original_tran_seq = T-REDINK-NOPE`
`biz_redink_record_detail`
- `detail_status = SUCCESS`
- `proc_type = EXECUTE`
- `pay_state_before = 1`
- `pay_state_after = 0`
- `redink_amount = 120.00`
`biz_charge`
- `pay_state = 0`
- 支付信息已清空为红冲后的未收费态
`bk_transaction`
- 原交易 `T-REDINK-NOPE` 状态变为 `REVERSED`
- 新增 follow-up
- `tran_seq = RV9923062026041717511073C805`
- `tran_type = PAY_INVALID`
- `status = SUCCESS`
- `original_tran_seq = T-REDINK-NOPE`
### 查询回读
- `GET /admin-api/business/accounting-adjust/get?adjustmentNo=REV004-992306-20260417175109` -> formal-first 返回成功
- `GET /admin-api/business/accounting-adjust/page?...objectType=REDINK_RECORD` -> formal-first 返回成功
说明至此REDINK_RECORD 已补齐“真实执行 -> 自动落 formal -> formal-first 查询”的完整闭环证据。

View File

@ -0,0 +1,224 @@
# REV004 / 分账现状对照摘要2026-04-14
## 1. 目的
本摘要用于把 **旧设计**、**老数据字典**、**当前代码状态** 三者放在一起对“分账SplitAdjust”给出一页式结论回答
- 旧系统/旧设计里的分账到底是什么
- 当前 REV004 设计里把它定位成什么
- 当前后端代码做到哪一步了
- 三者之间的差距到底在哪里
---
## 2. 一句话结论
> **旧系统里的分账是“真正的账单拆分/重分摊业务对象”,有汇总表、明细表和拆分后的结果对象;当前 REV004 设计也把它定义为独立正式对象,但当前后端代码只落到了“分账申请态”,还没有落到“审批通过后真正拆账生成子账单”的执行态。**
---
## 3. 旧设计口径12_REV_Detailed.md
来源:
- `../water-docs/docs/design/02_Detailed_Design/12_REV_Detailed.md`
### 旧设计里怎么定义分账
文档明确把:
- `SplitAdjust`
列为:
- **目标正式业务对象**
- 并且属于:
- **L2 独立业务层**
### 旧设计里的关键语义
文档明确写到:
- `SplitAdjust | 分账调整 | 当前作为费用组成重分摊场景表达 | 支持按水量 / 按费用组成等分摊策略`
并在迁移补充里写到:
- **分账调整汇总 / 明细**
- 承接方式:
- 在线主模型 + 费用重分摊场景
- 需要保留:
- 原分摊结果
- 调整后结果
- 策略类型
- 责任链
### 从旧设计可得的结论
旧设计的分账不是普通字段修改,也不是一条审批备注,而是:
- 有独立业务语义
- 有汇总/明细层
- 有原结果与新结果的前后对照
- 有策略与责任链
---
## 4. 老数据字典口径(营收数据字典.md
来源:
- `../water-docs/docs/design/04_Appendix/Archive/05_Data_Dictionary/营收数据字典.md`
### 老系统真实表结构
#### 4.1 汇总表
- `PM_SEPARATE_RECORDS`
关键字段:
- `Applicant`
- `Mobile`
- `ApplyType`
- `SeparateType`
- `State`
- `Remark`
- `TaskId`
- `StepId`
- `FlowRemark`
- `BusinessType`
#### 4.2 明细表
- `PM_SEPARATE_RECORD_DETAILS`
关键字段:
- `SeparateRecordId`
- `CustId / CustCode / CustName / CustAddress`
- `FeeId`
- `NewFeeId`
- `BillMonth`
- `BillWater / NewBillWater`
- `LateFee / NewLateFee`
- `BillAmount / NewBillAmount`
- `ExtendedAmount / NewExtendedAmount`
- `ItemStr`
- `ProcType / ProcPerson / ProcDate / ProcRemark`
- `State`
### 从老数据字典可得的结论
老系统里的分账已经明显是**执行态对象**,因为它不只是有申请信息,还已经有:
- 原费用对象:`FeeId`
- 新产生对象:`NewFeeId`
- 原水量 / 分账水量
- 原金额 / 新金额
- 原滞纳金 / 新滞纳金
- 费用组成
也就是说,老系统分账不是“申请单”,而是:
> **有申请、有明细、有拆后结果对象的完整业务表族。**
---
## 5. 当前代码状态
来源:
- `sw-business/sw-business-server/src/main/java/.../AccountingAdjustProcessServiceImpl.java`
- `sw-business/sw-business-server/src/main/java/.../ChargeServiceImpl.java`
### 当前入口
当前分账提交入口:
- `POST /admin-api/business/accounting-adjust/unsold-split-submit`
调用路径:
- `AccountingAdjustProcessServiceImpl.createUnsoldSplit(...)`
- 转成统一账务调整:
- `objectType = SPLIT_ADJUST`
- `adjustType = SPLIT`
- 进入 `chargeService.adjustAccounting(...)`
### 当前真正处理逻辑
`ChargeServiceImpl.handleSplitAdjust(...)` 中,只做了:
- `approvalRequired = true`
- `resultStatus = PENDING_APPROVAL`
- `approvalStatus = PENDING_APPROVAL`
- `writeBackStatus = PENDING`
- `message = 账单拆分申请已提交,待审批`
- `needUpdate = false`
### 当前校验逻辑
只校验:
- 原账单必须未收费
- `splitCount >= 2`
- `splitCount <= 12`
- 必须填写原因编码
- 必须填写调整原因
### 从当前代码可得的结论
当前代码实现的是:
- **分账申请态**
没有做到:
- 生成分账主表/明细表
- 生成目标账单
- 回填新账单 ID
- 原账单失效/已拆分标记
- 执行态回看
---
## 6. 三者对照
| 对照维度 | 旧设计 | 老数据字典 | 当前代码 |
|---|---|---|---|
| 是否独立对象 | 是,`SplitAdjust` | 是,汇总表+明细表 | 语义上是,代码上仍挂统一入口 |
| 是否支持按水量 / 按费用组成 | 是 | 是(`SeparateType` | 申请态支持对象类型,但未落执行规则 |
| 是否有汇总表 | 有方向 | 有真实表 | 当前没有真实表落地 |
| 是否有明细表 | 有方向 | 有真实表 | 当前没有真实表落地 |
| 是否有“原对象 -> 新对象”关系 | 有方向 | 有(`FeeId -> NewFeeId` | 没有 |
| 是否有拆前拆后水量/金额 | 有方向 | 有 | 没有执行态数据 |
| 是否只到审批申请 | 否 | 否 | 是 |
| 是否真正生成子账单 | 应该要 | 已有新费用ID表达 | 当前未实现 |
---
## 7. 当前最大的差距
最核心的差距不是“少几个字段”,而是:
### 旧系统 / 旧设计的分账
是:
- **完整业务对象**
- **有结果承接**
- **有拆后对象**
### 当前 REV004 代码的分账
只是:
- **申请态入口**
- **待审批状态表达**
- **统一日志/查询承接**
所以差距本质上是:
> **从“受理态”到“执行态”的整层能力还没有落。**
---
## 8. 为什么会停在这里
结合三者判断,原因可以归纳成:
1. 当前这轮 REV004 后端优先目标是统一入口、状态、日志、查询,不是重建所有独立执行对象。
2. 真正分账执行涉及:
- 分摊规则
- 主表/明细表
- 目标账单生成
- 守恒校验
- 收费/开票承接
3. 因此当前才先落成:
- `SPLIT_ADJUST` 申请态
而没有一步到位落成:
- `SplitAdjust` 执行态。
---
## 9. 最终判断
### 业务真值
分账本质上是:
- **账单拆分 / 重分摊**
- 不是退款
- 不是减免
- 也不只是审批单
### 当前状态
当前 REV004
- 已经把“分账”纳入正式对象语义
- 但后端实现仍停在申请态
### 最适合对外讲的一句话
> 旧系统与旧设计里的分账本来就是“有汇总、有明细、有拆后结果对象”的正式业务对象;当前 REV004 后端只先落了统一申请与审批承接,没有把真正的拆账执行态一起落出来,所以它现在更像“分账申请”,还不是“已执行的分账对象”。
---
## 10. 建议下一步
若要继续推进分账执行态,建议:
1. 以老表结构 + 旧设计为真值来源,先冻结最小执行态模型
2. 先做按水量分账 MVP
3. 再扩按费用组成分账
4. 最后补前端执行态页面与回看能力

View File

@ -0,0 +1,246 @@
# REV004 / 分账执行态后端设计草案2026-04-14
## 1. 目标
在当前“分账申请态”基础上,补齐“审批通过后真正执行拆账”的后端能力,使系统可以:
- 将一笔原始未收费账单拆成多笔目标账单
- 支持两类分账策略:
- 按水量分账
- 按费用组成分账
- 保证金额/水量守恒、状态可追踪、失败可回滚
- 被后续收费、开票、日志、查询完整承接
---
## 2. 当前现状
### 已有
- 统一对象类型:`SPLIT_ADJUST`
- 统一提交入口:`unsold-split-submit`
- 当前结果:`PENDING_APPROVAL`
- 已有原因、审批、日志、查询承接能力
### 缺失
- 审批通过后的执行器
- 分账主表/明细表落库
- 目标账单生成
- 原账单与目标账单关系链
- 按水量/按费用组成的规则明细
- 执行态查询回看
---
## 3. 设计原则
1. **先审批、后执行**:分账执行必须挂在审批通过之后,不在申请提交时直接拆账。
2. **守恒原则**
- 按水量分账:子账单水量之和 = 原账单水量
- 按费用组成分账:子账单金额之和 = 原账单金额
3. **原账单可追溯**:必须保留原账单与所有目标账单关系。
4. **执行幂等**:同一分账单不得重复执行。
5. **失败可回滚**:执行中任一步失败,必须整体回滚。
6. **查询可回看**:日志页/分账页必须能看到申请、审批、执行结果、目标账单明细。
---
## 4. 结果对象建议
### 最终业务真值
建议以:
- **多张目标子账单**
为正式业务真值;
- “多笔待收费结果”只是前台呈现视角。
### 原因
- 文档原始语义就是“由一笔账单分成两笔独立账单信息”
- 后续还要支持分别收费、分别开票、分别承担
- 若没有目标账单实体,后续业务承接会变得模糊
---
## 5. 数据模型草案
### 5.1 主表:`biz_split_adjust`
建议字段:
- `id`
- `split_adjust_no`:分账单号
- `source_charge_id`:原账单 ID
- `split_rule_type`:分账规则类型(`BY_WATER` / `BY_COMPONENT`
- `reason_code`
- `remark`
- `approval_status`
- `execute_status``PENDING / PROCESSING / SUCCESS / FAIL`
- `execute_message`
- `executed_at`
- `accounting_case_id`(如继续挂统一骨架)
- 通用审计字段
### 5.2 明细表:`biz_split_adjust_detail`
建议字段:
- `id`
- `split_adjust_id`
- `seq_no`
- `target_cust_id` / `target_cust_code`(若允许拆给不同客户)
- `target_charge_id`(执行后生成)
- `split_basis`:拆分依据描述
- `split_ratio`
- `split_water`
- `split_amount`
- `component_code`(按费用组成分账时必填)
- `component_amount`
- `status`
- 通用审计字段
### 5.3 与现有 `biz_charge` 的关系
- 原账单:`source_charge_id`
- 子账单:执行后在 `biz_charge` 新增多条记录
- 子账单增加来源追踪字段(建议二选一):
- `source_charge_id`
- 或 `split_adjust_id`
建议至少有一个能让后续查询直接知道:
> 这张账单是由哪次分账生成的。
---
## 6. 执行流程草案
### Phase 1申请提交
接口:`POST /unsold-split-submit`
- 校验未收费、`splitCount`、原因等
- 保存申请主单/明细草稿(如果前端已能提供拆分明细)
- 状态置为 `PENDING_APPROVAL`
> 若当前前端还没有真正提交拆分明细,只是申请头信息,则需在后续补充“审批前明细维护”或“审批时确认明细”能力。
### Phase 2审批通过
触发点:审批系统回调/人工审批通过
- 校验该分账单仍未执行
- 锁定原账单
- 进入执行事务
### Phase 3执行拆账
#### 3.1 按水量分账
- 读取原账单水量、单价/模板/费用构成
- 根据各子项 `split_water` 重新计算子账单金额
- 生成 N 条目标账单
- 校验:
- `sum(split_water) = source.bill_water`
- `sum(target.bill_amount)` 与可接受计算误差范围内守恒
#### 3.2 按费用组成分账
- 读取原账单明细 `biz_charge_detail`
- 按费用项将金额拆入不同子账单
- 汇总生成 N 条目标账单及其明细
- 校验:
- 各费用项总额守恒
- 原账单总金额守恒
### Phase 4收尾
- 原账单标记为:
- 已拆分 / 已失效 / 不可继续收费(建议新增状态或来源标识)
- 分账主单置为 `SUCCESS`
- 明细回填 `target_charge_id`
- 写 operat_log / 业务日志 / 查询投影
### Phase 5失败回滚
- 任一步失败:回滚事务
- 主单置 `FAIL`
- 保留失败原因
- 不产生部分子账单残留
---
## 7. 接口草案
### 7.1 申请接口(保留)
- `POST /unsold-split-submit`
### 7.2 明细查询接口(建议新增)
- `GET /split-adjust-detail?adjustmentNo=...`
- 返回:
- 原账单摘要
- 分账规则类型
- 子项明细
- 目标账单(若已执行)
### 7.3 明细维护接口(建议新增,若前端需要)
- `POST /split-adjust-draft-save`
- 在审批前保存:
- 按水量拆分行
- 按费用组成拆分行
### 7.4 审批通过执行接口(内部)
- `POST /internal/split-adjust/execute`
- 由审批流或业务服务调用,不暴露给前端
### 7.5 查询接口增强(建议)
- `log-detail` / `log-process`
- 增加目标账单摘要
- `unsold-page`
- 原账单若已提交分账且审批中/已执行,要有能力位变化提示
---
## 8. 状态机建议
### 申请主单状态
- `PENDING_APPROVAL`
- `APPROVED_PENDING_EXECUTE`
- `PROCESSING`
- `SUCCESS`
- `FAIL`
- `REVOKED`(如审批前允许撤销)
### 原账单状态建议
原账单不建议简单删除,建议新增可追溯状态:
- `UNPAID`
- `SPLIT_PENDING`
- `SPLIT_DONE`
- `SPLIT_INVALIDATED`
若不想改老字段,可用额外来源标记字段表达。
---
## 9. 与前端配合建议
### 前端最少补充信息
若要真正进入执行态,前端弹窗至少要能提交:
- 分账方式:按水量 / 按费用组成
- 子项列表
- 按水量:每笔 `split_water`
- 按费用组成:每笔目标费用项/金额归属
- 申请人 / 联系电话 / 原因 / 备注
### 前端结果回看
执行态落地后,前端需要新增:
- 原账单 -> 目标账单列表
- 子账单金额/水量/费用项明细
- 分账执行结果与失败原因
---
## 10. 分阶段落地建议
### 第一阶段(最小闭环)
目标:审批通过后真正生成子账单,但先只支持**按水量分账**
- 优先原因:
- 规则相对更直观
- 守恒约束明确
- 更容易先做闭环
### 第二阶段
扩展支持:**按费用组成分账**
- 需要补足 `biz_charge_detail` 级别重分摊能力
### 第三阶段
增强:
- 目标客户维度分账
- 更复杂的规则模板
- 开票/收费联动优化查询
---
## 11. 最终建议
若项目要正式推进“分账执行态”,建议:
1. 先把 **按水量分账** 做成最小执行闭环
2. 明确 `biz_split_adjust` / `biz_split_adjust_detail` 模型
3. 把审批通过后的执行器作为独立服务落地
4. 再补按费用组成的二阶段能力
一句话:
> 不建议继续在当前“统一 adjustAccounting 申请态”里硬塞执行逻辑,而应把 `SplitAdjust` 升级成独立正式业务对象来建设。

View File

@ -0,0 +1,108 @@
# REV004 / split-adjust formalization + dedicated interfaces evidence2026-04-14
## 1. 本轮实现范围
- 保持旧接口兼容:
- `POST /admin-api/business/accounting-adjust/unsold-split-submit`
- `GET /admin-api/business/accounting-adjust/get`
- `GET /admin-api/business/accounting-adjust/log-detail`
- 新增 split 专属接口族:
- `POST /admin-api/business/split-adjust/submit`
- `GET /admin-api/business/split-adjust/page`
- `GET /admin-api/business/split-adjust/detail`
- `GET /admin-api/business/split-adjust/result`
- split 执行真值升级为:
- `splitItems[{seqNo, splitWater}]`
- `splitCount` 作为兼容口径保留,并在旧入口适配阶段转译为 `splitItems`
## 2. 本轮代码落点
### 新增
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/splitadjust/SplitAdjustController.java`
- `.../controller/admin/splitadjust/vo/SplitAdjustSubmitReqVO.java`
- `.../controller/admin/splitadjust/vo/SplitAdjustSubmitRespVO.java`
- `.../controller/admin/splitadjust/vo/SplitAdjustDetailRespVO.java`
- `.../controller/admin/splitadjust/vo/SplitAdjustPageReqVO.java`
- `.../controller/admin/splitadjust/vo/SplitAdjustPageRespVO.java`
- `.../service/splitadjust/SplitAdjustService.java`
- `.../service/splitadjust/SplitAdjustServiceImpl.java`
### 继续增强
- `SplitAdjustFormalizationService`
- `AccountingAdjustActionServiceImpl`
- `AccountingAdjustProcessServiceImpl`
- `AccountingAdjustLogProcessServiceImpl`
- `AccountingAdjustDetailRespVO`
- `AccountingAdjustLogDetailRespVO`
- `ChargeDO`
- `sql/rev004/REV004_accounting_adjustments_ddl.sql`
- `Rev004AccountProcessCanaryQueryIntegrationTest`
- `AccountingAdjustActionServiceImplTest`
- `Rev004AccountProcessLiveDbReadinessTest`
- `sql/rev004/accountprocess/00_reset.sql`
## 3. 关键实现结论
1. 新 split submit 入口已经支持显式 `splitItems[{seqNo, splitWater}]`
2. `splitItems` 成为 formal 明细真值,审批通过执行会按明细水量比例分配子账单金额/水量
3. 旧 `unsold-split-submit` 已兼容接入新 split 主链,可直接传 `splitItems`
4. 新增 split 专属 detail/result/page 接口
5. 旧 `log-detail` 对新 split 专属单据也可 fallback 回看
6. `biz_charge` 已承接最小追溯字段:
- `source_charge_id`
- `split_adjust_id`
- `charge_origin_type`
- `split_status`
## 4. 验证命令与结果
### 4.1 编译
```bash
mvn -pl sw-business/sw-business-server -DskipTests compile
```
结果PASS
### 4.2 targeted tests阶段一
```bash
REV004_IT_DB_URL='jdbc:postgresql://192.168.10.130:5436/sw_system' \
REV004_IT_DB_USERNAME='sw_system' \
REV004_IT_DB_PASSWORD='Em@123456' \
mvn -pl sw-business/sw-business-server \
-Dtest=Rev004AccountProcessCanaryQueryIntegrationTest#splitAdjustSubmit_shouldAcceptSplitItemsAndExposeDedicatedDetailRoute,AccountingAdjustActionServiceImplTest \
test
```
结果PASS
- Tests run: 10
- Failures: 0
- Errors: 0
- Skipped: 0
### 4.3 targeted tests阶段二
```bash
REV004_IT_DB_URL='jdbc:postgresql://192.168.10.130:5436/sw_system' \
REV004_IT_DB_USERNAME='sw_system' \
REV004_IT_DB_PASSWORD='Em@123456' \
mvn -pl sw-business/sw-business-server \
-Dtest=Rev004AccountProcessCanaryQueryIntegrationTest#splitAdjustSubmit_shouldAcceptSplitItemsAndExposeDedicatedDetailRoute+legacyUnsoldSplitSubmit_shouldCompatToSplitItemsFlow+splitAdjustPage_shouldReturnDedicatedRows+splitAdjustResult_shouldReturnSuccessAfterApprove,AccountingAdjustActionServiceImplTest \
test
```
结果PASS
- Tests run: 13
- Failures: 0
- Errors: 0
- Skipped: 0
## 5. 场景覆盖
### 已覆盖
- 新 split submit -> dedicated detail
- 新 split submit -> old log-detail fallback
- 旧 split submit -> new split detail
- dedicated page query
- dedicated result query after approve
- split action service unit testsapprove/reject/write-back
### 仍待补强
- dedicated page + approval status filter 组合查询
- dedicated process 专属接口(如果最终保留)
- split 执行失败/回滚路径的 real-db targeted integration
## 6. 风险与后续
1. 旧接口兼容已接主链,但还需要继续做更完整的批量兼容覆盖
2. 当前仍未进入 BY_COMPONENT / `ItemStr` 真执行
3. 若要最终收口,还应补一轮 architect verification + deslop + regression rerun

View File

@ -0,0 +1,234 @@
# REV004 / 按水量分账最小闭环设计2026-04-14
## 1. 目标
本设计只覆盖 **第一阶段:按水量分账最小闭环**
目标是:
- 审批通过后,能够把一笔未收费原账单按多笔水量拆分,真正生成多张目标子账单;
- 先不做“按费用组成分账”;
- 先把最小可运行闭环打通,再作为后续扩展基础。
---
## 2. 为什么第一阶段先做按水量分账
原因:
1. **规则最清晰**:拆分水量之和必须等于原水量。
2. **业务校验最直接**:原账单 -> 多笔子账单,按水量重算金额,容易理解。
3. **比按费用组成更容易守恒**:先处理总水量、总金额守恒,再逐步扩到费用项粒度。
4. **更适合先做执行态样板**:审批通过、执行、回看、失败回滚等流程都能先沉淀下来。
---
## 3. 最小闭环边界
### 本阶段要做到
- 提交按水量分账申请
- 保存拆分明细(每笔分账水量)
- 审批通过后执行拆账
- 生成多张目标账单
- 原账单标记为已拆分/失效
- 日志与查询可回看
### 本阶段不做
- 按费用组成分账
- 目标客户跨户分账(如无强需求,可先默认同客户)
- 更复杂规则模板
- 开票联动优化
- 自动撤销分账执行结果
---
## 4. 输入输出定义
### 4.1 前端最少输入
按水量分账弹窗至少提交:
- `sourceChargeId`
- `splitItems[]`
- `seqNo`
- `splitWater`
- `reasonCode`
- `remark`
- `applicant`
- `contactMobile`
### 4.2 关键校验
- 原账单必须是未收费
- `splitItems.length >= 2`
- 每笔 `splitWater > 0`
- `sum(splitWater) = source.billWater`
- 必须填写原因
### 4.3 输出结果
申请提交成功后:
- `adjustmentNo`
- `resultStatus = PENDING_APPROVAL`
执行成功后应可回看:
- 原账单摘要
- 目标子账单列表
- 每张子账单的:
- 水量
- 账单金额
- 应收金额
- 违约金(若适用)
---
## 5. 数据模型MVP
### 5.1 主表:`biz_split_adjust`
建议 MVP 字段:
- `id`
- `split_adjust_no`
- `source_charge_id`
- `split_rule_type` = `BY_WATER`
- `reason_code`
- `remark`
- `approval_status`
- `execute_status`
- `execute_message`
- `executed_at`
- `creator / create_time / updater / update_time`
### 5.2 明细表:`biz_split_adjust_detail`
建议 MVP 字段:
- `id`
- `split_adjust_id`
- `seq_no`
- `split_water`
- `target_charge_id`(执行后回填)
- `split_amount`(执行后回填)
- `status`
- `creator / create_time / updater / update_time`
### 5.3 账单表最小扩展建议
`biz_charge` 里增加追溯字段(二选一或组合):
- `source_charge_id`
- `split_adjust_id`
- `charge_origin_type`NORMAL / SPLIT_CHILD
原账单增加状态表达(二选一):
- 新字段标记 `split_status`
- 或现有字段中增加来源/失效标识
MVP 阶段关键不是状态字段优雅,而是:
> 后续能稳定区分“原账单”和“拆分生成的子账单”。
---
## 6. 执行流程MVP
### Step 1申请提交
接口:`POST /unsold-split-submit`
- 校验基本参数
- 保存 `biz_split_adjust`
- 保存 `biz_split_adjust_detail`(只保存水量)
- 返回待审批
### Step 2审批通过
- 触发内部执行器
- 对 `biz_split_adjust` 加幂等校验:只允许执行一次
- 锁定原账单 `source_charge_id`
- 开事务
### Step 3生成目标账单
对每个 `split_adjust_detail`
1. 复制原账单基础信息
2. 将 `bill_water` 改成当前 `split_water`
3. 调用现有计价逻辑重新计算:
- `bill_amount`
- `extended_amount`
- 若适用则重算 `late_fee`
4. 插入新的 `biz_charge` 记录
5. 回填 `target_charge_id / split_amount`
### Step 4处理原账单
- 原账单置为“已拆分,不可继续收费”
- 不直接删除原账单
- 保证历史可追溯
### Step 5收尾
- `biz_split_adjust.execute_status = SUCCESS`
- 写 operat_log / log detail
- 查询面可见结果
### Step 6失败回滚
- 任一子账单生成失败:事务回滚
- 主单置 `FAIL`
- 记录失败原因
- 不允许出现半拆分状态
---
## 7. 重算策略建议
MVP 不建议自己重新写一套计价逻辑,建议:
- 复用已有账单计算能力
- 输入拆分后的水量
- 走现有价格模板/费用计算规则
原因:
- 这样能减少“分账执行”和“普通开账计费”之间的口径偏差
- 也更容易保证后续账单金额解释一致
关键原则:
> 分账只是“改变水量输入并生成多张账单”,不要重造一套新的计费引擎。
---
## 8. 查询回看MVP
建议至少补两个查询面:
### 8.1 分账详情查询
- 原账单摘要
- 分账规则类型BY_WATER
- 每笔拆分水量
- 每笔生成的目标账单 ID / 金额
- 执行状态 / 错误原因
### 8.2 日志页增强
在现有 `log-detail / log-process` 中,增加:
- 原账单 -> 子账单映射摘要
- 执行结果摘要
---
## 9. 测试建议MVP
### 9.1 单测
- 水量守恒校验
- 拆分笔数边界(<2, >12
- 非未收费账单禁止发起
- 执行幂等
### 9.2 集成测试
- 提交按水量分账申请 -> 待审批
- 审批通过 -> 生成 N 张子账单
- 子账单水量之和 = 原账单水量
- 原账单不可继续收费
- 日志页可回看执行结果
- 执行失败整体回滚
### 9.3 验收测试
- 一张账单拆成 2 笔
- 一张账单拆成多笔
- 子账单后续可分别收费/开票(若本期不做全链,可先验证可查询/可识别)
---
## 10. MVP 成功标准
MVP 完成时,应满足:
1. 用户可提交按水量分账申请
2. 审批通过后,系统真正生成多张目标账单
3. 子账单水量之和与原账单守恒
4. 原账单被正确标记,不再继续作为普通未收费账单使用
5. 查询与日志能回看这次分账执行结果
---
## 11. 建议实施顺序
1. 先补 `biz_split_adjust` / `biz_split_adjust_detail`
2. 再补审批通过后的执行器
3. 再补查询回看
4. 最后补前端执行态结果页
一句话:
> 先把“按水量分账”做成审批后真正能拆出子账单的最小闭环,再考虑按费用组成扩展。