public void GetAllocationByAllocationResultId_GivenResultFoundButNoHeaders_ReturnsBadRequest()
        {
            //Arrange
            string allocationResultId = "12345";

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            PublishedProviderResult publishedProviderResult = CreatePublishedProviderResult();

            IPublishedResultsService resultsService = CreateResultsService();

            resultsService
            .GetPublishedProviderResultByVersionId(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            AllocationsService service = CreateService(resultsService);

            //Act
            IActionResult result = service.GetAllocationByAllocationResultId(allocationResultId, request);

            //Assert
            result
            .Should()
            .BeOfType <BadRequestResult>();
        }
Ejemplo n.º 2
0
        public async Task GetPublishedProviderResultWithHistoryByAllocationResultId_GivenResultFoundButNoHistory_ResturnsNull()
        {
            //Arrange
            string allocationResultId = "12345";

            string query = $"select c from c where c.documentType = 'PublishedAllocationLineResultVersion' and c.deleted = false and c.content.entityId = '{allocationResultId}'";

            PublishedProviderResult publishedProviderResult = new PublishedProviderResult {
                ProviderId = "1111"
            };

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultForIdInPublishedState(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            IVersionRepository <PublishedAllocationLineResultVersion> versionRepository = CreatePublishedProviderResultsVersionRepository();

            versionRepository
            .GetVersions(Arg.Is(query), Arg.Is("1111"))
            .Returns((IEnumerable <PublishedAllocationLineResultVersion>)null);

            PublishedResultsService service = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository, publishedProviderResultsVersionRepository: versionRepository);

            //Act
            PublishedProviderResultWithHistory result = await service.GetPublishedProviderResultWithHistoryByAllocationResultId(allocationResultId);

            //Assert
            result
            .Should()
            .BeNull();
        }
        public void GetPublishedProviderResultByVersionId_GivenVersionFoundButResultCanbnotBeFound_ReturnsNull()
        {
            //Arrange
            string id       = "id-1";
            string entityId = "entity-id-1";

            PublishedAllocationLineResultVersion version = new PublishedAllocationLineResultVersion
            {
                PublishedProviderResultId = entityId,
                FeedIndexId = id
            };

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultVersionForFeedIndexId(Arg.Is(id))
            .Returns(version);

            publishedProviderResultsRepository
            .GetPublishedProviderResultForId(Arg.Is(entityId))
            .Returns((PublishedProviderResult)null);

            PublishedResultsService publishedResultsService = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository);

            //Act
            PublishedProviderResult result = publishedResultsService.GetPublishedProviderResultByVersionId(id);

            //Assert
            result
            .Should()
            .BeNull();
        }
