Bookings like "Narbonne Car" and "Narbonne Food" should roll up into one series/slice instead of staying separate, so grouping now uses the text up to the first space via TransactionDataset.GetTextGroup().
152 lines
6.1 KiB
C#
152 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Schaad.Accounting.Datasets;
|
|
using Schaad.Accounting.Datasets.Charts;
|
|
using Schaad.Accounting.Interfaces;
|
|
|
|
namespace Schaad.Accounting.Services
|
|
{
|
|
public class ChartService : IChartService
|
|
{
|
|
private readonly ISettingsService settingsService;
|
|
private readonly IViewService viewService;
|
|
|
|
public ChartService(ISettingsService settingsService, IViewService viewService)
|
|
{
|
|
this.settingsService = settingsService;
|
|
this.viewService = viewService;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<DataSerie>> GetExpensesPerMonthAsync()
|
|
{
|
|
var expenseTransactions = (await viewService.GetTransactionViewListAsync())
|
|
.Where(t => t.TargetAccount.Class == ClassIds.Expenses)
|
|
.ToList();
|
|
|
|
var distinctSubClasses = expenseTransactions
|
|
.Select(t => t.TargetAccount.SubClass)
|
|
.Distinct()
|
|
.Count();
|
|
|
|
return distinctSubClasses > 1
|
|
? await GetSubClassExpensesPerMonthAsync(expenseTransactions)
|
|
: await GetAccountExpensesPerMonthAsync();
|
|
}
|
|
|
|
private async Task<List<DataSerie>> GetSubClassExpensesPerMonthAsync(List<TransactionDataset> expenseTransactions)
|
|
{
|
|
var year = settingsService.GetYear();
|
|
var maxMonth = expenseTransactions
|
|
.OrderByDescending(t => t.ValueDate)
|
|
.FirstOrDefault()?.ValueDate.Month ?? 12;
|
|
|
|
var subClassNameByNumber = (await viewService.GetAccountViewListAsync())
|
|
.GroupBy(a => a.SubClass)
|
|
.ToDictionary(g => g.Key, g => g.First().SubClassName);
|
|
|
|
var list = new List<DataSerie>();
|
|
foreach (var grp in expenseTransactions.GroupBy(t => t.TargetAccount.SubClass))
|
|
{
|
|
var groupedByMonth = grp
|
|
.GroupBy(t => t.ValueDate.Month)
|
|
.ToDictionary(g => g.Key, g => g.Sum(t => t.GetValue(t.TargetAccount.IsFxAccount)));
|
|
EnsureEntryForEveryMonth(groupedByMonth, maxMonth);
|
|
|
|
list.Add(new DataSerie(
|
|
Id: grp.Key.ToString(),
|
|
Name: subClassNameByNumber[grp.Key],
|
|
X: groupedByMonth.OrderBy(g => g.Key).Select(g => new DateOnly(year, g.Key, 1)).ToList(),
|
|
Y: groupedByMonth.OrderBy(g => g.Key).Select(g => g.Value).ToList()
|
|
));
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private async Task<List<DataSerie>> GetAccountExpensesPerMonthAsync()
|
|
{
|
|
var year = settingsService.GetYear();
|
|
var allTransactions = await viewService.GetTransactionViewListAsync();
|
|
var expenseAccounts = (await viewService.GetAccountViewListAsync()).Where(a => a.Class == ClassIds.Expenses);
|
|
|
|
var list = new List<DataSerie>();
|
|
foreach (var account in expenseAccounts)
|
|
{
|
|
var transactions = allTransactions.Where(t => t.TargetAccountId == account.Id).ToList();
|
|
if (transactions.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var maxMonth = transactions.Max(t => t.ValueDate.Month);
|
|
var groupedByMonth = transactions
|
|
.GroupBy(t => t.ValueDate.Month)
|
|
.ToDictionary(g => g.Key, g => g.Sum(t => t.GetValue(account.IsFxAccount)));
|
|
EnsureEntryForEveryMonth(groupedByMonth, maxMonth);
|
|
|
|
list.Add(new DataSerie(
|
|
Id: account.Id,
|
|
Name: account.Name,
|
|
X: groupedByMonth.OrderBy(g => g.Key).Select(g => new DateOnly(year, g.Key, 1)).ToList(),
|
|
Y: groupedByMonth.OrderBy(g => g.Key).Select(g => g.Value).ToList()
|
|
));
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<DataSerie>> GetBookingTextExpensesPerMonthAsync(string accountId)
|
|
{
|
|
var account = await viewService.GetAccountViewAsync(accountId);
|
|
var transactions = await viewService.GetTransactionViewListAsync(accountId);
|
|
if (transactions.Count == 0)
|
|
{
|
|
return new List<DataSerie>();
|
|
}
|
|
|
|
var year = settingsService.GetYear();
|
|
var maxMonth = transactions.Max(t => t.ValueDate.Month);
|
|
|
|
var list = new List<DataSerie>();
|
|
foreach (var grp in transactions.GroupBy(t => t.GetTextGroup()))
|
|
{
|
|
var groupedByMonth = grp
|
|
.GroupBy(t => t.ValueDate.Month)
|
|
.ToDictionary(g => g.Key, g => g.Sum(t => t.GetValue(account.IsFxAccount, accountId)));
|
|
EnsureEntryForEveryMonth(groupedByMonth, maxMonth);
|
|
|
|
list.Add(new DataSerie(
|
|
Id: grp.Key,
|
|
Name: grp.Key,
|
|
X: groupedByMonth.OrderBy(g => g.Key).Select(g => new DateOnly(year, g.Key, 1)).ToList(),
|
|
Y: groupedByMonth.OrderBy(g => g.Key).Select(g => g.Value).ToList()
|
|
));
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<CategoryTotal>> GetBookingTextTotalsAsync(string accountId)
|
|
{
|
|
var account = await viewService.GetAccountViewAsync(accountId);
|
|
var transactions = await viewService.GetTransactionViewListAsync(accountId);
|
|
|
|
return transactions
|
|
.Where(t => t.TargetAccountId == accountId)
|
|
.GroupBy(t => t.GetTextGroup())
|
|
.Select(g => new CategoryTotal(g.Key, g.Sum(t => t.GetValue(account.IsFxAccount, accountId))))
|
|
.Where(c => c.Value != 0)
|
|
.ToList();
|
|
}
|
|
|
|
private static void EnsureEntryForEveryMonth(Dictionary<int, decimal> values, int maxMonth = 12)
|
|
{
|
|
for (int i = 1; i <= maxMonth; i++)
|
|
{
|
|
if (values.ContainsKey(i) == false)
|
|
{
|
|
values.Add(i, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|