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);
 }
        public void UsingTestData1_FirstLineShouldHaveSurplusOf2712()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(2712.97M, subject.CalculatedSurplus);
        }
 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);
 }
        public void UsingTestData1_FirstLineShouldHaveDate20130815()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(new DateTime(2013, 08, 15), subject.Date);
        }
        public void UsingTestData1_FirstLineShouldHaveBankBalance2950()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(2950, subject.TotalBankBalance);
        }
        public void UsingTestData1_FirstLineShouldHave3Entries()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(3, subject.Entries.Count());
        }
Beispiel #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);
        }
        /// <summary>
        ///     Makes sure that the IsNew property on LedgerBook EntryLines is not set to true, as it will be when they are newly
        ///     created.
        ///     Also ensures the StoredInAccount property for each ledger is set.
        /// </summary>
        internal static void Finalise(LedgerBook book, bool unlock = false)
        {
            if (book.Reconciliations.None())
            {
                return;
            }
            var ledgers = new Dictionary <BudgetBucket, LedgerBucket>();

            foreach (LedgerEntryLine line in book.Reconciliations)
            {
                if (!unlock)
                {
                    PrivateAccessor.SetProperty(line, "IsNew", false);
                }
                foreach (LedgerEntry entry in line.Entries)
                {
                    if (!unlock)
                    {
                        PrivateAccessor.SetField(entry, "isNew", false);
                    }
                    if (entry.LedgerBucket.StoredInAccount == null)
                    {
                        entry.LedgerBucket.StoredInAccount = StatementModelTestData.ChequeAccount;
                    }
                    if (!ledgers.ContainsKey(entry.LedgerBucket.BudgetBucket))
                    {
                        ledgers.Add(entry.LedgerBucket.BudgetBucket, entry.LedgerBucket);
                    }
                }
            }

            book.Ledgers = ledgers.Values;
        }
        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);
        }
Beispiel #10
0
 partial void ToDtoPreprocessing(LedgerBook model)
 {
     if (model.MobileSettings == null)
     {
         model.MobileSettings = new MobileStorageSettings();
     }
 }
        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);
        }
Beispiel #12
0
 public void Post([FromBody] LedgerBook ledgerBook)
 {
     if (ModelState.IsValid)
     {
         LedgerBookRepository.Add(ledgerBook);
     }
 }
Beispiel #13
0
        private LedgerBook getSampleBook()
        {
            Console.WriteLine("Creating Sample Book");
            LedgerBook book = new LedgerBook("SampleBook" + ++BookNamingIndex);

            Console.WriteLine("Adding Items to book, current count: " + book.Count);
            book.Add(LedgerItem.Create(new DateTime(1997, 3, 1), "Sales Profit", LedgerItemCreateMode.Credit, 327.8));


            Console.WriteLine("Adding Items to book, current count: " + book.Count);
            book.Add(LedgerItem.Create(new DateTime(1997, 3, 3), "Sales Profit", LedgerItemCreateMode.Credit, 668.23));

            Console.WriteLine("Adding Items to book, current count: " + book.Count);
            book.Add(LedgerItem.Create(new DateTime(1997, 3, 4), "Boiler Maintenance", LedgerItemCreateMode.Debit, 122.6));

            Console.WriteLine("Adding Items to book, current count: " + book.Count);
            book.Add(LedgerItem.Create(new DateTime(1997, 3, 8), "Sales Profit", LedgerItemCreateMode.Credit, 1024.3));

            Console.WriteLine("Adding Items to book, current count: " + book.Count);
            book.Add(LedgerItem.Create(new DateTime(1997, 3, 9), "Sales Profit", LedgerItemCreateMode.Credit, 422));

            Console.WriteLine("Adding Items to book, current count: " + book.Count);
            book.Add(LedgerItem.Create(new DateTime(1997, 3, 12), "Sales Profit", LedgerItemCreateMode.Credit, 23));

            Console.WriteLine("Added Items to book complete, current count: " + book.Count);
            return(book);
        }