Ejemplo n.º 4
0
        public void GetAllocationByAllocationResultId_GivenResultFound_ReturnsContentResult()
        {
            //Arrange
            string allocationResultId = "12345";

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary.Add("Accept", new StringValues("application/json"));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            PublishedProviderResult publishedProviderResult = CreatePublishedProviderResult();

            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.FeedIndexId = allocationResultId;

            IPublishedResultsService resultsService = CreateResultsService();

            resultsService
            .GetPublishedProviderResultByVersionId(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            AllocationsService service = CreateService(resultsService);

            //Act
            IActionResult result = service.GetAllocationByAllocationResultId(allocationResultId, request);

            //Assert
            result
            .Should()
            .BeOfType <ContentResult>();

            ContentResult contentResult = result as ContentResult;

            AllocationModel allocationModel = JsonConvert.DeserializeObject <AllocationModel>(contentResult.Content);

            allocationModel
            .Should()
            .NotBeNull();

            allocationModel.AllocationResultId.Should().Be(allocationResultId);
            allocationModel.AllocationStatus.Should().Be("Published");
            allocationModel.AllocationAmount.Should().Be(50);
            allocationModel.FundingStream.Id.Should().Be("fs-1");
            allocationModel.FundingStream.Name.Should().Be("funding stream 1");
            allocationModel.Period.Id.Should().Be("Ay12345");
            allocationModel.Provider.UkPrn.Should().Be("1111");
            allocationModel.Provider.Upin.Should().Be("2222");
            allocationModel.Provider.OpenDate.Should().NotBeNull();
            allocationModel.AllocationLine.Id.Should().Be("AAAAA");
            allocationModel.AllocationLine.Name.Should().Be("test allocation line 1");
            allocationModel.ProfilePeriods.Should().HaveCount(1);

            AssertProviderVariationValuesNotSet(allocationModel.Provider.ProviderVariation);
        }
        public async Task GetPublishedProviderResultByAllocationResultId_GivenVersionAndFoundInHistory_ReturnsResult()
        {
            //Arrange
            string allocationResultId = "12345";

            int version = 5;

            PublishedProviderResult publishedProviderResult = new PublishedProviderResult
            {
                FundingStreamResult = new PublishedFundingStreamResult
                {
                    AllocationLineResult = new PublishedAllocationLineResult
                    {
                        Current = new PublishedAllocationLineResultVersion {
                            Version = 2
                        }
                    }
                }
            };

            PublishedAllocationLineResultVersion publishedAllocationLineResultVersion = new PublishedAllocationLineResultVersion
            {
                Version = 5
            };

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultForIdInPublishedState(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            IVersionRepository <PublishedAllocationLineResultVersion> versionRepository = CreatePublishedProviderResultsVersionRepository();

            versionRepository
            .GetVersion(Arg.Is(allocationResultId), Arg.Is(version))
            .Returns(publishedAllocationLineResultVersion);

            PublishedResultsService service = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository, publishedProviderResultsVersionRepository: versionRepository);

            //Act
            PublishedProviderResult result = await service.GetPublishedProviderResultByAllocationResultId(allocationResultId, version);

            //Assert
            result
            .Should()
            .NotBeNull();

            result
            .FundingStreamResult
            .AllocationLineResult
            .Current
            .Version
            .Should()
            .Be(5);
        }
Ejemplo n.º 6
0
        public async Task GetPublishedProviderResultWithHistoryByAllocationResultId_GivenResultAndHistory_ResturnsResult()
        {
            //Arrange
            string allocationResultId = "12345";

            PublishedProviderResult publishedProviderResult = new PublishedProviderResult
            {
                ProviderId          = "1111",
                FundingStreamResult = new PublishedFundingStreamResult
                {
                    AllocationLineResult = new PublishedAllocationLineResult {
                    }
                }
            };

            IEnumerable <PublishedAllocationLineResultVersion> history = new[]
            {
                new PublishedAllocationLineResultVersion(),
                new PublishedAllocationLineResultVersion(),
                new PublishedAllocationLineResultVersion()
            };

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultForIdInPublishedState(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            IVersionRepository <PublishedAllocationLineResultVersion> versionRepository = CreatePublishedProviderResultsVersionRepository();

            versionRepository
            .GetVersions(Arg.Is(allocationResultId), Arg.Is("1111"))
            .Returns(history);

            PublishedResultsService service = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository, publishedProviderResultsVersionRepository: versionRepository);

            //Act
            PublishedProviderResultWithHistory result = await service.GetPublishedProviderResultWithHistoryByAllocationResultId(allocationResultId);

            //Assert
            result
            .Should()
            .NotBeNull();

            result
            .PublishedProviderResult
            .Should()
            .NotBeNull();

            result
            .History
            .Count()
            .Should()
            .Be(3);
        }
Ejemplo n.º 7
0
        private void EnsurePredecessors(PublishedProviderResult successorResult, string affectedProviderId)
        {
            if (successorResult.FundingStreamResult.AllocationLineResult.Current.Predecessors == null)
            {
                successorResult.FundingStreamResult.AllocationLineResult.Current.Predecessors = new List <string>();
            }

            if (!successorResult.FundingStreamResult.AllocationLineResult.Current.Predecessors.Contains(affectedProviderId))
            {
                ((List <string>)successorResult.FundingStreamResult.AllocationLineResult.Current.Predecessors).Add(affectedProviderId);
            }
        }
Ejemplo n.º 8
0
        public void GetAllocationByAllocationResultId_GivenMajorMinorFeatureToggleOn_ReturnsMajorMinorVersions()
        {
            //Arrange
            string allocationResultId = "12345";

            IHeaderDictionary headerDictionary = new HeaderDictionary
            {
                { "Accept", new StringValues("application/json") }
            };

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            PublishedProviderResult publishedProviderResult = CreatePublishedProviderResult();

            IPublishedResultsService resultsService = CreateResultsService();

            resultsService
            .GetPublishedProviderResultByVersionId(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            AllocationsService service = CreateService(resultsService);

            //Act
            IActionResult result = service.GetAllocationByAllocationResultId(allocationResultId, request);

            //Assert
            result
            .Should()
            .BeOfType <ContentResult>();

            ContentResult contentResult = result as ContentResult;

            string id = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{publishedProviderResult.SpecificationId}{publishedProviderResult.ProviderId}{publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.Id}"));

            AllocationModel allocationModel = JsonConvert.DeserializeObject <AllocationModel>(contentResult.Content);

            allocationModel
            .Should()
            .NotBeNull();

            allocationModel.AllocationMajorVersion.Should().Be(1);
            allocationModel.AllocationMinorVersion.Should().Be(1);

            AssertProviderVariationValuesNotSet(allocationModel.Provider.ProviderVariation);
        }
Ejemplo n.º 9
0
        public IActionResult GetAllocationByAllocationResultId(string allocationResultId, HttpRequest httpRequest)
        {
            Guard.IsNullOrWhiteSpace(allocationResultId, nameof(allocationResultId));
            Guard.ArgumentNotNull(httpRequest, nameof(httpRequest));

            PublishedProviderResult publishedProviderResult = _publishedResultsService.GetPublishedProviderResultByVersionId(allocationResultId);

            if (publishedProviderResult == null)
            {
                return(new NotFoundResult());
            }

            AllocationModel allocation = CreateAllocation(publishedProviderResult);

            return(Formatter.ActionResult <AllocationModel>(httpRequest, allocation));
        }
        public void GetPublishedProviderResultByVersionId_GivenResultFound_ReturnsResult()
        {
            //Arrange
            string id       = "id-1";
            string entityId = "entity-id-1";

            PublishedAllocationLineResultVersion version = new PublishedAllocationLineResultVersion
            {
                PublishedProviderResultId = entityId,
                FeedIndexId = id
            };

            PublishedProviderResult publishedProviderResult = new PublishedProviderResult
            {
                FundingStreamResult = new PublishedFundingStreamResult
                {
                    AllocationLineResult = new PublishedAllocationLineResult()
                }
            };

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultVersionForFeedIndexId(Arg.Is(id))
            .Returns(version);

            publishedProviderResultsRepository
            .GetPublishedProviderResultForId(Arg.Is(entityId))
            .Returns(publishedProviderResult);

            PublishedResultsService publishedResultsService = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository);

            //Act
            PublishedProviderResult result = publishedResultsService.GetPublishedProviderResultByVersionId(id);

            //Assert
            result
            .Should()
            .NotBeNull();

            result
            .FundingStreamResult
            .AllocationLineResult
            .Current
            .Should()
            .Be(version);
        }
Ejemplo n.º 11
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);
        }
        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);
        }
        public async Task GetPublishedProviderResultByAllocationResultId_GivenVersionSuppliedButAlreadyCurrent_ReturnsResultDoesNotFetchHistory()
        {
            //Arrange
            string allocationResultId = "12345";

            int version = 1;

            PublishedProviderResult publishedProviderResult = new PublishedProviderResult
            {
                FundingStreamResult = new PublishedFundingStreamResult
                {
                    AllocationLineResult = new PublishedAllocationLineResult
                    {
                        Current = new PublishedAllocationLineResultVersion {
                            Version = version
                        }
                    }
                }
            };

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultForIdInPublishedState(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            IVersionRepository <PublishedAllocationLineResultVersion> versionRepository = CreatePublishedProviderResultsVersionRepository();

            PublishedResultsService service = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository, publishedProviderResultsVersionRepository: versionRepository);

            //Act
            PublishedProviderResult result = await service.GetPublishedProviderResultByAllocationResultId(allocationResultId, version);

            //Assert
            result
            .Should()
            .NotBeNull();

            await
            versionRepository
            .DidNotReceive()
            .GetVersion(Arg.Any <string>(), Arg.Any <int>());
        }
