예제 #1
0
        private bool UpdateDbAccountBalances(Transaction transaction, EventArgumentEnum eventArgument)
        {
            try
            {
                switch (eventArgument)
                {
                case EventArgumentEnum.Create:
                {
                    if (transaction.DebitAccount != null && transaction.DebitAccount.Id != 0)
                    {
                        var originalBalance = transaction.DebitAccount.Balance;         // logs beginning balance
                        transaction.DebitAccount.Balance += transaction.Amount;
                        Logger.Instance.Calculation($"{transaction.DebitAccount.Name}.balance ({originalBalance}) + {transaction.Amount} = {transaction.DebitAccount.Balance}");

                        // Update Account's required savings
                        transaction.CreditAccount.BalanceSurplus = _calc.UpdateBalanceSurplus(transaction.CreditAccount);


                        _db.Entry(transaction.DebitAccount).State = EntityState.Modified;
                    }

                    if (transaction.CreditAccount != null && transaction.CreditAccount.Id != 0)
                    {
                        var originalBalance = transaction.CreditAccount.Balance;         // logs beginning balance
                        transaction.CreditAccount.Balance -= transaction.Amount;
                        Logger.Instance.Calculation($"{transaction.CreditAccount.Name}.balance ({originalBalance}) + {transaction.Amount} = {transaction.CreditAccount.Balance}");

                        // Update Account's required savings
                        transaction.CreditAccount.BalanceSurplus = _calc.UpdateBalanceSurplus(transaction.CreditAccount);


                        _db.Entry(transaction.CreditAccount).State = EntityState.Modified;
                    }


                    _db.SaveChanges();
                    return(true);
                }

                case EventArgumentEnum.Delete:
                case EventArgumentEnum.Update:
                {
                    var accountManager = new AccountManager();
                    var calculations   = new Calculations();

                    var originalTransaction = _db.Transactions
                                              .AsNoTracking()
                                              .Where(t => t.Id == transaction.Id)
                                              .Cast <Transaction>()
                                              .FirstOrDefault();
                    if (originalTransaction == null)
                    {
                        return(false);
                    }
                    var originalCreditAccount = _db.Accounts.FirstOrDefault(a => a.Id == (originalTransaction.CreditAccountId ?? 0));
                    var originalDebitAccount  = transaction.Type == TransactionTypesEnum.Income ? accountManager.GetPoolAccount() : _db.Accounts.FirstOrDefault(a => a.Id == (originalTransaction.DebitAccountId ?? 0));
                    var originalAmount        = originalTransaction.Amount;

                    // Reassign the Debit/Credit Account Id's to Transaction Model
                    transaction.CreditAccountId = originalTransaction.CreditAccountId;
                    transaction.DebitAccountId  = originalTransaction.DebitAccountId;

                    if (transaction.Type == TransactionTypesEnum.Income)
                    {
                        var accounts = accountManager.GetAllAccounts();
                        switch (eventArgument)
                        {
                        case EventArgumentEnum.Delete:
                        {
                            if (originalDebitAccount != null)
                            {
                                // Pool all Account balances (including deficits)
                                foreach (Account account in accounts.Where(a => a.Balance != 0.0m))
                                {
                                    try
                                    {
                                        if (account.Balance > 0.0m)
                                        {
                                            var balance = account.Balance;
                                            account.Balance -= balance;
                                            originalDebitAccount.Balance += balance;
                                        }
                                        else if (account.Balance < 0.0m)
                                        {
                                            var deficit = account.Balance * -1;

                                            account.Balance -= deficit;
                                            originalDebitAccount.Balance -= deficit;
                                        }

                                        account.BalanceSurplus = calculations.UpdateBalanceSurplus(account);
                                    }
                                    catch (Exception e)
                                    {
                                        Logger.Instance.Error(e);
                                    }
                                }

                                // Subtract the amount of the income transaction from the Pool
                                originalDebitAccount.Balance -= transaction.Amount;

                                // If there's still a balance left, rebalance Accounts with a negative balance surplus
                                if (originalDebitAccount.Balance > 0.0m)
                                {
                                    foreach (Account account in accounts.Where(a => !a.ExcludeFromSurplus))
                                    {
                                        try
                                        {
                                            if (account.BalanceSurplus > 0.0m)
                                            {
                                                var balance = account.Balance;
                                                account.Balance -= balance;
                                                originalDebitAccount.Balance += balance;
                                            }
                                            else
                                            {
                                                var deficit = account.BalanceSurplus * -1;

                                                if (originalDebitAccount.Balance < deficit)
                                                {
                                                    account.Balance += originalDebitAccount.Balance;
                                                    originalDebitAccount.Balance -=
                                                        originalDebitAccount.Balance;
                                                }
                                                else                 // Make account whole
                                                {
                                                    account.Balance += deficit;
                                                    originalDebitAccount.Balance -= deficit;
                                                }
                                            }

                                            account.BalanceSurplus = calculations.UpdateBalanceSurplus(account);


                                            _db.Entry(account).State = EntityState.Modified;
                                        }
                                        catch (Exception e)
                                        {
                                            Logger.Instance.Error(e);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Logger.Instance.Debug("Debit account for income transaction is null");
                            }


                            if (_db.ChangeTracker.HasChanges())
                            {
                                _db.SaveChanges();
                            }


                            return(true);
                        }

                        case EventArgumentEnum.Update:
                        {
                            if (originalDebitAccount != null)
                            {
                                // Pool Account balances (including deficits)
                                foreach (Account account in accounts.Where(a => a.Balance != 0.0m))
                                {
                                    try
                                    {
                                        if (account.Balance > 0.0m)
                                        {
                                            var balance = account.Balance;
                                            account.Balance -= balance;
                                            originalDebitAccount.Balance += balance;
                                        }
                                        else if (account.Balance < 0.0m)
                                        {
                                            var deficit = account.Balance * -1;

                                            account.Balance -= deficit;
                                            originalDebitAccount.Balance -= deficit;
                                        }

                                        account.BalanceSurplus = calculations.UpdateBalanceSurplus(account);
                                    }
                                    catch (Exception e)
                                    {
                                        Logger.Instance.Error(e);
                                    }
                                }

                                // Subtract difference of the updated transaction and the original transaction amount
                                originalDebitAccount.Balance += transaction.Amount - originalAmount;

                                // if there's a balance left, rebalance Accounts with a negative balance surplus
                                if (originalDebitAccount.Balance > 0.0m)
                                {
                                    foreach (Account account in accounts.Where(a => !a.ExcludeFromSurplus))
                                    {
                                        try
                                        {
                                            if (account.BalanceSurplus > 0.0m)
                                            {
                                                var balance = account.Balance;
                                                account.Balance -= balance;
                                                originalDebitAccount.Balance += balance;
                                            }
                                            else
                                            {
                                                var deficit = account.BalanceSurplus * -1;

                                                if (originalDebitAccount.Balance < deficit)
                                                {
                                                    account.Balance += originalDebitAccount.Balance;
                                                    originalDebitAccount.Balance -=
                                                        originalDebitAccount.Balance;
                                                }
                                                else                 // Make account whole
                                                {
                                                    account.Balance += deficit;
                                                    originalDebitAccount.Balance -= deficit;
                                                }
                                            }

                                            account.BalanceSurplus = calculations.UpdateBalanceSurplus(account);


                                            _db.Entry(account).State = EntityState.Modified;
                                        }
                                        catch (Exception e)
                                        {
                                            Logger.Instance.Error(e);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                Logger.Instance.Debug("Debit account for income transaction is null");
                            }


                            if (_db.ChangeTracker.HasChanges())
                            {
                                _db.SaveChanges();
                            }


                            return(true);
                        }

                        default:
                            throw new NotImplementedException();
                        }
                    }

                    switch (eventArgument)
                    {
                    case EventArgumentEnum.Delete:
                    {
                        if (originalDebitAccount != null)
                        {
                            originalDebitAccount.Balance -= transaction.Amount;

                            // Update Account's required savings

                            originalDebitAccount.BalanceSurplus   = _calc.UpdateBalanceSurplus(originalDebitAccount);
                            _db.Entry(originalDebitAccount).State = EntityState.Modified;
                        }

                        if (originalCreditAccount != null)
                        {
                            originalCreditAccount.Balance += transaction.Amount;

                            // Update Account's required savings

                            originalCreditAccount.BalanceSurplus   = _calc.UpdateBalanceSurplus(originalCreditAccount);
                            _db.Entry(originalCreditAccount).State = EntityState.Modified;
                        }


                        _db.SaveChanges();
                        return(true);
                    }

                    case EventArgumentEnum.Update:
                    {
                        var amountDifference = transaction.Amount - originalAmount;
                        if (originalDebitAccount != null)
                        {
                            originalDebitAccount.Balance         += amountDifference;
                            originalDebitAccount.BalanceSurplus   = _calc.UpdateBalanceSurplus(originalDebitAccount);
                            _db.Entry(originalDebitAccount).State = EntityState.Modified;
                        }

                        if (originalCreditAccount != null)
                        {
                            originalCreditAccount.Balance         -= amountDifference;
                            originalCreditAccount.BalanceSurplus   = _calc.UpdateBalanceSurplus(originalCreditAccount);
                            _db.Entry(originalCreditAccount).State = EntityState.Modified;
                        }


                        _db.SaveChanges();
                        return(true);
                    }

                    default:
                        throw new NotImplementedException();
                    }
                }

                default:
                    throw new NotImplementedException($"{eventArgument} is not an accepted type for TransactionController.UpdateDbAccountBalances method");
                }
            }
            catch (Exception e)
            {
                Logger.Instance.Error(e);
                return(false);
            }
        }
예제 #2
0
        public AccountMetrics GetMetrics()
        {
            try
            {
                //TODO: Needs Refactoring
                AccountMetrics metrics              = new AccountMetrics();
                AccountManager accountManager       = new AccountManager();
                BillManager    billManager          = new BillManager();
                List <Account> accounts             = GetAllAccounts();
                var            poolAccount          = GetPoolAccount();
                var            requiredSavingsDict  = _calc.GetRequiredSavingsDict();
                var            totalRequiredSavings = 0.0m;

                foreach (var savings in requiredSavingsDict)
                {
                    try
                    {
                        totalRequiredSavings += savings.Value;
                    }
                    catch (Exception e)
                    {
                        Logger.Instance.Error(e);
                    }
                }

                if (!accounts.Any())
                {
                    return(metrics);
                }

                metrics.LargestBalance  = accounts.Max(a => a.Balance);
                metrics.SmallestBalance = accounts.Min(a => a.Balance);
                metrics.AverageBalance  = accounts.Sum(a => a.Balance) / accounts.Count;
                var incomeTransactions      = _db.Transactions.Where(t => t.Type == TransactionTypesEnum.Income);
                var oldestIncomeTransaction = incomeTransactions.OrderBy(t => t.Date).FirstOrDefault();
                var daysAgo = 0;
                if (oldestIncomeTransaction != null)
                {
                    daysAgo = (DateTime.Today - oldestIncomeTransaction.Date).Days;
                }
                var monthsAgo = daysAgo / 30 < 1 ? 1 : daysAgo / 30;


                if (incomeTransactions.Any())
                {
                    metrics.MonthlySurplus = (incomeTransactions.Sum(t => t.Amount) / monthsAgo) - (accounts.Sum(a => a.PaycheckContribution) * 2);
                }
                metrics.LargestSurplus  = accounts.Max(a => a.BalanceSurplus);
                metrics.SmallestSurplus = accounts.Min(a => a.BalanceSurplus);
                var surplusAccounts = accounts.Where(a => a.BalanceSurplus > 0).ToList().Count; if (surplusAccounts > 0)
                {
                    metrics.AverageSurplus = accounts.Sum(a => a.BalanceSurplus) / surplusAccounts;
                }

                var cashBalance         = accounts.Sum(a => a.Balance) + poolAccount.Balance;
                var outstandingExpenses = billManager.GetOutstandingExpenseTotal();

                metrics.CashBalance       = cashBalance;
                metrics.AccountingBalance = cashBalance - totalRequiredSavings;

                var totalSurplus = accounts.Sum(a => a.BalanceSurplus) + poolAccount.Balance;
                metrics.SpendableCash             = totalSurplus > 0 ? totalSurplus : 0.0m; // Account balance surplus = account balance - balance limit (balance limit is 0, surplus = balance - required savings).  Balance limit allows the account to "fill up" to the limit
                metrics.OutstandingExpenses       = outstandingExpenses;
                metrics.PoolBalance               = accountManager.GetPoolAccount().Balance;
                metrics.OutstandingAccountDeficit = accounts.Where(a => a.BalanceSurplus < 0).Sum(a => a.BalanceSurplus);

                return(metrics);
            }
            catch (Exception e)
            {
                Logger.Instance.Error(e);
                return(null);
            }
        }