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 16, 2024
1 parent dbc2969 commit 5b87560
Show file tree
Hide file tree
Showing 11 changed files with 492 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<QtsInfo?> CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache)
public static async Task<QtsInfo?> CreateAsync(dfeta_qtsregistration? qtsRegistration, ReferenceDataCache referenceDataCache, DateTime? qtlsDate, bool? qtlsHasBeenSet)
{
if (qtsRegistration is null)
{
Expand All @@ -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))
};
}
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 Core.ApiSchema.V3.VNext.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 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<FindPersonsResult> CreateResultAsync(IEnumerable<Contact> matched)
{
Expand Down Expand Up @@ -79,22 +93,23 @@ protected async Task<FindPersonsResult> CreateResultAsync(IEnumerable<Contact> 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()
{
Code = a.AlertType.DqtSanctionCode!,
StartDate = a.StartDate
})
.AsReadOnly(),
Alerts = alerts.GetValueOrDefault(r.Id, [])
Alerts = alerts.GetValueOrDefault(r.Id, [])
.Where(a => !a.AlertType.InternalOnly)
.Select(a => new Alert()
{
Expand All @@ -115,25 +130,25 @@ protected async Task<FindPersonsResult> CreateResultAsync(IEnumerable<Contact> 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,
MiddleName = name.MiddleName,
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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,6 +57,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 +195,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 +390,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 +402,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, contact.dfeta_QtlsDateHasBeenSet),
QtlsStatus = qtlsStatus,
Eyts = await EytsInfo.CreateAsync(eyts, referenceDataCache),
EmailAddress = contact.EMailAddress1,
Induction = induction,
Expand Down Expand Up @@ -462,6 +469,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
@@ -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;
Expand All @@ -14,4 +15,5 @@ public partial record FindPersonResponse
public partial record FindPersonResponseResult
{
public required InductionStatus InductionStatus { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,4 +18,5 @@ public partial record FindPersonsResponse
public partial record FindPersonsResponseResult
{
public required InductionStatus InductionStatus { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -9,6 +10,7 @@ namespace TeachingRecordSystem.Api.V3.VNext.Responses;
public partial record GetPersonResponse
{
public required Option<GetPersonResponseInduction> Induction { get; init; }
public required QtlsStatus QtlsStatus { get; set; }
}

[AutoMap(typeof(GetPersonResultInduction))]
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using TeachingRecordSystem.Core.ApiSchema.V3.VNext;

namespace TeachingRecordSystem.Api.Tests.V3.VNext;

[Collection(nameof(DisableParallelization))]
Expand Down Expand Up @@ -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!);
}
}
Loading

0 comments on commit 5b87560

Please sign in to comment.