Ejemplo n.º 14
0
        private void CopyPropertiesFromExisitngResult(PublishedProviderResult result, PublishedProviderResultExisting existingResult)
        {
            result.FundingStreamResult.AllocationLineResult.Current.Version = existingResult.Version + 1;

            result.FundingStreamResult.AllocationLineResult.Current.Major = existingResult.Major;
            result.FundingStreamResult.AllocationLineResult.Current.Minor = existingResult.Minor;

            result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods   = existingResult.ProfilePeriods.ToArray();
            result.FundingStreamResult.AllocationLineResult.Current.FinancialEnvelopes = existingResult.FinancialEnvelopes;

            if (existingResult.Status != AllocationLineStatus.Held)
            {
                result.FundingStreamResult.AllocationLineResult.Current.Status = AllocationLineStatus.Updated;
            }

            if (existingResult.Published != null)
            {
                result.FundingStreamResult.AllocationLineResult.Published = existingResult.Published;
            }
        }
        public async Task GetPublishedProviderResultByAllocationResultId_GivenResultNotFound_ResturnsNull()
        {
            //Arrange
            string allocationResultId = "12345";

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultForIdInPublishedState(Arg.Is(allocationResultId))
            .Returns((PublishedProviderResult)null);

            PublishedResultsService service = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository);

            //Act
            PublishedProviderResult result = await service.GetPublishedProviderResultByAllocationResultId(allocationResultId);

            //Assert
            result
            .Should()
            .BeNull();
        }
        public void GetPublishedProviderResultByVersionId_GivenVersionCannotBeFound_ReturnsNull()
        {
            //Arrange
            string id = "id-1";

            IPublishedProviderResultsRepository publishedProviderResultsRepository = CreatePublishedProviderResultsRepository();

            publishedProviderResultsRepository
            .GetPublishedProviderResultVersionForFeedIndexId(Arg.Is(id))
            .Returns((PublishedAllocationLineResultVersion)null);

            PublishedResultsService publishedResultsService = CreateResultsService(publishedProviderResultsRepository: publishedProviderResultsRepository);

            //Act
            PublishedProviderResult result = publishedResultsService.GetPublishedProviderResultByVersionId(id);

            //Assert
            result
            .Should()
            .BeNull();
        }
