From 769f930ebc3c841355f89caabfe1a2091d35601c Mon Sep 17 00:00:00 2001 From: Kevin Joy Date: Mon, 16 Dec 2024 12:35:41 +0000 Subject: [PATCH] Added qtlsstatus to vnext getperson --- .../V3/Implementation/Dtos/QtlsStatus.cs | 15 ++ .../V3/Implementation/Dtos/QtsInfo.cs | 73 +++++---- .../Operations/FindPersonsBase.cs | 53 ++++--- .../V3/Implementation/Operations/GetPerson.cs | 21 ++- .../V3/VNext/Responses/FindPersonResponse.cs | 2 + .../V3/VNext/Responses/FindPersonsResponse.cs | 4 +- .../V3/VNext/Responses/GetPersonResponse.cs | 4 +- .../ApiSchema/V3/VNext/Dtos/QtlsStatus.cs | 8 + ...FindPersonByLastNameAndDateOfBirthTests.cs | 84 ++++++++++ .../FindPersonsByTrnAndDateOfBirthTests.cs | 145 ++++++++++++++++++ .../V3/VNext/GetPersonByTrnTests.cs | 94 ++++++++++++ .../V3/VNext/GetPersonTests.cs | 67 ++++++++ 12 files changed, 515 insertions(+), 55 deletions(-) create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtlsStatus.cs create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/QtlsStatus.cs diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtlsStatus.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtlsStatus.cs new file mode 100644 index 000000000..441393142 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtlsStatus.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; + +namespace TeachingRecordSystem.Api.V3.Implementation.Dtos; + +public enum QtlsStatus +{ + [Description("None")] + None = 0, + + [Description("Expired")] + Expired = 1, + + [Description("Active")] + Active = 2, +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs index 940d9e748..5807c8bcc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs @@ -9,50 +9,59 @@ public record QtsInfo public required string CertificateUrl { get; init; } public required string StatusDescription { get; init; } - public static async Task CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache) + public static async Task CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache, DateTime? qtlsDate) { - if (qtsRegistration is null) + var qtsDates = new List() { qtsRegistration?.dfeta_QTSDate, qtlsDate }; + var earliestDate = qtsDates.Where(x => x != null).OrderBy(date => date).FirstOrDefault(); + if (earliestDate is null && qtsRegistration is null) { return null; } - var awardedDate = qtsRegistration.dfeta_QTSDate.ToDateOnlyWithDqtBstFix(isLocalTime: true); - if (awardedDate is null) - { - return null; - } - - var teacherStatus = await referenceDataCache.GetTeacherStatusByIdAsync(qtsRegistration.dfeta_TeacherStatusId.Id); - var statusDescription = GetStatusDescription(teacherStatus); + var teacherStatus = qtsRegistration != null ? await referenceDataCache.GetTeacherStatusByIdAsync(qtsRegistration.dfeta_TeacherStatusId.Id) : null; + var statusDescription = GetStatusDescription(teacherStatus, qtsRegistration?.dfeta_QTSDate, qtlsDate); return new() { - Awarded = awardedDate!.Value, + Awarded = earliestDate!.Value.ToDateOnlyWithDqtBstFix(isLocalTime: true), CertificateUrl = "/v3/certificates/qts", StatusDescription = statusDescription, }; } - private static string GetStatusDescription(dfeta_teacherstatus teacherStatus) => teacherStatus.dfeta_Value switch + private static string GetStatusDescription(dfeta_teacherstatus? teacherStatus, DateTime? qtsDate = null, DateTime? qtlsDate = null) { - "28" => "Qualified", - "50" => "Qualified", - "67" => "Qualified", - "68" => "Qualified", - "69" => "Qualified", - "71" => "Qualified", - "87" => "Qualified", - "90" => "Qualified", - "100" => "Qualified", - "103" => "Qualified", - "104" => "Qualified", - "206" => "Qualified", - "211" => "Trainee teacher", - "212" => "Assessment only route candidate", - "213" => "Qualified", - "214" => "Partial qualified teacher status", - "223" => "Qualified", - _ when teacherStatus.dfeta_name.StartsWith("Qualified teacher", StringComparison.OrdinalIgnoreCase) => "Qualified", - _ => throw new ArgumentException($"Unregonized QTS status: '{teacherStatus.dfeta_Value}'.", nameof(teacherStatus)) - }; + return (qtsDate, qtlsDate) switch + { + (null, null) => GetStatusDescriptionForTeacherStatus(teacherStatus), + (var qts, var qtls) when qtls.ToDateOnlyWithDqtBstFix(isLocalTime: true) <= qts.ToDateOnlyWithDqtBstFix(isLocalTime: true) => "Qualified Teacher Learning and Skills status", + (null, var qtls) => "Qualified Teacher Learning and Skills status", + _ => GetStatusDescriptionForTeacherStatus(teacherStatus), + }; + + string GetStatusDescriptionForTeacherStatus(dfeta_teacherstatus? teacherStatus) => + teacherStatus!.dfeta_Value switch + { + "28" => "Qualified", + "50" => "Qualified", + "67" => "Qualified", + "68" => "Qualified", + "69" => "Qualified", + "71" => "Qualified", + "87" => "Qualified", + "90" => "Qualified", + "100" => "Qualified", + "103" => "Qualified", + "104" => "Qualified", + "206" => "Qualified", + "211" => "Trainee teacher", + "212" => "Assessment only route candidate", + "213" => "Qualified", + "214" => "Partial qualified teacher status", + "223" => "Qualified", + _ when teacherStatus.dfeta_name.StartsWith("Qualified teacher", StringComparison.OrdinalIgnoreCase) => "Qualified", + _ => throw new ArgumentException($"Unrecognized QTS status: '{teacherStatus.dfeta_Value}'.", nameof(teacherStatus)) + }; + } + } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/FindPersonsBase.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/FindPersonsBase.cs index b7e4432ae..97ed03330 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/FindPersonsBase.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/FindPersonsBase.cs @@ -23,6 +23,7 @@ public record FindPersonsResultItem public required DqtInductionStatusInfo? DqtInductionStatus { get; init; } public required QtsInfo? Qts { get; init; } public required EytsInfo? Eyts { get; init; } + public required QtlsStatus QtlsStatus { get; init; } } public abstract class FindPersonsHandlerBase( @@ -45,7 +46,20 @@ public abstract class FindPersonsHandlerBase( Contact.Fields.dfeta_StatedFirstName, Contact.Fields.dfeta_StatedMiddleName, Contact.Fields.dfeta_StatedLastName, - Contact.Fields.dfeta_InductionStatus); + Contact.Fields.dfeta_InductionStatus, + Contact.Fields.dfeta_qtlsdate, + Contact.Fields.dfeta_QtlsDateHasBeenSet); + + private static QtlsStatus MapQtlsStatus(DateTime? qtlsDate, bool? qtlsDateHasBeenSet) + { + return (qtlsDate, qtlsDateHasBeenSet) switch + { + (not null, _) => QtlsStatus.Active, + (null, true) => QtlsStatus.Expired, + (null, false) => QtlsStatus.None, + (_, _) => QtlsStatus.None, + }; + } protected async Task CreateResultAsync(IEnumerable matched) { @@ -81,6 +95,7 @@ protected async Task CreateResultAsync(IEnumerable m .ToAsyncEnumerable() .SelectAwait(async r => new FindPersonsResultItem() { + QtlsStatus = MapQtlsStatus(r.dfeta_qtlsdate, r.dfeta_QtlsDateHasBeenSet), Trn = r.dfeta_TRN, DateOfBirth = r.BirthDate!.Value.ToDateOnlyWithDqtBstFix(isLocalTime: false), FirstName = r.ResolveFirstName(), @@ -95,26 +110,26 @@ protected async Task CreateResultAsync(IEnumerable m }) .AsReadOnly(), Alerts = alerts.GetValueOrDefault(r.Id, []) - .Where(a => !a.AlertType.InternalOnly) - .Select(a => new Alert() - { - AlertId = a.AlertId, - AlertType = new() + .Where(a => !a.AlertType.InternalOnly) + .Select(a => new Alert() { - AlertTypeId = a.AlertType.AlertTypeId, - AlertCategory = new() + AlertId = a.AlertId, + AlertType = new() { - AlertCategoryId = a.AlertType.AlertCategory.AlertCategoryId, - Name = a.AlertType.AlertCategory.Name + AlertTypeId = a.AlertType.AlertTypeId, + AlertCategory = new() + { + AlertCategoryId = a.AlertType.AlertCategory.AlertCategoryId, + Name = a.AlertType.AlertCategory.Name + }, + Name = a.AlertType.Name, + DqtSanctionCode = a.AlertType.DqtSanctionCode! }, - Name = a.AlertType.Name, - DqtSanctionCode = a.AlertType.DqtSanctionCode! - }, - Details = a.Details, - StartDate = a.StartDate, - EndDate = a.EndDate - }) - .AsReadOnly(), + Details = a.Details, + StartDate = a.StartDate, + EndDate = a.EndDate + }) + .AsReadOnly(), PreviousNames = previousNameHelper.GetFullPreviousNames(previousNames[r.Id], contactsById[r.Id]) .Select(name => new NameInfo() { @@ -131,7 +146,7 @@ protected async Task CreateResultAsync(IEnumerable m StatusDescription = inductionStatus.GetDescription() } : null, - Qts = await QtsInfo.CreateAsync(qtsRegistrations[r.Id].OrderBy(qr => qr.CreatedOn).FirstOrDefault(s => s.dfeta_QTSDate is not null), referenceDataCache), + Qts = await QtsInfo.CreateAsync(qtsRegistrations[r.Id].OrderBy(qr => qr.CreatedOn).FirstOrDefault(s => s.dfeta_QTSDate is not null), referenceDataCache, r.dfeta_qtlsdate), Eyts = await EytsInfo.CreateAsync(qtsRegistrations[r.Id].OrderBy(qr => qr.CreatedOn).FirstOrDefault(s => s.dfeta_EYTSDate is not null), referenceDataCache), }) .OrderBy(c => c.Trn) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs index 7f59a50b3..a1bfdf8d2 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs @@ -56,6 +56,7 @@ public record GetPersonResult public required Option> Alerts { get; init; } public required Option> PreviousNames { get; init; } public required Option AllowIdSignInWithProhibitions { get; init; } + public required QtlsStatus QtlsStatus { get; set; } } public record GetPersonResultInduction : InductionInfo @@ -193,7 +194,9 @@ public async Task> HandleAsync(GetPersonCommand comma Contact.Fields.dfeta_EYTSDate, Contact.Fields.EMailAddress1, Contact.Fields.dfeta_AllowIDSignInWithProhibitions, - Contact.Fields.dfeta_InductionStatus))); + Contact.Fields.dfeta_InductionStatus, + Contact.Fields.dfeta_QtlsDateHasBeenSet, + Contact.Fields.dfeta_qtlsdate))); if (contactDetail is null) { @@ -386,6 +389,8 @@ async Task WithTrsDbLockAsync(Func> action) induction = Option.Some(mappedInduction.Induction); } + var qtlsStatus = MapQtlsStatus(contact.dfeta_qtlsdate, contact.dfeta_QtlsDateHasBeenSet); + return new GetPersonResult() { Trn = command.Trn, @@ -396,7 +401,8 @@ async Task WithTrsDbLockAsync(Func> action) NationalInsuranceNumber = contact.dfeta_NINumber, PendingNameChange = command.Include.HasFlag(GetPersonCommandIncludes.PendingDetailChanges) ? Option.Some((await getPendingDetailChangesTask!).PendingNameRequest) : default, PendingDateOfBirthChange = command.Include.HasFlag(GetPersonCommandIncludes.PendingDetailChanges) ? Option.Some((await getPendingDetailChangesTask!).PendingDateOfBirthRequest) : default, - Qts = await QtsInfo.CreateAsync(qts, referenceDataCache), + Qts = await QtsInfo.CreateAsync(qts, referenceDataCache, contact.dfeta_qtlsdate), + QtlsStatus = qtlsStatus, Eyts = await EytsInfo.CreateAsync(eyts, referenceDataCache), EmailAddress = contact.EMailAddress1, Induction = induction, @@ -462,6 +468,17 @@ async Task WithTrsDbLockAsync(Func> action) }; } + private static QtlsStatus MapQtlsStatus(DateTime? qtlsDate, bool? qtlsDateHasBeenSet) + { + return (qtlsDate, qtlsDateHasBeenSet) switch + { + (not null, _) => QtlsStatus.Active, + (null, true) => QtlsStatus.Expired, + (null, false) => QtlsStatus.None, + (_, _) => QtlsStatus.None, + }; + } + private static (GetPersonResultDqtInduction? DqtInduction, GetPersonResultInduction Induction) MapInduction( dfeta_induction? induction, IEnumerable? inductionPeriods, diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs index c5a300c5b..a4de036eb 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs @@ -1,5 +1,6 @@ using TeachingRecordSystem.Api.V3.Implementation.Operations; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus; +using QtlsStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.QtlsStatus; namespace TeachingRecordSystem.Api.V3.VNext.Responses; @@ -14,4 +15,5 @@ public partial record FindPersonResponse public partial record FindPersonResponseResult { public required InductionStatus InductionStatus { get; init; } + public required QtlsStatus QtlsStatus { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs index 3a77e70ce..e292f6bd7 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs @@ -1,6 +1,7 @@ using AutoMapper.Configuration.Annotations; using TeachingRecordSystem.Api.V3.Implementation.Operations; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus; +using QtlsStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.QtlsStatus; namespace TeachingRecordSystem.Api.V3.VNext.Responses; @@ -13,8 +14,9 @@ public partial record FindPersonsResponse } [AutoMap(typeof(FindPersonsResultItem))] -[GenerateVersionedDto(typeof(V20240920.Responses.FindPersonsResponseResult), excludeMembers: ["InductionStatus"])] +[GenerateVersionedDto(typeof(V20240920.Responses.FindPersonsResponseResult), excludeMembers: ["InductionStatus", "QtlsStatus"])] public partial record FindPersonsResponseResult { public required InductionStatus InductionStatus { get; init; } + public required QtlsStatus QtlsStatus { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs index 8f1e96b03..683adfb68 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs @@ -1,6 +1,7 @@ using Optional; using TeachingRecordSystem.Api.V3.Implementation.Operations; -using TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos; +using InductionInfo = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionInfo; +using QtlsStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.QtlsStatus; namespace TeachingRecordSystem.Api.V3.VNext.Responses; @@ -9,6 +10,7 @@ namespace TeachingRecordSystem.Api.V3.VNext.Responses; public partial record GetPersonResponse { public required Option Induction { get; init; } + public required QtlsStatus QtlsStatus { get; set; } } [AutoMap(typeof(GetPersonResultInduction))] diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/QtlsStatus.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/QtlsStatus.cs new file mode 100644 index 000000000..d8b842bf7 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/Dtos/QtlsStatus.cs @@ -0,0 +1,8 @@ +namespace TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos; + +public enum QtlsStatus +{ + None = 0, + Expired = 1, + Active = 2, +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonByLastNameAndDateOfBirthTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonByLastNameAndDateOfBirthTests.cs index faecce063..0d9b1dceb 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonByLastNameAndDateOfBirthTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonByLastNameAndDateOfBirthTests.cs @@ -1,3 +1,5 @@ +using TeachingRecordSystem.Api.V3.Implementation.Dtos; + namespace TeachingRecordSystem.Api.Tests.V3.VNext; [Collection(nameof(DisableParallelization))] @@ -67,4 +69,86 @@ public async Task Get_PersonHasNonNullDqtInductionStatus_ReturnsExpectedStatus() var responseInduction = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("inductionStatus").GetString(); Assert.Equal(inductionStatus.ToString(), responseInduction); } + + [Fact] + public async Task Get_WithExpiredQtlsDate_ReturnsExpiredQtlsStatus() + { + // Arrange + var lastName = "Smith"; + var dateOfBirth = new DateOnly(1990, 1, 1); + var qtlsDate = new DateOnly(2020, 01, 01); + + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithLastName(lastName) + .WithQtlsDate(qtlsDate) + .WithDateOfBirth(dateOfBirth)); + + var entity = new Microsoft.Xrm.Sdk.Entity() { Id = person.PersonId, LogicalName = Contact.EntityLogicalName }; + entity[Contact.Fields.dfeta_qtlsdate] = null; + await TestData.OrganizationService.UpdateAsync(entity); + + var request = new HttpRequestMessage( + HttpMethod.Get, + $"/v3/persons?findBy=LastNameAndDateOfBirth&lastName={lastName}&dateOfBirth={dateOfBirth:yyyy-MM-dd}"); + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Expired.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithQtlsDate_ReturnsActiveQtlsStatus() + { + // Arrange + var lastName = "Smith"; + var dateOfBirth = new DateOnly(1990, 1, 1); + var qtlsDate = new DateOnly(2020, 01, 01); + + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithLastName(lastName) + .WithQtlsDate(qtlsDate) + .WithDateOfBirth(dateOfBirth)); + + var request = new HttpRequestMessage( + HttpMethod.Get, + $"/v3/persons?findBy=LastNameAndDateOfBirth&lastName={lastName}&dateOfBirth={dateOfBirth:yyyy-MM-dd}"); + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Active.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithoutQtlsDate_ReturnsNoneQtlsStatus() + { + // Arrange + var lastName = "Smith"; + var dateOfBirth = new DateOnly(1990, 1, 1); + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithLastName(lastName) + .WithDateOfBirth(dateOfBirth)); + + var request = new HttpRequestMessage( + HttpMethod.Get, + $"/v3/persons?findBy=LastNameAndDateOfBirth&lastName={lastName}&dateOfBirth={dateOfBirth:yyyy-MM-dd}"); + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.None.ToString(), qtlsStatus!); + } } diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonsByTrnAndDateOfBirthTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonsByTrnAndDateOfBirthTests.cs index b19a56c68..7a7dfa56e 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonsByTrnAndDateOfBirthTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/FindPersonsByTrnAndDateOfBirthTests.cs @@ -1,3 +1,5 @@ +using TeachingRecordSystem.Api.V3.Implementation.Dtos; + namespace TeachingRecordSystem.Api.Tests.V3.VNext; [Collection(nameof(DisableParallelization))] @@ -89,4 +91,147 @@ public async Task Get_PersonHasNonNullDqtInductionStatus_ReturnsExpectedStatus() var responseInduction = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("inductionStatus").GetString(); Assert.Equal(inductionStatus.ToString(), responseInduction); } + + [Fact] + public async Task Get_WithQtlsDate_ReturnsActiveQtlsStatus() + { + // Arrange + var lastName = "Smith"; + var dateOfBirth = new DateOnly(1990, 1, 1); + var dqtInductionStatus = dfeta_InductionStatus.Pass; + var inductionStatus = dqtInductionStatus.ToInductionStatus(); + var inductionStartDate = new DateOnly(1996, 2, 3); + var inductionCompletedDate = new DateOnly(1996, 6, 7); + var qtlsDate = new DateOnly(2020, 01, 01); + + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithQtlsDate(qtlsDate) + .WithLastName(lastName) + .WithDateOfBirth(dateOfBirth) + .WithDqtInduction( + dqtInductionStatus, + inductionExemptionReason: null, + inductionStartDate, + inductionCompletedDate)); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/v3/persons/find") + { + Content = JsonContent.Create(new + { + persons = new[] + { + new + { + trn = person.Trn, + dateOfBirth = person.DateOfBirth + } + } + }) + }; + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Active.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithoutQtlsDate_ReturnsNoneQtlsStatus() + { + // Arrange + var lastName = "Smith"; + var dateOfBirth = new DateOnly(1990, 1, 1); + var dqtInductionStatus = dfeta_InductionStatus.Pass; + var inductionStatus = dqtInductionStatus.ToInductionStatus(); + var inductionStartDate = new DateOnly(1996, 2, 3); + var inductionCompletedDate = new DateOnly(1996, 6, 7); + + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithLastName(lastName) + .WithDateOfBirth(dateOfBirth) + .WithDqtInduction( + dqtInductionStatus, + inductionExemptionReason: null, + inductionStartDate, + inductionCompletedDate)); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/v3/persons/find") + { + Content = JsonContent.Create(new + { + persons = new[] + { + new + { + trn = person.Trn, + dateOfBirth = person.DateOfBirth + } + } + }) + }; + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.None.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithExpiredQtlsDate_ReturnsExpiredQtlsStatus() + { + // Arrange + var lastName = "Smith"; + var dateOfBirth = new DateOnly(1990, 1, 1); + var dqtInductionStatus = dfeta_InductionStatus.Pass; + var inductionStatus = dqtInductionStatus.ToInductionStatus(); + var inductionStartDate = new DateOnly(1996, 2, 3); + var inductionCompletedDate = new DateOnly(1996, 6, 7); + var qtlsDate = new DateOnly(2020, 01, 01); + + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithQtlsDate(qtlsDate) + .WithLastName(lastName) + .WithDateOfBirth(dateOfBirth) + .WithDqtInduction( + dqtInductionStatus, + inductionExemptionReason: null, + inductionStartDate, + inductionCompletedDate)); + + var entity = new Microsoft.Xrm.Sdk.Entity() { Id = person.PersonId, LogicalName = Contact.EntityLogicalName }; + entity[Contact.Fields.dfeta_qtlsdate] = null; + await TestData.OrganizationService.UpdateAsync(entity); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/v3/persons/find") + { + Content = JsonContent.Create(new + { + persons = new[] + { + new + { + trn = person.Trn, + dateOfBirth = person.DateOfBirth + } + } + }) + }; + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Expired.ToString(), qtlsStatus!); + } } diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonByTrnTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonByTrnTests.cs index 76f35ad1c..0e0a51eff 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonByTrnTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonByTrnTests.cs @@ -1,3 +1,5 @@ +using TeachingRecordSystem.Api.V3.Implementation.Dtos; + namespace TeachingRecordSystem.Api.Tests.V3.VNext; public class GetPersonByTrnTests : TestBase @@ -145,6 +147,98 @@ public async Task Get_WithNonNullDqtInductionStatus_ReturnsExpectedInduction() responseInduction); } + [Fact] + public async Task Get_WithQtlsDate_ReturnsActiveQtlsStatus() + { + // Arrange + var dqtStatus = dfeta_InductionStatus.Pass; + var status = dqtStatus.ToInductionStatus(); + var startDate = new DateOnly(1996, 2, 3); + var completedDate = new DateOnly(1996, 6, 7); + var qtlsDate = new DateOnly(2020, 01, 01); + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithQtlsDate(qtlsDate) + .WithDqtInduction( + dqtStatus, + inductionExemptionReason: null, + startDate, + completedDate)); + + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"/v3/persons/{person.Trn}?include=Induction"); + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Active.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithExpiredQtlsDate_ReturnsExpiredQtlsStatus() + { + // Arrange + var dqtStatus = dfeta_InductionStatus.Pass; + var status = dqtStatus.ToInductionStatus(); + var startDate = new DateOnly(1996, 2, 3); + var completedDate = new DateOnly(1996, 6, 7); + var qtlsDate = new DateOnly(2020, 01, 01); + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithQtlsDate(qtlsDate) + .WithDqtInduction( + dqtStatus, + inductionExemptionReason: null, + startDate, + completedDate)); + + var entity = new Microsoft.Xrm.Sdk.Entity() { Id = person.PersonId, LogicalName = Contact.EntityLogicalName }; + entity[Contact.Fields.dfeta_qtlsdate] = null; + await TestData.OrganizationService.UpdateAsync(entity); + + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"/v3/persons/{person.Trn}?include=Induction"); + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Expired.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithoutQtlsDate_ReturnsNoneQtlsStatus() + { + // Arrange + var dqtStatus = dfeta_InductionStatus.Pass; + var status = dqtStatus.ToInductionStatus(); + var startDate = new DateOnly(1996, 2, 3); + var completedDate = new DateOnly(1996, 6, 7); + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithDqtInduction( + dqtStatus, + inductionExemptionReason: null, + startDate, + completedDate)); + + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, $"/v3/persons/{person.Trn}?include=Induction"); + + // Act + var response = await GetHttpClientWithApiKey().SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.None.ToString(), qtlsStatus!); + } + [Fact] public async Task Get_WithNullDqtInductionStatus_ReturnsNoneInductionStatus() { diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonTests.cs index 8ce9880bb..e93fa1321 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Api.Tests/V3/VNext/GetPersonTests.cs @@ -1,3 +1,5 @@ +using TeachingRecordSystem.Api.V3.Implementation.Dtos; + namespace TeachingRecordSystem.Api.Tests.V3.VNext; public class GetPersonTests(HostFixture hostFixture) : TestBase(hostFixture) @@ -66,4 +68,69 @@ public async Task Get_WithNullDqtInductionStatus_ReturnsNoneInductionStatus() }, responseInduction); } + + [Fact] + public async Task Get_WithQtlsDate_ReturnsActiveQtlsStatus() + { + // Arrange + var qtlsDate = new DateOnly(2020, 01, 01); + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithQtlsDate(qtlsDate)); + + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, "/v3/person"); + + // Act + var response = await GetHttpClientWithIdentityAccessToken(person.Trn!).SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Active.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithoutQtlsDate_ReturnsNoneQtlsStatus() + { + // Arrange + var person = await TestData.CreatePersonAsync(p => p + .WithTrn()); + + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, "/v3/person"); + + // Act + var response = await GetHttpClientWithIdentityAccessToken(person.Trn!).SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.None.ToString(), qtlsStatus!); + } + + [Fact] + public async Task Get_WithExpiredQtlsDate_ReturnsExpiredQtlsStatus() + { + // Arrange + var qtlsDate = new DateOnly(2020, 01, 01); + var person = await TestData.CreatePersonAsync(p => p + .WithTrn() + .WithQtlsDate(qtlsDate)); + + var entity = new Microsoft.Xrm.Sdk.Entity() { Id = person.PersonId, LogicalName = Contact.EntityLogicalName }; + entity[Contact.Fields.dfeta_qtlsdate] = null; + await TestData.OrganizationService.UpdateAsync(entity); + + // Arrange + var request = new HttpRequestMessage(HttpMethod.Get, "/v3/person"); + + // Act + var response = await GetHttpClientWithIdentityAccessToken(person.Trn!).SendAsync(request); + + // Assert + var jsonResponse = await AssertEx.JsonResponseAsync(response); + var qtlsStatus = jsonResponse.RootElement.GetProperty("qtlsStatus").GetString(); + Assert.Equal(QtlsStatus.Expired.ToString(), qtlsStatus!); + } }