private static FundingStream GetFundingStream(SpecificationCurrentVersion specification, ProviderChangeItem providerChangeItem) { FundingStream fundingStream = specification.FundingStreams.FirstOrDefault(s => s.AllocationLines.Any(a => a.ProviderLookups.Any(l => l.ProviderType == providerChangeItem.SuccessorProvider.ProviderType && l.ProviderSubType == providerChangeItem.SuccessorProvider.ProviderSubType))); if (fundingStream == null) { throw new NonRetriableException($"Could not find funding stream with matching provider type '{providerChangeItem.SuccessorProvider.ProviderType}' and subtype '{providerChangeItem.SuccessorProvider.ProviderSubType}' for specification '{specification.Id}'"); } return(fundingStream); }
private async Task <Period> GetFundingPeriod(SpecificationCurrentVersion specification) { Period fundingPeriod = await _specificationsRepository.GetFundingPeriodById(specification.FundingPeriod.Id); if (fundingPeriod == null) { throw new NonRetriableException($"Failed to find a funding period for id: {specification.FundingPeriod.Id}"); } return(fundingPeriod); }
public async Task ReIndexAllocationNotificationFeeds_GivenPublishedProviderFoundButAllHeld_DoesNotIndexReturnsContentResult() { //Arrange Message message = new Message(); IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository(); repository .GetAllNonHeldPublishedProviderResults() .Returns(Enumerable.Empty <PublishedProviderResult>()); ILogger logger = CreateLogger(); ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository(); SpecificationCurrentVersion specification = CreateSpecification(specificationId); ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository(); specificationsRepository .GetCurrentSpecificationById(Arg.Is("spec-1")) .Returns(specification); PublishedResultsService resultsService = CreateResultsService(logger, publishedProviderResultsRepository: repository, allocationNotificationFeedSearchRepository: searchRepository, specificationsRepository: specificationsRepository); //Act await resultsService.ReIndexAllocationNotificationFeeds(message); //Assert await searchRepository .DidNotReceive() .Index(Arg.Any <IEnumerable <AllocationNotificationFeedIndex> >()); logger .Received(1) .Warning(Arg.Is("No published provider results were found to index.")); await repository .Received(0) .GetAllNonHeldPublishedProviderResultVersions(Arg.Any <string>(), Arg.Any <string>()); }
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); }
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); }
public async Task <ProcessProviderVariationsResult> ProcessProviderVariations( JobViewModel triggeringJob, SpecificationCurrentVersion specification, IEnumerable <ProviderResult> providerResults, IEnumerable <PublishedProviderResultExisting> existingPublishedProviderResults, IEnumerable <PublishedProviderResult> allPublishedProviderResults, List <PublishedProviderResult> resultsToSave, Reference author) { Guard.ArgumentNotNull(triggeringJob, nameof(triggeringJob)); Guard.ArgumentNotNull(specification, nameof(specification)); Guard.ArgumentNotNull(providerResults, nameof(providerResults)); Guard.ArgumentNotNull(existingPublishedProviderResults, nameof(existingPublishedProviderResults)); Guard.ArgumentNotNull(allPublishedProviderResults, nameof(allPublishedProviderResults)); Guard.ArgumentNotNull(resultsToSave, nameof(resultsToSave)); Guard.ArgumentNotNull(author, nameof(author)); List <ProviderVariationError> errors = new List <ProviderVariationError>(); ProcessProviderVariationsResult result = new ProcessProviderVariationsResult(); // Only process on a refresh, not on choose if (existingPublishedProviderResults.Any()) { _logger.Information($"Processing provider variations for specification '{specification.Id}' and job '{triggeringJob.Id}'"); IEnumerable <ProviderChangeItem> providerVariations; try { providerVariations = await _providerVariationAssemblerService.AssembleProviderVariationItems(providerResults, existingPublishedProviderResults, specification.Id); if (providerVariations.AnyWithNullCheck(v => v.HasProviderClosed) && !specification.VariationDate.HasValue) { errors.Add(new ProviderVariationError { Error = "Variations have been found for the scoped providers, but the specification has no variation date set" }); result.Errors = errors; return(result); } Period fundingPeriod = await GetFundingPeriod(specification); foreach (ProviderChangeItem providerChange in providerVariations) { foreach (AllocationLine allocationLine in specification.FundingStreams.SelectMany(f => f.AllocationLines)) { (IEnumerable <ProviderVariationError> variationErrors, bool canContinue)processingResult = (Enumerable.Empty <ProviderVariationError>(), true); if (providerChange.HasProviderClosed && providerChange.DoesProviderHaveSuccessor) { // If successor has a previous result PublishedProviderResultExisting successorExistingResult = null; if (allocationLine.ProviderLookups.Any(p => p.ProviderType == providerChange.UpdatedProvider.ProviderType && p.ProviderSubType == providerChange.UpdatedProvider.ProviderSubType)) { successorExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.SuccessorProviderId); } if (successorExistingResult != null) { processingResult = ProcessProviderClosedWithSuccessor(providerChange, allocationLine, specification, existingPublishedProviderResults, allPublishedProviderResults, resultsToSave, successorExistingResult); } else { processingResult = ProcessProviderClosedWithSuccessor(providerChange, allocationLine, specification, existingPublishedProviderResults, allPublishedProviderResults, resultsToSave, author, fundingPeriod); } } else if (providerChange.HasProviderClosed && !providerChange.DoesProviderHaveSuccessor) { // Get previous result for affected provider PublishedProviderResultExisting affectedProviderExistingResult = existingPublishedProviderResults.FirstOrDefault(r => r.ProviderId == providerChange.UpdatedProvider.Id && r.AllocationLineId == allocationLine.Id); if (affectedProviderExistingResult != null) { processingResult = ProcessProviderClosedWithoutSuccessor(providerChange, allocationLine, specification, affectedProviderExistingResult, allPublishedProviderResults, resultsToSave); } else { _logger.Information($"Provider '{providerChange.UpdatedProvider.Id}' has closed without successor but has no existing result. Specification '{specification.Id}' and allocation line '{allocationLine.Id}'"); } } errors.AddRange(processingResult.variationErrors); if (!processingResult.canContinue) { continue; } if (providerChange.HasProviderDataChanged) { ProcessProviderDataChanged(providerChange, allocationLine, existingPublishedProviderResults, allPublishedProviderResults, resultsToSave); } } } if (!errors.Any()) { result.ProviderChanges = providerVariations; } } catch (Exception ex) { errors.Add(new ProviderVariationError { Error = ex.Message }); result.Errors = errors; return(result); } } else { _logger.Information($"Not processing variations for specification '{specification.Id}' as job '{triggeringJob.Id}' is not for Refresh."); } result.Errors = errors; return(result); }
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); }
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 async Task ReIndexAllocationNotificationFeeds_GivenPublishedProviderFoundButUpdatingIndexThrowsException_ReturnsInternalServerError() { //Arrange Message message = new Message(); IEnumerable <PublishedProviderResult> results = CreatePublishedProviderResultsWithDifferentProviders(); foreach (PublishedProviderResult result in results) { result.FundingStreamResult.AllocationLineResult.Current.Status = AllocationLineStatus.Approved; result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = new[] { new ProfilingPeriod() }; } IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository(); repository .GetAllNonHeldPublishedProviderResults() .Returns(results); IEnumerable <PublishedAllocationLineResultVersion> history = CreatePublishedProviderResultsWithDifferentProviders() .Select(m => m.FundingStreamResult.AllocationLineResult.Current); history.ElementAt(1).Status = AllocationLineStatus.Approved; history.ElementAt(1).Status = AllocationLineStatus.Published; foreach (var providerVersion in history.GroupBy(c => c.PublishedProviderResultId)) { if (providerVersion.Any()) { IEnumerable <PublishedAllocationLineResultVersion> providerHistory = providerVersion.AsEnumerable(); string providerId = providerHistory.First().ProviderId; providerId .Should() .NotBeNullOrWhiteSpace(); repository .GetAllNonHeldPublishedProviderResultVersions(Arg.Is(providerVersion.Key), Arg.Is(providerId)) .Returns(providerHistory); } } ILogger logger = CreateLogger(); ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository(); searchRepository.When(x => x.Index(Arg.Any <IEnumerable <AllocationNotificationFeedIndex> >())) .Do(x => { throw new Exception("Error indexing"); }); SpecificationCurrentVersion specification = CreateSpecification("spec-1"); ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository(); specificationsRepository .GetCurrentSpecificationById(Arg.Is("spec-1")) .Returns(specification); PublishedResultsService resultsService = CreateResultsService( logger, publishedProviderResultsRepository: repository, allocationNotificationFeedSearchRepository: searchRepository, specificationsRepository: specificationsRepository); //Act Func <Task> test = async() => await resultsService.ReIndexAllocationNotificationFeeds(message); //Assert test .Should() .ThrowExactly <RetriableException>(); logger .Received() .Error(Arg.Any <Exception>(), Arg.Is("Failed to index allocation feeds")); await repository .Received(3) .GetAllNonHeldPublishedProviderResultVersions(Arg.Any <string>(), Arg.Any <string>()); }
public async Task ReIndexAllocationNotificationFeeds_GivenPublishedProviderFoundAndMajorMinorFeatureToggleIsEnabledAndIsAllAllocationResultsVersionsInFeedIndexEnabled_IndexesAndReturnsNoContentResult() { //Arrange int major = 2; int minor = 7; Message message = new Message(); const string specificationId = "spec-1"; IEnumerable <PublishedProviderResult> results = CreatePublishedProviderResultsWithDifferentProviders(); foreach (PublishedProviderResult result in results) { result.FundingStreamResult.AllocationLineResult.Current.Status = AllocationLineStatus.Approved; result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = new[] { new ProfilingPeriod() }; result.FundingStreamResult.AllocationLineResult.Current.Major = major; result.FundingStreamResult.AllocationLineResult.Current.Minor = minor; result.FundingStreamResult.AllocationLineResult.Current.FeedIndexId = "feed-index-id"; } IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository(); repository .GetAllNonHeldPublishedProviderResults() .Returns(results); ILogger logger = CreateLogger(); IEnumerable <PublishedAllocationLineResultVersion> history = results.Select(m => m.FundingStreamResult.AllocationLineResult.Current); history.ElementAt(0).Status = AllocationLineStatus.Approved; foreach (var providerVersion in history.GroupBy(c => c.PublishedProviderResultId)) { if (providerVersion.Any()) { IEnumerable <PublishedAllocationLineResultVersion> providerHistory = providerVersion.AsEnumerable(); string providerId = providerHistory.First().ProviderId; providerId .Should() .NotBeNullOrWhiteSpace(); repository .GetAllNonHeldPublishedProviderResultVersions(Arg.Is(providerVersion.Key), Arg.Is(providerId)) .Returns(providerHistory); } } ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository(); SpecificationCurrentVersion specification = CreateSpecification(specificationId); ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository(); specificationsRepository .GetCurrentSpecificationById(Arg.Is("spec-1")) .Returns(specification); IEnumerable <AllocationNotificationFeedIndex> resultsBeingSaved = null; await searchRepository.Index(Arg.Do <IEnumerable <AllocationNotificationFeedIndex> >(r => resultsBeingSaved = r)); PublishedResultsService resultsService = CreateResultsService( logger, publishedProviderResultsRepository: repository, allocationNotificationFeedSearchRepository: searchRepository, specificationsRepository: specificationsRepository); //Act await resultsService.ReIndexAllocationNotificationFeeds(message); //Assert await searchRepository .Received(1) .Index(Arg.Is <IEnumerable <AllocationNotificationFeedIndex> >(m => m.Count() == 3)); AllocationNotificationFeedIndex feedResult = resultsBeingSaved.FirstOrDefault(m => m.ProviderId == "1111"); feedResult.ProviderId.Should().Be("1111"); feedResult.Title.Should().Be("Allocation test allocation line 1 was Approved"); feedResult.Summary.Should().Be($"UKPRN: 1111, version {major}.{minor}"); feedResult.DatePublished.HasValue.Should().Be(false); feedResult.FundingStreamId.Should().Be("fs-1"); feedResult.FundingStreamName.Should().Be("funding stream 1"); feedResult.FundingPeriodId.Should().Be("1819"); feedResult.ProviderUkPrn.Should().Be("1111"); feedResult.ProviderUpin.Should().Be("2222"); feedResult.AllocationLineId.Should().Be("AAAAA"); feedResult.AllocationLineName.Should().Be("test allocation line 1"); feedResult.AllocationVersionNumber.Should().Be(1); feedResult.AllocationAmount.Should().Be(50.0); feedResult.ProviderProfiling.Should().Be("[{\"period\":null,\"occurrence\":0,\"periodYear\":0,\"periodType\":null,\"profileValue\":0.0,\"distributionPeriod\":null}]"); feedResult.ProviderName.Should().Be("test provider name 1"); feedResult.LaCode.Should().Be("77777"); feedResult.Authority.Should().Be("London"); feedResult.ProviderType.Should().Be("test type"); feedResult.SubProviderType.Should().Be("test sub type"); feedResult.EstablishmentNumber.Should().Be("es123"); feedResult.FundingPeriodStartYear.Should().Be(DateTime.Now.Year); feedResult.FundingPeriodEndYear.Should().Be(DateTime.Now.Year + 1); feedResult.FundingStreamStartDay.Should().Be(1); feedResult.FundingStreamStartMonth.Should().Be(8); feedResult.FundingStreamEndDay.Should().Be(31); feedResult.FundingStreamEndMonth.Should().Be(7); feedResult.FundingStreamPeriodName.Should().Be("period-type 1"); feedResult.FundingStreamPeriodId.Should().Be("pt1"); feedResult.AllocationLineContractRequired.Should().Be(true); feedResult.AllocationLineFundingRoute.Should().Be("LA"); feedResult.MajorVersion.Should().Be(major); feedResult.MinorVersion.Should().Be(minor); }
public async Task ReIndexAllocationNotificationFeeds_GivenResultHasProviderDataChange_AndHasNotBeenVariedInAnyOtherWay_IndexesAndReturnsNoContentResult() { //Arrange Message message = new Message(); const string specificationId = "spec-1"; IEnumerable <PublishedProviderResult> results = CreatePublishedProviderResultsWithDifferentProviders(); foreach (PublishedProviderResult result in results) { result.FundingStreamResult.AllocationLineResult.Current.Status = AllocationLineStatus.Approved; result.FundingStreamResult.AllocationLineResult.Current.ProfilingPeriods = new[] { new ProfilingPeriod() }; result.FundingStreamResult.AllocationLineResult.Current.FinancialEnvelopes = new[] { new FinancialEnvelope() }; result.FundingStreamResult.AllocationLineResult.Current.Calculations = new[] { new PublishedProviderCalculationResult { CalculationSpecification = new Common.Models.Reference("calc-id-1", "calc1"), Policy = new PolicySummary("policy-id-1", "policy1", "desc") }, new PublishedProviderCalculationResult { CalculationSpecification = new Common.Models.Reference("calc-id-2", "calc2"), Policy = new PolicySummary("policy-id-1", "policy1", "desc") }, new PublishedProviderCalculationResult { CalculationSpecification = new Common.Models.Reference("calc-id-3", "calc3"), Policy = new PolicySummary("policy-id-2", "policy2", "desc") }, }; } PublishedAllocationLineResult publishedAllocationLineResult = results.First().FundingStreamResult.AllocationLineResult; publishedAllocationLineResult.HasResultBeenVaried = false; publishedAllocationLineResult.Current.VariationReasons = new[] { VariationReason.AuthorityFieldUpdated, VariationReason.NameFieldUpdated }; IPublishedProviderResultsRepository repository = CreatePublishedProviderResultsRepository(); repository .GetAllNonHeldPublishedProviderResults() .Returns(results); IEnumerable <PublishedAllocationLineResultVersion> history = results.Select(m => m.FundingStreamResult.AllocationLineResult.Current); history.ElementAt(0).Status = AllocationLineStatus.Approved; history.ElementAt(1).Status = AllocationLineStatus.Approved; history.ElementAt(2).Status = AllocationLineStatus.Published; foreach (var providerVersion in history.GroupBy(c => c.PublishedProviderResultId)) { if (providerVersion.Any()) { IEnumerable <PublishedAllocationLineResultVersion> providerHistory = providerVersion.AsEnumerable(); string providerId = providerHistory.First().ProviderId; providerId .Should() .NotBeNullOrWhiteSpace(); repository .GetAllNonHeldPublishedProviderResultVersions(Arg.Is(providerVersion.Key), Arg.Is(providerId)) .Returns(providerHistory); } } ILogger logger = CreateLogger(); ISearchRepository <AllocationNotificationFeedIndex> searchRepository = CreateAllocationNotificationFeedSearchRepository(); SpecificationCurrentVersion specification = CreateSpecification(specificationId); ISpecificationsRepository specificationsRepository = CreateSpecificationsRepository(); specificationsRepository .GetCurrentSpecificationById(Arg.Is(specificationId)) .Returns(specification); IEnumerable <AllocationNotificationFeedIndex> resultsBeingSaved = null; await searchRepository .Index(Arg.Do <IEnumerable <AllocationNotificationFeedIndex> >(r => resultsBeingSaved = r)); PublishedResultsService resultsService = CreateResultsService( logger, publishedProviderResultsRepository: repository, allocationNotificationFeedSearchRepository: searchRepository, specificationsRepository: specificationsRepository); //Act await resultsService.ReIndexAllocationNotificationFeeds(message); //Assert await searchRepository .Received(1) .Index(Arg.Is <IEnumerable <AllocationNotificationFeedIndex> >(m => m.Count() == 3)); AllocationNotificationFeedIndex feedResult = resultsBeingSaved.FirstOrDefault(m => m.ProviderId == "1111"); feedResult.ProviderId.Should().Be("1111"); feedResult.Title.Should().Be("Allocation test allocation line 1 was Approved"); feedResult.Summary.Should().Be("UKPRN: 1111, version 0.1"); feedResult.DatePublished.HasValue.Should().Be(false); feedResult.FundingStreamId.Should().Be("fs-1"); feedResult.FundingStreamName.Should().Be("funding stream 1"); feedResult.FundingPeriodId.Should().Be("1819"); feedResult.ProviderUkPrn.Should().Be("1111"); feedResult.ProviderUpin.Should().Be("2222"); feedResult.AllocationLineId.Should().Be("AAAAA"); feedResult.AllocationLineName.Should().Be("test allocation line 1"); feedResult.AllocationVersionNumber.Should().Be(1); feedResult.AllocationAmount.Should().Be(50.0); feedResult.ProviderProfiling.Should().Be("[{\"period\":null,\"occurrence\":0,\"periodYear\":0,\"periodType\":null,\"profileValue\":0.0,\"distributionPeriod\":null}]"); feedResult.ProviderName.Should().Be("test provider name 1"); feedResult.LaCode.Should().Be("77777"); feedResult.Authority.Should().Be("London"); feedResult.ProviderType.Should().Be("test type"); feedResult.SubProviderType.Should().Be("test sub type"); feedResult.EstablishmentNumber.Should().Be("es123"); feedResult.FundingPeriodStartYear.Should().Be(DateTime.Now.Year); feedResult.FundingPeriodEndYear.Should().Be(DateTime.Now.Year + 1); feedResult.FundingStreamStartDay.Should().Be(1); feedResult.FundingStreamStartMonth.Should().Be(8); feedResult.FundingStreamEndDay.Should().Be(31); feedResult.FundingStreamEndMonth.Should().Be(7); feedResult.FundingStreamPeriodName.Should().Be("period-type 1"); feedResult.FundingStreamPeriodId.Should().Be("pt1"); feedResult.AllocationLineContractRequired.Should().Be(true); feedResult.AllocationLineFundingRoute.Should().Be("LA"); feedResult.AllocationLineShortName.Should().Be("tal1"); feedResult.PolicySummaries.Should().Be("[{\"policy\":{\"description\":\"test decscription\",\"parentPolicyId\":null,\"id\":\"policy-1\",\"name\":\"policy one\"},\"policies\":[{\"policy\":{\"description\":\"test decscription\",\"parentPolicyId\":null,\"id\":\"subpolicy-1\",\"name\":\"sub policy one\"},\"policies\":[],\"calculations\":[]}],\"calculations\":[]}]"); feedResult.Calculations.Should().Be("[{\"calculationName\":\"calc1\",\"calculationDisplayName\":\"calc1\",\"calculationVersion\":0,\"calculationType\":\"Number\",\"calculationAmount\":null,\"allocationLineId\":\"AAAAA\",\"policyId\":\"policy-id-1\",\"policyName\":\"policy1\"},{\"calculationName\":\"calc2\",\"calculationDisplayName\":\"calc2\",\"calculationVersion\":0,\"calculationType\":\"Number\",\"calculationAmount\":null,\"allocationLineId\":\"AAAAA\",\"policyId\":\"policy-id-1\",\"policyName\":\"policy1\"},{\"calculationName\":\"calc3\",\"calculationDisplayName\":\"calc3\",\"calculationVersion\":0,\"calculationType\":\"Number\",\"calculationAmount\":null,\"allocationLineId\":\"AAAAA\",\"policyId\":\"policy-id-2\",\"policyName\":\"policy2\"}]"); feedResult.OpenReason.Should().BeNull(); feedResult.CloseReason.Should().BeNull(); feedResult.Predecessors.Should().BeNull(); feedResult.Successors.Should().BeNull(); }
public async Task <IEnumerable <PublishedProviderResult> > AssemblePublishedProviderResults(IEnumerable <ProviderResult> providerResults, Reference author, SpecificationCurrentVersion specificationCurrentVersion) { Guard.ArgumentNotNull(providerResults, nameof(providerResults)); Guard.ArgumentNotNull(author, nameof(author)); Guard.ArgumentNotNull(specificationCurrentVersion, nameof(specificationCurrentVersion)); string specificationId = specificationCurrentVersion.Id; Period fundingPeriod = await _specificationsRepository.GetFundingPeriodById(specificationCurrentVersion.FundingPeriod.Id); if (fundingPeriod == null) { throw new NonRetriableException($"Failed to find a funding period for id: {specificationCurrentVersion.FundingPeriod.Id}"); } IEnumerable <string> providerIds = providerResults.Select(m => m.Provider.Id); ConcurrentBag <PublishedProviderResult> publishedProviderResults = new ConcurrentBag <PublishedProviderResult>(); IEnumerable <FundingStream> allFundingStreams = await GetAllFundingStreams(); Parallel.ForEach(providerResults, (providerResult) => { IEnumerable <PublishedFundingStreamResult> publishedFundingStreamResults = AssembleFundingStreamResults(providerResult, specificationCurrentVersion, author, allFundingStreams); foreach (PublishedFundingStreamResult publishedFundingStreamResult in publishedFundingStreamResults) { PublishedProviderResult publishedProviderResult = new PublishedProviderResult { ProviderId = providerResult.Provider.Id, SpecificationId = specificationId, FundingStreamResult = publishedFundingStreamResult, FundingPeriod = fundingPeriod, }; publishedProviderResult.FundingStreamResult.AllocationLineResult.Current.PublishedProviderResultId = publishedProviderResult.Id; publishedProviderResults.Add(publishedProviderResult); } }); return(publishedProviderResults); }
private IEnumerable <PublishedFundingStreamResult> AssembleFundingStreamResults(ProviderResult providerResult, SpecificationCurrentVersion specificationCurrentVersion, Reference author, IEnumerable <FundingStream> allFundingStreams) { IList <PublishedFundingStreamResult> publishedFundingStreamResults = new List <PublishedFundingStreamResult>(); Dictionary <string, PublishedAllocationLineDefinition> publishedAllocationLines = new Dictionary <string, PublishedAllocationLineDefinition>(); foreach (Reference fundingStreamReference in specificationCurrentVersion.FundingStreams) { FundingStream fundingStream = allFundingStreams.FirstOrDefault(m => m.Id == fundingStreamReference.Id); if (fundingStream == null) { throw new NonRetriableException($"Failed to find a funding stream for id: {fundingStreamReference.Id}"); } PublishedFundingStreamDefinition publishedFundingStreamDefinition = _mapper.Map <PublishedFundingStreamDefinition>(fundingStream); List <PublishedProviderCalculationResult> publishedProviderCalculationResults = new List <PublishedProviderCalculationResult>(providerResult.CalculationResults.Count()); foreach (CalculationResult calculationResult in providerResult.CalculationResults) { (Policy policy, Policy parentPolicy, Calculation calculation) = FindPolicy(calculationResult.CalculationSpecification?.Id, specificationCurrentVersion.Policies); if (calculation == null) { throw new NonRetriableException($"Calculation specification not found in specification. Calculation Spec Id ='{calculationResult?.CalculationSpecification?.Id}'"); } if (calculation.CalculationType == CalculationType.Number && !calculation.IsPublic) { continue; } PublishedProviderCalculationResult publishedProviderCalculationResult = new PublishedProviderCalculationResult() { CalculationSpecification = calculationResult.CalculationSpecification, AllocationLine = calculationResult.AllocationLine, IsPublic = calculation.IsPublic, CalculationType = ConvertCalculationType(calculationResult.CalculationType), Value = calculationResult.Value, CalculationVersion = calculationResult.Version }; if (policy != null) { publishedProviderCalculationResult.Policy = new PolicySummary(policy.Id, policy.Name, policy.Description); } if (parentPolicy != null) { publishedProviderCalculationResult.ParentPolicy = new PolicySummary(parentPolicy.Id, parentPolicy.Name, parentPolicy.Description); } publishedProviderCalculationResults.Add(publishedProviderCalculationResult); } IEnumerable <IGrouping <string, CalculationResult> > allocationLineGroups = providerResult .CalculationResults .Where(c => c.CalculationType == Models.Calcs.CalculationType.Funding && c.Value.HasValue && c.AllocationLine != null && !string.IsNullOrWhiteSpace(c.AllocationLine.Id)) .GroupBy(m => m.AllocationLine.Id); foreach (IGrouping <string, CalculationResult> allocationLineResultGroup in allocationLineGroups) { PublishedAllocationLineDefinition publishedAllocationLine; if (!publishedAllocationLines.TryGetValue(allocationLineResultGroup.Key, out publishedAllocationLine)) { AllocationLine allocationLine = fundingStream.AllocationLines.FirstOrDefault(m => m.Id == allocationLineResultGroup.Key); if (allocationLine != null) { publishedAllocationLine = _mapper.Map <PublishedAllocationLineDefinition>(allocationLine); publishedAllocationLines.Add(allocationLineResultGroup.Key, publishedAllocationLine); } } if (publishedAllocationLine != null) { PublishedFundingStreamResult publishedFundingStreamResult = new PublishedFundingStreamResult { FundingStream = publishedFundingStreamDefinition, FundingStreamPeriod = $"{fundingStream.Id}{specificationCurrentVersion.FundingPeriod.Id}", DistributionPeriod = $"{fundingStream.PeriodType.Id}{specificationCurrentVersion.FundingPeriod.Id}" }; PublishedAllocationLineResultVersion publishedAllocationLineResultVersion = new PublishedAllocationLineResultVersion { Author = author, Date = DateTimeOffset.Now, Status = AllocationLineStatus.Held, Value = allocationLineResultGroup.Sum(m => m.Value), Provider = providerResult.Provider, SpecificationId = specificationCurrentVersion.Id, ProviderId = providerResult.Provider.Id, Calculations = publishedProviderCalculationResults.Where(c => c.AllocationLine == null || string.Equals(c.AllocationLine.Id, publishedAllocationLine.Id, StringComparison.InvariantCultureIgnoreCase)), }; publishedFundingStreamResult.AllocationLineResult = new PublishedAllocationLineResult { AllocationLine = publishedAllocationLine, Current = publishedAllocationLineResultVersion }; publishedFundingStreamResults.Add(publishedFundingStreamResult); } } } return(publishedFundingStreamResults); }
private bool ValidateCalculation(string argument, SpecificationCurrentVersion specification) { return(specification.GetCalculations().SingleOrDefault(x => x.Name == argument) != null); }
public IEnumerable <GherkinError> Validate(Step step, SpecificationCurrentVersion specification, List <DefinitionSpecificationRelationship> dataRelationships, List <DatasetDefinition> dataDefinitions) { foreach (var stepAction in StepsAction) { var stepDefinition = stepAction.GetCustomAttribute <TestStepAttribute>(); if (stepDefinition.Keyword == step.Keyword?.Trim().ToLowerInvariant()) { if (Regex.IsMatch(step.Text, stepDefinition.Regex)) { var arguments = Regex.Split(step.Text, stepDefinition.Regex).Skip(1).ToArray(); var instance = Activator.CreateInstance(stepAction) as GherkinStepAction; var propertyInfos = stepAction.GetProperties() .Where(x => x.GetCustomAttribute <TestStepArgumentAttribute>() != null).ToArray(); string datasetName = null; string fieldName = null; for (var index = 0; index < propertyInfos.Length; index++) { var propertyInfo = propertyInfos[index]; var argument = arguments[index]; var argumentDefinition = propertyInfo.GetCustomAttribute <TestStepArgumentAttribute>(); switch (argumentDefinition.Type) { case StepArgumentType.DatasetName: datasetName = argument; if (!ValidateField(argument, fieldName, dataRelationships, dataDefinitions)) { yield return(new GherkinError($"'{argument} is not a valid dataset name'", step.Location.Line, step.Location.Column)); propertyInfo.SetValue(instance, argument); } break; case StepArgumentType.FieldName: fieldName = argument; if (!ValidateField(datasetName, argument, dataRelationships, dataDefinitions)) { yield return(new GherkinError($"'{argument} is not a valid field name in {datasetName}'", step.Location.Line, step.Location.Column)); propertyInfo.SetValue(instance, argument); } break; case StepArgumentType.CalculationName: if (!ValidateCalculation(argument, specification)) { yield return(new GherkinError($"'{argument} is not a valid calculation name'", step.Location.Line, step.Location.Column)); propertyInfo.SetValue(instance, argument); } break; } } } } } }