Repository: SkillsFundingAgency/das-findapprenticeship-web
Pull request #316: Fai 2423 ml saved vacancy multiple active save icons in search
Author: login: LACrossley
Created: 2025-05-01T20:38:36Z | Merged: 2025-05-13T09:21:34Z



Diff:
diff --git a/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommand.cs b/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommand.cs
index c43c99495..23871bcef 100644
--- a/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommand.cs
+++ b/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommand.cs
@@ -5,6 +5,7 @@ namespace SFA.DAS.FAA.Application.Commands.Vacancy.DeleteSavedVacancy
     public record DeleteSavedVacancyCommand : IRequest<Unit>
     {
         public Guid CandidateId { get; init; }
-        public required string VacancyReference { get; set; }
+        public required string VacancyId { get; set; }
+        public bool DeleteAllByVacancyReference { get; set; }
     }
 }
\ No newline at end of file
diff --git a/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommandHandler.cs b/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommandHandler.cs
index 41eed53d5..80e3cc9d8 100644
--- a/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommandHandler.cs
+++ b/src/SFA.DAS.FAA.Application/Commands/Vacancy/DeleteSavedVacancy/DeleteSavedVacancyCommandHandler.cs
@@ -14,7 +14,8 @@ public async Task<Unit> Handle(DeleteSavedVacancyCommand request, CancellationTo
         {
             var apiRequest = new PostDeleteSavedVacancyApiRequest(request.CandidateId, new PostDeleteSavedVacancyApiRequestData
             {
-                VacancyReference = request.VacancyReference
+                VacancyId = request.VacancyId,
+                DeleteAllByVacancyReference = request.DeleteAllByVacancyReference
             });
             await _apiClient.PostWithResponseCode(apiRequest);
 
diff --git a/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommand.cs b/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommand.cs
index 623f27bdb..7114f8195 100644
--- a/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommand.cs
+++ b/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommand.cs
@@ -5,6 +5,6 @@ namespace SFA.DAS.FAA.Application.Commands.Vacancy.SaveVacancy
     public record SaveVacancyCommand : IRequest<SaveVacancyCommandResult>
     {
         public Guid CandidateId { get; init; }
-        public required string VacancyReference { get; init; }
+        public required string VacancyId { get; init; }
     }
 }
\ No newline at end of file
diff --git a/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommandHandler.cs b/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommandHandler.cs
index 0569ad07f..2715566ad 100644
--- a/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommandHandler.cs
+++ b/src/SFA.DAS.FAA.Application/Commands/Vacancy/SaveVacancy/SaveVacancyCommandHandler.cs
@@ -17,7 +17,7 @@ public async Task<SaveVacancyCommandResult> Handle(SaveVacancyCommand request, C
         {
             var data = new PostSaveVacancyApiRequestData
             {
-                VacancyReference = request.VacancyReference
+                VacancyId = request.VacancyId
             };
 
             var apiRequest = new PostSaveVacancyApiRequest(request.CandidateId, data);
diff --git a/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenDeletingSavedVacancyCommand.cs b/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenDeletingSavedVacancyCommand.cs
index b774cb999..53f27a89e 100644
--- a/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenDeletingSavedVacancyCommand.cs
+++ b/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenDeletingSavedVacancyCommand.cs
@@ -4,9 +4,11 @@
 using Moq;
 using NUnit.Framework;
 using SFA.DAS.FAA.Application.Commands.Vacancy.DeleteSavedVacancy;
+using SFA.DAS.FAA.Domain;
 using SFA.DAS.FAA.Domain.Interfaces;
 using SFA.DAS.FAA.Domain.SavedVacancies;
 using SFA.DAS.Testing.AutoFixture;
+using System.Net;
 
 namespace SFA.DAS.FAA.Application.UnitTests.Commands.Vacancy
 {
@@ -20,18 +22,23 @@ public async Task Then_The_CommandResult_Is_Returned_As_Expected(
             [Greedy] DeleteSavedVacancyCommandHandler handler)
         {
             var expectedApiRequest =
-                new PostDeleteSavedVacancyApiRequest(command.CandidateId, new PostDeleteSavedVacancyApiRequestData { VacancyReference = command.VacancyReference });
+                new PostDeleteSavedVacancyApiRequest(command.CandidateId, new PostDeleteSavedVacancyApiRequestData { VacancyId = command.VacancyId, DeleteAllByVacancyReference = command.DeleteAllByVacancyReference });
 
             apiClient.Setup(x =>
                     x.PostWithResponseCode(
                         It.Is<PostDeleteSavedVacancyApiRequest>(r => r.PostUrl == expectedApiRequest.PostUrl
-                                                                     && ((PostDeleteSavedVacancyApiRequestData)r.Data).VacancyReference == command.VacancyReference
-                        )));
+                                                                     && ((PostDeleteSavedVacancyApiRequestData)r.Data).VacancyId == command.VacancyId
+                                                                     && ((PostDeleteSavedVacancyApiRequestData)r.Data).DeleteAllByVacancyReference == command.DeleteAllByVacancyReference
+                        ))).Returns(Task.CompletedTask);
 
             var result = await handler.Handle(command, It.IsAny<CancellationToken>());
 
             result.Should().Be(new Unit());
-            apiClient.Verify(x => x.PostWithResponseCode(It.IsAny<PostDeleteSavedVacancyApiRequest>()), Times.Once);
+            apiClient.Verify(x =>
+                    x.PostWithResponseCode(It.Is<PostDeleteSavedVacancyApiRequest>(r => r.PostUrl == expectedApiRequest.PostUrl
+                                                                    && ((PostDeleteSavedVacancyApiRequestData)r.Data).VacancyId == command.VacancyId
+                                                                    && ((PostDeleteSavedVacancyApiRequestData)r.Data).DeleteAllByVacancyReference == command.DeleteAllByVacancyReference
+                                                                    )), Times.Once);
         }
     }
 }
