private async Task TryCachePupilNumberTemplateCalculationIds(string cacheKey,
                                                                         string fundingStreamId, string fundingPeriodId,
                                                                         string templateVersion)
            {
                ApiResponse <TemplateMetadataContents> templateContentsResponse = await _policiesResilience.ExecuteAsync(
                    () => _policies.GetFundingTemplateContents(fundingStreamId, fundingPeriodId, templateVersion));

                if (!templateContentsResponse.StatusCode.IsSuccess())
                {
                    throw new InvalidOperationException("Cannot move pupil numbers to successor.\n" +
                                                        $" Did not locate Template MetaData Contents for funding stream id {fundingStreamId} and template version {templateVersion}");
                }

                TemplateMetadataContents templateMetadataContents = templateContentsResponse.Content;

                IEnumerable <FundingLine> flattenedFundingLines = templateMetadataContents.RootFundingLines
                                                                  .Flatten(_ => _.FundingLines) ?? new FundingLine[0];

                IEnumerable <uint> pupilNumberTemplateCalculationIds = flattenedFundingLines.SelectMany(_ =>
                                                                                                        _.Calculations.Flatten(cal => cal.Calculations))
                                                                       .Where(_ => _.Type == CalculationType.PupilNumber)
                                                                       .Select(_ => _.TemplateCalculationId)
                                                                       .Distinct()
                                                                       .ToArray();

                await _cachingResilience.ExecuteAsync(() => _caching.SetAsync(cacheKey,
                                                                              pupilNumberTemplateCalculationIds,
                                                                              TimeSpan.FromHours(24),
                                                                              false));
            }
예제 #2
0
 private void AndTheFundingTemplateContentsForPeriodAndStream(string fundingPeriodId,
                                                              string fundingStreamId,
                                                              string templateVersionId,
                                                              TemplateMetadataContents templateContents)
 {
     GivenTheFundingTemplateContentsForPeriodAndStream(fundingPeriodId, fundingStreamId, templateVersionId, templateContents);
 }
예제 #3
0
        public async Task <ISqlImportContext> CreateImportContext(string specificationId,
                                                                  string fundingStreamId,
                                                                  SchemaContext schemaContext)
        {
            ICosmosDbFeedIterator <PublishedProvider> publishedProviderFeed = GetPublishedProviderFeed(specificationId, fundingStreamId);

            TemplateMetadataContents template = await GetTemplateMetadataContents(specificationId, fundingStreamId);

            IEnumerable <FundingLine>  allFundingLines    = template.RootFundingLines.Flatten(_ => _.FundingLines);
            IEnumerable <Calculation>  allCalculations    = allFundingLines.SelectMany(_ => _.Calculations.Flatten(cal => cal.Calculations));
            IEnumerable <Calculation>  uniqueCalculations = allCalculations.DistinctBy(_ => _.TemplateCalculationId);
            IDictionary <uint, string> calculationNames   = GetCalculationNames(uniqueCalculations);

            return(new SqlImportContext
            {
                Documents = publishedProviderFeed,
                CalculationNames = calculationNames,
                Calculations = new CalculationDataTableBuilder(uniqueCalculations),
                Providers = new ProviderDataTableBuilder(),
                Funding = new PublishedProviderVersionDataTableBuilder(),
                InformationFundingLines = new InformationFundingLineDataTableBuilder(),
                PaymentFundingLines = new PaymentFundingLineDataTableBuilder(),
                SchemaContext = schemaContext
            });
        }
예제 #4
0
        public async Task GenerateTotals_GivenValidTemplateMetadataContentsAndProvidersButMissingCalculations_EmptyGeneratedProviderResultsReturned()
        {
            //Arrange
            ILogger logger = CreateLogger();

            ITemplateMetadataGenerator templateMetaDataGenerator = CreateTemplateGenerator(logger);

            TemplateMetadataContents contents = templateMetaDataGenerator.GetMetadata(GetResourceString("CalculateFunding.Services.Publishing.UnitTests.Resources.exampleFundingLineTemplate1.json"));

            IMapper mapper = CreateMapper();

            FundingLineTotalAggregator fundingLineTotalAggregator = new FundingLineTotalAggregator(new Mock <IFundingLineRoundingSettings>().Object);

            TemplateMapping mapping = CreateTemplateMappings();

            PublishedProviderDataGenerator publishedProviderDataGenerator = new PublishedProviderDataGenerator(logger, fundingLineTotalAggregator, mapper);

            //Act
            Dictionary <string, ProviderCalculationResult> providerCalculationResults = new Dictionary <string, ProviderCalculationResult>();

            IDictionary <string, GeneratedProviderResult> generatedProviderResult = publishedProviderDataGenerator.Generate(contents, mapping, GetProviders(), providerCalculationResults);

            generatedProviderResult.Any()
            .Should()
            .BeFalse();
        }
        private async Task <UniqueTemplateContents> GetTemplateData(SpecificationSummary specification, string fundingStreamId)
        {
            UniqueTemplateContents uniqueTemplateContents = new UniqueTemplateContents();

            TemplateMetadataContents templateMetadata = await GetTemplateMetadataContents(specification, fundingStreamId);

            if (templateMetadata == null)
            {
                throw new NonRetriableException(
                          $"Did not locate template information for specification {specification.Id} in {fundingStreamId}. Unable to complete Qa Schema Generation");
            }

            IEnumerable <FundingLine> flattenedFundingLines = templateMetadata.RootFundingLines.Flatten(_ => _.FundingLines)
                                                              ?? new FundingLine[0];

            IEnumerable <FundingLine> uniqueFundingLines = flattenedFundingLines.GroupBy(x => x.TemplateLineId)
                                                           .Select(f => f.First());

            IEnumerable <Calculation> flattenedCalculations =
                flattenedFundingLines.SelectMany(_ => _.Calculations.Flatten(cal => cal.Calculations)) ?? new Calculation[0];

            IEnumerable <Calculation> uniqueFlattenedCalculations =
                flattenedCalculations.GroupBy(x => x.TemplateCalculationId)
                .Select(x => x.FirstOrDefault());

            uniqueTemplateContents.FundingLines = uniqueFundingLines;
            uniqueTemplateContents.Calculations = uniqueFlattenedCalculations;

            return(uniqueTemplateContents);
        }
