private async Task AddRefundPaymentToCache(CalculatedRequiredLevyAmount paymentEvent)
        {
            var keysValue = await refundSortKeysCache.TryGet(CacheKeys.RefundPaymentsKeyListKey).ConfigureAwait(false);

            var refundKeysList = keysValue.HasValue ? keysValue.Value : new List <string>();

            refundKeysList.Add(paymentEvent.EventId.ToString());
            await requiredPaymentsCache.AddOrReplace(paymentEvent.EventId.ToString(), paymentEvent).ConfigureAwait(false);

            await refundSortKeysCache.AddOrReplace(CacheKeys.RefundPaymentsKeyListKey, refundKeysList).ConfigureAwait(false);
        }
        public async Task <ReadOnlyCollection <FundingSourcePaymentEvent> > ProcessReceiverTransferPayment(ProcessUnableToFundTransferFundingSourcePayment message)
        {
            if (!message.AccountId.HasValue)
            {
                throw new InvalidOperationException($"Invalid ProcessUnableToFundTransferFundingSourcePayment event.  No account id populated on message.  Event id: {message.EventId}");
            }

            paymentLogger.LogDebug($"Converting the unable to fund transfer payment to a levy payment.  Event id: {message.EventId}, account id: {message.AccountId}, job id: {message.JobId}");
            var requiredPayment = mapper.Map <CalculatedRequiredLevyAmount>(message);

            paymentLogger.LogVerbose("Mapped ProcessUnableToFundTransferFundingSourcePayment to CalculatedRequiredLevyAmount");
            var payments = new List <FundingSourcePaymentEvent>();
            var monthEndStartedCacheItem = await monthEndCache.TryGet(CacheKeys.MonthEndCacheKey);

            if (!monthEndStartedCacheItem.HasValue || !monthEndStartedCacheItem.Value)
            {
                paymentLogger.LogDebug("Month end has not been started yet so adding the payment to the cache.");
                await AddRequiredPayment(requiredPayment);
            }
            else
            {
                var levyAccountCacheItem = await levyAccountCache.TryGet(CacheKeys.LevyBalanceKey, CancellationToken.None)
                                           .ConfigureAwait(false);

                if (!levyAccountCacheItem.HasValue)
                {
                    throw new InvalidOperationException($"The last levy account balance has not been stored in the reliable for account: {message.AccountId}");
                }

                levyBalanceService.Initialise(levyAccountCacheItem.Value.Balance, levyAccountCacheItem.Value.TransferAllowance);
                paymentLogger.LogDebug("Service has finished month end processing so now generating the payments for the ProcessUnableToFundTransferFundingSourcePayment event.");
                payments.AddRange(CreateFundingSourcePaymentsForRequiredPayment(requiredPayment, message.AccountId.Value, message.JobId));
                var remainingBalance = mapper.Map <LevyAccountModel>(levyAccountCacheItem.Value);
                remainingBalance.Balance           = levyBalanceService.RemainingBalance;
                remainingBalance.TransferAllowance = levyBalanceService.RemainingTransferAllowance;
                await levyAccountCache.AddOrReplace(CacheKeys.LevyBalanceKey, remainingBalance);
            }
            paymentLogger.LogInfo($"Finished processing the ProcessUnableToFundTransferFundingSourcePayment. Event id: {message.EventId}, account id: {message.AccountId}, job id: {message.JobId}");
            return(payments.AsReadOnly());
        }
        private async Task AddRequiredPaymentToCache(CalculatedRequiredLevyAmount paymentEvent)
        {
            var keysValue = await requiredPaymentSortKeysCache.TryGet(CacheKeys.RequiredPaymentKeyListKey).ConfigureAwait(false);

            var requiredPaymentKeysList = keysValue.HasValue ? keysValue.Value : new List <RequiredPaymentSortKeyModel>();

            var newRequiredPaymentSortKey = new RequiredPaymentSortKeyModel
            {
                Id           = paymentEvent.EventId.ToString(),
                Uln          = paymentEvent.Learner.Uln,
                Ukprn        = paymentEvent.Ukprn,
                AgreedOnDate = paymentEvent.AgreedOnDate ?? DateTime.MinValue
            };

            requiredPaymentKeysList.Add(newRequiredPaymentSortKey);

            await requiredPaymentsCache.AddOrReplace(newRequiredPaymentSortKey.Id, paymentEvent).ConfigureAwait(false);

            await requiredPaymentSortKeysCache.AddOrReplace(CacheKeys.RequiredPaymentKeyListKey, requiredPaymentKeysList).ConfigureAwait(false);
        }
        public async Task <ReadOnlyCollection <FundingSourcePaymentEvent> > HandleMonthEnd(long employerAccountId, long jobId)
        {
            var fundingSourceEvents = new List <FundingSourcePaymentEvent>();

            var keys = await generateSortedPaymentKeys.GeyKeys().ConfigureAwait(false);

            var levyAccount = await levyFundingSourceRepository.GetLevyAccount(employerAccountId);

            levyBalanceService.Initialise(levyAccount.Balance, levyAccount.TransferAllowance);

            paymentLogger.LogDebug($"Processing {keys.Count} required payments, levy balance {levyAccount.Balance}, account {employerAccountId}, job id {jobId}");

            foreach (var key in keys)
            {
                var requiredPaymentEvent = await requiredPaymentsCache.TryGet(key).ConfigureAwait(false);

                if (!requiredPaymentEvent.HasValue)
                {
                    continue;
                }
                fundingSourceEvents.AddRange(CreateFundingSourcePaymentsForRequiredPayment(requiredPaymentEvent.Value, employerAccountId, jobId));
                await requiredPaymentsCache.Clear(key).ConfigureAwait(false);
            }

            paymentLogger.LogDebug($"Created {fundingSourceEvents.Count} payments - {GetFundsDebugString(fundingSourceEvents)}, account {employerAccountId}, job id {jobId}");

            levyAccount.Balance           = levyBalanceService.RemainingBalance;
            levyAccount.TransferAllowance = levyBalanceService.RemainingTransferAllowance;
            await levyAccountCache.AddOrReplace(CacheKeys.LevyBalanceKey, levyAccount);

            await refundSortKeysCache.Clear(CacheKeys.RefundPaymentsKeyListKey).ConfigureAwait(false);

            await transferPaymentSortKeysCache.Clear(CacheKeys.SenderTransferKeyListKey).ConfigureAwait(false);

            await requiredPaymentSortKeysCache.Clear(CacheKeys.RequiredPaymentKeyListKey).ConfigureAwait(false);

            await monthEndCache.AddOrReplace(CacheKeys.MonthEndCacheKey, true, CancellationToken.None);

            paymentLogger.LogInfo($"Finished generating levy and/or co-invested payments for the account: {employerAccountId}, number of payments: {fundingSourceEvents.Count}.");
            return(fundingSourceEvents.AsReadOnly());
        }
        public async Task StoreEmployerProviderPriority(EmployerChangedProviderPriority providerPriorityEvent)
        {
            try
            {
                int order             = 1;
                var paymentPriorities = new List <EmployerProviderPriorityModel>();
                foreach (var providerUkprn in providerPriorityEvent.OrderedProviders)
                {
                    paymentPriorities.Add(new EmployerProviderPriorityModel
                    {
                        Ukprn             = providerUkprn,
                        EmployerAccountId = providerPriorityEvent.EmployerAccountId,
                        Order             = order
                    });

                    order++;
                }

                using (var scope = new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled))
                {
                    paymentLogger.LogDebug($"Replacing Previous EmployerProviderPriority for Account Id {providerPriorityEvent.EmployerAccountId}");
                    await levyFundingSourceRepository.ReplaceEmployerProviderPriorities(providerPriorityEvent.EmployerAccountId, paymentPriorities).ConfigureAwait(false);

                    paymentLogger.LogDebug($"Successfully Replaced Previous EmployerProviderPriority for Account Id {providerPriorityEvent.EmployerAccountId}");

                    paymentLogger.LogDebug($"Adding EmployerProviderPriority to Cache for Account Id {providerPriorityEvent.EmployerAccountId}");
                    await employerProviderPriorities.AddOrReplace(CacheKeys.EmployerPaymentPriorities, paymentPriorities).ConfigureAwait(false);

                    paymentLogger.LogInfo($"Successfully Add EmployerProviderPriority to Cache for Account Id {providerPriorityEvent.EmployerAccountId}");

                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                paymentLogger.LogError($"Error while updating  EmployerProviderPriority for Account Id {providerPriorityEvent.EmployerAccountId}", e);
                throw;
            }
        }
        public async Task <ReadOnlyCollection <FundingSourcePaymentEvent> > HandleMonthEnd(
            ProcessLevyPaymentsOnMonthEndCommand command)
        {
            paymentLogger.LogVerbose(
                $"Handling ProcessLevyPaymentsOnMonthEndCommand for {Id}, Job: {command.JobId}, Account: {command.AccountId}");
            try
            {
                using (var operation =
                           telemetry.StartOperation("LevyFundedService.HandleMonthEnd", command.CommandId.ToString()))
                {
                    var stopwatch = Stopwatch.StartNew();


                    var fundingSourceEvents =
                        await fundingSourceEventGenerationService.HandleMonthEnd(command.AccountId, command.JobId, command.CollectionPeriod);

                    await monthEndCache.AddOrReplace(CacheKeys.MonthEndStartedForThisAccountCacheKey, true, CancellationToken.None);

                    telemetry.TrackDurationWithMetrics("LevyFundedService.HandleMonthEnd",
                                                       stopwatch,
                                                       command,
                                                       command.AccountId,
                                                       new Dictionary <string, double>
                    {
                        { TelemetryKeys.Count, fundingSourceEvents.Count }
                    });

                    telemetry.StopOperation(operation);
                    return(fundingSourceEvents);
                }
            }
            catch (Exception ex)
            {
                paymentLogger.LogError($"Failed to get levy or co-invested month end payments. Error: {ex.Message}",
                                       ex);
                throw;
            }
        }
