public async Task AssignProfilePatternKeyReturnsBadRequestIfNewPublishedProviderVersionCreationFailed() { string fundingLineCode = NewRandomString(); string existingProfilePatternKey = NewRandomString(); string newProfilePatterFundingKey = NewRandomString(); GivenTheFundingConfiguration(true); ProfilePatternKey profilePatternKey = NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode).WithKey(newProfilePatterFundingKey)); FundingLine fundingLine = NewFundingLine(_ => _.WithFundingLineCode(fundingLineCode)); PublishedProviderVersion existingPublishedProviderVersion = NewPublishedProviderVersion(ppv => ppv .WithFundingStreamId(_fundingStreamId) .WithFundingPeriodId(_fundingPeriodId) .WithProfilePatternKeys( NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode).WithKey(existingProfilePatternKey))) .WithFundingLines(fundingLine) ); PublishedProvider publishedProvider = NewPublishedProvider(_ => _.WithCurrent(existingPublishedProviderVersion)); GivenThePublishedProvider(publishedProvider); IActionResult result = await WhenProfilePatternKeyIsAssigned(_fundingStreamId, _fundingPeriodId, _providerId, profilePatternKey); ThenResultShouldBe(result, HttpStatusCode.BadRequest); }
public async Task AssignProfilePatternKeyReturnsNotModifiedIfMatchingProfilePatternKeyExists() { string fundingLineCode = NewRandomString(); string key = NewRandomString(); GivenTheFundingConfiguration(true); ProfilePatternKey profilePatternKey = NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode).WithKey(key)); PublishedProvider publishedProvider = NewPublishedProvider(_ => _.WithCurrent( NewPublishedProviderVersion(ppv => ppv.WithProfilePatternKeys( NewProfilePatternKey(ppk => ppk.WithFundingLineCode(fundingLineCode).WithKey(key)))))); GivenThePublishedProvider(publishedProvider); StatusCodeResult result = await WhenProfilePatternKeyIsAssigned(_fundingStreamId, _fundingPeriodId, _providerId, profilePatternKey) as StatusCodeResult; result .Should() .NotBeNull(); result .StatusCode .Should() .Be((int)HttpStatusCode.NotModified); }
public async Task <IActionResult> AssignProfilePatternKeyToPublishedProvider( [FromRoute] string fundingStreamId, [FromRoute] string fundingPeriodId, [FromRoute] string providerId, [FromBody] ProfilePatternKey profilePatternKey) { return(await _publishedProviderProfilingService.AssignProfilePatternKey( fundingStreamId, fundingPeriodId, providerId, profilePatternKey, Request.GetUserOrDefault())); }
public async Task <IActionResult> AssignProfilePatternKey( string fundingStreamId, string fundingPeriodId, string providerId, ProfilePatternKey profilePatternKey, Reference author) { Guard.IsNullOrWhiteSpace(fundingStreamId, nameof(fundingStreamId)); Guard.IsNullOrWhiteSpace(fundingPeriodId, nameof(fundingPeriodId)); Guard.IsNullOrWhiteSpace(providerId, nameof(providerId)); Guard.ArgumentNotNull(profilePatternKey, nameof(profilePatternKey)); PublishedProvider publishedProvider = await _publishingResiliencePolicy.ExecuteAsync(async() => await _publishedFundingRepository.GetPublishedProvider(fundingStreamId, fundingPeriodId, providerId)); if (publishedProvider == null) { return(new StatusCodeResult((int)HttpStatusCode.NotFound)); } FundingConfiguration fundingConfiguration = await _policiesService.GetFundingConfiguration(fundingStreamId, fundingPeriodId); if (fundingConfiguration == null || !fundingConfiguration.EnableUserEditableRuleBasedProfiles) { return(new BadRequestObjectResult($"User not allowed to edit rule based profiles for funding stream - '{fundingStreamId}' and funding period - '{fundingPeriodId}'")); } if (MatchingProfilePatternKeyExists(publishedProvider.Current, profilePatternKey)) { return(new StatusCodeResult((int)HttpStatusCode.NotModified)); } PublishedProvider modifiedPublishedProvider = await CreateVersion(publishedProvider, author); if (modifiedPublishedProvider == null) { return(new StatusCodeResult((int)HttpStatusCode.BadRequest)); } PublishedProviderVersion newPublishedProviderVersion = publishedProvider.Current; newPublishedProviderVersion.SetProfilePatternKey(profilePatternKey, author); await ProfileFundingLineValues(newPublishedProviderVersion, profilePatternKey); await _publishedProviderErrorDetection.ProcessPublishedProvider(publishedProvider, _ => _ is FundingLineValueProfileMismatchErrorDetector); await SavePublishedProvider(publishedProvider, newPublishedProviderVersion); return(new StatusCodeResult((int)HttpStatusCode.OK)); }
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); }
public async Task AssignProfilePatternKeyReturnsNotFoundIfPublishedProviderDoesNotExist() { GivenThePublishedProvider(null); GivenTheFundingConfiguration(true); ProfilePatternKey profilePatternKey = NewProfilePatternKey(); StatusCodeResult result = await WhenProfilePatternKeyIsAssigned(_fundingStreamId, _fundingPeriodId, _providerId, profilePatternKey) as StatusCodeResult; result .Should() .NotBeNull(); result .StatusCode .Should() .Be((int)HttpStatusCode.NotFound); }
private static void EnsurePublishedProvidersHaveProfilePatternDetails(BatchProfilingResponseModel response, ProfilingBatch batch) { ProfilePatternKey profilePatternKey = new ProfilePatternKey { Key = response.ProfilePatternKey, FundingLineCode = batch.FundingLineCode }; foreach (PublishedProviderVersion publishedProviderVersion in batch.PublishedProviders) { lock (publishedProviderVersion) { publishedProviderVersion.SetProfilePatternKey(profilePatternKey.DeepCopy()); } } }
public async Task <IActionResult> AssignProfilePatternKeyToPublishedProvider( [FromRoute] string fundingStreamId, [FromRoute] string fundingPeriodId, [FromRoute] string providerId, [FromBody] ProfilePatternKey profilePatternKey) { Guard.ArgumentNotNull(fundingStreamId, nameof(fundingStreamId)); Guard.ArgumentNotNull(fundingPeriodId, nameof(fundingPeriodId)); Guard.ArgumentNotNull(providerId, nameof(providerId)); Guard.ArgumentNotNull(profilePatternKey, nameof(profilePatternKey)); HttpStatusCode apiResponse = await _publishingApiClient.AssignProfilePatternKeyToPublishedProvider( fundingStreamId, fundingPeriodId, providerId, profilePatternKey); return(StatusCode((int)apiResponse)); }
public async Task AssignProfilePatternKeyReturnsOkAndUpdatesPatternKeyWithNewVersion() { string fundingLineCode = NewRandomString(); string existingProfilePatternKey = NewRandomString(); string newProfilePatterFundingKey = NewRandomString(); string specificationId = NewRandomString(); GivenTheFundingConfiguration(true); ProfilePatternKey profilePatternKey = NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode).WithKey(newProfilePatterFundingKey)); FundingLine fundingLine = NewFundingLine(_ => _.WithFundingLineCode(fundingLineCode)); PublishedProviderVersion existingPublishedProviderVersion = NewPublishedProviderVersion(ppv => ppv .WithFundingStreamId(_fundingStreamId) .WithSpecificationId(specificationId) .WithFundingPeriodId(_fundingPeriodId) .WithProfilePatternKeys( NewProfilePatternKey(_ => _.WithFundingLineCode(fundingLineCode).WithKey(existingProfilePatternKey))) .WithFundingLines(fundingLine) ); PublishedProvider publishedProvider = NewPublishedProvider(_ => _.WithCurrent(existingPublishedProviderVersion)); PublishedProviderVersion newPublishedProviderVersion = existingPublishedProviderVersion; PublishedProviderCreateVersionRequest publishedProviderCreateVersionRequest = NewPublishedProviderCreateVersionRequest(_ => _ .WithPublishedProvider(publishedProvider) .WithNewVersion(newPublishedProviderVersion)); GivenThePublishedProvider(publishedProvider); AndThePublishedProviderCreateVersionRequest(publishedProvider, publishedProviderCreateVersionRequest); AndTheNewCreatedPublishedProvider(publishedProvider, publishedProviderCreateVersionRequest); AndTheProfileVariationPointers(null, specificationId); AndTheProfileFundingLines(profilePatternKey); AndTheSavePublishedProviderVersionResponse(HttpStatusCode.OK, existingPublishedProviderVersion); AndTheUpsertPublishedProviderResponse(HttpStatusCode.OK, publishedProvider); IActionResult result = await WhenProfilePatternKeyIsAssigned(_fundingStreamId, _fundingPeriodId, _providerId, profilePatternKey); ThenResultShouldBe(result, HttpStatusCode.OK); AndProfilePatternKeyWasUpdated(newPublishedProviderVersion, profilePatternKey); AndThePublishedProviderWasProcessed(publishedProvider); AndTheProfilingAuditWasUpdatedForTheFundingLine(publishedProvider, profilePatternKey.FundingLineCode, _author); }
public void SetUp() { _customProfileService = new Mock <ICustomProfileService>(); _publishedProviderProfilingService = new Mock <IPublishedProviderProfilingService>(); _controller = new ProfilingActionsController( _publishedProviderProfilingService.Object, _customProfileService.Object); _fundingStreamId = NewRandomString(); _fundPeriodId = NewRandomString(); _providerId = NewRandomString(); _correlationId = NewRandomString(); _userId = NewRandomString(); _userName = NewRandomString(); _profilePatternKey = new ProfilePatternKey { FundingLineCode = NewRandomString(), Key = NewRandomString() }; HttpContext context = Substitute.For <HttpContext>(); HttpRequest request = Substitute.For <HttpRequest>(); ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Sid, _userId), new Claim(ClaimTypes.Name, _userName) })); context.Request.Returns(request); request.HttpContext.Returns(context); context.User.Returns(claimsPrincipal); _controller.ControllerContext = new ControllerContext { HttpContext = context }; request.Headers.Returns(new HeaderDictionary(new Dictionary <string, StringValues> { { "sfa-correlationId", new StringValues(_correlationId) } })); }
private void AndTheProfileFundingLines(ProfilePatternKey profilePatternKey) { _profilingService.Setup(_ => _.ProfileFundingLines( It.Is <IEnumerable <FundingLine> >(fl => FundingLinesMatches(fl)), It.Is <string>(fs => fs == _fundingStreamId), It.Is <string>(fp => fp == _fundingPeriodId), It.Is <IEnumerable <ProfilePatternKey> >(ppk => ppk.Any(k => k.FundingLineCode == profilePatternKey.FundingLineCode && k.Key == profilePatternKey.Key)), null, null) ).Returns <IEnumerable <FundingLine>, string, string, IEnumerable <ProfilePatternKey>, string, string>( (fundingLines, fs, fp, keys, pt, pst) => { FundingLine fundingLine = fundingLines.FirstOrDefault(); fundingLine.DistributionPeriods = NewDistributionPeriods( dp => dp .WithDistributionPeriodId(_distributionPeriod1Id) .WithProfilePeriods(NewProfilePeriods( pp => pp .WithAmount(_profilePeriod1ProfiledAmount) .WithOccurence(_profilePeriod1Occurence) .WithType(_profilePeriod1Type) .WithTypeValue(_profilePeriod1TypeValue) .WithYear(_profilePeriod1Year) ).ToArray()), dp => dp .WithDistributionPeriodId(_distributionPeriod2Id) .WithProfilePeriods(NewProfilePeriods( pp => pp .WithAmount(_profilePeriod2ProfiledAmount) .WithOccurence(_profilePeriod2Occurence) .WithType(_profilePeriod2Type) .WithTypeValue(_profilePeriod2TypeValue) .WithYear(_profilePeriod2Year) ).ToArray())).ToList(); return(Task.FromResult(ArraySegment <ProfilePatternKey> .Empty.AsEnumerable())); }); }
public async Task AssignProfilePatternKeyToPublishedProvider() { string fundingStreamId = NewRandomString(); string fundingPeriodId = NewRandomString(); string providerId = NewRandomString(); ProfilePatternKey profilePatternKey = new ProfilePatternKey { FundingLineCode = NewRandomString(), Key = NewRandomString() }; string expectedUri = $"publishedprovider/fundingStream/{fundingStreamId}/fundingPeriod/{fundingPeriodId}/provider/{providerId}"; GivenTheStatusCode(expectedUri, HttpStatusCode.OK, HttpMethod.Post); HttpStatusCode response = await _client.AssignProfilePatternKeyToPublishedProvider(fundingStreamId, fundingPeriodId, providerId, profilePatternKey); response .Should() .NotBeNull(); response .Should() .Be(HttpStatusCode.OK); }
public async Task AssignProfilePatternKeyReturnsBadRequestIfFundingConfigurationIsNotEnableedUserEditableRuleBasedProfiles() { string fundingLineCode = NewRandomString(); string key = NewRandomString(); PublishedProvider publishedProvider = NewPublishedProvider(_ => _.WithCurrent( NewPublishedProviderVersion(ppv => ppv.WithProfilePatternKeys( NewProfilePatternKey(ppk => ppk.WithFundingLineCode(fundingLineCode).WithKey(key)))))); GivenThePublishedProvider(publishedProvider); GivenTheFundingConfiguration(false); ProfilePatternKey profilePatternKey = NewProfilePatternKey(); BadRequestObjectResult result = await WhenProfilePatternKeyIsAssigned(_fundingStreamId, _fundingPeriodId, _providerId, profilePatternKey) as BadRequestObjectResult; result .Should() .NotBeNull(); result .Value .Should() .Be($"User not allowed to edit rule based profiles for funding stream - '{_fundingStreamId}' and funding period - '{_fundingPeriodId}'"); }
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); } }
private void AndProfilePatternKeyWasUpdated(PublishedProviderVersion publishedProviderVersion, ProfilePatternKey profilePatternKey) { Assert.AreEqual(publishedProviderVersion.ProfilePatternKeys.SingleOrDefault(_ => _.FundingLineCode == profilePatternKey.FundingLineCode), profilePatternKey); }
private bool MatchingProfilePatternKeyExists( PublishedProviderVersion publishedProviderVersion, ProfilePatternKey profilePatternKey) { return(publishedProviderVersion?.ProfilePatternKeys != null && publishedProviderVersion.ProfilePatternKeys.Contains(profilePatternKey)); }
private async Task ProfileFundingLine(FundingLine fundingLine, PublishedProviderVersion newPublishedProviderVersion, ProfilePatternKey profilePatternKey) { await _profilingService.ProfileFundingLines( new[] { fundingLine }, newPublishedProviderVersion.FundingStreamId, newPublishedProviderVersion.FundingPeriodId, new[] { profilePatternKey }); }
private async Task ProfileFundingLineValues(PublishedProviderVersion newPublishedProviderVersion, ProfilePatternKey profilePatternKey) { string fundingLineCode = profilePatternKey.FundingLineCode; FundingLine fundingLine = newPublishedProviderVersion.FundingLines.SingleOrDefault(_ => _.FundingLineCode == fundingLineCode); if (fundingLine == null) { string error = $"Did not locate a funding line with code {fundingLineCode} on published provider version {newPublishedProviderVersion.PublishedProviderId}"; _logger.Error(error); throw new InvalidOperationException(error); } ApiResponse <IEnumerable <ProfileVariationPointer> > variationPointersResponse = await _specificationResiliencePolicy.ExecuteAsync(() => _specificationsApiClient.GetProfileVariationPointers(newPublishedProviderVersion.SpecificationId)); IEnumerable <ProfileVariationPointer> profileVariationPointers = variationPointersResponse? .Content? .Where(_ => _.FundingLineId == fundingLineCode && _.FundingStreamId == newPublishedProviderVersion.FundingStreamId); if (ThereArePaidProfilePeriodsOnTheFundingLine(profileVariationPointers)) { await ReProfileFundingLine(newPublishedProviderVersion, profilePatternKey, fundingLineCode, fundingLine); } else { await ProfileFundingLine(fundingLine, newPublishedProviderVersion, profilePatternKey); } }
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 async Task <IActionResult> WhenProfilePatternKeyIsAssigned(string fundingStreamId, string fundingPeriodId, string providerId, ProfilePatternKey profilePatternKey) => await _service.AssignProfilePatternKey(fundingStreamId, fundingPeriodId, providerId, profilePatternKey, _author);