コード例 #1
0
        public void UsingTestData1_FirstLineShouldHaveBankBalance2950()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(2950, subject.TotalBankBalance);
        }
コード例 #2
0
        private void SetReconciliation(IReadOnlyDictionary <LedgerBucket, SpecificLedgerEntryTestDataBuilder> ledgers, string remarks)
        {
            var recon = new LedgerEntryLine(this.tempReconDate, this.tempBankBalances)
            {
                Remarks = remarks
            };
            LedgerEntryLine previousRecon = Reconciliations.OrderByDescending(r => r.Date).FirstOrDefault();
            var             entries       = new List <LedgerEntry>();

            foreach (LedgerBucket ledgerBucket in this.ledgerBuckets)
            {
                decimal openingBalance;
                if (previousRecon == null)
                {
                    openingBalance = this.openingBalances[ledgerBucket];
                }
                else
                {
                    LedgerEntry previousEntry = previousRecon.Entries.Single(e => e.LedgerBucket == ledgerBucket);
                    openingBalance = previousEntry.Balance;
                }
                var entry = new LedgerEntry
                {
                    LedgerBucket = ledgerBucket,
                    Balance      = openingBalance
                };
                entry.SetTransactionsForTesting(ledgers[ledgerBucket].Transactions.ToList());
                entries.Add(entry);
            }

            recon.SetEntriesForTesting(entries);
            this.reconciliations.Add(recon);
        }
コード例 #3
0
        private void OnShellDialogResponseReceived(ShellDialogResponseMessage message)
        {
            if (!message.IsItForMe(this.dialogCorrelationId))
            {
                return;
            }

            if (message.Response == ShellDialogButton.Ok)
            {
                if (ShowAddingNewTransactionPanel)
                {
                    OnAddNewTransactionCommandExecuted();
                }

                Save();
                this.entryLine = null;
                LedgerEntry    = null;
            }

            if (message.Response == ShellDialogButton.Cancel)
            {
                this.isAddDirty = false;
                this.entryLine  = null;
                LedgerEntry     = null;
            }

            EventHandler <LedgerTransactionEventArgs> handler = Complete;

            handler?.Invoke(this, new LedgerTransactionEventArgs(this.wasChanged));

            Reset();
            this.wasChanged = false;
        }
コード例 #4
0
        private decimal RetrieveOpeningBalance()
        {
            var  book  = this.ledgerService.LedgerBook;
            bool found = false;
            IEnumerable <LedgerEntryLine> remainingRecons = book.Reconciliations.SkipWhile(r =>
            {
                // Find the recon that directly precedes this current one.
                if (found)
                {
                    return(false);       // Found recon line on previous pass, now return.
                }
                found = r.Entries.Contains(LedgerEntry);
                return(true); // Keep skipping...
            }).Take(1);

            LedgerEntryLine previousLine = remainingRecons.FirstOrDefault();

            if (previousLine == null)
            {
                return(0M);
            }
            var previousEntry = previousLine.Entries.FirstOrDefault(l => l.LedgerBucket == LedgerEntry.LedgerBucket);

            return(previousEntry?.Balance ?? 0M);
        }
コード例 #5
0
        public void UsingTestData1_FirstLineShouldHaveSurplusOf2712()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(2712.97M, subject.CalculatedSurplus);
        }
コード例 #6
0
        public void UsingTestData1_FirstLineShouldHaveDate20130815()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(new DateTime(2013, 08, 15), subject.Date);
        }
コード例 #7
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);
        }
コード例 #8
0
        public void UsingTestData1_FirstLineShouldHave3Entries()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(3, subject.Entries.Count());
        }
コード例 #9
0
 public static IEnumerable <LedgerTransaction> FindAutoMatchingTransactions([CanBeNull] LedgerEntryLine recon, bool includeMatchedTransactions = false)
 {
     if (recon == null)
     {
         return(new List <LedgerTransaction>());
     }
     return(recon.Entries.SelectMany(e => FindAutoMatchingTransactions(e, includeMatchedTransactions)));
 }
