Files
EmailBill/openspec/changes/saving-detail-calculation/proposal.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

2.7 KiB
Raw Blame History

Proposal: 存款明细计算优化

Why

当前的存款计划计算逻辑不够清晰明确,用户难以理解"计划存款"的具体含义和计算方式。特别是在年度视图中,如何处理已归档月份(使用实际值)和未来月份(使用预算值)的逻辑不够透明。需要明确核心计算公式,并提供详细的明细展示,让用户能够清楚看到每一项收入和支出如何影响最终的计划存款金额。

What Changes

  • 重构存款计划核心计算公式

    月度计划存款 = 收入预算 + 发生在本月的年度收入 - 支出预算 - 发生在本月的年度支出

    年度计划存款 = 归档月已实收 + 未来月(包含本月)收入预算 - 归档月已实支 - 未来月(包含本月)支出预算

  • 明细项计算用金额规则(用于明细展示):

    • 支出项:取预算与实际的较大值(MAX(预算, 实际)
    • 支出项(硬性且实际=0按天数折算不做MAX比较可能大于预算
    • 收入项:实际已发生时取实际值,未发生时取预算值
    • 归档月份:直接使用归档的实际值,不重新计算
  • 增强存款明细展示

    • 显示每个预算项的预算金额、实际金额、计算用金额
    • 标注使用了哪个值(预算/实际/按天折算)
    • 高亮超支/未达标项目
    • 明确展示计算过程和中间步骤
  • 支持月度和年度两种时间维度的存款明细

  • 确保与现有归档逻辑(BudgetArchive)和固定收支(IsMandatoryExpense)兼容

Capabilities

New Capabilities

  • saving-detail-calculation: 存款明细计算核心算法,包括月度和年度计算逻辑
  • saving-detail-display: 存款明细前端展示组件,包括明细表格和计算过程说明

Modified Capabilities

  • budget-savings: 现有存款预算服务的计算逻辑需要根据新规则重构

Impact

后端影响

  • 修改Service/Budget/BudgetSavingsService.cs - 重构 GetForMonthAsyncGetForYearAsync 方法
  • 新增:计算用金额的辅助方法(支出/收入/硬性的判断逻辑)
  • 依赖:依赖现有的 BudgetArchiveRepositoryTransactionStatisticsService

前端影响

  • 修改:存款统计页面,增加"明细"标签页或折叠面板
  • 新增:明细表格组件,展示预算、实际、计算用值三列

测试影响

  • 新增WebApi.Test/Budget/BudgetSavingsCalculationTest.cs - 覆盖所有计算场景的单元测试
  • 修改WebApi.Test/Budget/BudgetSavingsTest.cs - 更新现有测试以匹配新逻辑

数据影响

  • 无数据库结构变更
  • 无需数据迁移
  • 归档数据格式保持不变