Наследование: INotifyPropertyChanged
        /// <summary>
        ///     Load the given file into a <see cref="StatementModel" />.
        /// </summary>
        /// <param name="fileName">The file to load.</param>
        /// <param name="accountType">
        ///     The account type to classify these transactions. This is useful when merging one statement to another. For example,
        ///     merging a cheque account
        ///     export with visa account export, each can be classified using an account type.
        /// </param>
        public StatementModel Load(string fileName, AccountType accountType)
        {
            this.importUtilities.AbortIfFileDoesntExist(fileName, this.userMessageBox);

            var transactions = new List<Transaction>();
            foreach (string line in ReadLines(fileName))
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                string[] split = line.Split(',');
                var transaction = new Transaction
                {
                    AccountType = accountType,
                    TransactionType = FetchTransactionType(split, 0),
                    Description = this.importUtilities.SafeArrayFetchString(split, 1),
                    Reference1 = this.importUtilities.SafeArrayFetchString(split, 2),
                    Reference2 = this.importUtilities.SafeArrayFetchString(split, 3),
                    Reference3 = this.importUtilities.SafeArrayFetchString(split, 4),
                    Amount = this.importUtilities.SafeArrayFetchDecimal(split, 5),
                    Date = this.importUtilities.SafeArrayFetchDate(split, 6),
                };
                transactions.Add(transaction);
            }

            StatementModel statement = new StatementModel(this.logger)
            {
                FileName = fileName,
                LastImport = DateTime.Now,
            }.LoadTransactions(transactions);

            return statement;
        }
        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 ReconciliationManager(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 Load(StatementModel statementModel, BudgetCollection budgets, GlobalFilterCriteria criteria)
        {
            Analysis = new OverallPerformanceBudgetAnalyser(statementModel, budgets, this.bucketRepository);
            Analysis.Analyse(criteria);
            OverallPerformance = (double)Analysis.OverallPerformance;
            ExpenseFilter = true;
            IncomeFilter = false;

            RaisePropertyChanged(() => Analysis);
            ICollectionView view = CollectionViewSource.GetDefaultView(Analysis.Analyses);
            view.Filter = x =>
            {
                var bucketAnalysis = x as BucketPerformanceAnalyser;
                if (bucketAnalysis == null)
                {
                    return true;
                }

                if (IncomeFilter)
                {
                    return bucketAnalysis.Bucket is IncomeBudgetBucket;
                }

                bool result = !(bucketAnalysis.Bucket is IncomeBudgetBucket);
                return result;
            };
        }
        public void DetectDuplicateTransactions_ShouldSummaryText_GivenTestData4()
        {
            this.testData = StatementModelTestData.TestData4();
            Arrange();

            string result = this.subject.DetectDuplicateTransactions();
            Console.WriteLine(result);
            Assert.IsFalse(string.IsNullOrWhiteSpace(result));
        }
        public override void Update([NotNull] params object[] input)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

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

            Budget = (BudgetCurrencyContext)input[0];
            this.statement = (StatementModel)input[1];
            Filter = (GlobalFilterCriteria)input[2];
            this.bucketRepository = (IBudgetBucketRepository)input[3];

            if (!this.bucketRepository.IsValidCode(BucketCode))
            {
                Enabled = false;
                return;
            }

            SetAdditionalDependencies(input);

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

            Enabled = true;
            decimal totalBudget = MonthlyBudgetAmount()
                                  * Filter.BeginDate.Value.DurationInMonths(Filter.EndDate.Value);
            Maximum = Convert.ToDouble(totalBudget);

            // Debit transactions are negative so normally the total spend will be a negative number.
            decimal remainingBudget = totalBudget + this.statement.Transactions.Where(t => t.BudgetBucket != null && t.BudgetBucket.Code == BucketCode).Sum(t => t.Amount);
            if (remainingBudget < 0)
            {
                remainingBudget = 0;
            }

            Value = Convert.ToDouble(remainingBudget);
            ToolTip = string.Format(CultureInfo.CurrentCulture, RemainingBudgetToolTip, remainingBudget);

            if (remainingBudget < 0.2M * totalBudget)
            {
                ColourStyleName = WidgetWarningStyle;
            }
            else
            {
                ColourStyleName = this.standardStyle;
            }
        }
        public async Task CreateNewAndSaveAsync(string storageKey)
        {
            if (storageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(storageKey));
            }

            var newStatement = new StatementModel(this.logger) { StorageKey = storageKey };
            await SaveAsync(newStatement, storageKey, false);
        }
        private static DateTime CalculateEndDate(StatementModel statement, GlobalFilterCriteria criteria)
        {
            if (criteria.Cleared || criteria.EndDate == null)
            {
                DateTime maxDate = statement.AllTransactions.Max(t => t.Date).Date;
                return maxDate.LastDateInMonth();
            }

            return criteria.EndDate.Value;
        }
 private void Act(StatementModel testData)
 {
     var subject = new Mapper_TransactionSetDto_StatementModel(
         new FakeLogger(), 
         new Mapper_TransactionDto_Transaction(
             new InMemoryAccountTypeRepository(), 
             new BucketBucketRepoAlwaysFind(), 
             new InMemoryTransactionTypeRepository()));
     Result = subject.ToDto(testData);
 }
        /// <summary>
        /// Statement Model with transactions between 15/07/2013 and 14/09/2013
        /// Includes income transactions.
        /// </summary>
        public static StatementModel TestData2()
        {
            var statement = new StatementModel(new FakeLogger())
            {
                FileName = @"C:\TestData2\Foo2Statement.csv",
                LastImport = new DateTime(2013, 08, 15),
            };

            var transactions = CreateTransactions2();
            statement.LoadTransactions(transactions);
            return statement;
        }
        /// <summary>
        ///     Statement Model with transactions between 15/07/2013 and 14/09/2013
        ///     Includes income transactions.
        ///     Adjusted for use with LedgerCalculator - No ledgers will be overdrawn when using LedgerBook TestData 1.
        /// </summary>
        public static StatementModel TestData3()
        {
            var statement = new StatementModel(new FakeLogger())
            {
                StorageKey = @"C:\TestData3\Foo2Statement.csv",
                LastImport = new DateTime(2013, 08, 15)
            };

            IEnumerable<Transaction> transactions = CreateTransactions3();
            statement.LoadTransactions(transactions);
            return statement;
        }
        /// <summary>
        ///     Imports a bank statement file and merges it into an existing statement model. You cannot merge two Budget Analyser
        ///     Statement files.
        /// </summary>
        public StatementModel ImportAndMergeBankStatement(StatementModel statementModel, bool throwIfFileNotFound = false)
        {
            var task = GetFileNameFromUser(OpenMode.Merge, statementModel);
            task.Wait();
            var fileName = task.Result;
            if (string.IsNullOrWhiteSpace(fileName))
            {
                // User cancelled
                return null;
            }

            return LoadAnyStatementFile(fileName);
        }
        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);
        }
