/// <summary> /// Examines the ledger book's most recent reconciliation looking for transactions waiting to be matched to /// transactions imported in the current month. /// If any transactions are found, the statement is then examined to see if the transactions appear, if they do not a /// new <see cref="ValidationWarningException" /> /// is thrown; otherwise the method returns. /// </summary> public void ValidateAgainstOrphanedAutoMatchingTransactions(LedgerBook ledgerBook, StatementModel statement) { if (ledgerBook == null) { throw new ArgumentNullException(nameof(ledgerBook)); } if (statement == null) { throw new ArgumentNullException(nameof(statement)); } var lastLine = ledgerBook.Reconciliations.FirstOrDefault(); if (lastLine == null) { return; } List <LedgerTransaction> unmatchedTxns = lastLine.Entries .SelectMany(e => e.Transactions) .Where( t => !string.IsNullOrWhiteSpace(t.AutoMatchingReference) && !t.AutoMatchingReference.StartsWith(ReconciliationBuilder.MatchedPrefix, StringComparison.Ordinal)) .ToList(); if (unmatchedTxns.None()) { return; } List <Transaction> statementSubSet = statement.AllTransactions.Where(t => t.Date >= lastLine.Date).ToList(); foreach (var ledgerTransaction in unmatchedTxns) { IEnumerable <Transaction> statementTxns = ReconciliationBuilder.TransactionsToAutoMatch(statementSubSet, ledgerTransaction.AutoMatchingReference); if (statementTxns.None()) { this.logger.LogWarning( l => l.Format( "There appears to be some transactions from last month that should be auto-matched to a statement transactions, but no matching statement transactions were found. {0}", ledgerTransaction)); throw new ValidationWarningException( string.Format( CultureInfo.CurrentCulture, "There appears to be some transactions from last month that should be auto-matched to a statement transactions, but no matching statement transactions were found.\nHave you forgotten to do a transfer?\nTransaction ID:{0} Ref:{1} Amount:{2:C}", ledgerTransaction.Id, ledgerTransaction.AutoMatchingReference, ledgerTransaction.Amount)) { Source = "1" }; } } }
private void PreReconciliationValidation(LedgerBook ledgerBook, DateTime reconciliationDate, StatementModel statement) { var messages = new StringBuilder(); if (!ledgerBook.Validate(messages)) { throw new InvalidOperationException("Ledger book is currently in an invalid state. Cannot add new entries.\n" + messages); } if (statement == null) { return; } var startDate = ReconciliationBuilder.CalculateDateForReconcile(ledgerBook, reconciliationDate); ValidateDates(ledgerBook, startDate, reconciliationDate, statement); ValidateAgainstUncategorisedTransactions(startDate, reconciliationDate, statement); ValidateAgainstOrphanedAutoMatchingTransactions(ledgerBook, statement); ValidateAgainstMissingTransactions(reconciliationDate, statement); }