Inheritance: IModelValidate
Exemplo n.º 1
0
        /// <summary>
        ///     Locates the most recent <see cref="LedgerEntryLine" /> for the given date filter. Note that this will only return
        ///     the most recent line that fits the criteria.
        /// </summary>
        public virtual decimal LocateApplicableLedgerBalance([NotNull] LedgerBook ledgerBook,
                                                             [NotNull] GlobalFilterCriteria filter, string bucketCode)
        {
            CheckCacheForCleanUp();
            if (ledgerBook == null)
            {
                throw new ArgumentNullException(nameof(ledgerBook));
            }

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

            var line = LocateApplicableLedgerLine(ledgerBook, filter);

            if (line == null)
            {
                return(0);
            }

            return(line.Entries
                   .Where(ledgerEntry => ledgerEntry.LedgerBucket.BudgetBucket.Code == bucketCode)
                   .Select(ledgerEntry => ledgerEntry.Balance)
                   .FirstOrDefault());
        }
 public void TestInitialise()
 {
     var accountRepo = new InMemoryAccountTypeRepository();
     var bucketRepo = new BucketBucketRepoAlwaysFind();
     var subject = new Mapper_LedgerBookDto_LedgerBook(bucketRepo, accountRepo, new LedgerBucketFactory(bucketRepo, accountRepo), new LedgerTransactionFactory(), new Mock<IReconciliationBuilder>().Object);
     Result = subject.ToModel(TestData);
 }
Exemplo n.º 3
0
        internal void RecalculateClosingBalance(LedgerBook ledgerBook)
        {
            // Recalc balance based on opening balance and transactions.
            var previousLine   = ledgerBook.Reconciliations.Skip(1).FirstOrDefault();
            var openingBalance = LedgerEntryLine.FindPreviousEntryClosingBalance(previousLine, LedgerBucket);

            RecalculateClosingBalance(openingBalance);
        }
