Пример #1
0
        private static FundingStream GetFundingStream(SpecificationCurrentVersion specification, ProviderChangeItem providerChangeItem)
        {
            FundingStream fundingStream = specification.FundingStreams.FirstOrDefault(s => s.AllocationLines.Any(a => a.ProviderLookups.Any(l => l.ProviderType == providerChangeItem.SuccessorProvider.ProviderType && l.ProviderSubType == providerChangeItem.SuccessorProvider.ProviderSubType)));

            if (fundingStream == null)
            {
                throw new NonRetriableException($"Could not find funding stream with matching provider type '{providerChangeItem.SuccessorProvider.ProviderType}' and subtype '{providerChangeItem.SuccessorProvider.ProviderSubType}' for specification '{specification.Id}'");
            }

            return(fundingStream);
        }
Пример #2
0
        private async Task <Period> GetFundingPeriod(SpecificationCurrentVersion specification)
        {
            Period fundingPeriod = await _specificationsRepository.GetFundingPeriodById(specification.FundingPeriod.Id);

            if (fundingPeriod == null)
            {
                throw new NonRetriableException($"Failed to find a funding period for id: {specification.FundingPeriod.Id}");
            }

            return(fundingPeriod);
        }
Пример #3
0
        public async Task ReIndexAllocationNotificationFeeds_GivenPublishedProviderFoundButAllHeld_DoesNotIndexReturnsContentResult()
        {
            //Arrange
            Message message = new Message();

            IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository();

            repository
            .GetAllNonHeldPublishedProviderResults()
            .Returns(Enumerable.Empty <PublishedProviderResult>());

            ILogger logger = CreateLogger();

            ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository();

            SpecificationCurrentVersion specification = CreateSpecification(specificationId);

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetCurrentSpecificationById(Arg.Is("spec-1"))
            .Returns(specification);

            PublishedResultsService resultsService = CreateResultsService(logger, publishedProviderResultsRepository: repository,
                                                                          allocationNotificationFeedSearchRepository: searchRepository, specificationsRepository: specificationsRepository);

            //Act
            await resultsService.ReIndexAllocationNotificationFeeds(message);

            //Assert
            await
            searchRepository
            .DidNotReceive()
            .Index(Arg.Any <IEnumerable <AllocationNotificationFeedIndex> >());

            logger
            .Received(1)
            .Warning(Arg.Is("No published provider results were found to index."));

            await
            repository
            .Received(0)
            .GetAllNonHeldPublishedProviderResultVersions(Arg.Any <string>(), Arg.Any <string>());
        }
Пример #4
0
        private PublishedProviderResult CreateSuccessorResult(SpecificationCurrentVersion specification, ProviderChangeItem providerChangeItem, Reference author, Period fundingPeriod)
        {
            FundingStream fundingStream = GetFundingStream(specification, providerChangeItem);
            PublishedFundingStreamDefinition fundingStreamDefinition = _mapper.Map <PublishedFundingStreamDefinition>(fundingStream);

            AllocationLine allocationLine = fundingStream.AllocationLines.FirstOrDefault(a => a.ProviderLookups.Any(l => l.ProviderType == providerChangeItem.SuccessorProvider.ProviderType && l.ProviderSubType == providerChangeItem.SuccessorProvider.ProviderSubType));
            PublishedAllocationLineDefinition publishedAllocationLine = _mapper.Map <PublishedAllocationLineDefinition>(allocationLine);

            PublishedProviderResult successorResult = new PublishedProviderResult
            {
                FundingPeriod       = fundingPeriod,
                FundingStreamResult = new PublishedFundingStreamResult
                {
                    AllocationLineResult = new PublishedAllocationLineResult
                    {
                        AllocationLine = publishedAllocationLine,
                        Current        = new PublishedAllocationLineResultVersion
                        {
                            Author          = author,
                            Calculations    = null, // don't set calcs as result hasn't been generated from calculation run
                            Date            = DateTimeOffset.Now,
                            Provider        = providerChangeItem.SuccessorProvider,
                            ProviderId      = providerChangeItem.SuccessorProviderId,
                            SpecificationId = specification.Id,
                            Status          = AllocationLineStatus.Held,
                            Value           = 0,
                            Version         = 1
                        },
                        HasResultBeenVaried = true
                    },
                    DistributionPeriod  = $"{fundingStream.PeriodType.Id}{specification.FundingPeriod.Id}",
                    FundingStream       = fundingStreamDefinition,
                    FundingStreamPeriod = $"{fundingStream.Id}{specification.FundingPeriod.Id}"
                },
                ProviderId      = providerChangeItem.SuccessorProviderId,
                SpecificationId = specification.Id,
            };

            successorResult.FundingStreamResult.AllocationLineResult.Current.PublishedProviderResultId = successorResult.Id;

            EnsurePredecessors(successorResult, providerChangeItem.UpdatedProvider.Id);

            return(successorResult);
        }
Пример #5
0
        private (IEnumerable <ProviderVariationError> variationErrors, bool canContinue) ProcessProviderClosedWithoutSuccessor(
            ProviderChangeItem providerChange,
            AllocationLine allocationLine,
            SpecificationCurrentVersion specification,
            PublishedProviderResultExisting affectedProviderExistingResult,
            IEnumerable <PublishedProviderResult> allPublishedProviderResults,
            List <PublishedProviderResult> resultsToSave)
        {
            List <ProviderVariationError> errors = new List <ProviderVariationError>();

            _logger.Information($"Processing provider {providerChange.UpdatedProvider.Id} when closed without successor. Specification '{specification.Id}' and allocation line {allocationLine.Id}");

            if (affectedProviderExistingResult.HasResultBeenVaried)
            {
                // Don't apply variation logic to an already varied result
                _logger.Information($"Result for provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id} has already been varied. Specification '{specification.Id}'");
                return(errors, false);
            }

            // Find profiling periods after the variation date, for the affected provider
            IEnumerable <ProfilingPeriod> affectedProfilingPeriods = Enumerable.Empty <ProfilingPeriod>();

            if (!affectedProviderExistingResult.ProfilePeriods.IsNullOrEmpty())
            {
                affectedProfilingPeriods = affectedProviderExistingResult.ProfilePeriods.Where(p => p.PeriodDate > specification.VariationDate);
            }

            if (affectedProfilingPeriods.IsNullOrEmpty())
            {
                _logger.Information($"There are no affected profiling periods for the allocation line result {allocationLine.Id} and provider {providerChange.UpdatedProvider.Id}");
                return(errors, true);
            }

            // See if the affected provider has already had a result generated that needs to be saved
            PublishedProviderResult affectedResult = resultsToSave.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                  r.FundingStreamResult.AllocationLineResult.AllocationLine.Id == allocationLine.Id);

            if (affectedResult == null)
            {
                // No new result to save so copy the from the generated version to use as a base
                affectedResult = allPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                            r.FundingStreamResult.AllocationLineResult.AllocationLine.Id == allocationLine.Id);

                if (affectedResult == null)
                {
                    errors.Add(new ProviderVariationError {
                        AllocationLineId = allocationLine.Id, Error = "Could not find/create result for successor", UKPRN = providerChange.UpdatedProvider.UKPRN
                    });
                    return(errors, false);
                }

                _logger.Information($"Creating new result for affected provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id}. Specification '{specification.Id}'");
                resultsToSave.Add(affectedResult);
            }

            // Have to copy info from existing result otherwise they won't be set
            CopyPropertiesFromExisitngResult(affectedResult, affectedProviderExistingResult);

            EnsureProviderUpToDate(affectedResult, providerChange);

            decimal affectedProfilingPeriodsTotal = affectedProfilingPeriods.Sum(p => p.Value);

            // Zero out the affected profile periods in the affected provider
            foreach (ProfilingPeriod profilePeriod in affectedProfilingPeriods)
            {
                profilePeriod.Value = 0;
            }

            // Remove the amount in the affected profiling periods from the affected providers allocation total
            affectedResult.FundingStreamResult.AllocationLineResult.Current.Value -= affectedProfilingPeriodsTotal;

            // Set a flag to indicate result has been varied
            affectedResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried = true;

            return(errors, true);
        }