コード例 #10
0
        public void ShouldMapLineBankBalance()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(TestData.Reconciliations.First().BankBalance, subject.TotalBankBalance);
            Assert.AreNotEqual(0, subject.TotalBankBalance);
        }
コード例 #11
0
        public BankBalanceViewModel([CanBeNull] LedgerEntryLine line, [NotNull] BankBalance balance) : base(balance.Account, balance.Balance)
        {
            if (balance == null)
            {
                throw new ArgumentNullException(nameof(balance));
            }

            this.line = line;
        }
コード例 #12
0
        public void CancelBalanceAdjustment(LedgerEntryLine entryLine, Guid transactionId)
        {
            if (entryLine == null)
            {
                throw new ArgumentNullException(nameof(entryLine));
            }

            entryLine.CancelBalanceAdjustment(transactionId);
        }
コード例 #13
0
        private static LedgerEntryLine CreateLine(DateTime date, IEnumerable <BankBalance> bankBalances, string remarks)
        {
            var line = new LedgerEntryLine(date, bankBalances)
            {
                Remarks = remarks
            };

            return(line);
        }
コード例 #14
0
        /// <summary>
        ///     Transfer funds from one ledger bucket to another. This is only possible if the current ledger reconciliation is
        ///     unlocked.
        ///     This is usually used during reconciliation.
        /// </summary>
        /// <param name="ledgerBook">The parent ledger book.</param>
        /// <param name="reconciliation">
        ///     The reconciliation line that this transfer will be created in.  A transfer can only occur
        ///     between two ledgers in the same reconciliation.
        /// </param>
        /// <param name="transferDetails">The details of the requested transfer.</param>
        public void TransferFunds(LedgerBook ledgerBook, LedgerEntryLine reconciliation, TransferFundsCommand transferDetails)
        {
            if (reconciliation == null)
            {
                throw new ArgumentNullException(nameof(reconciliation), "There are no reconciliations. Transfer funds can only be used on the most recent reconciliation.");
            }

            this.reconciliationManager.TransferFunds(ledgerBook, transferDetails, reconciliation);
        }
コード例 #15
0
        public void ShouldMapLineBalanceAdjustments()
        {
            TestData = LedgerBookDtoTestData.TestData2();
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(TestData.Reconciliations.First().BankBalanceAdjustments.Sum(a => a.Amount), subject.TotalBalanceAdjustments);
            Assert.AreNotEqual(0, subject.BankBalanceAdjustments.Count());
        }
コード例 #16
0
        public void Initialise(params object[] anyParameters)
        {
            foreach (var argument in anyParameters)
            {
                NewReconLine = NewReconLine ?? argument as LedgerEntryLine;
            }

            if (NewReconLine == null)
            {
                throw new ArgumentNullException(nameof(NewReconLine));
            }
        }
コード例 #17
0
        public static void Output(this LedgerEntryLine line, Dictionary <BudgetBucket, int> ledgerOrder, bool outputTransactions = false, bool outputHeader = false)
        {
            if (outputHeader)
            {
                OutputReconciliationHeader();
            }

            Debug.Write($"{line.Date:d}  ");
            foreach (var entry in line.Entries.OrderBy(e => e.LedgerBucket.BudgetBucket))
            {
                Debug.Write($"{entry.NetAmount.ToString("N").PadRight(8)} {entry.LedgerBucket.StoredInAccount.Name.Truncate(1)} {entry.Balance.ToString("N").PadRight(9)}");
            }

            Debug.Write(line.CalculatedSurplus.ToString("N").PadRight(9));
            var balanceCount = 0;

            foreach (var bankBalance in line.BankBalances)
            {
                if (++balanceCount > 2)
                {
                    break;
                }
                // Only two bank balances are shown in the test output at this stage.
                var balanceText = string.Format("{0} {1} ", bankBalance.Account.Name.Truncate(1), bankBalance.Balance.ToString("N"));
                Debug.Write(balanceText.PadLeft(13).TruncateLeft(13));
            }
            Debug.Write(line.TotalBalanceAdjustments.ToString("N").PadLeft(9).TruncateLeft(9));
            Debug.Write(line.LedgerBalance.ToString("N").PadLeft(13).TruncateLeft(13));
            Debug.WriteLine(string.Empty);

            if (outputTransactions)
            {
                foreach (var entry in line.Entries.OrderBy(e => e.LedgerBucket.BudgetBucket))
                {
                    var tab = new string(' ', 11 + 18 * ledgerOrder[entry.LedgerBucket.BudgetBucket]);
                    foreach (var transaction in entry.Transactions)
                    {
                        Debug.WriteLine(
                            "{0} {1} {2} {3} {4} {5}",
                            tab,
                            entry.LedgerBucket.BudgetBucket.Code.PadRight(6),
                            transaction.Amount >= 0 ? (transaction.Amount.ToString("N") + "Cr").PadLeft(8) : (transaction.Amount.ToString("N") + "Dr").PadLeft(16),
                            transaction.Narrative.Truncate(15),
                            transaction.Id,
                            transaction.AutoMatchingReference);
                    }
                }
                Debug.WriteLine("=================================================================================================================================");
            }
        }