예제 #6
0
        public async Task Assemble_GivenSpecificationWithTwoFundingStreamsButTemplateContentsNotFoundForOneFundingStream_ReturnsCollectionWithOneItem()
        {
            //Arrange
            TemplateMetadataContents templateMetadataContents = new TemplateMetadataContents();

            SpecificationSummary specificationSummary = CreateSpecificationSummary();

            IPoliciesApiClient policiesApiClient = CreatePoliciesClient();

            policiesApiClient
            .GetFundingTemplateContents(Arg.Is("fs-1"), Arg.Is("fp-1"), Arg.Is("1.0"))
            .Returns(new ApiResponse <TemplateMetadataContents>(HttpStatusCode.OK, templateMetadataContents));
            policiesApiClient
            .GetFundingTemplateContents(Arg.Is("fs-2"), Arg.Is("fp-1"), Arg.Is("1.0"))
            .Returns((ApiResponse <TemplateMetadataContents>)null);

            TemplateMetadataContentsAssemblerService templateMetadataContentsAssemblerService = CreateService(policiesApiClient: policiesApiClient);

            //Act
            var templateMetadataContentsCollection = await templateMetadataContentsAssemblerService.Assemble(specificationSummary);

            //Assert
            templateMetadataContentsCollection
            .Should()
            .HaveCount(1);

            templateMetadataContentsCollection
            .First().Value
            .Should()
            .Be(templateMetadataContents);
        }
예제 #7
0
        public async Task Assemble_GivenSpecificationWithTwoFundingStreamsAndTemplatesFound_ReturnsCollectionWithTwoItems()
        {
            //Arrange
            TemplateMetadataContents templateMetadataContentsFs1 = new TemplateMetadataContents();
            TemplateMetadataContents templateMetadataContentsFs2 = new TemplateMetadataContents();

            SpecificationSummary specificationSummary = CreateSpecificationSummary();

            IPoliciesApiClient policiesApiClient = CreatePoliciesClient();

            policiesApiClient
            .GetFundingTemplateContents(Arg.Is("fs-1"), Arg.Is("fp-1"), Arg.Is("1.0"))
            .Returns(new ApiResponse <TemplateMetadataContents>(HttpStatusCode.OK, templateMetadataContentsFs1));
            policiesApiClient
            .GetFundingTemplateContents(Arg.Is("fs-2"), Arg.Is("fp-1"), Arg.Is("1.0"))
            .Returns(new ApiResponse <TemplateMetadataContents>(HttpStatusCode.OK, templateMetadataContentsFs2));

            TemplateMetadataContentsAssemblerService templateMetadataContentsAssemblerService = CreateService(policiesApiClient: policiesApiClient);

            //Act
            var templateMetadataContentsCollection = await templateMetadataContentsAssemblerService.Assemble(specificationSummary);

            //Assert
            templateMetadataContentsCollection
            .Should()
            .HaveCount(2);
        }
        public async Task CachesPupilNumberTemplateCalculationsIfNotCachedForContext()
        {
            uint calculationOneId   = NewRandomUint();
            uint calculationTwoId   = NewRandomUint();
            uint calculationThreeId = NewRandomUint();

            TemplateMetadataContents templateMapping = NewTemplateMetadataContents(_ =>
                                                                                   _.WithFundingLines(NewTemplateFundingLine(fl =>
                                                                                                                             fl.WithCalculations(NewTemplateCalculation(cl =>
                                                                                                                                                                        cl.WithTemplateCalculationId(calculationOneId)
                                                                                                                                                                        .WithType(TemplateCalculationType.PupilNumber)),
                                                                                                                                                 NewTemplateCalculation(cl =>
                                                                                                                                                                        cl.WithTemplateCalculationId(calculationTwoId)
                                                                                                                                                                        .WithType(NewCalculationTypeExcept(TemplateCalculationType.PupilNumber))))
                                                                                                                             .WithFundingLines(NewTemplateFundingLine(fl2 =>
                                                                                                                                                                      fl2.WithCalculations(NewTemplateCalculation(cl =>
                                                                                                                                                                                                                  cl.WithTemplateCalculationId(calculationThreeId)
                                                                                                                                                                                                                  .WithType(TemplateCalculationType.PupilNumber))))))));

            GivenTheTemplateMetadataContents(templateMapping);
            AndTheFundingCalculations(NewFundingCalculation(_ => _.WithTemplateCalculationId(calculationOneId)
                                                            .WithValue(calculationOneId)),
                                      NewFundingCalculation(),
                                      NewFundingCalculation(_ => _.WithTemplateCalculationId(calculationTwoId)
                                                            .WithValue(calculationThreeId)));
            AndTheSuccessorFundingCalculations(NewFundingCalculation(_ => _.WithTemplateCalculationId(calculationOneId)
                                                                     .WithValue(calculationOneId)),
                                               NewFundingCalculation(),
                                               NewFundingCalculation(_ => _.WithTemplateCalculationId(calculationTwoId)
                                                                     .WithValue(calculationThreeId)));

            await WhenTheChangeIsApplied();

            ThenTheTemplateCalculationIdsWereCached(calculationThreeId, calculationOneId);
        }
        public void ThrowsExceptionWhenContentGeneratorReturnsNull()
        {
            // Arrange
            TemplateMetadataContents            templateMetadataContents           = Substitute.For <TemplateMetadataContents>();
            TemplateMapping                     templateMapping                    = Substitute.For <TemplateMapping>();
            IPublishedProviderContentsGenerator publishedProviderContentsGenerator = Substitute.For <IPublishedProviderContentsGenerator>();

            Dictionary <string, GeneratedProviderResult> generatedPublishedProviderData = new Dictionary <string, GeneratedProviderResult>();
            List <PublishedProvider> publishedProvidersToUpdate = new List <PublishedProvider>();

            GeneratedProviderResult generatedProviderResult = new GeneratedProviderResult();

            PublishedProviderVersion publishedProviderVersion = NewPublishedProviderVersion(providerVersion => providerVersion
                                                                                            .WithProviderId(ProviderVersionProviderId)
                                                                                            .WithFundingPeriodId(ProviderVersionFundingPeriodId)
                                                                                            .WithFundingStreamId(ProviderVersionFundingStreamId)
                                                                                            .WithVersion(ProviderVersionVersion));

            PublishedProvider publishedProvider = NewPublishedProvider(provider => provider.WithCurrent(publishedProviderVersion));

            generatedPublishedProviderData.Add(key, generatedProviderResult);
            publishedProvidersToUpdate.Add(publishedProvider);

            // Act
            Func <Task> invocation = async() => await _publishedProviderContentPersistanceService.SavePublishedProviderContents(
                templateMetadataContents, templateMapping, publishedProvidersToUpdate, publishedProviderContentsGenerator);

            // Assert
            ThenExceptionShouldBeThrown($"Generator failed to generate content for published provider version with id: '{publishedProviderVersion.Id}'", invocation);
        }