Пример #6
0
        public async Task <ProcessProviderVariationsResult> ProcessProviderVariations(
            JobViewModel triggeringJob,
            SpecificationCurrentVersion specification,
            IEnumerable <ProviderResult> providerResults,
            IEnumerable <PublishedProviderResultExisting> existingPublishedProviderResults,
            IEnumerable <PublishedProviderResult> allPublishedProviderResults,
            List <PublishedProviderResult> resultsToSave,
            Reference author)
        {
            Guard.ArgumentNotNull(triggeringJob, nameof(triggeringJob));
            Guard.ArgumentNotNull(specification, nameof(specification));
            Guard.ArgumentNotNull(providerResults, nameof(providerResults));
            Guard.ArgumentNotNull(existingPublishedProviderResults, nameof(existingPublishedProviderResults));
            Guard.ArgumentNotNull(allPublishedProviderResults, nameof(allPublishedProviderResults));
            Guard.ArgumentNotNull(resultsToSave, nameof(resultsToSave));
            Guard.ArgumentNotNull(author, nameof(author));

            List <ProviderVariationError>   errors = new List <ProviderVariationError>();
            ProcessProviderVariationsResult result = new ProcessProviderVariationsResult();

            // Only process on a refresh, not on choose
            if (existingPublishedProviderResults.Any())
            {
                _logger.Information($"Processing provider variations for specification '{specification.Id}' and job '{triggeringJob.Id}'");

                IEnumerable <ProviderChangeItem> providerVariations;
                try
                {
                    providerVariations = await _providerVariationAssemblerService.AssembleProviderVariationItems(providerResults, existingPublishedProviderResults, specification.Id);

                    if (providerVariations.AnyWithNullCheck(v => v.HasProviderClosed) && !specification.VariationDate.HasValue)
                    {
                        errors.Add(new ProviderVariationError {
                            Error = "Variations have been found for the scoped providers, but the specification has no variation date set"
                        });
                        result.Errors = errors;
                        return(result);
                    }

                    Period fundingPeriod = await GetFundingPeriod(specification);

                    foreach (ProviderChangeItem providerChange in providerVariations)
                    {
                        foreach (AllocationLine allocationLine in specification.FundingStreams.SelectMany(f => f.AllocationLines))
                        {
                            (IEnumerable <ProviderVariationError> variationErrors, bool canContinue)processingResult = (Enumerable.Empty <ProviderVariationError>(), true);

                            if (providerChange.HasProviderClosed && providerChange.DoesProviderHaveSuccessor)
                            {
                                // If successor has a previous result
                                PublishedProviderResultExisting successorExistingResult = null;

                                if (allocationLine.ProviderLookups.Any(p => p.ProviderType == providerChange.UpdatedProvider.ProviderType && p.ProviderSubType == providerChange.UpdatedProvider.ProviderSubType))
                                {
                                    successorExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.SuccessorProviderId);
                                }

                                if (successorExistingResult != null)
                                {
                                    processingResult = ProcessProviderClosedWithSuccessor(providerChange, allocationLine, specification, existingPublishedProviderResults, allPublishedProviderResults, resultsToSave, successorExistingResult);
                                }
                                else
                                {
                                    processingResult = ProcessProviderClosedWithSuccessor(providerChange, allocationLine, specification, existingPublishedProviderResults, allPublishedProviderResults, resultsToSave, author, fundingPeriod);
                                }
                            }
                            else if (providerChange.HasProviderClosed && !providerChange.DoesProviderHaveSuccessor)
                            {
                                // Get previous result for affected provider
                                PublishedProviderResultExisting affectedProviderExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                                                                                 r.AllocationLineId == allocationLine.Id);

                                if (affectedProviderExistingResult != null)
                                {
                                    processingResult = ProcessProviderClosedWithoutSuccessor(providerChange, allocationLine, specification, affectedProviderExistingResult, allPublishedProviderResults, resultsToSave);
                                }
                                else
                                {
                                    _logger.Information($"Provider '{providerChange.UpdatedProvider.Id}' has closed without successor but has no existing result. Specification '{specification.Id}' and allocation line '{allocationLine.Id}'");
                                }
                            }

                            errors.AddRange(processingResult.variationErrors);

                            if (!processingResult.canContinue)
                            {
                                continue;
                            }

                            if (providerChange.HasProviderDataChanged)
                            {
                                ProcessProviderDataChanged(providerChange, allocationLine, existingPublishedProviderResults, allPublishedProviderResults, resultsToSave);
                            }
                        }
                    }

                    if (!errors.Any())
                    {
                        result.ProviderChanges = providerVariations;
                    }
                }
                catch (Exception ex)
                {
                    errors.Add(new ProviderVariationError {
                        Error = ex.Message
                    });
                    result.Errors = errors;
                    return(result);
                }
            }
            else
            {
                _logger.Information($"Not processing variations for specification '{specification.Id}' as job '{triggeringJob.Id}' is not for Refresh.");
            }

            result.Errors = errors;

            return(result);
        }
