public Task closing_an_open_period(YearMonth openedOn, EquityAccount retainedEarnings, GeneralLedgerEntryIdentifier[] generalLedgerEntryIdentifiers, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) => new Scenario() .Given(ChartOfAccounts.Identifier, new AccountDefined { AccountNumber = retainedEarnings.AccountNumber.ToInt32(), AccountName = retainedEarnings.AccountName.ToString() }) .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn.OnDayOfMonth(1)) }) .When(new BeginClosingAccountingPeriod { GeneralLedgerEntryIds = ImmutableArray <Guid> .Empty.AddRange(Array.ConvertAll(generalLedgerEntryIdentifiers, x => x.ToGuid())), ClosingOn = openedOn.OnDayOfMonth(2).AtMidnight().ToDateTimeUnspecified(), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Then(GeneralLedger.Identifier, new AccountingPeriodClosing { Period = AccountingPeriod.Open(openedOn.OnDayOfMonth(1)).ToString(), GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, x => x.ToGuid()), ClosingOn = Time.Format.LocalDateTime(openedOn.OnDayOfMonth(2).AtMidnight()), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Assert(_handler, _facts);
public async ValueTask <GeneralLedgerEntry> Get(GeneralLedgerEntryIdentifier identifier, CancellationToken cancellationToken = default) { var optional = await _inner.GetOptional(identifier.ToString(), cancellationToken); return(optional.HasValue ? optional.Value : throw new InvalidOperationException()); }
public Task entry_not_in_balance_throws(GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, int sequenceNumber, LocalDate openedOn, AccountName accountName, AccountNumber accountNumber) { var scenario = new Scenario() .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn) }) .Given(ChartOfAccounts.Identifier, new AccountDefined { AccountName = accountName.ToString(), AccountNumber = accountNumber.ToInt32() }) .When(new PostGeneralLedgerEntry { Period = AccountingPeriod.Open(openedOn).ToString(), BusinessTransaction = new BadTransaction { Account = accountNumber, ReferenceNumber = sequenceNumber }, CreatedOn = openedOn.ToDateTimeUnspecified(), GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() }) .Throws(new GeneralLedgerEntryNotInBalanceException(generalLedgerEntryIdentifier)); _writer.Write(scenario.Build()); return(scenario.Assert(new GeneralLedgerEntryHandlers(new GeneralLedgerTestRepository(_facts), new GeneralLedgerEntryTestRepository(_facts), _ => false), _facts)); }
public Task entry_not_in_balance_throws(GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, int sequenceNumber, DateTimeOffset openedOn, AccountName accountName, AccountNumber accountNumber) { var scenario = new Scenario() .Given("generalLedger", new GeneralLedgerOpened { OpenedOn = openedOn }) .Given("chartOfAccounts", new AccountDefined { AccountName = accountName.ToString(), AccountNumber = accountNumber.ToInt32() }) .When(new PostGeneralLedgerEntry { Period = Period.Open(openedOn).ToString(), BusinessTransaction = new BadTransaction { Account = accountNumber, ReferenceNumber = sequenceNumber }, CreatedOn = openedOn, GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() }) .Throws(new GeneralLedgerEntryNotInBalanceException(generalLedgerEntryIdentifier)); _writer.Write(scenario.Build()); return(scenario.Assert(_handler, _facts)); }
public async ValueTask <GeneralLedgerEntry> Get(GeneralLedgerEntryIdentifier identifier, CancellationToken cancellationToken = default) { var optional = await _inner.GetOptional(GeneralLedgerEntry.FormatStreamIdentifier(identifier), cancellationToken); return(optional.HasValue ? optional.Value : throw new GeneralLedgerEntryNotFoundException(identifier)); }
public async ValueTask <GeneralLedgerEntry> Get(GeneralLedgerEntryIdentifier identifier, CancellationToken cancellationToken = default) { var optionalGeneralLedgerEntry = await _inner.GetById(identifier.ToString(), cancellationToken); if (!optionalGeneralLedgerEntry.HasValue) { throw new InvalidOperationException(); } return(optionalGeneralLedgerEntry.Value); }
public async ValueTask <GeneralLedgerEntry> Get(GeneralLedgerEntryIdentifier identifier, CancellationToken cancellationToken = default) { var optionalGeneralLedgerEntry = await _inner.GetById(GeneralLedgerEntry.FormatStreamIdentifier(identifier), cancellationToken); if (!optionalGeneralLedgerEntry.HasValue) { throw new GeneralLedgerEntryNotFoundException(identifier); } return(optionalGeneralLedgerEntry.Value); }
public Task when_a_general_ledger_entry_was_created(GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, Period period) => new NpgsqlProjectionScenario(new BalanceSheetReportProjection()) .Given(new CreateSchema()) .Given(new GeneralLedgerEntryCreated { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Period = period.ToString() }) .Then(_schema, "balance_sheet_general_ledger_entry_period", new BalanceSheetReportProjection.GeneralLedgerEntryPeriod { PeriodMonth = period.Month, PeriodYear = period.Year, GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() }) .Assert();
public Task closing_the_period_before_the_period_has_started(DateTimeOffset openedOn, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) => new Scenario() .Given("generalLedger", new GeneralLedgerOpened { OpenedOn = openedOn }) .When(new BeginClosingAccountingPeriod { ClosingOn = openedOn.AddMonths(-1), RetainedEarningsAccountNumber = _retainedEarnings.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Throws(new ClosingDateBeforePeriodException(Period.Open(openedOn), openedOn.AddMonths(-1))) .Assert(_handler, _facts);
public async Task when_an_entry_is_posted( GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, LocalDateTime createdOn, Money[] amounts) { var period = AccountingPeriod.Open(createdOn.Date); var thru = createdOn.Date.PlusDays(1).AtMidnight(); var accounts = await OpenBooks(createdOn).ToArrayAsync(); var debits = Array.ConvertAll(amounts, amount => new Debit(accounts.OrderBy(_ => Guid.NewGuid()).First().accountNumber, amount)); var credits = Array.ConvertAll(amounts, amount => new Credit(accounts.OrderBy(_ => Guid.NewGuid()).First().accountNumber, amount)); var journalEntry = new JournalEntry { ReferenceNumber = 1, Credits = Array.ConvertAll(credits, credit => new JournalEntry.Item { Amount = credit.Amount.ToDecimal(), AccountNumber = credit.AccountNumber.Value }), Debits = Array.ConvertAll(debits, debit => new JournalEntry.Item { Amount = debit.Amount.ToDecimal(), AccountNumber = debit.AccountNumber.ToInt32() }) }; var command = new PostGeneralLedgerEntry { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), CreatedOn = createdOn.ToDateTimeUnspecified(), BusinessTransaction = journalEntry, Period = period.ToString() }; var expected = new BalanceSheetReport { Thru = thru.ToDateTimeUnspecified(), LineItems = journalEntry.Debits.Concat(journalEntry.Credits.Select(c => new JournalEntry.Item() { Amount = -c.Amount, AccountNumber = c.AccountNumber })).Aggregate(ImmutableDictionary <int, LineItem> .Empty, (items, item) => items.SetItem( item.AccountNumber, new LineItem { AccountNumber = item.AccountNumber, Name = accounts.Single(x => x.accountNumber.ToInt32() == item.AccountNumber).accountName .ToString(), Balance = items.TryGetValue(item.AccountNumber, out var existing) ? existing.Balance + item.Amount : new () { DecimalValue = item.Amount } })).Values.OrderBy(x => x.AccountNumber).ToImmutableArray(),
public Task applying_credit_to_non_existing_account_throws( GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, int sequenceNumber, LocalDate openedOn, AccountNumber accountNumber) => new Scenario() .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn) }) .When(new PostGeneralLedgerEntry { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Period = AccountingPeriod.Open(openedOn).ToString(), BusinessTransaction = new TestTransaction(new GeneralLedgerEntryNumber("t", sequenceNumber), credits: new[] { new Credit(accountNumber, Money.Zero) }), CreatedOn = openedOn.ToDateTimeUnspecified() }) .Throws(new AccountDeactivatedException(accountNumber)) .Assert(new GeneralLedgerEntryHandlers(new GeneralLedgerTestRepository(_facts), new GeneralLedgerEntryTestRepository(_facts), _ => true), _facts);
public Task closing_the_period_before_the_period_has_started(LocalDate openedOn, EquityAccount retainedEarnings, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) => new Scenario() .Given(ChartOfAccounts.Identifier, new AccountDefined { AccountNumber = retainedEarnings.AccountNumber.ToInt32(), AccountName = retainedEarnings.AccountName.ToString() }) .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn) }) .When(new BeginClosingAccountingPeriod { ClosingOn = openedOn.PlusMonths(-1).ToDateTimeUnspecified(), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Throws(new ClosingDateBeforePeriodException(AccountingPeriod.Open(openedOn), openedOn.PlusMonths(-1))) .Assert(_handler, _facts);
public Task closing_a_closed_period(Period period, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) => new Scenario() .Given("generalLedger", new GeneralLedgerOpened { OpenedOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 1)) }, new AccountingPeriodClosing { Period = period.ToString(), ClosingOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 2)), RetainedEarningsAccountNumber = _retainedEarnings.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .When(new BeginClosingAccountingPeriod { ClosingOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 2)), RetainedEarningsAccountNumber = _retainedEarnings.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Throws(new PeriodClosingInProcessException(period)) .Assert(_handler, _facts);
public Task when_the_general_ledger_entry_was_posted( GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, Period period, AccountNumber credit, AccountNumber debit, Money amount, int iterations) => new NpgsqlProjectionScenario(new BalanceSheetReportProjection()) .Given(new CreateSchema()) .Given(new GeneralLedgerEntryCreated { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Period = period.ToString() }) .Given(Enumerable.Range(0, iterations).Select(_ => new DebitApplied { Amount = amount.ToDecimal(), AccountNumber = debit.ToInt32(), GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() })) .Given(Enumerable.Range(0, iterations).Select(_ => new CreditApplied { Amount = amount.ToDecimal(), AccountNumber = credit.ToInt32(), GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() })) .Given(new GeneralLedgerEntryPosted { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Period = period.ToString() }) .Then(_schema, "balance_sheet_general_ledger_entry_period", Array.Empty <BalanceSheetReportProjection.GeneralLedgerEntryPeriod>()) .Then(_schema, "balance_sheet_items_unposted", Array.Empty <BalanceSheetReportProjection.UnpostedGeneralLedgerEntryLine>()) .Then(_schema, "balance_sheet_report", new BalanceSheetReportProjection.Item { Balance = amount.ToDecimal() * iterations, PeriodMonth = period.Month, PeriodYear = period.Year, AccountNumber = debit.ToInt32() }, new BalanceSheetReportProjection.Item { Balance = -amount.ToDecimal() * iterations, PeriodMonth = period.Month, PeriodYear = period.Year, AccountNumber = credit.ToInt32() }) .Assert();
public async Task when_closing_the_period(LocalDateTime createdOn, GeneralLedgerEntryIdentifier closingEntryIdentifier) { var accountingPeriodClosedSource = new TaskCompletionSource <ResolvedEvent>(); var checkpointSource = new TaskCompletionSource <Position>(); await EventStoreClient.SubscribeToAllAsync((_, e, _) => { switch (e.Event.EventType) { case nameof(AccountingPeriodClosed): accountingPeriodClosedSource.TrySetResult(e); break; case "checkpoint": checkpointSource.TrySetResult( new Position( BitConverter.ToUInt64(e.Event.Data.Span), BitConverter.ToUInt64(e.Event.Data.Span[8..]))); break; }
public async Task when_an_entry_is_posted( GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, DateTimeOffset createdOn, Money[] amounts) { var period = Period.Open(createdOn); var accounts = await OpenBooks(createdOn).ToArrayAsync(); var debits = Array.ConvertAll(amounts, amount => new Debit(accounts.OrderBy(_ => Guid.NewGuid()).First().accountNumber, amount)); var credits = Array.ConvertAll(amounts, amount => new Credit(accounts.OrderBy(_ => Guid.NewGuid()).First().accountNumber, amount)); var command = new PostGeneralLedgerEntry { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), CreatedOn = createdOn, BusinessTransaction = new JournalEntry { ReferenceNumber = 1, Credits = Array.ConvertAll(credits, credit => new JournalEntry.Item { Amount = credit.Amount.ToDecimal(), AccountNumber = credit.AccountNumber.Value }), Debits = Array.ConvertAll(debits, debit => new JournalEntry.Item { Amount = debit.Amount.ToDecimal(), AccountNumber = debit.AccountNumber.ToInt32() }) }, Period = period.ToString() }; await HttpClient.SendCommand("/general-ledger/entries", command, TransactoSerializerOptions.BusinessTransactions(typeof(JournalEntry))); await Task.Delay(TimeSpan.FromSeconds(2)); using var response = await HttpClient.GetAsync($"/balance-sheet/{createdOn.AddDays(1):O}"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var json = await response.Content.ReadAsStringAsync(); var balanceSheet = JsonSerializer.Deserialize <BalanceSheetReport>(json, TransactoSerializerOptions.Events); }
public Task closing_an_open_period(Period period, GeneralLedgerEntryIdentifier[] generalLedgerEntryIdentifiers, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) => new Scenario() .Given("generalLedger", new GeneralLedgerOpened { OpenedOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 2)) }) .When(new BeginClosingAccountingPeriod { GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, x => x.ToGuid()), ClosingOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 2)), RetainedEarningsAccountNumber = _retainedEarnings.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Then("generalLedger", new AccountingPeriodClosing { Period = period.ToString(), GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, x => x.ToGuid()), ClosingOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 2)), RetainedEarningsAccountNumber = _retainedEarnings.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Assert(_handler, _facts);
public Task entry_date_not_in_current_or_next_period_throws( GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, GeneralLedgerEntryNumber generalLedgerEntryNumber, LocalDate openedOn) { var createdOn = openedOn.PlusMonths(2).AtMidnight(); return(new Scenario() .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn) }) .When(new PostGeneralLedgerEntry { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Period = AccountingPeriod.Open(openedOn).Next().Next().ToString(), BusinessTransaction = new TestTransaction(generalLedgerEntryNumber), CreatedOn = createdOn.ToDateTimeUnspecified() }) .Throws(new GeneralLedgerEntryNotInPeriodException(generalLedgerEntryNumber, createdOn, AccountingPeriod.Open(openedOn).Next())) .Assert(new GeneralLedgerEntryHandlers(new GeneralLedgerTestRepository(_facts), new GeneralLedgerEntryTestRepository(_facts), _ => false), _facts)); }
public Task closing_a_closed_period(YearMonth openedOn, EquityAccount retainedEarnings, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) => new Scenario() .Given(ChartOfAccounts.Identifier, new AccountDefined { AccountNumber = retainedEarnings.AccountNumber.ToInt32(), AccountName = retainedEarnings.AccountName.ToString() }) .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn.OnDayOfMonth(1)) }, new AccountingPeriodClosing { Period = AccountingPeriod.Open(openedOn.OnDayOfMonth(1)).ToString(), ClosingOn = Time.Format.LocalDateTime(openedOn.OnDayOfMonth(2).AtMidnight()), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .When(new BeginClosingAccountingPeriod { ClosingOn = openedOn.OnDayOfMonth(2).AtMidnight().ToDateTimeUnspecified(), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }) .Throws(new PeriodClosingInProcessException(AccountingPeriod.Open(openedOn.OnDayOfMonth(1)))) .Assert(_handler, _facts);
public Task unposted_entry_throws(LocalDate openedOn, GeneralLedgerEntryNumber generalLedgerEntryNumber, EquityAccount retainedEarnings, GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier) { var period = AccountingPeriod.Open(openedOn); var closingOn = openedOn.AtMidnight(); var accountingPeriodClosing = new AccountingPeriodClosing { Period = period.ToString(), ClosingOn = Time.Format.LocalDateTime(closingOn), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), GeneralLedgerEntryIds = new[] { generalLedgerEntryIdentifier.ToGuid() } }; return(new Scenario() .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn) }, accountingPeriodClosing) .Given(ChartOfAccounts.Identifier, new AccountDefined { AccountName = retainedEarnings.AccountName.ToString(), AccountNumber = retainedEarnings.AccountNumber.ToInt32() }) .Given(GeneralLedgerEntry.FormatStreamIdentifier(generalLedgerEntryIdentifier), new GeneralLedgerEntryCreated { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Number = generalLedgerEntryNumber.ToString(), Period = period.ToString(), CreatedOn = Time.Format.LocalDateTime(openedOn.AtMidnight()) }) .When(accountingPeriodClosing) .Throws(new GeneralLedgerEntryWasNotPostedException(generalLedgerEntryIdentifier)) .Assert(_handler, _facts)); }
public Task when_a_debit_was_applied( GeneralLedgerEntryIdentifier generalLedgerEntryIdentifier, Period period, Credit credit) => new NpgsqlProjectionScenario(new BalanceSheetReportProjection()) .Given(new CreateSchema()) .Given(new GeneralLedgerEntryCreated { GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Period = period.ToString() }, new DebitApplied { Amount = credit.Amount.ToDecimal(), AccountNumber = credit.AccountNumber.ToInt32(), GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() }) .Then(_schema, "balance_sheet_general_ledger_entry_period", new BalanceSheetReportProjection.GeneralLedgerEntryPeriod { PeriodMonth = period.Month, PeriodYear = period.Year, GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid() }) .Then(_schema, "balance_sheet_items_unposted", new BalanceSheetReportProjection.UnpostedGeneralLedgerEntryLine { AccountNumber = credit.AccountNumber.ToInt32(), GeneralLedgerEntryId = generalLedgerEntryIdentifier.ToGuid(), Debit = credit.Amount.ToDecimal() }) .Assert();
public Task period_closing_started(LocalDate openedOn, EquityAccount retainedEarnings, AssetAccount cashAccount, IncomeAccount incomeAccount, ExpenseAccount expenseAccount, GeneralLedgerEntryIdentifier[] generalLedgerEntryIdentifiers, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier, Money income, Money expense) { var period = AccountingPeriod.Open(openedOn); var closingOn = openedOn.AtMidnight(); var accountingPeriodClosing = new AccountingPeriodClosing { Period = period.ToString(), ClosingOn = Time.Format.LocalDateTime(closingOn), RetainedEarningsAccountNumber = retainedEarnings.AccountNumber.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, identifier => identifier.ToGuid()) }; var net = income - expense; var generalLedgerEntryFacts = generalLedgerEntryIdentifiers.SelectMany( (identifier, index) => Array.ConvertAll(new object[] { new GeneralLedgerEntryCreated { Number = $"sale-{index}", Period = period.ToString(), CreatedOn = Time.Format.LocalDate(openedOn), GeneralLedgerEntryId = identifier.ToGuid() }, new CreditApplied { Amount = income.ToDecimal(), AccountNumber = incomeAccount.AccountNumber.ToInt32(), GeneralLedgerEntryId = identifier.ToGuid() }, new DebitApplied { Amount = expense.ToDecimal(), AccountNumber = expenseAccount.AccountNumber.ToInt32(), GeneralLedgerEntryId = identifier.ToGuid() }, net > Money.Zero ? new DebitApplied { Amount = net.ToDecimal(), AccountNumber = cashAccount.AccountNumber.ToInt32(), GeneralLedgerEntryId = identifier.ToGuid() } : new CreditApplied { Amount = -net.ToDecimal(), AccountNumber = cashAccount.AccountNumber.ToInt32(), GeneralLedgerEntryId = identifier.ToGuid() }, new GeneralLedgerEntryPosted { Period = period.ToString(), GeneralLedgerEntryId = identifier.ToGuid() }, }, e => new Fact(GeneralLedgerEntry.FormatStreamIdentifier(identifier), e))) .ToArray(); return(new Scenario() .Given(ChartOfAccounts.Identifier, new AccountDefined { AccountName = cashAccount.AccountName.ToString(), AccountNumber = cashAccount.AccountNumber.ToInt32() }, new AccountDefined { AccountName = incomeAccount.AccountName.ToString(), AccountNumber = incomeAccount.AccountNumber.ToInt32() }, new AccountDefined { AccountName = expenseAccount.AccountName.ToString(), AccountNumber = expenseAccount.AccountNumber.ToInt32() }, new AccountDefined { AccountName = retainedEarnings.AccountName.ToString(), AccountNumber = retainedEarnings.AccountNumber.ToInt32() }) .Given(GeneralLedger.Identifier, new GeneralLedgerOpened { OpenedOn = Time.Format.LocalDate(openedOn) }, accountingPeriodClosing) .Given(generalLedgerEntryFacts) .When(accountingPeriodClosing) .Then(GeneralLedger.Identifier, new GeneralLedgerEntryCreated { CreatedOn = Time.Format.LocalDateTime(closingOn), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), Number = $"jec-{period}", Period = period.ToString() }, new DebitApplied { Amount = income.ToDecimal() * generalLedgerEntryIdentifiers.Length, AccountNumber = incomeAccount.AccountNumber.ToInt32(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, new CreditApplied { Amount = expense.ToDecimal() * generalLedgerEntryIdentifiers.Length, AccountNumber = expenseAccount.AccountNumber.ToInt32(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, net < Money.Zero ? new DebitApplied { Amount = -net.ToDecimal() * generalLedgerEntryIdentifiers.Length, AccountNumber = retainedEarnings.AccountNumber.ToInt32(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() } : new CreditApplied { Amount = net.ToDecimal() * generalLedgerEntryIdentifiers.Length, AccountNumber = retainedEarnings.AccountNumber.ToInt32(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, new GeneralLedgerEntryPosted { Period = period.ToString(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, new AccountingPeriodClosed { Period = period.ToString(), GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, identifier => identifier.ToGuid()), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), Balance = new[] { new BalanceLineItem { AccountNumber = cashAccount.AccountNumber.ToInt32(), Amount = net.ToDecimal() * generalLedgerEntryIdentifiers.Length }, new BalanceLineItem { AccountNumber = retainedEarnings.AccountNumber.ToInt32(), Amount = net.ToDecimal() * generalLedgerEntryIdentifiers.Length }, new BalanceLineItem { AccountNumber = incomeAccount.AccountNumber.ToInt32(), Amount = Money.Zero.ToDecimal() }, new BalanceLineItem { AccountNumber = expenseAccount.AccountNumber.ToInt32(), Amount = Money.Zero.ToDecimal() } } }) .Assert(_handler, _facts)); }
public Task period_closing_started(DateTimeOffset openedOn, GeneralLedgerEntryIdentifier[] generalLedgerEntryIdentifiers, GeneralLedgerEntryIdentifier closingGeneralLedgerEntryIdentifier, Money amount) { var period = Period.Open(openedOn); var cashAccountNumber = new AccountNumber(new Random().Next(1000, 1999)); var incomeAccountNumber = new AccountNumber(new Random().Next(4000, 4999)); var closingOn = new DateTimeOffset(new DateTime(period.Year, period.Month, 2)); var accountingPeriodClosing = new AccountingPeriodClosing { Period = period.ToString(), ClosingOn = closingOn, RetainedEarningsAccountNumber = _retainedEarnings.ToInt32(), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, identifier => identifier.ToGuid()) }; var generalLedgerEntryFacts = generalLedgerEntryIdentifiers.SelectMany( (identifier, index) => Array.ConvertAll(new object[] { new GeneralLedgerEntryCreated { Number = $"sale-{index}", Period = period.ToString(), CreatedOn = openedOn, GeneralLedgerEntryId = identifier.ToGuid() }, new DebitApplied { Amount = amount.ToDecimal(), AccountNumber = cashAccountNumber.ToInt32(), GeneralLedgerEntryId = identifier.ToGuid() }, new CreditApplied { Amount = amount.ToDecimal(), AccountNumber = incomeAccountNumber.ToInt32(), GeneralLedgerEntryId = identifier.ToGuid() }, new GeneralLedgerEntryPosted { Period = period.ToString(), GeneralLedgerEntryId = identifier.ToGuid() }, }, e => new Fact($"generalLedgerEntry-{identifier}", e))) .ToArray(); return(new Scenario() .Given("chartOfAccounts", new AccountDefined { AccountName = "Cash on Hand", AccountNumber = cashAccountNumber.ToInt32() }, new AccountDefined { AccountName = "Income", AccountNumber = incomeAccountNumber.ToInt32() }, new AccountDefined { AccountName = "Retained Earnings", AccountNumber = _retainedEarnings.ToInt32() }) .Given("generalLedger", new GeneralLedgerOpened { OpenedOn = openedOn }, accountingPeriodClosing) .Given(generalLedgerEntryFacts) .When(accountingPeriodClosing) .Then("generalLedger", new GeneralLedgerEntryCreated { CreatedOn = closingOn, GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), Number = $"jec-{period}", Period = period.ToString() }, new DebitApplied { Amount = amount.ToDecimal() * generalLedgerEntryIdentifiers.Length, AccountNumber = incomeAccountNumber.ToInt32(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, new CreditApplied { Amount = amount.ToDecimal() * generalLedgerEntryIdentifiers.Length, AccountNumber = _retainedEarnings.ToInt32(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, new GeneralLedgerEntryPosted { Period = period.ToString(), GeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid() }, new AccountingPeriodClosed { Period = period.ToString(), GeneralLedgerEntryIds = Array.ConvertAll(generalLedgerEntryIdentifiers, identifier => identifier.ToGuid()), ClosingGeneralLedgerEntryId = closingGeneralLedgerEntryIdentifier.ToGuid(), Balance = new Dictionary <int, decimal> { [cashAccountNumber.ToInt32()] = amount.ToDecimal() * generalLedgerEntryIdentifiers.Length, [incomeAccountNumber.ToInt32()] = Money.Zero.ToDecimal(), [_retainedEarnings.ToInt32()] = -(amount.ToDecimal() * generalLedgerEntryIdentifiers.Length) } }) .Assert(_handler, _facts)); }