Exemplo n.º 4
0
 private static double CalculateChecksum(LedgerBook dataEntity)
 {
     // ReSharper disable once EnumerableSumInExplicitUncheckedContext - Used to calculate a checksum and revolving (overflowing) integers are ok here.
     return(dataEntity.Reconciliations.Sum(
                l =>
                (double)l.LedgerBalance
                + l.BankBalanceAdjustments.Sum(b => (double)b.Amount)
                + l.Entries.Sum(e => (double)e.Balance)));
 }
        public void UnlockMostRecentLineShouldNotThrowIfBookIsEmpty()
        {
            var subject = new LedgerBook(new FakeLogger())
            {
                Name = "Foo", Modified = new DateTime(2011, 12, 4), FileName = @"C:\TestLedgerBook.xml",
            };
            LedgerEntryLine result = subject.UnlockMostRecentLine();

            Assert.IsNull(result);
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="ReconciliationConsistencyChecker" /> class.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        public ReconciliationConsistencyChecker([NotNull] LedgerBook book)
        {
            if (book == null)
            {
                throw new ArgumentNullException(nameof(book));
            }

            this.ledgerBook = book;
            this.check1 = this.ledgerBook.Reconciliations.Sum(e => e.CalculatedSurplus);
        }
Exemplo n.º 7
0
        /// <summary>
        ///     Locates the applicable ledger line.
        /// </summary>
        public virtual LedgerEntryLine LocateApplicableLedgerLine(LedgerBook ledgerBook, DateTime beginDate)
        {
            CheckCacheForCleanUp();
            if (ledgerBook == null)
            {
                return(null);
            }

            return(LocateLedgerEntryLine(ledgerBook, beginDate, beginDate.AddMonths(1).AddDays(-1)));
        }
Exemplo n.º 8
0
 public static Dictionary<BudgetBucket, int> LedgerOrder(LedgerBook book)
 {
     var ledgerOrder = new Dictionary<BudgetBucket, int>();
     var index = 0;
     foreach (LedgerBucket ledger in book.Ledgers.OrderBy(l => l.BudgetBucket))
     {
         Debug.Write("{0}", ledger.BudgetBucket.Code.PadRight(20));
         ledgerOrder.Add(ledger.BudgetBucket, index++);
     }
     return ledgerOrder;
 }
        public void UnlockMostRecentLineShouldNotThrowIfBookIsEmpty()
        {
            this.subject = new LedgerBook(new ReconciliationBuilder(new FakeLogger()))
            {
                Name = "Foo",
                Modified = new DateTime(2011, 12, 4),
                StorageKey = @"C:\TestLedgerBook.xml"
            };
            LedgerEntryLine result = this.subject.UnlockMostRecentLine();

            Assert.IsNull(result);
        }
Exemplo n.º 10
0
        /// <summary>
        ///     Finds any overspent ledgers for the month and returns the date and value the of the total overspend.  This
        ///     resulting
        ///     collection can then be used to subtract from Surplus.
        ///     Overdrawn ledgers are supplemented from Surplus.
        ///     Negative values indicate overdrawn ledgers.
        /// </summary>
        public virtual IEnumerable <ReportTransaction> CalculateOverspentLedgers([NotNull] StatementModel statement,
                                                                                 [NotNull] LedgerBook ledger, DateTime beginDate)
        {
            CheckCacheForCleanUp();

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

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

            // Given the same ledger, statement and begin date this data won't change.
            return((IEnumerable <ReportTransaction>)GetOrAddFromCache(
                       BuildCacheKey(statement, ledger, beginDate),
                       () =>
            {
                var overSpendTransactions = new List <ReportTransaction>();
                var ledgerLine = LocateApplicableLedgerLine(ledger, beginDate);
                if (ledgerLine == null)
                {
                    return overSpendTransactions;
                }

                var endDate = beginDate.AddMonths(1);
                var currentDate = beginDate;
                Dictionary <BudgetBucket, decimal> runningBalances = ledgerLine.Entries.ToDictionary(entry => entry.LedgerBucket.BudgetBucket,
                                                                                                     entry => entry.Balance);
                Dictionary <BudgetBucket, decimal> previousBalances = ledgerLine.Entries.ToDictionary(entry => entry.LedgerBucket.BudgetBucket,
                                                                                                      entry => 0M);

                do
                {
                    var currentDateCopy = currentDate;
                    foreach (var transaction in statement.Transactions.Where(t => t.Date == currentDateCopy))
                    {
                        if (runningBalances.ContainsKey(transaction.BudgetBucket))
                        {
                            runningBalances[transaction.BudgetBucket] += transaction.Amount;
                        }
                    }

                    ProcessOverdrawnLedgers(runningBalances, previousBalances, overSpendTransactions, currentDate);

                    currentDate = currentDate.AddDays(1);
                } while (currentDate < endDate);
                return overSpendTransactions;
            }));
        }
        public void UsingInvalidLedgerBook_Reconcile_ShouldThrow()
        {
            var subject = new LedgerBook(new FakeLogger())
            {
                Name = "Foo", Modified = new DateTime(2012, 02, 29), FileName = "", 
            };

            subject.Reconcile(
                new DateTime(2012, 02, 20),
                new[] { new BankBalance(StatementModelTestData.ChequeAccount, 2050M) },
                BudgetModelTestData.CreateTestData1(),
                StatementModelTestData.TestData1());
        }
        public void TestIntialise()
        {
            this.mockBucketRepo = new Mock<IBudgetBucketRepository>();
            this.mockRuleService = new Mock<ITransactionRuleService>();
            this.mockReconciliationConsistency = new Mock<IReconciliationConsistency>();
            this.subject = new ReconciliationManager(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);
        }
        public override void Update([NotNull] params object[] input)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (!ValidateUpdateInput(input))
            {
                Enabled = false;
                return;
            }

            this.statement = (StatementModel)input[0];
            this.filter = (GlobalFilterCriteria)input[1];
            this.ledgerBook = (LedgerBook)input[2];

            if (this.ledgerBook == null || this.statement == null || this.filter == null || this.filter.Cleared || this.filter.BeginDate == null || this.filter.EndDate == null)
            {
                Enabled = false;
                return;
            }

            if (this.filter.BeginDate.Value.DurationInMonths(this.filter.EndDate.Value) != 1)
            {
                ToolTip = DesignedForOneMonthOnly;
                Enabled = false;
                return;
            }

            Enabled = true;
            decimal openingBalance = CalculateOpeningBalance(this.filter, this.ledgerBook);
            decimal remainingBalance = LedgerCalculation.CalculateCurrentMonthSurplusBalance(this.ledgerBook, this.filter, this.statement);

            Maximum = Convert.ToDouble(openingBalance);
            Value = Convert.ToDouble(remainingBalance);
            Minimum = 0;
            if (remainingBalance < 0.2M * openingBalance)
            {
                ColourStyleName = WidgetWarningStyle;
            }
            else
            {
                ColourStyleName = this.standardStyle;
            }

            ToolTip = string.Format(CultureInfo.CurrentCulture, "Remaining Surplus for period is {0:C} of {1:C}", remainingBalance, openingBalance);
        }
Exemplo n.º 14
0
        public LedgerBook Build()
        {
            var book = new LedgerBook(new ReconciliationBuilder(new FakeLogger()))
            {
                Name = Name,
                Modified = Modified,
                StorageKey = StorageKey
            };

            book.SetReconciliations(this.reconciliations);
            if (book.Reconciliations.None())
            {
                this.ledgerBuckets.ForEach(l => book.AddLedger(l));
            }

            LedgerBookTestData.Finalise(book, this.lockWhenFinished);
            return book;
        }