Beispiel #14
0
        public void TestIntialise()
        {
            this.mockRuleService = new Mock <ITransactionRuleService>(MockBehavior.Strict);
            this.mockReconciliationConsistency = new Mock <IReconciliationConsistency>();
            this.bucketRepo            = new BucketBucketRepoAlwaysFind();
            this.testDataBudgets       = BudgetModelTestData.CreateCollectionWith1And2();
            this.testDataBudgetContext = new BudgetCurrencyContext(this.testDataBudgets, this.testDataBudgets.CurrentActiveBudget);
            this.testDataStatement     = new StatementModelBuilder()
                                         .TestData5()
                                         .AppendTransaction(new Transaction
            {
                Account         = StatementModelTestData.ChequeAccount,
                Amount          = -23.56M,
                BudgetBucket    = StatementModelTestData.RegoBucket,
                Date            = ReconcileDate.Date.AddDays(-1),
                TransactionType = new NamedTransaction("Foo"),
                Description     = "Last transaction"
            })
                                         .Build();
            this.testDataToDoList = new List <ToDoTask>();
            this.subject          = new ReconciliationCreationManager(this.mockRuleService.Object, this.mockReconciliationConsistency.Object, new FakeLogger());

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

            this.mockReconciliationConsistency.Setup(m => m.EnsureConsistency(It.IsAny <LedgerBook>())).Returns(new Mock <IDisposable>().Object);
        }
        public void ShouldMapName()
        {
            LedgerBook result = ArrangeAndAct();

            Assert.AreEqual(TestData.Name, result.Name);
            Assert.IsNotNull(result.Name);
        }
        public void ShouldMapFileName()
        {
            LedgerBook result = ArrangeAndAct();

            Assert.AreEqual(TestData.StorageKey, result.StorageKey);
            Assert.IsNotNull(result.StorageKey);
        }
Beispiel #17
0
        public void RemoveTest()
        {
            LedgerBook book = getSampleBook();

            Console.WriteLine("The Items Before Remove:");
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Removing new item at index 0");
            book.Remove(book[0]);
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Removing new item at index 3");
            book.Remove(book[3]);
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Removing new item at index Count");
            book.Remove(book[book.Count() - 1]);
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Removing item not included");
            book.Remove(LedgerItem.Create(new DateTime(2020, 1, 19), "New Installation of Boiler", LedgerItemCreateMode.Debit, 1024.22));
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
        }
        public void ShouldMapModifiedDate()
        {
            LedgerBook result = ArrangeAndAct();

            Assert.AreEqual(TestData.Modified, result.Modified);
            Assert.AreNotEqual(DateTime.MinValue, result.Modified);
        }
Beispiel #19
0
        public void InsertTest()
        {
            LedgerBook book = getSampleBook();

            Console.WriteLine("The Items Before Insert:");
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Inserting new item at index 0");
            book.Insert(0
                        , LedgerItem.Create(new DateTime(2020, 1, 19), "New Installation of Boiler", LedgerItemCreateMode.Debit, 1024.22));
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Inserting new item at index 3");
            book.Insert(3
                        , LedgerItem.Create(new DateTime(2019, 12, 2), "New Installation of Boiler", LedgerItemCreateMode.Debit, 884.8));
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("Inserting new item at index Count");
            book.Insert(book.Count
                        , LedgerItem.Create(new DateTime(2077, 5, 6), "New Installation of Boiler", LedgerItemCreateMode.Debit, 2884.8));
            foreach (LedgerItem item in book)
            {
                Console.WriteLine(item);
            }
        }
        public void UsingTestData1_FirstLineHairEntryShouldHaveBalance120()
        {
            LedgerBook  result  = ArrangeAndAct();
            LedgerEntry subject = result.Reconciliations.First().Entries.First(e => e.LedgerBucket.BudgetBucket.Code == TestDataConstants.HairBucketCode);

            Assert.AreEqual(120, subject.Balance);
        }
        private static void ValidateDates(LedgerBook ledgerBook, DateTime startDate, DateTime reconciliationDate, StatementModel statement)
        {
            var recentEntry = ledgerBook.Reconciliations.FirstOrDefault();

            if (recentEntry != null)
            {
                if (reconciliationDate <= recentEntry.Date)
                {
                    throw new InvalidOperationException("The start Date entered is before the previous ledger entry.");
                }

                if (recentEntry.Date.AddDays(7 * 4) > reconciliationDate)
                {
                    throw new InvalidOperationException(
                              "The start Date entered is not at least 4 weeks after the previous reconciliation. ");
                }

                if (recentEntry.Date.Day != reconciliationDate.Day)
                {
                    throw new ValidationWarningException(
                              $"The reconciliation Date chosen, {reconciliationDate}, isn't the same day of the month as the previous entry {recentEntry.Date}. Not required, but ideally reconciliations should be evenly spaced.")
                          {
                              Source = "4"
                          };
                }
            }

            if (!statement.AllTransactions.Any(t => t.Date >= startDate))
            {
                throw new ValidationWarningException("There doesn't appear to be any transactions in the statement for the month up to " + reconciliationDate.ToString("d"))
                      {
                          Source = "5"
                      };
            }
        }
        /// <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"
                          };
                }
            }
        }
        public void ShouldMapLineDate()
        {
            LedgerBook result  = ArrangeAndAct();
            DateTime   subject = result.Reconciliations.First().Date;

            Assert.AreEqual(TestData.Reconciliations.First().Date, subject);
            Assert.AreNotEqual(DateTime.MinValue, subject);
        }
        public void ShouldMapLineRemarks()
        {
            LedgerBook result  = ArrangeAndAct();
            string     subject = result.Reconciliations.First().Remarks;

            Assert.AreEqual(TestData.Reconciliations.First().Remarks, subject);
            Assert.IsNotNull(subject);
        }
        public void ShouldMapLineEntryTransactionType()
        {
            LedgerBook result  = ArrangeAndAct();
            string     subject = result.Reconciliations.First().Entries.First().Transactions.First().GetType().FullName;

            Assert.AreEqual(TestData.Reconciliations.First().Entries.First().Transactions.First().TransactionType, subject);
            Assert.IsNotNull(subject);
        }
        public void ShouldMapLineEntryTransactionAmount()
        {
            LedgerBook result  = ArrangeAndAct();
            decimal    subject = result.Reconciliations.First().Entries.First().Transactions.First().Amount;

            Assert.AreEqual(TestData.Reconciliations.First().Entries.First().Transactions.First().Amount, subject);
            Assert.AreNotEqual(0, subject);
        }
        public void ShouldMapLineEntryBucketCode()
        {
            LedgerBook result  = ArrangeAndAct();
            string     subject = result.Reconciliations.First().Entries.First().LedgerBucket.BudgetBucket.Code;

            Assert.AreEqual(TestData.Reconciliations.First().Entries.First().BucketCode, subject);
            Assert.IsNotNull(subject);
        }
        public void ShouldMapLineBankBalance()
        {
            LedgerBook      result  = ArrangeAndAct();
            LedgerEntryLine subject = result.Reconciliations.First();

            Assert.AreEqual(TestData.Reconciliations.First().BankBalance, subject.TotalBankBalance);
            Assert.AreNotEqual(0, subject.TotalBankBalance);
        }
        public void ShouldMapLineEntryTransactionId()
        {
            LedgerBook result  = ArrangeAndAct();
            Guid       subject = result.Reconciliations.First().Entries.First().Transactions.First().Id;

            Assert.AreEqual(TestData.Reconciliations.First().Entries.First().Transactions.First().Id, subject);
            Assert.AreNotEqual(Guid.Empty, subject);
        }
