From 0a7b5d8a9b9b02f2108fe6b758539871a87aeb33 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Thu, 2 Jul 2026 13:27:28 +0100 Subject: [PATCH 1/6] WIP --- ...tchApprenticeshipPaymentsCommandHandler.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs index bc4afb897..1f5cd16d2 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs @@ -1,5 +1,6 @@ using NServiceBus; using SFA.DAS.CommitmentsV2.Authentication; +using SFA.DAS.CommitmentsV2.Configuration; using SFA.DAS.CommitmentsV2.Data; using SFA.DAS.CommitmentsV2.Data.Extensions; using SFA.DAS.CommitmentsV2.Domain.Exceptions; @@ -7,6 +8,7 @@ using SFA.DAS.CommitmentsV2.Messages.Commands; using SFA.DAS.CommitmentsV2.Shared.Interfaces; using SFA.DAS.CommitmentsV2.Types; +using SFA.DAS.Encoding; namespace SFA.DAS.CommitmentsV2.Application.Commands.PatchApprenticeshipPayments; @@ -14,7 +16,9 @@ public class PatchApprenticeshipPaymentsCommandHandler( Lazy dbContext, ICurrentDateTime currentDate, IAuthenticationService authenticationService, - IMessageSession messageSession) + IMessageSession messageSession, + IEncodingService encodingService, + CommitmentsV2Configuration commitmentsV2Configuration) : IRequestHandler { public async Task Handle(PatchApprenticeshipPaymentsCommand command, CancellationToken cancellationToken) @@ -42,6 +46,8 @@ public async Task Handle(PatchApprenticeshipPaymentsCommand command, Cancellatio await dbContext.Value.SaveChangesAsync(cancellationToken); + await SendEmail(isFreeze, apprenticeship.Cohort.ProviderId, apprenticeship.Cohort.AccountLegalEntity.Name, apprenticeship.Id); + await messageSession.Send(new StoreLearningHistoryCommand { ApprenticeshipId = command.ApprenticeshipId, @@ -85,4 +91,26 @@ private static void CheckPartyIsValid(Party party, bool isFreeze) return null; } + + private async Task SendEmail(bool isFreeze, long providerId, string employerName, long apprenticeshipId) + { + var encodedApprenticeshipId = encodingService.Encode(apprenticeshipId, EncodingType.ApprenticeshipId); + + var sendEmailToProviderCommand = new SendEmailToProviderCommand( + providerId, + isFreeze ? "ProviderApprenticeshipPaymentFrozenNotification " : "ProviderApprenticeshipPaymentUnfrozenNotification", + new Dictionary + { + {"employer_name", employerName}, + { + "link_to_mange_apprenticeships", + $"{commitmentsV2Configuration.ProviderCommitmentsBaseUrl}{providerId}/apprentices/{encodedApprenticeshipId}" + }, + { "link_to_unsubscribe", $"{commitmentsV2Configuration.ProviderUrl.ProviderApprenticeshipServiceBaseUrl}notification-settings" } + }); + + await messageSession.Send(sendEmailToProviderCommand); + } + + } From d228835f06541c82b4eb7f5329f0e233b9f68b99 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Fri, 3 Jul 2026 09:37:01 +0100 Subject: [PATCH 2/6] sends notification email --- ...prenticeshipPaymentsCommandHandlerTests.cs | 41 ++++++++++++++++++- ...tchApprenticeshipPaymentsCommandHandler.cs | 6 +-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/PatchApprenticeshipPaymentsCommandHandlerTests.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/PatchApprenticeshipPaymentsCommandHandlerTests.cs index 943e920d2..5f027739e 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/PatchApprenticeshipPaymentsCommandHandlerTests.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2.UnitTests/Application/Commands/PatchApprenticeshipPaymentsCommandHandlerTests.cs @@ -1,12 +1,14 @@ using NServiceBus; using SFA.DAS.CommitmentsV2.Application.Commands.PatchApprenticeshipPayments; using SFA.DAS.CommitmentsV2.Authentication; +using SFA.DAS.CommitmentsV2.Configuration; using SFA.DAS.CommitmentsV2.Data; using SFA.DAS.CommitmentsV2.Domain.Exceptions; using SFA.DAS.CommitmentsV2.Messages.Commands; using SFA.DAS.CommitmentsV2.Models; using SFA.DAS.CommitmentsV2.Shared.Interfaces; using SFA.DAS.CommitmentsV2.Types; +using SFA.DAS.Encoding; using SFA.DAS.UnitOfWork.Context; namespace SFA.DAS.CommitmentsV2.UnitTests.Application.Commands; @@ -20,6 +22,9 @@ public class PatchApprenticeshipPaymentsCommandHandlerTests private Mock _currentDateTime; private Mock _messageSession; private UnitOfWorkContext _unitOfWorkContext; + private Mock _encodingService; + private CommitmentsV2Configuration _commitmentsV2Configuration; + private PatchApprenticeshipPaymentsCommandHandler _handler; [SetUp] @@ -33,13 +38,21 @@ public void Init() _currentDateTime = new Mock(); _currentDateTime.Setup(x => x.UtcNow).Returns(DateTime.UtcNow); _messageSession = new Mock(); + _encodingService = new Mock(); + _encodingService.Setup(x => x.Encode(It.IsAny(), EncodingType.ApprenticeshipId)).Returns("ABC123"); + _commitmentsV2Configuration = new CommitmentsV2Configuration(); + _commitmentsV2Configuration.ProviderUrl = new ProviderUrlConfiguration(); + _commitmentsV2Configuration.ProviderUrl.ProviderApprenticeshipServiceBaseUrl = "https://test.local"; _unitOfWorkContext = new UnitOfWorkContext(); _handler = new PatchApprenticeshipPaymentsCommandHandler( new Lazy(() => _dbContext), _currentDateTime.Object, _authenticationService.Object, - _messageSession.Object); + _messageSession.Object, + _encodingService.Object, + _commitmentsV2Configuration + ); } [TearDown] @@ -106,6 +119,30 @@ await _handler.Handle(new PatchApprenticeshipPaymentsCommand It.IsAny()), Times.Once); } + [TestCase(true, "ProviderApprenticeshipPaymentFrozenNotification")] + [TestCase(false, "ProviderApprenticeshipPaymentUnfrozenNotification")] + public async Task Handle_WhenPaymentFreezeDateProvided_SendsNotificationEmail(bool freeze, string template) + { + var apprenticeship = await SetupApprenticeship(frozen: !freeze); + _authenticationService.Setup(a => a.GetUserParty()).Returns(Party.Employer); + + await _handler.Handle(new PatchApprenticeshipPaymentsCommand + { + ApprenticeshipId = apprenticeship.Id, + PaymentFreezeDate = freeze ? DateTime.UtcNow.Date : null, + FreezePaymentsReason = freeze ? FreezePaymentsReason.LearnerOnBreak : null, + UserInfo = new UserInfo() + }, CancellationToken.None); + + _messageSession.Verify(x => x.Send( + It.Is(c => c.ProviderId == apprenticeship.Cohort.ProviderId && + c.Template == template && + c.Tokens["employer_name"] == apprenticeship.Cohort.AccountLegalEntity.Name && + c.Tokens["link_to_manage_apprenticeships"].Contains($"{apprenticeship.Cohort.ProviderId}/apprentices/ABC123") + ), + It.IsAny()), Times.Once); + } + [Test] public async Task Handle_WhenFreezePaymentsReasonMissing_ThrowsDomainException() { @@ -195,7 +232,7 @@ private async Task SetupApprenticeship(bool frozen = false) { EmployerAccountId = fixture.Create(), ProviderId = fixture.Create(), - AccountLegalEntity = new AccountLegalEntity() + AccountLegalEntity = new AccountLegalEntity(new Account(), 123, 1234, "XXXXX", "XXX123", "Test", CommitmentsV2.Models.OrganisationType.Other, null, DateTime.Today) }, PaymentStatus = PaymentStatus.Active, StartDate = DateTime.UtcNow.AddMonths(-2), diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs index 1f5cd16d2..6316e5512 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs @@ -98,13 +98,13 @@ private async Task SendEmail(bool isFreeze, long providerId, string employerName var sendEmailToProviderCommand = new SendEmailToProviderCommand( providerId, - isFreeze ? "ProviderApprenticeshipPaymentFrozenNotification " : "ProviderApprenticeshipPaymentUnfrozenNotification", + isFreeze ? "ProviderApprenticeshipPaymentFrozenNotification" : "ProviderApprenticeshipPaymentUnfrozenNotification", new Dictionary { {"employer_name", employerName}, { - "link_to_mange_apprenticeships", - $"{commitmentsV2Configuration.ProviderCommitmentsBaseUrl}{providerId}/apprentices/{encodedApprenticeshipId}" + "link_to_manage_apprenticeships", + $"< href=\"{commitmentsV2Configuration.ProviderCommitmentsBaseUrl}{providerId}/apprentices/{encodedApprenticeshipId}\">sign in to your Apprenticeship Service account" }, { "link_to_unsubscribe", $"{commitmentsV2Configuration.ProviderUrl.ProviderApprenticeshipServiceBaseUrl}notification-settings" } }); From 2f32f238fdfb0fc9499c8930101042c55770f3c4 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Fri, 3 Jul 2026 10:37:30 +0100 Subject: [PATCH 3/6] tidy --- .../PatchApprenticeshipPaymentsCommandHandler.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs index 6316e5512..09f492be8 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs @@ -110,7 +110,4 @@ private async Task SendEmail(bool isFreeze, long providerId, string employerName }); await messageSession.Send(sendEmailToProviderCommand); - } - - -} + } \ No newline at end of file From 11e4e632e1195c0cb2d41f018a26aae33f605324 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Tue, 7 Jul 2026 13:30:56 +0100 Subject: [PATCH 4/6] fix build error --- .../PatchApprenticeshipPaymentsCommandHandler.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs index 09f492be8..becf8ee49 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs @@ -110,4 +110,5 @@ private async Task SendEmail(bool isFreeze, long providerId, string employerName }); await messageSession.Send(sendEmailToProviderCommand); - } \ No newline at end of file + } +} \ No newline at end of file From ce07b1815032097854ce0ff2e14f3d244db1efa0 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Mon, 20 Jul 2026 10:21:10 +0100 Subject: [PATCH 5/6] added sign in to your Apprenticeship Service account" + $"sign in to your Apprenticeship Service account" }, { "link_to_unsubscribe", $"{commitmentsV2Configuration.ProviderUrl.ProviderApprenticeshipServiceBaseUrl}notification-settings" } }); From a730ea6bad1e88c7b24dfa8fff9d06ebf7cc1bc3 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Thu, 30 Jul 2026 14:30:01 +0100 Subject: [PATCH 6/6] remopve hyper link --- .../PatchApprenticeshipPaymentsCommandHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs index 6cd3647ba..27d4c2c1a 100644 --- a/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs +++ b/src/CommitmentsV2/SFA.DAS.CommitmentsV2/Application/Commands/PatchApprenticeshipPayments/PatchApprenticeshipPaymentsCommandHandler.cs @@ -122,7 +122,7 @@ private async Task SendEmail(bool isFreeze, long providerId, string employerName {"employer_name", employerName}, { "link_to_manage_apprenticeships", - $"sign in to your Apprenticeship Service account" + $"{commitmentsV2Configuration.ProviderCommitmentsBaseUrl}{providerId}/apprentices/{encodedApprenticeshipId}\"" }, { "link_to_unsubscribe", $"{commitmentsV2Configuration.ProviderUrl.ProviderApprenticeshipServiceBaseUrl}notification-settings" } });