Exemplo n.º 15
0
        /// <summary>
        ///     Calculates the current month surplus balance.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        public virtual decimal CalculateCurrentMonthSurplusBalance([NotNull] LedgerBook ledgerBook,
                                                                   [NotNull] GlobalFilterCriteria filter, [NotNull] StatementModel statement)
        {
            CheckCacheForCleanUp();
            if (ledgerBook == null)
            {
                throw new ArgumentNullException(nameof(ledgerBook));
            }

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

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

            if (filter.Cleared || filter.BeginDate == null)
            {
                return(0);
            }

            var entryLine = LocateApplicableLedgerLine(ledgerBook, filter);

            if (entryLine == null)
            {
                return(0);
            }

            var beginningOfMonthBalance = entryLine.CalculatedSurplus;
            var transactionTotal        = CalculateTransactionTotal(filter.BeginDate.Value, statement, entryLine,
                                                                    SurplusBucket.SurplusCode);

            beginningOfMonthBalance += transactionTotal;

            // Find any ledgers that are overpsent and subtract them from the Surplus total.  This is actually what is happening when you overspend a ledger, it spills over and spend Surplus.
            Dictionary <BudgetBucket, decimal> ledgersSummary = CalculateLedgersBalanceSummary(ledgerBook, filter.BeginDate.Value, statement);

            beginningOfMonthBalance += ledgersSummary.Where(kvp => kvp.Value < 0).Sum(kvp => kvp.Value);

            return(beginningOfMonthBalance);
        }
Exemplo n.º 16
0
        public void Build(
            GlobalFilterCriteria criteria,
            StatementModel statementModel,
            BudgetModel budgetModel,
            LedgerBook ledgerBookModel)
        {
            var beginDate = CalculateBeginDate(criteria);
            var dateRangeDescription = string.Format(CultureInfo.CurrentCulture,
                "For the month starting {0:D} to {1:D} inclusive.", beginDate, beginDate.AddMonths(1).AddDays(-1));

            var listOfCharts = new List<BurnDownChartAnalyserResult>(this.budgetBucketRepository.Buckets.Count());
            foreach (var bucket in this.budgetBucketRepository.Buckets
                .Where(b => b is ExpenseBucket && b.Active)
                .OrderBy(b => b.Code))
            {
                var analysis = AnalyseDataForChart(statementModel, budgetModel, ledgerBookModel, bucket, beginDate);
                analysis.ChartTitle = string.Format(CultureInfo.CurrentCulture, "{0} Spending Chart", bucket.Code);
                listOfCharts.Add(analysis);
            }

            listOfCharts = listOfCharts.ToList();

            // Put surplus at the top.
            var analysisResult = AnalyseDataForChart(statementModel, budgetModel, ledgerBookModel,
                this.budgetBucketRepository.SurplusBucket, beginDate);
            analysisResult.ChartTitle = string.Format(CultureInfo.CurrentCulture, "{0} Spending Chart",
                this.budgetBucketRepository.SurplusBucket);
            listOfCharts.Insert(0, analysisResult);

            // Put any custom charts on top.
            foreach (var customChart in CustomCharts)
            {
                IEnumerable<BudgetBucket> buckets = this.budgetBucketRepository.Buckets
                    .Join(customChart.BucketIds, bucket => bucket.Code, code => code, (bucket, code) => bucket);

                var analysis = AnalyseDataForChart(statementModel, budgetModel, ledgerBookModel, buckets, beginDate);
                analysis.ChartTitle = customChart.Name;
                analysis.IsCustomAggregateChart = true;
                listOfCharts.Insert(0, analysis);
            }

            Results = new BurnDownCharts(beginDate, dateRangeDescription, listOfCharts);
        }
Exemplo n.º 17
0
 public BurnDownCharts BuildAllCharts(
     StatementModel statementModel,
     BudgetModel budgetModel,
     LedgerBook ledgerBookModel, 
     GlobalFilterCriteria criteria)
 {
     if (criteria == null) throw new ArgumentNullException(nameof(criteria));
     if (criteria.Cleared) throw new ArgumentException("There is no date range criteria set. This graph is intended for one month of data.");
     if (criteria.EndDate == null || criteria.BeginDate == null)
     {
         throw new ArgumentException("There is no date range set; either the begin or end date is not set. This graph is intended for one month of data.");
     }
     if (criteria.EndDate.Value.Subtract(criteria.EndDate.Value).Days > 31)
     {
         throw new ArgumentException("The date range is too great for this graph. This graph is intended for one month of data.");
     }
     this.chartsBuilder.Build(criteria, statementModel, budgetModel, ledgerBookModel);
     return this.chartsBuilder.Results;
 }
Exemplo n.º 18
0
        public async Task SaveAsync(LedgerBook book, string storageKey, bool isEncrypted)
        {
            if (book == null)
            {
                throw new ArgumentNullException(nameof(book));
            }

            if (storageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(storageKey));
            }

            var dataEntity = this.mapper.ToDto(book);

            book.StorageKey       = storageKey;
            dataEntity.StorageKey = storageKey;
            dataEntity.Checksum   = CalculateChecksum(book);

            await SaveDtoToDiskAsync(dataEntity, isEncrypted);
        }