Пример #7
0
        private (IEnumerable <ProviderVariationError> variationErrors, bool canContinue) ProcessProviderClosedWithSuccessor(
            ProviderChangeItem providerChange,
            AllocationLine allocationLine,
            SpecificationCurrentVersion specification,
            IEnumerable <PublishedProviderResultExisting> existingPublishedProviderResults,
            IEnumerable <PublishedProviderResult> allPublishedProviderResults,
            List <PublishedProviderResult> resultsToSave,
            Reference author,
            Period fundingPeriod)
        {
            List <ProviderVariationError> errors = new List <ProviderVariationError>();

            _logger.Information($"Processing Provider '{providerChange.UpdatedProvider.Id}' when closed with successor but has no existing result. Specifiction '{specification.Id}' and allocation line {allocationLine.Id}");

            // Get previous result for affected provider
            PublishedProviderResultExisting affectedProviderExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                                                             r.AllocationLineId == allocationLine.Id);

            if (affectedProviderExistingResult == null)
            {
                _logger.Information($"No existing result for provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id} to vary. Specification '{specification.Id}'");
                return(errors, true);
            }

            if (affectedProviderExistingResult.HasResultBeenVaried)
            {
                // Don't apply variation logic to an already varied result
                _logger.Information($"Result for provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id} has already been varied. Specification '{specification.Id}'");
                return(errors, false);
            }

            // Find profiling periods after the variation date, for the affected provider
            IEnumerable <ProfilingPeriod> affectedProfilingPeriods = Enumerable.Empty <ProfilingPeriod>();

            if (!affectedProviderExistingResult.ProfilePeriods.IsNullOrEmpty())
            {
                affectedProfilingPeriods = affectedProviderExistingResult.ProfilePeriods.Where(p => p.PeriodDate > specification.VariationDate);
            }

            if (affectedProfilingPeriods.IsNullOrEmpty())
            {
                _logger.Information($"There are no affected profiling periods for the allocation line result {allocationLine.Id} and provider {providerChange.UpdatedProvider.Id}");
                return(errors, true);
            }

            // Check for an existing result for the successor
            IEnumerable <PublishedProviderResult> successorResults = resultsToSave.Where(r => r.ProviderId == providerChange.SuccessorProviderId);

            PublishedProviderResult successorResult = null;

            // Find existing result which is in the same funding stream as current allocation line (spec may have multiple) and which matches the provider type and subtype
            if (successorResults.Any())
            {
                foreach (PublishedProviderResult existingResult in successorResults)
                {
                    foreach (FundingStream fundingStream in specification.FundingStreams)
                    {
                        if (fundingStream.AllocationLines.Any(a => a.Id == allocationLine.Id))
                        {
                            foreach (AllocationLine fsAllocationLine in fundingStream.AllocationLines)
                            {
                                if (fsAllocationLine.ProviderLookups.AnyWithNullCheck(p => p.ProviderType == providerChange.SuccessorProvider.ProviderType && p.ProviderSubType == providerChange.SuccessorProvider.ProviderSubType))
                                {
                                    successorResult = existingResult;
                                    break;
                                }
                            }

                            if (successorResult != null)
                            {
                                break;
                            }
                        }
                    }

                    if (successorResult != null)
                    {
                        break;
                    }
                }
            }

            if (successorResult == null)
            {
                // If no new result for the successor then create one
                successorResult = CreateSuccessorResult(specification, providerChange, author, fundingPeriod);

                _logger.Information($"Creating new result for successor provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id}. Specification '{specification.Id}'");
                resultsToSave.Add(successorResult);
            }

            // Copy info from existing result otherwise they won't be set
            successorResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods   = MergeProfilingPeriods(successorResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods, affectedProviderExistingResult.ProfilePeriods);
            successorResult.FundingStreamResult.AllocationLineResult.Current.FinancialEnvelopes = MergeFinancialEnvelopes(successorResult.FundingStreamResult.AllocationLineResult.Current.FinancialEnvelopes, affectedProviderExistingResult.FinancialEnvelopes);

            decimal affectedProfilingPeriodsTotal = affectedProfilingPeriods.Sum(p => p.Value);

            // As we have moved all the periods from the affected result to the successor result we need to zero out the unaffected profile periods
            IEnumerable <ProfilingPeriod> unaffectedProfilingPeriods = affectedProviderExistingResult.ProfilePeriods.Except(affectedProfilingPeriods);

            foreach (ProfilingPeriod profilePeriod in unaffectedProfilingPeriods)
            {
                ProfilingPeriod successorProfilePeriod = successorResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods.FirstOrDefault(p => p.Period == profilePeriod.Period && p.Year == profilePeriod.Year && p.Type == profilePeriod.Type);

                // Zero the unaffected profile period
                successorProfilePeriod.Value = 0;
            }

            // Set the allocation total to the sum of the affected profiling periods
            successorResult.FundingStreamResult.AllocationLineResult.Current.Value += affectedProfilingPeriodsTotal;

            // Set a flag to indicate successor result has been varied
            successorResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried = true;

            // See if the affected provider has already had a result generated that needs to be saved
            PublishedProviderResult affectedResult = resultsToSave.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                  r.FundingStreamResult.AllocationLineResult.AllocationLine.Id == allocationLine.Id);

            if (affectedResult == null)
            {
                // No new result to save so copy the from the generated version to use as a base
                affectedResult = allPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                            r.FundingStreamResult.AllocationLineResult.AllocationLine.Id == allocationLine.Id);

                if (affectedResult == null)
                {
                    errors.Add(new ProviderVariationError {
                        AllocationLineId = allocationLine.Id, Error = "Could not find/create result for affected provider", UKPRN = providerChange.UpdatedProvider.UKPRN
                    });
                    return(errors, false);
                }

                _logger.Information($"Creating new result for affected provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id}. Specification '{specification.Id}'");
                resultsToSave.Add(affectedResult);
            }

            // Have to copy info from existing result otherwise they won't be set
            CopyPropertiesFromExisitngResult(affectedResult, affectedProviderExistingResult);

            EnsureProviderUpToDate(affectedResult, providerChange);

            // Zero out the affected profile periods in the affected provider
            foreach (ProfilingPeriod profilePeriod in affectedProfilingPeriods)
            {
                profilePeriod.Value = 0;
            }

            // Remove the amount in the affected profiling periods from the affected providers allocation total
            affectedResult.FundingStreamResult.AllocationLineResult.Current.Value -= affectedProfilingPeriodsTotal;

            // Set a flag to indicate result has been varied
            affectedResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried = true;

            // Ensure the predecessor information is added to the successor
            EnsurePredecessors(successorResult, providerChange.UpdatedProvider.UKPRN);

            return(errors, true);
        }
