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);
 }
Exemple #5
0
        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);
        }
Exemple #6
0
        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);
        }