\ No newline at end of file
diff --git a/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenHandlingSaveVacancyCommand.cs b/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenHandlingSaveVacancyCommand.cs
index 7cbb23458..f4c21dee6 100644
--- a/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenHandlingSaveVacancyCommand.cs
+++ b/src/SFA.DAS.FAA.ApplicationUnitTests/Commands/Vacancy/WhenHandlingSaveVacancyCommand.cs
@@ -20,12 +20,12 @@ public async Task Then_The_CommandResult_Is_Returned_As_Expected(
             [Greedy] SaveVacancyCommandHandler handler)
         {
             var expectedApiRequest =
-                new PostSaveVacancyApiRequest(command.CandidateId, new PostSaveVacancyApiRequestData{ VacancyReference = command.VacancyReference });
+                new PostSaveVacancyApiRequest(command.CandidateId, new PostSaveVacancyApiRequestData{ VacancyId = command.VacancyId});
 
             apiClient.Setup(x =>
                     x.PostWithResponseCode<PostSaveVacancyApiResponse>(
                         It.Is<PostSaveVacancyApiRequest>(r => r.PostUrl == expectedApiRequest.PostUrl
-                                                              && ((PostSaveVacancyApiRequestData)r.Data).VacancyReference == command.VacancyReference
+                                                              && ((PostSaveVacancyApiRequestData)r.Data).VacancyId == command.VacancyId
                         )))
                 .ReturnsAsync(apiResponse);
 
@@ -41,12 +41,12 @@ public async Task Then_The_CommandResult_Null_Returned_As_Expected(
             [Greedy] SaveVacancyCommandHandler handler)
         {
             var expectedApiRequest =
-                new PostSaveVacancyApiRequest(command.CandidateId, new PostSaveVacancyApiRequestData { VacancyReference = command.VacancyReference });
+                new PostSaveVacancyApiRequest(command.CandidateId, new PostSaveVacancyApiRequestData { VacancyId = command.VacancyId });
 
             apiClient.Setup(x =>
                     x.PostWithResponseCode<PostSaveVacancyApiResponse>(
                         It.Is<PostSaveVacancyApiRequest>(r => r.PostUrl == expectedApiRequest.PostUrl
-                                                              && ((PostSaveVacancyApiRequestData)r.Data).VacancyReference == command.VacancyReference
+                                                              && ((PostSaveVacancyApiRequestData)r.Data).VacancyId == command.VacancyId 
                         )))
                 .ReturnsAsync(() => null);
 
diff --git a/src/SFA.DAS.FAA.ApplicationUnitTests/Queries/SavedVacancies/WhenHandlingGetIndexQuery.cs b/src/SFA.DAS.FAA.ApplicationUnitTests/Queries/SavedVacancies/WhenHandlingGetIndexQuery.cs
index 2aa4d8198..5c9a048c3 100644
--- a/src/SFA.DAS.FAA.ApplicationUnitTests/Queries/SavedVacancies/WhenHandlingGetIndexQuery.cs
+++ b/src/SFA.DAS.FAA.ApplicationUnitTests/Queries/SavedVacancies/WhenHandlingGetIndexQuery.cs
@@ -61,7 +61,7 @@ public async Task Then_VacancyReference_Is_Null_Result_Is_Returned(
                 .ReturnsAsync(apiResponse);
 
 
-            var getApprenticeshipVacancyApiRequest = new GetApprenticeshipVacancyApiRequest(query.DeleteVacancyReference, null);
+            var getApprenticeshipVacancyApiRequest = new GetApprenticeshipVacancyApiRequest(query.DeleteVacancyReference!, null);
 
             apiClientMock.Setup(client =>
                     client.Get<GetApprenticeshipVacancyApiResponse>(
@@ -76,7 +76,7 @@ public async Task Then_VacancyReference_Is_Null_Result_Is_Returned(
             result.SavedVacancies.Should().BeEquivalentTo(apiResponse.SavedVacancies, options => options
                 .Excluding(x => x.Address)
                 .Excluding(x => x.OtherAddresses));
-            result.DeletedVacancy.EmployerName.Should().Be(getApprenticeshipVacancyApiResponse.EmployerName);
+            result.DeletedVacancy!.EmployerName.Should().Be(getApprenticeshipVacancyApiResponse.EmployerName);
             result.DeletedVacancy.VacancyTitle.Should().Be(getApprenticeshipVacancyApiResponse.Title);
             result.DeletedVacancy.VacancyReference.Should().Be(getApprenticeshipVacancyApiResponse.VacancyReference);
         }
diff --git a/src/SFA.DAS.FAA.Domain/SavedVacancies/PostDeleteSavedVacancyApiRequest.cs b/src/SFA.DAS.FAA.Domain/SavedVacancies/PostDeleteSavedVacancyApiRequest.cs
index 4a6d9d96d..97f74eda0 100644
--- a/src/SFA.DAS.FAA.Domain/SavedVacancies/PostDeleteSavedVacancyApiRequest.cs
+++ b/src/SFA.DAS.FAA.Domain/SavedVacancies/PostDeleteSavedVacancyApiRequest.cs
@@ -10,6 +10,7 @@ public record PostDeleteSavedVacancyApiRequest(Guid CandidateId, PostDeleteSaved
 
     public record PostDeleteSavedVacancyApiRequestData
     {
-        public required string VacancyReference { get; set; }
+        public required string VacancyId { get; set; }
+        public bool DeleteAllByVacancyReference { get; set; }
     }
 }
\ No newline at end of file
diff --git a/src/SFA.DAS.FAA.Domain/SavedVacancies/PostSaveVacancyApiRequest.cs b/src/SFA.DAS.FAA.Domain/SavedVacancies/PostSaveVacancyApiRequest.cs
index da68089ee..d33579f24 100644
--- a/src/SFA.DAS.FAA.Domain/SavedVacancies/PostSaveVacancyApiRequest.cs
+++ b/src/SFA.DAS.FAA.Domain/SavedVacancies/PostSaveVacancyApiRequest.cs
@@ -11,7 +11,7 @@ public record PostSaveVacancyApiRequest(Guid CandidateId, PostSaveVacancyApiRequ
 
     public record PostSaveVacancyApiRequestData
     {
-        public required string VacancyReference { get; set; }
+        public required string VacancyId { get; set; }
     }
 
     public record PostSaveVacancyApiResponse
diff --git a/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostDeleteSavedVacancyApiRequest.cs b/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostDeleteSavedVacancyApiRequest.cs
index 03da72521..2784b770b 100644
--- a/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostDeleteSavedVacancyApiRequest.cs
+++ b/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostDeleteSavedVacancyApiRequest.cs
@@ -11,11 +11,13 @@ public class WhenBuildingPostDeleteSavedVacancyApiRequest
         [Test, AutoData]
         public void Then_Then_Request_Is_Built(
             Guid candidateId,
-            string vacancyReference)
+            string vacancyId,
+            bool deleteAllByVacancyReference)
         {
             var data = new PostDeleteSavedVacancyApiRequestData
             {
-                VacancyReference = vacancyReference
+                VacancyId = vacancyId,
+                DeleteAllByVacancyReference = deleteAllByVacancyReference
             };
             var actual = new PostDeleteSavedVacancyApiRequest(candidateId, data);
 
diff --git a/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostSaveVacancyApiRequest.cs b/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostSaveVacancyApiRequest.cs
index 9c003febb..a472f0d3c 100644
--- a/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostSaveVacancyApiRequest.cs
+++ b/src/SFA.DAS.FAA.DomainUnitTests/Vacancy/WhenBuildingPostSaveVacancyApiRequest.cs
@@ -11,11 +11,11 @@ public class WhenBuildingPostSaveVacancyApiRequest
         [Test, AutoData]
         public void Then_Then_Request_Is_Built(
             Guid candidateId,
-            string vacancyReference)
+            string vacancyId)
         {
             var data = new PostSaveVacancyApiRequestData
             {
-                VacancyReference = vacancyReference
+                VacancyId = vacancyId
             };
             var actual = new PostSaveVacancyApiRequest(candidateId, data);
 
diff --git a/src/SFA.DAS.FAA.Web.AcceptanceTests/SFA.DAS.FAA.Web.AcceptanceTests.csproj b/src/SFA.DAS.FAA.Web.AcceptanceTests/SFA.DAS.FAA.Web.AcceptanceTests.csproj
index 1c18922e6..e08630b66 100644
--- a/src/SFA.DAS.FAA.Web.AcceptanceTests/SFA.DAS.FAA.Web.AcceptanceTests.csproj
+++ b/src/SFA.DAS.FAA.Web.AcceptanceTests/SFA.DAS.FAA.Web.AcceptanceTests.csproj
@@ -10,6 +10,7 @@
 	<ItemGroup>
 		<PackageReference Include="Azure.Identity" Version="1.13.2" />
 		<PackageReference Include="FluentAssertions" Version="7.1.0" />
+		<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.23.0" />
 		<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.13" />
 		<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.11.0" />
 		<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
diff --git a/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenDeletingSavedVacancy.cs b/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenDeletingSavedVacancy.cs
index 254c2c1b7..764169e60 100644
--- a/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenDeletingSavedVacancy.cs
+++ b/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenDeletingSavedVacancy.cs
@@ -21,7 +21,7 @@ public class WhenDeletingSavedVacancy
         [Test, MoqAutoData]
         public async Task Then_If_Command_Returns_Redirect_Returned(
             Guid candidateId,
-            string vacancyReference,
+            string vacancyId,
             IDateTimeService dateTimeService,
             [Frozen] Mock<IMediator> mediator,
             [Greedy] Web.Controllers.VacanciesController controller)
@@ -38,20 +38,22 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
 
                 }
             };
+            var vacancyReference = vacancyId.Split('-')[0];
 
-            var actual = await controller.VacancyDetailsDeleteSavedVacancy(vacancyReference, true) as RedirectToRouteResult;
+            var actual = await controller.VacancyDetailsDeleteSavedVacancy(vacancyId, true) as RedirectToRouteResult;
 
             actual!.RouteName.Should().Be(RouteNames.Vacancies);
             actual.RouteValues.Should().NotBeEmpty();
             actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference);
 
-            mediator.Verify(x => x.Send(It.IsAny<DeleteSavedVacancyCommand>(), It.IsAny<CancellationToken>()), Times.Once);
+            mediator.Verify(x => x.Send(It.Is<DeleteSavedVacancyCommand>(c =>
+                c.VacancyId == vacancyId && c.CandidateId == candidateId), It.IsAny<CancellationToken>()), Times.Once);
         }
 
         [Test, MoqAutoData]
         public async Task Then_If_Command_Returns_JsonOk_Returned(
             Guid candidateId,
-            string vacancyReference,
+            string vacancyId,
             IDateTimeService dateTimeService,
             [Frozen] Mock<IMediator> mediator,
             [Greedy] Web.Controllers.VacanciesController controller)
@@ -68,12 +70,13 @@ public async Task Then_If_Command_Returns_JsonOk_Returned(
 
                 }
             };
+            var vacancyReference = vacancyId.Split('-')[0];
 
-            var actual = await controller.VacancyDetailsDeleteSavedVacancy(vacancyReference, false) as JsonResult;
+            var actual = await controller.VacancyDetailsDeleteSavedVacancy(vacancyId, false) as JsonResult;
 
             actual!.Value.Should().Be(StatusCodes.Status200OK);
 
-            mediator.Verify(x => x.Send(It.IsAny<DeleteSavedVacancyCommand>(), It.IsAny<CancellationToken>()), Times.Once);
+            mediator.Verify(x => x.Send(It.Is<DeleteSavedVacancyCommand>(c => c.VacancyId == vacancyId && c.CandidateId == candidateId), It.IsAny<CancellationToken>()), Times.Once);
         }
     }
 }
