public async Task ZerosProfilesAfterProfileVariationPointersInSpecificationOnEachMatchingFundingLine() { string fundingLineOneId = NewRandomString(); string fundingLineTwoId = NewRandomString(); int year = 2020; int occurence = 1; string typeValue = "January"; GivenTheVariationPointersForTheSpecification(NewVariationPointer(_ => _.WithFundingLineId(fundingLineOneId) .WithOccurence(occurence) .WithYear(year) .WithTypeValue(typeValue)), NewVariationPointer(_ => _.WithFundingLineId(fundingLineTwoId) .WithOccurence(occurence) .WithYear(year) .WithTypeValue(typeValue))); decimal periodOneAmount = 293487M; ProfilePeriod periodOne = NewProfilePeriod(0, 2020, "January", periodOneAmount); ProfilePeriod periodTwo = NewProfilePeriod(1, 2020, "January", 2973864M); ProfilePeriod periodThree = NewProfilePeriod(0, 2020, "February", 123764M); ProfilePeriod periodFour = NewProfilePeriod(1, 2020, "January", 6487234M); ProfilePeriod periodFive = NewProfilePeriod(2, 2020, "January", 1290837M); AndTheFundingLines(NewFundingLine(_ => _.WithFundingLineCode(fundingLineOneId) .WithDistributionPeriods(NewDistributionPeriod(dp => dp.WithProfilePeriods(periodOne, periodTwo, periodThree)), NewDistributionPeriod(dp => dp.WithProfilePeriods(periodFour, periodFive))))); await WhenTheChangeIsApplied(); ThenProfilePeriodsShouldBeZeroAmount(periodTwo, periodThree, periodFive, periodFour); AndTheProfilePeriodAmountShouldBe(periodOne, periodOneAmount); }
private bool FundingLinesMatches(IEnumerable <FundingLine> fundingLines) { FundingLine fundingLine = fundingLines.FirstOrDefault(); if (fundingLine == null) { return(false); } ProfilePeriod firstProfilePeriod = fundingLine.DistributionPeriods?.SingleOrDefault(_ => _.DistributionPeriodId == _distributionPeriod1Id)?.ProfilePeriods.FirstOrDefault(); ProfilePeriod lastProfilePeriod = fundingLine.DistributionPeriods?.SingleOrDefault(_ => _.DistributionPeriodId == _distributionPeriod2Id)?.ProfilePeriods.FirstOrDefault(); if (firstProfilePeriod == null || lastProfilePeriod == null) { return(false); } return(firstProfilePeriod.ProfiledValue == _profilePeriod1ProfiledAmount && firstProfilePeriod.Occurrence == _profilePeriod1Occurence && firstProfilePeriod.Type == _profilePeriod1Type && firstProfilePeriod.TypeValue == _profilePeriod1TypeValue && firstProfilePeriod.Year == _profilePeriod1Year && lastProfilePeriod.ProfiledValue == _profilePeriod2ProfiledAmount && lastProfilePeriod.Occurrence == _profilePeriod2Occurence && lastProfilePeriod.Type == _profilePeriod2Type && lastProfilePeriod.TypeValue == _profilePeriod2TypeValue && lastProfilePeriod.Year == _profilePeriod2Year); }
public void ProjectsDistributionPeriodsAndProfilePeriodsOrderedByYearThenProfilePeriodMonthThenOccurence_ExampleOne() { ProfilePeriod lastPeriod = NewProfilePeriod(2, 2021, "December"); ProfilePeriod firstPeriod = NewProfilePeriod(0, 2020, "December"); ProfilePeriod secondPeriod = NewProfilePeriod(1, 2020, "December"); ProfilePeriod thirdPeriod = NewProfilePeriod(0, 2021, "January"); FundingLine fundingLine = NewFundingLine(_ => _.WithDistributionPeriods(NewDistributionPeriod( dp => dp.WithProfilePeriods(thirdPeriod, secondPeriod)), NewDistributionPeriod(dp => dp.WithProfilePeriods(lastPeriod, firstPeriod)))); ProfilePeriod[] orderedProfilePeriods = new YearMonthOrderedProfilePeriods(fundingLine) .ToArray(); orderedProfilePeriods[0] .Should() .BeSameAs(firstPeriod); orderedProfilePeriods[1] .Should() .BeSameAs(secondPeriod); orderedProfilePeriods[2] .Should() .BeSameAs(thirdPeriod); orderedProfilePeriods[3] .Should() .BeSameAs(lastPeriod); }
protected override void MakeAdjustmentsFromProfileVariationPointer(ProfileVariationPointer variationPointer) { FundingLine closedFundingLine = RefreshState.FundingLines? .SingleOrDefault(_ => _.FundingLineCode == variationPointer.FundingLineId); FundingLine successorFundingLine = SuccessorRefreshState?.FundingLines? .SingleOrDefault(_ => _.FundingLineCode == variationPointer.FundingLineId); if (closedFundingLine == null || successorFundingLine == null) { throw new ArgumentOutOfRangeException(nameof(variationPointer), $"Did not locate a funding line for variation pointer with fundingLineId {variationPointer.FundingLineId}"); } ProfilePeriod[] orderedClosedProfilePeriods = new YearMonthOrderedProfilePeriods(closedFundingLine) .ToArray(); ProfilePeriod[] orderedSuccessorProfilePeriods = new YearMonthOrderedProfilePeriods(successorFundingLine) .ToArray(); int variationPointerIndex = GetProfilePeriodIndexForVariationPoint(variationPointer, orderedClosedProfilePeriods); for (int profilePeriod = variationPointerIndex; profilePeriod < orderedClosedProfilePeriods.Length; profilePeriod++) { ProfilePeriod successorProfilePeriod = orderedSuccessorProfilePeriods[profilePeriod]; successorProfilePeriod.ProfiledValue = successorProfilePeriod.ProfiledValue + orderedClosedProfilePeriods[profilePeriod].ProfiledValue; } }
protected void AndTheProfilePeriodAmountShouldBe(ProfilePeriod profilePeriod, decimal expectedAmount) { profilePeriod .ProfiledValue .Should() .Be(expectedAmount); }
private DistributionPeriod[] NewDistributionPeriods(Action <DistributionPeriodBuilder> setUp = null) { DistributionPeriodBuilder distributionPeriodBuilder = new DistributionPeriodBuilder(); setUp?.Invoke(distributionPeriodBuilder); ProfilePeriod profilePeriodOne = NewProfilePeriod(); ProfilePeriod profilePeriodTwo = NewProfilePeriod(); distributionPeriodBuilder.WithProfilePeriods(profilePeriodOne, profilePeriodTwo); distributionPeriodBuilder.WithValue(profilePeriodOne.ProfiledValue + profilePeriodTwo.ProfiledValue); return(new [] { distributionPeriodBuilder.Build() }); }
private void AdjustPeriodsForUnderPayment(int variationPointerIndex, decimal latestPeriodAmount, ProfilePeriod[] orderedSnapShotProfilePeriods, ProfilePeriod[] orderRefreshProfilePeriods) { decimal amountAlreadyPaid = orderedSnapShotProfilePeriods.Take(variationPointerIndex).Sum(_ => _.ProfiledValue); decimal amountThatShouldHaveBeenPaid = latestPeriodAmount * variationPointerIndex; decimal amountUnderPaid = Math.Abs(amountAlreadyPaid - amountThatShouldHaveBeenPaid); ProfilePeriod periodToAdjust = orderRefreshProfilePeriods[variationPointerIndex]; periodToAdjust.ProfiledValue = periodToAdjust.ProfiledValue + amountUnderPaid; }
private void AndPaidProfilePeriodExists(string distributionId, ProfilePeriod profilePeriod, ProfilePatternKey profilePatternKey) { _profilingService.Verify(_ => _.ProfileFundingLines(It.Is <IEnumerable <FundingLine> >(fl => PaidProfileFundingLinesMatches(fl, distributionId, profilePeriod)), _fundingStreamId, _fundingPeriodId, It.Is <IEnumerable <ProfilePatternKey> >(ppk => ppk.Any(k => k.FundingLineCode == profilePatternKey.FundingLineCode && k.Key == profilePatternKey.Key)), null, null), Times.Once); }
private IEnumerable <ExistingProfilePeriod> BuildExistingProfilePeriods(ProfilePeriod[] profilePeriods, int paidUpToIndex) { for (int period = 0; period < profilePeriods.Length; period++) { ProfilePeriod profilePeriod = profilePeriods[period]; yield return(new ExistingProfilePeriod { DistributionPeriod = profilePeriod.DistributionPeriodId, Occurrence = profilePeriod.Occurrence, Type = profilePeriod.Type.AsMatchingEnum <PeriodType>(), Year = profilePeriod.Year, TypeValue = profilePeriod.TypeValue, ProfileValue = period < paidUpToIndex ? profilePeriod.ProfiledValue : (decimal?)null }); } }
public void ThenTheUpsertedProviderVersionForHasTheFollowingFundingLineProfilePeriods(string providerId, IEnumerable <ExpectedFundingLineProfileValues> expectedFundingLineProfileValues) { PublishedProviderVersion publishedProviderVersion = GetUpsertedPublishedProviderVersion(providerId); foreach (ExpectedFundingLineProfileValues expectedFundingLineProfileValue in expectedFundingLineProfileValues) { FundingLine fundingLine = publishedProviderVersion.FundingLines.SingleOrDefault(_ => _.FundingLineCode == expectedFundingLineProfileValue.FundingLineCode); fundingLine .Should() .NotBeNull(); foreach (ExpectedDistributionPeriod expectedDistributionPeriod in expectedFundingLineProfileValue.ExpectedDistributionPeriods) { DistributionPeriod distributionPeriod = fundingLine.DistributionPeriods.SingleOrDefault(_ => _.DistributionPeriodId == expectedDistributionPeriod.DistributionPeriodId); distributionPeriod .Should() .NotBeNull(); foreach (ExpectedProfileValue expectedProfileValue in expectedDistributionPeriod.ExpectedProfileValues) { ProfilePeriod profilePeriod = distributionPeriod .ProfilePeriods.SingleOrDefault( _ => _.Type == expectedProfileValue.Type && _.TypeValue == expectedProfileValue.TypeValue && _.Year == expectedProfileValue.Year && _.Occurrence == expectedProfileValue.Occurrence); profilePeriod .Should() .NotBeNull(); profilePeriod .ProfiledValue .Should() .Be(expectedProfileValue.ProfiledValue); } } } }
public async Task SkipsProcessingPeriodIfAVariationPointerIsSet() { string fundingLineOneId = NewRandomString(); string fundingLineTwoId = NewRandomString(); int year = 2020; int occurence = 1; string typeValue = "January"; GivenTheVariationPointersForTheSpecification(NewVariationPointer(_ => _.WithFundingLineId(fundingLineOneId) .WithOccurence(occurence) .WithYear(year) .WithTypeValue(typeValue)), NewVariationPointer(_ => _.WithFundingLineId(fundingLineTwoId) .WithOccurence(occurence) .WithYear(year) .WithTypeValue(typeValue))); decimal periodOneAmount = 293487M; decimal periodTwoAmount = 2973864M; decimal periodThreeAmount = 123764M; decimal periodFourAmount = 6487234M; decimal periodFiveAmount = 1290837M; ProfilePeriod periodOne = NewProfilePeriod(0, 2020, "January", periodOneAmount); ProfilePeriod periodTwo = NewProfilePeriod(1, 2020, "January", periodTwoAmount); ProfilePeriod periodThree = NewProfilePeriod(0, 2020, "February", periodThreeAmount); ProfilePeriod periodFour = NewProfilePeriod(1, 2020, "January", periodFourAmount); ProfilePeriod periodFive = NewProfilePeriod(2, 2020, "January", periodFiveAmount); AndTheFundingLines(NewFundingLine(_ => _.WithFundingLineCode(fundingLineOneId) .WithDistributionPeriods(NewDistributionPeriod(dp => dp.WithProfilePeriods(periodOne, periodTwo, periodThree)), NewDistributionPeriod(dp => dp.WithProfilePeriods(periodFour, periodFive))))); await WhenTheChangeIsApplied(); AndTheProfilePeriodAmountShouldBe(periodOne, periodOneAmount); AndTheProfilePeriodAmountShouldBe(periodTwo, periodTwoAmount); AndTheProfilePeriodAmountShouldBe(periodThree, periodThreeAmount); AndTheProfilePeriodAmountShouldBe(periodFour, periodFourAmount); AndTheProfilePeriodAmountShouldBe(periodFive, periodFiveAmount); AndNoVariationChangesWereQueued(); }
public async Task OverridesProfilePeriodsOnPublishedProviderVersionAndGeneratesNewVersion(PublishedProviderStatus currentStatus, PublishedProviderStatus expectedRequestedStatus) { string fundingLineOne = NewRandomString(); ProfilePeriod profilePeriod1 = NewProfilePeriod(_ => _.WithDistributionPeriodId("FY-2021")); ProfilePeriod profilePeriod2 = NewProfilePeriod(_ => _.WithDistributionPeriodId("FY-2022")); ApplyCustomProfileRequest request = NewApplyCustomProfileRequest(_ => _ .WithFundingLineCode(fundingLineOne) .WithProfilePeriods(profilePeriod1, profilePeriod2)); PublishedProvider publishedProvider = NewPublishedProvider(_ => _.WithCurrent( NewPublishedProviderVersion(ppv => ppv.WithPublishedProviderStatus(currentStatus) .WithFundingLines(NewFundingLine(fl => fl.WithFundingLineCode(fundingLineOne) .WithDistributionPeriods(NewDistributionPeriod(dp => dp.WithDistributionPeriodId("FY-2021") .WithProfilePeriods(profilePeriod1)), NewDistributionPeriod(dp => dp.WithDistributionPeriodId("FY-2022") .WithProfilePeriods(profilePeriod2)))) )))); Reference author = NewAuthor(); GivenTheValidationResultForTheRequest(NewValidationResult(), request); AndThePublishedProvider(request.PublishedProviderId, publishedProvider); IActionResult result = await WhenTheCustomProfileIsApplied(request, author); result .Should() .BeOfType <NoContentResult>(); IEnumerable <ProfilePeriod> profilePeriods = request.ProfilePeriods; FundingLine fundingLine = publishedProvider.Current.FundingLines.Single(fl => fl.FundingLineCode == fundingLineOne); AndTheCustomProfilePeriodsWereUsedOn(fundingLine, profilePeriods); AndANewProviderVersionWasCreatedFor(publishedProvider, expectedRequestedStatus, author); AndProfilingAuditUpdatedForFundingLines(publishedProvider, new[] { fundingLineOne }, author); }
public async Task ZerosProfilesWhenNoVariationsPointersAreSetInSpecificationOnEachMatchingFundingLine() { string fundingLineOneId = NewRandomString(); int year = 2020; decimal periodOneAmount = 293487M; ProfilePeriod periodOne = NewProfilePeriod(0, year, "January", periodOneAmount); ProfilePeriod periodTwo = NewProfilePeriod(1, year, "January", 2973864M); ProfilePeriod periodThree = NewProfilePeriod(0, year, "February", 123764M); ProfilePeriod periodFour = NewProfilePeriod(1, year, "January", 6487234M); ProfilePeriod periodFive = NewProfilePeriod(2, year, "January", 1290837M); AndTheFundingLines(NewFundingLine(_ => _.WithFundingLineCode(fundingLineOneId) .WithFundingLineType(FundingLineType.Payment) .WithDistributionPeriods(NewDistributionPeriod(dp => dp.WithProfilePeriods(periodOne, periodTwo, periodThree)), NewDistributionPeriod(dp => dp.WithProfilePeriods(periodFour, periodFive))))); await WhenTheChangeIsApplied(); ThenProfilePeriodsShouldBeZeroAmount(periodOne, periodTwo, periodThree, periodFour, periodFive); }
private bool PaidProfileFundingLinesMatches(IEnumerable <FundingLine> fundingLines, string distributionId, ProfilePeriod profilePeriod) { FundingLine fundingLine = fundingLines.FirstOrDefault(); ProfilePeriod paidProfilePeriod = fundingLine .DistributionPeriods .SingleOrDefault(_ => _.DistributionPeriodId == distributionId) ?.ProfilePeriods .FirstOrDefault(); if (paidProfilePeriod == null) { return(false); } return(paidProfilePeriod.ProfiledValue == profilePeriod.ProfiledValue && paidProfilePeriod.Occurrence == profilePeriod.Occurrence && paidProfilePeriod.Type == profilePeriod.Type && paidProfilePeriod.TypeValue == profilePeriod.TypeValue && paidProfilePeriod.Year == profilePeriod.Year); }
private bool AdjustingPeriodsForOverPaymentLeavesRemainder(int variationPointerIndex, decimal latestPeriodAmount, ProfilePeriod[] orderedSnapShotProfilePeriods, ProfilePeriod[] orderRefreshProfilePeriods, out decimal remainingOverPayment) { decimal amountAlreadyPaid = orderedSnapShotProfilePeriods.Take(variationPointerIndex).Sum(_ => _.ProfiledValue); decimal amountThatShouldHaveBeenPaid = latestPeriodAmount * variationPointerIndex; remainingOverPayment = amountAlreadyPaid - amountThatShouldHaveBeenPaid; for (int profilePeriod = variationPointerIndex; profilePeriod < orderRefreshProfilePeriods.Length; profilePeriod++) { if (remainingOverPayment <= 0) { break; } ProfilePeriod periodToAdjust = orderRefreshProfilePeriods[profilePeriod]; decimal adjustedProfileValue = periodToAdjust.ProfiledValue - remainingOverPayment; if (adjustedProfileValue < 0) { remainingOverPayment = Math.Abs(adjustedProfileValue); adjustedProfileValue = 0; } else { remainingOverPayment = 0; } periodToAdjust.ProfiledValue = adjustedProfileValue; } return(remainingOverPayment != 0); }
private string AsLiteral(ProfilePeriod profilePeriod) { return($"{profilePeriod.Year}{profilePeriod.Type}{profilePeriod.TypeValue}{profilePeriod.Occurrence}{profilePeriod.ProfiledValue}"); }
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); }
protected void ThenTheProfilePeriodAmountShouldBe(ProfilePeriod profilePeriod, decimal expectedAmount) { AndTheProfilePeriodAmountShouldBe(profilePeriod, expectedAmount); }