Ejemplo n.º 17
0
        private void ProcessProviderDataChanged(
            ProviderChangeItem providerChange,
            AllocationLine allocationLine,
            IEnumerable <PublishedProviderResultExisting> existingPublishedProviderResults,
            IEnumerable <PublishedProviderResult> allPublishedProviderResults,
            List <PublishedProviderResult> resultsToSave)
        {
            // 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)
            {
                // Get previous result for affected provider
                PublishedProviderResultExisting affectedProviderExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id &&
                                                                                                                                 r.AllocationLineId == allocationLine.Id);

                if (affectedProviderExistingResult != 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);
                    CopyPropertiesFromExisitngResult(affectedResult, affectedProviderExistingResult);

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

            // If still no result to save then there is nothing to update
            if (affectedResult != null)
            {
                _logger.Information($"Processing data update for provider {providerChange.UpdatedProvider.Id} and allocation line {allocationLine.Id}. Specification '{affectedResult.SpecificationId}'");

                affectedResult.FundingStreamResult.AllocationLineResult.Current.Provider         = providerChange.UpdatedProvider;
                affectedResult.FundingStreamResult.AllocationLineResult.Current.VariationReasons = providerChange.VariationReasons;
            }
        }
Ejemplo n.º 18
0
 private void EnsureProviderUpToDate(PublishedProviderResult affectedResult, ProviderChangeItem providerChangeItem)
 {
     affectedResult.FundingStreamResult.AllocationLineResult.Current.Provider = providerChangeItem.UpdatedProvider;
 }
