1. AGENTS.md 更新 - water-docs: 新增 specs/ 与 docs/design/ 生命周期规则章节 - water-backend: 更新协作引用(建设期/建成后、evidence 模块化) 2. specs/ 重复合并 - 006-reminder-event-design 合并入 003-rev006-reminder-event-design - 001-rev004-accounting 删除冗余 data-model.md + contracts/ - 002-rev005-invoice-flow 删除冗余 data-model.md + contracts/ 3. evidence 按模块归档 - 35 个 REV-004 文件归入 evidence/rev004-accounting/ - 7 个通用 bugfix 文件归入 evidence/bugfix/ 和 bugfix/frontend/ - 新建 rev005-invoice/、rev006-reminder/、rev007-statistics/ 目录 4. guides/ 清理 - 14 个 REV004_*.md 移入 evidence/rev004-accounting/ 5. 遗留文件处理 - docs/research/ 归档到 Archive/06_Migration_Plans/ - backend-check detached worktrees 清理 6. 交叉引用修复 - 006-reminder-event-design → 003-rev006-reminder-event-design - docs/guides/REV004_ → docs/evidence/rev004-accounting/REV004_ 7. DB 设计文档修正(01_Database_Design.md) - biz_invoice 明确为开票配置表,非发票记录表 - 新增 biz_invoice_record 为发票申请/结果主表 - 新增 biz_charge_invoice_rel 账单-发票关联说明 - REV-005 承接口径表名全部修正 8. 发票审计证据 - 新增 evidence/rev005-invoice/2026-06-16-invoice-document-audit.md
6.0 KiB
6.0 KiB
REV004 / 按水量分账最小闭环设计(2026-04-14)
1. 目标
本设计只覆盖 第一阶段:按水量分账最小闭环。
目标是:
- 审批通过后,能够把一笔未收费原账单按多笔水量拆分,真正生成多张目标子账单;
- 先不做“按费用组成分账”;
- 先把最小可运行闭环打通,再作为后续扩展基础。
2. 为什么第一阶段先做按水量分账
原因:
- 规则最清晰:拆分水量之和必须等于原水量。
- 业务校验最直接:原账单 -> 多笔子账单,按水量重算金额,容易理解。
- 比按费用组成更容易守恒:先处理总水量、总金额守恒,再逐步扩到费用项粒度。
- 更适合先做执行态样板:审批通过、执行、回看、失败回滚等流程都能先沉淀下来。
3. 最小闭环边界
本阶段要做到
- 提交按水量分账申请
- 保存拆分明细(每笔分账水量)
- 审批通过后执行拆账
- 生成多张目标账单
- 原账单标记为已拆分/失效
- 日志与查询可回看
本阶段不做
- 按费用组成分账
- 目标客户跨户分账(如无强需求,可先默认同客户)
- 更复杂规则模板
- 开票联动优化
- 自动撤销分账执行结果
4. 输入输出定义
4.1 前端最少输入
按水量分账弹窗至少提交:
sourceChargeIdsplitItems[]seqNosplitWater
reasonCoderemarkapplicantcontactMobile
4.2 关键校验
- 原账单必须是未收费
splitItems.length >= 2- 每笔
splitWater > 0 sum(splitWater) = source.billWater- 必须填写原因
4.3 输出结果
申请提交成功后:
adjustmentNoresultStatus = PENDING_APPROVAL
执行成功后应可回看:
- 原账单摘要
- 目标子账单列表
- 每张子账单的:
- 水量
- 账单金额
- 应收金额
- 违约金(若适用)
5. 数据模型(MVP)
5.1 主表:biz_split_adjust
建议 MVP 字段:
idsplit_adjust_nosource_charge_idsplit_rule_type=BY_WATERreason_coderemarkapproval_statusexecute_statusexecute_messageexecuted_atcreator / create_time / updater / update_time
5.2 明细表:biz_split_adjust_detail
建议 MVP 字段:
idsplit_adjust_idseq_nosplit_watertarget_charge_id(执行后回填)split_amount(执行后回填)statuscreator / create_time / updater / update_time
5.3 账单表最小扩展建议
在 biz_charge 里增加追溯字段(二选一或组合):
source_charge_idsplit_adjust_idcharge_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:
- 复制原账单基础信息
- 将
bill_water改成当前split_water - 调用现有计价逻辑重新计算:
bill_amountextended_amount- 若适用则重算
late_fee
- 插入新的
biz_charge记录 - 回填
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 完成时,应满足:
- 用户可提交按水量分账申请
- 审批通过后,系统真正生成多张目标账单
- 子账单水量之和与原账单守恒
- 原账单被正确标记,不再继续作为普通未收费账单使用
- 查询与日志能回看这次分账执行结果
11. 建议实施顺序
- 先补
biz_split_adjust/biz_split_adjust_detail - 再补审批通过后的执行器
- 再补查询回看
- 最后补前端执行态结果页
一句话:
先把“按水量分账”做成审批后真正能拆出子账单的最小闭环,再考虑按费用组成扩展。