public async Task <IActionResult> PreviewProfilingChange(ProfilePreviewRequest request) { Guard.ArgumentNotNull(request, nameof(request)); ReProfileRequest reProfileRequest = await _reProfilingRequestBuilder.BuildReProfileRequest(request.SpecificationId, request.FundingStreamId, request.FundingPeriodId, request.ProviderId, request.FundingLineCode, request.ProfilePatternKey, request.ConfigurationType); ApiResponse <ReProfileResponse> reProfilingApiResponse = await _profilingResilience.ExecuteAsync(() => _profiling.ReProfile(reProfileRequest)); ReProfileResponse reProfileResponse = reProfilingApiResponse?.Content; if (reProfileResponse == null) { throw new InvalidOperationException( $"Did not received a valid re-profiling response for profile pattern preview request {request}"); } ExistingProfilePeriod[] existingProfilePeriods = reProfileRequest.ExistingPeriods.ToArray(); int isPaidTo = GetIsPaidTo(existingProfilePeriods); ProfileTotal[] profileTotals = BuildProfileTotals(reProfileResponse, existingProfilePeriods, isPaidTo); await AddFundingDatesToProfileTotals(request, profileTotals); return(new OkObjectResult(profileTotals)); }
private static ProfileTotal[] BuildProfileTotals(ReProfileResponse reProfileResponse, ExistingProfilePeriod[] existingProfilePeriods, int isPaidTo) { return(reProfileResponse.DeliveryProfilePeriods.Select((deliveryProfilePeriod, installmentNumber) => new ProfileTotal { DistributionPeriodId = deliveryProfilePeriod.DistributionPeriod, Occurrence = deliveryProfilePeriod.Occurrence, Value = installmentNumber < isPaidTo ? existingProfilePeriods[installmentNumber].ProfileValue.GetValueOrDefault() : deliveryProfilePeriod.ProfileValue, Year = deliveryProfilePeriod.Year, InstallmentNumber = installmentNumber + 1, IsPaid = installmentNumber < isPaidTo, PeriodType = deliveryProfilePeriod.Type.ToString(), TypeValue = deliveryProfilePeriod.TypeValue }).ToArray()); }
public async Task ReProfilesFundingLinesInTheRefreshStateWhereTheyShowAsAffectedFundingLineCodes() { FundingLine fundingLineOne = NewFundingLine(); FundingLine fundingLineTwo = NewFundingLine(); FundingLine fundingLineThree = NewFundingLine(); ReProfileRequest reProfileRequestOne = NewReProfileRequest(); ReProfileRequest reProfileRequestThree = NewReProfileRequest(); ReProfileResponse reProfileResponseOne = NewReProfileResponse(); ReProfileResponse reProfileResponseThree = NewReProfileResponse(); DistributionPeriod[] distributionPeriodsOne = NewDistributionPeriods(); DistributionPeriod[] distributionPeriodsTwo = NewDistributionPeriods(); DistributionPeriod[] distributionPeriodsThree = NewDistributionPeriods(); fundingLineOne.DistributionPeriods = NewDistributionPeriods(_ => _.WithDistributionPeriodId(distributionPeriodsOne.Single().DistributionPeriodId)); fundingLineTwo.DistributionPeriods = distributionPeriodsTwo; fundingLineThree.DistributionPeriods = NewDistributionPeriods(_ => _.WithDistributionPeriodId(distributionPeriodsThree.Single().DistributionPeriodId)); GivenTheFundingLines(fundingLineOne, fundingLineTwo, fundingLineThree); AndTheAffectedFundingLineCodes(fundingLineOne.FundingLineCode, fundingLineThree.FundingLineCode); AndTheTheReProfileRequest(fundingLineOne, reProfileRequestOne); AndTheTheReProfileRequest(fundingLineThree, reProfileRequestThree); AndTheReProfileResponse(reProfileRequestOne, reProfileResponseOne); AndTheReProfileResponse(reProfileRequestThree, reProfileResponseThree); AndTheReProfileResponseMapping(reProfileResponseOne, distributionPeriodsOne); AndTheReProfileResponseMapping(reProfileResponseThree, distributionPeriodsThree); await WhenTheChangeIsApplied(); fundingLineOne.DistributionPeriods .Should() .BeEquivalentTo <DistributionPeriod>(distributionPeriodsOne); fundingLineTwo.DistributionPeriods .Should() .BeSameAs(distributionPeriodsTwo); fundingLineThree.DistributionPeriods .Should() .BeEquivalentTo <DistributionPeriod>(distributionPeriodsThree); }
private async Task ReProfileFundingLine(string fundingLineCode, PublishedProviderVersion refreshState, IApplyProviderVariations variationApplications) { FundingLine fundingLine = refreshState.FundingLines.SingleOrDefault(_ => _.FundingLineCode == fundingLineCode); string providerId = refreshState.ProviderId; if (fundingLine == null) { throw new NonRetriableException($"Could not locate funding line {fundingLineCode} for published provider version {providerId}"); } ReProfileRequest reProfileRequest = await variationApplications.ReProfilingRequestBuilder.BuildReProfileRequest(refreshState.SpecificationId, refreshState.FundingStreamId, refreshState.FundingPeriodId, providerId, fundingLineCode, null, ProfileConfigurationType.RuleBased, fundingLine.Value); ReProfileResponse reProfileResponse = (await variationApplications.ResiliencePolicies.ProfilingApiClient.ExecuteAsync(() => variationApplications.ProfilingApiClient.ReProfile(reProfileRequest)))?.Content; if (reProfileResponse == null) { throw new NonRetriableException($"Could not re profile funding line {fundingLineCode} for provider {providerId}"); } IEnumerable <DistributionPeriod> distributionPeriods = variationApplications.ReProfilingResponseMapper.MapReProfileResponseIntoDistributionPeriods(reProfileResponse); foreach (DistributionPeriod distributionPeriod in distributionPeriods) { refreshState.UpdateDistributionPeriodForFundingLine(fundingLineCode, distributionPeriod.DistributionPeriodId, distributionPeriod.ProfilePeriods); } }
private async Task ReProfileFundingLine(PublishedProviderVersion newPublishedProviderVersion, ProfilePatternKey profilePatternKey, string fundingLineCode, FundingLine fundingLine) { ReProfileRequest reProfileRequest = await _profilingRequestBuilder.BuildReProfileRequest(newPublishedProviderVersion.SpecificationId, newPublishedProviderVersion.FundingStreamId, newPublishedProviderVersion.FundingPeriodId, newPublishedProviderVersion.ProviderId, fundingLineCode, profilePatternKey.Key, ProfileConfigurationType.Custom, fundingLine.Value); ReProfileResponse reProfileResponse = (await _profilingPolicy.ExecuteAsync(() => _profiling.ReProfile(reProfileRequest)))?.Content; if (reProfileResponse == null) { string error = $"Unable to re-profile funding line {fundingLineCode} on specification {newPublishedProviderVersion.SpecificationId} with profile pattern {profilePatternKey.Key}"; _logger.Error(error); throw new InvalidOperationException(error); } fundingLine.DistributionPeriods = _reProfilingResponseMapper.MapReProfileResponseIntoDistributionPeriods(reProfileResponse); newPublishedProviderVersion.RemoveCarryOver(fundingLineCode); if (reProfileResponse.CarryOverAmount > 0) { newPublishedProviderVersion.AddCarryOver(fundingLineCode, ProfilingCarryOverType.CustomProfile, reProfileResponse.CarryOverAmount); } }
public IEnumerable <DistributionPeriod> MapReProfileResponseIntoDistributionPeriods(ReProfileResponse reProfileResponse) => reProfileResponse.DeliveryProfilePeriods.GroupBy(_ => _.DistributionPeriod) .Select(_ => new DistributionPeriod { Value = _.Sum(profilePeriod => profilePeriod.ProfileValue), DistributionPeriodId = _.Key, ProfilePeriods = _.Select(profilePeriod => new ProfilePeriod { DistributionPeriodId = _.Key, Occurrence = profilePeriod.Occurrence, Type = profilePeriod.Type.AsMatchingEnum <ProfilePeriodType>(), Year = profilePeriod.Year, ProfiledValue = profilePeriod.ProfileValue, TypeValue = profilePeriod.TypeValue }) });
public async Task ReProfilesFundingLineAndMapsResultsIntoProfileTotals() { ProfilePreviewRequest previewRequest = NewProfilePreviewRequest(); string distributionPeriod = NewRandomString(); ReProfileRequest expectedReProfileRequest = NewReProfileRequest(_ => _.WithFundingLineTotal(999) .WithExistingFundingLineTotal(1000) .WithExistingProfilePeriods(NewExistingProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("January") .WithValue(23) .WithYear(2021) .WithOccurrence(0)), NewExistingProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("January") .WithValue(24) .WithYear(2021) .WithOccurrence(1)), NewExistingProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("February") .WithValue(null) .WithYear(2021) .WithOccurrence(0)), NewExistingProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("March") .WithValue(null) .WithYear(2021) .WithOccurrence(0)), NewExistingProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("April") .WithValue(null) .WithYear(2021) .WithOccurrence(0)), NewExistingProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("May") .WithValue(null) .WithYear(2021) .WithOccurrence(0)) )); ReProfileResponse expectedReProfileResponse = NewReProfileResponse(_ => _.WithCarryOverAmount(992) .WithDeliveryProfilePeriods(NewDeliveryProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("January") .WithValue(33) .WithYear(2021) .WithOccurrence(0)), NewDeliveryProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("January") .WithValue(34) .WithYear(2021) .WithOccurrence(1)), NewDeliveryProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("February") .WithValue(35) .WithYear(2021) .WithOccurrence(0)), NewDeliveryProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("March") .WithValue(36) .WithYear(2021) .WithOccurrence(0)), NewDeliveryProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("April") .WithValue(37) .WithYear(2021) .WithOccurrence(0)), NewDeliveryProfilePeriod(exp => exp.WithDistributionPeriod(distributionPeriod) .WithPeriodType(PeriodType.CalendarMonth) .WithTypeValue("May") .WithValue(38) .WithYear(2021) .WithOccurrence(0)))); DateTimeOffset expectedActualDateOne = NewRandomDate(); DateTimeOffset expectedActualDateTwo = NewRandomDate(); DateTimeOffset expectedActualDateThree = NewRandomDate(); DateTimeOffset expectedActualDateFour = NewRandomDate(); FundingDate expectedFundingDate = NewFundingDate(_ => _.WithPatterns(NewFundingDatePattern(fdp => fdp.WithOccurrence(0) .WithPeriod("January") .WithPeriodYear(2021) .WithPaymentDate(expectedActualDateOne)), NewFundingDatePattern(fdp => fdp.WithOccurrence(0) .WithPeriod("February") .WithPeriodYear(2021) .WithPaymentDate(expectedActualDateTwo)), NewFundingDatePattern(fdp => fdp.WithOccurrence(0) .WithPeriod("April") .WithPeriodYear(2021) .WithPaymentDate(expectedActualDateThree)), NewFundingDatePattern(fdp => fdp.WithOccurrence(0) .WithPeriod("May") .WithPeriodYear(2021) .WithPaymentDate(expectedActualDateFour)), NewFundingDatePattern())); GivenTheReProfileRequest(previewRequest, expectedReProfileRequest); AndTheReProfileResponse(expectedReProfileRequest, expectedReProfileResponse); AndTheFundingDate(previewRequest, expectedFundingDate); OkObjectResult response = await WhenTheProfilePatternChangeIsPreviewed(previewRequest) as OkObjectResult; response? .Value .Should() .BeEquivalentTo(new [] { NewProfileTotal(_ => _.WithOccurrence(0) .WithDistributionPeriod(distributionPeriod) .WithValue(23) .WithYear(2021) .WithPeriodType("CalenderMonth") .WithTypeValue("January") .WithIsPaid(true) .WithInstallmentNumber(1) .WithActualDate(expectedActualDateOne)), NewProfileTotal(_ => _.WithOccurrence(1) .WithDistributionPeriod(distributionPeriod) .WithValue(24) .WithYear(2021) .WithPeriodType("CalenderMonth") .WithTypeValue("January") .WithIsPaid(true) .WithInstallmentNumber(2) .WithActualDate(null)), NewProfileTotal(_ => _.WithOccurrence(0) .WithDistributionPeriod(distributionPeriod) .WithValue(35) .WithYear(2021) .WithPeriodType("CalenderMonth") .WithTypeValue("February") .WithIsPaid(false) .WithInstallmentNumber(3) .WithActualDate(expectedActualDateTwo)), NewProfileTotal(_ => _.WithOccurrence(0) .WithDistributionPeriod(distributionPeriod) .WithValue(36) .WithYear(2021) .WithPeriodType("CalenderMonth") .WithTypeValue("March") .WithIsPaid(false) .WithInstallmentNumber(4) .WithActualDate(null)), NewProfileTotal(_ => _.WithOccurrence(0) .WithDistributionPeriod(distributionPeriod) .WithValue(37) .WithYear(2021) .WithPeriodType("CalenderMonth") .WithTypeValue("April") .WithIsPaid(false) .WithInstallmentNumber(5) .WithActualDate(expectedActualDateThree)), NewProfileTotal(_ => _.WithOccurrence(0) .WithDistributionPeriod(distributionPeriod) .WithValue(38) .WithYear(2021) .WithPeriodType("CalenderMonth") .WithTypeValue("May") .WithIsPaid(false) .WithInstallmentNumber(6) .WithActualDate(expectedActualDateFour)) }); }
private void AndTheReProfileResponse(ReProfileRequest request, ReProfileResponse expectedResponse) => _profiling.Setup(_ => _.ReProfile(request)) .ReturnsAsync(new ApiResponse <ReProfileResponse>(HttpStatusCode.OK, expectedResponse));
public async Task AssignProfilePatternKeyForFundingLineWithAlreadyPaidProfilePeriodsUsesReProfileResponseResultsFromApi() { string fundingLineCode = NewRandomString(); string existingProfilePatternKey = NewRandomString(); string newProfilePatterFundingKey = NewRandomString(); string specificationId = NewRandomString(); int occurence = NewRandomNumberBetween(1, 100); ProfilePeriodType profilePeriodType = NewRandomEnum <ProfilePeriodType>(); string typeValue = NewRandomString(); int year = NewRandomNumberBetween(2019, 2021); string distributionPeriodId = NewRandomString(); decimal carryOverAmount = NewRandomNumberBetween(1, int.MaxValue); GivenTheFundingConfiguration(true); ProfilePatternKey profilePatternKey = NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode).WithKey(newProfilePatterFundingKey)); ProfilePeriod paidProfilePeriod = NewProfilePeriod(pp => pp .WithDistributionPeriodId(distributionPeriodId) .WithType(profilePeriodType) .WithTypeValue(typeValue) .WithYear(year) .WithOccurence(occurence)); FundingLine fundingLine = NewFundingLine(_ => _ .WithFundingLineCode(fundingLineCode) .WithDistributionPeriods( NewDistributionPeriod(dp => dp .WithDistributionPeriodId(distributionPeriodId) .WithProfilePeriods(paidProfilePeriod)) )); PublishedProviderVersion existingPublishedProviderVersion = NewPublishedProviderVersion(ppv => ppv .WithFundingStreamId(_fundingStreamId) .WithFundingPeriodId(_fundingPeriodId) .WithSpecificationId(specificationId) .WithProfilePatternKeys( NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode) .WithKey(existingProfilePatternKey))) .WithFundingLines(fundingLine) ); PublishedProvider publishedProvider = NewPublishedProvider(_ => _.WithCurrent(existingPublishedProviderVersion)); PublishedProviderCreateVersionRequest publishedProviderCreateVersionRequest = NewPublishedProviderCreateVersionRequest(_ => _.WithPublishedProvider(publishedProvider) .WithNewVersion(existingPublishedProviderVersion)); IEnumerable <ProfileVariationPointer> profileVariationPointers = NewProfileVariationPointers(_ => _ .WithFundingLineId(fundingLineCode) .WithFundingStreamId(_fundingStreamId) .WithOccurence(occurence) .WithPeriodType(profilePeriodType.ToString()) .WithTypeValue(typeValue) .WithYear(year)); ReProfileRequest reProfileRequest = NewReProfileRequest(); ReProfileResponse reProfileResponse = NewReProfileResponse(_ => _.WithCarryOverAmount(carryOverAmount) .WithDeliveryProfilePeriods(NewDeliveryProfilePeriod(dpp => dpp.WithOccurrence(1) .WithValue(10) .WithYear(2021) .WithTypeValue("JANUARY") .WithPeriodType(PeriodType.CalendarMonth) .WithDistributionPeriod("dp1")), NewDeliveryProfilePeriod(dpp => dpp.WithOccurrence(1) .WithValue(20) .WithYear(2022) .WithTypeValue("JANUARY") .WithPeriodType(PeriodType.CalendarMonth) .WithDistributionPeriod("dp2")))); GivenThePublishedProvider(publishedProvider); AndThePublishedProviderCreateVersionRequest(publishedProvider, publishedProviderCreateVersionRequest); AndTheNewCreatedPublishedProvider(publishedProvider, publishedProviderCreateVersionRequest); AndTheProfileVariationPointers(profileVariationPointers, specificationId); AndTheReProfileRequest(existingPublishedProviderVersion.SpecificationId, existingPublishedProviderVersion.FundingStreamId, existingPublishedProviderVersion.FundingPeriodId, existingPublishedProviderVersion.ProviderId, profilePatternKey.FundingLineCode, profilePatternKey.Key, ProfileConfigurationType.Custom, fundingLine.Value, reProfileRequest); AndTheReProfileResponse(reProfileRequest, reProfileResponse); AndTheProfileFundingLines(profilePatternKey); AndTheSavePublishedProviderVersionResponse(HttpStatusCode.OK, existingPublishedProviderVersion); AndTheUpsertPublishedProviderResponse(HttpStatusCode.OK, publishedProvider); IActionResult result = await WhenProfilePatternKeyIsAssigned(_fundingStreamId, _fundingPeriodId, _providerId, profilePatternKey); ThenResultShouldBe(result, HttpStatusCode.OK); AndProfilePatternKeyWasUpdated(existingPublishedProviderVersion, profilePatternKey); fundingLine.DistributionPeriods .Count() .Should() .Be(2); DistributionPeriod firstDistributionPeriod = fundingLine.DistributionPeriods.SingleOrDefault(_ => _.DistributionPeriodId == "dp1"); firstDistributionPeriod.ProfilePeriods .Should() .BeEquivalentTo(NewProfilePeriod(_ => _.WithAmount(10) .WithTypeValue("JANUARY") .WithDistributionPeriodId("dp1") .WithType(ProfilePeriodType.CalendarMonth) .WithOccurence(1) .WithYear(2021))); DistributionPeriod secondDistributionPeriod = fundingLine.DistributionPeriods.SingleOrDefault(_ => _.DistributionPeriodId == "dp2"); secondDistributionPeriod.ProfilePeriods .Should() .BeEquivalentTo(NewProfilePeriod(_ => _.WithAmount(20) .WithTypeValue("JANUARY") .WithDistributionPeriodId("dp2") .WithType(ProfilePeriodType.CalendarMonth) .WithOccurence(1) .WithYear(2022))); existingPublishedProviderVersion.CarryOvers .Should() .BeEquivalentTo(NewCarryOver(_ => _.WithAmount(carryOverAmount) .WithFundingLineCode(fundingLineCode) .WithType(ProfilingCarryOverType.CustomProfile))); AndThePublishedProviderWasProcessed(publishedProvider); AndTheProfilingAuditWasUpdatedForTheFundingLine(publishedProvider, profilePatternKey.FundingLineCode, _author); }
private void AndTheReProfileResponseMapping(ReProfileResponse reProfileResponse, IEnumerable <DistributionPeriod> distributionPeriods) => _reProfilingResponseMapper.Setup(_ => _.MapReProfileResponseIntoDistributionPeriods(reProfileResponse)) .Returns(distributionPeriods);