Пример #8
0
        private (IEnumerable <ProviderVariationError> variationErrors, bool canContinue) ProcessProviderClosedWithSuccessor(
            ProviderChangeItem providerChange,
            AllocationLine allocationLine,
            SpecificationCurrentVersion specification,
            IEnumerable <PublishedProviderResultExisting> existingPublishedProviderResults,
            IEnumerable <PublishedProviderResult> allPublishedProviderResults,
            List <PublishedProviderResult> resultsToSave,
            PublishedProviderResultExisting successorExistingResult)
        {
            List <ProviderVariationError> errors = new List <ProviderVariationError>();

            _logger.Information($"Processing provider {providerChange.UpdatedProvider.Id} when closed with successor. Specification '{specification.Id}' and allocation line {allocationLine.Id}");

            // Get previous result for affected provider
            PublishedProviderResultExisting affectedProviderExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                                                             r.AllocationLineId == allocationLine.Id);

            if (affectedProviderExistingResult == null)
            {
                _logger.Information($"No existing result for provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id} to vary. Specification '{specification.Id}'");
                return(errors, true);
            }

            if (affectedProviderExistingResult.HasResultBeenVaried)
            {
                // Don't apply variation logic to an already varied result
                _logger.Information($"Result for provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id} has already been varied. Specification '{specification.Id}'");
                return(errors, false);
            }

            // Find profiling periods after the variation date, for the affected provider
            IEnumerable <ProfilingPeriod> affectedProfilingPeriods = Enumerable.Empty <ProfilingPeriod>();

            if (!affectedProviderExistingResult.ProfilePeriods.IsNullOrEmpty())
            {
                affectedProfilingPeriods = affectedProviderExistingResult.ProfilePeriods.Where(p => p.PeriodDate > specification.VariationDate);
            }

            if (affectedProfilingPeriods.IsNullOrEmpty())
            {
                _logger.Information($"There are no affected profiling periods for the allocation line result {allocationLine.Id} and provider {providerChange.UpdatedProvider.Id}");
                return(errors, true);
            }

            // See if the successor has already had a result generated that needs to be saved
            PublishedProviderResult successorResult = resultsToSave.FirstOrDefault(r => r.ProviderId == providerChange.SuccessorProviderId &&
                                                                                   (allocationLine.ProviderLookups != null &&
                                                                                    allocationLine.ProviderLookups.Any(p => p.ProviderType == providerChange.UpdatedProvider.ProviderType && p.ProviderSubType == providerChange.UpdatedProvider.ProviderSubType)));

            if (successorResult == null)
            {
                // If no new result for the successor so copy from the generated list as a base
                successorResult = allPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.SuccessorProviderId &&
                                                                             (allocationLine.ProviderLookups != null &&
                                                                              allocationLine.ProviderLookups.Any(p => p.ProviderType == providerChange.UpdatedProvider.ProviderType && p.ProviderSubType == providerChange.UpdatedProvider.ProviderSubType)));

                if (successorResult == null)
                {
                    _logger.Information($"Could not find result for successor provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id} to update. Specification '{specification.Id}'");
                    errors.Add(new ProviderVariationError {
                        UKPRN = providerChange.UpdatedProvider.UKPRN, Error = "Could not find/create result for successor", AllocationLineId = allocationLine.Id
                    });
                    return(errors, false);
                }

                _logger.Information($"Creating new result for successor provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id}. Specification '{specification.Id}'");
                resultsToSave.Add(successorResult);
            }

            // Have to copy info from existing result otherwise they won't be set
            CopyPropertiesFromExisitngResult(successorResult, successorExistingResult);

            EnsurePredecessors(successorResult, affectedProviderExistingResult.ProviderId);

            decimal affectedProfilingPeriodsTotal = affectedProfilingPeriods.Sum(p => p.Value);

            // Move the values from each affected profiling periods from the affected provider to the successor
            foreach (ProfilingPeriod profilePeriod in affectedProfilingPeriods)
            {
                ProfilingPeriod successorProfilePeriod = successorResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods.FirstOrDefault(p => p.Period == profilePeriod.Period && p.Year == profilePeriod.Year && p.Type == profilePeriod.Type);

                if (successorProfilePeriod == null)
                {
                    _logger.Information($"Creating new profile for successor provider {providerChange.SuccessorProviderId}. Specification '{specification.Id}' and allocation line {allocationLine.Id}");

                    successorProfilePeriod = new Models.Results.ProfilingPeriod
                    {
                        DistributionPeriod = profilePeriod.DistributionPeriod,
                        Occurrence         = profilePeriod.Occurrence,
                        Period             = profilePeriod.Period,
                        Type = profilePeriod.Type,
                        Year = profilePeriod.Year
                    };

                    List <ProfilingPeriod> tempPeriods = new List <ProfilingPeriod>(successorResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods);
                    tempPeriods.AddRange(new[] { successorProfilePeriod });
                    successorResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = tempPeriods;
                }

                // Add the value from the affected profile to the matching successor profile
                successorProfilePeriod.Value += profilePeriod.Value;
            }

            // Add the amount in the affected profiling periods to the successors allocation total
            successorResult.FundingStreamResult.AllocationLineResult.Current.Value += affectedProfilingPeriodsTotal;

            // Set a flag to indicate successor result has been varied
            successorResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried = true;

            // See if the affected provider has already had a result generated that needs to be saved
            PublishedProviderResult affectedResult = resultsToSave.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                  r.FundingStreamResult.AllocationLineResult.AllocationLine.Id == allocationLine.Id);

            if (affectedResult == null)
            {
                // No new result to save so copy the from the generated version to use as a base
                affectedResult = allPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                            r.FundingStreamResult.AllocationLineResult.AllocationLine.Id == allocationLine.Id);

                if (affectedResult == null)
                {
                    errors.Add(new ProviderVariationError {
                        AllocationLineId = allocationLine.Id, Error = "Could not find/create result for successor", UKPRN = providerChange.UpdatedProvider.UKPRN
                    });
                    return(errors, false);
                }

                _logger.Information($"Creating new result for affected provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id}. Specification '{specification.Id}'");
                resultsToSave.Add(affectedResult);
            }

            // Have to copy info from existing result otherwise they won't be set
            CopyPropertiesFromExisitngResult(affectedResult, affectedProviderExistingResult);

            EnsureProviderUpToDate(affectedResult, providerChange);

            // Zero out the affected profile periods in the affected provider
            foreach (ProfilingPeriod profilePeriod in affectedProfilingPeriods)
            {
                profilePeriod.Value = 0;
            }

            // Remove the amount in the affected profiling periods from the affected providers allocation total
            affectedResult.FundingStreamResult.AllocationLineResult.Current.Value -= affectedProfilingPeriodsTotal;

            // Set a flag to indicate result has been varied
            affectedResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried = true;

            // Ensure the predecessor information is added to the successor
            EnsurePredecessors(successorResult, providerChange.UpdatedProvider.UKPRN);

            return(errors, true);
        }