예제 #10
0
        public string GenerateContents(PublishedFundingVersion publishedFundingVersion,
                                       TemplateMetadataContents templateMetadataContents)
        {
            Guard.ArgumentNotNull(publishedFundingVersion, nameof(publishedFundingVersion));
            Guard.ArgumentNotNull(templateMetadataContents, nameof(templateMetadataContents));

            SchemaJson contents = new SchemaJson
            {
                Schema        = "https://fundingschemas.blob.core.windows.net/schemas/logicalmodel-1.0.json#schema",
                SchemaVersion = publishedFundingVersion.SchemaVersion,
                Funding       = new
                {
                    publishedFundingVersion.TemplateVersion,
                    Id             = publishedFundingVersion.FundingId,
                    FundingVersion = $"{publishedFundingVersion.MajorVersion}_{publishedFundingVersion.MinorVersion}",
                    Status         = publishedFundingVersion.Status.ToString(),
                    FundingStream  = new
                    {
                        Code = publishedFundingVersion.FundingStreamId,
                        Name = publishedFundingVersion.FundingStreamName
                    },
                    FundingPeriod = new
                    {
                        publishedFundingVersion.FundingPeriod.Id,
                        publishedFundingVersion.FundingPeriod.Period,
                        publishedFundingVersion.FundingPeriod.Name,
                        Type = publishedFundingVersion.FundingPeriod.Type.ToString(),
                        publishedFundingVersion.FundingPeriod.StartDate,
                        publishedFundingVersion.FundingPeriod.EndDate
                    },
                    OrganisationGroup = new
                    {
                        GroupTypeCode           = publishedFundingVersion.OrganisationGroupTypeCode,
                        GroupTypeIdentifier     = publishedFundingVersion.OrganisationGroupTypeIdentifier,
                        IdentifierValue         = publishedFundingVersion.OrganisationGroupIdentifierValue,
                        GroupTypeClassification = publishedFundingVersion.OrganisationGroupTypeClassification,
                        Name           = publishedFundingVersion.OrganisationGroupName,
                        SearchableName = publishedFundingVersion.OrganisationGroupSearchableName,
                        Identifiers    = publishedFundingVersion.OrganisationGroupIdentifiers?.Select(groupTypeIdentifier => new
                        {
                            groupTypeIdentifier.Type,
                            groupTypeIdentifier.Value
                        }).ToArray()
                    },
                    FundingValue = new
                    {
                        TotalValue   = publishedFundingVersion.TotalFunding,
                        FundingLines = templateMetadataContents.RootFundingLines?.Select(_ => BuildSchemaJsonFundingLines(publishedFundingVersion.ReferenceData, publishedFundingVersion.Calculations, publishedFundingVersion.FundingLines, _, publishedFundingVersion.OrganisationGroupTypeIdentifier, publishedFundingVersion.OrganisationGroupIdentifierValue))
                    },
                    ProviderFundings = publishedFundingVersion.ProviderFundings?.ToArray(),
                    publishedFundingVersion.GroupingReason,
                    publishedFundingVersion.StatusChangedDate,
                    publishedFundingVersion.ExternalPublicationDate,
                    publishedFundingVersion.EarliestPaymentAvailableDate,
                    VariationReasons = publishedFundingVersion.VariationReasons?.ToArray()
                }
            };

            return(contents.AsJson());
        }
