using System.Collections.ObjectModel;
namespace BudgetApp.Domain.Models;
///
/// Ledger aggregate containing all ledger entries.
/// Provides calculations and operations on entries.
///
public class Ledger
{
private readonly List _entries;
public ReadOnlyCollection Entries => _entries.AsReadOnly();
public Ledger()
{
_entries = new List();
}
public Ledger(IEnumerable entries)
{
if (entries == null)
throw new ArgumentNullException(nameof(entries));
_entries = new List(entries);
}
///
/// Adds a ledger entry to the ledger.
///
public void AddEntry(LedgerEntry entry)
{
if (entry == null)
throw new ArgumentNullException(nameof(entry));
entry.Validate();
_entries.Add(entry);
}
///
/// Removes a ledger entry from the ledger.
///
public void RemoveEntry(Guid entryId)
{
var entry = _entries.FirstOrDefault(e => e.Id == entryId);
if (entry != null)
{
_entries.Remove(entry);
}
}
///
/// Gets all entries of a specific type.
///
public IEnumerable GetEntriesByType(EntryType type)
{
return _entries.Where(e => e.Type == type);
}
///
/// Gets entries within a date range.
///
public IEnumerable GetEntriesByDateRange(DateTime startDate, DateTime endDate)
{
return _entries.Where(e => e.Date >= startDate && e.Date <= endDate);
}
///
/// Calculates the total amount for entries of a specific type.
///
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);
}
///
/// Calculates the total income minus total expenses (net balance).
///
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);
}
///
/// Gets all entries that allocate to a specific budget.
///
public IEnumerable GetEntriesForBudget(Guid budgetId)
{
return _entries.Where(e => e.BudgetAllocations.ContainsKey(budgetId));
}
///
/// Calculates the total amount allocated to a specific budget from all entries.
///
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);
}
}