fix
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 31s
Docker Build & Deploy / Deploy to Production (push) Successful in 7s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 31s
Docker Build & Deploy / Deploy to Production (push) Successful in 7s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
This commit is contained in:
@@ -426,6 +426,7 @@ public class BudgetSavingsService(
|
||||
// 归档的预算收入支出明细
|
||||
var archiveIncomeItems = new List<(long id, string name, int[] months, decimal limit, decimal current)>();
|
||||
var archiveExpenseItems = new List<(long id, string name, int[] months, decimal limit, decimal current)>();
|
||||
var archiveSavingsItems = new List<(long id, string name, int[] months, decimal limit, decimal current)>();
|
||||
// 获取归档数据
|
||||
var archives = await budgetArchiveRepository.GetArchivesByYearAsync(year);
|
||||
var archiveBudgetGroups = archives
|
||||
@@ -440,6 +441,7 @@ public class BudgetSavingsService(
|
||||
{
|
||||
BudgetCategory.Income => archiveIncomeItems,
|
||||
BudgetCategory.Expense => archiveExpenseItems,
|
||||
BudgetCategory.Savings => archiveSavingsItems,
|
||||
_ => throw new NotSupportedException($"Category {archive.Category} is not supported.")
|
||||
};
|
||||
|
||||
@@ -663,7 +665,62 @@ public class BudgetSavingsService(
|
||||
""");
|
||||
}
|
||||
#endregion
|
||||
#region 构建归档存款明细表格
|
||||
var archiveSavingsDiff = 0m;
|
||||
if (archiveSavingsItems.Any())
|
||||
{
|
||||
description.AppendLine("<h3>已归档存款明细</h3>");
|
||||
description.AppendLine("""
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>预算</th>
|
||||
<th>月</th>
|
||||
<th>合计</th>
|
||||
<th>实际</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
""");
|
||||
|
||||
// 已归档的存款
|
||||
foreach (var (_, name, months, limit, current) in archiveSavingsItems)
|
||||
{
|
||||
description.AppendLine($"""
|
||||
<tr>
|
||||
<td>{name}</td>
|
||||
<td>{(limit == 0 ? "不限额" : limit.ToString("N0"))}</td>
|
||||
<td>{FormatMonths(months)}</td>
|
||||
<td>{limit * months.Length:N0}</td>
|
||||
<td><span class='income-value'>{current:N0}</span></td>
|
||||
</tr>
|
||||
""");
|
||||
}
|
||||
description.AppendLine("</tbody></table>");
|
||||
|
||||
archiveSavingsDiff = archiveSavingsItems.Sum(i => i.current) - archiveSavingsItems.Sum(i => i.limit * i.months.Length);
|
||||
description.AppendLine($"""
|
||||
<p>
|
||||
<span class="highlight">已归档存款总结: </span>
|
||||
{(archiveSavingsDiff > 0 ? "超额存款" : "未达预期")}:
|
||||
<span class='{(archiveSavingsDiff > 0 ? "income-value" : "expense-value")}'>
|
||||
<strong>{archiveSavingsDiff:N0}</strong>
|
||||
</span>
|
||||
=
|
||||
实际存款合计:
|
||||
<span class='income-value'>
|
||||
<strong>{archiveSavingsItems.Sum(i => i.current):N0}</strong>
|
||||
</span>
|
||||
-
|
||||
预算存款合计:
|
||||
<span class='income-value'>
|
||||
<strong>{archiveSavingsItems.Sum(i => i.limit * i.months.Length):N0}</strong>
|
||||
</span>
|
||||
</p>
|
||||
""");
|
||||
}
|
||||
#endregion
|
||||
#region 构建当前年度预算支出明细表格
|
||||
description.AppendLine("<h3>预算支出明细</h3>");
|
||||
description.AppendLine("""
|
||||
@@ -723,7 +780,10 @@ public class BudgetSavingsService(
|
||||
#region 总结
|
||||
var archiveIncomeBudget = archiveIncomeItems.Sum(i => i.limit * i.months.Length);
|
||||
var archiveExpenseBudget = archiveExpenseItems.Sum(i => i.limit * i.months.Length);
|
||||
var archiveSavings = archiveIncomeBudget - archiveExpenseBudget + archiveIncomeDiff + archiveExpenseDiff;
|
||||
// 如果有归档存款数据,直接使用;否则用收入-支出计算
|
||||
var archiveSavings = archiveSavingsItems.Any()
|
||||
? archiveSavingsItems.Sum(i => i.current)
|
||||
: archiveIncomeBudget - archiveExpenseBudget + archiveIncomeDiff + archiveExpenseDiff;
|
||||
|
||||
var expectedIncome = currentMonthlyIncomeItems.Sum(i => i.limit == 0 ? i.current : i.limit * i.factor) + currentYearlyIncomeItems.Sum(i => i.isMandatory || i.limit == 0 ? i.current : i.limit);
|
||||
var expectedExpense = currentMonthlyExpenseItems.Sum(i => i.limit == 0 ? i.current : i.limit * i.factor) + currentYearlyExpenseItems.Sum(i => i.isMandatory || i.limit == 0 ? i.current : i.limit);
|
||||
|
||||
@@ -525,7 +525,9 @@ public class BudgetStatsService(
|
||||
logger.LogDebug("获取到 {Count} 个当前有效预算", currentBudgetsDict.Count);
|
||||
|
||||
// 用于跟踪已处理的预算ID,避免重复
|
||||
// 对于年度预算,只添加一次;对于月度预算,跟踪 (Id, Month) 组合
|
||||
var processedBudgetIds = new HashSet<long>();
|
||||
var processedMonthlyBudgetKeys = new HashSet<(long Id, int Month)>();
|
||||
|
||||
// 1. 处理历史归档月份(1月到当前月-1)
|
||||
if (referenceDate.Year == now.Year && now.Month > 1)
|
||||
@@ -544,6 +546,9 @@ public class BudgetStatsService(
|
||||
// 对于月度预算,每个月都添加一个归档项
|
||||
if (item.Type == BudgetPeriodType.Month)
|
||||
{
|
||||
// 记录已处理的月度预算
|
||||
processedMonthlyBudgetKeys.Add((item.Id, m));
|
||||
|
||||
result.Add(new BudgetStatsItem
|
||||
{
|
||||
Id = item.Id,
|
||||
@@ -612,30 +617,40 @@ public class BudgetStatsService(
|
||||
logger.LogInformation("添加当前年度预算: {BudgetName} - 预算金额: {Limit}, 实际金额: {Current}",
|
||||
budget.Name, budget.Limit, currentAmount);
|
||||
}
|
||||
// 对于月度预算,仅添加当前月的预算项
|
||||
// 对于月度预算,仅添加当前月的预算项(如果还没有从归档中添加)
|
||||
else if (budget.Type == BudgetPeriodType.Month)
|
||||
{
|
||||
// 只计算当前月的实际值
|
||||
var currentAmount = await CalculateCurrentAmountAsync(budget, BudgetPeriodType.Month, referenceDate);
|
||||
result.Add(new BudgetStatsItem
|
||||
// 检查当前月是否已经从归档中添加过
|
||||
if (!processedMonthlyBudgetKeys.Contains((budget.Id, now.Month)))
|
||||
{
|
||||
Id = budget.Id,
|
||||
Name = budget.Name,
|
||||
Type = budget.Type,
|
||||
Limit = budget.Limit, // 月度预算的原始限额
|
||||
Current = currentAmount, // 当前月的实际值
|
||||
Category = budget.Category,
|
||||
SelectedCategories = string.IsNullOrEmpty(budget.SelectedCategories)
|
||||
? []
|
||||
: budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries),
|
||||
NoLimit = budget.NoLimit,
|
||||
IsMandatoryExpense = budget.IsMandatoryExpense,
|
||||
IsArchive = false,
|
||||
// 标记这是当前月的月度预算,用于年度限额计算
|
||||
IsCurrentMonth = true
|
||||
});
|
||||
logger.LogInformation("添加当前月的月度预算: {BudgetName} - 月度限额: {Limit}, 当前月实际值: {Current}",
|
||||
budget.Name, budget.Limit, currentAmount);
|
||||
// 只计算当前月的实际值(使用真实的当前月日期,而不是referenceDate)
|
||||
var currentMonthDate = new DateTime(now.Year, now.Month, 1);
|
||||
var currentAmount = await CalculateCurrentAmountAsync(budget, BudgetPeriodType.Month, currentMonthDate);
|
||||
result.Add(new BudgetStatsItem
|
||||
{
|
||||
Id = budget.Id,
|
||||
Name = budget.Name,
|
||||
Type = budget.Type,
|
||||
Limit = budget.Limit, // 月度预算的原始限额
|
||||
Current = currentAmount, // 当前月的实际值
|
||||
Category = budget.Category,
|
||||
SelectedCategories = string.IsNullOrEmpty(budget.SelectedCategories)
|
||||
? []
|
||||
: budget.SelectedCategories.Split(',', StringSplitOptions.RemoveEmptyEntries),
|
||||
NoLimit = budget.NoLimit,
|
||||
IsMandatoryExpense = budget.IsMandatoryExpense,
|
||||
IsArchive = false,
|
||||
// 标记这是当前月的月度预算,用于年度限额计算
|
||||
IsCurrentMonth = true
|
||||
});
|
||||
logger.LogInformation("添加当前月的月度预算: {BudgetName} - 月度限额: {Limit}, 当前月实际值: {Current}, 计算日期: {CalculateDate:yyyy-MM}",
|
||||
budget.Name, budget.Limit, currentAmount, currentMonthDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("跳过已从归档添加的当前月月度预算: {BudgetName} - {Month}月",
|
||||
budget.Name, now.Month);
|
||||
}
|
||||
|
||||
// 如果还有剩余月份(未来月份),再添加一项作为未来的预算占位
|
||||
var remainingMonths = 12 - now.Month;
|
||||
@@ -1138,9 +1153,10 @@ public class BudgetStatsService(
|
||||
{
|
||||
var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Year, referenceDate);
|
||||
var typeStr = budget.IsCurrentMonth ? "当前月" : "未来月";
|
||||
// 修正:当前月是1个月,未来月是剩余月份数量
|
||||
var calcStr = budget.IsCurrentMonth
|
||||
? $"1月×{budget.Limit:N0}"
|
||||
: $"{budget.RemainingMonths}月×{budget.Limit:N0}";
|
||||
? $"1个月×{budget.Limit:N0}"
|
||||
: $"{budget.RemainingMonths}个月×{budget.Limit:N0}";
|
||||
|
||||
description.AppendLine($"""
|
||||
<tr>
|
||||
@@ -1211,11 +1227,11 @@ public class BudgetStatsService(
|
||||
var budgetLimit = CalculateBudgetLimit(budget, BudgetPeriodType.Year, referenceDate);
|
||||
if (budget.IsCurrentMonth)
|
||||
{
|
||||
limitParts.Add($"{budget.Name}(当前月×{budget.Limit:N0}={budgetLimit:N0})");
|
||||
limitParts.Add($"{budget.Name}(当前月1个月×{budget.Limit:N0}={budgetLimit:N0})");
|
||||
}
|
||||
else
|
||||
{
|
||||
limitParts.Add($"{budget.Name}(剩余{budget.RemainingMonths}月×{budget.Limit:N0}={budgetLimit:N0})");
|
||||
limitParts.Add($"{budget.Name}(未来{budget.RemainingMonths}个月×{budget.Limit:N0}={budgetLimit:N0})");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,22 @@ public class TransactionStatisticsService(
|
||||
{
|
||||
public async Task<Dictionary<string, (int count, decimal expense, decimal income, decimal saving)>> GetDailyStatisticsAsync(int year, int month, string? savingClassify = null)
|
||||
{
|
||||
var startDate = new DateTime(year, month, 1);
|
||||
var endDate = startDate.AddMonths(1);
|
||||
// 当 month=0 时,表示查询整年数据
|
||||
DateTime startDate;
|
||||
DateTime endDate;
|
||||
|
||||
if (month == 0)
|
||||
{
|
||||
// 查询整年:1月1日至12月31日
|
||||
startDate = new DateTime(year, 1, 1);
|
||||
endDate = new DateTime(year, 12, 31).AddDays(1); // 包含12月31日
|
||||
}
|
||||
else
|
||||
{
|
||||
// 查询指定月份
|
||||
startDate = new DateTime(year, month, 1);
|
||||
endDate = startDate.AddMonths(1);
|
||||
}
|
||||
|
||||
return await GetDailyStatisticsByRangeAsync(startDate, endDate, savingClassify);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user