public async Task RespondsWithBadRequestIfRequestFailsValidation()
        {
            string propertyOne = NewRandomString();
            string propertyTwo = NewRandomString();
            string errorOne    = NewRandomString();
            string errorTwo    = NewRandomString();

            ProfileBatchRequest profileBatchRequest = NewProfileBatchRequest();

            GivenTheValidationResult(profileBatchRequest,
                                     NewValidationResult(_ => _.WithFailures(
                                                             NewValidationFailure(vf => vf
                                                                                  .WithPropertyName(propertyOne)
                                                                                  .WithErrorMessage(errorOne)),
                                                             NewValidationFailure(vf => vf
                                                                                  .WithPropertyName(propertyTwo)
                                                                                  .WithErrorMessage(errorTwo)))));

            BadRequestObjectResult badRequestObjectResult = await WhenTheBatchProfileRequestIsProcessed(profileBatchRequest) as BadRequestObjectResult;

            badRequestObjectResult?.Value
            .Should()
            .BeEquivalentTo(NewSerializeableError(_ => _.WithError(propertyOne, errorOne)
                                                  .WithError(propertyTwo, errorTwo)));
        }
        public async Task ProfilesEachProviderFundingValueInTheSuppliedBatches()
        {
            decimal fundingValueOne   = NewRandomFundingValue();
            decimal fundingValueTwo   = NewRandomFundingValue();
            decimal fundingValueThree = NewRandomFundingValue();

            ProfileBatchRequest request = NewProfileBatchRequest(_ => _.WithFundingValues(fundingValueOne,
                                                                                          fundingValueTwo,
                                                                                          fundingValueThree));

            FundingStreamPeriodProfilePattern profilePattern = NewProfilePattern();

            AllocationProfileResponse allocationProfileResponseOne   = NewAllocationProfileResponse();
            AllocationProfileResponse allocationProfileResponseTwo   = NewAllocationProfileResponse();
            AllocationProfileResponse allocationProfileResponseThree = NewAllocationProfileResponse();

            GivenTheValidationResult(request, NewValidationResult());
            AndTheProfilePattern(request, profilePattern);
            AndTheProfilingResponse(request, profilePattern, fundingValueOne, allocationProfileResponseOne);
            AndTheProfilingResponse(request, profilePattern, fundingValueTwo, allocationProfileResponseTwo);
            AndTheProfilingResponse(request, profilePattern, fundingValueThree, allocationProfileResponseThree);

            OkObjectResult result = await WhenTheBatchProfileRequestIsProcessed(request) as OkObjectResult;

            result?.Value
            .Should()
            .BeEquivalentTo(new[]
            {
                new BatchAllocationProfileResponse(request.GetFundingValueKey(fundingValueOne), fundingValueOne, allocationProfileResponseOne),
                new BatchAllocationProfileResponse(request.GetFundingValueKey(fundingValueTwo), fundingValueTwo, allocationProfileResponseTwo),
                new BatchAllocationProfileResponse(request.GetFundingValueKey(fundingValueThree), fundingValueThree, allocationProfileResponseThree)
            });
        }
 public BatchProfileRequestContext(FundingStreamPeriodProfilePattern profilePattern,
                                   ProfileBatchRequest request,
                                   int pageSize) : base(request.FundingValues, pageSize)
 {
     Request        = request;
     ProfilePattern = profilePattern;
 }
 private void AndTheProfilePattern(ProfileBatchRequest request,
                                   FundingStreamPeriodProfilePattern profilePattern)
 => _profilePatterns.Setup(_ => _.GetProfilePattern(request.FundingPeriodId,
                                                    request.FundingStreamId,
                                                    request.FundingLineCode,
                                                    request.ProviderType,
                                                    request.ProviderSubType))
 .ReturnsAsync(profilePattern);
        public async Task <IActionResult> ProfileBatch([FromBody] ProfileBatchRequest request)
        {
            if (!ModelState.IsValid)
            {
                return(new BadRequestObjectResult(ModelState));
            }

            return(await _calculateProfileService.ProcessProfileAllocationBatchRequest(request));
        }
        public async Task <IActionResult> ProcessProfileAllocationBatchRequest(ProfileBatchRequest profileBatchRequest)
        {
            Guard.ArgumentNotNull(profileBatchRequest, nameof(ProfileBatchRequest));

            ValidationResult validationResult = await _batchRequestValidation.ValidateAsync(profileBatchRequest);

            if (!validationResult.IsValid)
            {
                return(validationResult.AsBadRequest());
            }

            try
            {
                FundingStreamPeriodProfilePattern profilePattern = await GetProfilePattern(profileBatchRequest);

                if (profilePattern == null)
                {
                    _logger.Error("Unable to find profile pattern for FundingStream = {fundingStreamId}, FundingPeriodId={FundingPeriodId}, FundingLineCode={FundingLineCode}, ProfilePatternKey={ProfilePatternKey}, ProviderType={ProviderType}, ProviderSubType={ProviderSubType}",
                                  profileBatchRequest.FundingStreamId,
                                  profileBatchRequest.FundingPeriodId,
                                  profileBatchRequest.FundingLineCode,
                                  profileBatchRequest.ProfilePatternKey,
                                  profileBatchRequest.ProviderType,
                                  profileBatchRequest.ProviderSubType);
                }

                BatchProfileRequestContext batchProfileRequestContext = new BatchProfileRequestContext(profilePattern,
                                                                                                       profileBatchRequest,
                                                                                                       5);

                IProducerConsumer producerConsumer = _producerConsumerFactory.CreateProducerConsumer(ProduceProviderFundingValues,
                                                                                                     ProfileProviderFundingValues,
                                                                                                     10,
                                                                                                     10,
                                                                                                     _logger);

                await producerConsumer.Run(batchProfileRequestContext);

                return(new OkObjectResult(batchProfileRequestContext.Responses.ToArray()));
            }
            catch (Exception ex)
            {
                LogError(ex, profileBatchRequest);

                throw;
            }
        }
        private Task ProfileProviderFundingValues(CancellationToken token,
                                                  dynamic context,
                                                  IEnumerable <decimal> providerFundingValues)
        {
            BatchProfileRequestContext batchProfileRequestContext = (BatchProfileRequestContext)context;

            foreach (decimal providerFundingValue in providerFundingValues)
            {
                ProfileBatchRequest request = batchProfileRequestContext.Request;

                AllocationProfileResponse allocationProfileResponse = ProfileAllocation(request,
                                                                                        batchProfileRequestContext.ProfilePattern,
                                                                                        providerFundingValue);

                batchProfileRequestContext.AddResponse(
                    new BatchAllocationProfileResponse(request.GetFundingValueKey(providerFundingValue),
                                                       providerFundingValue,
                                                       allocationProfileResponse));
            }

            return(Task.CompletedTask);
        }
        public void ProfileAllocation_ShouldSetProfilePatternKeyAndDisplayNameInResponse()
        {
            string profilePatternKey         = NewRandomString();
            string profilePatternDisplayName = NewRandomString();

            ProfileBatchRequest profileRequest = NewProfileBatchRequest(_ => _.WithFundingStreamId(NewRandomString()));
            FundingStreamPeriodProfilePattern profilePattern = NewFundingStreamPeriodProfilePattern(_ =>
                                                                                                    _.WithProfilePattern()
                                                                                                    .WithProfilePatternKey(profilePatternKey)
                                                                                                    .WithProfilePatternDisplayName(profilePatternDisplayName));

            IFundingValueProfiler profiler = new FundingValueProfiler();

            AllocationProfileResponse response = profiler.ProfileAllocation(profileRequest, profilePattern, decimal.MinValue);

            response.Should()
            .NotBeNull();
            response.ProfilePatternKey
            .Should().Be(profilePatternKey);
            response.ProfilePatternDisplayName
            .Should().Be(profilePatternDisplayName);
        }
 private void GivenTheValidationResult(ProfileBatchRequest request,
                                       ValidationResult validationResult)
 => _batchRequestValidation.Setup(_ => _.ValidateAsync(request, default))
 private async Task <IActionResult> WhenTheBatchProfileRequestIsProcessed(ProfileBatchRequest profileBatchRequest)
 => await _service.ProcessProfileAllocationBatchRequest(profileBatchRequest);