Exemplo n.º 19
0
        public BurnDownChartAnalyserResult CreateNewCustomAggregateChart(
            StatementModel statementModel,
            BudgetModel budgetModel,
            IEnumerable<BudgetBucket> buckets,
            LedgerBook ledgerBookModel,
            DateTime beginDate,
            string chartTitle)
        {
            List<BudgetBucket> bucketsList = buckets.ToList();
            var result = this.chartAnalyser.Analyse(statementModel, budgetModel, bucketsList, ledgerBookModel, beginDate);
            result.ChartTitle = chartTitle;
            var persistChart = new CustomAggregateBurnDownGraph
            {
                BucketIds = bucketsList.Select(b => b.Code).ToList(),
                Name = chartTitle
            };

            this.chartsBuilder.CustomCharts = this.chartsBuilder.CustomCharts.Union(new[] { persistChart }).ToList();
            return result;
        }
        public void TestInitialise()
        {
            this.bucketRepo = new BucketBucketRepoAlwaysFind();
            this.subject = new RemainingSurplusWidget();
            this.criteriaTestData = new GlobalFilterCriteria
            {
                BeginDate = new DateTime(2015, 10, 20),
                EndDate = new DateTime(2015, 11, 19)
            };

            StatementModelTestDataForThisTest.AccountTypeRepo = new InMemoryAccountTypeRepository();
            StatementModelTestDataForThisTest.BudgetBucketRepo = this.bucketRepo;
            this.statementTestData = StatementModelTestDataForThisTest.TestDataGenerated();

            BudgetModel budgetModel = BudgetModelTestData.CreateTestData1();
            this.budgetTestData = new BudgetCurrencyContext(new BudgetCollection(budgetModel), budgetModel);

            this.ledgerBookTestData = new LedgerBookBuilder
            {
                StorageKey = "RemainingSurplusWidgetTest.xml",
                Modified = new DateTime(2015, 11, 23),
                Name = "Smith Budget 2015"
            }
                .IncludeLedger(LedgerBookTestData.PhoneLedger, 130M)
                .IncludeLedger(LedgerBookTestData.CarMtcLedger, 90M)
                .IncludeLedger(LedgerBookTestData.PowerLedger)
                .AppendReconciliation(
                    new DateTime(2015, 10, 20),
                    new BankBalance(LedgerBookTestData.ChequeAccount, 4502.75M))
                .WithReconciliationEntries(
                    entryBuilder =>
                    {
                        entryBuilder.WithLedger(LedgerBookTestData.PhoneLedger).HasNoTransactions();
                        entryBuilder.WithLedger(LedgerBookTestData.CarMtcLedger).HasNoTransactions();
                        entryBuilder.WithLedger(LedgerBookTestData.PowerLedger)
                            .AppendTransactions(txnBuilder => { txnBuilder.WithCredit(3000M, "Oct Savings", new DateTime(2015, 10, 20), "automatchref12"); });
                    })
                .Build();

            this.ledgerCalculation = new LedgerCalculation(new FakeLogger());
        }
        public void Reconcile_ShouldCreateBalanceAdjustmentOf150_GivenSavingsMonthlyBudgetAmountsSumTo150()
        {
            // 95 Car Mtc Monthly budget
            // 55 Hair cut monthly budget
            // ===
            // 150 Balance Adjustment expected in Savings
            // Power 175 goes in Chq
            this.subject = new LedgerBookBuilder()
                .IncludeLedger(new SavedUpForLedger { BudgetBucket = StatementModelTestData.CarMtcBucket, StoredInAccount = LedgerBookTestData.SavingsAccount })
                .IncludeLedger(new SavedUpForLedger { BudgetBucket = StatementModelTestData.HairBucket, StoredInAccount = LedgerBookTestData.SavingsAccount })
                .IncludeLedger(LedgerBookTestData.PowerLedger)
                .Build();

            Act();

            this.subject.Output(true);
            var resultRecon = this.subject.Reconciliations.First();

            Assert.AreEqual(150M, resultRecon.BankBalanceAdjustments.Single(b => b.BankAccount == LedgerBookTestData.SavingsAccount).Amount);
            Assert.AreEqual(-150M, resultRecon.BankBalanceAdjustments.Single(b => b.BankAccount == LedgerBookTestData.ChequeAccount).Amount);
        }
