Skip to content

Commit

Permalink
Added qtlsstatus to vnext getperson
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKevJoy committed Dec 27, 2024
1 parent 43b8c83 commit 255bada
Show file tree
Hide file tree
Showing 13 changed files with 565 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -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,
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,59 @@ public record QtsInfo
public required string CertificateUrl { get; init; }
public required string StatusDescription { get; init; }

public static async Task<QtsInfo?> CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache)
public static async Task<QtsInfo?> CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache, DateTime? qtlsDate)
{
if (qtsRegistration is null)
var qtsDates = new List<DateTime?>() { 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))
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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<FindPersonsResult> CreateResultAsync(IEnumerable<Contact> matched)
{
Expand Down Expand Up @@ -131,8 +145,9 @@ protected async Task<FindPersonsResult> CreateResultAsync(IEnumerable<Contact> 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),
QtlsStatus = MapQtlsStatus(r.dfeta_qtlsdate, r.dfeta_QtlsDateHasBeenSet),
})
.OrderBy(c => c.Trn)
.ToArrayAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public record GetPersonResult
public required Option<IReadOnlyCollection<Alert>> Alerts { get; init; }
public required Option<IReadOnlyCollection<NameInfo>> PreviousNames { get; init; }
public required Option<bool> AllowIdSignInWithProhibitions { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}

public record GetPersonResultInduction : InductionInfo
Expand Down Expand Up @@ -193,7 +194,9 @@ public async Task<ApiResult<GetPersonResult>> 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)
{
Expand Down Expand Up @@ -386,6 +389,8 @@ async Task<T> WithTrsDbLockAsync<T>(Func<Task<T>> action)
induction = Option.Some(mappedInduction.Induction);
}

var qtlsStatus = MapQtlsStatus(contact.dfeta_qtlsdate, contact.dfeta_QtlsDateHasBeenSet);

return new GetPersonResult()
{
Trn = command.Trn,
Expand All @@ -396,7 +401,8 @@ async Task<T> WithTrsDbLockAsync<T>(Func<Task<T>> 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,
Expand Down Expand Up @@ -462,6 +468,17 @@ async Task<T> WithTrsDbLockAsync<T>(Func<Task<T>> 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<dfeta_inductionperiod>? inductionPeriods,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using TeachingRecordSystem.Core.ApiSchema.V3.V20240814.Dtos;
using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos;
using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus;
using QtlsStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.QtlsStatus;

namespace TeachingRecordSystem.Api.V3.VNext.Responses;

Expand All @@ -27,4 +28,5 @@ public record FindPersonResponseResult
public required EytsInfo? Eyts { get; init; }
public required IReadOnlyCollection<Alert> Alerts { get; init; }
public required InductionStatus InductionStatus { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using TeachingRecordSystem.Core.ApiSchema.V3.V20240920.Dtos;
using InductionStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.InductionStatus;
using NameInfo = TeachingRecordSystem.Core.ApiSchema.V3.V20240101.Dtos.NameInfo;
using QtlsStatus = TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos.QtlsStatus;

namespace TeachingRecordSystem.Api.V3.VNext.Responses;

Expand All @@ -28,4 +29,5 @@ public record FindPersonsResponseResult
public required EytsInfo? Eyts { get; init; }
public required IReadOnlyCollection<Alert> Alerts { get; init; }
public required InductionStatus InductionStatus { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public record GetPersonResponse
public required Option<IReadOnlyCollection<Alert>> Alerts { get; init; }
public required Option<IReadOnlyCollection<NameInfo>> PreviousNames { get; init; }
public required Option<bool> AllowIdSignInWithProhibitions { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}

[AutoMap(typeof(Implementation.Dtos.QtsInfo))]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TeachingRecordSystem.Core.ApiSchema.V3.VNext.Dtos;

public enum QtlsStatus
{
None = 0,
Expired = 1,
Active = 2,
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using TeachingRecordSystem.Api.V3.Implementation.Dtos;

namespace TeachingRecordSystem.Api.Tests.V3.VNext;

[Collection(nameof(DisableParallelization))]
Expand Down Expand Up @@ -67,4 +69,122 @@ 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!);
}

[Theory]
[InlineData("01/01/2019", "01/01/2022", "Qualified Teacher Learning and Skills status", "2019-01-01")]
[InlineData("01/01/2019", "01/01/1999", "Qualified", "1999-01-01")]
public async Task Get_QtsAndActiveQtls_ReturnsQtsStatusOfEarliestOfDates(string qtlsDateStr, string qtsDateStr, string expectedStatusDescription, string expectedAwardedDate)
{
// Arrange
var qtlsDate = DateOnly.Parse(qtlsDateStr);
var qtsDate = DateOnly.Parse(qtsDateStr);
var lastName = "Smith";
var dateOfBirth = new DateOnly(1990, 1, 1);
var person = await TestData.CreatePersonAsync(p => p
.WithTrn()
.WithLastName(lastName)
.WithDateOfBirth(dateOfBirth)
.WithQts(qtsDate)
.WithQtlsDate(qtlsDate));

var status = await ReferenceCache.GetTeacherStatusByValueAsync("71"); //qualified teacher
var qtsRegistration = new dfeta_qtsregistration() { dfeta_QTSDate = qtsDate.ToDateTime(), dfeta_TeacherStatusId = status.ToEntityReference() };
DataverseAdapterMock.Setup(x => x.GetQtsRegistrationsByTeacherAsync(It.IsAny<Guid>(), It.IsAny<string[]>())).ReturnsAsync(new[] { qtsRegistration });
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 qts = jsonResponse.RootElement.GetProperty("results").EnumerateArray().Single().GetProperty("qts");
var statusDescription = qts.GetProperty("statusDescription").GetString();
var awarded = qts.GetProperty("awarded").GetString();
Assert.Equal(expectedStatusDescription, statusDescription!);
Assert.Equal(expectedAwardedDate, awarded!);
}
}
Loading

0 comments on commit 255bada

Please sign in to comment.