Пример #9
0
        public async Task ReIndexAllocationNotificationFeeds_GivenPublishedProviderFoundButUpdatingIndexThrowsException_ReturnsInternalServerError()
        {
            //Arrange
            Message message = new Message();

            IEnumerable <PublishedProviderResult> results = CreatePublishedProviderResultsWithDifferentProviders();

            foreach (PublishedProviderResult result in results)
            {
                result.FundingStreamResult.AllocationLineResult.Current.Status           = AllocationLineStatus.Approved;
                result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = new[] { new ProfilingPeriod() };
            }

            IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository();

            repository
            .GetAllNonHeldPublishedProviderResults()
            .Returns(results);

            IEnumerable <PublishedAllocationLineResultVersion> history = CreatePublishedProviderResultsWithDifferentProviders()
                                                                         .Select(m => m.FundingStreamResult.AllocationLineResult.Current);

            history.ElementAt(1).Status = AllocationLineStatus.Approved;
            history.ElementAt(1).Status = AllocationLineStatus.Published;

            foreach (var providerVersion in history.GroupBy(c => c.PublishedProviderResultId))
            {
                if (providerVersion.Any())
                {
                    IEnumerable <PublishedAllocationLineResultVersion> providerHistory = providerVersion.AsEnumerable();

                    string providerId = providerHistory.First().ProviderId;

                    providerId
                    .Should()
                    .NotBeNullOrWhiteSpace();

                    repository
                    .GetAllNonHeldPublishedProviderResultVersions(Arg.Is(providerVersion.Key), Arg.Is(providerId))
                    .Returns(providerHistory);
                }
            }

            ILogger logger = CreateLogger();

            ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository();

            searchRepository.When(x => x.Index(Arg.Any <IEnumerable <AllocationNotificationFeedIndex> >()))
            .Do(x => { throw new Exception("Error indexing"); });

            SpecificationCurrentVersion specification = CreateSpecification("spec-1");

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetCurrentSpecificationById(Arg.Is("spec-1"))
            .Returns(specification);

            PublishedResultsService resultsService = CreateResultsService(
                logger,
                publishedProviderResultsRepository: repository,
                allocationNotificationFeedSearchRepository: searchRepository,
                specificationsRepository: specificationsRepository);

            //Act
            Func <Task> test = async() => await resultsService.ReIndexAllocationNotificationFeeds(message);

            //Assert
            test
            .Should()
            .ThrowExactly <RetriableException>();

            logger
            .Received()
            .Error(Arg.Any <Exception>(), Arg.Is("Failed to index allocation feeds"));

            await
            repository
            .Received(3)
            .GetAllNonHeldPublishedProviderResultVersions(Arg.Any <string>(), Arg.Any <string>());
        }
Пример #10
0
        public async Task ReIndexAllocationNotificationFeeds_GivenPublishedProviderFoundAndMajorMinorFeatureToggleIsEnabledAndIsAllAllocationResultsVersionsInFeedIndexEnabled_IndexesAndReturnsNoContentResult()
        {
            //Arrange
            int     major   = 2;
            int     minor   = 7;
            Message message = new Message();

            const string specificationId = "spec-1";

            IEnumerable <PublishedProviderResult> results = CreatePublishedProviderResultsWithDifferentProviders();

            foreach (PublishedProviderResult result in results)
            {
                result.FundingStreamResult.AllocationLineResult.Current.Status           = AllocationLineStatus.Approved;
                result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = new[] { new ProfilingPeriod() };
                result.FundingStreamResult.AllocationLineResult.Current.Major            = major;
                result.FundingStreamResult.AllocationLineResult.Current.Minor            = minor;
                result.FundingStreamResult.AllocationLineResult.Current.FeedIndexId      = "feed-index-id";
            }

            IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository();

            repository
            .GetAllNonHeldPublishedProviderResults()
            .Returns(results);

            ILogger logger = CreateLogger();

            IEnumerable <PublishedAllocationLineResultVersion> history = results.Select(m => m.FundingStreamResult.AllocationLineResult.Current);

            history.ElementAt(0).Status = AllocationLineStatus.Approved;

            foreach (var providerVersion in history.GroupBy(c => c.PublishedProviderResultId))
            {
                if (providerVersion.Any())
                {
                    IEnumerable <PublishedAllocationLineResultVersion> providerHistory = providerVersion.AsEnumerable();

                    string providerId = providerHistory.First().ProviderId;

                    providerId
                    .Should()
                    .NotBeNullOrWhiteSpace();

                    repository
                    .GetAllNonHeldPublishedProviderResultVersions(Arg.Is(providerVersion.Key), Arg.Is(providerId))
                    .Returns(providerHistory);
                }
            }

            ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository();

            SpecificationCurrentVersion specification = CreateSpecification(specificationId);

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetCurrentSpecificationById(Arg.Is("spec-1"))
            .Returns(specification);

            IEnumerable <AllocationNotificationFeedIndex> resultsBeingSaved = null;
            await searchRepository.Index(Arg.Do <IEnumerable <AllocationNotificationFeedIndex> >(r => resultsBeingSaved = r));

            PublishedResultsService resultsService = CreateResultsService(
                logger,
                publishedProviderResultsRepository: repository,
                allocationNotificationFeedSearchRepository: searchRepository,
                specificationsRepository: specificationsRepository);

            //Act
            await resultsService.ReIndexAllocationNotificationFeeds(message);

            //Assert
            await
            searchRepository
            .Received(1)
            .Index(Arg.Is <IEnumerable <AllocationNotificationFeedIndex> >(m => m.Count() == 3));

            AllocationNotificationFeedIndex feedResult = resultsBeingSaved.FirstOrDefault(m => m.ProviderId == "1111");

            feedResult.ProviderId.Should().Be("1111");
            feedResult.Title.Should().Be("Allocation test allocation line 1 was Approved");
            feedResult.Summary.Should().Be($"UKPRN: 1111, version {major}.{minor}");
            feedResult.DatePublished.HasValue.Should().Be(false);
            feedResult.FundingStreamId.Should().Be("fs-1");
            feedResult.FundingStreamName.Should().Be("funding stream 1");
            feedResult.FundingPeriodId.Should().Be("1819");
            feedResult.ProviderUkPrn.Should().Be("1111");
            feedResult.ProviderUpin.Should().Be("2222");
            feedResult.AllocationLineId.Should().Be("AAAAA");
            feedResult.AllocationLineName.Should().Be("test allocation line 1");
            feedResult.AllocationVersionNumber.Should().Be(1);
            feedResult.AllocationAmount.Should().Be(50.0);
            feedResult.ProviderProfiling.Should().Be("[{\"period\":null,\"occurrence\":0,\"periodYear\":0,\"periodType\":null,\"profileValue\":0.0,\"distributionPeriod\":null}]");
            feedResult.ProviderName.Should().Be("test provider name 1");
            feedResult.LaCode.Should().Be("77777");
            feedResult.Authority.Should().Be("London");
            feedResult.ProviderType.Should().Be("test type");
            feedResult.SubProviderType.Should().Be("test sub type");
            feedResult.EstablishmentNumber.Should().Be("es123");
            feedResult.FundingPeriodStartYear.Should().Be(DateTime.Now.Year);
            feedResult.FundingPeriodEndYear.Should().Be(DateTime.Now.Year + 1);
            feedResult.FundingStreamStartDay.Should().Be(1);
            feedResult.FundingStreamStartMonth.Should().Be(8);
            feedResult.FundingStreamEndDay.Should().Be(31);
            feedResult.FundingStreamEndMonth.Should().Be(7);
            feedResult.FundingStreamPeriodName.Should().Be("period-type 1");
            feedResult.FundingStreamPeriodId.Should().Be("pt1");
            feedResult.AllocationLineContractRequired.Should().Be(true);
            feedResult.AllocationLineFundingRoute.Should().Be("LA");
            feedResult.MajorVersion.Should().Be(major);
            feedResult.MinorVersion.Should().Be(minor);
        }