\ No newline at end of file
diff --git a/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenPostingSaveVacancy.cs b/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenPostingSaveVacancy.cs
index 9bdab7368..7824be7e9 100644
--- a/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenPostingSaveVacancy.cs
+++ b/src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenPostingSaveVacancy.cs
@@ -20,7 +20,7 @@ public class WhenPostingSaveVacancy
         [Test, MoqAutoData]
         public async Task Then_If_Command_Returns_Redirect_Returned(
             Guid candidateId,
-            string vacancyReference,
+            string vacancyId,
             SaveVacancyCommandResult mediatorResult,
             IDateTimeService dateTimeService,
             [Frozen] Mock<IMediator> mediator,
@@ -38,10 +38,12 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
 
                 }
             };
-            mediator.Setup(x => x.Send(It.IsAny<SaveVacancyCommand>(), It.IsAny<CancellationToken>()))
+            mediator.Setup(x => x.Send(It.Is<SaveVacancyCommand>(c =>
+                c.VacancyId == vacancyId && c.CandidateId == candidateId), It.IsAny<CancellationToken>()))
                 .ReturnsAsync(mediatorResult);
+            var vacancyReference = vacancyId.Split('-')[0];
 
-            var actual = await controller.VacancyDetailsSaveVacancy(vacancyReference) as RedirectToRouteResult;
+            var actual = await controller.VacancyDetailsSaveVacancy(vacancyId) as RedirectToRouteResult;
 
             actual!.RouteName.Should().Be(RouteNames.Vacancies);
             actual.RouteValues.Should().NotBeEmpty();
