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>(); }
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(); }
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); }
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); }
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); } }
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); }
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); }
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>()); }
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(); }
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; } }
private void EnsureProviderUpToDate(PublishedProviderResult affectedResult, ProviderChangeItem providerChangeItem) { affectedResult.FundingStreamResult.AllocationLineResult.Current.Provider = providerChangeItem.UpdatedProvider; }
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); }
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); }
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"); }
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>(), }); }
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); }