using FinancialApi.Application; using Microsoft.EntityFrameworkCore; using Wolverine.Attributes; using Wolverine.Persistence; namespace FinancialApi.Infrastructure; public record ApplyFeeCommand(int AccountId, decimal Amount); public record FeePair(Account CustomerAccount, Account RevenueAccount); public record FeeAppliedEvent(int AccountId, decimal Amount); public static class ApplyFeeHandler { public static async Task LoadAsync( ApplyFeeCommand cmd, AccountDbContext db) { var customer = await db.Accounts.AsNoTracking().SingleOrDefaultAsync(x => x.Id == cmd.AccountId); var revenue = await db.Accounts.AsNoTracking().SingleOrDefaultAsync(x => x.Id == 99999); return (customer == null || revenue == null) ? null : new FeePair(customer, revenue); } [Transactional] public static ( IStorageAction CustomerWrite, IStorageAction RevenueWrite, IStorageAction JournalWrite, FeeAppliedEvent Event ) Handle( ApplyFeeCommand cmd, FeePair pair ) { var updatedCustomer = pair.CustomerAccount.ApplyPosting(cmd.Amount, EntryType.Debit); var updatedRevenue = pair.RevenueAccount.ApplyPosting(cmd.Amount, EntryType.Credit); var lines = new List { new(pair.CustomerAccount.Id, cmd.Amount, EntryType.Debit), new(9999, cmd.Amount, EntryType.Credit) }; var journalEntry = BalancedJournal.Create(Guid.NewGuid(), $"Service Fee Applied: {cmd.Amount} to Account {cmd.AccountId}", DateTimeOffset.UtcNow, lines); var @event = new FeeAppliedEvent(cmd.AccountId, cmd.Amount); return ( Storage.Update(updatedCustomer), Storage.Update(updatedRevenue), Storage.Insert(journalEntry.Entry), @event ); } }