From a06a75ee97ee5084ab9864125ab7e516d3d077f9 Mon Sep 17 00:00:00 2001 From: SunCheng Date: Thu, 22 Jan 2026 11:06:52 +0800 Subject: [PATCH] fix --- Service/Budget/BudgetService.cs | 21 +++++---- WebApi.Test/Budget/BudgetTest.cs | 79 ++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/Service/Budget/BudgetService.cs b/Service/Budget/BudgetService.cs index f7da49c..8dcdf1f 100644 --- a/Service/Budget/BudgetService.cs +++ b/Service/Budget/BudgetService.cs @@ -1,4 +1,4 @@ -namespace Service.Budget; +namespace Service.Budget; public interface IBudgetService { @@ -183,6 +183,12 @@ public class BudgetService( .Where(b => b.Category == category && !b.NoLimit) .ToList(); + // 月度统计中,只包含月度预算;年度统计中,包含所有预算 + if (statType == BudgetPeriodType.Month) + { + relevant = relevant.Where(b => b.Type == BudgetPeriodType.Month).ToList(); + } + if (relevant.Count == 0) { return result; @@ -204,12 +210,7 @@ public class BudgetService( { // 限额折算 var itemLimit = budget.Limit; - if (statType == BudgetPeriodType.Month && budget.Type == BudgetPeriodType.Year) - { - // 月度视图下,年度预算不参与限额计算 - itemLimit = 0; - } - else if (statType == BudgetPeriodType.Year && budget.Type == BudgetPeriodType.Month) + if (statType == BudgetPeriodType.Year && budget.Type == BudgetPeriodType.Month) { // 年度视图下,月度预算折算为年度 itemLimit = budget.Limit * 12; @@ -229,13 +230,13 @@ public class BudgetService( IsMandatoryExpense = budget.IsMandatoryExpense }, referenceDate); - if (budget.Type == statType) + if (statType == BudgetPeriodType.Month) { totalCurrent += currentAmount; } - else if (statType == BudgetPeriodType.Year && budget.Type == BudgetPeriodType.Month) + else if (statType == BudgetPeriodType.Year) { - // 年度视图下,月度预算计入其当前值(作为对年度目前的贡献) + // 年度视图下,累加所有预算的当前值 totalCurrent += currentAmount; } } diff --git a/WebApi.Test/Budget/BudgetTest.cs b/WebApi.Test/Budget/BudgetTest.cs index 95cd087..2a19ccc 100644 --- a/WebApi.Test/Budget/BudgetTest.cs +++ b/WebApi.Test/Budget/BudgetTest.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Common; namespace WebApi.Test.Budget; @@ -55,10 +55,8 @@ public class BudgetTest : BaseTest var result = await _service.GetCategoryStatsAsync(BudgetCategory.Expense, referenceDate); // Assert - result.Month.Limit.Should().Be(2500); - result.Month.Current.Should().Be(1500); - result.Month.Count.Should().Be(2); - result.Month.Rate.Should().Be(1500m / 2500m * 100); + result.Month.Limit.Should().Be(2500); // 吃喝2000 + 交通500 + result.Month.Current.Should().Be(1500); // 吃喝1200 + 交通300 } [Fact] @@ -169,4 +167,75 @@ public class BudgetTest : BaseTest result.Year.Limit.Should().Be(3660); result.Year.Current.Should().Be(910); } + + [Fact] + public async Task GetCategoryStats_月度_发生年度收支_Test() + { + // Arrange + var referenceDate = new DateTime(2024, 1, 15); + + // 设置预算:包含月度预算和年度预算 + var budgets = new List + { + // 月度预算:吃喝 + new() { Id = 1, Name = "吃喝", Limit = 2000, Category = BudgetCategory.Expense, Type = BudgetPeriodType.Month, SelectedCategories = "餐饮,零食" }, + + // 月度预算:交通 + new() { Id = 2, Name = "交通", Limit = 500, Category = BudgetCategory.Expense, Type = BudgetPeriodType.Month, SelectedCategories = "交通" }, + + // 年度预算:年度旅游(当前月度发生了相关支出) + new() { Id = 3, Name = "年度旅游", Limit = 12000, Category = BudgetCategory.Expense, Type = BudgetPeriodType.Year, SelectedCategories = "旅游,度假" }, + + // 年度预算:年度奖金(当前月度发生了相关收入) + new() { Id = 4, Name = "年度奖金", Limit = 50000, Category = BudgetCategory.Income, Type = BudgetPeriodType.Year, SelectedCategories = "奖金,年终奖" } + }; + + _budgetRepository.GetAllAsync().Returns(budgets); + + // 设置月度预算的当前金额 + _budgetRepository.GetCurrentAmountAsync(Arg.Any(), Arg.Any(), Arg.Any()) + .Returns(args => + { + var b = (BudgetRecord)args[0]; + return b.Name switch + { + "吃喝" => 1200m, // 月度预算:已用1200元 + "交通" => 300m, // 月度预算:已用300元 + "年度旅游" => 2000m, // 年度预算:1月份已用2000元 + "年度奖金" => 10000m, // 年度预算:1月份已收10000元 + _ => 0m + }; + }); + + // 设置趋势统计数据为空(简化测试) + _transactionsRepository.GetFilteredTrendStatisticsAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any>(), Arg.Any()) + .Returns(new Dictionary()); + + // Act - 测试支出统计 + var expenseResult = await _service.GetCategoryStatsAsync(BudgetCategory.Expense, referenceDate); + + // Act - 测试收入统计 + var incomeResult = await _service.GetCategoryStatsAsync(BudgetCategory.Income, referenceDate); + + // Assert - 支出月度统计:只包含月度预算 + expenseResult.Month.Limit.Should().Be(2500); // 吃喝2000 + 交通500 + expenseResult.Month.Current.Should().Be(1500); // 吃喝1200 + 交通300 + expenseResult.Month.Count.Should().Be(2); // 只包含2个月度预算 + expenseResult.Month.Rate.Should().Be(1500m / 2500m * 100); // 60% + + // Assert - 支出年度统计:包含所有预算(月度+年度) + expenseResult.Year.Limit.Should().Be(12000 + (2500 * 12)); // 年度旅游12000 + 月度预算折算为年度(2500*12) + expenseResult.Year.Current.Should().Be(2000 + 1500); // 年度旅游2000 + 月度预算1500 + expenseResult.Year.Count.Should().Be(3); // 包含3个预算(2个月度+1个年度) + + // Assert - 收入月度统计:只包含月度预算(这里没有月度收入预算,所以应该为0) + incomeResult.Month.Limit.Should().Be(0); // 没有月度收入预算 + incomeResult.Month.Current.Should().Be(0); // 没有月度收入预算 + incomeResult.Month.Count.Should().Be(0); // 没有月度收入预算 + + // Assert - 收入年度统计:包含所有预算(只有年度收入预算) + incomeResult.Year.Limit.Should().Be(50000); // 年度奖金50000 + incomeResult.Year.Current.Should().Be(10000); // 年度奖金已收10000 + incomeResult.Year.Count.Should().Be(1); // 包含1个年度收入预算 + } } \ No newline at end of file