示例#7
0
        private async Task Initialise()
        {
            if (await actorCache.IsInitialiseFlagIsSet().ConfigureAwait(false))
            {
                paymentLogger.LogVerbose($"Actor already initialised for employer {Id}");
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            paymentLogger.LogInfo($"Initialising actor for employer {Id.GetLongId()}");

            var paymentPriorities = await levyFundingSourceRepository.GetPaymentPriorities(Id.GetLongId()).ConfigureAwait(false);

            await employerProviderPriorities
            .AddOrReplace(CacheKeys.EmployerPaymentPriorities, paymentPriorities, default(CancellationToken))
            .ConfigureAwait(false);

            await actorCache.SetInitialiseFlag().ConfigureAwait(false);

            paymentLogger.LogInfo($"Initialised actor for employer {Id.GetLongId()}");
            TrackInfrastructureEvent("LevyFundedService.Initialise", stopwatch);
        }
        public async Task <ReadOnlyCollection <FundingSourcePaymentEvent> > HandleMonthEnd(long employerAccountId, long jobId, CollectionPeriod collectionPeriod)
        {
            var levyAccount = await levyFundingSourceRepository.GetLevyAccount(employerAccountId);

            levyBalanceService.Initialise(levyAccount.Balance, levyAccount.TransferAllowance);

            var orderedRequiredLevyPayments = await GetOrderedCalculatedRequiredLevyAmounts(employerAccountId, collectionPeriod).ConfigureAwait(false);

            logger.LogDebug($"Processing {orderedRequiredLevyPayments.Count} required payments, levy balance {levyAccount.Balance}, account {employerAccountId}, job id {jobId}");
            var fundingSourceEvents = new List <FundingSourcePaymentEvent>();

            fundingSourceEvents.AddRange(orderedRequiredLevyPayments.SelectMany(payment =>
                                                                                fundingSourcePaymentEventBuilder.BuildFundingSourcePaymentsForRequiredPayment(payment, employerAccountId, jobId)));

            logger.LogDebug($"Created {fundingSourceEvents.Count} payments - {GetFundsDebugString(fundingSourceEvents)}, account {employerAccountId}, job id {jobId}");

            levyAccount.Balance           = levyBalanceService.RemainingBalance;
            levyAccount.TransferAllowance = levyBalanceService.RemainingTransferAllowance;
            await levyAccountCache.AddOrReplace(CacheKeys.LevyBalanceKey, levyAccount);

            logger.LogInfo($"Finished generating levy and/or co-invested payments for the account: {employerAccountId}, number of payments: {fundingSourceEvents.Count}.");
            return(fundingSourceEvents.AsReadOnly());
        }