Files
EmailBill/WebApi.Test/Budget/BudgetSavingsTest.cs
SunCheng 2cb5bffc70 feat(budget): 添加存款明细数据生成逻辑
- 实现 GenerateMonthlyDetails 方法生成月度存款明细
  - 为每个预算项调用 BudgetItemCalculator 计算有效金额
  - 生成计算说明(使用预算/使用实际/超支/按天折算)
  - 标记超支项目
  - 生成汇总信息(总收入、总支出、计划存款)

- GetForMonthAsync 现在返回 Details 字段
  - 包含收入明细列表
  - 包含支出明细列表
  - 包含计算汇总和公式

- 新增集成测试验证 Details 字段生成正确
  - 验证收入项计算规则
  - 验证支出项超支标记
  - 验证硬性支出处理
  - 验证汇总计算

测试结果:58个预算测试全部通过
2026-02-20 16:59:17 +08:00

666 lines
27 KiB
C#
Raw Permalink 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.
using Service.Transaction;
namespace WebApi.Test.Budget;
public class BudgetSavingsTest : BaseTest
{
private readonly IBudgetRepository _budgetRepository = Substitute.For<IBudgetRepository>();
private readonly IBudgetArchiveRepository _budgetArchiveRepository = Substitute.For<IBudgetArchiveRepository>();
private readonly ITransactionStatisticsService _transactionStatisticsService = Substitute.For<ITransactionStatisticsService>();
private readonly IConfigService _configService = Substitute.For<IConfigService>();
private readonly IDateTimeProvider _dateTimeProvider = Substitute.For<IDateTimeProvider>();
private readonly BudgetSavingsService _service;
public BudgetSavingsTest()
{
_dateTimeProvider.Now.Returns(DateTime.Now);
_service = new BudgetSavingsService(
_budgetRepository,
_budgetArchiveRepository,
_transactionStatisticsService,
_configService,
_dateTimeProvider
);
}
[Fact]
public async Task GetSavings_月度_Test()
{
// Arrange
var referenceDate = new DateTime(2024, 1, 1);
var budgets = new List<BudgetRecord>
{
new()
{
Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 10000, Category = BudgetCategory.Income,
SelectedCategories = "工资"
},
new()
{
Id = 2, Name = "餐饮", Type = BudgetPeriodType.Month, Limit = 2000, Category = BudgetCategory.Expense,
SelectedCategories = "餐饮"
}
};
var transactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 10000m },
{ ("餐饮", TransactionType.Expense), 1500m }
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(transactions);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Month, referenceDate);
// Assert
result.Should().NotBeNull();
result.Limit.Should().Be(8000);
}
[Fact]
public async Task GetSavings_月度_应返回Details字段()
{
// Arrange
var referenceDate = new DateTime(2024, 2, 15);
_dateTimeProvider.Now.Returns(referenceDate);
var budgets = new List<BudgetRecord>
{
new()
{
Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 10000, Category = BudgetCategory.Income,
SelectedCategories = "工资"
},
new()
{
Id = 2, Name = "餐饮", Type = BudgetPeriodType.Month, Limit = 2000, Category = BudgetCategory.Expense,
SelectedCategories = "餐饮"
},
new()
{
Id = 3, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3000, Category = BudgetCategory.Expense,
SelectedCategories = "房租", IsMandatoryExpense = true
}
};
var transactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 10000m },
{ ("餐饮", TransactionType.Expense), 2500m }, // 超支
{ ("房租", TransactionType.Expense), 0m } // 硬性未发生
};
_transactionStatisticsService.GetAmountGroupByClassifyAsync(
Arg.Any<DateTime>(),
Arg.Any<DateTime>()
).Returns(transactions);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns("存款");
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Month, referenceDate, budgets);
// Assert
result.Should().NotBeNull();
result.Details.Should().NotBeNull();
// 验证收入明细
result.Details!.IncomeItems.Should().HaveCount(1);
var incomeItem = result.Details.IncomeItems[0];
incomeItem.Name.Should().Be("工资");
incomeItem.BudgetLimit.Should().Be(10000);
incomeItem.ActualAmount.Should().Be(10000);
incomeItem.EffectiveAmount.Should().Be(10000);
incomeItem.CalculationNote.Should().Be("使用实际");
// 验证支出明细
result.Details.ExpenseItems.Should().HaveCount(2);
// 餐饮超支
var expenseItem1 = result.Details.ExpenseItems.FirstOrDefault(e => e.Name == "餐饮");
expenseItem1.Should().NotBeNull();
expenseItem1!.BudgetLimit.Should().Be(2000);
expenseItem1.ActualAmount.Should().Be(2500);
expenseItem1.EffectiveAmount.Should().Be(2500); // MAX(2000, 2500)
expenseItem1.CalculationNote.Should().Be("使用实际(超支)");
expenseItem1.IsOverBudget.Should().BeTrue();
// 房租按天折算硬性消费在实际为0时会自动填充
var expenseItem2 = result.Details.ExpenseItems.FirstOrDefault(e => e.Name == "房租");
expenseItem2.Should().NotBeNull();
expenseItem2!.BudgetLimit.Should().Be(3000);
// 硬性消费在 GetForMonthAsync 中已经填充了按天折算的值到 current
expenseItem2.ActualAmount.Should().BeApproximately(3000m / 29 * 15, 0.01m);
// EffectiveAmount 使用 MAX(预算3000, 实际1551.72) = 3000
expenseItem2.EffectiveAmount.Should().Be(3000);
expenseItem2.CalculationNote.Should().Be("使用预算"); // MAX 后选择了预算值
// 验证汇总
result.Details.Summary.Should().NotBeNull();
result.Details.Summary.TotalIncomeBudget.Should().BeApproximately(10000, 0.01m);
// 支出汇总餐饮2500 + 房租3000(MAX) = 5500
result.Details.Summary.TotalExpenseBudget.Should().BeApproximately(5500, 1m);
result.Details.Summary.PlannedSavings.Should().BeApproximately(4500, 1m);
}
[Fact]
public async Task GetSavings_月度_年度收支_Test()
{
// Arrange
var referenceDate = new DateTime(2024, 1, 1);
var budgets = new List<BudgetRecord>
{
new()
{
Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 10000, Category = BudgetCategory.Income,
SelectedCategories = "工资"
},
new()
{
Id = 2, Name = "餐饮", Type = BudgetPeriodType.Month, Limit = 2000, Category = BudgetCategory.Expense,
SelectedCategories = "餐饮"
},
new()
{
Id = 3, Name = "年终奖", Type = BudgetPeriodType.Year, Limit = 50000, Category = BudgetCategory.Income,
SelectedCategories = "奖金"
},
new()
{
Id = 4, Name = "保险", Type = BudgetPeriodType.Year, Limit = 6000, Category = BudgetCategory.Expense,
SelectedCategories = "保险"
}
};
var transactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 10000m },
{ ("餐饮", TransactionType.Expense), 1500m },
{ ("奖金", TransactionType.Income), 50000m },
{ ("保险", TransactionType.Expense), 6000m }
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(transactions);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Month, referenceDate);
// Assert
result.Should().NotBeNull();
// 计划收入 = 月度计划收入(10000) + 本月发生的年度实际收入(50000) = 60000
// 计划支出 = 月度计划支出(2000) + 本月发生的年度实际支出(6000) = 8000
// 计划存款 = 60000 - 8000 = 52000
result.Limit.Should().Be(60000 - 8000);
}
[Fact]
public async Task GetSavings_月度_年度收支_硬性收支_Test()
{
// Arrange
// 模拟当前日期为 2026-01-20
var now = new DateTime(2026, 1, 20);
_dateTimeProvider.Now.Returns(now);
var referenceDate = new DateTime(2026, 1, 1);
var budgets = new List<BudgetRecord>
{
// 房租 3100硬性支出。假设目前还没付实际为0系统应按 20/31 天估算为 2000
new()
{
Id = 1, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3100, Category = BudgetCategory.Expense,
SelectedCategories = "房租", IsMandatoryExpense = true
},
// 理财收益 6200硬性收入。假设目前还没到账实际为0系统应按 20/31 天估算为 4000
new()
{
Id = 2, Name = "理财收益", Type = BudgetPeriodType.Month, Limit = 6200, Category = BudgetCategory.Income,
SelectedCategories = "理财", IsMandatoryExpense = true
}
};
// 模拟实际交易为 0
var transactions = new Dictionary<(string, TransactionType), decimal>();
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(transactions);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Month, referenceDate);
// Assert
// 2026年1月有31天当前是20号
// 预期的估算值:
// 支出 = 3100 / 31 * 20 = 2000
// 收入 = 6200 / 31 * 20 = 4000
result.Should().NotBeNull();
// 计划存款 = 计划收入(6200) - 计划支出(3100) = 3100
result.Limit.Should().Be(6200 - 3100);
}
[Fact]
public async Task GetSavings_年度_预算_实际_Test()
{
// Arrange
var year = 2024;
var referenceDate = new DateTime(year, 1, 1);
_dateTimeProvider.Now.Returns(new DateTime(year, 1, 20));
var budgets = new List<BudgetRecord>
{
new() { Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 10000, Category = BudgetCategory.Income, SelectedCategories = "工资" },
new() { Id = 2, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3000, Category = BudgetCategory.Expense, SelectedCategories = "房租" },
new() { Id = 3, Name = "年终奖", Type = BudgetPeriodType.Year, Limit = 50000, Category = BudgetCategory.Income, SelectedCategories = "奖金" },
new() { Id = 4, Name = "旅游", Type = BudgetPeriodType.Year, Limit = 20000, Category = BudgetCategory.Expense, SelectedCategories = "旅游" }
};
var transactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 10000m },
{ ("房租", TransactionType.Expense), 3000m },
{ ("存款", TransactionType.None), 2000m }
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(transactions);
_budgetArchiveRepository.GetArchivesByYearAsync(year).Returns(new List<BudgetArchive>());
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Year, referenceDate);
// Assert
result.Should().NotBeNull();
// MonthlyIncome: 10000 * 12 = 170000
// MonthlyExpense: 3000 * 12 = 56000
// YearlyIncome: 50000 * 1 = 50000
// YearlyExpense: 20000 * 1 = 20000
// Savings: (170000 + 50000) - (56000 + 20000) = 114000
result.Limit.Should().Be(114000);
result.Current.Should().Be(2000);
result.Name.Should().Be("年度存款计划");
}
[Fact]
public async Task GetSavings_年度_归档盈亏_Test()
{
// Arrange
var year = 2024;
// 当前是3月15号
_dateTimeProvider.Now.Returns(new DateTime(year, 3, 15));
var budgets = new List<BudgetRecord>
{
// Monthly Budget changed from 10000 (Jan) to 11000 (Current/Feb)
new() { Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 11000, Category = BudgetCategory.Income, SelectedCategories = "工资" },
new() { Id = 2, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3000, Category = BudgetCategory.Expense, SelectedCategories = "房租" },
};
var currentTransactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 11000m }
};
var archives = new List<BudgetArchive>
{
new()
{
Year = year, Month = 1,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 10000,
Actual = 12000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 3600,
Category = BudgetCategory.Expense
}
]
},
new()
{
Year = year, Month = 2,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 11000,
Actual = 3000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 5000,
Category = BudgetCategory.Expense
}
]
}
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(currentTransactions);
_budgetArchiveRepository.GetArchivesByYearAsync(year).Returns(archives);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Year, new DateTime(year, 1, 1));
// Assert
result.Should().NotBeNull();
// 归档实际收入1月 = 12000 - 3600 = 8400
// 归档实际收入2月 = 3000 - 5000 = -2000
// 预计收入 = 8400 + -2000 + 11000 * 10 = 116400
// 预计支出 = 3000 * 10 = 30000
// 预计存款 = 116400 - 30000 = 86400
result.Limit.Should().Be(86400);
}
[Fact]
public async Task GetSavings_年度_硬性收支_Test()
{
// Arrange
var year = 2024;
// 当前是3月15号
_dateTimeProvider.Now.Returns(new DateTime(year, 3, 15));
var budgets = new List<BudgetRecord>
{
// Monthly Budget changed from 10000 (Jan) to 11000 (Current/Feb)
new() { Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 11000, Category = BudgetCategory.Income, SelectedCategories = "工资" },
new() { Id = 2, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3000, Category = BudgetCategory.Expense, SelectedCategories = "房租" },
new() { Id = 3, Name = "硬性支出", Type = BudgetPeriodType.Year, Limit = 10000, Category = BudgetCategory.Expense, SelectedCategories = "房租", IsMandatoryExpense = true },
};
var currentTransactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 11000m }
};
var archives = new List<BudgetArchive>
{
new()
{
Year = year, Month = 1,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 10000,
Actual = 12000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 3600,
Category = BudgetCategory.Expense
}
]
},
new()
{
Year = year, Month = 2,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 11000,
Actual = 3000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 5000,
Category = BudgetCategory.Expense
}
]
}
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(currentTransactions);
_budgetArchiveRepository.GetArchivesByYearAsync(year).Returns(archives);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Year, new DateTime(year, 1, 1));
// Assert
result.Should().NotBeNull();
// 归档实际收入1月 = 12000 - 3600 = 8400
// 归档实际收入2月 = 3000 - 5000 = -2000
// 预计收入 = 8400 + -2000 + 11000 * 10 = 116400
// 硬性支出平均到每天 = 10000 / 366 * 75 = 2049.18
// 预计支出 = 3000 * 10 = 30000
// 预计存款 = 116400 - 30000 - 2049.18 = 84350.82
result.Limit.Should().BeApproximately(84350.82m, 0.01m);
}
[Fact]
public async Task GetSavings_年度_不限额_Test()
{
// Arrange
var year = 2024;
// 当前是3月15号
_dateTimeProvider.Now.Returns(new DateTime(year, 3, 15));
var budgets = new List<BudgetRecord>
{
// Monthly Budget changed from 10000 (Jan) to 11000 (Current/Feb)
new() { Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 11000, Category = BudgetCategory.Income, SelectedCategories = "工资" },
new() { Id = 2, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3000, Category = BudgetCategory.Expense, SelectedCategories = "房租" },
new() { Id = 3, Name = "硬性支出", Type = BudgetPeriodType.Year, Limit = 10000, Category = BudgetCategory.Expense, SelectedCategories = "房租", IsMandatoryExpense = true },
new() { Id = 4, Name = "意外支出", Type = BudgetPeriodType.Year, Limit = 0, Category = BudgetCategory.Expense, SelectedCategories = "意外支出", NoLimit = true },
new() { Id = 5, Name = "意外收入", Type = BudgetPeriodType.Month, Limit = 0, Category = BudgetCategory.Income, SelectedCategories = "意外收入", NoLimit = true }
};
var currentTransactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 11000m },
{ ("意外支出", TransactionType.Expense), 300m },
{ ("意外收入", TransactionType.Income), 2000m },
};
var archives = new List<BudgetArchive>
{
new()
{
Year = year, Month = 1,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 10000,
Actual = 12000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 3600,
Category = BudgetCategory.Expense
}
]
},
new()
{
Year = year, Month = 2,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 11000,
Actual = 3000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 5000,
Category = BudgetCategory.Expense
}
]
}
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(currentTransactions);
_budgetArchiveRepository.GetArchivesByYearAsync(year).Returns(archives);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("存款"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Year, new DateTime(year, 1, 1));
// Assert
result.Should().NotBeNull();
// 归档实际收入1月 = 12000 - 3600 = 8400
// 归档实际收入2月 = 3000 - 5000 = -2000
// 预计收入 = 8400 + -2000 + 11000 * 10 = 116400
// 硬性支出平均到每天 = 10000 / 366 * 75 = 2049.18
// 预计支出 = 3000 * 10 = 30000
// 预计意外支出 = 300
// 预计意外收入 = 2000
// 预计存款 = 116400 - 30000 - 2049.18 - 300 + 2000 = 86050.82
result.Limit.Should().BeApproximately(86050.82m, 0.1m);
}
[Fact]
public async Task GetSavings_年度_包含一月份归档存款_Test()
{
// Arrange
var year = 2026;
// 当前是2月11号
_dateTimeProvider.Now.Returns(new DateTime(year, 2, 11));
var budgets = new List<BudgetRecord>
{
// 月度预算
new() { Id = 1, Name = "工资", Type = BudgetPeriodType.Month, Limit = 11000, Category = BudgetCategory.Income, SelectedCategories = "工资" },
new() { Id = 2, Name = "房租", Type = BudgetPeriodType.Month, Limit = 3000, Category = BudgetCategory.Expense, SelectedCategories = "房租" }
};
// 当前月2月的交易数据
var currentTransactions = new Dictionary<(string, TransactionType), decimal>
{
{ ("工资", TransactionType.Income), 11000m },
{ ("房租", TransactionType.Expense), 3000m },
{ ("转账到公共", TransactionType.Expense), 5000m } // 2月份实际存款5000元
};
// 一月份的归档数据
var archives = new List<BudgetArchive>
{
new()
{
Year = year, Month = 1,
Content =
[
new BudgetArchiveContent
{
Id = 1,
Name = "工资",
Type = BudgetPeriodType.Month,
Limit = 11000,
Actual = 11000,
Category = BudgetCategory.Income
},
new BudgetArchiveContent
{
Id = 2,
Name = "房租",
Type = BudgetPeriodType.Month,
Limit = 3000,
Actual = 3000,
Category = BudgetCategory.Expense
},
new BudgetArchiveContent
{
Id = -2,
Name = "月度存款计划",
Type = BudgetPeriodType.Month,
Limit = 6287.34m,
Actual = 9600.0m, // ✅ 一月份实际存款9600元
Category = BudgetCategory.Savings
}
]
}
};
_budgetRepository.GetAllAsync().Returns(budgets);
_transactionStatisticsService.GetAmountGroupByClassifyAsync(Arg.Any<DateTime>(), Arg.Any<DateTime>())
.Returns(currentTransactions);
_budgetArchiveRepository.GetArchivesByYearAsync(year).Returns(archives);
_configService.GetConfigByKeyAsync<string>("SavingsCategories").Returns(Task.FromResult<string?>("转账到公共"));
// Act
var result = await _service.GetSavingsDtoAsync(BudgetPeriodType.Year, new DateTime(year, 1, 1));
// Assert
result.Should().NotBeNull();
// 年度已存款 = 一月份归档存款9600 + 二月份当前存款5000 = 14600
result.Current.Should().Be(14600m);
}
}