123 lines
3.5 KiB
C#
123 lines
3.5 KiB
C#
using System.Collections.ObjectModel;
|
|
|
|
namespace BudgetApp.Domain.Models;
|
|
|
|
/// <summary>
|
|
/// Ledger aggregate containing all ledger entries.
|
|
/// Provides calculations and operations on entries.
|
|
/// </summary>
|
|
public class Ledger
|
|
{
|
|
private readonly List<LedgerEntry> _entries;
|
|
|
|
public ReadOnlyCollection<LedgerEntry> Entries => _entries.AsReadOnly();
|
|
|
|
public Ledger()
|
|
{
|
|
_entries = new List<LedgerEntry>();
|
|
}
|
|
|
|
public Ledger(IEnumerable<LedgerEntry> entries)
|
|
{
|
|
if (entries == null)
|
|
throw new ArgumentNullException(nameof(entries));
|
|
|
|
_entries = new List<LedgerEntry>(entries);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a ledger entry to the ledger.
|
|
/// </summary>
|
|
public void AddEntry(LedgerEntry entry)
|
|
{
|
|
if (entry == null)
|
|
throw new ArgumentNullException(nameof(entry));
|
|
|
|
entry.Validate();
|
|
_entries.Add(entry);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a ledger entry from the ledger.
|
|
/// </summary>
|
|
public void RemoveEntry(Guid entryId)
|
|
{
|
|
var entry = _entries.FirstOrDefault(e => e.Id == entryId);
|
|
if (entry != null)
|
|
{
|
|
_entries.Remove(entry);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all entries of a specific type.
|
|
/// </summary>
|
|
public IEnumerable<LedgerEntry> GetEntriesByType(EntryType type)
|
|
{
|
|
return _entries.Where(e => e.Type == type);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets entries within a date range.
|
|
/// </summary>
|
|
public IEnumerable<LedgerEntry> GetEntriesByDateRange(DateTime startDate, DateTime endDate)
|
|
{
|
|
return _entries.Where(e => e.Date >= startDate && e.Date <= endDate);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the total amount for entries of a specific type.
|
|
/// </summary>
|
|
public Money CalculateTotalByType(EntryType type, string currency)
|
|
{
|
|
var total = _entries
|
|
.Where(e => e.Type == type && e.Amount.Currency == currency)
|
|
.Sum(e => e.Amount.Amount);
|
|
|
|
return new Money(total, currency);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the total income minus total expenses (net balance).
|
|
/// </summary>
|
|
public Money CalculateNetBalance(string currency)
|
|
{
|
|
var income = CalculateTotalByType(EntryType.Income, currency);
|
|
var expenses = CalculateTotalByType(EntryType.Expense, currency);
|
|
|
|
var netAmount = income.Amount - expenses.Amount;
|
|
return new Money(Math.Max(0, netAmount), currency);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all entries that allocate to a specific budget.
|
|
/// </summary>
|
|
public IEnumerable<LedgerEntry> GetEntriesForBudget(Guid budgetId)
|
|
{
|
|
return _entries.Where(e => e.BudgetAllocations.ContainsKey(budgetId));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates the total amount allocated to a specific budget from all entries.
|
|
/// </summary>
|
|
public Money CalculateTotalAllocatedToBudget(Guid budgetId, string currency)
|
|
{
|
|
var total = _entries
|
|
.Where(e => e.BudgetAllocations.ContainsKey(budgetId))
|
|
.Sum(e =>
|
|
{
|
|
if (!e.BudgetAllocations.TryGetValue(budgetId, out var allocation))
|
|
return 0;
|
|
|
|
if (allocation.Currency != currency)
|
|
return 0;
|
|
|
|
// Income adds to budget, expenses subtract
|
|
return e.Type == EntryType.Income ? allocation.Amount : -allocation.Amount;
|
|
});
|
|
|
|
return new Money(Math.Max(0, total), currency);
|
|
}
|
|
}
|
|
|