Files
EmailBill/openspec/changes/saving-detail-calculation/tasks.md
SunCheng 4cc205fc25 feat(budget): 实现存款明细计算核心逻辑
- 添加 BudgetItemCalculator 辅助类,实现明细项计算规则
  - 收入:实际>0取实际,否则取预算
  - 支出:取MAX(预算, 实际)
  - 硬性支出未发生:按天数折算
  - 归档数据:直接使用实际值

- 实现月度和年度存款核心公式
  - 月度:收入预算 + 本月年度收入 - 支出预算 - 本月年度支出
  - 年度:归档已实收 + 未来收入预算 - 归档已实支 - 未来支出预算

- 定义存款明细数据结构
  - SavingsDetail: 包含收入/支出明细列表和汇总
  - BudgetDetailItem: 预算明细项(含计算用金额、计算说明等)
  - SavingsCalculationSummary: 计算汇总信息

- 新增单元测试
  - BudgetItemCalculatorTest: 11个测试覆盖所有计算规则
  - BudgetSavingsCalculationTest: 6个测试验证核心公式

测试结果:所有测试通过 (366 passed, 0 failed)
2026-02-20 16:26:04 +08:00

6.9 KiB
Raw Blame History

Tasks: 存款明细计算优化实施清单

1. 数据结构定义

  • 1.1 在 Application/Dto/BudgetDto.cs 中定义 SavingsDetail record 类型
  • 1.2 在 Application/Dto/BudgetDto.cs 中定义 BudgetDetailItem record 类型
  • 1.3 在 Application/Dto/BudgetDto.cs 中定义 SavingsCalculationSummary record 类型
  • 1.4 在 BudgetResult 中添加 Details 属性(类型为 SavingsDetail?

2. 核心计算辅助类 - TDD 红灯阶段

  • 2.1 创建 WebApi.Test/Budget/BudgetItemCalculatorTest.cs 测试文件
  • 2.2 编写测试收入项实际已发生actual > 0应返回实际值
  • 2.3 编写测试收入项实际未发生actual = 0应返回预算值
  • 2.4 编写测试:支出项普通情况应返回 MAX(预算, 实际)
  • 2.5 编写测试:支出项未超预算应返回预算值
  • 2.6 编写测试:支出项超预算应返回实际值
  • 2.7 编写测试支出项硬性且实际为0月度应按天数折算
  • 2.8 编写测试支出项硬性且实际为0年度应按天数折算
  • 2.9 编写测试:支出项硬性且实际>0应返回MAX值
  • 2.10 编写测试:归档数据应直接返回实际值
  • 2.11 编写测试闰年2月按天折算边界情况
  • 2.12 编写测试平年2月按天折算边界情况
  • 2.13 运行所有测试,确认红灯(测试失败)

3. 核心计算辅助类 - TDD 绿灯阶段

  • 3.1 创建 Service/Budget/BudgetItemCalculator.cs 静态类
  • 3.2 实现 CalculateEffectiveAmount 方法(包含所有计算规则)
  • 3.3 实现 CalculateMandatoryAmount 私有方法(硬性消费按天折算)
  • 3.4 实现 GenerateCalculationNote 方法(生成计算说明)
  • 3.5 运行所有测试,确认绿灯(测试通过)

4. 月度存款核心公式 - TDD 红灯阶段

  • 4.1 创建 WebApi.Test/Budget/BudgetSavingsCalculationTest.cs 测试文件
  • 4.2 编写测试:月度计划存款公式 - 纯月度预算场景
  • 4.3 编写测试:月度计划存款公式 - 月度预算 + 本月发生的年度预算
  • 4.4 编写测试:月度计划存款公式 - 年度预算未在本月发生应不计入
  • 4.5 运行测试,确认红灯

5. 月度存款核心公式 - TDD 绿灯阶段

  • 5.1 在 BudgetSavingsService 中添加 CalculateMonthlyPlannedSavings 私有方法
  • 5.2 实现月度计划存款公式:收入预算 + 本月年度收入 - 支出预算 - 本月年度支出
  • 5.3 运行测试,确认绿灯

6. 年度存款核心公式 - TDD 红灯阶段

  • 6.1 编写测试:年度计划存款公式 - 年初无归档数据场景
  • 6.2 编写测试:年度计划存款公式 - 年中有归档数据场景
  • 6.3 编写测试:年度计划存款公式 - 归档数据包含年度预算
  • 6.4 运行测试,确认红灯

7. 年度存款核心公式 - TDD 绿灯阶段

  • 7.1 在 BudgetSavingsService 中添加 CalculateYearlyPlannedSavings 私有方法
  • 7.2 实现年度计划存款公式:归档已实收 + 未来收入预算 - 归档已实支 - 未来支出预算
  • 7.3 运行测试,确认绿灯

8. 重构 GetForMonthAsync - TDD 红灯阶段

  • 8.1 在 WebApi.Test/Budget/BudgetSavingsTest.cs 中编写测试:月度查询应返回 Details 字段
  • 8.2 编写测试:月度明细应包含所有月度预算项
  • 8.3 编写测试:月度明细应包含本月发生的年度预算项
  • 8.4 编写测试:月度明细中每项应包含计算用金额和计算说明
  • 8.5 编写测试:超支项目应标记 IsOverBudget = true
  • 8.6 编写测试:不记额预算应排除在汇总之外
  • 8.7 运行测试,确认红灯

9. 重构 GetForMonthAsync - TDD 绿灯阶段

  • 9.1 重构 GetForMonthAsync 方法,使用 CalculateMonthlyPlannedSavings
  • 9.2 添加明细数据收集逻辑(创建 BudgetDetailItem 列表)
  • 9.3 为每个预算项调用 BudgetItemCalculator.CalculateEffectiveAmount
  • 9.4 生成 SavingsDetail 对象并填充到 BudgetResult.Details
  • 9.5 生成 SavingsCalculationSummary 汇总信息
  • 9.6 保留原有的 HTML Description 生成逻辑(向后兼容)
  • 9.7 运行测试,确认绿灯

10. 重构 GetForYearAsync - TDD 红灯阶段

  • 10.1 编写测试:年度查询应返回 Details 字段
  • 10.2 编写测试年度明细应包含归档月份标注IsArchived = true
  • 10.3 编写测试:年度明细应包含 ArchivedMonths 字段
  • 10.4 编写测试:归档数据应使用归档的实际值
  • 10.5 编写测试:未来月份预算应正确折算
  • 10.6 编写测试:年度预算项不应重复计算
  • 10.7 运行测试,确认红灯

11. 重构 GetForYearAsync - TDD 绿灯阶段

  • 11.1 重构 GetForYearAsync 方法,使用 CalculateYearlyPlannedSavings
  • 11.2 添加归档数据读取和明细项创建逻辑
  • 11.3 为归档数据标注 IsArchived = trueArchivedMonths
  • 11.4 添加未来月份预算的明细项创建逻辑
  • 11.5 生成 SavingsDetail 对象并填充到 BudgetResult.Details
  • 11.6 保留原有的 HTML Description 生成逻辑(向后兼容)
  • 11.7 运行测试,确认绿灯

12. 边界情况测试

  • 12.1 编写测试:闰年年度硬性支出按天折算
  • 12.2 编写测试:平年年度硬性支出按天折算
  • 12.3 编写测试月初1号硬性支出折算
  • 12.4 编写测试月末28/29/30/31号硬性支出折算
  • 12.5 编写测试:不记额预算的处理
  • 12.6 编写测试:无预算项时的空列表处理
  • 12.7 编写测试所有预算项实际为0的情况
  • 12.8 运行所有边界测试,确认通过

13. 集成测试

  • 13.1 编写完整场景集成测试:月度查询包含月度+年度混合
  • 13.2 编写完整场景集成测试:年度查询包含归档+未来混合
  • 13.3 编写集成测试:验证 HTML Description 和 Details 数据一致性
  • 13.4 编写集成测试:验证与 BudgetArchiveRepository 的集成
  • 13.5 编写集成测试:验证与 TransactionStatisticsService 的集成
  • 13.6 运行所有集成测试,确认通过

14. 代码审查与重构

  • 14.1 审查所有新增代码,确保符合项目编码规范
  • 14.2 检查中文注释是否完整清晰
  • 14.3 重构重复代码,提取共用方法
  • 14.4 优化变量命名,确保语义清晰
  • 14.5 运行所有测试,确保重构后测试仍然通过

15. 文档与验收

  • 15.1 更新 BudgetSavingsService 相关方法的 XML 文档注释
  • 15.2 添加 BudgetItemCalculator 的使用示例注释
  • 15.3 运行完整测试套件:dotnet test WebApi.Test/WebApi.Test.csproj
  • 15.4 验证所有测试通过0 failed
  • 15.5 手动验证:通过 API 调用验证返回数据格式正确
  • 15.6 确认向后兼容:旧版前端仍可正常使用 Description 字段