Пример #11
0
        public async Task ReIndexAllocationNotificationFeeds_GivenResultHasProviderDataChange_AndHasNotBeenVariedInAnyOtherWay_IndexesAndReturnsNoContentResult()
        {
            //Arrange
            Message message = new Message();

            const string specificationId = "spec-1";

            IEnumerable <PublishedProviderResult> results = CreatePublishedProviderResultsWithDifferentProviders();

            foreach (PublishedProviderResult result in results)
            {
                result.FundingStreamResult.AllocationLineResult.Current.Status             = AllocationLineStatus.Approved;
                result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods   = new[] { new ProfilingPeriod() };
                result.FundingStreamResult.AllocationLineResult.Current.FinancialEnvelopes = new[] { new FinancialEnvelope() };
                result.FundingStreamResult.AllocationLineResult.Current.Calculations       = new[]
                {
                    new PublishedProviderCalculationResult {
                        CalculationSpecification = new Common.Models.Reference("calc-id-1", "calc1"), Policy = new PolicySummary("policy-id-1", "policy1", "desc")
                    },
                    new PublishedProviderCalculationResult {
                        CalculationSpecification = new Common.Models.Reference("calc-id-2", "calc2"), Policy = new PolicySummary("policy-id-1", "policy1", "desc")
                    },
                    new PublishedProviderCalculationResult {
                        CalculationSpecification = new Common.Models.Reference("calc-id-3", "calc3"), Policy = new PolicySummary("policy-id-2", "policy2", "desc")
                    },
                };
            }

            PublishedAllocationLineResult publishedAllocationLineResult = results.First().FundingStreamResult.AllocationLineResult;

            publishedAllocationLineResult.HasResultBeenVaried      = false;
            publishedAllocationLineResult.Current.VariationReasons = new[] { VariationReason.AuthorityFieldUpdated, VariationReason.NameFieldUpdated };

            IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository();

            repository
            .GetAllNonHeldPublishedProviderResults()
            .Returns(results);

            IEnumerable <PublishedAllocationLineResultVersion> history = results.Select(m => m.FundingStreamResult.AllocationLineResult.Current);

            history.ElementAt(0).Status = AllocationLineStatus.Approved;
            history.ElementAt(1).Status = AllocationLineStatus.Approved;
            history.ElementAt(2).Status = AllocationLineStatus.Published;

            foreach (var providerVersion in history.GroupBy(c => c.PublishedProviderResultId))
            {
                if (providerVersion.Any())
                {
                    IEnumerable <PublishedAllocationLineResultVersion> providerHistory = providerVersion.AsEnumerable();

                    string providerId = providerHistory.First().ProviderId;

                    providerId
                    .Should()
                    .NotBeNullOrWhiteSpace();

                    repository
                    .GetAllNonHeldPublishedProviderResultVersions(Arg.Is(providerVersion.Key), Arg.Is(providerId))
                    .Returns(providerHistory);
                }
            }

            ILogger logger = CreateLogger();

            ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository();

            SpecificationCurrentVersion specification = CreateSpecification(specificationId);

            ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository();

            specificationsRepository
            .GetCurrentSpecificationById(Arg.Is(specificationId))
            .Returns(specification);

            IEnumerable <AllocationNotificationFeedIndex> resultsBeingSaved = null;
            await searchRepository
            .Index(Arg.Do <IEnumerable <AllocationNotificationFeedIndex> >(r => resultsBeingSaved = r));

            PublishedResultsService resultsService = CreateResultsService(
                logger,
                publishedProviderResultsRepository: repository,
                allocationNotificationFeedSearchRepository: searchRepository,
                specificationsRepository: specificationsRepository);

            //Act
            await resultsService.ReIndexAllocationNotificationFeeds(message);

            //Assert
            await
            searchRepository
            .Received(1)
            .Index(Arg.Is <IEnumerable <AllocationNotificationFeedIndex> >(m => m.Count() == 3));

            AllocationNotificationFeedIndex feedResult = resultsBeingSaved.FirstOrDefault(m => m.ProviderId == "1111");

            feedResult.ProviderId.Should().Be("1111");
            feedResult.Title.Should().Be("Allocation test allocation line 1 was Approved");
            feedResult.Summary.Should().Be("UKPRN: 1111, version 0.1");
            feedResult.DatePublished.HasValue.Should().Be(false);
            feedResult.FundingStreamId.Should().Be("fs-1");
            feedResult.FundingStreamName.Should().Be("funding stream 1");
            feedResult.FundingPeriodId.Should().Be("1819");
            feedResult.ProviderUkPrn.Should().Be("1111");
            feedResult.ProviderUpin.Should().Be("2222");
            feedResult.AllocationLineId.Should().Be("AAAAA");
            feedResult.AllocationLineName.Should().Be("test allocation line 1");
            feedResult.AllocationVersionNumber.Should().Be(1);
            feedResult.AllocationAmount.Should().Be(50.0);
            feedResult.ProviderProfiling.Should().Be("[{\"period\":null,\"occurrence\":0,\"periodYear\":0,\"periodType\":null,\"profileValue\":0.0,\"distributionPeriod\":null}]");
            feedResult.ProviderName.Should().Be("test provider name 1");
            feedResult.LaCode.Should().Be("77777");
            feedResult.Authority.Should().Be("London");
            feedResult.ProviderType.Should().Be("test type");
            feedResult.SubProviderType.Should().Be("test sub type");
            feedResult.EstablishmentNumber.Should().Be("es123");
            feedResult.FundingPeriodStartYear.Should().Be(DateTime.Now.Year);
            feedResult.FundingPeriodEndYear.Should().Be(DateTime.Now.Year + 1);
            feedResult.FundingStreamStartDay.Should().Be(1);
            feedResult.FundingStreamStartMonth.Should().Be(8);
            feedResult.FundingStreamEndDay.Should().Be(31);
            feedResult.FundingStreamEndMonth.Should().Be(7);
            feedResult.FundingStreamPeriodName.Should().Be("period-type 1");
            feedResult.FundingStreamPeriodId.Should().Be("pt1");
            feedResult.AllocationLineContractRequired.Should().Be(true);
            feedResult.AllocationLineFundingRoute.Should().Be("LA");
            feedResult.AllocationLineShortName.Should().Be("tal1");
            feedResult.PolicySummaries.Should().Be("[{\"policy\":{\"description\":\"test decscription\",\"parentPolicyId\":null,\"id\":\"policy-1\",\"name\":\"policy one\"},\"policies\":[{\"policy\":{\"description\":\"test decscription\",\"parentPolicyId\":null,\"id\":\"subpolicy-1\",\"name\":\"sub policy one\"},\"policies\":[],\"calculations\":[]}],\"calculations\":[]}]");
            feedResult.Calculations.Should().Be("[{\"calculationName\":\"calc1\",\"calculationDisplayName\":\"calc1\",\"calculationVersion\":0,\"calculationType\":\"Number\",\"calculationAmount\":null,\"allocationLineId\":\"AAAAA\",\"policyId\":\"policy-id-1\",\"policyName\":\"policy1\"},{\"calculationName\":\"calc2\",\"calculationDisplayName\":\"calc2\",\"calculationVersion\":0,\"calculationType\":\"Number\",\"calculationAmount\":null,\"allocationLineId\":\"AAAAA\",\"policyId\":\"policy-id-1\",\"policyName\":\"policy1\"},{\"calculationName\":\"calc3\",\"calculationDisplayName\":\"calc3\",\"calculationVersion\":0,\"calculationType\":\"Number\",\"calculationAmount\":null,\"allocationLineId\":\"AAAAA\",\"policyId\":\"policy-id-2\",\"policyName\":\"policy2\"}]");
            feedResult.OpenReason.Should().BeNull();
            feedResult.CloseReason.Should().BeNull();
            feedResult.Predecessors.Should().BeNull();
            feedResult.Successors.Should().BeNull();
        }
        public async Task <IEnumerable <PublishedProviderResult> > AssemblePublishedProviderResults(IEnumerable <ProviderResult> providerResults, Reference author, SpecificationCurrentVersion specificationCurrentVersion)
        {
            Guard.ArgumentNotNull(providerResults, nameof(providerResults));
            Guard.ArgumentNotNull(author, nameof(author));
            Guard.ArgumentNotNull(specificationCurrentVersion, nameof(specificationCurrentVersion));

            string specificationId = specificationCurrentVersion.Id;

            Period fundingPeriod = await _specificationsRepository.GetFundingPeriodById(specificationCurrentVersion.FundingPeriod.Id);

            if (fundingPeriod == null)
            {
                throw new NonRetriableException($"Failed to find a funding period for id: {specificationCurrentVersion.FundingPeriod.Id}");
            }

            IEnumerable <string> providerIds = providerResults.Select(m => m.Provider.Id);

            ConcurrentBag <PublishedProviderResult> publishedProviderResults = new ConcurrentBag <PublishedProviderResult>();

            IEnumerable <FundingStream> allFundingStreams = await GetAllFundingStreams();

            Parallel.ForEach(providerResults, (providerResult) =>
            {
                IEnumerable <PublishedFundingStreamResult> publishedFundingStreamResults = AssembleFundingStreamResults(providerResult, specificationCurrentVersion, author, allFundingStreams);

                foreach (PublishedFundingStreamResult publishedFundingStreamResult in publishedFundingStreamResults)
                {
                    PublishedProviderResult publishedProviderResult = new PublishedProviderResult
                    {
                        ProviderId          = providerResult.Provider.Id,
                        SpecificationId     = specificationId,
                        FundingStreamResult = publishedFundingStreamResult,
                        FundingPeriod       = fundingPeriod,
                    };

                    publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.PublishedProviderResultId = publishedProviderResult.Id;

                    publishedProviderResults.Add(publishedProviderResult);
                }
            });

            return(publishedProviderResults);
        }
        private IEnumerable <PublishedFundingStreamResult> AssembleFundingStreamResults(ProviderResult providerResult, SpecificationCurrentVersion specificationCurrentVersion, Reference author, IEnumerable <FundingStream> allFundingStreams)
        {
            IList <PublishedFundingStreamResult> publishedFundingStreamResults = new List <PublishedFundingStreamResult>();

            Dictionary <string, PublishedAllocationLineDefinition> publishedAllocationLines = new Dictionary <string, PublishedAllocationLineDefinition>();

            foreach (Reference fundingStreamReference in specificationCurrentVersion.FundingStreams)
            {
                FundingStream fundingStream = allFundingStreams.FirstOrDefault(m => m.Id == fundingStreamReference.Id);

                if (fundingStream == null)
                {
                    throw new NonRetriableException($"Failed to find a funding stream for id: {fundingStreamReference.Id}");
                }

                PublishedFundingStreamDefinition publishedFundingStreamDefinition = _mapper.Map <PublishedFundingStreamDefinition>(fundingStream);

                List <PublishedProviderCalculationResult> publishedProviderCalculationResults = new List <PublishedProviderCalculationResult>(providerResult.CalculationResults.Count());

                foreach (CalculationResult calculationResult in providerResult.CalculationResults)
                {
                    (Policy policy, Policy parentPolicy, Calculation calculation) = FindPolicy(calculationResult.CalculationSpecification?.Id, specificationCurrentVersion.Policies);

                    if (calculation == null)
                    {
                        throw new NonRetriableException($"Calculation specification not found in specification. Calculation Spec Id ='{calculationResult?.CalculationSpecification?.Id}'");
                    }

                    if (calculation.CalculationType == CalculationType.Number && !calculation.IsPublic)
                    {
                        continue;
                    }

                    PublishedProviderCalculationResult publishedProviderCalculationResult = new PublishedProviderCalculationResult()
                    {
                        CalculationSpecification = calculationResult.CalculationSpecification,
                        AllocationLine           = calculationResult.AllocationLine,
                        IsPublic           = calculation.IsPublic,
                        CalculationType    = ConvertCalculationType(calculationResult.CalculationType),
                        Value              = calculationResult.Value,
                        CalculationVersion = calculationResult.Version
                    };

                    if (policy != null)
                    {
                        publishedProviderCalculationResult.Policy = new PolicySummary(policy.Id, policy.Name, policy.Description);
                    }

                    if (parentPolicy != null)
                    {
                        publishedProviderCalculationResult.ParentPolicy = new PolicySummary(parentPolicy.Id, parentPolicy.Name, parentPolicy.Description);
                    }

                    publishedProviderCalculationResults.Add(publishedProviderCalculationResult);
                }

                IEnumerable <IGrouping <string, CalculationResult> > allocationLineGroups = providerResult
                                                                                            .CalculationResults
                                                                                            .Where(c => c.CalculationType == Models.Calcs.CalculationType.Funding && c.Value.HasValue && c.AllocationLine != null && !string.IsNullOrWhiteSpace(c.AllocationLine.Id))
                                                                                            .GroupBy(m => m.AllocationLine.Id);

                foreach (IGrouping <string, CalculationResult> allocationLineResultGroup in allocationLineGroups)
                {
                    PublishedAllocationLineDefinition publishedAllocationLine;
                    if (!publishedAllocationLines.TryGetValue(allocationLineResultGroup.Key, out publishedAllocationLine))
                    {
                        AllocationLine allocationLine = fundingStream.AllocationLines.FirstOrDefault(m => m.Id == allocationLineResultGroup.Key);
                        if (allocationLine != null)
                        {
                            publishedAllocationLine = _mapper.Map <PublishedAllocationLineDefinition>(allocationLine);
                            publishedAllocationLines.Add(allocationLineResultGroup.Key, publishedAllocationLine);
                        }
                    }

                    if (publishedAllocationLine != null)
                    {
                        PublishedFundingStreamResult publishedFundingStreamResult = new PublishedFundingStreamResult
                        {
                            FundingStream = publishedFundingStreamDefinition,

                            FundingStreamPeriod = $"{fundingStream.Id}{specificationCurrentVersion.FundingPeriod.Id}",

                            DistributionPeriod = $"{fundingStream.PeriodType.Id}{specificationCurrentVersion.FundingPeriod.Id}"
                        };

                        PublishedAllocationLineResultVersion publishedAllocationLineResultVersion = new PublishedAllocationLineResultVersion
                        {
                            Author          = author,
                            Date            = DateTimeOffset.Now,
                            Status          = AllocationLineStatus.Held,
                            Value           = allocationLineResultGroup.Sum(m => m.Value),
                            Provider        = providerResult.Provider,
                            SpecificationId = specificationCurrentVersion.Id,
                            ProviderId      = providerResult.Provider.Id,
                            Calculations    = publishedProviderCalculationResults.Where(c => c.AllocationLine == null || string.Equals(c.AllocationLine.Id, publishedAllocationLine.Id, StringComparison.InvariantCultureIgnoreCase)),
                        };

                        publishedFundingStreamResult.AllocationLineResult = new PublishedAllocationLineResult
                        {
                            AllocationLine = publishedAllocationLine,
                            Current        = publishedAllocationLineResultVersion
                        };

                        publishedFundingStreamResults.Add(publishedFundingStreamResult);
                    }
                }
            }

            return(publishedFundingStreamResults);
        }