Exemplo n.º 22
0
        /// <summary>
        ///     Locates the applicable ledger line.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        public virtual LedgerEntryLine LocateApplicableLedgerLine(LedgerBook ledgerBook,
                                                                  [NotNull] GlobalFilterCriteria filter)
        {
            CheckCacheForCleanUp();
            if (ledgerBook == null)
            {
                return(null);
            }

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

            if (filter.Cleared)
            {
                return(ledgerBook.Reconciliations.FirstOrDefault());
            }

            Debug.Assert(filter.BeginDate != null);
            Debug.Assert(filter.EndDate != null);
            return(LocateLedgerEntryLine(ledgerBook, filter.BeginDate.Value, filter.EndDate.Value));
        }
Exemplo n.º 23
0
        private Dictionary <BudgetBucket, decimal> CalculateLedgersBalanceSummary(LedgerBook ledgerBook,
                                                                                  DateTime beginDate, StatementModel statement)
        {
            var endDate           = beginDate.AddMonths(1).AddDays(-1);
            var currentLegderLine = LocateLedgerEntryLine(ledgerBook, beginDate, endDate);

            if (currentLegderLine == null)
            {
                return(new Dictionary <BudgetBucket, decimal>());
            }

            var ledgersSummary = new Dictionary <BudgetBucket, decimal>();

            foreach (var entry in currentLegderLine.Entries)
            {
                var closingBalance = CalculateTransactionTotal(beginDate, statement, currentLegderLine,
                                                               entry.LedgerBucket.BudgetBucket.Code);
                var balance = entry.Balance + closingBalance;
                ledgersSummary.Add(entry.LedgerBucket.BudgetBucket, balance);
            }

            return(ledgersSummary);
        }
Exemplo n.º 24
0
        private static decimal CalculateSavingsToDateWithTrackedLedgers(StatementModel statement, LedgerBook ledger)
        {
            if (ledger == null)
            {
                return 0;
            }

            var trackedSavingsLedgers = ledger.Ledgers
                                            .Where(l => l.BudgetBucket is SavingsCommitmentBucket)
                                            .Select(l => l.BudgetBucket)
                                            .ToList();
            if (!trackedSavingsLedgers.Any())
            {
                return SumDebitSavingsTransactions(statement);
            }

            decimal savingsToDate = CalculateTrackedSavingLedgersContributions(statement, trackedSavingsLedgers);

            // Other non-ledger-book-tracked savings will appear as debits in the statement so need to be negated.
            var otherNontrackedSavings = statement.Transactions.Where(t => t.BudgetBucket is SavingsCommitmentBucket && trackedSavingsLedgers.All(b => b != t.BudgetBucket));
            savingsToDate += otherNontrackedSavings.Sum(t => -t.Amount);
            return savingsToDate;
        }
Exemplo n.º 25
0
        /// <summary>
        ///     Calculates the current month ledger balances.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        public virtual IDictionary <BudgetBucket, decimal> CalculateCurrentMonthLedgerBalances(
            [NotNull] LedgerBook ledgerBook,
            [NotNull] GlobalFilterCriteria filter,
            [NotNull] StatementModel statement)
        {
            CheckCacheForCleanUp();
            if (ledgerBook == null)
            {
                throw new ArgumentNullException(nameof(ledgerBook));
            }

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

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

            var ledgers = new Dictionary <BudgetBucket, decimal>();

            if (filter.Cleared || filter.BeginDate == null)
            {
                return(ledgers);
            }

            Dictionary <BudgetBucket, decimal> ledgersSummary = CalculateLedgersBalanceSummary(ledgerBook, filter.BeginDate.Value, statement);

            // Check Surplus
            var surplusBalance = CalculateCurrentMonthSurplusBalance(ledgerBook, filter, statement);

            ledgersSummary.Add(new SurplusBucket(), surplusBalance);

            return(ledgersSummary);
        }
