public void GenerateTotals_GivenValidTemplateMetadataContentsAndCalculations_ReturnsFundingLines() { //Arrange ILogger logger = CreateLogger(); ITemplateMetadataGenerator templateMetaDataGenerator = CreateTemplateGenerator(logger); TemplateMetadataContents contents = templateMetaDataGenerator.GetMetadata(GetResourceString("CalculateFunding.Services.Publishing.UnitTests.Resources.exampleFundingLineTemplate1.json")); Mock <IFundingLineRoundingSettings> rounding = new Mock <IFundingLineRoundingSettings>(); rounding.Setup(_ => _.DecimalPlaces) .Returns(2); FundingLineTotalAggregator fundingLineTotalAggregator = new FundingLineTotalAggregator(rounding.Object); TemplateMapping mapping = CreateTemplateMappings(); //Act GeneratorModels.FundingValue fundingValue = fundingLineTotalAggregator.GenerateTotals(contents, mapping.TemplateMappingItems.ToDictionary(_ => _.TemplateId), CreateCalculations(mapping).ToDictionary(_ => _.Id)); IEnumerable <GeneratorModels.FundingLine> fundingLines = fundingValue.FundingLines.Flatten(_ => _.FundingLines); //Assert fundingLines.Single(_ => _.TemplateLineId == 1).Value .Should() .Be(16200.64M); fundingLines.Single(_ => _.TemplateLineId == 2).Value .Should() .Be(8000M); fundingLines.Single(_ => _.TemplateLineId == 3).Value .Should() .Be(3200M); fundingLines.Single(_ => _.TemplateLineId == 4).Value .Should() .Be(5000.64M); fundingLines.Single(_ => _.TemplateLineId == 5).Value .Should() .Be(null); fundingLines.Single(_ => _.TemplateLineId == 6).Value .Should() .Be(8000M); fundingLines.Single(_ => _.TemplateLineId == 7).Value .Should() .Be(500M); fundingLines.Single(_ => _.TemplateLineId == 8).Value .Should() .Be(1200M); }
/// <summary> /// Generate Funding Lines, Calculations and Reference Data for a funding stream for all in scope providers /// </summary> /// <param name="templateMetadata">Template Metadata</param> /// <param name="templateMapping">Template Mapping</param> /// <param name="scopedProviders">Scoped providers for a specification</param> /// <param name="calculationResults">Calculation Results</param> /// <returns>Dictionary of Generated Provider Results, keyed on ProviderId</returns> public IDictionary <string, GeneratedProviderResult> Generate(TemplateMetadataContents templateMetadata, Common.ApiClient.Calcs.Models.TemplateMapping templateMapping, IEnumerable <Provider> scopedProviders, IDictionary <string, ProviderCalculationResult> calculationResults) { Guard.ArgumentNotNull(templateMetadata, nameof(templateMetadata)); Guard.ArgumentNotNull(templateMapping, nameof(templateMapping)); Guard.ArgumentNotNull(calculationResults, nameof(calculationResults)); ConcurrentDictionary <string, GeneratedProviderResult> results = new ConcurrentDictionary <string, GeneratedProviderResult>(); TimeSpan loggingPeriod = TimeSpan.FromMinutes(5); using (new Timer( _ => _logger.Information($"{results.Count}: Published Providers processed."), null, loggingPeriod, loggingPeriod)) Parallel.ForEach(scopedProviders, new ParallelOptions { MaxDegreeOfParallelism = 15 }, (provider) => { GeneratedProviderResult generatedProviderResult = new GeneratedProviderResult(); ProviderCalculationResult calculationResultsForProvider = null; calculationResults.TryGetValue(provider.ProviderId, out calculationResultsForProvider); if (calculationResultsForProvider != null) { GeneratorModels.FundingValue fundingValue = _fundingLineTotalAggregator.GenerateTotals(templateMetadata, templateMapping.TemplateMappingItems.ToDictionary(_ => _.TemplateId), calculationResultsForProvider.Results.ToDictionary(_ => _.Id)); // Get funding lines IEnumerable <GeneratorModels.FundingLine> fundingLines = fundingValue.FundingLines?.Flatten(_ => _.FundingLines) ?? new GeneratorModels.FundingLine[0]; Dictionary <uint, GeneratorModels.FundingLine> uniqueFundingLine = new Dictionary <uint, GeneratorModels.FundingLine>(); generatedProviderResult.FundingLines = fundingLines.Where(_ => uniqueFundingLine.TryAdd(_.TemplateLineId, _)).Select(_ => { return(_mapper.Map <FundingLine>(_)); }).ToList(); // Set total funding generatedProviderResult.TotalFunding = generatedProviderResult.FundingLines .Sum(p => { return(p.Type == FundingLineType.Payment ? p.Value : 0); }); Dictionary <uint, GeneratorModels.Calculation> uniqueCalculations = new Dictionary <uint, GeneratorModels.Calculation>(); // Get calculations IEnumerable <GeneratorModels.Calculation> fundingCalculations = uniqueFundingLine.Values?.SelectMany(_ => _.Calculations.Flatten(calc => calc.Calculations)) ?? new GeneratorModels.Calculation[0]; generatedProviderResult.Calculations = fundingCalculations.Where(_ => uniqueCalculations.TryAdd(_.TemplateCalculationId, _)).Select(_ => { return(_mapper.Map <FundingCalculation>(_)); }).ToList(); // Set Provider information generatedProviderResult.Provider = _mapper.Map <Provider>(provider); results.TryAdd(provider.ProviderId, generatedProviderResult); } }); return(results); }