Пример #14
0
 private bool ValidateCalculation(string argument, SpecificationCurrentVersion specification)
 {
     return(specification.GetCalculations().SingleOrDefault(x => x.Name == argument) != null);
 }
Пример #15
0
        public IEnumerable <GherkinError> Validate(Step step, SpecificationCurrentVersion specification,
                                                   List <DefinitionSpecificationRelationship> dataRelationships,
                                                   List <DatasetDefinition> dataDefinitions)
        {
            foreach (var stepAction in StepsAction)
            {
                var stepDefinition = stepAction.GetCustomAttribute <TestStepAttribute>();
                if (stepDefinition.Keyword == step.Keyword?.Trim().ToLowerInvariant())
                {
                    if (Regex.IsMatch(step.Text, stepDefinition.Regex))
                    {
                        var arguments     = Regex.Split(step.Text, stepDefinition.Regex).Skip(1).ToArray();
                        var instance      = Activator.CreateInstance(stepAction) as GherkinStepAction;
                        var propertyInfos = stepAction.GetProperties()
                                            .Where(x => x.GetCustomAttribute <TestStepArgumentAttribute>() != null).ToArray();

                        string datasetName = null;
                        string fieldName   = null;

                        for (var index = 0; index < propertyInfos.Length; index++)
                        {
                            var propertyInfo       = propertyInfos[index];
                            var argument           = arguments[index];
                            var argumentDefinition = propertyInfo.GetCustomAttribute <TestStepArgumentAttribute>();
                            switch (argumentDefinition.Type)
                            {
                            case StepArgumentType.DatasetName:
                                datasetName = argument;
                                if (!ValidateField(argument, fieldName, dataRelationships, dataDefinitions))
                                {
                                    yield return(new GherkinError($"'{argument} is not a valid dataset name'", step.Location.Line, step.Location.Column));

                                    propertyInfo.SetValue(instance, argument);
                                }
                                break;

                            case StepArgumentType.FieldName:
                                fieldName = argument;
                                if (!ValidateField(datasetName, argument, dataRelationships, dataDefinitions))
                                {
                                    yield return(new GherkinError($"'{argument} is not a valid field name in {datasetName}'", step.Location.Line, step.Location.Column));

                                    propertyInfo.SetValue(instance, argument);
                                }
                                break;

                            case StepArgumentType.CalculationName:
                                if (!ValidateCalculation(argument, specification))
                                {
                                    yield return(new GherkinError($"'{argument} is not a valid calculation name'", step.Location.Line, step.Location.Column));

                                    propertyInfo.SetValue(instance, argument);
                                }

                                break;
                            }
                        }
                    }
                }
            }
        }