Пример #13
0
        public StatementModel Build()
        {
            if (this.additionalTransactions.None())
            {
                return this.model;
            }

            // IEnumerable<MethodInfo> privateMergeMethods = this.model.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).Where(m => m.Name == "Merge");
            // MethodInfo privateMergeMethod = privateMergeMethods.First(m => m.IsPrivate);
            // privateMergeMethod.Invoke(this.model, new object[] { this.additionalTransactions });
            var additionalTransactionsModel = new StatementModel(new FakeLogger())
            {
                LastImport = this.additionalTransactions.Max(t => t.Date).Date,
            };
            additionalTransactionsModel.LoadTransactions(this.additionalTransactions);
            return this.model.Merge(additionalTransactionsModel);
        }
Пример #14
0
        /// <summary>
        ///     Creates a new LedgerEntryLine for this <see cref="LedgerBook" />.
        /// </summary>
        /// <param name="date">
        ///     The date for the <see cref="LedgerEntryLine" />. Also used to search for transactions in the
        ///     <see cref="statement" />.
        /// </param>
        /// <param name="bankBalances">
        ///     The bank balances as at the <see cref="date" /> to include in this new single line of the
        ///     ledger book.
        /// </param>
        /// <param name="budget">The current budget.</param>
        /// <param name="statement">The currently loaded statement.</param>
        /// <param name="ignoreWarnings">Ignores validation warnings if true, otherwise <see cref="ValidationWarningException" />.</param>
        /// <exception cref="InvalidOperationException">Thrown when this <see cref="LedgerBook" /> is in an invalid state.</exception>
        public LedgerEntryLine Reconcile(
            DateTime date,
            IEnumerable<BankBalance> bankBalances,
            BudgetModel budget,
            StatementModel statement = null,
            bool ignoreWarnings = false)
        {
            try
            {
                PreReconciliationValidation(date, statement);
            }
            catch (ValidationWarningException)
            {
                if (!ignoreWarnings)
                {
                    throw;
                }
            }

            decimal consistencyCheck1 = DatedEntries.Sum(e => e.CalculatedSurplus);
            var newLine = new LedgerEntryLine(date, bankBalances);
            var previousEntries = new Dictionary<LedgerColumn, LedgerEntry>();
            LedgerEntryLine previousLine = this.datedEntries.FirstOrDefault();
            foreach (LedgerColumn ledger in Ledgers)
            {
                LedgerEntry previousEntry = null;
                if (previousLine != null)
                {
                    previousEntry = previousLine.Entries.FirstOrDefault(e => e.LedgerColumn.Equals(ledger));
                }

                previousEntries.Add(ledger, previousEntry);
            }

            newLine.AddNew(previousEntries, budget, statement, CalculateStartDateForReconcile(date));
            decimal consistencyCheck2 = DatedEntries.Sum(e => e.CalculatedSurplus);
            if (consistencyCheck1 != consistencyCheck2)
            {
                throw new CorruptedLedgerBookException("Code Error: The previous dated entries have changed, this is not allowed. Data is corrupt.");
            }

            this.datedEntries.Insert(0, newLine);
            this.newlyAddedLedgers.Clear();
            return newLine;
        }
