From 0d9edf9b03d4537e9e70223a3cd222ca3c086720 Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Fri, 10 Mar 2023 15:33:54 +0000 Subject: [PATCH 01/10] Handle create cohort journey for learner verification --- .../Requests/CreateCohortRequest.cs | 1 + .../CohortControllerTests/CreateTests.cs | 4 +- .../Controllers/CohortController.cs | 3 +- .../VerifyLearnerResponse.cs | 60 ++++++ .../Commands/AddCohortCommandHandlerTests.cs | 28 +-- ...ToDraftApprenticeshipDetailsMapperTests.cs | 6 +- .../Services/CohortDomainServiceTests.cs | 184 +++++++++--------- .../CreateCohortRequestValidatorTests.cs | 6 + .../Commands/AddCohort/AddCohortCommand.cs | 52 ++--- .../Commands/AddCohort/AddCohortHandler.cs | 1 + .../Domain/Interfaces/ICohortDomainService.cs | 11 +- .../Services/CohortDomainService.cs | 171 +++++++++------- .../CreateCohortRequestValidator.cs | 1 + 13 files changed, 328 insertions(+), 200 deletions(-) create mode 100644 src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs index f8df74b4e4..c4c5671013 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs @@ -27,5 +27,6 @@ public class CreateCohortRequest : SaveDataRequest public DateTime? EmploymentEndDate { get; set; } public bool IgnoreStartDateOverlap { get; set; } public bool? IsOnFlexiPaymentPilot { get; set; } + public VerifyLearnerResponse LearnerValidationServiceResponseCode { get; set; } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs index d2778ea2e9..5593bfaa47 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs @@ -68,7 +68,9 @@ public CreateTestsFixture() c.Uln == Request.Uln && c.TransferSenderId == Request.TransferSenderId && c.PledgeApplicationId == Request.PledgeApplicationId && - c.UserInfo == Request.UserInfo), CancellationToken.None)) + c.UserInfo == Request.UserInfo && + c.IsOnFlexiPaymentPilot == Request.IsOnFlexiPaymentPilot && + c.LearnerValidationServiceResponseCode == Request.LearnerValidationServiceResponseCode), CancellationToken.None)) .ReturnsAsync(Result); } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs index ced0aab186..2b2c3cc123 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs @@ -65,7 +65,8 @@ public async Task Create([FromBody]CreateCohortRequest request) request.EmploymentEndDate, request.UserInfo, request.IgnoreStartDateOverlap, - request.IsOnFlexiPaymentPilot); + request.IsOnFlexiPaymentPilot, + request.LearnerValidationServiceResponseCode); var result = await _mediator.Send(command); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs new file mode 100644 index 0000000000..eb713bdeee --- /dev/null +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using System.ComponentModel; + +namespace SFA.DAS.CommitmentsV2.Types +{ + public enum LearnerValidationServiceResponseCode + { + [Description("WSVRC001")] + SuccessfulMatch, + + [Description("WSVRC002")] + SuccessfulLinkedMatch, + + [Description("WSVRC003")] + SimilarMatch, + + [Description("WSVRC004")] + SimilarLinkedMatch, + + [Description("WSVRC005")] + LearnerDoesNotMatch, + + [Description("WSVRC006")] + UlnNotFound + } + + public enum FailureFlag + { + [Description("VRF1")] + GivenDoesntMatchGiven, + + [Description("VRF2")] + GivenDoesntMatchFamily, + + [Description("VRF3")] + GivenDoesntMatchPreviousFamily, + + [Description("VRF4")] + FamilyDoesntMatchGiven, + + [Description("VRF5")] + FamilyDoesntMatchFamily, + + [Description("VRF6")] + FamilyDoesntMatchPreviousFamily, + + [Description("VRF7")] + DateOfBirthDoesntMatchDateOfBirth, + + [Description("VRF8")] + GenderDoesntMatchGender + } + + public class VerifyLearnerResponse + { + public LearnerValidationServiceResponseCode ResponseCode { get; set; } + + public IEnumerable FailureFlags { get; set; } + } +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs index 2638e25bfa..ca38a4d073 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs @@ -43,6 +43,7 @@ public async Task ShouldCreateCohort() fixtures.CohortDomainServiceMock.Verify(x => x.CreateCohort(providerId, accountId, accountLegalEntityId, transferSenderId, pledgeApplicationId, It.IsAny(), fixtures.UserInfo, + It.IsAny(), It.IsAny())); Assert.AreEqual(expectedHash, response.Reference); @@ -53,6 +54,10 @@ public class TestLogger : ILogger { private readonly List<(LogLevel logLevel, Exception exception, string message)> _logMessages = new List<(LogLevel logLevel, Exception exception, string message)>(); + public bool HasErrors => _logMessages.Any(l => l.logLevel == LogLevel.Error); + + public bool HasInfo => _logMessages.Any(l => l.logLevel == LogLevel.Information); + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { _logMessages.Add((logLevel, exception, formatter(state, exception))); @@ -67,17 +72,10 @@ public IDisposable BeginScope(TState state) { throw new NotImplementedException(); } - - public bool HasErrors => _logMessages.Any(l => l.logLevel == LogLevel.Error); - public bool HasInfo => _logMessages.Any(l => l.logLevel == LogLevel.Information); } public class AddCohortCommandHandlerTestFixture { - public ProviderCommitmentsDbContext Db { get; set; } - - public Mock Provider { get; set; } - public AddCohortCommandHandlerTestFixture() { Db = new ProviderCommitmentsDbContext(new DbContextOptionsBuilder() @@ -95,14 +93,18 @@ public AddCohortCommandHandlerTestFixture() commitment.Apprenticeships.Add(new DraftApprenticeship()); CohortDomainServiceMock = new Mock(); - CohortDomainServiceMock.Setup(x => x.CreateCohort(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny())) + CohortDomainServiceMock + .Setup(x => x.CreateCohort(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(commitment); Logger = new TestLogger(); UserInfo = new UserInfo(); } + public ProviderCommitmentsDbContext Db { get; set; } + + public Mock Provider { get; set; } public Mock EncodingServiceMock { get; } public IEncodingService EncodingService => EncodingServiceMock.Object; @@ -112,6 +114,7 @@ public AddCohortCommandHandlerTestFixture() public TestLogger Logger { get; } public UserInfo UserInfo { get; } + public VerifyLearnerResponse LearnerValidationResponseCode { get; } public AddCohortCommandHandlerTestFixture WithGeneratedHash(string hash) { @@ -125,12 +128,12 @@ public AddCohortCommandHandlerTestFixture WithGeneratedHash(string hash) public async Task Handle(long accountId, long accountLegalEntity, long providerId, long? transferSenderId, int? pledgeApplicationId, string courseCode) { Db.SaveChanges(); - + var command = new AddCohortCommand( accountId, accountLegalEntity, providerId, - courseCode, + courseCode, null, null, null, @@ -149,7 +152,8 @@ public async Task Handle(long accountId, long accountLegalEntit null, UserInfo, false, - false); + false, + LearnerValidationResponseCode); var handler = new AddCohortHandler(new Lazy(() => Db), EncodingService, diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs index 715ac7d414..6e109570f1 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs @@ -157,7 +157,7 @@ public AddCohortCommandToDraftApprenticeshipDetailsMapperTestsFixture() Command = new AddCohortCommand(command.AccountId, command.AccountLegalEntityId, command.ProviderId, courseCode, command.DeliveryModel, command.Cost, command.StartDate, command.ActualStartDate, command.EndDate, command.OriginatorReference, command.ReservationId, command.FirstName, command.LastName, command.Email, command.DateOfBirth, - command.Uln, command.TransferSenderId, command.PledgeApplicationId, command.EmploymentPrice, command.EmploymentEndDate, command.UserInfo, true, true); + command.Uln, command.TransferSenderId, command.PledgeApplicationId, command.EmploymentPrice, command.EmploymentEndDate, command.UserInfo, true, true, command.LearnerValidationServiceResponseCode); AuthorizationService = new Mock(); TrainingProgrammeLookup = new Mock(); @@ -194,7 +194,7 @@ private AddCohortCommand AddCohortCommandNoDate() return new AddCohortCommand(Command.AccountId, Command.AccountLegalEntityId, Command.ProviderId, Command.CourseCode, Command.DeliveryModel, Command.Cost, null, null, null, Command.OriginatorReference, Command.ReservationId, Command.FirstName, Command.LastName, Command.Email, Command.DateOfBirth, Command.Uln, - Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false); + Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false, Command.LearnerValidationServiceResponseCode); } public Task MapWithFramework() @@ -217,7 +217,7 @@ private AddCohortCommand CommandWithFramework() return new AddCohortCommand(Command.AccountId, Command.AccountLegalEntityId, Command.ProviderId, frameworkId, Command.DeliveryModel, Command.Cost, Command.StartDate, Command.ActualStartDate, Command.EndDate, Command.OriginatorReference, Command.ReservationId, Command.FirstName, Command.LastName, Command.Email, Command.DateOfBirth, Command.Uln, - Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false); + Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false, Command.LearnerValidationServiceResponseCode); } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs index e8aca18f09..52dcec1ce6 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs @@ -207,8 +207,6 @@ await _fixture _fixture.VerifyException(); } - - [Test] public async Task CreateCohortWithOtherParty_ThrowsBadRequest_WhenPledgeApplicationNotFound() { @@ -219,7 +217,6 @@ await _fixture _fixture.VerifyException(); } - [Test] public async Task CreateCohort_ThrowsBadRequest_WhenAccountIdDoesNotMatchAccountIdOnLegalEntity() { @@ -407,6 +404,7 @@ public async Task EmailOverlapOnApprenticeship_Validation(Party party, bool isAp await _fixture.WithParty(party).WithEmailOverlapWithApprenticeship(isApproved).CreateCohort(); _fixture.VerifyEmailOverlapExceptionOnApprenticeship(isApproved); } + [TestCase(Party.Provider)] [TestCase(Party.Employer)] public async Task EmailOverlapOnApprenticeship_Validation_FindsNoOverlaps(Party party) @@ -447,7 +445,7 @@ public void AddDraftApprenticeship_WhenCohortIsApprovedByAllParties_ShouldThrowE _fixture.WithExistingCohortApprovedByAllParties(Party.Employer); Assert.ThrowsAsync(() => _fixture.AddDraftApprenticeship()); } - + [Test] public void UpdateDraftApprenticeship_WhenCohortIsApprovedByAllParties_ShouldThrowException() { @@ -578,7 +576,7 @@ public async Task UpdateDraftApprenticeship_WhenContinuation_StartDateMustBeAfte .WithContinuation(overlap); await _fixture.UpdateDraftApprenticeship(); - if(expectThrow) + if (expectThrow) { _fixture.VerifyException(); } @@ -719,54 +717,6 @@ public async Task UpdateDraftApprenticeship_IsSuccessfulAndRPLHasNotPreviouslyBe public class CohortDomainServiceTestFixture { - public DateTime Now { get; set; } - public CohortDomainService CohortDomainService { get; set; } - public ProviderCommitmentsDbContext Db { get; set; } - public long ProviderId { get; } - public long AccountId { get; } - public long TransferSenderId { get; } - public string TransferSenderName { get; } - public int? PledgeApplicationId { get; } - public long AccountLegalEntityId { get; } - public long CohortId { get; } - public Party RequestingParty { get; private set; } - public string AccountLegalEntityPublicHashedId { get; } - public long ChangeOfPartyRequestId { get; } - public DraftApprenticeshipDetails DraftApprenticeshipDetails { get; } - public DraftApprenticeship ExistingDraftApprenticeship { get; } - public Apprenticeship PreviousApprenticeship { get; } - public long DraftApprenticeshipId { get; } - public Mock ChangeOfPartyRequest { get; } - public Account EmployerAccount { get; set; } - public Account TransferSenderAccount { get; set; } - public Mock Provider { get; set; } - public Mock AccountLegalEntity { get; set; } - public Cohort Cohort { get; set; } - public Cohort NewCohort { get; set; } - public Mock AcademicYearDateProvider { get; } - public Mock UlnValidator { get; } - public Mock ReservationValidationService { get; } - public Mock EmployerAgreementService { get; } - public Mock EncodingService { get; } - private Mock OverlapCheckService { get; } - private Mock EmailOptionalService { get; } - public Party Party { get; set; } - public Mock AuthenticationService { get; } - public Mock CurrentDateTime { get; set; } - public Mock AccountApiClient { get; set; } - public Mock LevyTransferMatchingApiClient { get; set; } - public Mock> FeatureTogglesService { get; set; } - public PledgeApplication PledgeApplication { get; set; } - public List TransferConnections { get; } - - public Exception Exception { get; private set; } - public List DomainErrors { get; } - public string Message { get; private set; } - public UserInfo UserInfo { get; private set; } - public ApprenticeshipPriorLearning PriorLearning{ get; private set; } - - public long MaLegalEntityId { get; private set; } - public CohortDomainServiceTestFixture() { Now = DateTime.UtcNow; @@ -792,17 +742,17 @@ public CohortDomainServiceTestFixture() Message = fixture.Create(); - NewCohort = new Cohort {Apprenticeships = new List {new DraftApprenticeship()}}; - - Provider = new Mock(()=> new Provider(ProviderId, "Test Provider", DateTime.UtcNow, DateTime.UtcNow)); + NewCohort = new Cohort { Apprenticeships = new List { new DraftApprenticeship() } }; + + Provider = new Mock(() => new Provider(ProviderId, "Test Provider", DateTime.UtcNow, DateTime.UtcNow)); Provider.Setup(x => x.CreateCohort(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(NewCohort); Db.Providers.Add(Provider.Object); EmployerAccount = new Account(AccountId, "AAAA", "BBBB", "Account 1", DateTime.UtcNow); Db.Accounts.Add(EmployerAccount); - AccountLegalEntity = new Mock(()=> - new AccountLegalEntity(EmployerAccount,AccountLegalEntityId,MaLegalEntityId,"test","ABC","Test",OrganisationType.CompaniesHouse,"test",DateTime.UtcNow)); + AccountLegalEntity = new Mock(() => + new AccountLegalEntity(EmployerAccount, AccountLegalEntityId, MaLegalEntityId, "test", "ABC", "Test", OrganisationType.CompaniesHouse, "test", DateTime.UtcNow)); AccountLegalEntity.Setup(x => x.CreateCohort(ProviderId, It.IsAny(), null, null, It.IsAny(), It.IsAny())) .Returns(NewCohort); @@ -834,26 +784,30 @@ public CohortDomainServiceTestFixture() TransferConnections = new List {new TransferConnectionViewModel {FundingEmployerAccountId = TransferSenderId}}; - DraftApprenticeshipId = fixture.Create(); DraftApprenticeshipDetails = new DraftApprenticeshipDetails { - FirstName = "Test", LastName = "Test", DeliveryModel = DeliveryModel.Regular, IgnoreStartDateOverlap = false, IsOnFlexiPaymentPilot = false + FirstName = "Test", + LastName = "Test", + DeliveryModel = DeliveryModel.Regular, + IgnoreStartDateOverlap = false, + IsOnFlexiPaymentPilot = false }; - ExistingDraftApprenticeship = new DraftApprenticeship { - Id = DraftApprenticeshipId, - CommitmentId = CohortId, - FirstName = fixture.Create(), - LastName = fixture.Create(), - Uln = "4860364820", - StartDate = DateTime.UtcNow, - EndDate = DateTime.UtcNow.AddYears(1), - CourseCode = fixture.Create(), - Cost = fixture.Create(), - IsOnFlexiPaymentPilot = false + ExistingDraftApprenticeship = new DraftApprenticeship + { + Id = DraftApprenticeshipId, + CommitmentId = CohortId, + FirstName = fixture.Create(), + LastName = fixture.Create(), + Uln = "4860364820", + StartDate = DateTime.UtcNow, + EndDate = DateTime.UtcNow.AddYears(1), + CourseCode = fixture.Create(), + Cost = fixture.Create(), + IsOnFlexiPaymentPilot = false }; ExistingDraftApprenticeship.SetValue(x => x.DateOfBirth, ExistingDraftApprenticeship.StartDate.Value.AddYears(-16)); @@ -884,7 +838,7 @@ public CohortDomainServiceTestFixture() OverlapCheckService = new Mock(); OverlapCheckService.Setup(x => x.CheckForOverlaps(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .ReturnsAsync(new OverlapCheckResult(false,false)); + .ReturnsAsync(new OverlapCheckResult(false, false)); OverlapCheckService.Setup(x => x.CheckForEmailOverlaps(It.IsAny(), It.IsAny())) .ReturnsAsync(new List()); @@ -892,20 +846,20 @@ public CohortDomainServiceTestFixture() EncodingService = new Mock(); AuthenticationService = new Mock(); - + CurrentDateTime = new Mock(); CurrentDateTime.Setup(d => d.UtcNow).Returns(Now); AccountApiClient = new Mock(); AccountApiClient.Setup(x => x.GetTransferConnections(It.IsAny())) .ReturnsAsync(TransferConnections); - + EmailOptionalService = new Mock(); PriorLearning = fixture.Create(); FeatureTogglesService = new Mock>(); - FeatureTogglesService.Setup(x=>x.GetFeatureToggle(Constants.RecognitionOfPriorLearningFeature)).Returns(new FeatureToggle { IsEnabled = false }); + FeatureTogglesService.Setup(x => x.GetFeatureToggle(Constants.RecognitionOfPriorLearningFeature)).Returns(new FeatureToggle { IsEnabled = false }); Exception = null; DomainErrors = new List(); @@ -929,9 +883,56 @@ public CohortDomainServiceTestFixture() Db.SaveChanges(); } + public DateTime Now { get; set; } + public CohortDomainService CohortDomainService { get; set; } + public ProviderCommitmentsDbContext Db { get; set; } + public long ProviderId { get; } + public long AccountId { get; } + public long TransferSenderId { get; } + public string TransferSenderName { get; } + public int? PledgeApplicationId { get; } + public long AccountLegalEntityId { get; } + public long CohortId { get; } + public Party RequestingParty { get; private set; } + public string AccountLegalEntityPublicHashedId { get; } + public long ChangeOfPartyRequestId { get; } + public DraftApprenticeshipDetails DraftApprenticeshipDetails { get; } + public DraftApprenticeship ExistingDraftApprenticeship { get; } + public Apprenticeship PreviousApprenticeship { get; } + public long DraftApprenticeshipId { get; } + public Mock ChangeOfPartyRequest { get; } + public Account EmployerAccount { get; set; } + public Account TransferSenderAccount { get; set; } + public Mock Provider { get; set; } + public Mock AccountLegalEntity { get; set; } + public Cohort Cohort { get; set; } + public Cohort NewCohort { get; set; } + public Mock AcademicYearDateProvider { get; } + public Mock UlnValidator { get; } + public Mock ReservationValidationService { get; } + public Mock EmployerAgreementService { get; } + public Mock EncodingService { get; } + public Party Party { get; set; } + public Mock AuthenticationService { get; } + public Mock CurrentDateTime { get; set; } + public Mock AccountApiClient { get; set; } + public Mock LevyTransferMatchingApiClient { get; set; } + public Mock> FeatureTogglesService { get; set; } + public PledgeApplication PledgeApplication { get; set; } + public List TransferConnections { get; } + public Exception Exception { get; private set; } + public List DomainErrors { get; } + public string Message { get; private set; } + public UserInfo UserInfo { get; private set; } + public VerifyLearnerResponse LearnerValidationResponseCode { get; private set; } + public ApprenticeshipPriorLearning PriorLearning { get; private set; } + public long MaLegalEntityId { get; private set; } + private Mock OverlapCheckService { get; } + private Mock EmailOptionalService { get; } + public CohortDomainServiceTestFixture WithPriorLearning() { - ExistingDraftApprenticeship.SetValue(x=>x.RecognisePriorLearning, true); + ExistingDraftApprenticeship.SetValue(x => x.RecognisePriorLearning, true); ExistingDraftApprenticeship.SetPriorLearningDetails(10, 100); return this; } @@ -956,7 +957,7 @@ public CohortDomainServiceTestFixture WithNoMessage() return this; } - public CohortDomainServiceTestFixture WithTrainingProgramme(ProgrammeType programmeType = ProgrammeType.Standard) + public CohortDomainServiceTestFixture WithTrainingProgramme(ProgrammeType programmeType = ProgrammeType.Standard) { DraftApprenticeshipDetails.TrainingProgramme = new SFA.DAS.CommitmentsV2.Domain.Entities.TrainingProgramme("TEST", "TEST", @@ -1099,7 +1100,7 @@ public CohortDomainServiceTestFixture WithCohortMappedToProviderAndAccountLegalE Cohort = new Cohort { Id = CohortId, - WithParty = withParty, + WithParty = withParty, Originator = creatingParty.ToOriginator(), EditStatus = (withParty == Party.Employer || withParty == Party.Provider) ? withParty.ToEditStatus() : EditStatus.Both, Provider = Provider.Object, @@ -1110,8 +1111,8 @@ public CohortDomainServiceTestFixture WithCohortMappedToProviderAndAccountLegalE TransferSenderId = null, }; - var cohorts = new List {Cohort}; - + var cohorts = new List { Cohort }; + Provider.Setup(x => x.Cohorts).Returns(cohorts); AccountLegalEntity.Setup(x => x.Cohorts).Returns(cohorts); @@ -1177,6 +1178,7 @@ public CohortDomainServiceTestFixture WithChangeOfEmployerCohort(Party withParty return this; } + public CohortDomainServiceTestFixture WithExistingCohortApprovedByAllParties(Party creatingParty) { WithCohortMappedToProviderAndAccountLegalEntity(creatingParty, Party.None); @@ -1231,7 +1233,6 @@ public CohortDomainServiceTestFixture WithExistingDraftApprenticeshipWithPriorLe return this; } - public CohortDomainServiceTestFixture WithOverlappingEmails() { var f = new Fixture(); @@ -1247,7 +1248,7 @@ public CohortDomainServiceTestFixture WithRPLRequired() .Returns(new FeatureToggle { IsEnabled = true }); return this; } - + public void VerifyCheckForEmailOverlapsOnCohortIsCalledCorrectlyWhenApproving() { OverlapCheckService.Verify(x => x.CheckForEmailOverlaps(CohortId, It.IsAny())); @@ -1263,7 +1264,7 @@ public CohortDomainServiceTestFixture WithContinuation(bool overlap) DraftApprenticeshipDetails.DateOfBirth = ExistingDraftApprenticeship.DateOfBirth; DraftApprenticeshipDetails.Uln = ExistingDraftApprenticeship.Uln; DraftApprenticeshipDetails.StartDate = ExistingDraftApprenticeship.StartDate; - DraftApprenticeshipDetails.TrainingProgramme = new SFA.DAS.CommitmentsV2.Domain.Entities.TrainingProgramme(ExistingDraftApprenticeship.CourseCode, "", ProgrammeType.Framework, Now,Now); + DraftApprenticeshipDetails.TrainingProgramme = new SFA.DAS.CommitmentsV2.Domain.Entities.TrainingProgramme(ExistingDraftApprenticeship.CourseCode, "", ProgrammeType.Framework, Now, Now); if (overlap) { @@ -1306,7 +1307,7 @@ public CohortDomainServiceTestFixture WithDecodeOfPublicHashedAccountLegalEntity public CohortDomainServiceTestFixture WithAgreementSignedAs(bool signed) { - EmployerAgreementService.Setup(x => x.IsAgreementSigned(It.IsAny(), It.IsAny(), + EmployerAgreementService.Setup(x => x.IsAgreementSigned(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(signed); return this; } @@ -1324,19 +1325,19 @@ public async Task CreateCohort(long? accountId = null, long? accountLega DomainErrors.Clear(); accountId = accountId ?? AccountId; - accountLegalEntityId = accountLegalEntityId ?? AccountLegalEntityId; + accountLegalEntityId = accountLegalEntityId ?? AccountLegalEntityId; try { var result = await CohortDomainService.CreateCohort(ProviderId, accountId.Value, accountLegalEntityId.Value, transferSenderId, pledgeApplicationId, - DraftApprenticeshipDetails, UserInfo, new CancellationToken()); + DraftApprenticeshipDetails, UserInfo, LearnerValidationResponseCode, new CancellationToken()); await Db.SaveChangesAsync(); return result; } catch (DomainException ex) { DomainErrors.AddRange(ex.DomainErrors); - if(Db.Cohorts.Contains(Cohort)) {Db.Cohorts.Remove(Cohort);} + if (Db.Cohorts.Contains(Cohort)) { Db.Cohorts.Remove(Cohort); } return null; } catch (Exception ex) @@ -1495,7 +1496,7 @@ public void VerifyCohortCreation(Party party) { if (party == Party.Provider) { - Provider.Verify(x => x.CreateCohort(ProviderId, It.Is(p=>p == AccountLegalEntity.Object), null, null, + Provider.Verify(x => x.CreateCohort(ProviderId, It.Is(p => p == AccountLegalEntity.Object), null, null, DraftApprenticeshipDetails, UserInfo)); } @@ -1575,7 +1576,7 @@ public void VerifyProviderDraftApprenticeshipAdded() public void VerifyDraftApprenticeshipUpdated() { - var updated = Cohort.DraftApprenticeships.SingleOrDefault(x=>x.Id == DraftApprenticeshipId); + var updated = Cohort.DraftApprenticeships.SingleOrDefault(x => x.Id == DraftApprenticeshipId); Assert.IsNotNull(updated, "No draft apprenticeship record found"); Assert.AreEqual(updated.FirstName, DraftApprenticeshipDetails.FirstName); @@ -1626,10 +1627,12 @@ public void VerifyLastUpdatedFieldsAreSet(Party withParty) Assert.AreEqual(Cohort.LastUpdatedByEmployerName, UserInfo.UserDisplayName); Assert.AreEqual(Cohort.LastUpdatedByEmployerEmail, UserInfo.UserEmail); break; + case Party.Provider: Assert.AreEqual(Cohort.LastUpdatedByProviderName, UserInfo.UserDisplayName); Assert.AreEqual(Cohort.LastUpdatedByProviderEmail, UserInfo.UserEmail); break; + default: Assert.Fail("Party must be provider or Employer"); break; @@ -1643,6 +1646,7 @@ public void VerifyLastUpdatedFieldsAreNotSet() Assert.IsNull(Cohort.LastUpdatedByProviderName); Assert.IsNull(Cohort.LastUpdatedByProviderEmail); } + public void VerifyStartDateException(bool passes) { if (passes) @@ -1764,7 +1768,7 @@ public void VerifyNoException() public void VerifyIsAgreementSignedIsCalledCorrectly() { - EmployerAgreementService.Verify(x => x.IsAgreementSigned(AccountId, MaLegalEntityId, + EmployerAgreementService.Verify(x => x.IsAgreementSigned(AccountId, MaLegalEntityId, It.IsAny())); } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs index aaca5f9e9a..e9f9ddb025 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs @@ -90,6 +90,12 @@ public void Validate_IsOnFlexiPaymentPilotIsNull_ShouldBeInvalid() AssertValidationResult(request => request.IsOnFlexiPaymentPilot, (bool?)null, false); } + [Test] + public void Validate_LearnerValidationServiceResponseCodeIsNull_ShouldBeInvalid() + { + AssertValidationResult(request => request.LearnerValidationServiceResponseCode, null, false); + } + private void AssertValidationResult(Expression> property, T value, bool expectedValid) { // Arrange diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs index 69d061f476..3aa6765b3d 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs @@ -6,37 +6,13 @@ namespace SFA.DAS.CommitmentsV2.Application.Commands.AddCohort { public class AddCohortCommand : IRequest { - public long AccountId { get; } - public long AccountLegalEntityId { get; } - public long ProviderId { get; } - public string CourseCode { get; } - public DeliveryModel? DeliveryModel { get; } - public int? Cost { get; } - public DateTime? StartDate { get; } - public DateTime? ActualStartDate { get; } - public DateTime? EndDate { get; } - public string OriginatorReference { get; } - public Guid? ReservationId { get; } - public string FirstName { get; } - public string LastName { get; } - public string Email { get; } - public DateTime? DateOfBirth { get; } - public string Uln { get; } - public long? TransferSenderId { get; } - public int? PledgeApplicationId { get; } - public int? EmploymentPrice { get; set; } - public DateTime? EmploymentEndDate { get; set; } - public UserInfo UserInfo { get; } - public bool IgnoreStartDateOverlap { get; set; } - public bool? IsOnFlexiPaymentPilot { get; set; } - public AddCohortCommand(long accountId, long accountLegalEntityId, long providerId, string courseCode, DeliveryModel? deliveryModel, int? cost, DateTime? startDate, DateTime? actualStartDate, DateTime? endDate, string originatorReference, Guid? reservationId, string firstName, string lastName, string email, DateTime? dateOfBirth, string uln, long? transferSenderId, int? pledgeApplicationId, int? employmentPrice, DateTime? employmentEndDate, UserInfo userInfo, bool ignoreStartDateOverlap, - bool? isOnFlexiPaymentPilot) + bool? isOnFlexiPaymentPilot, VerifyLearnerResponse learnerValidationResponseCode) { AccountId = accountId; AccountLegalEntityId = accountLegalEntityId; @@ -59,9 +35,35 @@ public AddCohortCommand(long accountId, long accountLegalEntityId, long provider EmploymentPrice = employmentPrice; EmploymentEndDate = employmentEndDate; IsOnFlexiPaymentPilot = isOnFlexiPaymentPilot; + LearnerValidationServiceResponseCode = learnerValidationResponseCode; UserInfo = userInfo ?? throw new ArgumentNullException(nameof(userInfo)); IgnoreStartDateOverlap = ignoreStartDateOverlap; } + + public long AccountId { get; } + public long AccountLegalEntityId { get; } + public long ProviderId { get; } + public string CourseCode { get; } + public DeliveryModel? DeliveryModel { get; } + public int? Cost { get; } + public DateTime? StartDate { get; } + public DateTime? ActualStartDate { get; } + public DateTime? EndDate { get; } + public string OriginatorReference { get; } + public Guid? ReservationId { get; } + public string FirstName { get; } + public string LastName { get; } + public string Email { get; } + public DateTime? DateOfBirth { get; } + public string Uln { get; } + public long? TransferSenderId { get; } + public int? PledgeApplicationId { get; } + public int? EmploymentPrice { get; set; } + public DateTime? EmploymentEndDate { get; set; } + public UserInfo UserInfo { get; } + public bool IgnoreStartDateOverlap { get; set; } + public bool? IsOnFlexiPaymentPilot { get; set; } + public VerifyLearnerResponse LearnerValidationServiceResponseCode { get; set; } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs index 24602bfd96..a8eb47f1b2 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs @@ -49,6 +49,7 @@ public async Task Handle(AddCohortCommand command, Cancellation command.PledgeApplicationId, draftApprenticeshipDetails, command.UserInfo, + command.LearnerValidationServiceResponseCode, cancellationToken); db.Cohorts.Add(cohort); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs index 2d075c0bfc..ff08ab17ee 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs @@ -11,14 +11,23 @@ namespace SFA.DAS.CommitmentsV2.Domain.Interfaces public interface ICohortDomainService { Task AddDraftApprenticeship(long providerId, long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken); + Task ApproveCohort(long cohortId, string message, UserInfo userInfo, Party? requestingParty, CancellationToken cancellationToken); - Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken); + + Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, VerifyLearnerResponse learnerValidationResponseCode, CancellationToken cancellationToken); + Task CreateCohortWithOtherParty(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, string message, UserInfo userInfo, CancellationToken cancellationToken); + Task CreateEmptyCohort(long providerId, long accountId, long accountLegalEntityId, UserInfo userInfo, CancellationToken cancellationToken); + Task SendCohortToOtherParty(long cohortId, string message, UserInfo userInfo, Party? requestingParty, CancellationToken cancellationToken); + Task UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken); + Task DeleteDraftApprenticeship(long cohortId, long apprenticeshipId, UserInfo userInfo, CancellationToken cancellationToken); + Task> AddDraftApprenticeships(List draftApprenticeships, List csvBulkUploadApprenticehips, long providerId, UserInfo userInfo, CancellationToken cancellationToken); + Task ValidateDraftApprenticeshipForOverlappingTrainingDateRequest(long providerId, long? cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 6400f45e06..af40b2ec2d 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -39,7 +39,7 @@ public class CohortDomainService : ICohortDomainService private readonly ICurrentDateTime _currentDateTime; private readonly IEmployerAgreementService _employerAgreementService; private readonly IEncodingService _encodingService; - private readonly IAccountApiClient _accountApiClient; + private readonly IAccountApiClient _accountApiClient; private readonly IEmailOptionalService _emailService; private readonly ILevyTransferMatchingApiClient _levyTransferMatchingApiClient; private readonly IFeatureTogglesService _featureTogglesService; @@ -54,7 +54,7 @@ public CohortDomainService(Lazy dbContext, ICurrentDateTime currentDateTime, IEmployerAgreementService employerAgreementService, IEncodingService encodingService, - IAccountApiClient accountApiClient, + IAccountApiClient accountApiClient, IEmailOptionalService emailOptionalService, ILevyTransferMatchingApiClient levyTransferMatchingApiClient, IFeatureTogglesService featureTogglesService) @@ -81,7 +81,7 @@ public async Task AddDraftApprenticeship(long providerId, l var cohort = await db.GetCohortAggregate(cohortId, cancellationToken); var party = _authenticationService.GetUserParty(); var draftApprenticeship = cohort.AddDraftApprenticeship(draftApprenticeshipDetails, party, userInfo); - await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohort.Id, cancellationToken); + //await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohort.Id, cancellationToken); //TODO return draftApprenticeship; } @@ -89,7 +89,7 @@ public async Task ValidateDraftApprenticeshipForOverlappingTrainingDateRequest(l { Cohort cohort = null; draftApprenticeshipDetails.IgnoreStartDateOverlap = true; - await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohortId, cancellationToken); + //await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohortId, cancellationToken); //TODO if (cohortId.HasValue && cohortId.Value > 0) { cohort = await _dbContext.Value.GetCohortAggregate(cohortId.Value, cancellationToken: cancellationToken); @@ -151,7 +151,7 @@ public async Task> AddDraftApprenticeships(List x.Value).Union(newCohorts.Select(x => x.Value)); @@ -175,22 +175,7 @@ public async Task ApproveCohort(long cohortId, string message, UserInfo userInfo cohort.Approve(party, message, userInfo, _currentDateTime.UtcNow, apprenticeEmailIsRequired, isRPLRequired); } - private async Task ValidateUlnOverlap(Cohort cohort) - { - foreach (var draftApprenticeship in cohort.DraftApprenticeships) - { - if (!string.IsNullOrEmpty(draftApprenticeship.Uln) && draftApprenticeship.StartDate.HasValue && draftApprenticeship.EndDate.HasValue) - { - var result = await _overlapCheckService.CheckForOverlaps(draftApprenticeship.Uln, draftApprenticeship.StartDate.Value.To(draftApprenticeship.EndDate.Value), draftApprenticeship.Id, CancellationToken.None); - if (result.HasOverlaps) - { - throw new DomainException(draftApprenticeship.Uln, "The draft apprenticeship has overlap"); - } - } - } - } - - public async Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken) + public async Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, VerifyLearnerResponse learnerValidationResponseCode, CancellationToken cancellationToken) { var originatingParty = _authenticationService.GetUserParty(); var db = _dbContext.Value; @@ -199,7 +184,7 @@ public async Task CreateCohort(long providerId, long accountId, long acc var transferSender = transferSenderId.HasValue ? await GetTransferSender(accountId, transferSenderId.Value, pledgeApplicationId, db, cancellationToken) : null; var originator = GetCohortOriginator(originatingParty, provider, accountLegalEntity); - await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, null, cancellationToken); + await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, learnerValidationResponseCode, null, cancellationToken); return originator.CreateCohort(providerId, accountLegalEntity, transferSender, pledgeApplicationId, draftApprenticeshipDetails, userInfo); } @@ -250,7 +235,7 @@ public async Task SendCohortToOtherParty(long cohortId, string message, UserInfo public async Task UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken) { var cohort = await _dbContext.Value.GetCohortAggregate(cohortId, cancellationToken: cancellationToken); - + AssertHasProvider(cohortId, cohort.ProviderId); AssertHasApprenticeshipId(cohortId, draftApprenticeshipDetails.Id); @@ -261,7 +246,7 @@ public async Task UpdateDraftApprenticeship(long cohortId, DraftApprenti await ValidateStartDateForContinuation(cohort, draftApprenticeshipDetails); } - await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohortId, cancellationToken); + //await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohortId, cancellationToken); return cohort; } @@ -279,6 +264,58 @@ public async Task DeleteDraftApprenticeship(long cohortId, long apprenti return cohort; } + private static void AssertHasApprenticeshipId(long cohortId, long draftApprenticeshipDetailId) + { + if (draftApprenticeshipDetailId < 1) + { + throw new InvalidOperationException($"Cannot update cohort {cohortId} because the supplied draft apprenticeship does not have an id"); + } + } + + private static async Task GetAccountLegalEntity(long accountId, long accountLegalEntityId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) + { + var accountLegalEntity = + await db.AccountLegalEntities.SingleOrDefaultAsync(x => x.Id == accountLegalEntityId, + cancellationToken); + if (accountLegalEntity == null) + throw new BadRequestException($"AccountLegalEntity {accountLegalEntityId} was not found"); + if (accountLegalEntity.AccountId != accountId) + throw new BadRequestException($"AccountLegalEntity {accountLegalEntityId} does not belong to the Account {accountId}"); + + return accountLegalEntity; + } + + private static async Task GetAccount(long accountId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) + { + var account = await db.Accounts.SingleOrDefaultAsync(x => x.Id == accountId, cancellationToken); + if (account == null) + throw new BadRequestException($"Account {accountId} was not found"); + + return account; + } + + private static async Task GetProvider(long providerId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) + { + var provider = await db.Providers.SingleOrDefaultAsync(p => p.UkPrn == providerId, cancellationToken); + if (provider == null) throw new BadRequestException($"Provider {providerId} was not found"); + return provider; + } + + private async Task ValidateUlnOverlap(Cohort cohort) + { + foreach (var draftApprenticeship in cohort.DraftApprenticeships) + { + if (!string.IsNullOrEmpty(draftApprenticeship.Uln) && draftApprenticeship.StartDate.HasValue && draftApprenticeship.EndDate.HasValue) + { + var result = await _overlapCheckService.CheckForOverlaps(draftApprenticeship.Uln, draftApprenticeship.StartDate.Value.To(draftApprenticeship.EndDate.Value), draftApprenticeship.Id, CancellationToken.None); + if (result.HasOverlaps) + { + throw new DomainException(draftApprenticeship.Uln, "The draft apprenticeship has overlap"); + } + } + } + } + // Will remove once it goes through testing //public async Task DeleteApprenticeshipConfirmationStatus(long apprenticeshipId) //{ @@ -297,8 +334,10 @@ private ICohortOriginator GetCohortOriginator(Party originatingParty, Provider p { case Party.Employer: return accountLegalEntity; + case Party.Provider: return provider; + default: throw new ArgumentException($"Unable to get ICohortOriginator from Party of type {originatingParty}"); } @@ -308,41 +347,12 @@ private void AssertHasProvider(long cohortId, long? providerId) { if (providerId == null) { - // We need a provider id to validate the apprenticeship with reservations, so a provider id is mandatory. + // We need a provider id to validate the apprenticeship with reservations, so a + // provider id is mandatory. throw new InvalidOperationException($"Cannot update cohort {cohortId} because it is not linked to a provider"); } } - private static void AssertHasApprenticeshipId(long cohortId, long draftApprenticeshipDetailId) - { - if (draftApprenticeshipDetailId < 1) - { - throw new InvalidOperationException($"Cannot update cohort {cohortId} because the supplied draft apprenticeship does not have an id"); - } - } - - private static async Task GetAccountLegalEntity(long accountId, long accountLegalEntityId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) - { - var accountLegalEntity = - await db.AccountLegalEntities.SingleOrDefaultAsync(x => x.Id == accountLegalEntityId, - cancellationToken); - if (accountLegalEntity == null) - throw new BadRequestException($"AccountLegalEntity {accountLegalEntityId} was not found"); - if (accountLegalEntity.AccountId != accountId) - throw new BadRequestException($"AccountLegalEntity {accountLegalEntityId} does not belong to the Account {accountId}"); - - return accountLegalEntity; - } - - private static async Task GetAccount(long accountId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) - { - var account = await db.Accounts.SingleOrDefaultAsync(x => x.Id == accountId, cancellationToken); - if (account == null) - throw new BadRequestException($"Account {accountId} was not found"); - - return account; - } - private async Task GetTransferSender(long employerAccountId, long transferSenderId, int? pledgeApplicationId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) { if (pledgeApplicationId.HasValue) @@ -353,11 +363,10 @@ private async Task GetTransferSender(long employerAccountId, long trans { await ValidateTransferSenderIdIsAFundingConnection(employerAccountId, transferSenderId); } - + return await GetAccount(transferSenderId, db, cancellationToken); } - private async Task ValidatePledgeApplicationId(long accountId, long transferSenderId, int pledgeApplicationId) { var pledgeApplication = await _levyTransferMatchingApiClient.GetPledgeApplication(pledgeApplicationId); @@ -394,13 +403,6 @@ private async Task ValidateTransferSenderIdIsAFundingConnection(long accountId, throw new BadRequestException($"TransferSenderId {transferSenderId} is not a FundingEmployer for Account {accountId}"); } - private static async Task GetProvider(long providerId, ProviderCommitmentsDbContext db, CancellationToken cancellationToken) - { - var provider = await db.Providers.SingleOrDefaultAsync(p => p.UkPrn == providerId, cancellationToken); - if (provider == null) throw new BadRequestException($"Provider {providerId} was not found"); - return provider; - } - private async Task ValidateStartDateForContinuation(Cohort cohort, DraftApprenticeshipDetails draftApprenticeshipDetails) { if (!draftApprenticeshipDetails.StartDate.HasValue) return; @@ -422,8 +424,9 @@ private async Task ValidateStartDateForContinuation(Cohort cohort, DraftApprenti } } - private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, long? cohortId, CancellationToken cancellationToken) + private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, VerifyLearnerResponse learnerValidationResponseCode, long? cohortId, CancellationToken cancellationToken) { + HandleLearnerVerificationResponse(learnerValidationResponseCode); ValidateApprenticeshipDate(draftApprenticeshipDetails); ValidateUln(draftApprenticeshipDetails); await ValidateOverlaps(draftApprenticeshipDetails, cancellationToken); @@ -431,6 +434,39 @@ private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails await ValidateReservation(draftApprenticeshipDetails, cancellationToken); } + private void HandleLearnerVerificationResponse(VerifyLearnerResponse learnerValidationResponseCode) + { + if (learnerValidationResponseCode is null) + { + throw new DomainException(nameof(learnerValidationResponseCode), "Learner details validation was unsuccessful."); + } + + switch (learnerValidationResponseCode.ResponseCode) + { + case LearnerValidationServiceResponseCode.SuccessfulMatch: + case LearnerValidationServiceResponseCode.SuccessfulLinkedMatch: + break; + + case LearnerValidationServiceResponseCode.SimilarMatch: + case LearnerValidationServiceResponseCode.SimilarLinkedMatch: + // Note that in these cases, some or all of the fields (excluding unique learner + // number) are found to be similar to a learner on the Learner Record Service, + // but not an exact match + break; + + case LearnerValidationServiceResponseCode.LearnerDoesNotMatch: + // Note that in this case, some or all of the fields (excluding unique learner + // number) did not successfully match any learners on the Learner Record Service + // Further detials can be found in learnerValidationResponseCode.FailureFlags + break; + + case LearnerValidationServiceResponseCode.UlnNotFound: + throw new DomainException(nameof(learnerValidationResponseCode), "Unique learner number does not match any learners on the Learner Record Service."); + default: + break; + } + } + private void ValidateUln(DraftApprenticeshipDetails draftApprenticeshipDetails) { if (string.IsNullOrWhiteSpace(draftApprenticeshipDetails.Uln)) return; @@ -481,7 +517,7 @@ private async Task ValidateReservation(DraftApprenticeshipDetails details, Cance var errors = validationResult.ValidationErrors.Select(error => new DomainError(error.PropertyName, error.Reason)).ToList(); errors.ThrowIfAny(); } - + private async Task ValidateOverlaps(DraftApprenticeshipDetails details, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(details.Uln) || !details.StartDate.HasValue || !details.EndDate.HasValue) return; @@ -550,6 +586,7 @@ async Task GetMaLegalEntityId() throw new DomainException(nameof(cohort.EmployerAccountId), $"Employer {cohort.EmployerAccountId} cannot approve any cohort because the agreement is not signed"); } } + private async Task ValidateNoEmailOverlapsExist(Cohort cohort, CancellationToken cancellationToken) { var emailOverlaps = await _overlapCheckService.CheckForEmailOverlaps(cohort.Id, cancellationToken); @@ -560,4 +597,4 @@ private async Task ValidateNoEmailOverlapsExist(Cohort cohort, CancellationToken } } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs index bf00d3e109..7209bdc16b 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs @@ -18,6 +18,7 @@ public CreateCohortRequestValidator(IAuthorizationService authorizationService) RuleFor(r => r.UserInfo).SetValidator(new UserInfoValidator()).When(r => r.UserInfo != null); RuleFor(model => (int)model.DeliveryModel).InclusiveBetween(0, 2).WithMessage("Delivery Model can only be between 0 and 2").When(model => model.DeliveryModel.HasValue); RuleFor(r => r.IsOnFlexiPaymentPilot).NotNull().WithMessage("Select whether this apprentice will be on the pilot programme."); + RuleFor(r => r.LearnerValidationServiceResponseCode).NotNull().WithMessage("The learner details were not successfully validated."); } } } From f132f7a5da3f447983e259a97daddbc2f611e13f Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Fri, 10 Mar 2023 16:25:14 +0000 Subject: [PATCH 02/10] Handle add draft apprenticeship journey for learner verification Also renamed response object for clarity --- .../Requests/AddDraftApprenticeshipRequest.cs | 1 + .../Requests/CreateCohortRequest.cs | 2 +- .../CohortControllerTests/CreateTests.cs | 2 +- .../Controllers/CohortController.cs | 2 +- ...onse.cs => LearnerVerificationResponse.cs} | 6 +-- .../Commands/AddCohortCommandHandlerTests.cs | 8 ++-- ...dDraftApprenticeshipCommandHandlerTests.cs | 10 +++-- ...ToDraftApprenticeshipDetailsMapperTests.cs | 6 +-- .../Services/CohortDomainServiceTests.cs | 6 +-- ...raftApprenticeshipRequestValidatorTests.cs | 11 ++++-- .../CreateCohortRequestValidatorTests.cs | 10 ++--- .../Commands/AddCohort/AddCohortCommand.cs | 6 +-- .../Commands/AddCohort/AddCohortHandler.cs | 6 +-- .../AddDraftApprenticeshipCommand.cs | 1 + .../AddDraftApprenticeshipCommandHandler.cs | 8 ++-- .../Domain/Interfaces/ICohortDomainService.cs | 4 +- .../Services/CohortDomainService.cs | 38 +++++++++---------- .../AddDraftApprenticeshipRequestValidator.cs | 5 ++- .../CreateCohortRequestValidator.cs | 8 ++-- 19 files changed, 74 insertions(+), 66 deletions(-) rename src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/{VerifyLearnerResponse.cs => LearnerVerificationResponse.cs} (86%) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/AddDraftApprenticeshipRequest.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/AddDraftApprenticeshipRequest.cs index 8fdb638129..6d93cd2ff0 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/AddDraftApprenticeshipRequest.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/AddDraftApprenticeshipRequest.cs @@ -24,5 +24,6 @@ public class AddDraftApprenticeshipRequest : SaveDataRequest public DateTime? EmploymentEndDate { get; set; } public bool IgnoreStartDateOverlap { get; set; } public bool? IsOnFlexiPaymentPilot { get; set; } + public LearnerVerificationResponse LearnerVerificationResponse { get; set; } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs index c4c5671013..0d8b6d8f77 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/CreateCohortRequest.cs @@ -27,6 +27,6 @@ public class CreateCohortRequest : SaveDataRequest public DateTime? EmploymentEndDate { get; set; } public bool IgnoreStartDateOverlap { get; set; } public bool? IsOnFlexiPaymentPilot { get; set; } - public VerifyLearnerResponse LearnerValidationServiceResponseCode { get; set; } + public LearnerVerificationResponse LearnerVerificationResponse { get; set; } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs index 5593bfaa47..a9a1e00043 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.UnitTests/Controllers/CohortControllerTests/CreateTests.cs @@ -70,7 +70,7 @@ public CreateTestsFixture() c.PledgeApplicationId == Request.PledgeApplicationId && c.UserInfo == Request.UserInfo && c.IsOnFlexiPaymentPilot == Request.IsOnFlexiPaymentPilot && - c.LearnerValidationServiceResponseCode == Request.LearnerValidationServiceResponseCode), CancellationToken.None)) + c.LearnerVerificationResponse == Request.LearnerVerificationResponse), CancellationToken.None)) .ReturnsAsync(Result); } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs index 2b2c3cc123..2b214e1f87 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api/Controllers/CohortController.cs @@ -66,7 +66,7 @@ public async Task Create([FromBody]CreateCohortRequest request) request.UserInfo, request.IgnoreStartDateOverlap, request.IsOnFlexiPaymentPilot, - request.LearnerValidationServiceResponseCode); + request.LearnerVerificationResponse); var result = await _mediator.Send(command); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs similarity index 86% rename from src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs rename to src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs index eb713bdeee..3eff8b2d6d 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/VerifyLearnerResponse.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs @@ -3,7 +3,7 @@ namespace SFA.DAS.CommitmentsV2.Types { - public enum LearnerValidationServiceResponseCode + public enum LearnerVerificationResponseCode { [Description("WSVRC001")] SuccessfulMatch, @@ -51,9 +51,9 @@ public enum FailureFlag GenderDoesntMatchGender } - public class VerifyLearnerResponse + public class LearnerVerificationResponse { - public LearnerValidationServiceResponseCode ResponseCode { get; set; } + public LearnerVerificationResponseCode ResponseCode { get; set; } public IEnumerable FailureFlags { get; set; } } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs index ca38a4d073..0935d6c0fb 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddCohortCommandHandlerTests.cs @@ -43,7 +43,7 @@ public async Task ShouldCreateCohort() fixtures.CohortDomainServiceMock.Verify(x => x.CreateCohort(providerId, accountId, accountLegalEntityId, transferSenderId, pledgeApplicationId, It.IsAny(), fixtures.UserInfo, - It.IsAny(), + It.IsAny(), It.IsAny())); Assert.AreEqual(expectedHash, response.Reference); @@ -95,7 +95,7 @@ public AddCohortCommandHandlerTestFixture() CohortDomainServiceMock = new Mock(); CohortDomainServiceMock .Setup(x => x.CreateCohort(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync(commitment); Logger = new TestLogger(); @@ -114,7 +114,7 @@ public AddCohortCommandHandlerTestFixture() public TestLogger Logger { get; } public UserInfo UserInfo { get; } - public VerifyLearnerResponse LearnerValidationResponseCode { get; } + public LearnerVerificationResponse LearnerVerificationResponse { get; } public AddCohortCommandHandlerTestFixture WithGeneratedHash(string hash) { @@ -153,7 +153,7 @@ public async Task Handle(long accountId, long accountLegalEntit UserInfo, false, false, - LearnerValidationResponseCode); + LearnerVerificationResponse); var handler = new AddCohortHandler(new Lazy(() => Db), EncodingService, diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddDraftApprenticeshipCommandHandlerTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddDraftApprenticeshipCommandHandlerTests.cs index c2472f93fd..e82df1cf1a 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddDraftApprenticeshipCommandHandlerTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/AddDraftApprenticeshipCommandHandlerTests.cs @@ -31,7 +31,7 @@ public Task Handle_WhenCommandIsHandled_ThenShouldAddDraftApprenticeship() return TestAsync( f => f.AddDraftApprenticeship(), f => f.CohortDomainService.Verify(c => c.AddDraftApprenticeship(f.Command.ProviderId, - f.Command.CohortId, f.DraftApprenticeshipDetails, f.UserInfo, f.CancellationToken))); + f.Command.CohortId, f.DraftApprenticeshipDetails, f.UserInfo, f.LearnerVerificationResponse, f.CancellationToken))); } [Test] @@ -57,12 +57,13 @@ public class AddDraftApprenticeshipCommandHandlerTestsFixture public Mock CohortDomainService { get; set; } public IRequestHandler Handler { get; set; } public UserInfo UserInfo { get; } + public LearnerVerificationResponse LearnerVerificationResponse { get; } public AddDraftApprenticeshipCommandHandlerTestsFixture() { Fixture = new Fixture(); DraftApprenticeshipDetails = Fixture.Build() - .With(o => o.IgnoreStartDateOverlap,false) + .With(o => o.IgnoreStartDateOverlap, false) .Create(); DraftApprenticeship = new DraftApprenticeship().Set(a => a.Id, 123); CancellationToken = new CancellationToken(); @@ -74,8 +75,9 @@ public AddDraftApprenticeshipCommandHandlerTestsFixture() CohortDomainService = new Mock(); DraftApprenticeshipDetailsMapper = new Mock>(); UserInfo = Fixture.Create(); + LearnerVerificationResponse = Fixture.Create(); - Command = Fixture.Build().With(o => o.UserInfo, UserInfo).Without(x => x.IgnoreStartDateOverlap).Create(); + Command = Fixture.Build().With(o => o.UserInfo, UserInfo).With(o => o.LearnerVerificationResponse, LearnerVerificationResponse).Without(x => x.IgnoreStartDateOverlap).Create(); Handler = new AddDraftApprenticeshipCommandHandler( new Lazy(() => Db), @@ -84,7 +86,7 @@ public AddDraftApprenticeshipCommandHandlerTestsFixture() CohortDomainService.Object); CohortDomainService.Setup(s => s.AddDraftApprenticeship(Command.ProviderId, Command.CohortId, - DraftApprenticeshipDetails, Command.UserInfo, CancellationToken)).ReturnsAsync(DraftApprenticeship); + DraftApprenticeshipDetails, Command.UserInfo, Command.LearnerVerificationResponse, CancellationToken)).ReturnsAsync(DraftApprenticeship); DraftApprenticeshipDetailsMapper.Setup(m => m.Map(Command)).ReturnsAsync(DraftApprenticeshipDetails); } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs index 6e109570f1..721f58ba11 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/AddCohortCommandToDraftApprenticeshipDetailsMapperTests.cs @@ -157,7 +157,7 @@ public AddCohortCommandToDraftApprenticeshipDetailsMapperTestsFixture() Command = new AddCohortCommand(command.AccountId, command.AccountLegalEntityId, command.ProviderId, courseCode, command.DeliveryModel, command.Cost, command.StartDate, command.ActualStartDate, command.EndDate, command.OriginatorReference, command.ReservationId, command.FirstName, command.LastName, command.Email, command.DateOfBirth, - command.Uln, command.TransferSenderId, command.PledgeApplicationId, command.EmploymentPrice, command.EmploymentEndDate, command.UserInfo, true, true, command.LearnerValidationServiceResponseCode); + command.Uln, command.TransferSenderId, command.PledgeApplicationId, command.EmploymentPrice, command.EmploymentEndDate, command.UserInfo, true, true, command.LearnerVerificationResponse); AuthorizationService = new Mock(); TrainingProgrammeLookup = new Mock(); @@ -194,7 +194,7 @@ private AddCohortCommand AddCohortCommandNoDate() return new AddCohortCommand(Command.AccountId, Command.AccountLegalEntityId, Command.ProviderId, Command.CourseCode, Command.DeliveryModel, Command.Cost, null, null, null, Command.OriginatorReference, Command.ReservationId, Command.FirstName, Command.LastName, Command.Email, Command.DateOfBirth, Command.Uln, - Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false, Command.LearnerValidationServiceResponseCode); + Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false, Command.LearnerVerificationResponse); } public Task MapWithFramework() @@ -217,7 +217,7 @@ private AddCohortCommand CommandWithFramework() return new AddCohortCommand(Command.AccountId, Command.AccountLegalEntityId, Command.ProviderId, frameworkId, Command.DeliveryModel, Command.Cost, Command.StartDate, Command.ActualStartDate, Command.EndDate, Command.OriginatorReference, Command.ReservationId, Command.FirstName, Command.LastName, Command.Email, Command.DateOfBirth, Command.Uln, - Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false, Command.LearnerValidationServiceResponseCode); + Command.TransferSenderId, Command.PledgeApplicationId, Command.EmploymentPrice, Command.EmploymentEndDate, Command.UserInfo, false, false, Command.LearnerVerificationResponse); } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs index 52dcec1ce6..7b5b4ba9f1 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs @@ -924,7 +924,7 @@ public CohortDomainServiceTestFixture() public List DomainErrors { get; } public string Message { get; private set; } public UserInfo UserInfo { get; private set; } - public VerifyLearnerResponse LearnerValidationResponseCode { get; private set; } + public LearnerVerificationResponse LearnerVerificationResponse { get; private set; } public ApprenticeshipPriorLearning PriorLearning { get; private set; } public long MaLegalEntityId { get; private set; } private Mock OverlapCheckService { get; } @@ -1330,7 +1330,7 @@ public async Task CreateCohort(long? accountId = null, long? accountLega try { var result = await CohortDomainService.CreateCohort(ProviderId, accountId.Value, accountLegalEntityId.Value, transferSenderId, pledgeApplicationId, - DraftApprenticeshipDetails, UserInfo, LearnerValidationResponseCode, new CancellationToken()); + DraftApprenticeshipDetails, UserInfo, LearnerVerificationResponse, new CancellationToken()); await Db.SaveChangesAsync(); return result; } @@ -1403,7 +1403,7 @@ public async Task AddDraftApprenticeship(bool ignoreStartDateOverlap = false) try { - await CohortDomainService.AddDraftApprenticeship(ProviderId, CohortId, DraftApprenticeshipDetails, UserInfo, new CancellationToken()); + await CohortDomainService.AddDraftApprenticeship(ProviderId, CohortId, DraftApprenticeshipDetails, UserInfo, LearnerVerificationResponse, new CancellationToken()); await Db.SaveChangesAsync(); } catch (DomainException ex) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/AddDraftApprenticeshipRequestValidatorTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/AddDraftApprenticeshipRequestValidatorTests.cs index 5e5428bd2a..c66f1dd830 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/AddDraftApprenticeshipRequestValidatorTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/AddDraftApprenticeshipRequestValidatorTests.cs @@ -31,7 +31,6 @@ public void Validate_ProviderId_ShouldBeValidated(long value, bool expectedValid AssertValidationResult(request => request.ProviderId, value, expectedValid); } - [TestCase(false, false)] [TestCase(true, true)] public void Validate_ReservationId_ShouldBeValidated(bool hasValue, bool expectedValid) @@ -83,6 +82,12 @@ public void Validate_IsOnFlexiPaymentPilotIsNull_ShouldBeInvalid() AssertValidationResult(request => request.IsOnFlexiPaymentPilot, (bool?)null, false); } + [Test] + public void Validate_LearnerVerificationResponseIsNull_ShouldBeInvalid() + { + AssertValidationResult(request => request.LearnerVerificationResponse, null, false); + } + private void AssertValidationResult(Expression> property, T value, bool expectedValid) { // Arrange @@ -103,10 +108,10 @@ private void AssertValidationResult(Expression(); - + authorizationService.Setup(a => a.IsAuthorized(It.IsAny())) .Returns(o => feature(o.SingleOrDefault())); - + var validator = new AddDraftApprenticeshipRequestValidator(authorizationService.Object); // Act diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs index e9f9ddb025..37bdadf464 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Validators/CreateCohortRequestValidatorTests.cs @@ -91,9 +91,9 @@ public void Validate_IsOnFlexiPaymentPilotIsNull_ShouldBeInvalid() } [Test] - public void Validate_LearnerValidationServiceResponseCodeIsNull_ShouldBeInvalid() + public void Validate_LearnerVerificationResponseIsNull_ShouldBeInvalid() { - AssertValidationResult(request => request.LearnerValidationServiceResponseCode, null, false); + AssertValidationResult(request => request.LearnerVerificationResponse, null, false); } private void AssertValidationResult(Expression> property, T value, bool expectedValid) @@ -116,10 +116,10 @@ private void AssertValidationResult(Expression> { // Arrange var authorizationService = new Mock(); - + authorizationService.Setup(a => a.IsAuthorized(It.IsAny())) .Returns(o => feature(o.SingleOrDefault())); - + var validator = new CreateCohortRequestValidator(authorizationService.Object); // Act @@ -133,4 +133,4 @@ private void AssertValidationResult(Expression> } } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs index 3aa6765b3d..6397ca80b5 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortCommand.cs @@ -12,7 +12,7 @@ public AddCohortCommand(long accountId, long accountLegalEntityId, long provider string lastName, string email, DateTime? dateOfBirth, string uln, long? transferSenderId, int? pledgeApplicationId, int? employmentPrice, DateTime? employmentEndDate, UserInfo userInfo, bool ignoreStartDateOverlap, - bool? isOnFlexiPaymentPilot, VerifyLearnerResponse learnerValidationResponseCode) + bool? isOnFlexiPaymentPilot, LearnerVerificationResponse learnerVerificationResponse) { AccountId = accountId; AccountLegalEntityId = accountLegalEntityId; @@ -35,7 +35,7 @@ public AddCohortCommand(long accountId, long accountLegalEntityId, long provider EmploymentPrice = employmentPrice; EmploymentEndDate = employmentEndDate; IsOnFlexiPaymentPilot = isOnFlexiPaymentPilot; - LearnerValidationServiceResponseCode = learnerValidationResponseCode; + LearnerVerificationResponse = learnerVerificationResponse; UserInfo = userInfo ?? throw new ArgumentNullException(nameof(userInfo)); IgnoreStartDateOverlap = ignoreStartDateOverlap; @@ -64,6 +64,6 @@ public AddCohortCommand(long accountId, long accountLegalEntityId, long provider public UserInfo UserInfo { get; } public bool IgnoreStartDateOverlap { get; set; } public bool? IsOnFlexiPaymentPilot { get; set; } - public VerifyLearnerResponse LearnerValidationServiceResponseCode { get; set; } + public LearnerVerificationResponse LearnerVerificationResponse { get; set; } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs index a8eb47f1b2..ee89244887 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddCohort/AddCohortHandler.cs @@ -42,14 +42,14 @@ public async Task Handle(AddCohortCommand command, Cancellation var draftApprenticeshipDetails = await _draftApprenticeshipDetailsMapper.Map(command); - var cohort = await _cohortDomainService.CreateCohort(command.ProviderId, + var cohort = await _cohortDomainService.CreateCohort(command.ProviderId, command.AccountId, command.AccountLegalEntityId, command.TransferSenderId, command.PledgeApplicationId, draftApprenticeshipDetails, command.UserInfo, - command.LearnerValidationServiceResponseCode, + command.LearnerVerificationResponse, cancellationToken); db.Cohorts.Add(cohort); @@ -70,4 +70,4 @@ public async Task Handle(AddCohortCommand command, Cancellation return response; } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddDraftApprenticeship/AddDraftApprenticeshipCommand.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddDraftApprenticeship/AddDraftApprenticeshipCommand.cs index 5fc7364837..40c333dbd1 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddDraftApprenticeship/AddDraftApprenticeshipCommand.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/AddDraftApprenticeship/AddDraftApprenticeshipCommand.cs @@ -27,5 +27,6 @@ public class AddDraftApprenticeshipCommand : IRequest Handle(AddDraftApprenticeshipCom { var db = _dbContext.Value; var draftApprenticeshipDetails = await _draftApprenticeshipDetailsMapper.Map(request); - var draftApprenticeship = await _cohortDomainService.AddDraftApprenticeship(request.ProviderId, request.CohortId, draftApprenticeshipDetails, request.UserInfo, cancellationToken); - + var draftApprenticeship = await _cohortDomainService.AddDraftApprenticeship(request.ProviderId, request.CohortId, draftApprenticeshipDetails, request.UserInfo, request.LearnerVerificationResponse, cancellationToken); + await db.SaveChangesAsync(cancellationToken); - + _logger.LogInformation($"Added draft apprenticeship. Reservation-Id:{request.ReservationId} Commitment-Id:{request.CohortId} Apprenticeship-Id:{draftApprenticeship.Id}"); - + var response = new AddDraftApprenticeshipResult { Id = draftApprenticeship.Id diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs index ff08ab17ee..440a12f286 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs @@ -10,11 +10,11 @@ namespace SFA.DAS.CommitmentsV2.Domain.Interfaces { public interface ICohortDomainService { - Task AddDraftApprenticeship(long providerId, long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken); + Task AddDraftApprenticeship(long providerId, long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, LearnerVerificationResponse learnerVerificationResponse, CancellationToken cancellationToken); Task ApproveCohort(long cohortId, string message, UserInfo userInfo, Party? requestingParty, CancellationToken cancellationToken); - Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, VerifyLearnerResponse learnerValidationResponseCode, CancellationToken cancellationToken); + Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, LearnerVerificationResponse learnerVerificationResponse, CancellationToken cancellationToken); Task CreateCohortWithOtherParty(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, string message, UserInfo userInfo, CancellationToken cancellationToken); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index af40b2ec2d..54de057848 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -75,13 +75,13 @@ public CohortDomainService(Lazy dbContext, _featureTogglesService = featureTogglesService; } - public async Task AddDraftApprenticeship(long providerId, long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken) + public async Task AddDraftApprenticeship(long providerId, long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, LearnerVerificationResponse learnerVerificationResponse, CancellationToken cancellationToken) { var db = _dbContext.Value; var cohort = await db.GetCohortAggregate(cohortId, cancellationToken); var party = _authenticationService.GetUserParty(); var draftApprenticeship = cohort.AddDraftApprenticeship(draftApprenticeshipDetails, party, userInfo); - //await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohort.Id, cancellationToken); //TODO + await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, learnerVerificationResponse, cohort.Id, cancellationToken); return draftApprenticeship; } @@ -175,7 +175,7 @@ public async Task ApproveCohort(long cohortId, string message, UserInfo userInfo cohort.Approve(party, message, userInfo, _currentDateTime.UtcNow, apprenticeEmailIsRequired, isRPLRequired); } - public async Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, VerifyLearnerResponse learnerValidationResponseCode, CancellationToken cancellationToken) + public async Task CreateCohort(long providerId, long accountId, long accountLegalEntityId, long? transferSenderId, int? pledgeApplicationId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, LearnerVerificationResponse learnerVerificationResponse, CancellationToken cancellationToken) { var originatingParty = _authenticationService.GetUserParty(); var db = _dbContext.Value; @@ -184,7 +184,7 @@ public async Task CreateCohort(long providerId, long accountId, long acc var transferSender = transferSenderId.HasValue ? await GetTransferSender(accountId, transferSenderId.Value, pledgeApplicationId, db, cancellationToken) : null; var originator = GetCohortOriginator(originatingParty, provider, accountLegalEntity); - await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, learnerValidationResponseCode, null, cancellationToken); + await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, learnerVerificationResponse, null, cancellationToken); return originator.CreateCohort(providerId, accountLegalEntity, transferSender, pledgeApplicationId, draftApprenticeshipDetails, userInfo); } @@ -424,9 +424,12 @@ private async Task ValidateStartDateForContinuation(Cohort cohort, DraftApprenti } } - private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, VerifyLearnerResponse learnerValidationResponseCode, long? cohortId, CancellationToken cancellationToken) + private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, LearnerVerificationResponse learnerVerificationResponse, long? cohortId, CancellationToken cancellationToken) { - HandleLearnerVerificationResponse(learnerValidationResponseCode); + if (learnerVerificationResponse is not null) + { + HandleLearnerVerificationResponse(learnerVerificationResponse); + } ValidateApprenticeshipDate(draftApprenticeshipDetails); ValidateUln(draftApprenticeshipDetails); await ValidateOverlaps(draftApprenticeshipDetails, cancellationToken); @@ -434,34 +437,29 @@ private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails await ValidateReservation(draftApprenticeshipDetails, cancellationToken); } - private void HandleLearnerVerificationResponse(VerifyLearnerResponse learnerValidationResponseCode) + private void HandleLearnerVerificationResponse(LearnerVerificationResponse learnerVerificationResponse) { - if (learnerValidationResponseCode is null) - { - throw new DomainException(nameof(learnerValidationResponseCode), "Learner details validation was unsuccessful."); - } - - switch (learnerValidationResponseCode.ResponseCode) + switch (learnerVerificationResponse.ResponseCode) { - case LearnerValidationServiceResponseCode.SuccessfulMatch: - case LearnerValidationServiceResponseCode.SuccessfulLinkedMatch: + case LearnerVerificationResponseCode.SuccessfulMatch: + case LearnerVerificationResponseCode.SuccessfulLinkedMatch: break; - case LearnerValidationServiceResponseCode.SimilarMatch: - case LearnerValidationServiceResponseCode.SimilarLinkedMatch: + case LearnerVerificationResponseCode.SimilarMatch: + case LearnerVerificationResponseCode.SimilarLinkedMatch: // Note that in these cases, some or all of the fields (excluding unique learner // number) are found to be similar to a learner on the Learner Record Service, // but not an exact match break; - case LearnerValidationServiceResponseCode.LearnerDoesNotMatch: + case LearnerVerificationResponseCode.LearnerDoesNotMatch: // Note that in this case, some or all of the fields (excluding unique learner // number) did not successfully match any learners on the Learner Record Service // Further detials can be found in learnerValidationResponseCode.FailureFlags break; - case LearnerValidationServiceResponseCode.UlnNotFound: - throw new DomainException(nameof(learnerValidationResponseCode), "Unique learner number does not match any learners on the Learner Record Service."); + case LearnerVerificationResponseCode.UlnNotFound: + throw new DomainException(nameof(learnerVerificationResponse.ResponseCode), "Unique learner number does not match any learners on the Learner Record Service."); default: break; } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/AddDraftApprenticeshipRequestValidator.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/AddDraftApprenticeshipRequestValidator.cs index 3a495a4104..90343536c7 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/AddDraftApprenticeshipRequestValidator.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/AddDraftApprenticeshipRequestValidator.cs @@ -8,15 +8,16 @@ public class AddDraftApprenticeshipRequestValidator : AbstractValidator r.UserId).NotEmpty().WithMessage("The user id must be supplied"); + RuleFor(r => r.UserId).NotEmpty().WithMessage("The user id must be supplied"); RuleFor(r => r.ProviderId).Must(p => p > 0).WithMessage("The provider id must be positive"); RuleFor(r => r.FirstName).MaximumLength(100).WithMessage("You must enter a first name that's no longer than 100 characters"); - RuleFor(r => r.LastName).MaximumLength(100).WithMessage("You must enter a last name that's no longer than 100 characters"); + RuleFor(r => r.LastName).MaximumLength(100).WithMessage("You must enter a last name that's no longer than 100 characters"); RuleFor(r => r.OriginatorReference).MaximumLength(20).WithMessage("The Reference must be 20 characters or fewer"); RuleFor(r => r.ReservationId).NotEmpty().WithMessage("The reservation id must be supplied"); RuleFor(r => r.UserInfo).SetValidator(new UserInfoValidator()).When(r => r.UserInfo != null); RuleFor(model => (int)model.DeliveryModel).InclusiveBetween(0, 2).WithMessage("Delivery Model can only be between 0 and 2").When(model => model.DeliveryModel.HasValue); RuleFor(r => r.IsOnFlexiPaymentPilot).NotNull().WithMessage("Select whether this apprentice will be on the pilot programme."); + RuleFor(r => r.LearnerVerificationResponse).NotNull().WithMessage("The learner details were not successfully verified."); } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs index 7209bdc16b..27479c0914 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Validators/CreateCohortRequestValidator.cs @@ -9,16 +9,16 @@ public class CreateCohortRequestValidator : AbstractValidator r.AccountId).Must(accountId => accountId > 0).WithMessage("The Account Id valid"); - RuleFor(r => r.AccountLegalEntityId).Must(accountLegalEntityId => accountLegalEntityId > 0).WithMessage("The Account Legal Entity must be valid"); + RuleFor(r => r.AccountLegalEntityId).Must(accountLegalEntityId => accountLegalEntityId > 0).WithMessage("The Account Legal Entity must be valid"); RuleFor(r => r.ProviderId).Must(providerId => providerId > 0).WithMessage("The provider id must be positive"); RuleFor(r => r.FirstName).MaximumLength(100).WithMessage("You must enter a first name that's no longer than 100 characters"); - RuleFor(r => r.LastName).MaximumLength(100).WithMessage("You must enter a last name that's no longer than 100 characters"); + RuleFor(r => r.LastName).MaximumLength(100).WithMessage("You must enter a last name that's no longer than 100 characters"); RuleFor(r => r.OriginatorReference).MaximumLength(20).WithMessage("The Reference must be 20 characters or fewer"); RuleFor(r => r.ReservationId).NotEmpty().WithMessage("The reservation id must be supplied"); RuleFor(r => r.UserInfo).SetValidator(new UserInfoValidator()).When(r => r.UserInfo != null); RuleFor(model => (int)model.DeliveryModel).InclusiveBetween(0, 2).WithMessage("Delivery Model can only be between 0 and 2").When(model => model.DeliveryModel.HasValue); RuleFor(r => r.IsOnFlexiPaymentPilot).NotNull().WithMessage("Select whether this apprentice will be on the pilot programme."); - RuleFor(r => r.LearnerValidationServiceResponseCode).NotNull().WithMessage("The learner details were not successfully validated."); + RuleFor(r => r.LearnerVerificationResponse).NotNull().WithMessage("The learner details were not successfully verified."); } } -} +} \ No newline at end of file From 00b78803f208436aac4819e6af1b63e9b0864395 Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Mon, 13 Mar 2023 09:07:26 +0000 Subject: [PATCH 03/10] Hand update draft apprenticeship journey for learner verification --- .../UpdateDraftApprenticeshipRequest.cs | 3 ++- ...teDraftApprenticeshipCommandMapperTests.cs | 22 ++++++++++++++----- ...ToDraftApprenticeshipDetailsMapperTests.cs | 12 +++++----- .../Services/CohortDomainServiceTests.cs | 2 +- .../UpdateDraftApprenticeshipCommand.cs | 3 ++- .../UpdateDraftApprenticeshipHandler.cs | 10 ++++----- .../Domain/Interfaces/ICohortDomainService.cs | 2 +- ...oUpdateDraftApprenticeshipCommandMapper.cs | 3 ++- .../Services/CohortDomainService.cs | 10 +++++---- 9 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/UpdateDraftApprenticeshipRequest.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/UpdateDraftApprenticeshipRequest.cs index 07d89d9258..f91bff77c1 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/UpdateDraftApprenticeshipRequest.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Api.Types/Requests/UpdateDraftApprenticeshipRequest.cs @@ -23,5 +23,6 @@ public class UpdateDraftApprenticeshipRequest : SaveDataRequest public Guid? ReservationId { get; set; } public bool IgnoreStartDateOverlap { get; set; } public bool? IsOnFlexiPaymentPilot { get; set; } + public LearnerVerificationResponse LearnerVerificationResponse { get; set; } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapperTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapperTests.cs index dca1003aa3..f990096176 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapperTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapperTests.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Moq; using NUnit.Framework; using SFA.DAS.CommitmentsV2.Api.Types.Requests; using SFA.DAS.CommitmentsV2.Application.Commands.UpdateDraftApprenticeship; @@ -9,9 +10,9 @@ namespace SFA.DAS.CommitmentsV2.UnitTests.Mapping.RequestToCommandMappers { [TestFixture] - public class UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapperTests : + public class UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapperTests : OldMapperTester { [Test] @@ -19,7 +20,7 @@ public Task Map_CourseCode_ShouldBeSet() { return AssertPropertySet(from => from.CourseCode, "001/AAA"); } - + [Test] public Task Map_CostWithoutValue_ShouldBeSet() { @@ -56,7 +57,6 @@ public Task Map_StartDateWithValue_ShouldBeSet() return AssertPropertySet(from => from.StartDate, (DateTime?)DateTime.Now); } - [Test] public Task Map_ActualStartDateWithoutValue_ShouldBeSet() { @@ -153,6 +153,18 @@ public Task Map_IsOnFlexiPaymentPilotWithValue_ShouldBeSet() return AssertPropertySet(from => from.IsOnFlexiPaymentPilot, (bool?)true); } + [Test] + public Task Map_LearnerVerificationResponseWithoutValue_ShouldBeSet() + { + return AssertPropertySet(from => from.LearnerVerificationResponse, (LearnerVerificationResponse)null); + } + + [Test] + public Task Map_LearnerVerificationResponseWithValue_ShouldBeSet() + { + return AssertPropertySet(from => from.LearnerVerificationResponse, It.IsAny()); + } + [TestCase(DeliveryModel.Regular)] [TestCase(DeliveryModel.PortableFlexiJob)] public Task Map_DeliveryModel_ShouldBeSet(DeliveryModel dm) @@ -160,4 +172,4 @@ public Task Map_DeliveryModel_ShouldBeSet(DeliveryModel dm) return AssertPropertySet(from => from.DeliveryModel, dm); } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/UpdateDraftApprenticeshipToDraftApprenticeshipDetailsMapperTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/UpdateDraftApprenticeshipToDraftApprenticeshipDetailsMapperTests.cs index 0c1d8537cc..6105e43a53 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/UpdateDraftApprenticeshipToDraftApprenticeshipDetailsMapperTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Mapping/UpdateDraftApprenticeshipToDraftApprenticeshipDetailsMapperTests.cs @@ -49,7 +49,7 @@ public Task Map_WhenMapping_ThenShouldSetProperties() public Task Map_WhenMapping_WithNoDate_VersionPropertiesNotSet() { return TestAsync( - f => f.MapNoDateAndNoVersionFields(), + f => f.MapNoDateAndNoVersionFields(), (f, r) => { r.FirstName.Should().Be(f.Command.FirstName); @@ -73,7 +73,7 @@ public Task Map_WhenMapping_WithNoDate_VersionPropertiesNotSet() public Task Map_WhenMappingWithDateAndStandardId_Then_UsesCalculatedTrainingProgramme() { return TestAsync( - f => f.MapWithStandard(), + f => f.MapWithStandard(), (f, r) => { r.FirstName.Should().Be(f.Command.FirstName); @@ -121,7 +121,7 @@ public Task Map_WhenMappingWithFramework_Then_UsesGetTrainingProgramme() public Task Map_WhenMappingWithNoCourse_Then_TrainingCourseVersionConfirmedIsFalse() { return TestAsync( - f => f.MapNoCourse(), + f => f.MapNoCourse(), (f, r) => { r.FirstName.Should().Be(f.Command.FirstName); @@ -141,7 +141,7 @@ public Task Map_WhenMappingWithNoCourse_Then_TrainingCourseVersionConfirmedIsFal }); } } - + public class UpdateDraftApprenticeshipToDraftApprenticeshipDetailsMapperTestsFixture { public Fixture Fixture { get; set; } @@ -177,7 +177,7 @@ public Task MapNoDateAndNoVersionFields() Command.CourseCode = Fixture.Create().ToString(); return Mapper.Map(Command); } - + public Task MapWithDate() { Command.StartDate = DateTime.Now; @@ -197,4 +197,4 @@ public Task MapWithStandard() return Mapper.Map(Command); } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs index 7b5b4ba9f1..7d81576e3d 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Services/CohortDomainServiceTests.cs @@ -1466,7 +1466,7 @@ public async Task UpdateDraftApprenticeship(bool ignoreStartDateOverlap = false) try { - await CohortDomainService.UpdateDraftApprenticeship(CohortId, DraftApprenticeshipDetails, UserInfo, new CancellationToken()); + await CohortDomainService.UpdateDraftApprenticeship(CohortId, DraftApprenticeshipDetails, UserInfo, LearnerVerificationResponse, new CancellationToken()); await Db.SaveChangesAsync(); } catch (DomainException ex) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipCommand.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipCommand.cs index a8dda744a5..c31e935311 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipCommand.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipCommand.cs @@ -27,5 +27,6 @@ public class UpdateDraftApprenticeshipCommand : IRequest Handle(UpdateDraftApprenticeshipCommand command, CancellationToken cancellationToken) { var draftApprenticeshipDetails = await _draftApprenticeshipDetailsMapper.Map(command); - await _cohortDomainService.UpdateDraftApprenticeship(command.CohortId, draftApprenticeshipDetails, command.UserInfo, cancellationToken); + await _cohortDomainService.UpdateDraftApprenticeship(command.CohortId, draftApprenticeshipDetails, command.UserInfo, command.LearnerVerificationResponse, cancellationToken); _logger.LogInformation($"Saved cohort. Reservation-Id:{command.ReservationId} Commitment-Id:{command.CohortId} Apprenticeship:{command.ApprenticeshipId}"); @@ -44,4 +42,4 @@ public async Task Handle(UpdateDraftApprentic return response; } } -} +} \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs index 440a12f286..f9e792de29 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Domain/Interfaces/ICohortDomainService.cs @@ -22,7 +22,7 @@ public interface ICohortDomainService Task SendCohortToOtherParty(long cohortId, string message, UserInfo userInfo, Party? requestingParty, CancellationToken cancellationToken); - Task UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken); + Task UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, LearnerVerificationResponse learnerVerificationResponse, CancellationToken cancellationToken); Task DeleteDraftApprenticeship(long cohortId, long apprenticeshipId, UserInfo userInfo, CancellationToken cancellationToken); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapper.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapper.cs index 8341441735..fcaeb26665 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapper.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapper.cs @@ -6,7 +6,7 @@ namespace SFA.DAS.CommitmentsV2.Mapping.RequestToCommandMappers { public class UpdateDraftApprenticeshipRequestToUpdateDraftApprenticeshipCommandMapper : IOldMapper { - public Task Map(UpdateDraftApprenticeshipRequest source) + public Task Map(UpdateDraftApprenticeshipRequest source) { return Task.FromResult(new UpdateDraftApprenticeshipCommand { @@ -29,6 +29,7 @@ public Task Map(UpdateDraftApprenticeshipRequ UserInfo = source.UserInfo, IgnoreStartDateOverlap = source.IgnoreStartDateOverlap, IsOnFlexiPaymentPilot = source.IsOnFlexiPaymentPilot, + LearnerVerificationResponse = source.LearnerVerificationResponse }); } } diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 54de057848..037f0fe3e1 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -85,11 +85,12 @@ public async Task AddDraftApprenticeship(long providerId, l return draftApprenticeship; } + //TODO: Do we need to account for this scenario with details verification? public async Task ValidateDraftApprenticeshipForOverlappingTrainingDateRequest(long providerId, long? cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, CancellationToken cancellationToken) { Cohort cohort = null; draftApprenticeshipDetails.IgnoreStartDateOverlap = true; - //await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohortId, cancellationToken); //TODO + await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, null, cohortId, cancellationToken); if (cohortId.HasValue && cohortId.Value > 0) { cohort = await _dbContext.Value.GetCohortAggregate(cohortId.Value, cancellationToken: cancellationToken); @@ -99,6 +100,7 @@ public async Task ValidateDraftApprenticeshipForOverlappingTrainingDateRequest(l errors.ThrowIfAny(); } + //TODO: Do we need to account for the bulk upload scenario with details verification? public async Task> AddDraftApprenticeships(List draftApprenticeships, List csvBulkUploadApprenticehips, long providerId, UserInfo userInfo, CancellationToken cancellationToken) { var newCohorts = new Dictionary(); @@ -151,7 +153,7 @@ public async Task> AddDraftApprenticeships(List x.Value).Union(newCohorts.Select(x => x.Value)); @@ -232,7 +234,7 @@ public async Task SendCohortToOtherParty(long cohortId, string message, UserInfo cohort.SendToOtherParty(party, message, userInfo, _currentDateTime.UtcNow); } - public async Task UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken) + public async Task UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, LearnerVerificationResponse learnerVerificationResponse, CancellationToken cancellationToken) { var cohort = await _dbContext.Value.GetCohortAggregate(cohortId, cancellationToken: cancellationToken); @@ -246,7 +248,7 @@ public async Task UpdateDraftApprenticeship(long cohortId, DraftApprenti await ValidateStartDateForContinuation(cohort, draftApprenticeshipDetails); } - //await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cohortId, cancellationToken); + await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, learnerVerificationResponse, cohortId, cancellationToken); return cohort; } From 271a0a35bcec52f355c6a9c23a8b96c06fb1e852 Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Tue, 14 Mar 2023 12:32:38 +0000 Subject: [PATCH 04/10] Cleaning up comments --- .../UpdateDraftApprenticeshipHandler.cs | 1 - .../SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipHandler.cs index 61c788833d..ebb7b91b8f 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/UpdateDraftApprenticeship/UpdateDraftApprenticeshipHandler.cs @@ -24,7 +24,6 @@ public UpdateDraftApprenticeshipHandler( _cohortDomainService = cohortDomainService; } - //TODO FINISH DOING THE UPDATE public async Task Handle(UpdateDraftApprenticeshipCommand command, CancellationToken cancellationToken) { var draftApprenticeshipDetails = await _draftApprenticeshipDetailsMapper.Map(command); diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 037f0fe3e1..763b2945c2 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -100,7 +100,6 @@ public async Task ValidateDraftApprenticeshipForOverlappingTrainingDateRequest(l errors.ThrowIfAny(); } - //TODO: Do we need to account for the bulk upload scenario with details verification? public async Task> AddDraftApprenticeships(List draftApprenticeships, List csvBulkUploadApprenticehips, long providerId, UserInfo userInfo, CancellationToken cancellationToken) { var newCohorts = new Dictionary(); From fc55e57ee24420f670429d4374d5cdf69b62a6ee Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:56:31 +0000 Subject: [PATCH 05/10] Change learner verification object to be less LRS specific --- .../LearnerVerificationResponse.cs | 23 ++++--------------- .../Services/CohortDomainService.cs | 16 ++++++------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs index 3eff8b2d6d..7fffe726f0 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.Types/LearnerVerificationResponse.cs @@ -1,60 +1,45 @@ using System.Collections.Generic; -using System.ComponentModel; namespace SFA.DAS.CommitmentsV2.Types { - public enum LearnerVerificationResponseCode + public enum LearnerVerificationResponseType { - [Description("WSVRC001")] SuccessfulMatch, - [Description("WSVRC002")] SuccessfulLinkedMatch, - [Description("WSVRC003")] SimilarMatch, - [Description("WSVRC004")] SimilarLinkedMatch, - [Description("WSVRC005")] LearnerDoesNotMatch, - [Description("WSVRC006")] UlnNotFound } - public enum FailureFlag + public enum LearnerDetailMatchingError { - [Description("VRF1")] GivenDoesntMatchGiven, - [Description("VRF2")] GivenDoesntMatchFamily, - [Description("VRF3")] GivenDoesntMatchPreviousFamily, - [Description("VRF4")] FamilyDoesntMatchGiven, - [Description("VRF5")] FamilyDoesntMatchFamily, - [Description("VRF6")] FamilyDoesntMatchPreviousFamily, - [Description("VRF7")] DateOfBirthDoesntMatchDateOfBirth, - [Description("VRF8")] GenderDoesntMatchGender } public class LearnerVerificationResponse { - public LearnerVerificationResponseCode ResponseCode { get; set; } + public LearnerVerificationResponseType ResponseType { get; set; } - public IEnumerable FailureFlags { get; set; } + public IEnumerable MatchingErrors { get; set; } } } \ No newline at end of file diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 763b2945c2..4118937b27 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -440,27 +440,27 @@ private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails private void HandleLearnerVerificationResponse(LearnerVerificationResponse learnerVerificationResponse) { - switch (learnerVerificationResponse.ResponseCode) + switch (learnerVerificationResponse.ResponseType) { - case LearnerVerificationResponseCode.SuccessfulMatch: - case LearnerVerificationResponseCode.SuccessfulLinkedMatch: + case LearnerVerificationResponseType.SuccessfulMatch: + case LearnerVerificationResponseType.SuccessfulLinkedMatch: break; - case LearnerVerificationResponseCode.SimilarMatch: - case LearnerVerificationResponseCode.SimilarLinkedMatch: + case LearnerVerificationResponseType.SimilarMatch: + case LearnerVerificationResponseType.SimilarLinkedMatch: // Note that in these cases, some or all of the fields (excluding unique learner // number) are found to be similar to a learner on the Learner Record Service, // but not an exact match break; - case LearnerVerificationResponseCode.LearnerDoesNotMatch: + case LearnerVerificationResponseType.LearnerDoesNotMatch: // Note that in this case, some or all of the fields (excluding unique learner // number) did not successfully match any learners on the Learner Record Service // Further detials can be found in learnerValidationResponseCode.FailureFlags break; - case LearnerVerificationResponseCode.UlnNotFound: - throw new DomainException(nameof(learnerVerificationResponse.ResponseCode), "Unique learner number does not match any learners on the Learner Record Service."); + case LearnerVerificationResponseType.UlnNotFound: + throw new DomainException(nameof(learnerVerificationResponse.ResponseType), "Unique learner number does not match any learners on the Learner Record Service."); default: break; } From d77ae0331f07fdf842e7fcf25862a0fba8bd5ed8 Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Thu, 16 Mar 2023 08:12:34 +0000 Subject: [PATCH 06/10] Remove unsupported not pattern --- .../SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 94b363b8eb..d1e2d60ee0 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -423,7 +423,7 @@ private async Task ValidateStartDateForContinuation(Cohort cohort, DraftApprenti private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, LearnerVerificationResponse learnerVerificationResponse, long? cohortId, CancellationToken cancellationToken) { - if (learnerVerificationResponse is not null) + if (learnerVerificationResponse != null) { HandleLearnerVerificationResponse(learnerVerificationResponse); } From 348d4bb6afb64970fe3bc1892b6cb236c50536d1 Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Thu, 16 Mar 2023 14:38:38 +0000 Subject: [PATCH 07/10] Remove comment --- .../SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index d1e2d60ee0..a7ddf06a20 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -82,7 +82,6 @@ public async Task AddDraftApprenticeship(long providerId, l return draftApprenticeship; } - //TODO: Do we need to account for this scenario with details verification? public async Task ValidateDraftApprenticeshipForOverlappingTrainingDateRequest(long providerId, long? cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, CancellationToken cancellationToken) { Cohort cohort = null; From e2202a3f5c4d52496cbb47331b3621804250d5fc Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Thu, 23 Mar 2023 10:41:08 +0000 Subject: [PATCH 08/10] Re-add missing mapping removed during merge --- ...prenticeshipRequestToAddDraftApprenticeshipCommandMapper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/AddDraftApprenticeshipRequestToAddDraftApprenticeshipCommandMapper.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/AddDraftApprenticeshipRequestToAddDraftApprenticeshipCommandMapper.cs index e5a07abe9e..554bf75b12 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/AddDraftApprenticeshipRequestToAddDraftApprenticeshipCommandMapper.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Mapping/RequestToCommandMappers/AddDraftApprenticeshipRequestToAddDraftApprenticeshipCommandMapper.cs @@ -30,7 +30,8 @@ public Task Map(AddDraftApprenticeshipRequest sou EmploymentPrice = source.EmploymentPrice, UserInfo = source.UserInfo, IgnoreStartDateOverlap = source.IgnoreStartDateOverlap, - IsOnFlexiPaymentPilot = source.IsOnFlexiPaymentPilot + IsOnFlexiPaymentPilot = source.IsOnFlexiPaymentPilot, + LearnerVerificationResponse = source.LearnerVerificationResponse }); } } From 3e5c9a310b7ab7968f2f625405f896f8a41d40bc Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Thu, 23 Mar 2023 10:54:23 +0000 Subject: [PATCH 09/10] Re-order uln validations and fix bug where error not rendered --- .../SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 417d17c6f9..93fbbf02bc 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -422,12 +422,9 @@ private async Task ValidateStartDateForContinuation(Cohort cohort, DraftApprenti private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, LearnerVerificationResponse learnerVerificationResponse, long? cohortId, CancellationToken cancellationToken) { - if (learnerVerificationResponse != null) - { - HandleLearnerVerificationResponse(learnerVerificationResponse); - } ValidateApprenticeshipDate(draftApprenticeshipDetails); ValidateUln(draftApprenticeshipDetails); + if (learnerVerificationResponse != null) { HandleLearnerVerificationResponse(learnerVerificationResponse); } await ValidateOverlaps(draftApprenticeshipDetails, cancellationToken); await ValidateEmailOverlaps(draftApprenticeshipDetails, cohortId, cancellationToken); await ValidateReservation(draftApprenticeshipDetails, cancellationToken); @@ -455,7 +452,7 @@ private void HandleLearnerVerificationResponse(LearnerVerificationResponse learn break; case LearnerVerificationResponseType.UlnNotFound: - throw new DomainException(nameof(learnerVerificationResponse.ResponseType), "Unique learner number does not match any learners on the Learner Record Service."); + throw new DomainException("Uln", "Unique learner number does not match any learners on the Learner Record Service."); default: break; } From 711afd3d4d73e3f59b522751e74c6bcba2233f96 Mon Sep 17 00:00:00 2001 From: dinathain <55487881+dinathain@users.noreply.github.com> Date: Thu, 23 Mar 2023 11:01:44 +0000 Subject: [PATCH 10/10] Moving validation property name into constant --- .../SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs index 93fbbf02bc..09563c6be0 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Services/CohortDomainService.cs @@ -4,7 +4,6 @@ using SFA.DAS.CommitmentsV2.Authentication; using SFA.DAS.CommitmentsV2.Data; using SFA.DAS.CommitmentsV2.Data.Extensions; -using SFA.DAS.CommitmentsV2.Domain; using SFA.DAS.CommitmentsV2.Domain.Entities; using SFA.DAS.CommitmentsV2.Domain.Entities.Reservations; using SFA.DAS.CommitmentsV2.Domain.Exceptions; @@ -22,8 +21,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using SFA.DAS.Authorization.Features.Models; -using SFA.DAS.Authorization.Features.Services; namespace SFA.DAS.CommitmentsV2.Services { @@ -42,6 +39,7 @@ public class CohortDomainService : ICohortDomainService private readonly IAccountApiClient _accountApiClient; private readonly IEmailOptionalService _emailService; private readonly ILevyTransferMatchingApiClient _levyTransferMatchingApiClient; + private const string UlnValidationPropertyName = "Uln"; public CohortDomainService(Lazy dbContext, ILogger logger, @@ -452,7 +450,7 @@ private void HandleLearnerVerificationResponse(LearnerVerificationResponse learn break; case LearnerVerificationResponseType.UlnNotFound: - throw new DomainException("Uln", "Unique learner number does not match any learners on the Learner Record Service."); + throw new DomainException(UlnValidationPropertyName, "Unique learner number does not match any learners on the Learner Record Service."); default: break; }