public void ConstructWithGuidShouldSetId() { Guid id = Guid.NewGuid(); var subject = new CreditLedgerTransaction(id); Assert.AreEqual(id, subject.Id); }
public void WithAmountMinus50ShouldCreateADebitOf50() { var subject = new CreditLedgerTransaction(); LedgerTransaction result = subject.WithAmount(-50); Assert.AreEqual(-50M, result.Amount); }
public void WithAmount50ShouldReturnSameObjectForChaining() { var subject = new CreditLedgerTransaction(); LedgerTransaction result = subject.WithAmount(50); Assert.AreSame(subject, result); }
public void WithReversal50ShouldCreateANegativeCreditOf50() { var subject = new CreditLedgerTransaction(); LedgerTransaction result = subject.WithReversal(50); Assert.AreEqual(-50M, result.Credit); }
public LedgerTransactionToDtoMapperTest() { TestData = new CreditLedgerTransaction(new Guid("7F921750-4467-4EA4-81E6-3EFD466341C6")) { Amount = 123.99M, Narrative = "Foo bar." }; }
public void WithReversal50ShouldAZeroDebitAmount() { var subject = new CreditLedgerTransaction(); LedgerTransaction result = subject.WithReversal(50); Assert.AreEqual(0M, result.Debit); }
/// <summary> /// Allows ledger bucket specific behaviour during reconciliation. /// </summary> /// <exception cref="System.ArgumentNullException"></exception> public override bool ApplyReconciliationBehaviour(IList <LedgerTransaction> transactions, DateTime reconciliationDate, decimal openingBalance) { if (transactions == null) { throw new ArgumentNullException(nameof(transactions)); } LedgerTransaction zeroingTransaction = null; var netAmount = transactions.Sum(t => t.Amount); // This ledger can accumulate a balance but cannot be negative. var closingBalance = openingBalance + netAmount; var budgetedAmount = transactions.FirstOrDefault(t => t is BudgetCreditLedgerTransaction); if (budgetedAmount != null && closingBalance < budgetedAmount.Amount) { // This ledger has a monthly budgeted amount and the balance has resulted in a balance less than the monthly budgeted amount, supplement from surplus to equal budgeted amount. // While there is a monthly amount the balance should not drop below this amount. zeroingTransaction = new CreditLedgerTransaction { Date = reconciliationDate, Amount = budgetedAmount.Amount - closingBalance, Narrative = closingBalance < 0 ? SupplementOverdrawnText : SupplementLessThanBudgetText }; } else if (closingBalance < 0) { zeroingTransaction = new CreditLedgerTransaction { Date = reconciliationDate, Amount = -closingBalance, Narrative = SupplementOverdrawnText }; } if (zeroingTransaction != null) { transactions.Add(zeroingTransaction); return(true); } return(false); }
/// <summary> /// Allows ledger bucket specific behaviour during reconciliation. /// </summary> /// <exception cref="System.ArgumentNullException"></exception> public override void ApplyReconciliationBehaviour(IList<LedgerTransaction> transactions, DateTime reconciliationDate, decimal openingBalance) { if (transactions == null) { throw new ArgumentNullException(nameof(transactions)); } LedgerTransaction zeroingTransaction = null; var netAmount = transactions.Sum(t => t.Amount); // This ledger can accumulate a balance but cannot be negative. var closingBalance = openingBalance + netAmount; var budgetedAmount = transactions.FirstOrDefault(t => t is BudgetCreditLedgerTransaction); if (budgetedAmount != null && closingBalance < budgetedAmount.Amount) { // This ledger has a monthly budgeted amount and the balance has resulted in a balance less than the monthly budgeted amount, supplement from surplus to equal budgeted amount. // While there is a monthly amount the balance should not drop below this amount. zeroingTransaction = new CreditLedgerTransaction { Date = reconciliationDate, Amount = budgetedAmount.Amount - closingBalance, Narrative = closingBalance < 0 ? SupplementOverdrawnText : SupplementLessThanBudgetText }; } else if (closingBalance < 0) { zeroingTransaction = new CreditLedgerTransaction { Date = reconciliationDate, Amount = -closingBalance, Narrative = SupplementOverdrawnText }; } if (zeroingTransaction != null) { transactions.Add(zeroingTransaction); } }
private void SaveNewEntryTransaction() { try { if (NewTransactionIsCredit || NewTransactionIsDebit) { LedgerTransaction newTransaction; if (NewTransactionIsCredit) { newTransaction = new CreditLedgerTransaction(); } else { newTransaction = new DebitLedgerTransaction(); } if (NewTransactionIsReversal) { newTransaction.WithReversal(NewTransactionAmount).WithNarrative(NewTransactionNarrative); } else { newTransaction.WithAmount(NewTransactionAmount).WithNarrative(NewTransactionNarrative); } if (NewTransactionAccountType != null) { newTransaction.WithAccountType(NewTransactionAccountType); } LedgerEntry.AddTransaction(newTransaction); ShownTransactions.Add(newTransaction); } } catch (ArgumentException) { // Invalid transaction data return; } RaisePropertyChanged(() => TransactionsTotal); this.wasChanged = true; }
public LedgerTransaction BalanceAdjustment(decimal adjustment, string narrative) { if (!IsNew) { throw new InvalidOperationException("Cannot adjust existing ledger lines, only newly added lines can be adjusted."); } if (adjustment == 0) { throw new ArgumentException("The balance adjustment amount cannot be zero.", "adjustment"); } LedgerTransaction newAdjustment; if (adjustment < 0) { newAdjustment = new DebitLedgerTransaction { Debit = -adjustment, Narrative = narrative, }; } else { newAdjustment = new CreditLedgerTransaction { Credit = adjustment, Narrative = narrative, }; } this.bankBalanceAdjustments.Add(newAdjustment); return newAdjustment; }
public LedgerTransaction CreateLedgerTransaction(LedgerEntryLine reconciliation, LedgerEntry ledgerEntry, decimal amount, string narrative) { if (reconciliation == null) { throw new ArgumentNullException(nameof(reconciliation)); } if (ledgerEntry == null) { throw new ArgumentNullException(nameof(ledgerEntry)); } if (narrative == null) { throw new ArgumentNullException(nameof(narrative)); } LedgerTransaction newTransaction = new CreditLedgerTransaction(); newTransaction.WithAmount(amount).WithNarrative(narrative); newTransaction.Date = reconciliation.Date; ledgerEntry.AddTransaction(newTransaction); return newTransaction; }
private void PerformBankTransfer(TransferFundsCommand transferDetails, LedgerEntryLine ledgerEntryLine) { var sourceTransaction = new CreditLedgerTransaction { Amount = -transferDetails.TransferAmount, AutoMatchingReference = transferDetails.AutoMatchingReference, Date = ledgerEntryLine.Date, Narrative = transferDetails.Narrative }; var destinationTransaction = new CreditLedgerTransaction { Amount = transferDetails.TransferAmount, AutoMatchingReference = transferDetails.AutoMatchingReference, Date = ledgerEntryLine.Date, Narrative = transferDetails.Narrative }; if (transferDetails.BankTransferRequired) { ledgerEntryLine.BalanceAdjustment(-transferDetails.TransferAmount, transferDetails.Narrative, transferDetails.FromLedger.StoredInAccount); ledgerEntryLine.BalanceAdjustment(transferDetails.TransferAmount, transferDetails.Narrative, transferDetails.ToLedger.StoredInAccount); this.transactionRuleService.CreateNewSingleUseRule( transferDetails.FromLedger.BudgetBucket.Code, null, new[] { transferDetails.AutoMatchingReference }, null, -transferDetails.TransferAmount, true); this.transactionRuleService.CreateNewSingleUseRule( transferDetails.ToLedger.BudgetBucket.Code, null, new[] { transferDetails.AutoMatchingReference }, null, transferDetails.TransferAmount, true); } // No need for a source transaction for surplus ledger. if (!(transferDetails.FromLedger.BudgetBucket is SurplusBucket)) { var ledgerEntry = ledgerEntryLine.Entries.Single(e => e.LedgerBucket == transferDetails.FromLedger); ledgerEntry.AddTransaction(sourceTransaction); } // No need for a destination transaction for surplus ledger. if (!(transferDetails.ToLedger.BudgetBucket is SurplusBucket)) { var ledgerEntry = ledgerEntryLine.Entries.Single(e => e.LedgerBucket == transferDetails.ToLedger); ledgerEntry.AddTransaction(destinationTransaction); } }
/// <summary> /// Called by <see cref="LedgerBook.Reconcile" />. Sets up this new Entry with transactions. /// </summary> /// <param name="newTransactions">The list of new transactions for this entry.</param> internal LedgerEntry SetTransactionsForReconciliation(List<LedgerTransaction> newTransactions) { this.transactions = newTransactions; if (LedgerColumn.BudgetBucket is SpentMonthlyExpenseBucket && NetAmount != 0) { // SpentMonthly ledgers automatically zero their balance. They dont accumulate nor can they be negative. LedgerTransaction zeroingTransaction = null; if (NetAmount < 0) { if (newTransactions.OfType<BudgetCreditLedgerTransaction>().Any()) { zeroingTransaction = new CreditLedgerTransaction { Credit = -NetAmount, Narrative = "SpentMonthlyLedger: automatically supplementing shortfall from surplus", }; } else { if (Balance + NetAmount < 0) { zeroingTransaction = new CreditLedgerTransaction { Credit = -(Balance + NetAmount), Narrative = "SpentMonthlyLedger: automatically supplementing shortfall from surplus", }; } } } else { zeroingTransaction = new DebitLedgerTransaction { Debit = NetAmount, Narrative = "SpentMonthlyLedger: automatically zeroing the credit remainder", }; } if (zeroingTransaction != null) { this.transactions.Add(zeroingTransaction); } } else { // All other ledgers can accumulate a balance but cannot be negative. decimal newBalance = Balance + NetAmount; Balance = newBalance < 0 ? 0 : newBalance; } return this; }
public void UsingTestData1_AddTransactionShouldEffectEntryBalance() { ReconciliationResult entryLine = Act(this.subject, this.testDataBudget); var newTransaction = new CreditLedgerTransaction { Amount = -100 }; LedgerEntry entry = entryLine.Reconciliation.Entries.First(); entry.AddTransaction(newTransaction); this.subject.Output(); Assert.AreEqual(20, entry.Balance); }