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()); }
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); }
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); }
public void Post([FromBody] LedgerBook ledgerBook) { if (ModelState.IsValid) { LedgerBookRepository.Add(ledgerBook); } }
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); }
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); }
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); }
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); }
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); }