コード例 #18
0
        public void Show(LedgerEntryLine line, bool isNew)
        {
            LedgerEntryLine          = line;
            Remarks                  = LedgerEntryLine.Remarks;
            IsReadOnly               = !isNew;
            this.dialogCorrelationId = Guid.NewGuid();
            var dialogRequest = new ShellDialogRequestMessage(BudgetAnalyserFeature.LedgerBook, this, ShellDialogType.Ok)
            {
                Title         = "Ledger Entry Remarks",
                CorrelationId = this.dialogCorrelationId
            };

            MessengerInstance.Send(dialogRequest);
        }
コード例 #19
0
        public void UpdateRemarks(LedgerEntryLine entryLine, string remarks)
        {
            if (entryLine == null)
            {
                throw new ArgumentNullException(nameof(entryLine));
            }

            if (remarks == null)
            {
                throw new ArgumentNullException(nameof(remarks));
            }

            entryLine.UpdateRemarks(remarks);
        }
コード例 #20
0
        /// <summary>
        ///     Show the Ledger Transactions view, for viewing and editing Balance Adjustments
        /// </summary>
        public void ShowBankBalanceAdjustmentsDialog(LedgerEntryLine ledgerEntryLine, bool isNew)
        {
            if (ledgerEntryLine == null)
            {
                return;
            }

            InBalanceAdjustmentMode = true;
            InLedgerEntryMode       = false;
            LedgerEntry             = null;
            this.entryLine          = ledgerEntryLine;
            ShownTransactions       = new ObservableCollection <LedgerTransaction>(ledgerEntryLine.BankBalanceAdjustments);
            Title = "Balance Adjustment Transactions";
            ShowDialogCommon(isNew);
        }
コード例 #21
0
        /// <summary>
        ///     Show the Ledger Transactions view for viewing and editing Ledger Transactions.
        /// </summary>
        public void ShowLedgerTransactionsDialog(LedgerEntryLine ledgerEntryLine, LedgerEntry ledgerEntry, bool isNew)
        {
            if (ledgerEntry == null)
            {
                return;
            }

            InBalanceAdjustmentMode = false;
            InLedgerEntryMode       = true;
            LedgerEntry             = ledgerEntry;
            this.entryLine          = ledgerEntryLine; // Will be null when editing an existing LedgerEntry as opposed to creating a new reconciliation.
            ShownTransactions       = new ObservableCollection <LedgerTransaction>(LedgerEntry.Transactions);
            Title          = string.Format(CultureInfo.CurrentCulture, "{0} Transactions", ledgerEntry.LedgerBucket.BudgetBucket.Code);
            OpeningBalance = RetrieveOpeningBalance();
            ShowDialogCommon(isNew);
        }
