feat(budget): 实现存款明细计算核心逻辑
- 添加 BudgetItemCalculator 辅助类,实现明细项计算规则 - 收入:实际>0取实际,否则取预算 - 支出:取MAX(预算, 实际) - 硬性支出未发生:按天数折算 - 归档数据:直接使用实际值 - 实现月度和年度存款核心公式 - 月度:收入预算 + 本月年度收入 - 支出预算 - 本月年度支出 - 年度:归档已实收 + 未来收入预算 - 归档已实支 - 未来支出预算 - 定义存款明细数据结构 - SavingsDetail: 包含收入/支出明细列表和汇总 - BudgetDetailItem: 预算明细项(含计算用金额、计算说明等) - SavingsCalculationSummary: 计算汇总信息 - 新增单元测试 - BudgetItemCalculatorTest: 11个测试覆盖所有计算规则 - BudgetSavingsCalculationTest: 6个测试验证核心公式 测试结果:所有测试通过 (366 passed, 0 failed)
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Display income and expense budget in savings detail popup
|
||||
The savings detail popup SHALL display the associated income budget and expense budget information for the selected savings plan, including both budget limits and current amounts.
|
||||
|
||||
#### Scenario: User opens savings detail popup with matched budgets
|
||||
- **WHEN** user clicks the detail button on a savings plan card
|
||||
- **AND** there exist income and expense budgets for the same period and type
|
||||
- **THEN** the popup SHALL display the income budget limit and current amount
|
||||
- **AND** the popup SHALL display the expense budget limit and current amount
|
||||
- **AND** the popup SHALL display the savings formula (Income Limit - Expense Limit = Planned Savings)
|
||||
- **AND** the popup SHALL display the savings result (Planned Savings, Actual Savings, Remaining)
|
||||
|
||||
#### Scenario: User opens savings detail popup without matched budgets
|
||||
- **WHEN** user clicks the detail button on a savings plan card
|
||||
- **AND** there are no income or expense budgets for the same period and type
|
||||
- **THEN** the popup SHALL display 0 for income budget limit and current amount
|
||||
- **AND** the popup SHALL display 0 for expense budget limit and current amount
|
||||
- **AND** the popup SHALL still display the savings formula and result with these values
|
||||
|
||||
### Requirement: Pass budget data to savings component
|
||||
The parent component (Index.vue) SHALL pass income budgets and expense budgets to the SavingsBudgetContent component to enable detail popup display.
|
||||
|
||||
#### Scenario: Budget data is loaded successfully
|
||||
- **WHEN** the budget data is loaded from the API
|
||||
- **THEN** the income budgets SHALL be passed to SavingsBudgetContent via props
|
||||
- **AND** the expense budgets SHALL be passed to SavingsBudgetContent via props
|
||||
- **AND** the savings budgets SHALL be passed to SavingsBudgetContent via props (existing behavior)
|
||||
|
||||
### Requirement: Match income and expense budgets to savings plan
|
||||
The SavingsBudgetContent component SHALL match income and expense budgets to the current savings plan based on periodStart and type fields.
|
||||
|
||||
#### Scenario: Match budgets with same period and type
|
||||
- **WHEN** displaying savings plan details
|
||||
- **AND** the component searches for matching budgets
|
||||
- **THEN** the component SHALL find income budgets where periodStart and type match the savings plan
|
||||
- **AND** the component SHALL find expense budgets where periodStart and type match the savings plan
|
||||
- **AND** if multiple matches exist, the component SHALL use the first match
|
||||
|
||||
#### Scenario: No matching budgets found
|
||||
- **WHEN** displaying savings plan details
|
||||
- **AND** no income budget matches the savings plan's periodStart and type
|
||||
- **OR** no expense budget matches the savings plan's periodStart and type
|
||||
- **THEN** the component SHALL use 0 as the default value for unmatched budget fields
|
||||
- **AND** the popup SHALL still render without errors
|
||||
Reference in New Issue
Block a user