예제 #11
0
 private void GivenTheFundingTemplateContentsForPeriodAndStream(string fundingPeriodId,
                                                                string fundingStreamId,
                                                                string templateVersionId,
                                                                TemplateMetadataContents templateContents)
 {
     _policies.GetFundingTemplateContents(fundingStreamId, fundingPeriodId, templateVersionId)
     .Returns(new ApiResponse <TemplateMetadataContents>(HttpStatusCode.OK, templateContents));
 }
예제 #12
0
        public void TemplateMetadataSchema10_GetInvalidMetaData_ReturnsEmptyContents()
        {
            TemplateMetadataContents contents = WhenTheMetadataContentsIsGenerated("CalculateFunding.TemplateMetadata.Schema10.UnitTests.Resources.dsg1.0.error.json");

            logger
            .Received(1)
            .Error(Arg.Is <Exception>(x => x.GetType().Name == "JsonSerializationException"), Arg.Any <string>());
        }
        private IEnumerable <AggregateFundingLine> WhenTheSchema1_1FundingLinesAreAggregated()
        {
            ITemplateMetadataGenerator templateMetaDataGenerator = CreateSchema11TemplateGenerator();

            _contents = templateMetaDataGenerator.GetMetadata(GetResourceString("CalculateFunding.Services.Publishing.UnitTests.Resources.exampleProviderTemplate1_Schema1_1.json"));

            return(_fundingValueAggregator.GetTotals(_contents, GetProviderVersions("_Schema1_1")));
        }
예제 #14
0
        public async Task <PublishedFundingInput> GeneratePublishedFundingInput(IDictionary <string, PublishedProvider> publishedProvidersForFundingStream,
                                                                                IEnumerable <Provider> scopedProviders,
                                                                                Reference fundingStream,
                                                                                SpecificationSummary specification,
                                                                                IEnumerable <PublishedProvider> publishedProvidersInScope)
        {
            Guard.ArgumentNotNull(publishedProvidersForFundingStream, nameof(publishedProvidersForFundingStream));
            Guard.ArgumentNotNull(scopedProviders, nameof(scopedProviders));
            Guard.ArgumentNotNull(fundingStream, nameof(fundingStream));
            Guard.ArgumentNotNull(specification, nameof(specification));

            _logger.Information($"Fetching existing published funding");

            // Get latest version of existing published funding
            IEnumerable <PublishedFunding> publishedFunding = await _publishingResiliencePolicy.ExecuteAsync(() =>
                                                                                                             _publishedFundingDataService.GetCurrentPublishedFunding(fundingStream.Id, specification.FundingPeriod.Id));

            _logger.Information($"Fetched {publishedFunding.Count()} existing published funding items");

            _logger.Information($"Generating organisation groups");

            FundingConfiguration fundingConfiguration = await _policiesService.GetFundingConfiguration(fundingStream.Id, specification.FundingPeriod.Id);

            TemplateMetadataContents templateMetadataContents = await ReadTemplateMetadataContents(fundingStream, specification);

            // Foreach group, determine the provider versions required to be latest
            IEnumerable <OrganisationGroupResult> organisationGroups =
                await _organisationGroupGenerator.GenerateOrganisationGroup(fundingConfiguration, _mapper.Map <IEnumerable <ApiProvider> >(scopedProviders), specification.ProviderVersionId, specification.ProviderSnapshotId);

            // filter out organisation groups which don't contain a provider which is in scope
            if (!publishedProvidersInScope.IsNullOrEmpty())
            {
                HashSet <string> publishedProviderIdsInScope = new HashSet <string>(publishedProvidersInScope.DistinctBy(_ => _.Current.ProviderId).Select(_ => _.Current.ProviderId));
                organisationGroups = organisationGroups.Where(_ => _.Providers.Any(provider => publishedProviderIdsInScope.Contains(provider.ProviderId)));
            }

            _logger.Information($"A total of {organisationGroups.Count()} were generated");

            _logger.Information($"Generating organisation groups to save");

            // Compare existing published provider versions with existing current PublishedFundingVersion
            IEnumerable <(PublishedFunding PublishedFunding, OrganisationGroupResult OrganisationGroupResult)> organisationGroupsToSave =
                _publishedFundingChangeDetectorService.GenerateOrganisationGroupsToSave(organisationGroups, publishedFunding, publishedProvidersForFundingStream);

            _logger.Information($"A total of {organisationGroupsToSave.Count()} organisation groups returned to save");

            // Generate PublishedFundingVersion for new and updated PublishedFundings
            return(new PublishedFundingInput()
            {
                OrganisationGroupsToSave = organisationGroupsToSave,
                TemplateMetadataContents = templateMetadataContents,
                TemplateVersion = specification.TemplateIds[fundingStream.Id],
                FundingStream = fundingStream,
                FundingPeriod = await _policiesService.GetFundingPeriodByConfigurationId(specification.FundingPeriod.Id),
                PublishingDates = await _publishedFundingDateService.GetDatesForSpecification(specification.Id),
                SpecificationId = specification.Id,
            });
        }