コード例 #22
0
        public void TestIntialise()
        {
            this.mockBucketRepo  = new Mock <IBudgetBucketRepository>();
            this.mockRuleService = new Mock <ITransactionRuleService>();
            this.mockReconciliationConsistency = new Mock <IReconciliationConsistency>();
            this.subject = new ReconciliationCreationManager(this.mockRuleService.Object, this.mockReconciliationConsistency.Object, new FakeLogger());

            this.testDataLedgerBook = LedgerBookTestData.TestData5(() => new LedgerBookTestHarness(new Mock <IReconciliationBuilder>().Object));
            this.testDataEntryLine  = this.testDataLedgerBook.Reconciliations.First();
            this.testDataEntryLine.Unlock();

            this.surplusChqLedger = new SurplusLedger {
                StoredInAccount = StatementModelTestData.ChequeAccount
            };
            this.insHomeSavLedger = this.testDataLedgerBook.Ledgers.Single(l => l.BudgetBucket == StatementModelTestData.InsHomeBucket);
            this.phNetChqLedger   = this.testDataLedgerBook.Ledgers.Single(l => l.BudgetBucket == StatementModelTestData.PhoneBucket);
        }
コード例 #23
0
        private static decimal GetLedgerBalanceForBucket(BudgetModel budgetModel, LedgerEntryLine applicableLine,
                                                         BudgetBucket bucket)
        {
            if (bucket is SurplusBucket)
            {
                return(applicableLine.CalculatedSurplus);
            }

            var ledger = applicableLine.Entries.FirstOrDefault(e => e.LedgerBucket.BudgetBucket == bucket);

            if (ledger != null)
            {
                return(ledger.Balance);
            }

            // The Ledger line might not actually have a ledger for the given bucket.
            return(GetBudgetModelTotalForBucket(budgetModel, bucket));
        }
コード例 #24
0
        public void ShowDialog([NotNull] LedgerEntryLine ledgerLine)
        {
            if (ledgerLine == null)
            {
                throw new ArgumentNullException(nameof(ledgerLine));
            }

            SurplusBalances      = new ObservableCollection <BankBalance>(ledgerLine.SurplusBalances);
            this.ledgerEntryLine = ledgerLine;

            var dialogRequest = new ShellDialogRequestMessage(BudgetAnalyserFeature.LedgerBook, this, ShellDialogType.Ok)
            {
                CorrelationId = Guid.NewGuid(),
                Title         = "Surplus Balances in all Accounts"
            };

            MessengerInstance.Send(dialogRequest);
        }
コード例 #25
0
        private static string BuildToolTipForBankBalance(LedgerEntryLine line)
        {
            var individualLedgerBalances = new StringBuilder();

            foreach (BankBalance bankBalance in line.BankBalances)
            {
                individualLedgerBalances.AppendFormat(
                    CultureInfo.CurrentCulture,
                    "{0}: {1:N}; ",
                    bankBalance.Account,
                    bankBalance.Balance + line.BankBalanceAdjustments.Where(a => a.BankAccount == bankBalance.Account).Sum(a => a.Amount));
            }

            return(string.Format(
                       CultureInfo.CurrentCulture,
                       "Total Ledger Balance: {0:N}; Adjusted Bank Balance {1:N}; {2}",
                       line.LedgerBalance,
                       line.TotalBankBalance + line.TotalBalanceAdjustments,
                       individualLedgerBalances));
        }
コード例 #26
0
        /// <summary>
        ///     Used to show the bank balances involved in this <see cref="LedgerEntryLine" />.
        ///     Only shows balances at this stage, no editing allowed.
        /// </summary>
        public void ShowViewDialog([NotNull] Engine.Ledger.LedgerBook ledgerBook, [NotNull] LedgerEntryLine line)
        {
            if (ledgerBook == null)
            {
                throw new ArgumentNullException(nameof(ledgerBook));
            }

            if (line == null)
            {
                throw new ArgumentNullException(nameof(line));
            }

            this.parentBook      = ledgerBook;
            Date                 = line.Date;
            BankBalances         = new ObservableCollection <BankBalanceViewModel>(line.BankBalances.Select(b => new BankBalanceViewModel(line, b)));
            CreateMode           = false;
            AddBalanceVisibility = false;
            Editable             = false; // Bank balances are not editable after creating a new Ledger Line at this stage.

            ShowDialogCommon(Editable ? "Edit Bank Balances" : "Bank Balances");
        }