@@ -51,7 +53,7 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
         [Test, MoqAutoData]
         public async Task Then_If_Query_With_Redirect_Command_Returns_JsonOk_Returned(
             Guid candidateId,
-            string vacancyReference,
+            string vacancyId,
             SaveVacancyCommandResult mediatorResult,
             IDateTimeService dateTimeService,
             [Frozen] Mock<IMediator> mediator,
@@ -69,10 +71,11 @@ public async Task Then_If_Query_With_Redirect_Command_Returns_JsonOk_Returned(
 
                 }
             };
-            mediator.Setup(x => x.Send(It.IsAny<SaveVacancyCommand>(), It.IsAny<CancellationToken>()))
+            mediator.Setup(x => x.Send(It.Is<SaveVacancyCommand>(c =>
+                c.VacancyId == vacancyId && c.CandidateId == candidateId), It.IsAny<CancellationToken>()))
                 .ReturnsAsync(mediatorResult);
 
-            var actual = await controller.VacancyDetailsSaveVacancy(vacancyReference, false) as JsonResult;
+            var actual = await controller.VacancyDetailsSaveVacancy(vacancyId, false) as JsonResult;
 
             actual!.Value.Should().Be(StatusCodes.Status200OK);
         }
diff --git a/src/SFA.DAS.FAA.Web.UnitTests/SFA.DAS.FAA.Web.UnitTests.csproj b/src/SFA.DAS.FAA.Web.UnitTests/SFA.DAS.FAA.Web.UnitTests.csproj
index c65382e6b..72e748799 100644
--- a/src/SFA.DAS.FAA.Web.UnitTests/SFA.DAS.FAA.Web.UnitTests.csproj
+++ b/src/SFA.DAS.FAA.Web.UnitTests/SFA.DAS.FAA.Web.UnitTests.csproj
@@ -17,6 +17,7 @@
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
     <PackageReference Include="FluentAssertions" Version="7.1.0" />