예제 #15
0
        public async Task SavePublishedProviderContents(TemplateMetadataContents templateMetadataContents, TemplateMapping templateMapping, IEnumerable <PublishedProvider> publishedProvidersToUpdate, IPublishedProviderContentsGenerator generator, bool publishAll = false)
        {
            _logger.Information("Saving published provider contents");
            List <Task>   allTasks  = new List <Task>();
            SemaphoreSlim throttler = new SemaphoreSlim(initialCount: _publishingEngineOptions.SavePublishedProviderContentsConcurrencyCount);

            foreach (PublishedProvider provider in publishedProvidersToUpdate)
            {
                await throttler.WaitAsync();

                allTasks.Add(
                    Task.Run(async() =>
                {
                    try
                    {
                        IEnumerable <PublishedProviderVersion> publishedProviderVersions = publishAll ?
                                                                                           await _publishedProviderVersioningService.GetVersions(provider) :
                                                                                           new[] { provider.Current };

                        foreach (PublishedProviderVersion publishedProviderVersion in publishedProviderVersions)
                        {
                            string contents = generator.GenerateContents(publishedProviderVersion, templateMetadataContents, templateMapping);

                            if (string.IsNullOrWhiteSpace(contents))
                            {
                                throw new RetriableException($"Generator failed to generate content for published provider version with id: '{publishedProviderVersion.Id}'");
                            }

                            try
                            {
                                await _publishedProviderVersionService.SavePublishedProviderVersionBody(
                                    publishedProviderVersion.FundingId, contents, publishedProviderVersion.SpecificationId);
                            }
                            catch (Exception ex)
                            {
                                throw new RetriableException(ex.Message);
                            }

                            try
                            {
                                await _publishedProviderIndexerService.IndexPublishedProvider(publishedProviderVersion);
                            }
                            catch (Exception ex)
                            {
                                throw new RetriableException(ex.Message);
                            }
                        }
                    }
                    finally
                    {
                        throttler.Release();
                    }
                }));
            }

            await TaskHelper.WhenAllAndThrow(allTasks.ToArray());
        }
예제 #16
0
        public void GeneratesJsonConformingToThe11Schema()
        {
            TemplateMetadataContents templateMetadataContents = GetTemplateMetaDataContents("example-funding-template1.1.json");
            PublishedFundingVersion  publishedFundingVersion  = GetPublishedFundingVersion("example-published-funding-version.json");

            string funding = WhenThePublishedFundingVersionIsTransformed(publishedFundingVersion, templateMetadataContents);

            ThenTheJsonValidatesAgainstThe1_1FundingSchema(funding);
        }
 protected void AndTheTemplateMetadataContents(string schemaVersion,
                                               string templateContents,
                                               TemplateMetadataContents templateMetadataContents)
 {
     TemplateMetadataResolver.Setup(_ => _.GetService(schemaVersion))
     .Returns(TemplateMetadataGenerator.Object);
     TemplateMetadataGenerator.Setup(_ => _.GetMetadata(templateContents))
     .Returns(templateMetadataContents);
 }
예제 #18
0
 private void AndTheTemplate(string fundingStreamId,
                             string fundingPeriodId,
                             string templateVersion,
                             TemplateMetadataContents template)
 => _templates.Setup(_ => _.GetFundingTemplateContents(fundingStreamId,
                                                       fundingPeriodId,
                                                       templateVersion,
                                                       null))
 .ReturnsAsync(new ApiResponse <TemplateMetadataContents>(HttpStatusCode.OK, template));
        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);
        }
예제 #20
0
 public IEnumerable <CalculationFundingLine> GetCalculationFundingLines(TemplateMetadataContents template,
                                                                        uint templateId)
 => template.RootFundingLines?
 .Where(_ => ContainsCalculation(_, templateId))
 .Select(_ => new CalculationFundingLine
 {
     TemplateId = _.TemplateLineId,
     Name       = _.Name
 })
 .ToArray();
예제 #21
0
        public async Task <IActionResult> GetCalculationFundingLines(string calculationId)
        {
            Guard.IsNullOrWhiteSpace(calculationId, nameof(calculationId));

            Calculation calculation = await GetCalculation(calculationId);

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

            string specificationId = calculation.SpecificationId;

            string cacheKey = GetCacheKey(calculationId, specificationId);

            if (await CacheContains(cacheKey))
            {
                return(new OkObjectResult(await GetCachedCalculationFundingLines(cacheKey)));
            }

            SpecificationSummary specificationSummary = await GetSpecificationSummary(specificationId);

            Guard.ArgumentNotNull(specificationSummary, nameof(specificationSummary));

            string fundingStreamId = calculation.FundingStreamId;

            if (specificationSummary.TemplateIds == null || !specificationSummary.TemplateIds.TryGetValue(fundingStreamId, out string templateVersion))
            {
                throw new ArgumentOutOfRangeException(nameof(fundingStreamId),
                                                      $"Specification {specificationId} does not contain a template version for the funding stream {fundingStreamId}");
            }

            TemplateMetadataContents template = await GetTemplate(fundingStreamId,
                                                                  specificationSummary.FundingPeriod?.Id,
                                                                  templateVersion);

            Guard.ArgumentNotNull(template, nameof(template));

            TemplateMapping templateMapping = await GetTemplateMapping(fundingStreamId,
                                                                       specificationId);

            Guard.ArgumentNotNull(templateMapping, nameof(templateMapping));

            uint?templateId = templateMapping.TemplateMappingItems?.SingleOrDefault(_ => _.CalculationId == calculationId)?.TemplateId;

            Guard.Ensure(templateId.HasValue, $"Did not locate a template mapping item for CalculationId {calculationId}");

            IEnumerable <CalculationFundingLine> calculationFundingLines = GetCalculationFundingLines(template, templateId.GetValueOrDefault());

            await CacheCalculationFundingLines(cacheKey, calculationFundingLines.ToArray());

            return(new OkObjectResult(calculationFundingLines));
        }
