public bool HandlePaycheckContributions(Transaction transaction) { try { var accountManager = new AccountManager(); transaction.DebitAccount = accountManager.GetAccount(transaction.DebitAccountId); var accountsWithContributions = accountManager.GetAllAccounts().Where(a => a.PaycheckContribution > 0).ToList(); var totalContributions = accountsWithContributions.Sum(a => a.PaycheckContribution); var incomeAfterPaycheckContributions = transaction.Amount; if (totalContributions > transaction.Amount) { // TODO: How to handle income not enough to cover all paycheck contributions } foreach (var account in accountsWithContributions) { if (!UpdateAccountBalance(account, account.PaycheckContribution, AccountingTypes.Debit)) { return(false); } if (!AddTransferToDb(transaction, account)) { return(false); } incomeAfterPaycheckContributions -= account.PaycheckContribution; } Logger.Instance.Calculation($"Net income of {incomeAfterPaycheckContributions} added to {transaction.DebitAccount?.Name} after {totalContributions} in paycheck contributions was paid out"); if (!UpdateAccountBalance(transaction.DebitAccount, incomeAfterPaycheckContributions, AccountingTypes.Debit)) { return(false); } //TODO: find a better way to add remainder of income after paycheck contributions to Db var incomeAfterContributions = new Transaction(); incomeAfterContributions.Date = transaction.Date; incomeAfterContributions.Payee = $"Transfer to {transaction.DebitAccount?.Name}"; incomeAfterContributions.Category = transaction.Category; incomeAfterContributions.Memo = transaction.Memo; incomeAfterContributions.Type = transaction.Type; incomeAfterContributions.DebitAccountId = transaction.DebitAccountId; incomeAfterContributions.CreditAccountId = null; incomeAfterContributions.Amount = incomeAfterPaycheckContributions; _db.Transactions.Add(incomeAfterContributions); _db.SaveChanges(); return(true); } catch (Exception e) { Logger.Instance.Error(e); return(false); } }
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); } }
//TODO: Update to only update effected Accounts private bool UpdateAccountPaycheckContribution() { try { var updatedAccounts = new List <Account>(); var paycheckContributionsDict = _calc.GetPaycheckContributionsDict(); var accountManager = new AccountManager(); var account = new Account(); // Update paycheck contribution for all accounts foreach (var paycheckContribution in paycheckContributionsDict) { try { account = updatedAccounts.Find(a => string.Equals(a.Name, paycheckContribution.Key, StringComparison.CurrentCultureIgnoreCase)); var accountIndex = -1; if (account == null) { account = new Account { Name = paycheckContribution.Key }; } else { accountIndex = updatedAccounts.FindIndex(a => string.Equals(a.Name, paycheckContribution.Key, StringComparison.CurrentCultureIgnoreCase)); } if (!(paycheckContribution.Value >= account.PaycheckContribution)) { continue; } if (accountIndex >= 0) { updatedAccounts[accountIndex].PaycheckContribution = paycheckContribution.Value; } else { account.PaycheckContribution = paycheckContribution.Value; updatedAccounts.Add(account); } // iterate through all updated accounts and set state to modified to save to database var accounts = accountManager.GetAllAccounts(); foreach (var updatedAccount in updatedAccounts) { try { account = accounts.Find(a => string.Equals(a.Name, updatedAccount.Name, StringComparison.CurrentCultureIgnoreCase)); // shouldn't ever be null since updatedAccounts comes from Accounts in DB account.PaycheckContribution = updatedAccount.PaycheckContribution; account.RequiredSavings = updatedAccount.RequiredSavings; var requiredSurplus = account.Balance - account.RequiredSavings; if (requiredSurplus <= 0) { account.BalanceSurplus = requiredSurplus; } else { if (account.Balance - account.BalanceLimit <= 0) { account.BalanceSurplus = 0; } else { account.BalanceSurplus = account.Balance - account.BalanceLimit; } } _db.Entry(account).State = EntityState.Modified; } catch (Exception e) { Logger.Instance.Error(e); } } // save changes to the database if (_db.ChangeTracker.HasChanges()) { _db.SaveChanges(); } } catch (Exception e) { Logger.Instance.Error(e); } } return(true); } catch (Exception e) { Logger.Instance.Error(e); return(false); } }