Ejemplo n.º 19
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);
        }
Ejemplo n.º 20
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);
        }
Ejemplo n.º 21
0
        public void GetAllocationByAllocationResultId_GivenResultHasVariation_ReturnsContentResult()
        {
            //Arrange
            string allocationResultId = "12345";

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary.Add("Accept", new StringValues("application/json"));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            PublishedProviderResult publishedProviderResult = CreatePublishedProviderResult();

            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.FeedIndexId        = allocationResultId;
            publishedProviderResult.FundingStreamResult.AllocationLineResult.HasResultBeenVaried        = true;
            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.VariationReasons   = new[] { VariationReason.LegalNameFieldUpdated, VariationReason.LACodeFieldUpdated };
            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.Successor = "provider3";
            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Predecessors       = new[] { "provider1", "provider2" };
            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.ReasonEstablishmentOpened = "Fresh Start";
            publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.ReasonEstablishmentClosed = "Closure";


            IPublishedResultsService resultsService = CreateResultsService();

            resultsService
            .GetPublishedProviderResultByVersionId(Arg.Is(allocationResultId))
            .Returns(publishedProviderResult);

            AllocationsService service = CreateService(resultsService);

            //Act
            IActionResult result = service.GetAllocationByAllocationResultId(allocationResultId, request);

            //Assert
            result
            .Should()
            .BeOfType <ContentResult>();

            ContentResult contentResult = result as ContentResult;

            AllocationModel allocationModel = JsonConvert.DeserializeObject <AllocationModel>(contentResult.Content);

            allocationModel
            .Should()
            .NotBeNull();

            allocationModel.AllocationResultId.Should().Be(allocationResultId);
            allocationModel.AllocationStatus.Should().Be("Published");
            allocationModel.AllocationAmount.Should().Be(50);
            allocationModel.FundingStream.Id.Should().Be("fs-1");
            allocationModel.FundingStream.Name.Should().Be("funding stream 1");
            allocationModel.Period.Id.Should().Be("Ay12345");
            allocationModel.Provider.UkPrn.Should().Be("1111");
            allocationModel.Provider.Upin.Should().Be("2222");
            allocationModel.Provider.OpenDate.Should().NotBeNull();
            allocationModel.AllocationLine.Id.Should().Be("AAAAA");
            allocationModel.AllocationLine.Name.Should().Be("test allocation line 1");
            allocationModel.ProfilePeriods.Should().HaveCount(1);

            ProviderVariation providerVariationModel = allocationModel.Provider.ProviderVariation;

            providerVariationModel.Should().NotBeNull();
            providerVariationModel.VariationReasons.Should().BeEquivalentTo("LegalNameFieldUpdated", "LACodeFieldUpdated");
            providerVariationModel.Successors.First().Ukprn.Should().Be("provider3");
            providerVariationModel.Predecessors.First().Ukprn.Should().Be("provider1");
            providerVariationModel.Predecessors[1].Ukprn.Should().Be("provider2");
            providerVariationModel.OpenReason.Should().Be("Fresh Start");
            providerVariationModel.CloseReason.Should().Be("Closure");
        }