예제 #22
0
        private async Task <TemplateMetadataContents> ReadTemplateMetadataContents(Reference fundingStream, SpecificationSummary specification)
        {
            TemplateMetadataContents templateMetadataContents =
                await _policiesService.GetTemplateMetadataContents(fundingStream.Id, specification.FundingPeriod.Id, specification.TemplateIds[fundingStream.Id]);

            if (templateMetadataContents == null)
            {
                throw new NonRetriableException($"Unable to get template metadata contents for funding stream. '{fundingStream.Id}'");
            }

            return(templateMetadataContents);
        }
        private void AndTheTemplateContentsCalculation(TemplateMappingItem mappingItem,
                                                       TemplateMetadataContents templateMetadataContents,
                                                       TemplateCalculation calculation)
        {
            calculation.TemplateCalculationId = mappingItem.TemplateId;

            FundingLine fundingLine = templateMetadataContents.RootFundingLines.First();

            fundingLine.Calculations = fundingLine.Calculations.Concat(new[]
            {
                calculation
            });
        }
예제 #24
0
        public async Task CreatesDDLMatchingSpecificationFundingAndReCreatesSchemaObjectsInQaRepository()
        {
            string specificationId         = NewRandomString();
            string fundingStreamId         = NewRandomString();
            string fundingPeriodId         = NewRandomString();
            string templateVersion         = NewRandomString();
            string schemaVersion           = NewRandomString();
            string fundingTemplateContents = NewRandomString();

            Calculation calculationOne   = NewCalculation();
            Calculation calculationTwo   = NewCalculation();
            Calculation calculationThree = NewCalculation();
            Calculation calculationFour  = NewCalculation(_ => _.WithCalculations(calculationOne));
            Calculation calculationFive  = NewCalculation(_ => _.WithCalculations(calculationTwo));

            string fundingLineOneCode = NewRandomString();
            string fundingLineTwoCode = NewRandomString();

            SpecificationSummary specificationSummary = NewSpecificationSummary(_ => _.WithId(specificationId)
                                                                                .WithFundingStreamIds(fundingStreamId)
                                                                                .WithFundingPeriodId(fundingPeriodId)
                                                                                .WithTemplateIds((fundingStreamId, templateVersion)));
            FundingTemplateContents fundingTemplate = NewFundingTemplateContents(_ => _.WithSchemaVersion(schemaVersion)
                                                                                 .WithTemplateFileContents(fundingTemplateContents));
            TemplateMetadataContents templateMetadataContents = NewTemplateMetadataContents(_ => _.WithFundingLines(
                                                                                                NewFundingLine(fl => fl.WithCalculations(calculationFour,
                                                                                                                                         calculationFive)
                                                                                                               .WithFundingLineCode(fundingLineOneCode)
                                                                                                               .WithFundingLines(NewFundingLine(fl1 => fl1.WithCalculations(calculationThree)
                                                                                                                                                .WithFundingLineCode(fundingLineTwoCode)))
                                                                                                               )));

            FundingStreamPeriodProfilePattern profilePatternOne = NewFundingStreamPeriodProfilePattern(_ =>
                                                                                                       _.WithFundingPeriodId(fundingPeriodId)
                                                                                                       .WithFundingStreamId(fundingStreamId)
                                                                                                       .WithFundingLineId(fundingLineOneCode));
            FundingStreamPeriodProfilePattern profilePatternTwo = NewFundingStreamPeriodProfilePattern(_ =>
                                                                                                       _.WithFundingPeriodId(fundingPeriodId)
                                                                                                       .WithFundingStreamId(fundingStreamId)
                                                                                                       .WithFundingLineId(fundingLineTwoCode));

            GivenTheSpecification(specificationId, specificationSummary);
            AndTheFundingTemplate(fundingStreamId, fundingPeriodId, templateVersion, fundingTemplate);
            AndTheTemplateMetadataContents(schemaVersion, fundingTemplateContents, templateMetadataContents);
            AndTheProfiling(fundingStreamId, fundingPeriodId, profilePatternOne, profilePatternTwo);

            await WhenTheSchemaIsRecreated(specificationId, fundingStreamId);

            ThenTheTotalNumberOfDDLScriptsExecutedWas(32);
        }
        private async Task <IActionResult> GetPublishedProviderFundingStructure(PublishedProviderVersion publishedProviderVersion)
        {
            Guard.ArgumentNotNull(publishedProviderVersion, nameof(publishedProviderVersion));

            string specificationId = publishedProviderVersion.SpecificationId;
            string fundingStreamId = publishedProviderVersion.FundingStreamId;
            string fundingPeriodId = publishedProviderVersion.FundingPeriodId;

            SpecificationSummary specificationSummary = await _specificationService.GetSpecificationSummaryById(specificationId);

            if (specificationSummary == null)
            {
                return(new NotFoundObjectResult($"Specification not found for SpecificationId - {specificationId}"));
            }

            string templateVersion = specificationSummary.TemplateIds.ContainsKey(fundingStreamId)
                ? specificationSummary.TemplateIds[fundingStreamId]
                : null;

            if (templateVersion == null)
            {
                return(new InternalServerErrorResult($"Specification contains no matching template version for funding stream '{fundingStreamId}'"));
            }

            TemplateMetadataContents fundingTemplateContents = await _policiesService.GetTemplateMetadataContents(fundingStreamId, fundingPeriodId, templateVersion);

            if (fundingTemplateContents == null)
            {
                return(new InternalServerErrorResult($"Unable to locate funding template contents for {fundingStreamId} {fundingPeriodId} {templateVersion}"));
            }

            TemplateMapping templateMapping = await _calculationsService.GetTemplateMapping(specificationId, fundingStreamId);

            List <PublishedProviderFundingStructureItem> fundingStructures = new List <PublishedProviderFundingStructureItem>();

            RecursivelyAddFundingLineToFundingStructure(
                fundingStructures,
                fundingTemplateContents.RootFundingLines,
                templateMapping.TemplateMappingItems.ToList(),
                publishedProviderVersion);

            PublishedProviderFundingStructure fundingStructure = new PublishedProviderFundingStructure
            {
                Items = fundingStructures,
                PublishedProviderVersion = publishedProviderVersion.Version
            };

            return(new OkObjectResult(fundingStructure));
        }
        private void AndTemplateMetadataContents()
        {
            _calculationTemplateIds = new[] { NewTemplateCalculation(),
                                              NewTemplateCalculation(),
                                              NewTemplateCalculation() };

            _fundingLines = new[] { NewTemplateFundingLine(fl => fl.WithCalculations(_calculationTemplateIds)) };

            _templateMetadataContents = NewTemplateMetadataContents(_ => _.WithFundingLines(_fundingLines));

            _policiesService
            .GetTemplateMetadataContents(FundingStreamId, _specificationSummary.FundingPeriod.Id,
                                         _specificationSummary.TemplateIds[FundingStreamId])
            .Returns(_templateMetadataContents);
        }