Exemplo n.º 26
0
        /// <summary>
        ///     Calculates the current month bucket spend.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        public virtual decimal CalculateCurrentMonthBucketSpend(
            [NotNull] LedgerBook ledgerBook,
            [NotNull] GlobalFilterCriteria filter,
            [NotNull] StatementModel statement,
            [NotNull] string bucketCode)
        {
            CheckCacheForCleanUp();
            if (ledgerBook == null)
            {
                throw new ArgumentNullException(nameof(ledgerBook));
            }

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

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

            if (bucketCode.IsNothing())
            {
                throw new ArgumentNullException(nameof(bucketCode));
            }

            if (filter.BeginDate == null)
            {
                return(0);
            }

            var entryLine        = LocateApplicableLedgerLine(ledgerBook, filter);
            var transactionTotal = CalculateTransactionTotal(filter.BeginDate.Value, statement, entryLine, bucketCode);

            return(transactionTotal);
        }
 private void CreateLedgerBookTestData()
 {
     this.ledgerBookTestData = new LedgerBookBuilder
     {
         StorageKey = "BudgetBucketMonitorWidgetTest.xml",
         Modified = new DateTime(2015, 11, 23),
         Name = "Smith Budget 2015"
     }
         .IncludeLedger(LedgerBookTestData.PhoneLedger, 50M)
         .IncludeLedger(LedgerBookTestData.HouseInsLedgerSavingsAccount, 100M)
         .AppendReconciliation(
             new DateTime(2015, 10, 20),
             new BankBalance(LedgerBookTestData.ChequeAccount, 2000M),
             new BankBalance(LedgerBookTestData.SavingsAccount, 1000M))
         .WithReconciliationEntries(
             entryBuilder =>
             {
                 entryBuilder.WithLedger(LedgerBookTestData.PhoneLedger)
                     .AppendTransactions(txnBuilder => { txnBuilder.WithCredit(100, "Foo", new DateTime(2015, 10, 20), "automatchref12"); });
                 entryBuilder.WithLedger(LedgerBookTestData.HouseInsLedgerSavingsAccount)
                     .AppendTransactions(txnBuilder => { txnBuilder.WithCredit(-100, "Foo", new DateTime(2015, 10, 20), "automatchref12"); });
             })
         .Build();
 }
        public async Task SaveAsync(LedgerBook book, string storageKey, bool isEncrypted)
        {
            if (book == null)
            {
                throw new ArgumentNullException(nameof(book));
            }

            if (storageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(storageKey));
            }

            var dataEntity = this.mapper.ToDto(book);
            book.StorageKey = storageKey;
            dataEntity.StorageKey = storageKey;
            dataEntity.Checksum = CalculateChecksum(book);

            await SaveDtoToDiskAsync(dataEntity, isEncrypted);
        }
Exemplo n.º 29
0
 private static LedgerEntryLine LocateLedgerEntryLine(LedgerBook ledgerBook, DateTime begin, DateTime end)
 {
     return
         (ledgerBook.Reconciliations.FirstOrDefault(
              ledgerEntryLine => ledgerEntryLine.Date >= begin && ledgerEntryLine.Date <= end));
 }
Exemplo n.º 30
0
 private BurnDownChartAnalyserResult AnalyseDataForChart(
     StatementModel statementModel,
     BudgetModel budgetModel,
     LedgerBook ledgerBookModel,
     IEnumerable<BudgetBucket> buckets,
     DateTime beginDate)
 {
     var analyser = this.chartAnalyserFactory();
     var result = analyser.Analyse(statementModel, budgetModel, buckets, ledgerBookModel, beginDate);
     return result;
 }
Exemplo n.º 31
0
        private static LedgerBook Finalise(LedgerBook book)
        {
            foreach (LedgerEntryLine line in book.DatedEntries)
            {
                PrivateAccessor.SetProperty(line, "IsNew", false);
                foreach (LedgerEntry entry in line.Entries)
                {
                    PrivateAccessor.SetField(entry, "isNew", false);
                }
            }

            return book;
        }
Exemplo n.º 32
0
        private static IEnumerable<LedgerEntry> CompileLedgersAndBalances(LedgerBook parentLedgerBook)
        {
            var ledgersAndBalances = new List<LedgerEntry>();
            var previousLine = parentLedgerBook.Reconciliations.FirstOrDefault();
            if (previousLine == null)
            {
                return parentLedgerBook.Ledgers.Select(ledger => new LedgerEntry { Balance = 0, LedgerBucket = ledger });
            }

            foreach (var ledger in parentLedgerBook.Ledgers)
            {
                // Ledger Columns from a previous are not necessarily equal if the StoredInAccount has changed.
                var previousEntry =
                    previousLine.Entries.FirstOrDefault(e => e.LedgerBucket.BudgetBucket == ledger.BudgetBucket);

                // Its important to use the ledger column value from the book level map, not from the previous entry. The user
                // could have moved the ledger to a different account and so, the ledger column value in the book level map will be different.
                if (previousEntry == null)
                {
                    // Indicates a new ledger column has been added to the book starting this month.
                    ledgersAndBalances.Add(new LedgerEntry { Balance = 0, LedgerBucket = ledger });
                }
                else
                {
                    ledgersAndBalances.Add(previousEntry);
                }
            }

            return ledgersAndBalances;
        }
 public IDisposable EnsureConsistency(LedgerBook book)
 {
     return new ReconciliationConsistencyChecker(book);
 }
 private static double CalculateChecksum(LedgerBook dataEntity)
 {
     // ReSharper disable once EnumerableSumInExplicitUncheckedContext - Used to calculate a checksum and revolving (overflowing) integers are ok here.
     return dataEntity.Reconciliations.Sum(
         l =>
             (double) l.LedgerBalance
             + l.BankBalanceAdjustments.Sum(b => (double) b.Amount)
             + l.Entries.Sum(e => (double) e.Balance));
 }