+    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.23.0" />
     <PackageReference Include="Moq" Version="4.20.72" />
     <PackageReference Include="NUnit" Version="4.3.2" />
     <PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
diff --git a/src/SFA.DAS.FAA.Web/Controllers/SavedVacanciesController.cs b/src/SFA.DAS.FAA.Web/Controllers/SavedVacanciesController.cs
index 06e3d2e42..cfde1162b 100644
--- a/src/SFA.DAS.FAA.Web/Controllers/SavedVacanciesController.cs
+++ b/src/SFA.DAS.FAA.Web/Controllers/SavedVacanciesController.cs
@@ -37,8 +37,9 @@ public async Task<IActionResult> DeleteSavedVacancy([FromRoute] string vacancyRe
         {
             await mediator.Send(new DeleteSavedVacancyCommand
             {
-                VacancyReference = vacancyReference,
-                CandidateId = (Guid)User.Claims.CandidateId()!
+                VacancyId = vacancyReference,
+                CandidateId = (Guid)User.Claims.CandidateId()!,
+                DeleteAllByVacancyReference = true
             });
 
             return RedirectToRoute(RouteNames.SavedVacancies, new
diff --git a/src/SFA.DAS.FAA.Web/Controllers/SearchApprenticeshipsController.cs b/src/SFA.DAS.FAA.Web/Controllers/SearchApprenticeshipsController.cs
index a25271921..85555412c 100644
--- a/src/SFA.DAS.FAA.Web/Controllers/SearchApprenticeshipsController.cs
+++ b/src/SFA.DAS.FAA.Web/Controllers/SearchApprenticeshipsController.cs
@@ -317,12 +317,12 @@ public async Task<IActionResult> MapSearchResults([FromQuery] GetSearchResultsRe
 
     [HttpPost]
     [Authorize(Policy = nameof(PolicyNames.IsFaaUser))]
-    [Route("search-results/save/{vacancyReference}", Name = RouteNames.SaveVacancyFromSearchResultsPage)]
-    public async Task<IActionResult> SearchResultsSaveVacancy([FromRoute] string vacancyReference, [FromQuery] bool redirect = true)
+    [Route("search-results/save/{vacancyId}", Name = RouteNames.SaveVacancyFromSearchResultsPage)]
+    public async Task<IActionResult> SearchResultsSaveVacancy([FromRoute] string vacancyId, [FromQuery] bool redirect = true)
     {
         await mediator.Send(new SaveVacancyCommand
         {
-            VacancyReference = vacancyReference,
+            VacancyId = vacancyId,
             CandidateId = (Guid)User.Claims.CandidateId()!
         });
 
@@ -335,12 +335,12 @@ await mediator.Send(new SaveVacancyCommand
 
     [HttpPost]
     [Authorize(Policy = nameof(PolicyNames.IsFaaUser))]
-    [Route("search-results/delete/{vacancyReference}", Name = RouteNames.DeleteSavedVacancyFromSearchResultsPage)]
-    public async Task<IActionResult> SearchResultsDeleteSavedVacancy([FromRoute] string vacancyReference, [FromQuery] bool redirect = true)
+    [Route("search-results/delete/{vacancyId}", Name = RouteNames.DeleteSavedVacancyFromSearchResultsPage)]
+    public async Task<IActionResult> SearchResultsDeleteSavedVacancy([FromRoute] string vacancyId, [FromQuery] bool redirect = true)
     {
         await mediator.Send(new DeleteSavedVacancyCommand
         {
-            VacancyReference = vacancyReference,
+            VacancyId = vacancyId,
             CandidateId = (Guid)User.Claims.CandidateId()!
         });
 
diff --git a/src/SFA.DAS.FAA.Web/Controllers/VacanciesController.cs b/src/SFA.DAS.FAA.Web/Controllers/VacanciesController.cs
index b4c886b73..62d645c7a 100644
--- a/src/SFA.DAS.FAA.Web/Controllers/VacanciesController.cs
+++ b/src/SFA.DAS.FAA.Web/Controllers/VacanciesController.cs
@@ -80,15 +80,17 @@ public async Task<IActionResult> Apply([FromRoute] PostApplyRequest request)
 
     [HttpPost]
     [Authorize(Policy = nameof(PolicyNames.IsFaaUser))]
-    [Route("vacancy/save/{vacancyReference}", Name = RouteNames.SaveVacancyFromDetailsPage)]
-    public async Task<IActionResult> VacancyDetailsSaveVacancy([FromRoute] string vacancyReference, [FromQuery] bool redirect = true)
+    [Route("vacancy/save/{vacancyId}", Name = RouteNames.SaveVacancyFromDetailsPage)]
+    public async Task<IActionResult> VacancyDetailsSaveVacancy([FromRoute] string vacancyId, [FromQuery] bool redirect = true)
     {
         await mediator.Send(new SaveVacancyCommand
         {
-            VacancyReference = vacancyReference,
+            VacancyId = vacancyId,
             CandidateId = (Guid)User.Claims.CandidateId()!
         });
 
+        var vacancyReference = vacancyId.Split('-')[0];
+
         return redirect
             ? RedirectToRoute(RouteNames.Vacancies, new { vacancyReference })
             : new JsonResult(StatusCodes.Status200OK);
@@ -96,15 +98,18 @@ await mediator.Send(new SaveVacancyCommand
 
     [HttpPost]
     [Authorize(Policy = nameof(PolicyNames.IsFaaUser))]
-    [Route("vacancy/delete/{vacancyReference}", Name = RouteNames.DeleteSavedVacancyFromDetailsPage)]
-    public async Task<IActionResult> VacancyDetailsDeleteSavedVacancy([FromRoute] string vacancyReference, [FromQuery] bool redirect = true)
+    [Route("vacancy/delete/{vacancyId}", Name = RouteNames.DeleteSavedVacancyFromDetailsPage)]
+    public async Task<IActionResult> VacancyDetailsDeleteSavedVacancy([FromRoute] string vacancyId, [FromQuery] bool redirect = true)
     {
         await mediator.Send(new DeleteSavedVacancyCommand
         {
-            VacancyReference = vacancyReference,
-            CandidateId = (Guid)User.Claims.CandidateId()!
+            VacancyId = vacancyId,
+            CandidateId = (Guid)User.Claims.CandidateId()!,
+            DeleteAllByVacancyReference = true
         });
 
+        var vacancyReference = vacancyId.Split('-')[0];
+
         return redirect
             ? RedirectToRoute(RouteNames.Vacancies, new { vacancyReference })
             : new JsonResult(StatusCodes.Status200OK);
diff --git a/src/SFA.DAS.FAA.Web/Models/Vacancy/VacancyDetailsViewModel.cs b/src/SFA.DAS.FAA.Web/Models/Vacancy/VacancyDetailsViewModel.cs
index bb816b66c..ff64e9984 100644
--- a/src/SFA.DAS.FAA.Web/Models/Vacancy/VacancyDetailsViewModel.cs
+++ b/src/SFA.DAS.FAA.Web/Models/Vacancy/VacancyDetailsViewModel.cs
@@ -22,6 +22,7 @@ public class VacancyDetailsViewModel : NhsVacancyDetailsViewModel
         public string? ContactPhone { get; init; }
         public string? EmployerDescription { get; init; }
         public string? EmployerWebsite { get; init; }
+        public string? VacancyId { get; init; }
         public string? VacancyReference { get; init; }
         public string? VacancySummary { get; init; }
         public string? AnnualWage { get; init; }
@@ -151,6 +152,7 @@ public VacancyDetailsViewModel MapToViewModel(IDateTimeService dateTimeService,
                 Title = source.Vacancy?.Title,
                 TrainingPlan = source.Vacancy?.TrainingDescription.MakeSingleItemListsAccessible(),
                 TrainingProviderName = source.Vacancy?.ProviderName,
+                VacancyId = source.Vacancy?.Id,
                 VacancyReference = source.Vacancy?.VacancyReference,
                 VacancySource = source.Vacancy.VacancySource,
                 VacancySummary = source.Vacancy?.Description,
diff --git a/src/SFA.DAS.FAA.Web/Models/VacancyAdvertViewModel.cs b/src/SFA.DAS.FAA.Web/Models/VacancyAdvertViewModel.cs
index e96160c8d..39ddf1508 100644
--- a/src/SFA.DAS.FAA.Web/Models/VacancyAdvertViewModel.cs
+++ b/src/SFA.DAS.FAA.Web/Models/VacancyAdvertViewModel.cs
@@ -19,6 +19,7 @@ public class VacancyAdvertViewModel
     public decimal? Distance { get; private set; }
     public string ClosingDateDescription { get; private set; }
     public string VacancyReference { get; private set; }
+    public string VacancyId { get; set; }
     public string WageText { get; set; }
     public ApplicationStatus? ApplicationStatus { get; set; }
     public bool IsClosingSoon { get; set; }
@@ -49,6 +50,7 @@ public static VacancyAdvertViewModel MapToViewModel(IDateTimeService dateTimeSer
             Title = vacancyAdvert.VacancySource == VacancyDataSource.Nhs ? $"{vacancyAdvert.Title} (from NHS Jobs)" : vacancyAdvert.Title,
             VacancyLocation = vacancyAdvert.GetLocationDescription(),
             VacancyReference = vacancyAdvert.VacancyReference,
+            VacancyId = vacancyAdvert.Id,
             VacancySource = vacancyAdvert.VacancySource,
             WageText = vacancyAdvert.VacancySource == VacancyDataSource.Nhs 
                 ? VacancyDetailsHelperService.GetNhsWageText(vacancyAdvert.WageText) : VacancyDetailsHelperService.GetVacancyAdvertWageText(vacancyAdvert, candidateDateOfBirth),
diff --git a/src/SFA.DAS.FAA.Web/SFA.DAS.FAA.Web.csproj b/src/SFA.DAS.FAA.Web/SFA.DAS.FAA.Web.csproj
index 96d721bf7..136d8374d 100644
--- a/src/SFA.DAS.FAA.Web/SFA.DAS.FAA.Web.csproj
+++ b/src/SFA.DAS.FAA.Web/SFA.DAS.FAA.Web.csproj
@@ -12,7 +12,7 @@
     <PackageReference Include="FluentValidation" Version="11.11.0" />
     <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
     <PackageReference Include="HtmlTextWriter" Version="3.0.1" />
-    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
+    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.23.0" />
     <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.15" />
     <PackageReference Include="MediatR" Version="12.4.1" />
     <PackageReference Include="SFA.DAS.Configuration.AzureTableStorage" Version="17.1.113" />
diff --git a/src/SFA.DAS.FAA.Web/Views/SavedVacancies/Index.cshtml b/src/SFA.DAS.FAA.Web/Views/SavedVacancies/Index.cshtml
index 4a284bef1..4c697b5b2 100644
--- a/src/SFA.DAS.FAA.Web/Views/SavedVacancies/Index.cshtml
+++ b/src/SFA.DAS.FAA.Web/Views/SavedVacancies/Index.cshtml
@@ -19,7 +19,7 @@
                 <div class="govuk-notification-banner__content">
                     <h3 class="govuk-notification-banner__heading">
                         Removed <a class="govuk-notification-banner__link"
-                            href="@Url.RouteUrl(RouteNames.Vacancies, new { vacancyReference = @Model.DeletedVacancy.VacancyReference })">@Model.DeletedVacancy.VacancyTitle</a>
+                            href="@Url.RouteUrl(RouteNames.Vacancies, new { vacancyReference = @Model.DeletedVacancy.VacancyReference})">@Model.DeletedVacancy.VacancyTitle</a>
                         at @Model.DeletedVacancy.EmployerName.
                     </h3>
                 </div>
diff --git a/src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml b/src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
index 0b0a98203..879b9776c 100644
--- a/src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
+++ b/src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
@@ -261,7 +261,7 @@
                                     <div data-favourite="true"
                                          class="faa-save-vacancy @(vacancyAdvert.IsSavedVacancy ? "faa-save-vacancy--saved" : "")">
                                         <form method="post" asp-route="@RouteNames.DeleteSavedVacancyFromSearchResultsPage"
-                                              asp-route-vacancyReference="@vacancyAdvert.VacancyReference">
+                                              asp-route-vacancyId="@vacancyAdvert.VacancyId">
                                             <button type="submit"
                                                     class="govuk-link govuk-link--no-visited-state faa-vacancy-actions__link faa-save-vacancy__link--delete"
                                                     data-delete-favourite="true"
@@ -277,7 +277,7 @@
                                             </button>
                                         </form>
                                         <form method="post" asp-route="@RouteNames.SaveVacancyFromSearchResultsPage"
-                                              asp-route-vacancyReference="@vacancyAdvert.VacancyReference">
+                                              asp-route-vacancyId="@vacancyAdvert.VacancyId">
                                             <button type="submit"
                                                     class="govuk-link govuk-link--no-visited-state faa-vacancy-actions__link  faa-save-vacancy__link--save"
                                                     aria-pressed="false"
diff --git a/src/SFA.DAS.FAA.Web/Views/Vacancies/_LiveVacancy.cshtml b/src/SFA.DAS.FAA.Web/Views/Vacancies/_LiveVacancy.cshtml
index 622ae56e7..5976eb682 100644
--- a/src/SFA.DAS.FAA.Web/Views/Vacancies/_LiveVacancy.cshtml
+++ b/src/SFA.DAS.FAA.Web/Views/Vacancies/_LiveVacancy.cshtml
@@ -86,7 +86,7 @@
         {
             <div data-favourite="true" class="faa-save-vacancy @(Model.IsSavedVacancy ? "faa-save-vacancy--saved" : "")">
                 <form method="post" asp-route="@RouteNames.DeleteSavedVacancyFromDetailsPage"
-                      asp-route-vacancyreference="@Model.VacancyReference">
+                      asp-route-vacancyId="@Model.VacancyId">
                     <button aria-describeby="Remove-@Model.VacancyReference"
                         aria-pressed="true" 
                         aria-describedby="vacancy-title"
@@ -100,7 +100,7 @@
                     </button>
                 </form>
                 <form method="post" asp-route="@RouteNames.SaveVacancyFromDetailsPage"
-                      asp-route-vacancyreference="@Model.VacancyReference">
+                      asp-route-vacancyId="@Model.VacancyId">
                     <button aria-describeby="Save-@Model.VacancyReference"
                         aria-pressed="false"
                         aria-describedby="vacancy-title"


Reviews:
user: login: dashton82
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T06:54:19Z
user: login: LACrossley
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T13:35:32Z
user: login: LACrossley
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T13:37:24Z
user: login: LACrossley
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T13:46:22Z
user: login: LACrossley
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T13:47:49Z
user: login: dashton82
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T07:12:03Z
user: login: dashton82
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T09:13:48Z
user: login: balaji-j
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T09:20:15Z

Review comments:
diff_hunk: @@ -245,6 +245,7 @@
                                     <h2 class="govuk-heading-m das-search-results__heading govuk-!-margin-bottom-1">
                                         <a asp-route="@RouteNames.Vacancies"
                                            asp-route-vacancyReference="@vacancyAdvert.VacancyReference"
+                                           asp-route-vacancyId="@(vacancyAdvert.VacancySource == VacancyDataSource.Raa ? vacancyAdvert.VacancyId : null)"
path: src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
user: login: dashton82
body: I don't think this is required, and leaving here will add a unwanted query string param
created_at: 2025-05-01T20:59:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -271,7 +272,8 @@
                                             </button>
                                         </form>
                                         <form method="post" asp-route="@RouteNames.SaveVacancyFromSearchResultsPage"
-                                              asp-route-vacancyReference="@vacancyAdvert.VacancyReference">
+                                              asp-route-vacancyReference="@vacancyAdvert.VacancyReference"
path: src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
user: login: dashton82
body: Just vacancyId is needed here, vacancyReference can go
created_at: 2025-05-01T21:04:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,7 +45,7 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
 
             actual!.RouteName.Should().Be(RouteNames.Vacancies);
             actual.RouteValues.Should().NotBeEmpty();
-            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference);
+            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference.Split('-')[0]);
path: src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenPostingSaveVacancy.cs
user: login: dashton82
body: I think we should check that in the `SaveVacancyCommand` its set correctly
```
mediator.Setup(x => x.Send(It.Is<SaveVacancyCommand>(c=>
                    c.VacancyId == vacancyReference && c.CandidateId == candidateId), It.IsAny<CancellationToken>()))
                .ReturnsAsync(mediatorResult);
```
Also id rename the variable in the test to `vacancyId`
Then also change the setup so its clearer on that assertion beingn correct, at the moment the variable being set through AutoData will be vacancyRef{Guid}
created_at: 2025-05-01T21:29:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,7 +43,7 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
 
             actual!.RouteName.Should().Be(RouteNames.Vacancies);
             actual.RouteValues.Should().NotBeEmpty();
-            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference);
+            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference.Split('-')[0]);
 
             mediator.Verify(x => x.Send(It.IsAny<DeleteSavedVacancyCommand>(), It.IsAny<CancellationToken>()), Times.Once);
path: src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenDeletingSavedVacancy.cs
user: login: dashton82
body: Should probably validate this in the verify as well below
created_at: 2025-05-01T21:40:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -245,6 +245,7 @@
                                     <h2 class="govuk-heading-m das-search-results__heading govuk-!-margin-bottom-1">
                                         <a asp-route="@RouteNames.Vacancies"
                                            asp-route-vacancyReference="@vacancyAdvert.VacancyReference"
+                                           asp-route-vacancyId="@(vacancyAdvert.VacancySource == VacancyDataSource.Raa ? vacancyAdvert.VacancyId : null)"
path: src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
user: login: LACrossley
body: Removed from the latest commit. 

I'd added this when I thought we'd need the selected vacancyId on the vacancy details page to preserve the save/delete functionality for the specific location selected. Instead we decided I should refactor the commands from the vacancy details page and I forgot to delete this query param. The commands from the vacancy details now save the first location's vacancyId, as it did before, and delete all saved vacancyIds that share the same vacancyReference.
created_at: 2025-05-06T13:35:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -271,7 +272,8 @@
                                             </button>
                                         </form>
                                         <form method="post" asp-route="@RouteNames.SaveVacancyFromSearchResultsPage"
-                                              asp-route-vacancyReference="@vacancyAdvert.VacancyReference">
+                                              asp-route-vacancyReference="@vacancyAdvert.VacancyReference"
path: src/SFA.DAS.FAA.Web/Views/SearchApprenticeships/SearchResults.cshtml
user: login: LACrossley
body: Amended in latest commit.
created_at: 2025-05-06T13:37:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -45,7 +45,7 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
 
             actual!.RouteName.Should().Be(RouteNames.Vacancies);
             actual.RouteValues.Should().NotBeEmpty();
-            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference);
+            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference.Split('-')[0]);
path: src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenPostingSaveVacancy.cs
user: login: LACrossley
body: The command accepts the vacancyId and the controller redirects using the vacancyReference cut from the Id.
created_at: 2025-05-06T13:46:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,7 +43,7 @@ public async Task Then_If_Command_Returns_Redirect_Returned(
 
             actual!.RouteName.Should().Be(RouteNames.Vacancies);
             actual.RouteValues.Should().NotBeEmpty();
-            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference);
+            actual.RouteValues!["VacancyReference"].Should().Be(vacancyReference.Split('-')[0]);
 
             mediator.Verify(x => x.Send(It.IsAny<DeleteSavedVacancyCommand>(), It.IsAny<CancellationToken>()), Times.Once);
path: src/SFA.DAS.FAA.Web.UnitTests/Controllers/Vacancies/WhenDeletingSavedVacancy.cs
user: login: LACrossley
body: Added in latest.
created_at: 2025-05-06T13:47:49Z
author_association: CONTRIBUTOR

PR comments:
user: login: das-github-app[bot]
created_at: 2025-05-01T20:40:32Z
body: Please remember to check any packages used by this application to ensure they are up to date @LACrossley. cc/ @ecarroll95
author_association: NONE
user: login: das-github-app[bot]
created_at: 2025-05-06T13:34:33Z
body: Please remember to check any packages used by this application to ensure they are up to date @LACrossley. cc/ @ecarroll95
author_association: NONE
user: login: das-github-app[bot]
created_at: 2025-05-09T11:14:51Z
body: Please remember to check any packages used by this application to ensure they are up to date @LACrossley. cc/ @ecarroll95
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-05-09T11:18:54Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [100.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=SkillsFundingAgency_das-findapprenticeship-web&pullRequest=316)


author_association: NONE