Пример #15
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;
 }
Пример #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);
        }
Пример #17
0
        internal virtual StatementModel Merge([NotNull] StatementModel additionalModel)
        {
            ThrowIfDisposed();
            if (additionalModel == null)
            {
                throw new ArgumentNullException(nameof(additionalModel));
            }

            var combinedModel = new StatementModel(this.logger)
            {
                LastImport = additionalModel.LastImport,
                StorageKey = StorageKey
            };

            List <Transaction> mergedTransactions = AllTransactions.ToList().Merge(additionalModel.AllTransactions).ToList();

            combinedModel.LoadTransactions(mergedTransactions);
            return(combinedModel);
        }
        /// <summary>
        ///     Updates the widget with new input.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        public override void Update([NotNull] params object[] input)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            Enabled = false;

            if (!ValidateUpdateInput(input)) return;

            LedgerBook = (LedgerBook) input[0];
            StatementModel = (StatementModel) input[1];
            BudgetCollection = (BudgetCollection) input[2];
            Filter = (GlobalFilterCriteria) input[3];

            if (LedgerBook == null || StatementModel == null || BudgetCollection == null || Filter == null) return;

            Enabled = true;
        }
        public OverallPerformanceBudgetResult BuildChart(StatementModel statementModel, BudgetCollection budgets,
                                                         GlobalFilterCriteria criteria)
        {
            if (statementModel == null)
            {
                throw new ArgumentNullException(nameof(statementModel));
            }

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

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

            return this.analyser.Analyse(statementModel, budgets, criteria);
        }
