From 46ab6e5c19d6083d8848f4880472a030d0b6bcb3 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Fri, 6 Feb 2026 15:53:22 +0000 Subject: [PATCH 1/5] removed stadardCode --- .../LearnersController/WhenIGetById.cs | 1 - .../LearnersController/WhenISave.cs | 2 -- .../Responses/GetAllLearnersResponseTests.cs | 2 +- .../Controllers/ProviderLearnersController.cs | 1 - .../Models/Requests/SaveLearnerRequest.cs | 1 - .../Responses/GetAllLearnersResponse.cs | 2 -- .../Responses/GetLearnerByIdResponse.cs | 2 -- .../Models/Responses/GetSearchResponse.cs | 4 ++-- .../PostDeployment/Script.PostDeployment.sql | 7 +------ .../Tables/LearnerData.sql | 1 - .../ChangeSummary.cs | 9 --------- .../GetAllLearnersQueryHandlerTests.cs | 1 - .../GetLearnerByIdQueryHandlerTests.cs | 1 - .../Services/ChangeTrackingServiceTests.cs | 19 +------------------ .../SaveLearner/SaveLearnerNewCommand.cs | 1 - .../GetAll/GetForProviderQueryHandler.cs | 1 - .../Queries/GetAll/GetForProviderResult.cs | 1 - .../GetAllLearnersQueryHandler.cs | 1 - .../GetAllLearners/GetAllLearnersResult.cs | 1 - .../GetLearnerByIdQueryHandler.cs | 1 - .../GetLearnerById/GetLearnerByIdResult.cs | 1 - .../GetSearch/GetSearchQueryHandler.cs | 2 +- .../Queries/GetSearch/GetSearchResult.cs | 2 +- .../Data/Entities/Learner.cs | 2 -- .../Data/Repositories/LearnerRepository.cs | 3 +-- .../Services/ChangeTrackingService.cs | 5 ----- 26 files changed, 8 insertions(+), 66 deletions(-) diff --git a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs index c55f8a2..090dcc1 100644 --- a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs +++ b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs @@ -48,7 +48,6 @@ [Greedy] Api.Controllers.ProviderLearnersController sut response.EpaoPrice.Should().Be(learner.EpaoPrice); response.TrainingPrice.Should().Be(learner.TrainingPrice); response.AgreementId.Should().Be(learner.AgreementId); - response.StandardCode.Should().Be(learner.StandardCode); response.TrainingCode.Should().Be(learner.TrainingCode); response.TrainingName.Should().Be(learner.TrainingName); response.LearningType.Should().Be(learner.LearningType?.GetEnumDescription()); diff --git a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenISave.cs b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenISave.cs index 697e029..dacf3c9 100644 --- a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenISave.cs +++ b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenISave.cs @@ -110,7 +110,6 @@ [Greedy] Api.Controllers.ProviderLearnersController sut && ctx.ConsumerReference == request.ConsumerReference && ctx.CorrelationId == request.CorrelationId && ctx.ReceivedDate == request.ReceivedDate - && ctx.StandardCode == request.StandardCode && ctx.TrainingCode == request.LarsCode && ctx.TrainingName == request.TrainingName && ctx.LearningType == request.LearningType @@ -164,7 +163,6 @@ [Greedy] Api.Controllers.ProviderLearnersController sut && ctx.ConsumerReference == request.ConsumerReference && ctx.CorrelationId == request.CorrelationId && ctx.ReceivedDate == request.ReceivedDate - && ctx.StandardCode == request.StandardCode && ctx.TrainingCode == request.LarsCode && ctx.TrainingName == request.TrainingName && ctx.LearningType == request.LearningType diff --git a/src/SFA.DAS.LearnerData.Api.UnitTests/Models/Responses/GetAllLearnersResponseTests.cs b/src/SFA.DAS.LearnerData.Api.UnitTests/Models/Responses/GetAllLearnersResponseTests.cs index 46ee4a8..5ebe436 100644 --- a/src/SFA.DAS.LearnerData.Api.UnitTests/Models/Responses/GetAllLearnersResponseTests.cs +++ b/src/SFA.DAS.LearnerData.Api.UnitTests/Models/Responses/GetAllLearnersResponseTests.cs @@ -53,7 +53,7 @@ List resultItems firstResponseItem.ConsumerReference.Should().Be(firstResultItem.ConsumerReference); firstResponseItem.CorrelationId.Should().Be(firstResultItem.CorrelationId); firstResponseItem.ReceivedDate.Should().Be(firstResultItem.ReceivedDate); - firstResponseItem.StandardCode.Should().Be(firstResultItem.StandardCode); + firstResponseItem.TrainingCode.Should().Be(firstResultItem.TrainingCode); firstResponseItem.IsFlexiJob.Should().Be(firstResultItem.IsFlexiJob); firstResponseItem.PlannedOTJTrainingHours.Should().Be(firstResultItem.PlannedOTJTrainingHours); } diff --git a/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs b/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs index 31da17d..09e3225 100644 --- a/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs +++ b/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs @@ -75,7 +75,6 @@ public async Task Save(long ukprn, long uln, [FromBody] SaveLearn ConsumerReference = request.ConsumerReference, CorrelationId = request.CorrelationId, ReceivedDate = request.ReceivedDate, - StandardCode = request.StandardCode, TrainingCode = request.LarsCode, TrainingName = request.TrainingName, LearningType = request.LearningType.Value, diff --git a/src/SFA.DAS.LearnerData.Api/Models/Requests/SaveLearnerRequest.cs b/src/SFA.DAS.LearnerData.Api/Models/Requests/SaveLearnerRequest.cs index 5be91fd..c2484e3 100644 --- a/src/SFA.DAS.LearnerData.Api/Models/Requests/SaveLearnerRequest.cs +++ b/src/SFA.DAS.LearnerData.Api/Models/Requests/SaveLearnerRequest.cs @@ -17,7 +17,6 @@ public record SaveLearnerRequest public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public string? LarsCode { get; set; } public string? TrainingName { get; set; } public LearningType? LearningType { get; set; } diff --git a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetAllLearnersResponse.cs b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetAllLearnersResponse.cs index 50fd41f..da2e3a2 100644 --- a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetAllLearnersResponse.cs +++ b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetAllLearnersResponse.cs @@ -34,7 +34,6 @@ public static GetAllLearnersResponse MapFrom(GetAllLearnersResult result) ConsumerReference = item.ConsumerReference, CorrelationId = item.CorrelationId, ReceivedDate = item.ReceivedDate, - StandardCode = item.StandardCode, TrainingCode = item.TrainingCode, TrainingName = item.TrainingName, LearningType = item.LearningType?.GetEnumDescription(), @@ -70,7 +69,6 @@ public class GetAllLearnersResponseItem public string ConsumerReference { get; set; } = string.Empty; public Guid CorrelationId { get; set; } public DateTime ReceivedDate { get; set; } - public int StandardCode { get; set; } public string? TrainingCode { get; set; } public string? TrainingName { get; set; } public string? LearningType { get; set; } diff --git a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetLearnerByIdResponse.cs b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetLearnerByIdResponse.cs index 3d9a1a9..0f95051 100644 --- a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetLearnerByIdResponse.cs +++ b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetLearnerByIdResponse.cs @@ -18,7 +18,6 @@ public record GetLearnerByIdResponse : LearnerResponse public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public string? TrainingCode { get; set; } public string? TrainingName { get; set; } public string? LearningType { get; set; } @@ -52,7 +51,6 @@ public static GetLearnerByIdResponse MapFrom(GetLearnerByIdResult result) ConsumerReference = result.ConsumerReference, CorrelationId = result.CorrelationId, ReceivedDate = result.ReceivedDate, - StandardCode = result.StandardCode, TrainingCode = result.TrainingCode, TrainingName = result.TrainingName, LearningType = result.LearningType?.GetEnumDescription(), diff --git a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs index 930efaf..48bd011 100644 --- a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs +++ b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs @@ -32,7 +32,7 @@ public static GetSearchResponse MapFrom(GetSearchResult result) ConsumerReference = item.ConsumerReference, CorrelationId = item.CorrelationId, ReceivedDate = item.ReceivedDate, - StandardCode = item.StandardCode, + TrainingCode = item.TrainingCode, IsFlexiJob = item.IsFlexiJob, PlannedOTJTrainingHours = item.PlannedOTJTrainingHours }), @@ -59,7 +59,7 @@ public record GetSearchResponseItem : LearnerResponse public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } + public string TrainingCode { get; set; } public bool IsFlexiJob { get; set; } public int PlannedOTJTrainingHours { get; set; } public DateTime ReceivedDate { get; set; } diff --git a/src/SFA.DAS.LearnerData.Database/PostDeployment/Script.PostDeployment.sql b/src/SFA.DAS.LearnerData.Database/PostDeployment/Script.PostDeployment.sql index 34922ba..eef25e4 100644 --- a/src/SFA.DAS.LearnerData.Database/PostDeployment/Script.PostDeployment.sql +++ b/src/SFA.DAS.LearnerData.Database/PostDeployment/Script.PostDeployment.sql @@ -14,9 +14,4 @@ Post-Deployment Script Template IF OBJECT_ID('dbo.Learner', 'U') IS NOT NULL BEGIN DROP TABLE dbo.Learner; -END - --- Migrate existing TrainingCode data from StandardCode -UPDATE dbo.LearnerData SET - TrainingCode = CAST(StandardCode AS NVARCHAR(20)) -WHERE TrainingCode IS NULL; +END \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData.Database/Tables/LearnerData.sql b/src/SFA.DAS.LearnerData.Database/Tables/LearnerData.sql index 46f36ac..06d2e2a 100644 --- a/src/SFA.DAS.LearnerData.Database/Tables/LearnerData.sql +++ b/src/SFA.DAS.LearnerData.Database/Tables/LearnerData.sql @@ -13,7 +13,6 @@ CREATE TABLE [dbo].[LearnerData]( [EpaoPrice] [int] NOT NULL, [TrainingPrice] [int] NOT NULL, [AgreementId] [nvarchar](20) NULL, - [StandardCode] [int] NOT NULL, [TrainingCode] [nvarchar](20) NULL, [TrainingName] [nvarchar](126) NULL, [LearningType] [tinyint] NULL, diff --git a/src/SFA.DAS.LearnerData.Messages/ChangeSummary.cs b/src/SFA.DAS.LearnerData.Messages/ChangeSummary.cs index 4f9ecf8..c2f4253 100644 --- a/src/SFA.DAS.LearnerData.Messages/ChangeSummary.cs +++ b/src/SFA.DAS.LearnerData.Messages/ChangeSummary.cs @@ -20,7 +20,6 @@ public enum ChangeType PlannedEndDateChange, EpaoPriceChange, TrainingPriceChange, - StandardCodeChange, TrainingCodeChange, LearningTypeChange, IsFlexiJob @@ -88,13 +87,6 @@ public class TrainingPriceChange : IChange public int? NewValue { get; init; } } -public class StandardCodeChange : IChange -{ - public ChangeType ChangeType => ChangeType.StandardCodeChange; - public int? OldValue { get; init; } - public int? NewValue { get; init; } -} - public class TrainingCodeChange : IChange { public ChangeType ChangeType => ChangeType.TrainingCodeChange; @@ -141,7 +133,6 @@ public class ChangeJsonConverter : JsonConverter ChangeType.PlannedEndDateChange => JsonSerializer.Deserialize(root.GetRawText(), options), ChangeType.EpaoPriceChange => JsonSerializer.Deserialize(root.GetRawText(), options), ChangeType.TrainingPriceChange => JsonSerializer.Deserialize(root.GetRawText(), options), - ChangeType.StandardCodeChange => JsonSerializer.Deserialize(root.GetRawText(), options), ChangeType.IsFlexiJob => JsonSerializer.Deserialize(root.GetRawText(), options), _ => throw new JsonException($"Unknown change type: {changeType}") }; diff --git a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs index a16af40..d62e8dc 100644 --- a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs +++ b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs @@ -70,7 +70,6 @@ GetAllLearnersQueryHandler sut firstResultItem.ConsumerReference.Should().Be(firstLearner.ConsumerReference); firstResultItem.CorrelationId.Should().Be(firstLearner.CorrelationId); firstResultItem.ReceivedDate.Should().Be(firstLearner.ReceivedDate); - firstResultItem.StandardCode.Should().Be(firstLearner.StandardCode); firstResultItem.TrainingCode.Should().Be(firstLearner.TrainingCode); firstResultItem.TrainingName.Should().Be(firstLearner.TrainingName); firstResultItem.LearningType.Should().Be(firstLearner.LearningType); diff --git a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandlerTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandlerTests.cs index 44534b0..6784a1b 100644 --- a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandlerTests.cs +++ b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandlerTests.cs @@ -40,7 +40,6 @@ GetLearnerByIdQueryHandler sut result.EpaoPrice.Should().Be(learner.EpaoPrice); result.TrainingPrice.Should().Be(learner.TrainingPrice); result.AgreementId.Should().Be(learner.AgreementId); - result.StandardCode.Should().Be(learner.StandardCode); result.TrainingCode.Should().Be(learner.TrainingCode); result.TrainingName.Should().Be(learner.TrainingName); result.LearningType.Should().Be(learner.LearningType); diff --git a/src/SFA.DAS.LearnerData.UnitTests/Services/ChangeTrackingServiceTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Services/ChangeTrackingServiceTests.cs index 3c68d1d..b3ebb34 100644 --- a/src/SFA.DAS.LearnerData.UnitTests/Services/ChangeTrackingServiceTests.cs +++ b/src/SFA.DAS.LearnerData.UnitTests/Services/ChangeTrackingServiceTests.cs @@ -30,7 +30,6 @@ public void DetectChanges_WhenNoChanges_ShouldReturnEmptyChanges(ChangeTrackingS EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow, @@ -54,7 +53,6 @@ public void DetectChanges_WhenNoChanges_ShouldReturnEmptyChanges(ChangeTrackingS EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = existingLearner.ReceivedDate, @@ -91,7 +89,6 @@ public void DetectChanges_WhenAllFieldsChanged_ShouldReturnAllChanges(ChangeTrac EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, TrainingCode = "123", LearningType = LearningType.Apprenticeship, IsFlexiJob = false, @@ -117,7 +114,6 @@ public void DetectChanges_WhenAllFieldsChanged_ShouldReturnAllChanges(ChangeTrac EpaoPrice = 600, TrainingPrice = 16000, AgreementId = "XYZ789", - StandardCode = 456, TrainingCode = "456", LearningType = LearningType.ApprenticeshipUnit, IsFlexiJob = true, @@ -133,7 +129,7 @@ public void DetectChanges_WhenAllFieldsChanged_ShouldReturnAllChanges(ChangeTrac // Assert result.Should().NotBeNull(); result.HasLearnerChanges.Should().BeTrue(); - result.Changes.Should().HaveCount(12); + result.Changes.Should().HaveCount(11); // Verify each change type result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.FirstNameChange); @@ -144,7 +140,6 @@ public void DetectChanges_WhenAllFieldsChanged_ShouldReturnAllChanges(ChangeTrac result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.PlannedEndDateChange); result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.EpaoPriceChange); result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.TrainingPriceChange); - result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.StandardCodeChange); result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.TrainingCodeChange); result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.LearningTypeChange); result.Changes.Should().ContainSingle(c => c.ChangeType == ChangeType.IsFlexiJob); @@ -172,7 +167,6 @@ public void DetectChanges_WhenOnlyNonTrackedFieldsChanged_ShouldReturnEmptyChang EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow, @@ -196,7 +190,6 @@ public void DetectChanges_WhenOnlyNonTrackedFieldsChanged_ShouldReturnEmptyChang EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow.AddDays(1), @@ -233,7 +226,6 @@ public void DetectChanges_WhenNonLearnerFieldsChanged_ShouldReturnEmptyLearnerCh EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1100, ReceivedDate = DateTime.UtcNow, @@ -257,7 +249,6 @@ public void DetectChanges_WhenNonLearnerFieldsChanged_ShouldReturnEmptyLearnerCh EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow.AddDays(1), @@ -295,7 +286,6 @@ public void DetectChanges_WhenSingleFieldChanged_ShouldReturnOnlyThatChange(Chan EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow, @@ -319,7 +309,6 @@ public void DetectChanges_WhenSingleFieldChanged_ShouldReturnOnlyThatChange(Chan EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = existingLearner.ReceivedDate, @@ -358,7 +347,6 @@ public void DetectChanges_WhenMultipleFieldsChanged_ShouldReturnAllChanges(Chang EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow, @@ -382,7 +370,6 @@ public void DetectChanges_WhenMultipleFieldsChanged_ShouldReturnAllChanges(Chang EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = existingLearner.ReceivedDate, @@ -428,7 +415,6 @@ public void DetectChanges_WhenNullableFieldChangedFromNullToValue_ShouldDetectCh EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow, @@ -452,7 +438,6 @@ public void DetectChanges_WhenNullableFieldChangedFromNullToValue_ShouldDetectCh EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = existingLearner.ReceivedDate, @@ -492,7 +477,6 @@ public void DetectChanges_WhenNullableFieldChangedFromValueToNull_ShouldDetectCh EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = DateTime.UtcNow, @@ -516,7 +500,6 @@ public void DetectChanges_WhenNullableFieldChangedFromValueToNull_ShouldDetectCh EpaoPrice = 500, TrainingPrice = 15000, AgreementId = "ABC123", - StandardCode = 123, IsFlexiJob = false, PlannedOTJTrainingHours = 1200, ReceivedDate = existingLearner.ReceivedDate, diff --git a/src/SFA.DAS.LearnerData/Application/Commands/SaveLearner/SaveLearnerNewCommand.cs b/src/SFA.DAS.LearnerData/Application/Commands/SaveLearner/SaveLearnerNewCommand.cs index 3d0938a..4f0ab1a 100644 --- a/src/SFA.DAS.LearnerData/Application/Commands/SaveLearner/SaveLearnerNewCommand.cs +++ b/src/SFA.DAS.LearnerData/Application/Commands/SaveLearner/SaveLearnerNewCommand.cs @@ -18,7 +18,6 @@ public record SaveLearnerNewCommand : IRequest public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public string TrainingCode { get; set; } public string TrainingName { get; set; } public LearningType LearningType { get; set; } diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderQueryHandler.cs index e0e22c1..4c3f36d 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderQueryHandler.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderQueryHandler.cs @@ -39,7 +39,6 @@ public async Task Handle(GetForProviderQuery request, Canc ConsumerReference = learner.ConsumerReference, CorrelationId = learner.CorrelationId, ReceivedDate = learner.ReceivedDate, - StandardCode = learner.StandardCode, IsFlexiJob = learner.IsFlexiJob, PlannedOTJTrainingHours = learner.PlannedOTJTrainingHours }).ToList() diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderResult.cs index 1256442..4c3f706 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderResult.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetAll/GetForProviderResult.cs @@ -22,7 +22,6 @@ public record GetForProviderResultItem : LearnerResult public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public bool IsFlexiJob { get; set; } public int PlannedOTJTrainingHours { get; set; } public DateTime ReceivedDate { get; set; } diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs index 4b2541c..bbdc43e 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs @@ -38,7 +38,6 @@ public async Task Handle(GetAllLearnersQuery request, Canc ConsumerReference = learner.ConsumerReference, CorrelationId = learner.CorrelationId, ReceivedDate = learner.ReceivedDate, - StandardCode = learner.StandardCode, TrainingCode = learner.TrainingCode, TrainingName = learner.TrainingName, LearningType = learner.LearningType, diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs index 246ddaa..541ad22 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs @@ -20,7 +20,6 @@ public record GetAllLearnersResultItem : LearnerResult public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public string? TrainingCode { get; set; } public string? TrainingName { get; set; } public LearningType? LearningType { get; set; } diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandler.cs index 98ddbfe..e51de19 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandler.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdQueryHandler.cs @@ -38,7 +38,6 @@ public async Task Handle(GetLearnerByIdQuery request, Canc ConsumerReference = learner.ConsumerReference, CorrelationId = learner.CorrelationId, ReceivedDate = learner.ReceivedDate, - StandardCode = learner.StandardCode, TrainingCode = learner.TrainingCode, TrainingName = learner.TrainingName, LearningType = learner.LearningType, diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdResult.cs index 6e797f0..51f2e09 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdResult.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetLearnerById/GetLearnerByIdResult.cs @@ -18,7 +18,6 @@ public record GetLearnerByIdResult : LearnerResult public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public string? TrainingCode { get; set; } public string? TrainingName { get; set; } public LearningType? LearningType { get; set; } diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs index 879d165..ac3be82 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs @@ -77,10 +77,10 @@ public async Task Handle(GetSearchQuery request, CancellationTo EpaoPrice = learner.EpaoPrice, TrainingPrice = learner.TrainingPrice, AgreementId = learner.AgreementId, + TrainingCode = learner.TrainingCode, ConsumerReference = learner.ConsumerReference, CorrelationId = learner.CorrelationId, ReceivedDate = learner.ReceivedDate, - StandardCode = learner.StandardCode, IsFlexiJob = learner.IsFlexiJob, PlannedOTJTrainingHours = learner.PlannedOTJTrainingHours }), diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs index c063baf..6df17f1 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs @@ -21,7 +21,7 @@ public record GetByAcademicYearResultItem : LearnerResult public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } + public string? TrainingCode { get; set; } public bool IsFlexiJob { get; set; } public int PlannedOTJTrainingHours { get; set; } public DateTime ReceivedDate { get; set; } diff --git a/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs b/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs index 73de901..3ade690 100644 --- a/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs +++ b/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs @@ -18,7 +18,6 @@ public class Learner : Entity public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public int StandardCode { get; set; } public string? TrainingCode { get; set; } public string? TrainingName { get; set; } public LearningType? LearningType { get; set; } @@ -49,7 +48,6 @@ public static Learner From(SaveLearnerNewCommand command) ConsumerReference = command.ConsumerReference, CorrelationId = command.CorrelationId, ReceivedDate = command.ReceivedDate, - StandardCode = command.StandardCode, TrainingCode = command.TrainingCode, TrainingName = command.TrainingName, LearningType = command.LearningType, diff --git a/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs b/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs index b1a795e..1d37b73 100644 --- a/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs +++ b/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs @@ -165,7 +165,7 @@ private static string GetOrderNamesByField(string fieldName, bool sortDescending nameof(Learner.PlannedOTJTrainingHours) => $"PlannedOTJTrainingHours {sort}", nameof(Learner.PlannedEndDate) => $"PlannedEndDate {sort}", nameof(Learner.ReceivedDate) => $"ReceivedDate {sort}", - nameof(Learner.StandardCode) => $"StandardCode {sort}", + nameof(Learner.TrainingCode) => $"TrainingCode {sort}", nameof(Learner.StartDate) => $"StartDate {sort}, Firstname {sort}, Lastname {sort}, ULN {sort}", nameof(Learner.TrainingPrice) => $"TrainingPrice {sort}", nameof(Learner.Uln) => $"Uln {sort}", @@ -219,7 +219,6 @@ public async Task UpdateLearner(Learner existingL existingLearner.ConsumerReference = request.ConsumerReference; existingLearner.CorrelationId = request.CorrelationId; existingLearner.ReceivedDate = request.ReceivedDate; - existingLearner.StandardCode = request.StandardCode; existingLearner.TrainingCode = request.TrainingCode; existingLearner.TrainingName = request.TrainingName; existingLearner.LearningType = request.LearningType; diff --git a/src/SFA.DAS.LearnerData/Services/ChangeTrackingService.cs b/src/SFA.DAS.LearnerData/Services/ChangeTrackingService.cs index 1e60abb..56fc765 100644 --- a/src/SFA.DAS.LearnerData/Services/ChangeTrackingService.cs +++ b/src/SFA.DAS.LearnerData/Services/ChangeTrackingService.cs @@ -49,11 +49,6 @@ public ChangeSummary DetectChanges(Learner existingLearner, Learner newLearner) changes.Add(new TrainingPriceChange { OldValue = existingLearner.TrainingPrice, NewValue = newLearner.TrainingPrice }); } - if (!Equals(existingLearner.StandardCode, newLearner.StandardCode)) - { - changes.Add(new StandardCodeChange { OldValue = existingLearner.StandardCode, NewValue = newLearner.StandardCode }); - } - if (!Equals(existingLearner.TrainingCode, newLearner.TrainingCode)) { changes.Add(new TrainingCodeChange { OldValue = existingLearner.TrainingCode, NewValue = newLearner.TrainingCode }); From 8c7c607917cd0c8422ce54740f37c22f549d7b5f Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Tue, 10 Feb 2026 15:50:33 +0000 Subject: [PATCH 2/5] remove space --- .../Controllers/LearnersController/WhenIGetById.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs index 090dcc1..5406adc 100644 --- a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs +++ b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetById.cs @@ -33,7 +33,6 @@ [Greedy] Api.Controllers.ProviderLearnersController sut okResult.Should().NotBeNull(); var response = okResult.Value as GetLearnerByIdResponse; - response.Should().NotBeNull(); response.Id.Should().Be(learner.Id); response.Uln.Should().Be(learner.Uln); From bda1eb19fd727a90a7a47f3848bb1e9bd1a95917 Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Wed, 11 Feb 2026 15:26:27 +0000 Subject: [PATCH 3/5] setting StandardCode to a number --- .../GetAllLearnersQueryHandlerTests.cs | 2 ++ .../Extensions/StringExtensionsTests.cs | 18 ++++++++++++++++++ .../GetAllLearnersQueryHandler.cs | 2 ++ .../GetAllLearners/GetAllLearnersResult.cs | 1 + .../Data/Entities/Learner.cs | 2 +- .../Extensions/StringExtensions.cs | 12 ++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/SFA.DAS.LearnerData.UnitTests/Extensions/StringExtensionsTests.cs create mode 100644 src/SFA.DAS.LearnerData/Extensions/StringExtensions.cs diff --git a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs index d62e8dc..82b2e76 100644 --- a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs +++ b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetAllLearners/GetAllLearnersQueryHandlerTests.cs @@ -6,6 +6,7 @@ using SFA.DAS.LearnerData.Data; using SFA.DAS.LearnerData.Data.Entities; using SFA.DAS.LearnerData.Data.Repositories; +using SFA.DAS.LearnerData.Extensions; using SFA.DAS.Testing.AutoFixture; namespace SFA.DAS.LearnerData.UnitTests.Application.Queries.GetAllLearners; @@ -70,6 +71,7 @@ GetAllLearnersQueryHandler sut firstResultItem.ConsumerReference.Should().Be(firstLearner.ConsumerReference); firstResultItem.CorrelationId.Should().Be(firstLearner.CorrelationId); firstResultItem.ReceivedDate.Should().Be(firstLearner.ReceivedDate); + firstResultItem.StandardCode.Should().Be(firstLearner.TrainingCode.ToLongOrDefault()); firstResultItem.TrainingCode.Should().Be(firstLearner.TrainingCode); firstResultItem.TrainingName.Should().Be(firstLearner.TrainingName); firstResultItem.LearningType.Should().Be(firstLearner.LearningType); diff --git a/src/SFA.DAS.LearnerData.UnitTests/Extensions/StringExtensionsTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Extensions/StringExtensionsTests.cs new file mode 100644 index 0000000..42ef1cf --- /dev/null +++ b/src/SFA.DAS.LearnerData.UnitTests/Extensions/StringExtensionsTests.cs @@ -0,0 +1,18 @@ +using FluentAssertions; +using NUnit.Framework; +using SFA.DAS.LearnerData.Extensions; + +namespace SFA.DAS.LearnerData.UnitTests.Extensions; + +public class StringExtensionsTests +{ + [TestCase(null, 0)] + [TestCase("123", 123)] + [TestCase("X123", 0)] + public void Convert_String_ToLongOrDefault(string? input, long expectedOutput) + { + var result = input.ToLongOrDefault(); + + result.Should().Be(expectedOutput); + } +} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs index bbdc43e..f6b0ada 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersQueryHandler.cs @@ -1,5 +1,6 @@ using MediatR; using SFA.DAS.LearnerData.Data.Repositories; +using SFA.DAS.LearnerData.Extensions; namespace SFA.DAS.LearnerData.Application.Queries.GetAllLearners; @@ -38,6 +39,7 @@ public async Task Handle(GetAllLearnersQuery request, Canc ConsumerReference = learner.ConsumerReference, CorrelationId = learner.CorrelationId, ReceivedDate = learner.ReceivedDate, + StandardCode = learner.TrainingCode.ToLongOrDefault(), TrainingCode = learner.TrainingCode, TrainingName = learner.TrainingName, LearningType = learner.LearningType, diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs index 541ad22..4ff7aa9 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetAllLearners/GetAllLearnersResult.cs @@ -20,6 +20,7 @@ public record GetAllLearnersResultItem : LearnerResult public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } + public long StandardCode { get; set; } public string? TrainingCode { get; set; } public string? TrainingName { get; set; } public LearningType? LearningType { get; set; } diff --git a/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs b/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs index 3ade690..76c4dd3 100644 --- a/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs +++ b/src/SFA.DAS.LearnerData/Data/Entities/Learner.cs @@ -18,7 +18,7 @@ public class Learner : Entity public int EpaoPrice { get; set; } public int TrainingPrice { get; set; } public string? AgreementId { get; set; } - public string? TrainingCode { get; set; } + public string TrainingCode { get; set; } public string? TrainingName { get; set; } public LearningType? LearningType { get; set; } public bool IsFlexiJob { get; set; } diff --git a/src/SFA.DAS.LearnerData/Extensions/StringExtensions.cs b/src/SFA.DAS.LearnerData/Extensions/StringExtensions.cs new file mode 100644 index 0000000..62c482e --- /dev/null +++ b/src/SFA.DAS.LearnerData/Extensions/StringExtensions.cs @@ -0,0 +1,12 @@ +namespace SFA.DAS.LearnerData.Extensions; + +public static class StringExtensions +{ + public static long ToLongOrDefault(this string? input) + { + if (input != null && long.TryParse(input, out long result)) + return result; + + return 0; + } +} \ No newline at end of file From f7814117b0e79ae8f8abe939c178bcdc0939efbc Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Mon, 27 Apr 2026 15:57:36 +0100 Subject: [PATCH 4/5] reworked GetCourse endpoint into the Search result --- .../WhenIGetCourseCodesByUkprn.cs | 34 ------ .../Controllers/ProviderLearnersController.cs | 13 --- .../Models/Responses/GetSearchResponse.cs | 5 +- .../GetCourseCodesByUkprnHandlerTests.cs | 47 -------- .../GetSearch/GetSearchQueryHandlerTests.cs | 6 + .../WhenIGetCourseCodesByUkprn.cs | 74 ------------ .../WhenIGetCourseListForUkprn.cs | 110 ++++++++++++++++++ .../GetCourseCodesByUkprnQueryHandler.cs | 19 --- .../GetCourseCodesByUkprnResult.cs | 6 - .../GetSearch/GetSearchQueryHandler.cs | 6 +- .../Queries/GetSearch/GetSearchResult.cs | 2 + .../Data/Entities/Course.cs | 7 ++ .../Data/Repositories/LearnerRepository.cs | 73 +++++++----- 13 files changed, 179 insertions(+), 223 deletions(-) delete mode 100644 src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetCourseCodesByUkprn.cs delete mode 100644 src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnHandlerTests.cs delete mode 100644 src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseCodesByUkprn.cs create mode 100644 src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseListForUkprn.cs delete mode 100644 src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnQueryHandler.cs delete mode 100644 src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnResult.cs create mode 100644 src/SFA.DAS.LearnerData/Data/Entities/Course.cs diff --git a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetCourseCodesByUkprn.cs b/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetCourseCodesByUkprn.cs deleted file mode 100644 index 271a8cd..0000000 --- a/src/SFA.DAS.LearnerData.Api.UnitTests/Controllers/LearnersController/WhenIGetCourseCodesByUkprn.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AutoFixture.NUnit3; -using FluentAssertions; -using MediatR; -using Microsoft.AspNetCore.Mvc; -using Moq; -using NUnit.Framework; -using SFA.DAS.LearnerData.Application.Queries.GetCourseCodesByUkprn; -using SFA.DAS.Testing.AutoFixture; - -namespace SFA.DAS.LearnerData.Api.UnitTests.Controllers.LearnersController; - -public class WhenIGetCourseCodesByUkprn -{ - [Test, MoqAutoData] - public async Task Then_Ok_Response_Is_Returned_When_Course_Codes_Returned( - long ukprn, - GetCourseCodesByUkprnResult queryResult, - [Frozen] Mock sender, - [Greedy] Api.Controllers.ProviderLearnersController sut) - { - sender - .Setup(x => x.Send(It.Is(ctx => ctx.Ukprn == ukprn), It.IsAny())).ReturnsAsync(queryResult) - .Verifiable(); - - var result = await sut.GetCourseCodesByUkprn(ukprn) as OkObjectResult; - - result.Should().NotBeNull(); - - var response = result.Value as GetCourseCodesByUkprnResult; - response.Should().BeEquivalentTo(queryResult); - - sender.Verify(); - } -} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs b/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs index 8bae8b6..10548ab 100644 --- a/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs +++ b/src/SFA.DAS.LearnerData.Api/Controllers/ProviderLearnersController.cs @@ -7,7 +7,6 @@ using SFA.DAS.LearnerData.Api.Models.Responses; using SFA.DAS.LearnerData.Application.Commands.AssignApprenticeshipId; using SFA.DAS.LearnerData.Application.Commands.SaveLearner; -using SFA.DAS.LearnerData.Application.Queries.GetCourseCodesByUkprn; using SFA.DAS.LearnerData.Application.Queries.GetLearnerById; using SFA.DAS.LearnerData.Application.Queries.GetSearch; using SFA.DAS.LearnerData.Services; @@ -134,16 +133,4 @@ public async Task PatchApprenticeshipId(long ukprn, long id, [Fro return Ok(); } - - [HttpGet] - [ProducesResponseType((int)HttpStatusCode.OK)] - [Route("coursecodes")] - public async Task GetCourseCodesByUkprn(long ukprn) - { - var query = new GetCourseCodesByUkprnQuery(ukprn); - - var result = await sender.Send(query); - - return Ok(result); - } } \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs index 01092d5..69b8ce1 100644 --- a/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs +++ b/src/SFA.DAS.LearnerData.Api/Models/Responses/GetSearchResponse.cs @@ -1,4 +1,5 @@ using SFA.DAS.LearnerData.Application.Queries.GetSearch; +using SFA.DAS.LearnerData.Data.Entities; using SFA.DAS.LearnerData.Extensions; namespace SFA.DAS.LearnerData.Api.Models.Responses; @@ -6,12 +7,14 @@ namespace SFA.DAS.LearnerData.Api.Models.Responses; public record GetSearchResponse : PagedResponse { public DateTime? LastSubmissionDate { get; set; } - + public List Courses { get; set; } = []; + public static GetSearchResponse MapFrom(GetSearchResult result) { return new GetSearchResponse { LastSubmissionDate = result.LastSubmissionDate, + Courses = result.Courses, Data = result.Items.Select(item => new GetSearchResponseItem { Id = item.Id, diff --git a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnHandlerTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnHandlerTests.cs deleted file mode 100644 index 4e0800a..0000000 --- a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnHandlerTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -using AutoFixture.NUnit3; -using FluentAssertions; -using Moq; -using NUnit.Framework; -using SFA.DAS.LearnerData.Application.Queries.GetCourseCodesByUkprn; -using SFA.DAS.LearnerData.Data.Repositories; -using SFA.DAS.Testing.AutoFixture; - -namespace SFA.DAS.LearnerData.UnitTests.Application.Queries.GetCourseCodesByUkprn; - -public class GetCourseCodesByUkprnHandlerTests -{ - [Test, MoqAutoData] - public async Task Handle_GetCourseCodesByUkprn( - GetCourseCodesByUkprnQuery query, - List courseCodes, - [Frozen] Mock repository, - GetCourseCodesByUkprnQueryHandler sut) - { - repository - .Setup(x => x.GetCourseCodesByUkprn(It.Is(t => t == query.Ukprn), - default)).ReturnsAsync(courseCodes) - .Verifiable(); - - var result = await sut.Handle(query, default); - result.Should().NotBeNull(); - result.CourseCodes.Should().BeEquivalentTo(courseCodes); - repository.Verify(); - } - - [Test, MoqAutoData] - public async Task Handle_Returns_Empty_Result_When_Nocourses_Exists( - GetCourseCodesByUkprnQuery query, - [Frozen] Mock repository, - GetCourseCodesByUkprnQueryHandler sut) - { - repository - .Setup(x => x.GetCourseCodesByUkprn(It.Is(t => t == query.Ukprn), - default)).ReturnsAsync([]) - .Verifiable(); - - var result = await sut.Handle(query, default); - result.Should().NotBeNull(); - result.CourseCodes.Count.Should().Be(0); - repository.Verify(); - } -} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetSearch/GetSearchQueryHandlerTests.cs b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetSearch/GetSearchQueryHandlerTests.cs index 1f5b796..138458b 100644 --- a/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetSearch/GetSearchQueryHandlerTests.cs +++ b/src/SFA.DAS.LearnerData.UnitTests/Application/Queries/GetSearch/GetSearchQueryHandlerTests.cs @@ -17,6 +17,7 @@ public async Task Handle_GetForProvider_When_Learners_Exist( GetSearchQuery query, PagedResult learners, DateTime? lastSubmissionDate, + List courses, [Frozen] Mock repository, GetSearchQueryHandler sut ) @@ -35,6 +36,10 @@ GetSearchQueryHandler sut .Setup(x => x.GetLastSubmissionDate(query.UkPrn, It.IsAny())).ReturnsAsync(lastSubmissionDate) .Verifiable(); + repository + .Setup(x => x.GetCourseList(query.UkPrn, query.ExcludeApproved, query.MaxStartDate, query.ExcludeUlns, It.IsAny())).ReturnsAsync(courses) + .Verifiable(); + var result = await sut.Handle(query, CancellationToken.None); result.Should().NotBeNull(); result.Items.Should().BeEquivalentTo(learners.Data, options => options.ExcludingMissingMembers()); @@ -43,6 +48,7 @@ GetSearchQueryHandler sut result.PageSize.Should().Be(query.PageSize); result.TotalItems.Should().Be(learners.TotalItems); result.LastSubmissionDate.Should().Be(lastSubmissionDate); + result.Courses.Should().BeEquivalentTo(courses); repository.Verify(); } diff --git a/src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseCodesByUkprn.cs b/src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseCodesByUkprn.cs deleted file mode 100644 index 3df39d8..0000000 --- a/src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseCodesByUkprn.cs +++ /dev/null @@ -1,74 +0,0 @@ -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using SFA.DAS.LearnerData.Data; -using SFA.DAS.LearnerData.Data.Entities; -using SFA.DAS.LearnerData.Data.Repositories; -using SFA.DAS.Testing.AutoFixture; - -namespace SFA.DAS.LearnerData.UnitTests.Repositories; - -public class WhenIGetCourseCodesByUkprn -{ - private LearnerRepository _repository; - private LearnerDataDbContext _dbContext; - private CancellationToken _cancellationToken; - - [SetUp] - public void Setup() - { - _dbContext = new LearnerDataDbContext(new DbContextOptionsBuilder() - .UseInMemoryDatabase(Guid.NewGuid().ToString(), b => b.EnableNullChecks(false)) - .EnableSensitiveDataLogging() - .ConfigureWarnings(w => w.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning)) - .Options); - - _repository = new LearnerRepository(_dbContext, Mock.Of>()); - _cancellationToken = CancellationToken.None; - } - - [TearDown] - public void TearDown() - { - _dbContext.Dispose(); - } - - [Test, MoqAutoData] - public async Task Then_Returns_Empty_Result_When_No_CourseCodes_Exist( - long ukprn) - { - // Act - var result = await _repository.GetCourseCodesByUkprn(ukprn, _cancellationToken); - - // Assert - result.Should().NotBeNull(); - result.Count.Should().Be(0); - } - - [Test, MoqAutoData] - public async Task Then_Returns_CourseCodes_Give_Ukprn( - long ukprn) - { - var learners = new List() - { - new() { Ukprn = ukprn , TrainingCode = "1"}, - new() { Ukprn = ukprn , TrainingCode = "1"}, - new() { Ukprn = ukprn , TrainingCode = "2"}, - new() { Ukprn = ukprn , TrainingCode = "3"}, - }; - - learners.ForEach(t => t.Ukprn = ukprn); - _dbContext.Learners.AddRange(learners); - await _dbContext.SaveChangesAsync(); - - // Act - var result = await _repository.GetCourseCodesByUkprn(ukprn, _cancellationToken); - - // Assert - result.Should().NotBeNull(); - result.Should().BeEquivalentTo(learners.Where(t => t.Ukprn == ukprn).Select(t => t.TrainingCode).Distinct()); - } -} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseListForUkprn.cs b/src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseListForUkprn.cs new file mode 100644 index 0000000..2a68fdc --- /dev/null +++ b/src/SFA.DAS.LearnerData.UnitTests/Repositories/WhenIGetCourseListForUkprn.cs @@ -0,0 +1,110 @@ +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using SFA.DAS.LearnerData.Data; +using SFA.DAS.LearnerData.Data.Entities; +using SFA.DAS.LearnerData.Data.Repositories; +using SFA.DAS.Testing.AutoFixture; + +namespace SFA.DAS.LearnerData.UnitTests.Repositories; + +public class WhenIGetCourseListForUkprn +{ + private LearnerRepository _repository; + private LearnerDataDbContext _dbContext; + private CancellationToken _cancellationToken; + + [SetUp] + public void Setup() + { + _dbContext = new LearnerDataDbContext(new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString(), b => b.EnableNullChecks(false)) + .EnableSensitiveDataLogging() + .ConfigureWarnings(w => w.Ignore(CoreEventId.ManyServiceProvidersCreatedWarning)) + .Options); + + _repository = new LearnerRepository(_dbContext, Mock.Of>()); + _cancellationToken = CancellationToken.None; + } + + [TearDown] + public void TearDown() + { + _dbContext.Dispose(); + } + + [Test, MoqAutoData] + public async Task Then_Returns_Empty_Result_When_No_CourseCodes_Exist( + long ukprn, bool excludeApproved, string maxStartDate, string excludeUlns) + { + // Act + var result = await _repository.GetCourseList(ukprn, excludeApproved, maxStartDate, excludeUlns, _cancellationToken); + + // Assert + result.Should().NotBeNull(); + result.Count.Should().Be(0); + } + + [TestCase(100, true, null, null, 3)] + [TestCase(100, false, null, null, 4)] + [TestCase(100, false, null, null, 4)] + [TestCase(100, false, "2026-08-01", null, 4)] + [TestCase(100, false, null, "123456789,123456788", 3)] + public async Task Then_Returns_Courses_For_Query( + long ukprn, bool excludeApproved, string? maxStartDate, string? excludeUlns, int expectedCount) + { + + var learners = new List() + { + new() { Ukprn = ukprn , TrainingCode = "1", TrainingName = "Course1", StartDate = new DateTime(2027,01,01), Uln = 123456789 }, + new() { Ukprn = ukprn , TrainingCode = "1", TrainingName = "Course1", StartDate = new DateTime(2026, 01,01), Uln = 123456788 }, + new() { Ukprn = ukprn , TrainingCode = "2", TrainingName = "Course2", StartDate = new DateTime(2026,01,01)}, + new() { Ukprn = ukprn , TrainingCode = "2A", TrainingName = "Course2A", StartDate = new DateTime(2026,04,01), ApprenticeshipId = 999}, + new() { Ukprn = ukprn , TrainingCode = "3", TrainingName = "Course3", StartDate = new DateTime(2026, 01, 01)}, + new() { Ukprn = ukprn+1 , TrainingCode = "3", TrainingName = "Course3", StartDate = new DateTime(2027,01,01)}, + }; + + learners.ForEach(t => t.Ukprn = ukprn); + _dbContext.Learners.AddRange(learners); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _repository.GetCourseList(ukprn, excludeApproved, maxStartDate, excludeUlns, _cancellationToken); + + // Assert + result.Count.Should().Be(expectedCount); + } + + [Test, MoqAutoData] + public async Task Then_Returns_CourseCodes_And_Names_If_Present( + long ukprn) + { + + var learners = new List() + { + new() { Ukprn = ukprn , TrainingCode = "1", TrainingName = null, StartDate = new DateTime(2027,01,01), Uln = 123456789 }, + new() { Ukprn = ukprn , TrainingCode = "1", TrainingName = "Course1", StartDate = new DateTime(2026, 01,01), Uln = 123456788 }, + new() { Ukprn = ukprn , TrainingCode = "2", TrainingName = "Course2", StartDate = new DateTime(2026,01,01)}, + new() { Ukprn = ukprn , TrainingCode = "2A", TrainingName = "Course2A", StartDate = new DateTime(2026,04,01), ApprenticeshipId = 999}, + new() { Ukprn = ukprn , TrainingCode = "3", TrainingName = "Course3", StartDate = new DateTime(2026, 01, 01)}, + new() { Ukprn = ukprn , TrainingCode = "4", TrainingName = null, StartDate = new DateTime(2026, 01, 01)}, + new() { Ukprn = ukprn+1 , TrainingCode = "3", TrainingName = "Course3", StartDate = new DateTime(2027,01,01)}, + }; + + learners.ForEach(t => t.Ukprn = ukprn); + _dbContext.Learners.AddRange(learners); + await _dbContext.SaveChangesAsync(); + + // Act + var result = await _repository.GetCourseList(ukprn, false, null, null, _cancellationToken); + + // Assert + result.Should().NotBeNull(); + result.Count.Should().Be(5); + result.First(x => x.TrainingCode == "1").TrainingName.Should().Be("Course1"); + result.First(x => x.TrainingCode == "4").TrainingName.Should().BeNull(); + } +} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnQueryHandler.cs deleted file mode 100644 index 90d1038..0000000 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnQueryHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MediatR; -using SFA.DAS.LearnerData.Data.Repositories; - -namespace SFA.DAS.LearnerData.Application.Queries.GetCourseCodesByUkprn; - -public record GetCourseCodesByUkprnQuery(long Ukprn) : IRequest; - -public class GetCourseCodesByUkprnQueryHandler(ILearnerRepository repository) : IRequestHandler -{ - public async Task Handle(GetCourseCodesByUkprnQuery request, CancellationToken cancellationToken) - { - var codes = await repository.GetCourseCodesByUkprn(request.Ukprn, cancellationToken); - - return new GetCourseCodesByUkprnResult() - { - CourseCodes = codes - }; - } -} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnResult.cs deleted file mode 100644 index 5578f63..0000000 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetCourseCodesByUkprn/GetCourseCodesByUkprnResult.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SFA.DAS.LearnerData.Application.Queries.GetCourseCodesByUkprn; - -public class GetCourseCodesByUkprnResult -{ - public List CourseCodes { get; set; } -} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs index 1b6f28d..d5002ce 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchQueryHandler.cs @@ -59,11 +59,13 @@ public async Task Handle(GetSearchQuery request, CancellationTo DateTime? lastSubmissionDate = null; lastSubmissionDate = await repository.GetLastSubmissionDate(request.UkPrn, cancellationToken); + var courses = await repository.GetCourseList(request.UkPrn, request.ExcludeApproved, request.MaxStartDate, request.ExcludeUlns, cancellationToken); return new GetSearchResult { - LastSubmissionDate = lastSubmissionDate, - Items = result.Data.Select(learner => new GetByAcademicYearResultItem + LastSubmissionDate = lastSubmissionDate, + Courses = courses, + Items = result.Data.Select(learner => new GetByAcademicYearResultItem { Id = learner.Id, CreatedDate = learner.CreatedDate, diff --git a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs index 5720a3c..1d5e882 100644 --- a/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs +++ b/src/SFA.DAS.LearnerData/Application/Queries/GetSearch/GetSearchResult.cs @@ -1,3 +1,4 @@ +using SFA.DAS.LearnerData.Data.Entities; using SFA.DAS.LearnerData.Messages; namespace SFA.DAS.LearnerData.Application.Queries.GetSearch; @@ -5,6 +6,7 @@ namespace SFA.DAS.LearnerData.Application.Queries.GetSearch; public record GetSearchResult : PagedQueryResult { public DateTime? LastSubmissionDate { get; set; } + public List Courses { get; set; } = []; } public record GetByAcademicYearResultItem : LearnerResult diff --git a/src/SFA.DAS.LearnerData/Data/Entities/Course.cs b/src/SFA.DAS.LearnerData/Data/Entities/Course.cs new file mode 100644 index 0000000..af65204 --- /dev/null +++ b/src/SFA.DAS.LearnerData/Data/Entities/Course.cs @@ -0,0 +1,7 @@ +namespace SFA.DAS.LearnerData.Data.Entities; + +public class Course +{ + public string TrainingCode { get; set; } + public string? TrainingName { get; set; } +} \ No newline at end of file diff --git a/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs b/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs index 374ce1c..32fb683 100644 --- a/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs +++ b/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs @@ -11,26 +11,17 @@ namespace SFA.DAS.LearnerData.Data.Repositories; public interface ILearnerRepository { Task GetById(long id, CancellationToken cancellationToken); - Task Get(long ukPrn, long uln, CancellationToken cancellationToken); - Task> GetForProvider(long ukprn, CancellationToken cancellationToken); - Task> Search(long ukprn, int page, int? pageSize, int limit, int offset, string sortColumn, bool sortDescending, string filter, bool excludeApproved, int? startMonth, int startYear, string maxStartDate, string excludeUlns, string courseCode, CancellationToken cancellationToken); - Task> GetAllLearners(int page, int? pageSize, int limit, int offset, bool excludeApproved, CancellationToken cancellationToken); - Task GetLastSubmissionDate(long ukprn, CancellationToken cancellationToken); - Task AddLearner(SaveLearnerNewCommand request, CancellationToken cancellationToken); - Task UpdateLearner(Learner existingLearner, SaveLearnerNewCommand request, CancellationToken cancellationToken); - Task AssignApprenticeshipId(AssignApprenticeshipIdCommand request, CancellationToken cancellationToken); - - Task> GetCourseCodesByUkprn(long ukprn, CancellationToken cancellationToken); + Task> GetCourseList(long ukprn, bool excludeApproved, string maxStartDate, string excludeUlns, CancellationToken cancellationToken); } public class LearnerRepository(LearnerDataDbContext dbContext, ILogger logger) : ILearnerRepository @@ -63,26 +54,14 @@ public async Task> Search(long ukprn, int page, int? pageSi .AsNoTracking() .Where(x => x.Ukprn == ukprn); - if (!string.IsNullOrEmpty(excludeUlns)) - { - var excludeUlnList = excludeUlns - .Split(',') - .Select(s => s.Trim()) - .Where(s => !string.IsNullOrWhiteSpace(s)) - .Select(long.Parse); - - query = query.Where(x => !excludeUlnList.Contains(x.Uln)); - } + query = ExcludeUlnsFromQuery(query, excludeUlns); if (excludeApproved) { query = query.Where(x => x.ApprenticeshipId == null); } - if (!string.IsNullOrEmpty(filter)) - { - query = query.Where(x => x.LastName.Contains(filter) || x.FirstName.Contains(filter) || x.Uln.ToString() == filter); - } + query = ExcludeLearnerAfterStartDate(query, excludeUlns); if (startMonth.HasValue) { @@ -270,9 +249,49 @@ public async Task AssignApprenticeshipId(AssignApprenticeshipIdCommand request, await dbContext.SaveChangesAsync(cancellationToken); } - public async Task> GetCourseCodesByUkprn(long ukprn, CancellationToken cancellationToken) + public async Task> GetCourseList(long ukprn, bool excludeApproved, string maxStartDate, string excludeUlns, CancellationToken cancellationToken) { - return await dbContext.Learners.AsNoTracking().Where(t => t.Ukprn == ukprn). - Select(t => t.TrainingCode).Distinct().ToListAsync(cancellationToken); + var query = dbContext.Learners + .AsNoTracking() + .Where(x => x.Ukprn == ukprn); + + query = ExcludeUlnsFromQuery(query, excludeUlns); + + if (excludeApproved) + { + query = query.Where(x => x.ApprenticeshipId == null); + } + + query = ExcludeLearnerAfterStartDate(query, excludeUlns); + + return await query.GroupBy(l => l.TrainingCode).Select(g => new Course { TrainingCode = g.Key, TrainingName = g.Max(t => t.TrainingName) }).ToListAsync(cancellationToken); + } + + private static IQueryable ExcludeUlnsFromQuery(IQueryable query, string excludeUlns) + { + if (!string.IsNullOrEmpty(excludeUlns)) + { + var excludeUlnList = excludeUlns + .Split(',') + .Select(s => s.Trim()) + .Where(s => !string.IsNullOrWhiteSpace(s)) + .Select(long.Parse); + query = query.Where(x => !excludeUlnList.Contains(x.Uln)); + } + return query; } + + private static IQueryable ExcludeLearnerAfterStartDate(IQueryable query, string maxStartDate) + { + if (!string.IsNullOrEmpty(maxStartDate)) + { + DateTime maxDate; + if (DateTime.TryParse(maxStartDate, CultureInfo.InvariantCulture, out maxDate)) + { + query = query.Where(x => x.StartDate < maxDate); + } + } + return query; + } + } \ No newline at end of file From 3f83ba55c9401bf0e68121f5b3d52e3a5bb1fccd Mon Sep 17 00:00:00 2001 From: Paul Graham Date: Mon, 11 May 2026 22:22:55 +0100 Subject: [PATCH 5/5] re-add filter --- .../Data/Repositories/LearnerRepository.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs b/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs index 85d1304..f857369 100644 --- a/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs +++ b/src/SFA.DAS.LearnerData/Data/Repositories/LearnerRepository.cs @@ -66,6 +66,11 @@ public async Task> Search(long ukprn, int page, int? pageSi query = ExcludeLearnerAfterStartDate(query, excludeUlns); + if (!string.IsNullOrEmpty(filter)) + { + query = query.Where(x => x.LastName.Contains(filter) || x.FirstName.Contains(filter) || x.Uln.ToString() == filter); + } + if (startMonth.HasValue) { var month = startMonth.Value;