Compare commits
8 Commits
ad2fa59232
...
4432a33be7
| Author | SHA1 | Date | |
|---|---|---|---|
| 4432a33be7 | |||
| 9f027b9b7c | |||
| 08550406ad | |||
| 9cbd9a8b75 | |||
| 1823213a0b | |||
| 97c505a01c | |||
| 256b431add | |||
| 3bc4e4184f |
59
docs/evidence/2026-06-10-prestore-test-results.md
Normal file
59
docs/evidence/2026-06-10-prestore-test-results.md
Normal file
@ -0,0 +1,59 @@
|
||||
# 预存余额功能 — 测试与部署结果
|
||||
|
||||
> 2026-06-10 | 预存余额 P0-1~P1-2 功能测试验证
|
||||
|
||||
## 后端编译
|
||||
|
||||
| 项目 | 结果 |
|
||||
|------|------|
|
||||
| `mvn compile -pl sw-business/sw-business-server -am -o` | PASS |
|
||||
| `mvn package -pl sw-business/sw-business-server -am -o -DskipTests` | PASS (147MB jar) |
|
||||
|
||||
## 后端单元测试
|
||||
|
||||
| 测试类 | 状态 | 备注 |
|
||||
|--------|------|------|
|
||||
| ChargeServiceCounterPaymentTest (7 tests) | 7/7 PASS | 修复了 AccountLogContext + CustBillTypeService mock |
|
||||
| 其他已有单元测试 (300+ tests) | 全部 PASS | 仅 2 个已有失败 (CustServiceImplCustomerPageTest, PaymentRecordServiceImplTest) 非本次引入 |
|
||||
|
||||
## 新增测试代码
|
||||
|
||||
| 文件 | 类型 | 编译 |
|
||||
|------|------|------|
|
||||
| `test/.../CounterChargeFullChainIntegrationTest.java` (新增方法) | 集成测试 | PASS |
|
||||
| `test/resources/sql/prestore/01_counter_topup_log_seed.sql` | SQL 种子 | N/A |
|
||||
|
||||
> 集成测试需要 PostgreSQL 环境运行 (`REV004_IT_DB_URL` 等环境变量)。代码已通过编译验证,实际执行待部署环境就绪。
|
||||
|
||||
## 前端
|
||||
|
||||
| 项目 | 结果 |
|
||||
|------|------|
|
||||
| TypeScript 类型检查 (`tsc --noEmit`) | 新文件无新增错误 |
|
||||
| dist 构建 | dist/ 已存在 |
|
||||
| E2E 测试代码 (2 文件) | 已创建,待后端运行后执行 |
|
||||
|
||||
### 新增 E2E 测试
|
||||
|
||||
| 文件 | 覆盖 |
|
||||
|------|------|
|
||||
| `tests/e2e/prestore/counterTopup.e2e.spec.ts` | counterTopup充值流程, 欠费拒绝, counterPreview余额查询 |
|
||||
| `tests/e2e/prestore/prestorageAdjustBpm.e2e.spec.ts` | 预存调整列表, BPM创建, 详情查询 |
|
||||
|
||||
## 部署就绪项
|
||||
|
||||
| 产物 | 路径 |
|
||||
|------|------|
|
||||
| 后端 JAR | `sw-business/sw-business-server/target/sw-business-server.jar` |
|
||||
| 前端 dist | `water-frontend/dist/` |
|
||||
| DDL (PG) | `sql/rev005/REV006_account_log_ddl.sql` |
|
||||
| DDL (MySQL) | `sql/rev005/REV006_account_log_ddl_mysql.sql` |
|
||||
| DDL (MySQL) | `sql/rev005/REV006_cust_bill_type_ddl_mysql.sql` |
|
||||
|
||||
## 待执行项
|
||||
|
||||
1. 部署 PostgreSQL 并执行 DDL
|
||||
2. 启动后端 (`java -jar sw-business-server.jar --spring.profiles.active=local`)
|
||||
3. 启动前端 (`pnpm dev`)
|
||||
4. 运行 Browser 手动冒烟 (按 plan Task 7 清单)
|
||||
5. 运行 Playwright E2E 测试 (`npx playwright test tests/e2e/prestore/`)
|
||||
@ -0,0 +1,137 @@
|
||||
# 柜台结清列表过滤字段对齐修复验证记录
|
||||
|
||||
日期:2026-06-09
|
||||
|
||||
## 问题现象
|
||||
|
||||
`GET /admin-api/business/charge/counter-settle/unsettled-page` 前端传入 `custCode`、`chargeWay` 后,待结清分页结果未按客户编号和收费方式过滤。
|
||||
|
||||
追加核对 `charge` 系列前端接口口径后,又发现:
|
||||
|
||||
- 前端 `CounterUnsettledPageReqVO` 还声明了 `deptId`,后端待结清请求对象未接收,服务层未按站点过滤。
|
||||
- 前端已结清列表传入 `settleNo`,后端 `CounterSettledPageReqVO` 未接收,`SettleRecordMapper#selectSettledPage` 未按结清单号过滤。
|
||||
|
||||
示例参数:
|
||||
|
||||
```text
|
||||
pageNo=1&pageSize=10&custCode=15980151657&cashierId=&chargeWay=
|
||||
```
|
||||
|
||||
## 根因
|
||||
|
||||
- 后端 `CounterUnsettledPageReqVO` 仅定义了 `cashierId`,未定义 `deptId`、`custCode`、`chargeWay`,Spring MVC 绑定查询参数时会忽略这些字段。
|
||||
- `CounterSettleApplicationServiceImpl#queryUnsettledItems` 只按收费员查询待结清支付主单,未继续应用客户编号、收费方式、营业站点过滤。
|
||||
- 后端 `CounterSettledPageReqVO` 未定义 `settleNo`,已结清 Mapper 查询条件也未包含 `settle_no`。
|
||||
|
||||
## 修复范围
|
||||
|
||||
仓库:`../water-backend`
|
||||
|
||||
分支:`develop`
|
||||
|
||||
修复前基线:`86203127e`
|
||||
|
||||
修改文件:
|
||||
|
||||
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/charge/vo/CounterUnsettledPageReqVO.java`
|
||||
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/controller/admin/charge/vo/CounterSettledPageReqVO.java`
|
||||
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/dal/mysql/settlerecord/SettleRecordMapper.java`
|
||||
- `sw-business/sw-business-server/src/main/java/cn/com/emsoft/sw/business/service/countersettle/CounterSettleApplicationServiceImpl.java`
|
||||
- `sw-business/sw-business-server/src/test/java/cn/com/emsoft/sw/business/service/countersettle/CounterSettleApplicationServiceImplTest.java`
|
||||
- `sw-business/sw-business-server/src/test/java/cn/com/emsoft/sw/business/integration/countersettle/CounterSettleIntegrationTest.java`
|
||||
|
||||
## 修复内容
|
||||
|
||||
- `CounterUnsettledPageReqVO` 新增 `deptId`、`custCode`、`chargeWay` 查询字段。
|
||||
- 待结清列表在按收费员取得候选支付主单后,继续按 `custCode` 精确匹配、按 `chargeWay` 精确匹配、按账单 `deptId` 精确匹配。
|
||||
- 待结清导出复用同一查询逻辑,因此同步支持相同过滤条件。
|
||||
- `CounterSettledPageReqVO` 新增 `settleNo` 查询字段。
|
||||
- `SettleRecordMapper#selectSettledPage` 新增 `settleNo` 精确过滤,已结清导出复用同一查询逻辑。
|
||||
- 增加服务层单测覆盖 `custCode + chargeWay + deptId` 过滤、`settleNo` 参数传递和 Mapper 源码契约。
|
||||
- 增加接口集成测试断言,覆盖未结账匹配、不匹配客户编号、不匹配收费方式、不匹配站点,以及已结账匹配/不匹配结清单号;该集成测试受 `REV004_IT_DB_URL` 环境变量控制。
|
||||
|
||||
## 验证命令与结果
|
||||
|
||||
### RED 验证
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -Dtest=CounterSettleApplicationServiceImplTest#getUnsettledPage_shouldFilterByCustCodeAndChargeWay test
|
||||
```
|
||||
|
||||
结果:失败,符合预期。
|
||||
|
||||
- 失败点:`CounterUnsettledPageReqVO` 缺少 `setCustCode(String)`、`setChargeWay(int)`。
|
||||
- 说明:证明后端请求对象没有承接过滤参数。
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -Dtest=CounterSettleApplicationServiceImplTest#getSettledPage_shouldUseMapperPagedResult+getUnsettledPage_shouldFilterByCustCodeChargeWayAndDeptId test
|
||||
```
|
||||
|
||||
结果:失败,符合预期。
|
||||
|
||||
- 失败点:`CounterSettledPageReqVO` 缺少 `setSettleNo(String)` / `getSettleNo()`,`CounterUnsettledPageReqVO` 缺少 `setDeptId(long)`。
|
||||
- 说明:证明后端请求对象未完整对齐前端 `charge` 系列列表筛选字段。
|
||||
|
||||
### 服务层回归
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -Dtest=CounterSettleApplicationServiceImplTest#getUnsettledPage_shouldFilterByCustCodeAndChargeWay test
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Surefire 汇总:`Tests run: 1, Failures: 0, Errors: 0, Skipped: 0`
|
||||
- Maven 结果:`BUILD SUCCESS`
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -Dtest=CounterSettleApplicationServiceImplTest#getSettledPage_shouldUseMapperPagedResult+getUnsettledPage_shouldFilterByCustCodeChargeWayAndDeptId test
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Surefire 汇总:`Tests run: 2, Failures: 0, Errors: 0, Skipped: 0`
|
||||
- Maven 结果:`BUILD SUCCESS`
|
||||
|
||||
### 相关服务单测
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -Dtest=CounterSettleApplicationServiceImplTest test
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Surefire 汇总:`Tests run: 22, Failures: 0, Errors: 0, Skipped: 0`
|
||||
- Maven 结果:`BUILD SUCCESS`
|
||||
|
||||
### 编译验证
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -DskipTests compile
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Maven 结果:`BUILD SUCCESS`
|
||||
|
||||
### 接口集成测试
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/water-backend
|
||||
mvn -pl sw-business/sw-business-server -Dtest=CounterSettleIntegrationTest#counterSettleApis_shouldSupportUnsettledConfirmSettledAndDetails test
|
||||
```
|
||||
|
||||
结果:未执行,不作为通过项。
|
||||
|
||||
- Surefire 汇总:`Tests run: 1, Failures: 0, Errors: 0, Skipped: 1`
|
||||
- 原因:`CounterSettleIntegrationTest` 标注 `@EnabledIfEnvironmentVariable(named = "REV004_IT_DB_URL", matches = ".+")`,当前环境未提供该变量。
|
||||
|
||||
## 备注
|
||||
|
||||
- 本次验证期间存在既有 Maven model warning、Mockito dynamic-agent warning、`MockBean` deprecation warning,未导致编译或已执行单测失败。
|
||||
- `cashierId` 为空时仍沿用既有逻辑:优先使用当前登录用户 ID 作为收费员过滤值。
|
||||
@ -0,0 +1,63 @@
|
||||
# REV004 accountProcess Real Wiring Cleanup Evidence (2026-06-05)
|
||||
|
||||
## Scope
|
||||
|
||||
- Frontend repository: `/Volumes/Dpan/github/water-workspace/water-frontend`
|
||||
- Pages/components:
|
||||
- `src/views/accountProcess/accountLog/index.vue`
|
||||
- `src/views/accountProcess/accountLog/components/RefundForm.vue`
|
||||
- `src/views/accountProcess/accountLog/components/TransferPrestoreForm.vue`
|
||||
- `src/views/accountProcess/soldAdjustment/index.vue`
|
||||
- `src/views/accountProcess/unsoldAdjustment/components/UnsoldAdjustmentForm.vue`
|
||||
- `src/views/accountProcess/unsoldAdjustment/components/PriceAdjustmentForm.vue`
|
||||
- API:
|
||||
- `src/api/accountProcess/accountLog/index.ts`
|
||||
|
||||
## Interface Basis
|
||||
|
||||
- `GET /business/accounting-adjust/log-page`
|
||||
- `GET /business/accounting-adjust/log-stat`
|
||||
- `GET /business/accounting-adjust/log-process`
|
||||
- `GET /business/accounting-adjust/log-attachments`
|
||||
- `GET /business/accounting-adjust/log-export`
|
||||
- `POST /business/accounting-adjust/log-refund`
|
||||
- `POST /business/accounting-adjust/log-prestorage`
|
||||
- `POST /business/accounting-adjust/log-revoke`
|
||||
|
||||
Basis documents:
|
||||
|
||||
- `docs/evidence/rev004-accountlog-action-wiring-notes-2026-04-13.md`
|
||||
- `docs/evidence/rev004-accountprocess-interface-truth-matrix-2026-04-13.md`
|
||||
|
||||
## Verification
|
||||
|
||||
| Command | Result |
|
||||
| --- | --- |
|
||||
| `node --test tests/rev004/accountProcessRealWiring.test.mjs` | PASS (7/7) |
|
||||
| `node --test tests/rev006/unsoldAdjustmentSubmitPayload.test.mjs tests/rev006/soldAdjustmentSubmit.test.mjs tests/rev006/badDebtBatchSubmitContext.test.mjs` | PASS (29/29) |
|
||||
| `pnpm build:dev` | PASS |
|
||||
|
||||
## Commits
|
||||
|
||||
```
|
||||
5d00f526 test(accountprocess): cover remaining mock wiring gaps
|
||||
e001f9c0 feat(accountprocess): add account log action APIs
|
||||
b133fcc5 feat(accountprocess): wire account log refund action
|
||||
bf763907 feat(accountprocess): wire account log prestore action
|
||||
a48bb23c feat(accountprocess): wire account log page actions
|
||||
012fba78 fix(accountprocess): use customer id in sold detail navigation
|
||||
ebc7bfc3 fix(accountprocess): remove unsold adjustment demo defaults
|
||||
7b10e414 fix(accountprocess): remove hardcoded price adjustment selectors
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
- Account log secondary actions no longer show success without a backend call.
|
||||
- Account log export, process, attachments, and revoke actions call formal account log APIs.
|
||||
- Account log and sold adjustment customer links use the selected row `custId`.
|
||||
- Unsold adjustment no longer seeds `111` / `11.1` / `0.9` demo values.
|
||||
- Price adjustment no longer exposes hardcoded `112` / `测试2` options.
|
||||
|
||||
## Remaining Follow-up
|
||||
|
||||
- `src/views/accountProcess/index.vue` remains a static REV-004 workspace/handoff dashboard backed by `rev004.data.ts`; this is not converted to a live dashboard in this cleanup.
|
||||
101
docs/evidence/revenue-bugfix-clear-scope-2026-06-08.md
Normal file
101
docs/evidence/revenue-bugfix-clear-scope-2026-06-08.md
Normal file
@ -0,0 +1,101 @@
|
||||
# 营收明确缺陷第一批修复验证记录
|
||||
|
||||
日期:2026-06-08
|
||||
|
||||
## 修复范围
|
||||
|
||||
- #78 水价调整失败后重试闭环
|
||||
- #39 柜台预存缴费进入结账
|
||||
- #50 柜台结账收费员筛选
|
||||
- #53 预存抵扣校验
|
||||
- #58/#59 柜台红冲记录查询
|
||||
- #69/#76 待审批账务调整文案
|
||||
|
||||
## 后端基线
|
||||
|
||||
- 仓库:water-backend
|
||||
- Worktree:backend-revenue-bugfix-clear-scope
|
||||
- 提交:`ba136759b1925789cb0adc18105d00d6928add59`
|
||||
|
||||
## 前端基线
|
||||
|
||||
- 仓库:water-frontend
|
||||
- Worktree:frontend-revenue-bugfix-clear-scope
|
||||
- 提交:`5f7ad7754473541483b26efa324419eb7a5d1a3b`
|
||||
|
||||
## 验证命令与结果
|
||||
|
||||
### 后端 targeted tests
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/worktrees/backend-revenue-bugfix-clear-scope
|
||||
mvn -pl sw-business/sw-business-server -Dtest=PriceTemplateServiceImplTest,PriceTemplateAdjustmentLockRedisDAOTest,CounterSettleApplicationServiceImplTest,ChargeServiceImplCounterPrepayTest test
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Surefire 汇总:`Tests run: 26, Failures: 0, Errors: 0, Skipped: 0`
|
||||
- Maven 结果:`BUILD SUCCESS`
|
||||
- 备注:执行期间存在既有 Maven model warning、Mockito dynamic-agent warning;`PriceTemplateServiceImplTest` 中有一段业务代码捕获后记录的 NPE 栈日志,但测试结果为 0 failures / 0 errors。
|
||||
|
||||
### 后端 compile
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/worktrees/backend-revenue-bugfix-clear-scope
|
||||
mvn -pl sw-business/sw-business-server -DskipTests compile
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Maven 结果:`BUILD SUCCESS`
|
||||
|
||||
### 前端 contract test
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/worktrees/frontend-revenue-bugfix-clear-scope
|
||||
node --test tests/revenue-bugs/revenueBugfixClearScope.contract.test.mjs
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Node test 汇总:`tests 5`, `pass 5`, `fail 0`
|
||||
|
||||
### 前端 settings contract regression
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/worktrees/frontend-revenue-bugfix-clear-scope
|
||||
node --test tests/settings/priceTemplateAdjustmentErrorHandling.test.mjs
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- Node test 汇总:`tests 3`, `pass 3`, `fail 0`
|
||||
|
||||
### 前端 type check
|
||||
|
||||
```bash
|
||||
pnpm ts:check
|
||||
```
|
||||
|
||||
结果:未完成,不作为通过项。
|
||||
|
||||
- 首次执行长时间无诊断输出后以 `[ELIFECYCLE] Command failed.` 退出。
|
||||
- 随后按用户明确指令停止继续运行 `vue-tsc` / `pnpm ts:check`。
|
||||
- 已终止残留 `vue-tsc` 进程。
|
||||
|
||||
### 前端 build
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/worktrees/frontend-revenue-bugfix-clear-scope
|
||||
pnpm build:dev
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
- 输出:`Build successful. Please see dist directory`
|
||||
- 备注:构建期间存在既有 Vite CJS deprecation warning、SVG icon symbolId warning、Rollup PURE annotation warning。
|
||||
|
||||
## 备注
|
||||
|
||||
- 前端 worktree 中存在未跟踪 `test-results/*.png` 截图产物,本次未提交。
|
||||
- 本轮未处理 #70 和 #9。#70 需抓包确认提交字段;#9 需产品确认抄表状态规则。
|
||||
@ -0,0 +1,51 @@
|
||||
# 营收明确缺陷第一批前端修复验证记录
|
||||
|
||||
日期:2026-06-08
|
||||
|
||||
## 范围
|
||||
|
||||
本记录对应 `docs/superpowers/plans/2026-06-08-revenue-bugfix-clear-scope.md` 中前端 Task 5 至 Task 8:
|
||||
|
||||
- `#69/#76` 未销分账、呆坏账、价差、违约金减免提交后状态提示
|
||||
- `#78` 水价调整失败后重试闭环
|
||||
- `#58/#59` 柜台红冲记录页面接口与查询语义
|
||||
- `#39/#53` 柜台结账预存充值行展示、柜台收费预存抵扣为 0 的确认保护
|
||||
|
||||
## 前端基线
|
||||
|
||||
- 仓库:`water-frontend`
|
||||
- Worktree:`/Volumes/Dpan/github/water-workspace/worktrees/frontend-revenue-bugfix-clear-scope`
|
||||
- 分支:`frontend-revenue-bugfix-clear-scope`
|
||||
- 基础提交:`2a13e63e941e0a990f025844979847b3196effa9`
|
||||
- 状态:前端修复已在 worktree 中实现,尚未提交
|
||||
|
||||
## 验证命令
|
||||
|
||||
```bash
|
||||
cd /Volumes/Dpan/github/water-workspace/worktrees/frontend-revenue-bugfix-clear-scope
|
||||
node --test tests/revenue-bugs/revenueBugfixClearScope.contract.test.mjs
|
||||
pnpm dev --host 0.0.0.0
|
||||
```
|
||||
|
||||
## 验证结果
|
||||
|
||||
- 前端合约测试:通过,5 项通过、0 项失败。
|
||||
- Playwright 登录 smoke:通过。使用默认租户 `福建水投集团`、用户 `admin` 登录到 `http://localhost:18080/home/index`。
|
||||
- Playwright 页面 smoke:
|
||||
- `/operatingCharges/redReversalRecord`:页面可打开,查询区和表格已显示 `收费员`、`红冲时间`、`红冲金额`、`红冲原因` 等柜台红冲语义字段。
|
||||
- `/operatingCharges/counterCheckout`:页面可打开,未结账表中空收费单号显示为 `--`。
|
||||
- `/operatingCharges/counterCharging`:页面可打开。使用现有客户 `20260512111` 验证“预存抵扣金额为 0”确认弹窗出现,且未调用 `/business/charge/update`,未提交收费。
|
||||
- `/accountProcess/unsoldAdjustment`:页面可打开。
|
||||
- `/settings/price/priceTemplate`:页面可打开,显示 `开始调价`。
|
||||
- 后端接口口径核对:
|
||||
- 远端接口 `/admin-api/business/charge/counter-settle/red-flush-record-page` 返回业务 `code=404`,提示 `请求地址不存在:admin-api/business/charge/counter-settle/red-flush-record-page`。
|
||||
- 本地后端 worktree `backend-revenue-bugfix-clear-scope` 的 `ChargeController` 当前也未提供 `/counter-settle/red-flush-record-page` 和 `/counter-settle/red-flush-record-export`,与前端 Task 7 口径未闭合。
|
||||
- 预存抵扣后端兜底校验闭合:`ChargeServiceImpl` 校验抵扣金额非负且不超过应收金额,`AccountService.decreaseDeposit()` 校验账户预存余额不足并抛错。
|
||||
- `typecheck`:未执行完成。按用户要求停止并不再执行 typecheck。
|
||||
- `build`:未执行。
|
||||
|
||||
## 备注
|
||||
|
||||
依赖安装采用 `pnpm install`。安装过程中 pnpm 11 提示 `@carbon/icons` 构建脚本未批准;该临时配置改动未纳入本次业务修复。
|
||||
|
||||
Playwright 运行时按需安装了 Chromium 单浏览器。截图保存在前端 worktree 的 `test-results/` 目录下。
|
||||
1688
docs/superpowers/plans/2026-06-08-revenue-bugfix-clear-scope.md
Normal file
1688
docs/superpowers/plans/2026-06-08-revenue-bugfix-clear-scope.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,168 @@
|
||||
# 营收明确缺陷第一批修复设计
|
||||
|
||||
日期:2026-06-08
|
||||
|
||||
## 背景
|
||||
|
||||
本设计用于收敛当前营收缺陷中代码证据最明确、可闭环验收的一批问题。前期排查表明,部分缺陷并非单纯后端写库失败,而是前后端接口契约、页面状态文案、查询语义和锁恢复流程不一致导致用户认为“成功但未生效”或“查不到记录”。
|
||||
|
||||
本轮不改变账务调整审批规则,不把待审批动作改成即时落账;目标是让系统行为与用户提示一致,并补齐明确漏查和重试闭环。
|
||||
|
||||
## 修复范围
|
||||
|
||||
本轮纳入以下缺陷:
|
||||
|
||||
- `#78` 水价调整:执行报错后,用户不应只能关闭菜单从头开始。
|
||||
- `#39` 柜台结账:柜台预存缴费记录应能进入待结清并完成结账。
|
||||
- `#50` 柜台结账:收费员筛选不应被后端无条件覆盖为当前登录用户。
|
||||
- `#53` 柜台收费:预存抵扣金额需要前后端契约保护和回归验证。
|
||||
- `#58/#59` 红冲记录:柜台红冲后应能在红冲记录页按红冲时间查到。
|
||||
- `#69/#76` 未销分账、呆坏账:前端应准确表达“申请已提交,待审批/待回写”,不得提示为已生效。
|
||||
|
||||
以下缺陷不进入本轮实现,仅保留后续复现或产品确认:
|
||||
|
||||
- `#70` 未销调整提示成功但账单未变:现有后端金额/水量调整路径会写回,需要先抓请求体确认字段和值。
|
||||
- `#9` 抄表状态修改无影响:需要产品确认状态配置影响已生成任务还是仅影响后续任务。
|
||||
|
||||
## 设计原则
|
||||
|
||||
1. 保持最小闭环,不重构完整账务调整体系。
|
||||
2. 保留现有审批流语义,修正文案和状态展示,不把待审批改为立即落账。
|
||||
3. 查询接口按业务语义返回数据,页面筛选字段与后端字段一致。
|
||||
4. 后端对关键金额和状态做兜底校验,前端负责交互提示和用户确认。
|
||||
5. 所有修改需要有最小单测、前端合约测试或页面 smoke 覆盖。
|
||||
|
||||
## 后端设计
|
||||
|
||||
### 水价调整锁恢复
|
||||
|
||||
`PriceTemplateServiceImpl.updatePriceTemplate()` 继续保持执行完成后释放调价锁的总体策略,但失败路径需要让前端能够明确恢复:
|
||||
|
||||
- 后端异常响应保持业务错误信息可读。
|
||||
- 前端失败后重新进入 `startAdjustment()` 流程获取新锁。
|
||||
- `PriceTemplateAdjustmentLockRedisDAO.refreshLock()` 不再采用 `forceUnlock()` 后重新 `tryLock()` 的刷新模式,改为安全续期,避免刷新瞬间锁被其他用户抢占。
|
||||
|
||||
### 柜台预存缴费进入结账
|
||||
|
||||
`PaymentRecordMapper.selectCounterUnsettledRecords()` 从仅查询 `CHARGE_PAYMENT` 扩展为同时包含 `DEPOSIT_TOPUP`:
|
||||
|
||||
- `CHARGE_PAYMENT` 表示账单收费记录。
|
||||
- `DEPOSIT_TOPUP` 表示柜台预存充值记录。
|
||||
|
||||
`CounterSettleApplicationServiceImpl.confirm()` 需要支持预存充值记录无营业账 ID:
|
||||
|
||||
- 结账总金额仍以 `PaymentRecord.paymentAmount` 汇总。
|
||||
- 写入结账明细时,`chargeId`、`billMonth` 可为空。
|
||||
- `chargeMapper.markCounterSettled()` 只处理真实账单收费记录对应的 `chargeIds`。
|
||||
|
||||
### 收费员筛选
|
||||
|
||||
柜台结账查询的收费员解析规则改为:
|
||||
|
||||
- 请求 `cashierId` 为空时,默认使用当前登录用户。
|
||||
- 请求 `cashierId` 非空时,使用请求值查询。
|
||||
- 如后续接入完整数据权限,可在此基础上限制普通用户只能查自己、管理员可查指定收费员。本轮先不让后端无条件覆盖前端筛选值。
|
||||
|
||||
### 预存抵扣校验
|
||||
|
||||
柜台收费继续由前端传入 `prepayDeductAmount`:
|
||||
|
||||
- 后端校验抵扣金额不得小于 0。
|
||||
- 抵扣金额不得超过账单应收金额。
|
||||
- 抵扣金额不得超过账户预存余额。
|
||||
- 抵扣金额大于 0 时扣减账户余额,并在支付记录 `extJson` 中保留 `prepayDeductAmount`。
|
||||
|
||||
本轮不启用后端自动计算抵扣金额,避免改变用户输入语义。
|
||||
|
||||
### 柜台红冲记录查询
|
||||
|
||||
红冲记录页应基于柜台结账红冲链路展示,而不是复用账务调整日志:
|
||||
|
||||
- 查询来源为 `settle_record`、`settle_record_detail`、`payment_record` 的柜台红冲结果。
|
||||
- 默认包含部分红冲和全部红冲状态。
|
||||
- 日期筛选使用红冲时间 `reversedTime`,而不是账务日志的创建时间或处理时间。
|
||||
- 返回字段至少包含结账单号、收费员、客户、红冲金额、红冲时间、红冲原因。
|
||||
|
||||
## 前端设计
|
||||
|
||||
### 水价调整失败恢复
|
||||
|
||||
水价调整提交失败后,前端不再只把页面退出调整态。推荐交互:
|
||||
|
||||
1. 显示调价失败原因。
|
||||
2. 自动调用 `startAdjustment()` 尝试重新获取锁。
|
||||
3. 重新获取成功时保留当前页面数据,提示用户可继续修正后提交。
|
||||
4. 重新获取失败时提示锁被占用或已过期,并引导用户重新开始调价。
|
||||
|
||||
### 待审批动作状态文案
|
||||
|
||||
未销分账、呆坏账、价差调整、违约金减免等提交后,根据响应状态显示文案:
|
||||
|
||||
- `approvalRequired=true` 或 `resultStatus=PENDING_APPROVAL`:显示“申请已提交,待审批”。
|
||||
- `writeBackStatus=PENDING`:显示“待回写”或“待执行”,不刷新为已生效。
|
||||
- `resultStatus=SUCCESS` 且 `writeBackStatus=UPDATED`:显示“处理完成”。
|
||||
|
||||
页面不得仅用“提交成功”表达所有结果。
|
||||
|
||||
### 柜台结账页面
|
||||
|
||||
未结账列表需要正常展示预存充值记录:
|
||||
|
||||
- 无 `chargeId`、`billMonth` 时显示 `--`。
|
||||
- 客户、收费员、金额、缴费时间正常展示。
|
||||
- 结账确认汇总包含预存充值金额。
|
||||
|
||||
收费员筛选继续保留,前端传入的 `cashierId` 应与后端查询语义一致。
|
||||
|
||||
### 红冲记录页面
|
||||
|
||||
红冲记录页面改为柜台红冲记录视图:
|
||||
|
||||
- 查询接口改为柜台红冲记录接口。
|
||||
- 日期筛选标签改为“红冲时间”。
|
||||
- 参数使用 `beginReversedTime`、`endReversedTime`。
|
||||
- 列表展示柜台红冲相关字段,不再按账务调整日志字段组织。
|
||||
|
||||
### 预存抵扣交互
|
||||
|
||||
柜台收费页面保留当前按选中账单分摊 `prepayDeductAmount` 的逻辑,并补充交互保护:
|
||||
|
||||
- 抵扣金额不得超过预存余额。
|
||||
- 抵扣金额不得超过选中账单应收合计。
|
||||
- 用户开启预存抵扣但计算抵扣为 0 时,提交前给出明确提示或确认。
|
||||
|
||||
## 测试设计
|
||||
|
||||
### 后端测试
|
||||
|
||||
- 水价调整:覆盖失败后前端可重新开始调价;覆盖刷新锁不释放抢占。
|
||||
- 柜台结账:覆盖 `CHARGE_PAYMENT` 和 `DEPOSIT_TOPUP` 都进入未结账;覆盖预存记录结账时不要求 `chargeId`。
|
||||
- 收费员筛选:覆盖请求 `cashierId` 非空时后端按请求值查询。
|
||||
- 预存抵扣:覆盖正常抵扣、余额不足、非法金额。
|
||||
- 红冲记录:覆盖红冲状态默认可查,按 `reversedTime` 范围筛选。
|
||||
|
||||
### 前端测试
|
||||
|
||||
- 水价调整提交失败后重新获取锁或展示重获锁失败提示。
|
||||
- 分账和呆坏账返回待审批时提示“申请已提交,待审批”。
|
||||
- 柜台结账未结账列表能展示预存充值记录。
|
||||
- 红冲记录页调用柜台红冲记录接口,并按红冲时间传参。
|
||||
- 预存抵扣开启但抵扣金额为 0 时出现确认或提示。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 用户在水价调整报错后无需关闭菜单即可继续修正并重新提交。
|
||||
2. 柜台预存缴费能在柜台结账待结清列表中查询并完成结账。
|
||||
3. 柜台结账收费员筛选不再无条件固定为当前登录用户。
|
||||
4. 柜台红冲成功后,红冲记录页可按红冲时间查询到记录。
|
||||
5. 分账、呆坏账等待审批动作不再被前端表达为已生效。
|
||||
6. 预存抵扣金额写入支付记录并扣减账户余额,非法金额有明确错误。
|
||||
|
||||
## 实施边界
|
||||
|
||||
本设计不包含以下内容:
|
||||
|
||||
- 不重构完整 REV004 账务调整状态机。
|
||||
- 不新增完整 BPM 审批能力。
|
||||
- 不修改呆坏账、分账从待审批到已执行的业务规则。
|
||||
- 不处理未复现的 `#70` 和产品规则未确认的 `#9`。
|
||||
140
docs/superpowers/specs/2026-06-12-分账连续阶梯重算设计.md
Normal file
140
docs/superpowers/specs/2026-06-12-分账连续阶梯重算设计.md
Normal file
@ -0,0 +1,140 @@
|
||||
# 分账连续阶梯重算设计
|
||||
|
||||
> 2026-06-12 | 将按水量分账从"比例均摊"改为"连续阶梯重算"
|
||||
|
||||
---
|
||||
|
||||
## 一、目标
|
||||
|
||||
按水量分账(splitRuleType=COUNT)的计费方式从比例均摊改为连续阶梯重算,实现:
|
||||
|
||||
- 总水费 = 子账单水费之和,与直接算总水量结果一致
|
||||
- 第一笔子账单从第一阶梯开始计费,后续子账单接着前一笔的累计水量继续计算
|
||||
- 原账单的其他费用(污水、垃圾等)暂按比例均摊
|
||||
|
||||
---
|
||||
|
||||
## 二、改动范围
|
||||
|
||||
**后端改动(3 个文件):**
|
||||
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `AccountingAdjustActionServiceImpl` | 重写 `createSplitChildren()` |
|
||||
| `PriceDiffPreviewService` | 新增 `recalculate()` 重载,接受自定义水量和累计起始量 |
|
||||
| `PriceTemplateService` + impl | 新增 `getPriceTemplateByCode(snapCode, templateCode)` 重载 |
|
||||
|
||||
**不改动的:**
|
||||
- Controller、VO、数据库
|
||||
- `cloneChargeDetailForSplit`(费用明细克隆保持现有比例逻辑)
|
||||
- `createSplitChildrenByFeeComp`(按费用组成分账不动)
|
||||
|
||||
---
|
||||
|
||||
## 三、数据流
|
||||
|
||||
```
|
||||
applySplitWriteBack()
|
||||
├── markParentSplit() [不变]
|
||||
│
|
||||
├── createSplitChildren() [改造]
|
||||
│ ├── getPriceTemplateByCode(snap, code) → 原账单当时的水价模板
|
||||
│ ├── charge.getIsLadder() → 阶梯开关
|
||||
│ │
|
||||
│ ├── 逐笔重算 (accumulated 从 0 开始):
|
||||
│ │ ├── recalculate(template, water, accumulated, isLadder, true)
|
||||
│ │ │ → Map<costCode, amount>
|
||||
│ │ ├── setFees(child, feeMap) → 设各费用字段
|
||||
│ │ └── accumulated += water
|
||||
│ │
|
||||
│ └── 返回 children
|
||||
│
|
||||
└── cloneChargeDetailForSplit() [不变,比例复制]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、新增方法签名
|
||||
|
||||
### 4.1 PriceDiffPreviewService.recalculate 重载
|
||||
|
||||
```java
|
||||
/**
|
||||
* 用指定水价模板 + 指定水量 + 累计起始量重算各项费用
|
||||
*
|
||||
* @param template 水价模板
|
||||
* @param billWater 本次水量
|
||||
* @param accumulatedWater 累计起始水量(前面子账单已用的水量)
|
||||
* @param isLadder 是否阶梯计费
|
||||
* @param calculateGarbageFee 是否计算垃圾费
|
||||
* @return costCode → amount
|
||||
*/
|
||||
public Map<String, BigDecimal> recalculate(
|
||||
PriceTemplateDO template,
|
||||
BigDecimal billWater,
|
||||
BigDecimal accumulatedWater,
|
||||
Boolean isLadder,
|
||||
Boolean calculateGarbageFee
|
||||
)
|
||||
```
|
||||
|
||||
实现逻辑:从现有 `recalculate(ChargeDO, PriceTemplateDO, Boolean, Boolean)` 提取核心计算段,用水量参数 `accumulatedWater + billWater` 替代 `charge.getBillWater()`,阶梯判断基于累计量而非单次水量。
|
||||
|
||||
### 4.2 PriceTemplateService.getPriceTemplateByCode 重载
|
||||
|
||||
```java
|
||||
/**
|
||||
* 按快照编号和模板代码查询水价模板
|
||||
* @param snapCode 调价快照编号
|
||||
* @param templateCode 模板代码
|
||||
*/
|
||||
PriceTemplateDO getPriceTemplateByCode(String snapCode, String templateCode);
|
||||
```
|
||||
|
||||
实现:`priceTemplateMapper.selectOne(adjustmentSnapCode, snapCode, code, templateCode)`
|
||||
|
||||
---
|
||||
|
||||
## 五、createSplitChildren 改造
|
||||
|
||||
### 改造前(比例均摊)
|
||||
|
||||
```java
|
||||
List<BigDecimal> ratios = allocateByWaterRatio(billWaters, charge.getBillWater());
|
||||
List<BigDecimal> waterFees = allocateByRatio(charge.getWaterFee(), ratios, 2);
|
||||
// ... 所有费用项按同一比例分
|
||||
```
|
||||
|
||||
### 改造后(连续阶梯重算)
|
||||
|
||||
```java
|
||||
PriceTemplateDO template = priceTemplateService.getPriceTemplateByCode(
|
||||
charge.getAdjustmentSnapCode(), charge.getPriceTemplateCode());
|
||||
|
||||
Boolean isLadder = charge.getIsLadder();
|
||||
BigDecimal accumulated = BigDecimal.ZERO;
|
||||
|
||||
for (BigDecimal water : billWaters) {
|
||||
Map<String, BigDecimal> feeMap = priceDiffPreviewService.recalculate(
|
||||
template, water, accumulated, isLadder, true);
|
||||
|
||||
ChargeDO child = cloneBase(charge, splitAdjustId);
|
||||
child.setBillWater(water);
|
||||
setFeesFromMap(child, feeMap); // 水费/污水/垃圾等
|
||||
children.add(child);
|
||||
accumulated = accumulated.add(water);
|
||||
}
|
||||
```
|
||||
|
||||
`setFeesFromMap` 与 `PriceDiffWriteBackService.setFeesFromMap` 逻辑一致。
|
||||
|
||||
---
|
||||
|
||||
## 六、边界条件
|
||||
|
||||
| 场景 | 处理 |
|
||||
|------|------|
|
||||
| 模板不存在 | 抛出 `invalidParamException("原账单水价模板已失效")` |
|
||||
| billWaters 之和 ≠ charge.billWater | 不强制校验,允许浮点误差 |
|
||||
| isLadder 为 null | 默认 true(阶梯) |
|
||||
| adjustmentSnapCode 为 null | 降级到最新快照 |
|
||||
Loading…
x
Reference in New Issue
Block a user