Exemplo n.º 35
0
        public BurnDownChartAnalyserResult Analyse(StatementModel statementModel, BudgetModel budgetModel,
                                                   IEnumerable<BudgetBucket> bucketsSubset, LedgerBook ledgerBook, DateTime beginDate)
        {
            if (statementModel == null)
            {
                throw new ArgumentNullException(nameof(statementModel));
            }

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

            List<BudgetBucket> bucketsCopy = bucketsSubset.ToList();
            this.logger.LogInfo(
                l => "BurnDownChartAnalyser.Analyse: " + string.Join(" ", bucketsCopy.Select(b => b.Code)));

            var result = new BurnDownChartAnalyserResult();

            List<DateTime> datesOfTheMonth = YieldAllDaysInDateRange(beginDate);
            var lastDate = datesOfTheMonth.Last();

            CreateZeroLine(datesOfTheMonth, result);

            var openingBalance = GetBudgetedTotal(budgetModel, ledgerBook, bucketsCopy, beginDate);
            CalculateBudgetLineValues(openingBalance, datesOfTheMonth, result);

            List<ReportTransactionWithRunningBalance> spendingTransactions = CollateStatementTransactions(statementModel, bucketsCopy, beginDate, lastDate,
                openingBalance);

            // Only relevant when calculating surplus burndown - ovespent ledgers are supplemented from surplus so affect its burndown.
            if (ledgerBook != null && bucketsCopy.OfType<SurplusBucket>().Any())
            {
                List<ReportTransaction> overSpentLedgers =
                    this.ledgerCalculator.CalculateOverspentLedgers(statementModel, ledgerBook, beginDate).ToList();
                if (overSpentLedgers.Any())
                {
                    spendingTransactions.AddRange(
                        overSpentLedgers.Select(t => new ReportTransactionWithRunningBalance(t)));
                    spendingTransactions = spendingTransactions.OrderBy(t => t.Date).ToList();
                    UpdateReportTransactionRunningBalances(spendingTransactions);
                }
            }

            // Copy running balance from transaction list into burndown chart data
            var actualSpending = new SeriesData
            {
                SeriesName = BurnDownChartAnalyserResult.BalanceSeriesName,
                Description = "Running balance over time as transactions spend, the balance decreases."
            };
            result.GraphLines.SeriesList.Add(actualSpending);
            foreach (var day in datesOfTheMonth)
            {
                if (day > DateTime.Today)
                {
                    break;
                }

                var dayClosingBalance = GetDayClosingBalance(spendingTransactions, day);
                actualSpending.PlotsList.Add(new DatedGraphPlot { Date = day, Amount = dayClosingBalance });
                var copyOfDay = day;
                this.logger.LogInfo(l => l.Format("    {0} Close Bal:{1:N}", copyOfDay, dayClosingBalance));
            }

            result.ReportTransactions = spendingTransactions;
            return result;
        }
