using FinancialApi.Domain; using Wolverine.Persistence; namespace FinancialApi.Application; public record ReverseJournalCommand(Guid OriginalJournalId, string Reason); public record JournalReversedEvent(Guid OriginalJournalId, Guid ReversalJournalId); public record ReversalData(JournalEntry OriginalJournalEntry, IReadOnlyList AffectedAccounts); public interface IReversalQuery { Task GetReversalDataAsync(Guid journalEntryId); } public static class ReverseJournalHandler { public static async Task LoadAsync(ReverseJournalCommand cmd, IReversalQuery query) { var data = await query.GetReversalDataAsync(cmd.OriginalJournalId); if (data == null) { throw new InvalidOperationException($"Journal Entry {cmd.OriginalJournalId} does not exist"); } return data; } public static ( IStorageAction ReversalWrite, IStorageAction[] AccountWrites, JournalReversedEvent Event) Handle(ReverseJournalCommand cmd, ReversalData data) { var reversalJournal = BalancedJournal.CreateReversal(data.OriginalJournalEntry, cmd.Reason, DateTimeOffset.UtcNow); var accountState = data.AffectedAccounts.ToDictionary(a => a.Id); reversalJournal.Entry.Lines.ForEach(l => { var currentAccount = accountState[l.AccountId]; accountState[l.AccountId] = currentAccount.ApplyPosting(l.Amount, l.Type); }); var accountWrites = accountState.Values.Select(a => (IStorageAction)Storage.Update(a)).ToArray(); return ( Storage.Insert(reversalJournal.Entry), accountWrites, new JournalReversedEvent(cmd.OriginalJournalId, reversalJournal.Entry.Id) ); } }