Пример #20
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 BucketBurnDownController Load(
            StatementModel statementModel,
            BudgetModel budgetModel, 
            [NotNull] BudgetBucket bucket,
            DateTime beginDate,
            Engine.Ledger.LedgerBook ledgerBook)
        {
            if (bucket == null)
            {
                throw new ArgumentNullException("bucket");
            }
            this.Background = ConverterHelper.TileBackgroundBrush;
            this.Bucket = bucket;
            this.ActualSpendingLabel = this.Bucket.Code;
            this.ChartTitle = string.Format(CultureInfo.CurrentCulture, "{0} Spending Chart", bucket.Code);

            this.burnDownGraphAnalyser.Analyse(statementModel, budgetModel, new[] { bucket }, beginDate, ledgerBook);
            CopyOutputFromAnalyser();

            return this;
        }
        public OverallPerformanceBudgetAnalyser([NotNull] StatementModel statement, [NotNull] BudgetCollection budgets, [NotNull] IBudgetBucketRepository bucketRepository)
        {
            if (statement == null)
            {
                throw new ArgumentNullException("statement");
            }

            if (budgets == null)
            {
                throw new ArgumentNullException("budgets");
            }

            if (bucketRepository == null)
            {
                throw new ArgumentNullException("bucketRepository");
            }

            this.statement = statement;
            this.budgets = budgets;
            this.bucketRepository = bucketRepository;
        }
Пример #24
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));

                CreateToDoForAnyOverdrawnSurplusBalance();

                return new ReconciliationResult { Reconciliation = this.newReconciliationLine, Tasks = this.toDoList };
            }
            finally
            {
                this.newReconciliationLine = null;
            }
        }
        public GraphData BuildChart(StatementModel statementModel, GlobalFilterCriteria criteria)
        {
            if (statementModel == null)
            {
                throw new ArgumentNullException(nameof(statementModel));
            }

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

            if (statementModel.Transactions.Any(t => t.BudgetBucket == null))
            {
                throw new ArgumentException("There are uncategorised transactions, finish assigning a bucket to all transactions before this running this graph.");
            }

            this.analyser.Analyse(statementModel, criteria);
            var result = this.analyser.Graph;
            this.analyser.Reset();
            return result;
        }
        public void Build(GlobalFilterCriteria criteria,
            StatementModel statementModel,
            BudgetModel budgetModel,
            Engine.Ledger.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<BucketBurnDownController>(this.budgetBucketRepository.Buckets.Count());

            foreach (BudgetBucket bucket in this.budgetBucketRepository.Buckets
                .Where(b => b is ExpenseBucket)
                .OrderBy(b => b.Code))
            {
                BucketBurnDownController chartController = this.bucketSpendingFactory();
                chartController.Load(statementModel, budgetModel, bucket, beginDate, ledgerBookModel);
                listOfCharts.Add(chartController);
            }

            listOfCharts = listOfCharts.OrderBy(x => x.Bucket).ToList();

            // Put surplus at the top.
            listOfCharts.Insert(
                0,
                this.bucketSpendingFactory().Load(statementModel, budgetModel, this.budgetBucketRepository.SurplusBucket, beginDate, ledgerBookModel));

            // Put any custom charts on top.
            foreach (CustomAggregateBurnDownGraph customChart in this.CustomCharts)
            {
                BucketBurnDownController chartController = this.bucketSpendingFactory();
                IEnumerable<BudgetBucket> buckets = this.budgetBucketRepository.Buckets
                    .Join(customChart.BucketIds, bucket => bucket.Code, code => code, (bucket, code) => bucket);
                chartController.LoadCustomChart(statementModel, budgetModel, buckets, beginDate, ledgerBookModel, customChart.Name);
                listOfCharts.Insert(0, chartController);
            }

            this.Results = new BurnDownChartBuilderResults(beginDate, dateRangeDescription, listOfCharts);
        }
Пример #27
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;
        }
