归档
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 18s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s

This commit is contained in:
SunCheng
2026-02-21 21:58:55 +08:00
parent c2751c79cf
commit 9dce12c61b
53 changed files with 139 additions and 114 deletions

View File

@@ -0,0 +1,131 @@
# Spec: 存款明细计算核心算法
## ADDED Requirements
### Requirement: 月度计划存款计算公式
系统 SHALL 使用以下公式计算月度计划存款:
**月度计划存款 = 收入预算 + 发生在本月的年度收入 - 支出预算 - 发生在本月的年度支出**
其中:
- **收入预算**:所有月度收入预算项的预算金额之和
- **发生在本月的年度收入**年度收入预算项在本月实际发生的金额actual > 0
- **支出预算**:所有月度支出预算项的预算金额之和
- **发生在本月的年度支出**年度支出预算项在本月实际发生的金额actual > 0
#### Scenario: 纯月度预算计算
- **WHEN** 用户查询 2026年2月的月度存款且只有月度预算工资10000、奖金5000、房租3000、餐饮2000
- **THEN** 系统返回计划存款 = 10000 + 5000 - 3000 - 2000 = 10000
#### Scenario: 月度预算 + 本月发生的年度预算
- **WHEN** 用户查询 2026年2月的月度存款月度预算工资10000、房租3000且年度旅游支出在本月实际发生3000元
- **THEN** 系统返回计划存款 = 10000 - 3000 - 3000 = 4000
#### Scenario: 年度预算未在本月发生
- **WHEN** 用户查询 2026年2月的月度存款月度预算工资10000、房租3000年度年终奖预算50000但本月实际为0
- **THEN** 系统返回计划存款 = 10000 - 3000 = 7000年终奖不计入
### Requirement: 年度计划存款计算公式
系统 SHALL 使用以下公式计算年度计划存款:
**年度计划存款 = 归档月已实收 + 未来月(包含本月)收入预算 - 归档月已实支 - 未来月(包含本月)支出预算**
其中:
- **归档月已实收**已归档月份1月~当前月-1的实际收入金额之和`BudgetArchive` 读取
- **未来月收入预算**:当前月及未来月份的月度收入预算 × 剩余月数
- **归档月已实支**:已归档月份的实际支出金额之和,从 `BudgetArchive` 读取
- **未来月支出预算**:当前月及未来月份的月度支出预算 × 剩余月数
#### Scenario: 年初无归档数据
- **WHEN** 用户在 2026年1月查询年度存款月度预算工资10000/月、房租3000/月),无归档数据
- **THEN** 系统返回计划存款 = (10000 - 3000) × 12 = 84000
#### Scenario: 年中有归档数据
- **WHEN** 用户在 2026年3月查询年度存款1月归档已实收15000、已实支48002月归档已实收14000、已实支52003~12月月度预算工资10000、房租3000
- **THEN** 系统返回计划存款 = (15000 + 14000) + (10000 × 10) - (4800 + 5200) - (3000 × 10) = 129000
#### Scenario: 归档数据包含年度预算
- **WHEN** 归档数据中包含年度预算的实际发生金额如1月旅游支出3000
- **THEN** 系统将其计入"归档月已实支",不重复计算
### Requirement: 明细项计算用金额 - 收入规则
对于收入类预算项,系统 SHALL 根据以下规则计算"计算用金额"
- 如果实际金额 > 0计算用金额 = 实际金额
- 如果实际金额 = 0计算用金额 = 预算金额
#### Scenario: 收入已发生
- **WHEN** 工资预算10000实际发生9500
- **THEN** 计算用金额 = 9500标注为"使用实际"
#### Scenario: 收入未发生
- **WHEN** 奖金预算5000实际发生0
- **THEN** 计算用金额 = 5000标注为"使用预算"
### Requirement: 明细项计算用金额 - 支出规则(普通)
对于非硬性支出类预算项,系统 SHALL 计算用金额 = MAX(预算金额, 实际金额)
#### Scenario: 支出未超预算
- **WHEN** 餐饮预算2000实际发生1800
- **THEN** 计算用金额 = 2000标注为"使用预算"
#### Scenario: 支出超预算
- **WHEN** 餐饮预算2000实际发生2500
- **THEN** 计算用金额 = 2500标注为"使用实际(超支)",高亮显示
### Requirement: 明细项计算用金额 - 支出规则(硬性)
对于硬性支出(`IsMandatoryExpense = true`)且实际金额 = 0 的预算项,系统 SHALL 按天数折算计算用金额,不进行 MAX 比较。
**月度折算公式**:计算用金额 = 预算金额 / 当月天数 × 当前日期
**年度折算公式**:计算用金额 = 预算金额 / 当年天数 × 当前天数
#### Scenario: 硬性支出未发生(月度)
- **WHEN** 房租预算3000硬性实际为0当前日期为2月15日2月共28天
- **THEN** 计算用金额 = 3000 / 28 × 15 ≈ 1607.14,标注为"按天折算"
#### Scenario: 硬性支出已发生
- **WHEN** 房租预算3000硬性实际发生3000
- **THEN** 计算用金额 = MAX(3000, 3000) = 3000标注为"使用实际"
#### Scenario: 硬性支出超预算
- **WHEN** 水电预算500硬性实际发生600
- **THEN** 计算用金额 = MAX(500, 600) = 600标注为"使用实际(超支)"
#### Scenario: 硬性支出按天折算可能超预算
- **WHEN** 房租预算3000硬性实际为0当前日期为2月29日2月共28天
- **THEN** 计算用金额 = 3000 / 28 × 29 ≈ 3107.14(大于预算),标注为"按天折算"
### Requirement: 归档月份数据处理
对于已归档月份的预算数据,系统 SHALL 直接使用归档中的实际金额(`BudgetArchive.Content[].Actual`),不重新计算。
#### Scenario: 读取归档数据
- **WHEN** 用户在3月查询年度存款1月归档中工资实际10000、房租实际3000
- **THEN** 系统使用归档实际值10000和3000不根据当前预算重新计算
#### Scenario: 归档后预算调整
- **WHEN** 1月归档时工资预算10000实际100002月将工资预算调整为12000用户在3月查询年度存款
- **THEN** 1月仍使用归档的实际100002月及以后使用新预算12000
### Requirement: 闰年和月末边界处理
系统 SHALL 正确处理闰年和月末边界情况:
- 闰年判断:使用 `DateTime.IsLeapYear(year)` 判断闰年366天平年365天
- 月末天数:使用 `DateTime.DaysInMonth(year, month)` 获取
#### Scenario: 闰年2月硬性支出折算
- **WHEN** 2024年2月29日闰年房租预算3000硬性实际为0
- **THEN** 计算用金额 = 3000 / 29 × 29 = 3000
#### Scenario: 平年2月硬性支出折算
- **WHEN** 2026年2月28日平年房租预算3000硬性实际为0
- **THEN** 计算用金额 = 3000 / 28 × 28 = 3000
#### Scenario: 年度硬性支出闰年折算
- **WHEN** 2024年闰年第100天年度保险预算12000硬性实际为0
- **THEN** 计算用金额 = 12000 / 366 × 100 ≈ 3278.69
### Requirement: 不记额预算处理
对于不记额预算(`NoLimit = true`)的预算项,系统 SHALL 排除在计划存款计算之外,但在明细中显示为"不限额"。
#### Scenario: 不记额收入
- **WHEN** 存在不记额收入预算项如意外收入实际发生1000
- **THEN** 该项不计入"收入预算",明细中显示预算为"不限额"实际为1000