Ejemplo n.º 22
0
        AllocationModel CreateAllocation(PublishedProviderResult publishedProviderResult)
        {
            ProviderVariation providerVariation = new ProviderVariation();

            PublishedAllocationLineResult allocationLineResult = publishedProviderResult.FundingStreamResult.AllocationLineResult;

            if (!allocationLineResult.Current.VariationReasons.IsNullOrEmpty())
            {
                providerVariation.VariationReasons = new Collection <string>(allocationLineResult.Current.VariationReasons.Select(vr => vr.ToString()).ToList());
            }

            if (allocationLineResult.Current.Provider.Successor != null)
            {
                providerVariation.Successors = new Collection <ProviderInformationModel> {
                    new ProviderInformationModel()
                    {
                        Ukprn = allocationLineResult.Current.Provider.Successor
                    }
                };
            }

            if (!allocationLineResult.Current.Predecessors.IsNullOrEmpty())
            {
                List <ProviderInformationModel> providerModelsForPredecessor = allocationLineResult.Current.Predecessors.Select(fi => new ProviderInformationModel()
                {
                    Ukprn = fi
                }).ToList();
                providerVariation.Predecessors = new Collection <ProviderInformationModel>(providerModelsForPredecessor);
            }

            providerVariation.OpenReason  = allocationLineResult.Current.Provider.ReasonEstablishmentOpened;
            providerVariation.CloseReason = allocationLineResult.Current.Provider.ReasonEstablishmentClosed;

            return(new AllocationModel
            {
                AllocationResultTitle = $"Allocation {publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.Name} was {publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Status}",
                AllocationResultId = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.FeedIndexId,
                AllocationAmount = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Value.HasValue
                    ? publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Value.Value
                    : 0,
                AllocationMajorVersion = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Major,
                AllocationMinorVersion = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Minor,
                AllocationLine = new AllocationLine
                {
                    Id = publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.Id,
                    Name = publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.Name,
                    ShortName = publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.ShortName,
                    FundingRoute = publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.FundingRoute.ToString(),
                    ContractRequired = publishedProviderResult.FundingStreamResult.AllocationLineResult.AllocationLine.IsContractRequired
                        ? "Y"
                        : "N"
                },
                AllocationStatus = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Status.ToString(),
                FundingStream = new AllocationFundingStreamModel
                {
                    Id = publishedProviderResult.FundingStreamResult.FundingStream.Id,
                    Name = publishedProviderResult.FundingStreamResult.FundingStream.Name,
                    ShortName = publishedProviderResult.FundingStreamResult.FundingStream.ShortName,
                    PeriodType = new AllocationFundingStreamPeriodTypeModel
                    {
                        Id = publishedProviderResult.FundingStreamResult.FundingStream.PeriodType.Id,
                        Name = publishedProviderResult.FundingStreamResult.FundingStream.PeriodType.Id,
                        StartDay = publishedProviderResult.FundingStreamResult.FundingStream.PeriodType.StartDay,
                        StartMonth = publishedProviderResult.FundingStreamResult.FundingStream.PeriodType.StartMonth,
                        EndDay = publishedProviderResult.FundingStreamResult.FundingStream.PeriodType.EndDay,
                        EndMonth = publishedProviderResult.FundingStreamResult.FundingStream.PeriodType.EndMonth,
                    }
                },
                Period = new Period
                {
                    Id = publishedProviderResult.FundingPeriod.Id,
                    Name = publishedProviderResult.FundingPeriod.Name,
                    StartYear = publishedProviderResult.FundingPeriod.StartYear,
                    EndYear = publishedProviderResult.FundingPeriod.EndYear
                },
                Provider = new AllocationProviderModel
                {
                    Name = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.Name,
                    LegalName = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.LegalName,
                    UkPrn = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.UKPRN,
                    Upin = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.UPIN,
                    Urn = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.URN,
                    DfeEstablishmentNumber = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.DfeEstablishmentNumber,
                    EstablishmentNumber = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.EstablishmentNumber,
                    LaCode = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.LACode,
                    LocalAuthority = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.Authority,
                    Type = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.ProviderType,
                    SubType = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.ProviderSubType,
                    OpenDate = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.DateOpened,
                    CloseDate = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.DateClosed,
                    CrmAccountId = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.CrmAccountId,
                    NavVendorNo = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.NavVendorNo,
                    Status = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.Status,
                    ProviderId = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.Provider.Id,
                    ProviderVariation = providerVariation
                },
                ProfilePeriods = publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods != null
                    ? new List <ProfilePeriod>(publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods
                                               .Select(m => new ProfilePeriod
                {
                    DistributionPeriod = m.DistributionPeriod,
                    Occurrence = m.Occurrence,
                    Period = m.Period,
                    PeriodType = m.Type,
                    PeriodYear = m.Year.ToString(),
                    ProfileValue = m.Value
                })
                                               .ToArraySafe())
                    : new List <ProfilePeriod>(),
            });
        }
Ejemplo n.º 23
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);
        }