From 5b875602429f74b04ed3fe791356d970f9b2e205 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/QtsInfo.cs | 53 ++++--- .../Operations/FindPersonsBase.cs | 47 ++++-- .../V3/Implementation/Operations/GetPerson.cs | 22 ++- .../V3/VNext/Responses/FindPersonResponse.cs | 2 + .../V3/VNext/Responses/FindPersonsResponse.cs | 2 + .../V3/VNext/Responses/GetPersonResponse.cs | 2 + .../ApiSchema/V3/VNext/QtlsStatus.cs | 15 ++ ...FindPersonByLastNameAndDateOfBirthTests.cs | 84 ++++++++++ .../FindPersonsByTrnAndDateOfBirthTests.cs | 145 ++++++++++++++++++ .../V3/VNext/GetPersonByTrnTests.cs | 94 ++++++++++++ .../V3/VNext/GetPersonTests.cs | 68 ++++++++ 11 files changed, 492 insertions(+), 42 deletions(-) create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/QtlsStatus.cs diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs index 940d9e748..39672f2da 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Dtos/QtsInfo.cs @@ -8,8 +8,9 @@ public record QtsInfo public required DateOnly Awarded { get; init; } public required string CertificateUrl { get; init; } public required string StatusDescription { get; init; } + public required bool? QtlsHasBeenSet { get; init; } - public static async Task CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache) + public static async Task CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache, DateTime? qtlsDate, bool? qtlsHasBeenSet) { if (qtsRegistration is null) { @@ -23,36 +24,40 @@ public record QtsInfo } var teacherStatus = await referenceDataCache.GetTeacherStatusByIdAsync(qtsRegistration.dfeta_TeacherStatusId.Id); - var statusDescription = GetStatusDescription(teacherStatus); + var statusDescription = GetStatusDescription(teacherStatus, qtlsDate); return new() { Awarded = awardedDate!.Value, CertificateUrl = "/v3/certificates/qts", StatusDescription = statusDescription, + QtlsHasBeenSet = qtlsHasBeenSet }; } + private static string GetStatusDescription(dfeta_teacherstatus teacherStatus, DateTime? qtlsDate = null) + => qtlsDate.HasValue + ? "Qualified Teacher Learning and Skills status" + : 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)) + }; - private static string GetStatusDescription(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($"Unregonized 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..e116efa3c 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 Core.ApiSchema.V3.VNext.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 Core.ApiSchema.V3.VNext.QtlsStatus MapQtlsStatus(DateTime? qtlsDate, bool? qtlsDateHasBeenSet) + { + return (qtlsDate, qtlsDateHasBeenSet) switch + { + (not null, _) => Core.ApiSchema.V3.VNext.QtlsStatus.Active, + (null, true) => Core.ApiSchema.V3.VNext.QtlsStatus.Expired, + (null, false) => Core.ApiSchema.V3.VNext.QtlsStatus.None, + (_, _) => Core.ApiSchema.V3.VNext.QtlsStatus.None, + }; + } protected async Task CreateResultAsync(IEnumerable matched) { @@ -79,14 +93,15 @@ protected async Task CreateResultAsync(IEnumerable m var items = await matched .ToAsyncEnumerable() - .SelectAwait(async r => new FindPersonsResultItem() - { - Trn = r.dfeta_TRN, - DateOfBirth = r.BirthDate!.Value.ToDateOnlyWithDqtBstFix(isLocalTime: false), - FirstName = r.ResolveFirstName(), - MiddleName = r.ResolveMiddleName(), - LastName = r.ResolveLastName(), - Sanctions = alerts.GetValueOrDefault(r.Id, []) + .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(), + MiddleName = r.ResolveMiddleName(), + LastName = r.ResolveLastName(), + Sanctions = alerts.GetValueOrDefault(r.Id, []) .Where(a => Constants.LegacyExposableSanctionCodes.Contains(a.AlertType.DqtSanctionCode) && a.IsOpen) .Select(a => new SanctionInfo() { @@ -94,7 +109,7 @@ protected async Task CreateResultAsync(IEnumerable m StartDate = a.StartDate }) .AsReadOnly(), - Alerts = alerts.GetValueOrDefault(r.Id, []) + Alerts = alerts.GetValueOrDefault(r.Id, []) .Where(a => !a.AlertType.InternalOnly) .Select(a => new Alert() { @@ -115,7 +130,7 @@ protected async Task CreateResultAsync(IEnumerable m EndDate = a.EndDate }) .AsReadOnly(), - PreviousNames = previousNameHelper.GetFullPreviousNames(previousNames[r.Id], contactsById[r.Id]) + PreviousNames = previousNameHelper.GetFullPreviousNames(previousNames[r.Id], contactsById[r.Id]) .Select(name => new NameInfo() { FirstName = name.FirstName, @@ -123,17 +138,17 @@ protected async Task CreateResultAsync(IEnumerable m LastName = name.LastName }) .AsReadOnly(), - InductionStatus = r.dfeta_InductionStatus.ToInductionStatus(), - DqtInductionStatus = r.dfeta_InductionStatus?.ConvertToDqtInductionStatus() is Dtos.DqtInductionStatus inductionStatus ? + InductionStatus = r.dfeta_InductionStatus.ToInductionStatus(), + DqtInductionStatus = r.dfeta_InductionStatus?.ConvertToDqtInductionStatus() is Dtos.DqtInductionStatus inductionStatus ? new DqtInductionStatusInfo() { Status = inductionStatus, StatusDescription = inductionStatus.GetDescription() } : null, - Qts = await QtsInfo.CreateAsync(qtsRegistrations[r.Id].OrderBy(qr => qr.CreatedOn).FirstOrDefault(s => s.dfeta_QTSDate is not null), referenceDataCache), - Eyts = await EytsInfo.CreateAsync(qtsRegistrations[r.Id].OrderBy(qr => qr.CreatedOn).FirstOrDefault(s => s.dfeta_EYTSDate 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, r.dfeta_QtlsDateHasBeenSet), + Eyts = await EytsInfo.CreateAsync(qtsRegistrations[r.Id].OrderBy(qr => qr.CreatedOn).FirstOrDefault(s => s.dfeta_EYTSDate is not null), referenceDataCache), + }) .OrderBy(c => c.Trn) .ToArrayAsync(); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs index 7f59a50b3..b7b7af169 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Implementation/Operations/GetPerson.cs @@ -2,6 +2,7 @@ using Microsoft.Xrm.Sdk.Query; using Optional; using TeachingRecordSystem.Api.V3.Implementation.Dtos; +using TeachingRecordSystem.Core.ApiSchema.V3.VNext; using TeachingRecordSystem.Core.DataStore.Postgres; using TeachingRecordSystem.Core.Dqt; using TeachingRecordSystem.Core.Dqt.Models; @@ -56,6 +57,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 +195,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 +390,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 +402,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, contact.dfeta_QtlsDateHasBeenSet), + QtlsStatus = qtlsStatus, Eyts = await EytsInfo.CreateAsync(eyts, referenceDataCache), EmailAddress = contact.EMailAddress1, Induction = induction, @@ -462,6 +469,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..d54743522 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonResponse.cs @@ -1,4 +1,5 @@ using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Core.ApiSchema.V3.VNext; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus; 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..5ea7cdd08 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs @@ -1,5 +1,6 @@ using AutoMapper.Configuration.Annotations; using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Core.ApiSchema.V3.VNext; using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus; namespace TeachingRecordSystem.Api.V3.VNext.Responses; @@ -17,4 +18,5 @@ public partial record FindPersonsResponse 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..a5a5881ae 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/GetPersonResponse.cs @@ -1,5 +1,6 @@ using Optional; using TeachingRecordSystem.Api.V3.Implementation.Operations; +using TeachingRecordSystem.Core.ApiSchema.V3.VNext; using TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos; 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/QtlsStatus.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/QtlsStatus.cs new file mode 100644 index 000000000..ccd1590b0 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ApiSchema/V3/VNext/QtlsStatus.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; + +namespace TeachingRecordSystem.Core.ApiSchema.V3.VNext; + +public enum QtlsStatus +{ + [Description("None")] + None = 0, + + [Description("Expired")] + Expired = 1, + + [Description("Active")] + 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..5dae681d7 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.Core.ApiSchema.V3.VNext; + 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..8a54afc32 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.Core.ApiSchema.V3.VNext; + 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..c450b843b 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.Core.ApiSchema.V3.VNext; + 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..87049ed1f 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.Core.ApiSchema.V3.VNext; + namespace TeachingRecordSystem.Api.Tests.V3.VNext; public class GetPersonTests(HostFixture hostFixture) : TestBase(hostFixture) @@ -40,6 +42,7 @@ public async Task Get_WithNonNullDqtInductionStatus_ReturnsExpectedInduction() responseInduction); } + [Fact] public async Task Get_WithNullDqtInductionStatus_ReturnsNoneInductionStatus() { @@ -66,4 +69,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!); + } }