Пример #28
0
        internal virtual StatementModel Merge([NotNull] StatementModel additionalModel)
        {
            ThrowIfDisposed();
            if (additionalModel == null)
            {
                throw new ArgumentNullException(nameof(additionalModel));
            }

            var combinedModel = new StatementModel(this.logger)
            {
                LastImport = additionalModel.LastImport,
                StorageKey = StorageKey
            };

            List<Transaction> mergedTransactions = AllTransactions.ToList().Merge(additionalModel.AllTransactions).ToList();
            combinedModel.LoadTransactions(mergedTransactions);
            return combinedModel;
        }
        public void Load(
            [NotNull] StatementModel statementModel,
            [NotNull] BudgetModel budgetModel,
            [NotNull] GlobalFilterCriteria criteria,
            Engine.Ledger.LedgerBook ledgerBookModel)
        {
            if (statementModel == null)
            {
                throw new ArgumentNullException("statementModel");
            }

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

            if (criteria == null)
            {
                throw new ArgumentNullException("criteria");
            }

            this.statement = statementModel;
            this.budget = budgetModel;
            this.ledgerBook = ledgerBookModel;

            this.chartBuilder.Build(criteria, statementModel, budgetModel, ledgerBookModel);
            this.beginDate = this.chartBuilder.Results.BeginDate;
            DateRangeDescription = this.chartBuilder.Results.DateRangeDescription;
            ChartControllers = new BindingList<BucketBurnDownController>(this.chartBuilder.Results.Charts.ToList());

            RaisePropertyChanged(() => ChartControllers);
        }
Пример #30
0
        public async Task SaveAsync(StatementModel model, string storageKey, bool isEncrypted)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

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

            var transactionSet = this.mapper.ToDto(model);

            transactionSet.VersionHash = VersionHash;
            transactionSet.StorageKey  = storageKey;
            transactionSet.Checksum    = CalculateTransactionCheckSum(transactionSet);
            if (model.AllTransactions.Count() != transactionSet.Transactions.Count())
            {
                throw new StatementModelChecksumException(
                          string.Format(
                              CultureInfo.InvariantCulture,
                              "Only {0} out of {1} transactions have been mapped correctly. Aborting the save, to avoid data loss and corruption.",
                              transactionSet.Transactions.Count,
                              model.AllTransactions.Count()));
            }

            var writer = this.readerWriterSelector.SelectReaderWriter(isEncrypted);

            using (var stream = writer.CreateWritableStream(storageKey))
            {
                using (var streamWriter = new StreamWriter(stream))
                {
                    WriteHeader(streamWriter, transactionSet);

                    foreach (var transaction in transactionSet.Transactions)
                    {
                        var line = new StringBuilder();
                        line.Append(transaction.TransactionType);
                        line.Append(",");

                        line.Append(transaction.Description);
                        line.Append(",");

                        line.Append(transaction.Reference1);
                        line.Append(",");

                        line.Append(transaction.Reference2);
                        line.Append(",");

                        line.Append(transaction.Reference3);
                        line.Append(",");

                        line.Append(transaction.Amount);
                        line.Append(",");

                        line.Append(transaction.Date.ToString("O", CultureInfo.InvariantCulture));
                        line.Append(",");

                        line.Append(transaction.BudgetBucketCode);
                        line.Append(",");

                        line.Append(transaction.Account);
                        line.Append(",");

                        line.Append(transaction.Id);
                        line.Append(",");

                        await streamWriter.WriteLineAsync(line.ToString());
                    }

                    await streamWriter.FlushAsync();
                }
            }
        }
Пример #31
0
 public StatementReadyMessage(StatementModel statement)
 {
     StatementModel = statement;
 }
Пример #32
0
        private int SearchForOtherNonLedgerBookOverspentBuckets(
            StatementModel statement,
            GlobalFilterCriteria filter,
            IBudgetCurrencyContext budget,
            IDictionary<BudgetBucket, decimal> overspendingSummary)
        {
            var warnings = 0;
            List<Transaction> transactions = statement.Transactions.Where(t => t.Date < filter.BeginDate?.Date.AddMonths(1)).ToList();
            foreach (var expense in budget.Model.Expenses.Where(e => e.Bucket is BillToPayExpenseBucket))
            {
                if (overspendingSummary.ContainsKey(expense.Bucket))
                {
                    continue;
                }

                var bucketBalance = expense.Amount +
                                    transactions.Where(t => t.BudgetBucket == expense.Bucket).Sum(t => t.Amount);
                overspendingSummary.Add(expense.Bucket, bucketBalance);
                if (bucketBalance < -Tolerance)
                {
                    warnings++;
                }
            }

            return warnings;
        }