public void Can_calculate_balance_considering_actual_and_expected_values_and_some_nulls()
        {
            var incomes = new List<Income>();
            incomes.Add(new Income {AccountId = 1, ExpectedValue = 10.00m, ActualValue = null});
            incomes.Add(new Income {AccountId = 1, ExpectedValue = 10.01m, ActualValue = null});
            incomes.Add(new Income {AccountId = 1, ExpectedValue = 10.02m, ActualValue = 10.22m});
            incomes.Add(new Income {AccountId = 1, ExpectedValue = null, ActualValue = null});
            incomes.Add(new Income {AccountId = 1, ExpectedValue = 10.04m, ActualValue = 10.24m});
            incomes.Add(new Income {AccountId = 1, ExpectedValue = 10.05m, ActualValue = 10.25m});

            var expenses = new List<Expense>();
            expenses.Add(new Expense {AccountId = 1, ExpectedValue = null, ActualValue = 10.10m});
            expenses.Add(new Expense {AccountId = 1, ExpectedValue = 10.01m, ActualValue = null});
            expenses.Add(new Expense {AccountId = 1, ExpectedValue = 10.02m, ActualValue = 10.12m});
            expenses.Add(new Expense {AccountId = 1, ExpectedValue = 10.03m, ActualValue = 10.13m});
            expenses.Add(new Expense {AccountId = 1, ExpectedValue = null, ActualValue = 10.14m});
            expenses.Add(new Expense {AccountId = 1, ExpectedValue = 10.05m, ActualValue = null});

            var balanceService = new BalanceCalculationService();
            var calculationArgs = new CalculationArgs(incomes, expenses);
            var balance = balanceService.CalculateBalance(calculationArgs);

            Console.WriteLine("balance: " + balance.ForAccountId(1));
            Assert.IsTrue(balance.ForAccountId(1) == -9.83m);
        }
        public List<AccountSummary> CalculateAccountSummary(IEnumerable<Account> accounts, IEnumerable<BaseTransaction> transactions )
        {
            var baseTransactions = transactions as List<BaseTransaction> ?? transactions.ToList();
            var incomes = baseTransactions.OfType<Income>().ToList();
            var expenses = baseTransactions.OfType<Expense>().ToList();

            var summaries = new List<AccountSummary>();
            var svc = new BalanceCalculationService();
            var today = SystemTime.Now();
            var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
            var lastDayOfMonth = new DateTime(today.Year, today.Month,DateTime.DaysInMonth(today.Year,today.Month));

            //calculate balance for all acccounts today
            var args1 = new CalculationArgs(incomes, expenses) { StartingDate = firstDayOfMonth , EndingDate = today};
            var balanceToday =svc.CalculateBalance(args1);

            //calculate the balance in the end of the month to build the previsions column in the grid
            var args2 = new CalculationArgs(incomes, expenses) { StartingDate = firstDayOfMonth , EndingDate = lastDayOfMonth};
            var balanceEOM =svc.CalculateBalance(args2);

            foreach (var account in accounts)
            {
                var accountSummary = new AccountSummary();
                accountSummary.AccountId = account.Id;
                accountSummary.AccountName = account.Name;
                accountSummary.CurrentBalance = balanceToday.ForAccountId(account.Id);
                accountSummary.EndOfMonthBalance = balanceEOM.ForAccountId(account.Id);
                summaries.Add(accountSummary);
            }

            return summaries;
        }
        public CashFlowCalculationResult CalculateCashflow(CalculationArgs args)
        {
            var transactions = new List<IMoneyTransaction>();
            transactions.AddRange(args.Incomes.Where(x => x.Date.HasValue && (x.Date >= args.StartingDate && x.Date <= args.EndingDate)));
            transactions.AddRange(args.Expenses.Where(x => x.Date.HasValue && (x.Date >= args.StartingDate && x.Date <= args.EndingDate)));

            var dailySums = (from x in transactions.OrderBy(t=>t.Date)
                             group x by new { x.Date, AccountID = x.AccountId}
                             into g
                             select new {Date = g.Key.Date, AccountId = g.Key.AccountID, DailyAmount = g.Sum(x => x.Value)}).ToList();

            var distinctAccounts = dailySums.Select(x => x.AccountId).Distinct();

            var cashFlow = new CashFlowCalculationResult();

            foreach (var account in distinctAccounts)
            {

                decimal runningSum = 0;
                var accountId = account;
                var cashFlowCalc = dailySums.Where(a => a.AccountId == accountId).Select(x =>
                                                        {
                                                            runningSum += x.DailyAmount;
                                                        return new CashFlowEntry(x.AccountId, x.Date.Value, runningSum);
                                                        }
                    );

                cashFlow.AddEntries(cashFlowCalc.ToList());
            }

            return cashFlow;
        }
        public BalanceCalculationResult CalculateBalance(CalculationArgs args)
        {
            if (args.StartingDate > args.EndingDate)
                throw new InvalidOperationException("The starting date must be earlier than ending date.");

            var balanceResult = new BalanceCalculationResult();
            var accounts = args.GetDistinctAccountIds();
            foreach (var accountId in accounts)
            {
                var id = accountId;
                var incomes = args.Incomes.Where(x => x.AccountId == id).Where(x => (x.Date == null) || (x.Date >= args.StartingDate && x.Date <= args.EndingDate));
                var expenses = args.Expenses.Where(x => x.AccountId == id).Where(x => (x.Date == null) || (x.Date >= args.StartingDate && x.Date <= args.EndingDate));

                var incomeSum = 0.0m;
                var expenseSum = 0.0m;

                incomeSum = IncomeSum(incomeSum, incomes);
                expenseSum = ExpenseSum(expenseSum, expenses);

                var balance = incomeSum + expenseSum + args.InitialBalance;

                balanceResult.AddEntry(accountId,balance);

            }
            return balanceResult;
        }
        public void Can_calculate_simple_balance_with_some_nulls()
        {
            var balanceService = new BalanceCalculationService();

            var incomes = new List<Income>();
            incomes.Add(new Income {AccountId = 1, ActualValue = 10.01m});
            incomes.Add(new Income {AccountId = 1, ActualValue = 10.02m});
            incomes.Add(new Income {AccountId = 1, ActualValue = null});
            incomes.Add(new Income {AccountId = 1, ActualValue = 10.04m});
            incomes.Add(new Income {AccountId = 1, ActualValue = 10.05m});

            var expenses = new List<Expense>();
            expenses.Add(new Expense {AccountId = 1, ActualValue = 10.01m});
            expenses.Add(new Expense {AccountId = 1, ActualValue = 10.02m});
            expenses.Add(new Expense {AccountId = 1, ActualValue = 10.03m});
            expenses.Add(new Expense {AccountId = 1, ActualValue = 10.04m});
            expenses.Add(new Expense {AccountId = 1, ActualValue = null});

            var calculationArgs = new CalculationArgs(incomes, expenses);
            var balance = balanceService.CalculateBalance(calculationArgs);

            Console.WriteLine("balance: " + balance.ForAccountId(1));
            Assert.IsTrue(balance.ForAccountId(1) == 0.02m);
        }
        public void Can_calculate_simple_balance_with_more_than_one_account_and_some_nulls()
        {
            var incomes = new List<Income>();
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.20m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.21m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.22m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.23m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.24m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.25m });

            var expenses = new List<Expense>();
            expenses.Add(new Expense { AccountId = 4, ExpectedValue = 10.00m, ActualValue = null });
            expenses.Add(new Expense { AccountId = 4, ExpectedValue = 10.01m, ActualValue = null });
            expenses.Add(new Expense { AccountId = 4, ExpectedValue = 10.02m, ActualValue = null });
            expenses.Add(new Expense { AccountId = 4, ExpectedValue = 10.03m, ActualValue = null });
            expenses.Add(new Expense { AccountId = 4, ExpectedValue = 10.04m, ActualValue = null });
            expenses.Add(new Expense { AccountId = 4, ExpectedValue = 10.05m, ActualValue = null });

            var balanceService = new BalanceCalculationService();
            var calculationArgs = new CalculationArgs(incomes, expenses);
            var balance = balanceService.CalculateBalance(calculationArgs);

            Console.WriteLine("balance: " + balance.ForAccountId(1));
            Console.WriteLine("balance: " + balance.ForAccountId(4));
            Assert.IsTrue(balance.ForAccountId(1) == 61.35m);
            Assert.IsTrue(balance.ForAccountId(2) == 0);
            Assert.IsTrue(balance.ForAccountId(3) == 0);
            Assert.IsTrue(balance.ForAccountId(4) == -60.15m);
        }
        public void Can_calculate_balance_with_initial_balance()
        {
            var initialBalance = 1.19m;

            var incomes = new List<Income>();
            incomes.Add(new Income { AccountId = 1, ExpectedValue = 10.00m, ActualValue = 10.10m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = 10.01m, ActualValue = 10.11m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = 10.02m, ActualValue = 10.12m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = null, ActualValue = 10.13m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = 10.04m, ActualValue = 10.14m });
            incomes.Add(new Income { AccountId = 1, ExpectedValue = 10.05m, ActualValue = null });

            var expenses = new List<Expense>();
            expenses.Add(new Expense { AccountId = 1, ExpectedValue = 10.00m, ActualValue = 10.20m });
            expenses.Add(new Expense { AccountId = 1, ExpectedValue = 10.01m, ActualValue = 10.21m });
            expenses.Add(new Expense { AccountId = 1, ExpectedValue = 10.02m, ActualValue = 10.22m });
            expenses.Add(new Expense { AccountId = 1, ExpectedValue = 10.03m, ActualValue = 10.23m });
            expenses.Add(new Expense { AccountId = 1, ExpectedValue = 10.04m, ActualValue = 10.24m });
            expenses.Add(new Expense { AccountId = 1, ExpectedValue = null, ActualValue = null });

            var balanceService = new BalanceCalculationService();
            var calculationArgs = new CalculationArgs(incomes, expenses){InitialBalance = initialBalance};
            var balance = balanceService.CalculateBalance(calculationArgs);

            Console.WriteLine("balance: " + balance.ForAccountId(1));
            Assert.IsTrue(balance.ForAccountId(1) == 10.74m);
        }