コード例 #27
0
        public ReconciliationResult CreateNewMonthlyReconciliation(
            DateTime reconciliationDateExclusive,
            BudgetModel budget,
            StatementModel statement,
            params BankBalance[] bankBalances)
        {
            if (bankBalances == null)
            {
                throw new ArgumentNullException(nameof(bankBalances));
            }

            if (budget == null)
            {
                throw new ArgumentNullException(nameof(budget));
            }

            if (statement == null)
            {
                throw new ArgumentNullException(nameof(statement));
            }

            if (LedgerBook == null)
            {
                throw new ArgumentException("The Ledger Book property cannot be null. You must set this prior to calling this method.");
            }

            try
            {
                this.newReconciliationLine = new LedgerEntryLine(reconciliationDateExclusive, bankBalances);
                AddNew(budget, statement, CalculateDateForReconcile(LedgerBook, reconciliationDateExclusive));

                return(new ReconciliationResult {
                    Reconciliation = this.newReconciliationLine, Tasks = this.toDoList
                });
            }
            finally
            {
                this.newReconciliationLine = null;
            }
        }
コード例 #28
0
        private int AddSurplusCell(Grid grid, int gridRow, int gridColumn, LedgerEntryLine line)
        {
            AddBorderToGridCell(grid, SurplusBackground, false, gridRow, gridColumn);

            var stackPanel = new StackPanel {
                Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Right
            };

            grid.Children.Add(stackPanel);
            Grid.SetRow(stackPanel, gridRow);
            Grid.SetColumn(stackPanel, gridColumn);

            if (line.SurplusBalances.Any(b => b.Balance < 0))
            {
                var warningImage = new ContentControl
                {
                    Template = (ControlTemplate)FindResource("WarningImage"),
                    Width    = 20,
                    Height   = 20,
                    Margin   = new Thickness(5),
                    ToolTip  = "There are one or more negative surplus balances!"
                };
                stackPanel.Children.Add(warningImage);
            }

            var hyperlink = new Hyperlink(new Run(line.CalculatedSurplus.ToString("N", CultureInfo.CurrentCulture)))
            {
                Command          = this.showSurplusBalancesCommand,
                CommandParameter = line
            };
            var textBlock = new TextBlock(hyperlink)
            {
                Style      = (Style)FindResource(ImportantNumberStyle),
                ToolTip    = string.Format(CultureInfo.CurrentCulture, "Total Surplus: {0:N}. Click for more detail...", line.CalculatedSurplus),
                Foreground = (Brush)FindResource(SurplusTextBrush)
            };

            stackPanel.Children.Add(textBlock);
            return(++gridRow);
        }
コード例 #29
0
        public LedgerTransaction CreateBalanceAdjustment(LedgerEntryLine entryLine, decimal amount, string narrative,
                                                         Account account)
        {
            if (entryLine == null)
            {
                throw new ArgumentNullException(nameof(entryLine));
            }

            if (narrative == null)
            {
                throw new ArgumentNullException(nameof(narrative));
            }

            if (account == null)
            {
                throw new ArgumentNullException(nameof(account));
            }

            var adjustmentTransaction = entryLine.BalanceAdjustment(amount, narrative, account);

            adjustmentTransaction.Date = entryLine.Date;
            return(adjustmentTransaction);
        }
コード例 #30
0
 private void OnShowSurplusBalancesCommandExecuted(LedgerEntryLine line)
 {
     this.uiContext.ShowSurplusBalancesController.ShowDialog(line);
 }
コード例 #31
0
 partial void ToDtoPostprocessing(ref LedgerEntryLineDto dto, LedgerEntryLine model)
 {
     dto.BankBalance = model.TotalBankBalance;
 }
コード例 #32
0
 partial void ToModelPostprocessing(LedgerEntryLineDto dto, ref LedgerEntryLine model)
 {
     model.Lock();
 }