예제 #27
0
        public void TemplateMetadataSchema10_GetValidMetaData_ReturnsValidContents()
        {
            TemplateMetadataContents contents = WhenTheMetadataContentsIsGenerated("CalculateFunding.TemplateMetadata.Schema10.UnitTests.Resources.dsg1.0.json");

            contents.RootFundingLines.Count()
            .Should()
            .Be(2);

            contents.RootFundingLines.First().Name
            .Should()
            .Be("Prior To Recoupment");

            contents.RootFundingLines.First().Type
            .Should()
            .Be(FundingLineType.Information);

            contents.RootFundingLines.Last().Name
            .Should()
            .Be("Post Deduction For Recoupment And High Needs");

            contents.RootFundingLines.Last().FundingLineCode
            .Should()
            .Be("PostDeductionForRecoupmentAndHighNeeds");

            contents.RootFundingLines.Last().Calculations.First().ValueFormat
            .Should()
            .Be(CalculationValueFormat.Number);

            contents.RootFundingLines.Last().Calculations.First().AggregationType
            .Should()
            .Be(AggregationType.Sum);

            contents.RootFundingLines.Last().Calculations.First().Type
            .Should()
            .Be(CalculationType.PupilNumber);

            contents.RootFundingLines.Last().Calculations.First().ReferenceData.First().AggregationType
            .Should()
            .Be(AggregationType.Sum);

            contents.RootFundingLines.Last().Calculations.First().ReferenceData.First().Format
            .Should()
            .Be(ReferenceDataValueFormat.Number);

            contents.SchemaVersion
            .Should()
            .Be("1.0");
        }
        public void ThrowsExceptionIfCreateCallFailsWhenCreatingMissingCalculations()
        {
            TemplateMappingItem      mappingWithMissingCalculation1 = NewTemplateMappingItem();
            TemplateMapping          templateMapping          = NewTemplateMapping(_ => _.WithItems(mappingWithMissingCalculation1));
            TemplateMetadataContents templateMetadataContents = NewTemplateMetadataContents(_ => _.WithFundingLines(NewFundingLine(fl => fl.WithCalculations(NewTemplateMappingCalculation()))));
            TemplateCalculation      templateCalculationOne   = NewTemplateMappingCalculation(_ => _.WithName("template calculation 1"));

            GivenAValidMessage();
            AndTheJobCanBeRun();
            AndTheTemplateMapping(templateMapping);
            AndTheTemplateMetaDataContents(templateMetadataContents);
            AndTheTemplateContentsCalculation(mappingWithMissingCalculation1, templateMetadataContents, templateCalculationOne);
            AndTheSpecificationIsReturned();

            ThenAnExceptionShouldBeThrownWithMessage("Unable to create new default template calculation for template mapping");
        }
        public async Task <ActionResult <TemplateMetadataFundingLineCashCalculationsContents> > GetCashCalcsForTemplateVersion(string fundingStreamId, string fundingPeriodId, string templateVersion)
        {
            ActionResult <TemplateMetadataContents> templateMetadata = await GetFundingTemplateContentMetadata(fundingStreamId, fundingPeriodId, templateVersion);

            if (templateMetadata.Result != null)
            {
                return(templateMetadata.Result);
            }

            TemplateMetadataContents templateMetadataContents = templateMetadata.Value;

            IEnumerable <FundingLine> flattenedFundingLines  = templateMetadataContents.RootFundingLines.Flatten(x => x.FundingLines);
            IEnumerable <Calculation> flatternedCalculations = flattenedFundingLines.SelectMany(fl => fl.Calculations.Flatten(cal => cal.Calculations));

            IEnumerable <FundingLine> uniqueFundingLines = flattenedFundingLines.DistinctBy(f => f.TemplateLineId);

            IOrderedEnumerable <FundingLine> paymentFundingLine = uniqueFundingLines.Where(f => f.Type == Common.TemplateMetadata.Enums.FundingLineType.Payment).OrderBy(f => f.FundingLineCode);

            Dictionary <string, IEnumerable <TemplateMetadataCalculation> > cashCalculations = new Dictionary <string, IEnumerable <TemplateMetadataCalculation> >();

            List <TemplateMetadataFundingLine> fundingLineResults = new List <TemplateMetadataFundingLine>(paymentFundingLine.Count());

            foreach (FundingLine fundingLine in paymentFundingLine)
            {
                fundingLineResults.Add(new TemplateMetadataFundingLine()
                {
                    FundingLineCode = fundingLine.FundingLineCode,
                    Name            = fundingLine.Name,
                    TemplateLineId  = fundingLine.TemplateLineId,
                    Type            = Common.TemplateMetadata.Enums.FundingLineType.Payment,
                });

                List <TemplateMetadataCalculation> cashCalculationsForFundingLines = FindCashCalculations(fundingLine);

                cashCalculations.Add(fundingLine.FundingLineCode, cashCalculationsForFundingLines.OrderBy(_ => _.Name));
            }

            return(new TemplateMetadataFundingLineCashCalculationsContents()
            {
                FundingPeriodId = fundingPeriodId,
                FundingStreamId = fundingStreamId,
                SchemaVersion = templateMetadata.Value.SchemaVersion,
                TemplateVersion = templateMetadata.Value.TemplateVersion,
                FundingLines = fundingLineResults,
                CashCalculations = cashCalculations,
            });
        }
        private async Task <ActionResult <TemplateMetadataContents> > GetFundingTemplateContentMetadata(string fundingStreamId, string fundingPeriodId, string templateVersion)
        {
            TemplateMetadataContents fundingTemplateContentMetadata = await _cacheProvider.GetAsync <TemplateMetadataContents>($"{CacheKeys.FundingTemplateContentMetadata}{fundingStreamId}:{fundingPeriodId}:{templateVersion}");

            if (fundingTemplateContentMetadata == null)
            {
                ActionResult <string> fundingTemplateContentSourceFileResult = await GetFundingTemplateSourceFile(fundingStreamId, fundingPeriodId, templateVersion);

                if (fundingTemplateContentSourceFileResult.Result != null)
                {
                    return(fundingTemplateContentSourceFileResult.Result);
                }

                string fundingTemplateContentSourceFile = fundingTemplateContentSourceFileResult.Value;

                ActionResult <string> fundingTemplateValidationResult = GetFundingTemplateSchemaVersion(fundingTemplateContentSourceFile);
                if (fundingTemplateValidationResult.Result != null)
                {
                    return(fundingTemplateValidationResult.Result);
                }

                string fundingTemplateSchemaVersion = fundingTemplateValidationResult.Value;

                bool templateMetadataGeneratorRetrieved = _templateMetadataResolver.TryGetService(fundingTemplateSchemaVersion, out ITemplateMetadataGenerator templateMetadataGenerator);
                if (!templateMetadataGeneratorRetrieved)
                {
                    string message = $"Template metadata generator with given schema {fundingTemplateSchemaVersion} could not be retrieved.";
                    _logger.Error(message);

                    return(new PreconditionFailedResult(message));
                }

                string blobName = GetBlobNameFor(fundingStreamId, fundingPeriodId, templateVersion);

                fundingTemplateContentMetadata = templateMetadataGenerator.GetMetadata(fundingTemplateContentSourceFile);

                fundingTemplateContentMetadata.FundingStreamId = fundingStreamId;
                fundingTemplateContentMetadata.FundingPeriodId = fundingPeriodId;
                fundingTemplateContentMetadata.TemplateVersion = templateVersion;
                fundingTemplateContentMetadata.LastModified    = await _fundingTemplateRepositoryPolicy.ExecuteAsync(() => _fundingTemplateRepository.GetLastModifiedDate(blobName));

                await _cacheProvider.SetAsync($"{CacheKeys.FundingTemplateContentMetadata}{fundingStreamId}:{fundingPeriodId}:{templateVersion}", fundingTemplateContentMetadata);
            }

            return(fundingTemplateContentMetadata);
        }