Beispiel #30
0
 public void Put(int Id, [FromBody] LedgerBook LedgerBook)
 {
     LedgerBook.Id = Id;
     if (ModelState.IsValid)
     {
         LedgerBookRepository.Update(LedgerBook);
     }
 }
        /// <summary>
        ///     Custom initialisation and validation to be done directly after mapping the <see cref="LedgerBook" />.
        ///     For example: Must make sure that the <see cref="LedgerBook.Ledgers" /> Collection is populated and each one has a
        ///     default storage Account.
        /// </summary>
        private void InitialiseAndValidateLedgerBook(LedgerBookDto dto, LedgerBook model)
        {
            this.cachedLedgers.Clear();
            foreach (var ledgerBucket in model.Ledgers)
            {
                if (ledgerBucket.StoredInAccount == null)
                {
                    // Defaults to Cheque Account if unspecified.
                    ledgerBucket.StoredInAccount = this.accountTypeRepo.GetByKey(AccountTypeRepositoryConstants.Cheque);
                }

                GetOrAddFromCache(ledgerBucket);
            }

            var ledgersMapWasEmpty = model.Ledgers.None();

            // Default to CHEQUE when StoredInAccount is null.
            foreach (var line in model.Reconciliations)
            {
                foreach (var entry in line.Entries)
                {
                    // Ensure the ledger bucker is the same instance as listed in the book.Legders;
                    entry.LedgerBucket = GetOrAddFromCache(entry.LedgerBucket, true);
                    if (entry.LedgerBucket.StoredInAccount == null)
                    {
                        entry.LedgerBucket.StoredInAccount = this.accountTypeRepo.GetByKey(AccountTypeRepositoryConstants.Cheque);
                    }
                }
            }

            // If ledger column map at the book level was empty, default it to the last used ledger columns in the Dated Entries.
            if (ledgersMapWasEmpty && model.Reconciliations.Any())
            {
                model.Ledgers = model.Reconciliations.First().Entries.Select(e => e.LedgerBucket);
            }
        }
 partial void ToModelPostprocessing(LedgerBookDto dto, ref LedgerBook model)
 {
     InitialiseAndValidateLedgerBook(dto, model);
 }
 // ReSharper disable once RedundantAssignment
 partial void ModelFactory(LedgerBookDto dto, ref LedgerBook model)
 {
     // TODO Seems odd that a mapper requires the ReconciliationBuilder, either need a factory or better yet move the reconciliation code out of the LedgerBook class.
     model = new LedgerBook(this.reconciliationBuilder);
 }