# REV-003 营业收费 P0 验证证据 ## 1. 验证结论 2026-07-15 完成营业收费 P0 代码整改、审查后加固和定向验收。后端营业模块 130 项测试、银行模块 7 项测试、29 个 Maven reactor 模块编译、前端 44 项 Node 契约测试及 Vite 全量构建均通过。 验证期间未运行 `vue-tsc`。 ## 2. 实施提交 ### 后端 `fix/rev003-charging-p0` | 提交 | 内容 | |------|------| | `098749d58` | 增加柜台支付幂等和金额拆分字段 | | `04a5247a2` | 统一本金与违约金口径 | | `d72a360f2` | 账户加锁并去重柜台预存充值 | | `276d90df7` | 新增原子多账单柜台收费命令 | | `25c385c27` | 封堵通用财务状态和余额修改旁路 | | `f0b906048` | 按显式支付记录执行柜员结账 | | `6c2e4850c` | 修复已结/未结预存红冲状态路径 | | `a4d3cc0cc` | 防止银行假冲正和预存回调重放 | | `f7f32ff6e` | 审查后加固:请求级 advisory lock、通用写路径行锁、银行精确交易冲正、结算分账和审批终态保护 | ### 前端 `fix/rev003-charging-p0` | 提交 | 内容 | |------|------| | `fe21be95` | 柜台收费切换为单次原子批量提交 | | `06a5d70a` | 柜台结账只提交显式勾选的支付记录 | | `0553ff1a` | 审查后加固:成功与刷新结果分离、集收刷新、金额展示契约、当前收银员范围和输入校验 | ## 3. 后端验证 ### 营业模块定向测试 ```bash mvn -pl sw-business/sw-business-server -am \ -Dtest=ChargeControllerTest,ChargeServiceCounterPaymentTest,AccountServiceImplConcurrencyTest,CounterChargeApplicationServiceImplTest,PaymentRecordServiceImplTest,PaymentCommandApplicationServiceTest,CounterSettleApplicationServiceImplTest,PrestorageBpmCallbackServiceTest,PaymentQueryServiceTest \ -Dsurefire.failIfNoSpecifiedTests=false test ``` 结果:退出码 0,9 个测试类合计 `Tests run: 130, Failures: 0, Errors: 0, Skipped: 0`。 ### 银行冲正测试 ```bash mvn -pl sw-business-bank/sw-business-bank-server -am \ -Dtest=PayInvalidServiceImplTest,PayCebServiceImplTest \ -Dsurefire.failIfNoSpecifiedTests=false test ``` 结果:退出码 0,`Tests run: 7, Failures: 0, Errors: 0, Skipped: 0`。覆盖本金加违约金金额口径、空违约金兼容、失败交易原请求金额持久化及重放,以及银行原交易冲正失败时不得错误标记成功。测试日志中的异常栈为用例主动模拟业务红冲失败。 ### 后端编译 ```bash mvn -pl sw-business/sw-business-server,sw-business-bank/sw-business-bank-server \ -am -DskipTests compile ``` 结果:退出码 0,29 个 reactor 模块全部 `SUCCESS`,最终 `BUILD SUCCESS`。 ## 4. 前端验证 ### P0 契约测试 ```bash node --test \ src/views/operatingCharges/counterCharging/counterTopup.contract.test.mjs \ src/views/operatingCharges/counterCheckout/checkout-top-summary.contract.test.mjs \ tests/operatingCharges/counterChargingP0Flow.test.mjs \ tests/operatingCharges/counterChargingPersistentTopup.test.mjs \ tests/operatingCharges/counterChargingHubMode.test.mjs \ tests/operatingCharges/counterChargingHubActualAmount.test.mjs \ tests/operatingCharges/counterChargingZeroAmount.contract.test.mjs \ tests/operatingCharges/counterCheckoutCashierOptions.contract.test.mjs \ tests/operatingCharges/counterCheckoutExplicitSelection.test.mjs ``` 结果:退出码 0,`tests 44`、`pass 44`、`fail 0`。 覆盖点包括: - 本金与违约金按分计算,拒绝非法和负数金额。 - 同一批次只调用一次原子收费接口,重试期间复用请求号。 - 无欠费预存可连续操作,零金额账单不会误进入预存模式。 - 当前仅现金渠道可直接提交,配置异常时仍回退现金安全项。 - 结账只提交明确勾选且去重后的支付记录 ID;切换支付方式或刷新数据时清除选择。 - 结账金额和展示优先使用渠道实收,预存抵扣独立表达。 - 已结、未结红冲原因均为必填。 - 命令成功后立即清除重试请求号并展示成功结果;客户或汇总刷新失败只提示刷新警告,不得误报交易失败。 - 集收成功后重新查询各客户余额和未缴账单,同时保留本次收讫快照。 - 账单主表和详情统一显示本金加违约金;顶部实收优先使用 `channelAmount`,预存抵扣独立展示。 - 结账查询和提交主体固定为当前登录收银员,不再把其他用户、银行或收费方式混入收费员筛选。 - `useMessage.prompt` 透传 Element Plus 校验选项,金额换算拒绝 `NaN/Infinity`。 ### Vite 全量构建 `build:dev` 脚本已确认仅执行 `vite build --mode dev`,不包含 `vue-tsc`。 第一次按 Node 默认堆上限执行时,在 Rollup 大体量打包阶段触发约 4GB 堆上限,报 `JavaScript heap out of memory`。随后不修改源码和构建配置,仅提高本次 Node 堆上限复验: ```bash NODE_OPTIONS=--max-old-space-size=8192 \ node ./node_modules/vite/bin/vite.js build --mode dev ``` 结果:退出码 0,输出 `Build successful. Please see dist directory`。 构建仍会输出项目既有的中文 SVG `symbolId` 命名警告和 Rollup `PURE` 注释警告,本轮未新增相关资源,也不影响构建成功。 ## 5. 数据库集成门禁 当前环境未设置 `REV004_IT_DB_URL`,因此未执行依赖真实数据库的可选集成测试。上线前仍需在目标 PostgreSQL 环境验证: 1. 新增列、条件唯一索引和历史空值兼容 DDL 已完整部署。 2. PostgreSQL 事务级 advisory lock 可按“租户 + requestId”串行化同一柜台命令;同请求号不相交账单也不得双成功。 3. 同一账单并发收费只有一个请求成功,失败批次不留下部分支付或余额变化。 4. 柜员结账金额等于所选记录的渠道实收之和。 5. 已结/未结预存红冲正确扣减余额并生成唯一反向流水。 6. 创建反向支付唯一索引前,DDL 的重复关系预检没有发现历史脏数据;曾以零默认值落库的未知历史拆分字段已恢复为 NULL。 7. 银行缴费按“本金 + 违约金”校验并锁定账单;冲正必须命中原 `bankTransactionId`,重试旧冲正不得影响后续新缴费。 ## 6. 已知非本轮问题 实施期间单独运行完整 `ChargeServiceAccountingAdjustTest` 时,既有用例 `testAdjustAccounting_usageGarbageFeeUsesCustomerBasicNumberOnly` 出现期望 `12.34`、实际 `1221.66` 的失败。该用例属于用量垃圾费账务调整,不在 REV-003 P0 范围;本轮涉及的银行冲正方法、通用财务旁路和上述 137 项后端测试均已通过。该问题应作为 REV-004 独立缺陷继续处理。 前端扩大到全部 `tests/operatingCharges/*.test.mjs` 的历史库存扫描时,仍有若干与当前实现范围不一致或依赖固定相邻仓库路径的旧正则契约失败;本轮以列出的 44 项 P0 定向契约及 Vite 全量构建作为发布门禁,旧库存迁移另行治理。 ## 7. 发布约束 1. 先部署数据库 DDL,再部署后端,最后部署前端。 2. 不回退通用营业账/账户更新的财务旁路封堵。 3. 首批只开放现金柜台收费;非现金渠道接入真实确认前保持禁用。 4. 上线后按 `payment_batch_no`、`request_id`、账户流水和结账差异持续观察。