Exemplo n.º 36
0
        /// <summary>
        ///     Same as Test Data 2, but with multiple Bank Balances for the latest entry.
        ///     A Test LedgerBook with data populated for June July and August 2013.  Also includes some debit transactions.
        ///     August transactions include some balance adjustments.
        /// </summary>
        public static LedgerBook TestData4()
        {
            var hairLedger = new LedgerColumn { BudgetBucket = new SavedUpForExpenseBucket(TestDataConstants.HairBucketCode, "Hair cuts wheelbarrow.") };
            var powerLedger = new LedgerColumn { BudgetBucket = new SpentMonthlyExpenseBucket(TestDataConstants.PowerBucketCode, "Power ") };
            var phoneLedger = new LedgerColumn { BudgetBucket = new SpentMonthlyExpenseBucket(TestDataConstants.PhoneBucketCode, "Poo bar") };

            var book = new LedgerBook(new FakeLogger())
            {
                Name = "Test Data 4 Book",
                Modified = new DateTime(2013, 12, 16),
                FileName = "C:\\Folder\\book1.xml",
            };

            var list = new List<LedgerEntryLine>
            {
                CreateLine(new DateTime(2013, 06, 15), new[] { new BankBalance(StatementModelTestData.ChequeAccount, 2500) }, "Lorem ipsum").SetEntries(new List
                    <LedgerEntry>
                {
                    CreateLedgerEntry(hairLedger).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 55M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 45M, Narrative = "Hair cut" },
                    }),
                    CreateLedgerEntry(powerLedger).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 140M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 123.56M, Narrative = "Power bill" },
                    }),
                    CreateLedgerEntry(phoneLedger).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 95M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 86.43M, Narrative = "Pay phones" },
                    })
                }),
            };

            LedgerEntry previousHairEntry = list.Last().Entries.Single(e => e.LedgerColumn.BudgetBucket.Code == TestDataConstants.HairBucketCode);
            LedgerEntry previousPowerEntry = list.Last().Entries.Single(e => e.LedgerColumn.BudgetBucket.Code == TestDataConstants.PowerBucketCode);
            LedgerEntry previousPhoneEntry = list.Last().Entries.Single(e => e.LedgerColumn.BudgetBucket.Code == TestDataConstants.PhoneBucketCode);

            list.Add(
                CreateLine(new DateTime(2013, 07, 15), new[] { new BankBalance(StatementModelTestData.ChequeAccount, 3700) }, "dolor amet set").SetEntries(new List
                    <LedgerEntry>
                {
                    CreateLedgerEntry(hairLedger, previousHairEntry.Balance).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 55M, Debit = 0M, Narrative = "Budgeted amount" },
                    }),
                    CreateLedgerEntry(powerLedger, previousPowerEntry.Balance).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 140M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 145.56M, Narrative = "Power bill" },
                    }),
                    CreateLedgerEntry(phoneLedger, previousPhoneEntry.Balance).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 95M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 66.43M, Narrative = "Pay phones" },
                    })
                }));

            previousHairEntry = list.Last().Entries.Single(e => e.LedgerColumn.BudgetBucket.Code == TestDataConstants.HairBucketCode);
            previousPowerEntry = list.Last().Entries.Single(e => e.LedgerColumn.BudgetBucket.Code == TestDataConstants.PowerBucketCode);
            previousPhoneEntry = list.Last().Entries.Single(e => e.LedgerColumn.BudgetBucket.Code == TestDataConstants.PhoneBucketCode);

            LedgerEntryLine line = CreateLine(new DateTime(2013, 08, 15),
                new[] { new BankBalance(StatementModelTestData.ChequeAccount, 2750), new BankBalance(StatementModelTestData.SavingsAccount, 200) },
                "The quick brown fox jumped over the lazy dog").SetEntries(new List<LedgerEntry>
                {
                    CreateLedgerEntry(hairLedger, previousHairEntry.Balance).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 55M, Debit = 0M, Narrative = "Budgeted amount" },
                    }),
                    CreateLedgerEntry(powerLedger, previousPowerEntry.Balance).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 140M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 98.56M, Narrative = "Power bill" },
                    }),
                    CreateLedgerEntry(phoneLedger, previousPhoneEntry.Balance).SetTransactions(new List<LedgerTransaction>
                    {
                        new BudgetCreditLedgerTransaction { Credit = 95M, Debit = 0M, Narrative = "Budgeted amount" },
                        new DebitLedgerTransaction { Credit = 0M, Debit = 67.43M, Narrative = "Pay phones" },
                    })
                });
            line.BalanceAdjustment(-550, "Credit card payment yet to go out.");
            list.Add(line);

            book.SetDatedEntries(list);

            return Finalise(book);
        }
 public void TestInitialise()
 {
     this.testDataBudget = BudgetModelTestData.CreateTestData1();
     this.testDataStatement = StatementModelTestData.TestData1();
     this.subject = LedgerBookTestData.TestData1();
 }
        private void ActOnTestData5(StatementModel statementModelTestData = null)
        {
            this.subject = LedgerBookTestData.TestData5();
            this.testDataBudget = BudgetModelTestData.CreateTestData5();
            this.testDataStatement = statementModelTestData ?? StatementModelTestData.TestData5();

            Console.WriteLine("********************** BEFORE RUNNING RECONCILIATION *******************************");
            this.testDataStatement.Output(ReconcileDate.AddMonths(-1));
            this.subject.Output(true);

            var result = Act(bankBalances: new[] { new BankBalance(StatementModelTestData.ChequeAccount, 1850.5M), new BankBalance(StatementModelTestData.SavingsAccount, 1200M) });
            this.testDataToDoList = result.Tasks.ToList();

            Console.WriteLine();
            Console.WriteLine("********************** AFTER RUNNING RECONCILIATION *******************************");
            this.subject.Output(true);
        }
 public void TestInitialise()
 {
     AutoMapperConfigurationTest.AutoMapperConfiguration();
     TestData = LedgerBookTestData.TestData2();
 }
 public void TestInitialise()
 {
     TestData = LedgerBookTestData.TestData2();
 }
Exemplo n.º 41
0
 public void TestInitialise()
 {
     Subject = new LedgerCalculation();
     TestData = LedgerBookTestData.TestData1();
 }
Exemplo n.º 42
0
        /// <summary>
        ///     When creating a new reconciliation a start date is required to be able to search a statement for transactions
        ///     between the start date and the reconciliation date specified (today or pay day). The start date should start from
        ///     the previous ledger entry line or
        ///     one month prior if no records exist.
        /// </summary>
        /// <param name="ledgerBook">The Ledger Book to find the date for</param>
        /// <param name="reconciliationDate">The chosen reconciliation date from the user</param>
        internal static DateTime CalculateDateForReconcile(LedgerBook ledgerBook, DateTime reconciliationDate)
        {
            if (ledgerBook.Reconciliations.Any())
            {
                return ledgerBook.Reconciliations.First().Date;
            }

            var startDateIncl = reconciliationDate.AddMonths(-1);
            return startDateIncl;
        }