public async Task ApproveProvidersFundingJobForSuppliedSpecificationId() { ApiSpecificationSummary specificationSummary = NewApiSpecificationSummary(_ => _.WithIsSelectedForFunding(true)); string approveFundingJobId = NewRandomString(); ApiJob approveFundingJob = NewJob(_ => _.WithId(approveFundingJobId)); string filterIdOne = NewRandomString(); string filterIdTwo = NewRandomString(); GivenTheApiResponseDetailsForTheSuppliedId(specificationSummary); AndTheFilteredListOfPublishedProviderIds(filterIdOne, filterIdTwo); AndTheApiResponseDetailsForApproveProviderJob(approveFundingJob, JsonExtensions.AsJson(new PublishedProviderIdsRequest { PublishedProviderIds = new[] { filterIdOne, filterIdTwo } })); await WhenBatchProvidersAreApproved(); JobCreationResponse expectedJobCreationResponse = NewJobCreationResponse(_ => _.WithJobId(approveFundingJobId)); ActionResult .Should() .BeOfType <OkObjectResult>() .Which .Value .Should() .BeEquivalentTo(expectedJobCreationResponse); }
public async Task WhenPartialFundingIsApproved(Table table) { Message message = new Message(); string[] providerIds = table.AsStrings(); PublishedProviderIdsRequest approveProvidersRequest = new PublishedProviderIdsRequest { PublishedProviderIds = providerIds }; string approveProvidersRequestJson = JsonExtensions.AsJson(approveProvidersRequest); message.UserProperties.Add("user-id", _currentUserStepContext.UserId); message.UserProperties.Add("user-name", _currentUserStepContext.UserName); message.UserProperties.Add("specification-id", _currentSpecificationStepContext.SpecificationId); message.UserProperties.Add("jobId", _currentJobStepContext.JobId); message.Body = Encoding.UTF8.GetBytes(approveProvidersRequestJson); await _approveService.Run(message, async() => { await _approveService.ApproveResults(message, batched: true); }); }
public async Task ApproveResults(Message message, bool batched = false) { Guard.ArgumentNotNull(message, nameof(message)); _logger.Information("Starting approve provider funding job"); string specificationId = message.GetUserProperty <string>("specification-id"); PublishedProviderIdsRequest publishedProviderIdsRequest = null; string logApproveProcessingMessage = $"Processing approve specification funding job. JobId='{Job.Id}'. SpecificationId='{specificationId}'."; if (batched) { publishedProviderIdsRequest = message.GetPayloadAsInstanceOf <PublishedProviderIdsRequest>(); logApproveProcessingMessage += $" Request = {JsonExtensions.AsJson(publishedProviderIdsRequest)}."; } await PerformPrerequisiteChecks(specificationId, Job.Id, batched == true?PrerequisiteCheckerType.ApproveBatchProviders : PrerequisiteCheckerType.ApproveAllProviders); _logger.Information(logApproveProcessingMessage); _logger.Information("Fetching published providers for specification funding approval"); IEnumerable <PublishedProvider> publishedProviders = await GetPublishedProvidersForApproval(specificationId, publishedProviderIdsRequest?.PublishedProviderIds?.ToArray()); CheckPublishedProviderForErrors(specificationId, publishedProviders); Reference author = message.GetUserDetails(); string correlationId = message.GetUserProperty <string>(SfaCorrelationId); await ApproveProviders(publishedProviders, specificationId, Job.Id, author, correlationId); }
public async Task <IActionResult> PublishBatchProvidersFunding(string specificationId, PublishedProviderIdsRequest publishedProviderIdsRequest, Reference user, string correlationId) { ValidationResult specificationIdValidationResult = SpecificationIdValidator.Validate(specificationId); if (!specificationIdValidationResult.IsValid) { return(specificationIdValidationResult.AsBadRequest()); } ValidationResult publishedProviderIdsValidationResult = PublishedProviderIdsValidator.Validate(publishedProviderIdsRequest.PublishedProviderIds.ToArray()); if (!publishedProviderIdsValidationResult.IsValid) { return(publishedProviderIdsValidationResult.AsBadRequest()); } IActionResult actionResult = await IsSpecificationReadyForPublish(specificationId, ApprovalMode.Batches); if (!actionResult.IsOk()) { return(actionResult); } await FilterOutPublishedProvidersInError(publishedProviderIdsRequest); ApiJob job = await _createBatchPublishProviderFundingJobs.CreateJob(specificationId, user, correlationId, messageBody : JsonExtensions.AsJson(publishedProviderIdsRequest), compress : true); return(ProcessJobResponse(job, specificationId, JobConstants.DefinitionNames.PublishBatchProviderFundingJob)); }
private void GivenTheMessageHasTheApproveProvidersRequest(PublishedProviderIdsRequest approveProvidersRequest) { _message.Body = Encoding.UTF8.GetBytes(JsonExtensions.AsJson(approveProvidersRequest)); }
private async Task PublishFundingStream(Reference fundingStream, SpecificationSummary specification, string jobId, Reference author, string correlationId, PrerequisiteCheckerType prerequisiteCheckerType, string[] batchPublishedProviderIds = null) { _logger.Information($"Processing Publish Funding for {fundingStream.Id} in specification {specification.Id}"); if (!specification.TemplateIds.ContainsKey(fundingStream.Id) || string.IsNullOrWhiteSpace(specification.TemplateIds[fundingStream.Id])) { _logger.Information($"Skipped publishing {fundingStream.Id} as no template exists"); return; } // we always need to get every provider in scope whether it is released or otherwise so that we always genarate the contents // this is just in case an error has occurred during a release so we never get a case where we don't get blobs generated for the published providers (IDictionary <string, PublishedProvider> publishedProvidersForFundingStream, IDictionary <string, PublishedProvider> scopedPublishedProviders) = await _providerService.GetPublishedProviders(fundingStream, specification); IDictionary <string, PublishedProvider> publishedProvidersByPublishedProviderId = publishedProvidersForFundingStream.Values.ToDictionary(_ => _.PublishedProviderId); IEnumerable <PublishedProvider> selectedPublishedProviders = batchPublishedProviderIds.IsNullOrEmpty() ? publishedProvidersForFundingStream.Values : batchPublishedProviderIds.Where(_ => publishedProvidersByPublishedProviderId.ContainsKey(_)).Select(_ => publishedProvidersByPublishedProviderId[_]); AddInitialPublishVariationReasons(selectedPublishedProviders); _logger.Information($"Verifying prerequisites for funding publish"); IPrerequisiteChecker prerequisiteChecker = _prerequisiteCheckerLocator.GetPreReqChecker(prerequisiteCheckerType); try { await prerequisiteChecker.PerformChecks(specification, jobId, selectedPublishedProviders?.ToList()); } catch (JobPrereqFailedException ex) { throw new NonRetriableException(ex.Message, ex); } _logger.Information("Prerequisites for publish passed"); TemplateMapping templateMapping = await GetTemplateMapping(fundingStream, specification.Id); PublishedFundingInput publishedFundingInput = await _publishedFundingService.GeneratePublishedFundingInput(publishedProvidersForFundingStream, scopedPublishedProviders?.Values.Select(_ => _.Current.Provider), fundingStream, specification, batchPublishedProviderIds.IsNullOrEmpty()?null : selectedPublishedProviders); using Transaction transaction = _transactionFactory.NewTransaction <PublishService>(); try { // if any error occurs while updating or indexing then we need to re-index all published providers and persist published funding for consistency transaction.Enroll(async() => { await _publishedProviderVersionService.CreateReIndexJob(author, correlationId, specification.Id, jobId); await _createPublishIntegrityJob.CreateJob(specification.Id, author, correlationId, batchPublishedProviderIds.IsNullOrEmpty() ? null : new Dictionary <string, string> { { "providers-batch", JsonExtensions.AsJson(selectedPublishedProviders.Select(_ => _.PublishedProviderId)) } }, parentJobId: jobId); }); await SavePublishedProvidersAsReleased(jobId, author, selectedPublishedProviders, correlationId); ICollection <PublishedProvider> publishedProviders = publishedProvidersForFundingStream?.Values; _logger.Information($"Generating published funding"); IEnumerable <(PublishedFunding PublishedFunding, PublishedFundingVersion PublishedFundingVersion)> publishedFundingToSave = _publishedFundingGenerator.GeneratePublishedFunding(publishedFundingInput, publishedProviders).ToList(); _logger.Information($"A total of {publishedFundingToSave.Count()} published funding versions created to save."); foreach ((PublishedFunding PublishedFunding, PublishedFundingVersion PublishedFundingVersion)publishedFundingItems in publishedFundingToSave) { PropagateProviderVariationReasons(publishedFundingItems.PublishedFundingVersion, publishedProviders); } // if any error occurs while updating then we still need to run the indexer to be consistent transaction.Enroll(async() => { await _publishedIndexSearchResiliencePolicy.ExecuteAsync(() => _publishedFundingSearchRepository.RunIndexer()); }); // Save a version of published funding and set this version to current _logger.Information($"Saving published funding"); await _publishedFundingStatusUpdateService.UpdatePublishedFundingStatus(publishedFundingToSave, author, PublishedFundingStatus.Released, jobId, correlationId); _logger.Information($"Finished saving published funding"); // Save contents to blob storage and search for the feed _logger.Information($"Saving published funding contents"); await _publishedFundingContentsPersistanceService.SavePublishedFundingContents(publishedFundingToSave.Select(_ => _.PublishedFundingVersion), publishedFundingInput.TemplateMetadataContents); _logger.Information($"Finished saving published funding contents"); if (!selectedPublishedProviders.IsNullOrEmpty()) { // Generate contents JSON for provider and save to blob storage IPublishedProviderContentsGenerator generator = _publishedProviderContentsGeneratorResolver.GetService(publishedFundingInput.TemplateMetadataContents.SchemaVersion); await _publishedProviderContentsPersistanceService.SavePublishedProviderContents(publishedFundingInput.TemplateMetadataContents, templateMapping, selectedPublishedProviders, generator); } transaction.Complete(); } catch (Exception ex) { await transaction.Compensate(); throw; } }