diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs index 80bd0a4e3e..d0c15ed3b9 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs @@ -21,6 +21,7 @@ using TeachingRecordSystem.Api.Infrastructure.Security; using TeachingRecordSystem.Api.Validation; using TeachingRecordSystem.Core.Dqt; +using TeachingRecordSystem.Core.Dqt.Models; using TeachingRecordSystem.Core.Infrastructure; using TeachingRecordSystem.Core.Services.Certificates; using TeachingRecordSystem.Core.Services.GetAnIdentityApi; @@ -219,6 +220,7 @@ public static void Main(string[] args) services.AddMemoryCache(); services.AddSingleton(); services.AddTransient(); + services.AddSingleton(); builder.Services.AddOptions() .Bind(builder.Configuration.GetSection("EvidenceFiles")) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonByLastNameAndDateOfBirth.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonByLastNameAndDateOfBirth.cs index b3dcf29886..f8b2920cfe 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonByLastNameAndDateOfBirth.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonByLastNameAndDateOfBirth.cs @@ -22,10 +22,8 @@ public record FindPersonByLastNameAndDateOfBirthResultItem public required IReadOnlyCollection PreviousNames { get; init; } } -public class FindPersonByLastNameAndDateOfBirthHandler(ICrmQueryDispatcher crmQueryDispatcher, IConfiguration configuration) +public class FindPersonByLastNameAndDateOfBirthHandler(ICrmQueryDispatcher crmQueryDispatcher, PreviousNameHelper previousNameHelper) { - private readonly TimeSpan _concurrentNameChangeWindow = TimeSpan.FromSeconds(configuration.GetValue("ConcurrentNameChangeWindowSeconds", 5)); - public async Task Handle(FindPersonByLastNameAndDateOfBirthCommand command) { var contacts = await crmQueryDispatcher.ExecuteQuery( @@ -53,7 +51,7 @@ public async Task Handle(FindPersonByL var previousNames = (await crmQueryDispatcher.ExecuteQuery(new GetPreviousNamesByContactIdsQuery(contactsById.Keys))) .ToDictionary( kvp => kvp.Key, - kvp => PreviousNameHelper.GetFullPreviousNames(kvp.Value, contactsById[kvp.Key], _concurrentNameChangeWindow)); + kvp => previousNameHelper.GetFullPreviousNames(kvp.Value, contactsById[kvp.Key])); return new FindPersonByLastNameAndDateOfBirthResult( Total: contacts.Length, diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonsByTrnAndDateOfBirth.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonsByTrnAndDateOfBirth.cs new file mode 100644 index 0000000000..701a475671 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonsByTrnAndDateOfBirth.cs @@ -0,0 +1,92 @@ +using System.Collections.Immutable; +using Microsoft.Xrm.Sdk.Query; +using TeachingRecordSystem.Api.V3.Core.SharedModels; +using TeachingRecordSystem.Core.Dqt; +using TeachingRecordSystem.Core.Dqt.Models; +using TeachingRecordSystem.Core.Dqt.Queries; + +namespace TeachingRecordSystem.Api.V3.Core.Operations; + +public record FindPersonsByTrnAndDateOfBirthCommand(IEnumerable<(string Trn, DateOnly DateOfBirth)> Persons); + +public record FindPersonsByTrnAndDateOfBirthResult(int Total, IReadOnlyCollection Items); + +public record FindPersonsByTrnAndDateOfBirthResultItem +{ + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required IReadOnlyCollection Sanctions { get; init; } + public required IReadOnlyCollection PreviousNames { get; init; } +} + +public class FindPersonsByTrnAndDateOfBirthHandler(ICrmQueryDispatcher crmQueryDispatcher, PreviousNameHelper previousNameHelper) +{ + public async Task Handle(FindPersonsByTrnAndDateOfBirthCommand command) + { + var contacts = await crmQueryDispatcher.ExecuteQuery( + new GetActiveContactsByTrnsQuery( + command.Persons.Select(p => p.Trn), + new ColumnSet( + Contact.Fields.dfeta_TRN, + Contact.Fields.BirthDate, + Contact.Fields.FirstName, + Contact.Fields.MiddleName, + Contact.Fields.LastName, + Contact.Fields.dfeta_StatedFirstName, + Contact.Fields.dfeta_StatedMiddleName, + Contact.Fields.dfeta_StatedLastName))); + + // Remove any results where the request DOB doesn't match the contact's DOB + // (we can't easily do this in the query itself). + var matched = contacts + .Where(kvp => kvp.Value is not null) + .Where(kvp => command.Persons.Any(p => p.Trn == kvp.Key && p.DateOfBirth == kvp.Value!.BirthDate?.ToDateOnlyWithDqtBstFix(isLocalTime: false))) + .Select(kvp => kvp.Value!) + .ToArray(); + + var contactsById = matched.ToDictionary(c => c.Id, c => c); + + var sanctions = await crmQueryDispatcher.ExecuteQuery( + new GetSanctionsByContactIdsQuery( + contactsById.Keys, + ActiveOnly: true, + new())); + + var previousNames = (await crmQueryDispatcher.ExecuteQuery(new GetPreviousNamesByContactIdsQuery(contactsById.Keys))) + .ToDictionary( + kvp => kvp.Key, + kvp => previousNameHelper.GetFullPreviousNames(kvp.Value, contactsById[kvp.Key])); + + return new FindPersonsByTrnAndDateOfBirthResult( + Total: matched.Length, + Items: matched.Select(r => new FindPersonsByTrnAndDateOfBirthResultItem() + { + Trn = r.dfeta_TRN, + DateOfBirth = r.BirthDate!.Value.ToDateOnlyWithDqtBstFix(isLocalTime: false), + FirstName = r.ResolveFirstName(), + MiddleName = r.ResolveMiddleName(), + LastName = r.ResolveLastName(), + Sanctions = sanctions[r.Id] + .Where(s => Constants.ExposableSanctionCodes.Contains(s.SanctionCode)) + .Select(s => new SanctionInfo() + { + Code = s.SanctionCode, + StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true) + }) + .AsReadOnly(), + PreviousNames = previousNames[r.Id] + .Select(name => new NameInfo() + { + FirstName = name.FirstName, + MiddleName = name.MiddleName, + LastName = name.LastName + }) + .AsReadOnly() + }) + .OrderBy(c => c.Trn) + .AsReadOnly()); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetPerson.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetPerson.cs index 04099f3387..e77c3deabc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetPerson.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/GetPerson.cs @@ -161,12 +161,10 @@ public class GetPersonHandler( ICrmQueryDispatcher crmQueryDispatcher, ReferenceDataCache referenceDataCache, IDataverseAdapter dataverseAdapter, - IConfiguration configuration) + PreviousNameHelper previousNameHelper) { public async Task Handle(GetPersonCommand command) { - var concurrentNameChangeWindow = TimeSpan.FromSeconds(configuration.GetValue("ConcurrentNameChangeWindowSeconds", 5)); - var contactDetail = await crmQueryDispatcher.ExecuteQuery( new GetActiveContactDetailByTrnQuery( command.Trn, @@ -330,7 +328,7 @@ async Task GetSanctions() GetSanctions() : null; - IEnumerable? previousNames = PreviousNameHelper.GetFullPreviousNames(contactDetail.PreviousNames, contactDetail.Contact, concurrentNameChangeWindow) + IEnumerable? previousNames = previousNameHelper.GetFullPreviousNames(contactDetail.PreviousNames, contactDetail.Contact) .Select(name => new NameInfo() { FirstName = name.FirstName, diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs index 50794297fd..f7b3cf5938 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240101/Responses/FindTeachersResponse.cs @@ -4,7 +4,6 @@ namespace TeachingRecordSystem.Api.V3.V20240101.Responses; -[AutoMap(typeof(FindPersonByLastNameAndDateOfBirthResult))] public record FindTeachersResponse { public required int Total { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs index 314c567ee5..0e0e53d2f3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240606/Responses/FindPersonResponse.cs @@ -4,7 +4,6 @@ namespace TeachingRecordSystem.Api.V3.V20240606.Responses; -[AutoMap(typeof(FindPersonByLastNameAndDateOfBirthResult))] public record FindPersonResponse { public required int Total { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs new file mode 100644 index 0000000000..5e91ca9930 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs @@ -0,0 +1,56 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; +using TeachingRecordSystem.Api.Infrastructure.Security; +using TeachingRecordSystem.Api.V3.Core.Operations; +using TeachingRecordSystem.Api.V3.V20240814.Requests; +using TeachingRecordSystem.Api.V3.V20240814.Responses; + +namespace TeachingRecordSystem.Api.V3.V20240814.Controllers; + +[Route("persons")] +public class PersonsController(IMapper mapper) : ControllerBase +{ + [HttpPost("find")] + [SwaggerOperation( + OperationId = "FindPersons", + Summary = "Find persons", + Description = "Finds persons matching the specified criteria.")] + [ProducesResponseType(typeof(FindPersonsResponse), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [Authorize(Policy = AuthorizationPolicies.GetPerson)] + public async Task FindTeachers( + [FromBody] FindPersonsRequest request, + [FromServices] FindPersonsByTrnAndDateOfBirthHandler handler) + { + var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); + var result = await handler.Handle(command); + var response = mapper.Map(result); + return Ok(response); + } + + [HttpGet("")] + [SwaggerOperation( + OperationId = "FindPerson", + Summary = "Find person", + Description = "Finds a person matching the specified criteria.")] + [ProducesResponseType(typeof(FindPersonResponse), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [Authorize(Policy = AuthorizationPolicies.GetPerson)] + public async Task FindTeachers( + FindPersonRequest request, + [FromServices] FindPersonByLastNameAndDateOfBirthHandler handler) + { + var command = new FindPersonByLastNameAndDateOfBirthCommand(request.LastName!, request.DateOfBirth!.Value); + var result = await handler.Handle(command); + + var response = new FindPersonResponse() + { + Total = result.Total, + Query = request, + Results = result.Items.Select(mapper.Map).AsReadOnly() + }; + + return Ok(response); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonRequest.cs new file mode 100644 index 0000000000..52a2a5f921 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonRequest.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Mvc; + +namespace TeachingRecordSystem.Api.V3.V20240814.Requests; + +public record FindPersonRequest +{ + [FromQuery(Name = "findBy")] + public FindPersonFindBy FindBy { get; init; } + [FromQuery(Name = "lastName")] + public string? LastName { get; init; } + [FromQuery(Name = "dateOfBirth")] + public DateOnly? DateOfBirth { get; init; } +} + +public enum FindPersonFindBy +{ + LastNameAndDateOfBirth = 1 +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonsRequest.cs similarity index 82% rename from TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs rename to TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonsRequest.cs index cbc1940d8d..cf723103dc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Requests/FindPersonsRequest.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonsRequest.cs @@ -1,4 +1,4 @@ -namespace TeachingRecordSystem.Api.V3.VNext.Requests; +namespace TeachingRecordSystem.Api.V3.V20240814.Requests; public record FindPersonsRequest { diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs new file mode 100644 index 0000000000..ee1c272fed --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs @@ -0,0 +1,24 @@ +using TeachingRecordSystem.Api.V3.Core.Operations; +using TeachingRecordSystem.Api.V3.V20240101.ApiModels; +using TeachingRecordSystem.Api.V3.V20240814.Requests; + +namespace TeachingRecordSystem.Api.V3.V20240814.Responses; + +public record FindPersonResponse +{ + public required int Total { get; init; } + public required FindPersonRequest Query { get; init; } + public required IReadOnlyCollection Results { get; init; } +} + +[AutoMap(typeof(FindPersonByLastNameAndDateOfBirthResultItem))] +public record FindPersonResponseResult +{ + public required string Trn { get; init; } + public required DateOnly DateOfBirth { get; init; } + public required string FirstName { get; init; } + public required string MiddleName { get; init; } + public required string LastName { get; init; } + public required IReadOnlyCollection Sanctions { get; init; } + public required IReadOnlyCollection PreviousNames { get; init; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs similarity index 66% rename from TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs rename to TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs index 397256252a..8a614f26cb 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Responses/FindPersonsResponse.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonsResponse.cs @@ -1,13 +1,18 @@ +using AutoMapper.Configuration.Annotations; +using TeachingRecordSystem.Api.V3.Core.Operations; using TeachingRecordSystem.Api.V3.V20240101.ApiModels; -namespace TeachingRecordSystem.Api.V3.VNext.Responses; +namespace TeachingRecordSystem.Api.V3.V20240814.Responses; +[AutoMap(typeof(FindPersonsByTrnAndDateOfBirthResult))] public record FindPersonsResponse { public required int Total { get; init; } + [SourceMember(nameof(FindPersonsByTrnAndDateOfBirthResult.Items))] public required IReadOnlyCollection Results { get; init; } } +[AutoMap(typeof(FindPersonsByTrnAndDateOfBirthResultItem))] public record FindPersonsResponseResult { public required string Trn { get; init; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs index 772ac9b409..144e53d0f3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/VNext/Controllers/PersonsController.cs @@ -5,7 +5,6 @@ using TeachingRecordSystem.Api.V3.Core.Operations; using TeachingRecordSystem.Api.V3.VNext.ApiModels; using TeachingRecordSystem.Api.V3.VNext.Requests; -using TeachingRecordSystem.Api.V3.VNext.Responses; namespace TeachingRecordSystem.Api.V3.VNext.Controllers; @@ -47,17 +46,4 @@ public async Task GetQtls( var response = mapper.Map(result); return response is not null ? Ok(response) : NotFound(); } - - [HttpPost("find")] - [SwaggerOperation( - OperationId = "FindPersons", - Summary = "Find persons", - Description = "Finds persons matching the specified criteria.")] - [ProducesResponseType(typeof(FindPersonsResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] - [Authorize(Policy = AuthorizationPolicies.GetPerson)] - public Task FindTeachers([FromBody] FindPersonsRequest request) - { - throw new NotImplementedException(); - } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Api/VersionRegistry.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Api/VersionRegistry.cs index 6d33d79592..1b109d544f 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Api/VersionRegistry.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Api/VersionRegistry.cs @@ -14,6 +14,7 @@ public static class VersionRegistry V3MinorVersions.V20240412, V3MinorVersions.V20240416, V3MinorVersions.V20240606, + V3MinorVersions.V20240814, V3MinorVersions.VNext, ]; @@ -54,6 +55,7 @@ public static class V3MinorVersions public const string V20240412 = "20240412"; public const string V20240416 = "20240416"; public const string V20240606 = "20240606"; + public const string V20240814 = "20240814"; public const string VNext = VNextVersion; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/PreviousNameHelper.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/PreviousNameHelper.cs index 53b1c4813c..a658dc89cc 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/PreviousNameHelper.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/PreviousNameHelper.cs @@ -1,13 +1,14 @@ -namespace TeachingRecordSystem.Core.Dqt.Models; +using Microsoft.Extensions.Configuration; using FullName = (string FirstName, string MiddleName, string LastName); -public static class PreviousNameHelper +namespace TeachingRecordSystem.Core.Dqt.Models; + +public class PreviousNameHelper(IConfiguration configuration) { - public static FullName[] GetFullPreviousNames( - IEnumerable previousNames, - Contact contact, - TimeSpan concurrentNameChangeWindow) + public FullName[] GetFullPreviousNames(IEnumerable previousNames, Contact contact) { + var concurrentNameChangeWindow = TimeSpan.FromSeconds(configuration.GetValue("ConcurrentNameChangeWindowSeconds", 5)); + var result = new List(); var currentFirstName = contact.FirstName!; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetActiveContactsByTrnsQuery.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetActiveContactsByTrnsQuery.cs new file mode 100644 index 0000000000..7595dc218f --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetActiveContactsByTrnsQuery.cs @@ -0,0 +1,6 @@ +using Microsoft.Xrm.Sdk.Query; + +namespace TeachingRecordSystem.Core.Dqt.Queries; + +public record GetActiveContactsByTrnsQuery(IEnumerable Trns, ColumnSet ColumnSet) : + ICrmQuery>; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetActiveContactsByTrnsHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetActiveContactsByTrnsHandler.cs new file mode 100644 index 0000000000..e04410de65 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetActiveContactsByTrnsHandler.cs @@ -0,0 +1,33 @@ +using AngleSharp.Common; +using Microsoft.PowerPlatform.Dataverse.Client; +using Microsoft.Xrm.Sdk.Query; +using TeachingRecordSystem.Core.Dqt.Queries; + +namespace TeachingRecordSystem.Core.Dqt.QueryHandlers; + +public class GetActiveContactsByTrnsHandler : + ICrmQueryHandler> +{ + public async Task> Execute( + GetActiveContactsByTrnsQuery query, + IOrganizationServiceAsync organizationService) + { + var queryExpression = new QueryExpression(Contact.EntityLogicalName) + { + ColumnSet = query.ColumnSet, + Criteria = new FilterExpression(LogicalOperator.And) + { + Conditions = + { + new ConditionExpression(Contact.Fields.StateCode, ConditionOperator.Equal, (int)ContactState.Active), + new ConditionExpression(Contact.Fields.dfeta_TRN, ConditionOperator.In, query.Trns.ToArray()) + } + } + }; + + var response = await organizationService.RetrieveMultipleAsync(queryExpression); + var contacts = response.Entities.Select(e => e.ToEntity()).ToDictionary(c => c.dfeta_TRN, c => c); + + return query.Trns.ToDictionary(trn => trn, trn => contacts.GetValueOrDefault(trn)); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/ServiceCollectionExtensions.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ServiceCollectionExtensions.cs index b9ad20dba0..a75288d5e3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/ServiceCollectionExtensions.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ServiceCollectionExtensions.cs @@ -11,7 +11,8 @@ public static IServiceCollection AddTrsBaseServices(this IServiceCollection serv { return services .AddSingleton() - .AddCrmQueries(); + .AddCrmQueries() + .AddSingleton(); } public static IServiceCollection AddAccessYourTeachingQualificationsOptions( diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Index.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Index.cshtml.cs index e4bac5b0f5..ac761c37ca 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Index.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Index.cshtml.cs @@ -8,10 +8,8 @@ namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail; public class IndexModel( ICrmQueryDispatcher crmQueryDispatcher, - IConfiguration configuration) : PageModel + PreviousNameHelper previousNameHelper) : PageModel { - private readonly TimeSpan _concurrentNameChangeWindow = TimeSpan.FromSeconds(configuration.GetValue("ConcurrentNameChangeWindowSeconds", 5)); - [FromRoute] public Guid PersonId { get; set; } @@ -48,7 +46,7 @@ public async Task OnGet() Contact.Fields.dfeta_ActiveSanctions))); var contact = contactDetail!.Contact; - var previousNames = PreviousNameHelper.GetFullPreviousNames(contactDetail.PreviousNames, contactDetail.Contact, _concurrentNameChangeWindow); + var previousNames = previousNameHelper.GetFullPreviousNames(contactDetail.PreviousNames, contactDetail.Contact); Person = new PersonInfo() {