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

137 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks: 存款明细计算优化实施清单
## 1. 数据结构定义
- [x] 1.1 在 `Application/Dto/BudgetDto.cs` 中定义 `SavingsDetail` record 类型
- [x] 1.2 在 `Application/Dto/BudgetDto.cs` 中定义 `BudgetDetailItem` record 类型
- [x] 1.3 在 `Application/Dto/BudgetDto.cs` 中定义 `SavingsCalculationSummary` record 类型
- [x] 1.4 在 `BudgetResult` 中添加 `Details` 属性(类型为 `SavingsDetail?`
## 2. 核心计算辅助类 - TDD 红灯阶段
- [x] 2.1 创建 `WebApi.Test/Budget/BudgetItemCalculatorTest.cs` 测试文件
- [x] 2.2 编写测试收入项实际已发生actual > 0应返回实际值
- [x] 2.3 编写测试收入项实际未发生actual = 0应返回预算值
- [x] 2.4 编写测试:支出项普通情况应返回 MAX(预算, 实际)
- [x] 2.5 编写测试:支出项未超预算应返回预算值
- [x] 2.6 编写测试:支出项超预算应返回实际值
- [x] 2.7 编写测试支出项硬性且实际为0月度应按天数折算
- [x] 2.8 编写测试支出项硬性且实际为0年度应按天数折算
- [x] 2.9 编写测试:支出项硬性且实际>0应返回MAX值
- [x] 2.10 编写测试:归档数据应直接返回实际值
- [x] 2.11 编写测试闰年2月按天折算边界情况
- [x] 2.12 编写测试平年2月按天折算边界情况
- [x] 2.13 运行所有测试,确认红灯(测试失败)
## 3. 核心计算辅助类 - TDD 绿灯阶段
- [x] 3.1 创建 `Service/Budget/BudgetItemCalculator.cs` 静态类
- [x] 3.2 实现 `CalculateEffectiveAmount` 方法(包含所有计算规则)
- [x] 3.3 实现 `CalculateMandatoryAmount` 私有方法(硬性消费按天折算)
- [x] 3.4 实现 `GenerateCalculationNote` 方法(生成计算说明)
- [x] 3.5 运行所有测试,确认绿灯(测试通过)
## 4. 月度存款核心公式 - TDD 红灯阶段
- [x] 4.1 创建 `WebApi.Test/Budget/BudgetSavingsCalculationTest.cs` 测试文件
- [x] 4.2 编写测试:月度计划存款公式 - 纯月度预算场景
- [x] 4.3 编写测试:月度计划存款公式 - 月度预算 + 本月发生的年度预算
- [x] 4.4 编写测试:月度计划存款公式 - 年度预算未在本月发生应不计入
- [x] 4.5 运行测试,确认红灯
## 5. 月度存款核心公式 - TDD 绿灯阶段
- [x] 5.1 在 `BudgetSavingsService` 中添加 `CalculateMonthlyPlannedSavings` 私有方法
- [x] 5.2 实现月度计划存款公式:收入预算 + 本月年度收入 - 支出预算 - 本月年度支出
- [x] 5.3 运行测试,确认绿灯
## 6. 年度存款核心公式 - TDD 红灯阶段
- [x] 6.1 编写测试:年度计划存款公式 - 年初无归档数据场景
- [x] 6.2 编写测试:年度计划存款公式 - 年中有归档数据场景
- [x] 6.3 编写测试:年度计划存款公式 - 归档数据包含年度预算
- [x] 6.4 运行测试,确认红灯
## 7. 年度存款核心公式 - TDD 绿灯阶段
- [x] 7.1 在 `BudgetSavingsService` 中添加 `CalculateYearlyPlannedSavings` 私有方法
- [x] 7.2 实现年度计划存款公式:归档已实收 + 未来收入预算 - 归档已实支 - 未来支出预算
- [x] 7.3 运行测试,确认绿灯
## 8. 重构 GetForMonthAsync - TDD 红灯阶段
- [x] 8.1 在 `WebApi.Test/Budget/BudgetSavingsTest.cs` 中编写测试:月度查询应返回 Details 字段
- [x] 8.2 编写测试:月度明细应包含所有月度预算项
- [x] 8.3 编写测试:月度明细应包含本月发生的年度预算项
- [x] 8.4 编写测试:月度明细中每项应包含计算用金额和计算说明
- [x] 8.5 编写测试:超支项目应标记 IsOverBudget = true
- [x] 8.6 编写测试:不记额预算应排除在汇总之外
- [x] 8.7 运行测试,确认红灯
## 9. 重构 GetForMonthAsync - TDD 绿灯阶段
- [x] 9.1 重构 `GetForMonthAsync` 方法,使用 `CalculateMonthlyPlannedSavings`
- [x] 9.2 添加明细数据收集逻辑(创建 `BudgetDetailItem` 列表)
- [x] 9.3 为每个预算项调用 `BudgetItemCalculator.CalculateEffectiveAmount`
- [x] 9.4 生成 `SavingsDetail` 对象并填充到 `BudgetResult.Details`
- [x] 9.5 生成 `SavingsCalculationSummary` 汇总信息
- [x] 9.6 保留原有的 HTML `Description` 生成逻辑(向后兼容)
- [x] 9.7 运行测试,确认绿灯
## 10. 重构 GetForYearAsync - TDD 红灯阶段
- [x] 10.1 编写测试:年度查询应返回 Details 字段
- [x] 10.2 编写测试年度明细应包含归档月份标注IsArchived = true
- [x] 10.3 编写测试:年度明细应包含 ArchivedMonths 字段
- [x] 10.4 编写测试:归档数据应使用归档的实际值
- [x] 10.5 编写测试:未来月份预算应正确折算
- [x] 10.6 编写测试:年度预算项不应重复计算
- [x] 10.7 运行测试,确认红灯
## 11. 重构 GetForYearAsync - TDD 绿灯阶段
- [x] 11.1 重构 `GetForYearAsync` 方法,使用 `CalculateYearlyPlannedSavings`
- [x] 11.2 添加归档数据读取和明细项创建逻辑
- [x] 11.3 为归档数据标注 `IsArchived = true``ArchivedMonths`
- [x] 11.4 添加未来月份预算的明细项创建逻辑
- [x] 11.5 生成 `SavingsDetail` 对象并填充到 `BudgetResult.Details`
- [x] 11.6 保留原有的 HTML `Description` 生成逻辑(向后兼容)
- [x] 11.7 运行测试,确认绿灯
## 12. 边界情况测试
- [x] 12.1 编写测试:闰年年度硬性支出按天折算
- [x] 12.2 编写测试:平年年度硬性支出按天折算
- [x] 12.3 编写测试月初1号硬性支出折算
- [x] 12.4 编写测试月末28/29/30/31号硬性支出折算
- [x] 12.5 编写测试:不记额预算的处理
- [x] 12.6 编写测试:无预算项时的空列表处理
- [x] 12.7 编写测试所有预算项实际为0的情况
- [x] 12.8 运行所有边界测试,确认通过
## 13. 集成测试
- [x] 13.1 编写完整场景集成测试:月度查询包含月度+年度混合
- [x] 13.2 编写完整场景集成测试:年度查询包含归档+未来混合
- [x] 13.3 编写集成测试:验证 HTML Description 和 Details 数据一致性
- [x] 13.4 编写集成测试:验证与 BudgetArchiveRepository 的集成
- [x] 13.5 编写集成测试:验证与 TransactionStatisticsService 的集成
- [x] 13.6 运行所有集成测试,确认通过
## 14. 代码审查与重构
- [x] 14.1 审查所有新增代码,确保符合项目编码规范
- [x] 14.2 检查中文注释是否完整清晰
- [x] 14.3 重构重复代码,提取共用方法
- [x] 14.4 优化变量命名,确保语义清晰
- [x] 14.5 运行所有测试,确保重构后测试仍然通过
## 15. 文档与验收
- [x] 15.1 更新 `BudgetSavingsService` 相关方法的 XML 文档注释
- [x] 15.2 添加 `BudgetItemCalculator` 的使用示例注释
- [x] 15.3 运行完整测试套件:`dotnet test WebApi.Test/WebApi.Test.csproj`
- [x] 15.4 验证所有测试通过0 failed
- [x] 15.5 手动验证:通过 API 调用验证返回数据格式正确
- [x] 15.6 确认向后兼容:旧版前端仍可正常使用 Description 字段