private void BuildProjections(DateTime periodStart, int numberOfMonths, ProjectionGenerationType projectionGenerationType) { var startMonth = 0; _projections.Clear(); var lastBalance = _account.Balance; for (var month = startMonth; month <= numberOfMonths; month++) { var levyFundsIn = projectionGenerationType == ProjectionGenerationType.LevyDeclaration && month == startMonth ? 0 : _account.LevyDeclared; var ignoreCostOfTraining = month == startMonth; if (IsProjectionTypeLevyBeingRanBeforeLevyRun(periodStart, projectionGenerationType)) { ignoreCostOfTraining = false; levyFundsIn = _account.LevyDeclared; } var projection = CreateProjection( periodStart.AddMonths(month), levyFundsIn, lastBalance, projectionGenerationType, ignoreCostOfTraining, periodStart.Day); _projections.Add(projection); lastBalance = projection.FutureFunds; } }
private AccountProjectionModel CreateProjection(DateTime period, decimal levyFundsIn, decimal lastBalance, ProjectionGenerationType projectionGenerationType, bool isFirstMonth, int periodStartDay) { var totalCostOfTraning = _employerCommitments.GetTotalCostOfTraining(period); var completionPayments = _employerCommitments.GetTotalCompletionPayments(period); var currentBalance = GetCurrentBalance(lastBalance, completionPayments.TransferOutCompletionPayment, totalCostOfTraning.TransferOut, isFirstMonth); var trainingCosts = totalCostOfTraning.LevyFunded + completionPayments.LevyFundedCompletionPayment; var coInvestmentAmount = GetCoInvestmentAmountBasedOnCurrentBalanceAndTrainingCosts(currentBalance, trainingCosts); var moneyOut = isFirstMonth ? coInvestmentAmount : trainingCosts - coInvestmentAmount; var moneyIn = isFirstMonth && projectionGenerationType == ProjectionGenerationType.LevyDeclaration ? 0: levyFundsIn; var futureFunds = GetMonthEndBalance(currentBalance, moneyOut, moneyIn, projectionGenerationType, isFirstMonth, periodStartDay); var projection = new AccountProjectionModel { LevyFundsIn = _account.LevyDeclared, EmployerAccountId = _account.EmployerAccountId, Month = (short)period.Month, Year = (short)period.Year, LevyFundedCostOfTraining = totalCostOfTraning.LevyFunded, TransferInCostOfTraining = totalCostOfTraning.TransferIn, TransferOutCostOfTraining = totalCostOfTraning.TransferOut, LevyFundedCompletionPayments = completionPayments.LevyFundedCompletionPayment, TransferInCompletionPayments = completionPayments.TransferInCompletionPayment, TransferOutCompletionPayments = completionPayments.TransferOutCompletionPayment, CoInvestmentEmployer = coInvestmentAmount > 0 ? (coInvestmentAmount * 0.1m) : 0m, CoInvestmentGovernment = coInvestmentAmount > 0 ? (coInvestmentAmount * 0.9m) : 0m, FutureFunds = futureFunds, ProjectionCreationDate = DateTime.UtcNow, ProjectionGenerationType = projectionGenerationType }; return(projection); }
public decimal GetMonthEndBalance(decimal currentBalance, decimal moneyOut, decimal levyFundsIn, ProjectionGenerationType projectionGenerationType, bool isFirstMonth, int periodStartDay) { if (projectionGenerationType == ProjectionGenerationType.LevyDeclaration && isFirstMonth) { if (periodStartDay > 19) { return(currentBalance); } } if (currentBalance > 0 && currentBalance >= moneyOut) { return(currentBalance + levyFundsIn - moneyOut); } if (currentBalance > 0) { return(levyFundsIn); } return(currentBalance + levyFundsIn); }
private static bool IsProjectionTypeLevyBeingRanBeforeLevyRun(DateTime periodStart, ProjectionGenerationType projectionGenerationType) { return(projectionGenerationType == ProjectionGenerationType.LevyDeclaration && periodStart.Day < 19); }
public async Task <Dictionary <CalendarPeriod, decimal> > GetExpiringFunds(ReadOnlyCollection <AccountEstimationProjectionModel> estimationProjectorProjections, long employerAccountId, ProjectionGenerationType messageProjectionSource, DateTime projectionDate) { var stopwatch = new Stopwatch(); stopwatch.Start(); var netLevyTotal = await _levyDataSession.GetAllNetTotals(employerAccountId); var paymentsTotal = await _employerPaymentDataSession.GetPaymentTotals(employerAccountId); var expiringFunds = GetExpiringFunds(estimationProjectorProjections, netLevyTotal, paymentsTotal, messageProjectionSource, projectionDate); stopwatch.Stop(); _telemetry.TrackDuration("GenerateEstimatedExpiringFunds", stopwatch.Elapsed); return(expiringFunds); }
public Dictionary <CalendarPeriod, decimal> GetExpiringFunds(ReadOnlyCollection <AccountEstimationProjectionModel> estimationProjectorProjections, IEnumerable <LevyPeriod> levyPeriodTotals, Dictionary <CalendarPeriod, decimal> paymentsTotals, ProjectionGenerationType messageProjectionSource, DateTime projectionDate) { var previousLevyTotals = levyPeriodTotals.ToDictionary(k => new CalendarPeriod(k.CalendarYear, k.CalendarMonth), v => v.TotalNetLevyDeclared); var fundsIn = estimationProjectorProjections.ToDictionary(d => new CalendarPeriod(d.Year, d.Month), v => v.FundsIn); var fundsOut = estimationProjectorProjections.OrderBy(c => c.Year) .ThenBy(c => c.Month) .Skip(ShouldSkipFirstMonthPaymentValue(projectionDate, (ProjectionSource)messageProjectionSource)) .ToDictionary(d => new CalendarPeriod(d.Year, d.Month), v => v.AllModelledCosts.FundsOut + v.ActualCosts.FundsOut); fundsIn = fundsIn.Concat(previousLevyTotals).GroupBy(g => g.Key).ToDictionary(t => t.Key, t => t.Last().Value); fundsOut = fundsOut.Concat(paymentsTotals).GroupBy(g => g.Key).ToDictionary(t => t.Key, t => t.Last().Value); var expiringFunds = _expiredFunds.GetExpiringFunds(fundsIn, fundsOut, null, 24); return((Dictionary <CalendarPeriod, decimal>)expiringFunds); }