Example #1
0
        private async Task <bool> HoldBackCompletionPayments(TEarningEvent earningEvent, Earning earning, int type, CancellationToken cancellationToken)
        {
            if (type != (int)OnProgrammeEarningType.Completion)
            {
                return(false);
            }

            if (earning.Amount <= 0m)
            {
                return(false);
            }

            var priceEpisode     = earningEvent.PriceEpisodes.Single(p => p.Identifier == earning.PriceEpisodeIdentifier);
            var key              = apprenticeshipKeyProvider.GetCurrentKey();
            var employerPayments = await paymentHistoryRepository.GetEmployerCoInvestedPaymentHistoryTotal(key, cancellationToken).ConfigureAwait(false);

            return(completionPaymentService.ShouldHoldBackCompletionPayment(employerPayments, priceEpisode));
        }
Example #2
0
        public async Task <ReadOnlyCollection <PeriodisedRequiredPaymentEvent> > HandleEarningEvent(TEarningEvent earningEvent, IDataCache <PaymentHistoryEntity[]> paymentHistoryCache, CancellationToken cancellationToken)
        {
            if (earningEvent == null)
            {
                throw new ArgumentNullException(nameof(earningEvent));
            }

            try
            {
                var result = new List <PeriodisedRequiredPaymentEvent>();
                if (await duplicateEarningEventService.IsDuplicate(earningEvent, cancellationToken)
                    .ConfigureAwait(false))
                {
                    return(result.AsReadOnly());
                }
                var cachedPayments = await paymentHistoryCache.TryGet(CacheKeys.PaymentHistoryKey, cancellationToken);

                var academicYearPayments = cachedPayments.HasValue
                    ? cachedPayments.Value
                                           .Where(p => p.LearnAimReference.Equals(earningEvent.LearningAim.Reference, StringComparison.OrdinalIgnoreCase))
                                           .Select(p => mapper.Map <PaymentHistoryEntity, Payment>(p))
                                           .ToList()
                    : new List <Payment>();

                foreach (var(period, type) in GetPeriods(earningEvent))
                {
                    if (period.Period > earningEvent.CollectionPeriod.Period) // cut off future periods
                    {
                        continue;
                    }

                    if (period.Amount != 0 && !period.SfaContributionPercentage.HasValue)
                    {
                        throw new InvalidOperationException("Non-zero amount with no Sfa Contribution");
                    }

                    var payments = academicYearPayments.Where(payment => payment.DeliveryPeriod == period.Period &&
                                                              payment.TransactionType == type)
                                   .ToList();

                    List <RequiredPayment> requiredPayments;
                    var holdBackCompletionPayments = false;

                    if (NegativeEarningWillResultInARefund(period, payments))
                    {
                        requiredPayments = negativeEarningService
                                           .ProcessNegativeEarning(period.Amount, academicYearPayments, period.Period, period.PriceEpisodeIdentifier);
                    }
                    else
                    {
                        var earning = new Earning
                        {
                            Amount = period.Amount,
                            SfaContributionPercentage = period.SfaContributionPercentage,
                            EarningType            = GetEarningType(type),
                            PriceEpisodeIdentifier = period.PriceEpisodeIdentifier,
                            AccountId = period.AccountId,
                            TransferSenderAccountId = period.TransferSenderAccountId
                        };

                        requiredPayments = requiredPaymentProcessor.GetRequiredPayments(earning, payments);
                        if (requiredPayments.Count > 0)
                        {
                            holdBackCompletionPayments = await HoldBackCompletionPayments(earningEvent, earning, type, cancellationToken).ConfigureAwait(false);
                        }
                    }

                    if (requiredPayments.GroupBy(x => x.SfaContributionPercentage)
                        .All(x => x.Sum(y => y.Amount) == 0))
                    {
                        continue;
                    }

                    foreach (var requiredPayment in requiredPayments)
                    {
                        var requiredPaymentEvent = CreateRequiredPaymentEvent(requiredPayment.EarningType, type, holdBackCompletionPayments);
                        mapper.Map(period, requiredPaymentEvent);
                        mapper.Map(earningEvent, requiredPaymentEvent);
                        mapper.Map(requiredPayment, requiredPaymentEvent);
                        AddRefundCommitmentDetails(requiredPayment, requiredPaymentEvent);

                        var priceEpisodeIdentifier = requiredPaymentEvent.PriceEpisodeIdentifier;

                        if (earningEvent.PriceEpisodes != null && earningEvent.PriceEpisodes.Any())
                        {
                            var priceEpisode = earningEvent.PriceEpisodes.Count == 1
                                ? earningEvent.PriceEpisodes.FirstOrDefault()
                                : earningEvent.PriceEpisodes?.SingleOrDefault(x => x.Identifier == priceEpisodeIdentifier);

                            mapper.Map(priceEpisode, requiredPaymentEvent);

                            if (requiredPaymentEvent.LearningAim != null)
                            {
                                mapper.Map(priceEpisode, requiredPaymentEvent.LearningAim);
                            }
                        }

                        result.Add(requiredPaymentEvent);
                    }
                }
                return(result.AsReadOnly());
            }
            catch (Exception e)
            {
                paymentLogger.LogError($"Error while Handling EarningEvent for {earningEvent.Ukprn} ", e);
                throw;
            }
        }
        private async Task <bool> HoldBackCompletionPayments(TEarningEvent earningEvent, Earning earning, int type, CancellationToken cancellationToken)
        {
            if (type != (int)OnProgrammeEarningType.Completion)
            {
                return(false);
            }

            if (earning.Amount <= 0m)
            {
                return(false);
            }

            var priceEpisode     = earningEvent.PriceEpisodes.Single(p => p.Identifier == earning.PriceEpisodeIdentifier);
            var key              = apprenticeshipKeyProvider.GetCurrentKey();
            var employerPayments = await paymentHistoryRepository.GetEmployerCoInvestedPaymentHistoryTotal(key, cancellationToken).ConfigureAwait(false);

            var shouldHoldBackCompletionPayment = completionPaymentService.ShouldHoldBackCompletionPayment(employerPayments, priceEpisode);

            if (shouldHoldBackCompletionPayment)
            {
                var properties = new Dictionary <string, string>
                {
                    { TelemetryKeys.JobId, earningEvent.JobId.ToString() },
                    { TelemetryKeys.Ukprn, earningEvent.Ukprn.ToString() },
                    { TelemetryKeys.LearnerRef, earningEvent.Learner.ReferenceNumber },
                    { "LearningAimReference", earningEvent.LearningAim.Reference },
                    { "EarningEventId", earningEvent.EventId.ToString() },
                    { TelemetryKeys.CollectionPeriod, earningEvent.CollectionPeriod.Period.ToString() },
                    { TelemetryKeys.AcademicYear, earningEvent.CollectionPeriod.AcademicYear.ToString() },
                    { "Completion HoldBack Exemption Code", employerPayments.ToString(CultureInfo.InvariantCulture) },
                    { "Expected Employer Contribution", priceEpisode.CompletionHoldBackExemptionCode.ToString() },
                    { "Reported Employer Contribution", priceEpisode.EmployerContribution.ToString() },
                };

                telemetry.TrackEvent("Holding Back Completion Payment", properties, new Dictionary <string, double>());
            }

            return(shouldHoldBackCompletionPayment);
        }