Example #1
0
        public LedgerTransaction CreateLedgerTransaction(LedgerBook ledgerBook, 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.AddTransactionForPersistenceOnly(newTransaction);
            List <LedgerTransaction> replacementTxns = ledgerEntry.Transactions.ToList();

            replacementTxns.Add(newTransaction);
            ledgerEntry.SetTransactionsForReconciliation(replacementTxns);
            ledgerEntry.RecalculateClosingBalance(ledgerBook);
            return(newTransaction);
        }
        /// <summary>
        ///     This is effectively stage 2 of the Reconciliation process.
        ///     Called by <see cref="ReconciliationBuilder.CreateNewMonthlyReconciliation" />. It builds the contents of the new
        ///     ledger line based on budget and statement input.
        /// </summary>
        /// <param name="budget">The current applicable budget</param>
        /// <param name="statement">The current period statement.</param>
        /// <param name="startDateIncl">
        ///     The date of the previous ledger line. This is used to include transactions from the
        ///     Statement starting from this date and including this date.
        /// </param>
        private void AddNew(
            BudgetModel budget,
            StatementModel statement,
            DateTime startDateIncl)
        {
            if (!this.newReconciliationLine.IsNew)
            {
                throw new InvalidOperationException("Cannot add a new entry to an existing Ledger Line, only new Ledger Lines can have new entries added.");
            }

            var reconciliationDate = this.newReconciliationLine.Date;
            // Date filter must include the start date, which goes back to and includes the previous ledger date up to the date of this ledger line, but excludes this ledger date.
            // For example if this is a reconciliation for the 20/Feb then the start date is 20/Jan and the finish date is 20/Feb. So transactions pulled from statement are between
            // 20/Jan (inclusive) and 19/Feb (inclusive) but not including anything for the 20th of Feb.
            List <Transaction> filteredStatementTransactions = statement?.AllTransactions.Where(t => t.Date >= startDateIncl && t.Date < reconciliationDate).ToList() ?? new List <Transaction>();

            IEnumerable <LedgerEntry> previousLedgerBalances = CompileLedgersAndBalances(LedgerBook);

            var entries = new List <LedgerEntry>();

            foreach (var previousLedgerEntry in previousLedgerBalances)
            {
                LedgerBucket ledgerBucket;
                var          openingBalance = previousLedgerEntry.Balance;
                var          currentLedger  = LedgerBook.Ledgers.Single(l => l.BudgetBucket == previousLedgerEntry.LedgerBucket.BudgetBucket);
                if (previousLedgerEntry.LedgerBucket.StoredInAccount != currentLedger.StoredInAccount)
                {
                    // Check to see if a ledger has been moved into a new default account since last reconciliation.
                    ledgerBucket = currentLedger;
                }
                else
                {
                    ledgerBucket = previousLedgerEntry.LedgerBucket;
                }

                var newEntry = new LedgerEntry(true)
                {
                    Balance = openingBalance, LedgerBucket = ledgerBucket
                };

                // Start by adding the budgeted amount to a list of transactions.
                List <LedgerTransaction> transactions = IncludeBudgetedAmount(budget, ledgerBucket, reconciliationDate);

                // Append all other transactions for this bucket, if any, to the transaction list.
                transactions.AddRange(IncludeStatementTransactions(newEntry, filteredStatementTransactions));

                AutoMatchTransactionsAlreadyInPreviousPeriod(filteredStatementTransactions, previousLedgerEntry, transactions);
                newEntry.SetTransactionsForReconciliation(transactions);

                entries.Add(newEntry);
            }

            this.newReconciliationLine.SetNewLedgerEntries(entries);

            foreach (var behaviour in ReconciliationBehaviourFactory.ListAllBehaviours())
            {
                behaviour.Initialise(filteredStatementTransactions,
                                     this.newReconciliationLine,
                                     this.toDoList,
                                     this.logger,
                                     statement);
                behaviour.ApplyBehaviour();
            }

            // At this point each ledger balance is still set to the opening balance, it hasn't ben updated yet. This should always be done last.
            foreach (var ledger in this.newReconciliationLine.Entries)
            {
                ledger.Balance += ledger.Transactions.Sum(t => t.Amount);
            }
        }