Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow HE quals with no link to dfeta_hequalification table #1253

Merged
merged 1 commit into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,37 +128,15 @@ public class GetTeacherHandler(

if ((request.Include & (GetTeacherRequestIncludes.NpqQualifications | GetTeacherRequestIncludes.HigherEducationQualifications)) != 0)
{
string[]? columnNames = new[]
{
dfeta_qualification.Fields.dfeta_CompletionorAwardDate,
dfeta_qualification.Fields.dfeta_Type,
dfeta_qualification.Fields.StateCode
};

string[]? heQualificationColumnNames = null;
string[]? heSubjectColumnNames = null;

if (request.Include.HasFlag(GetTeacherRequestIncludes.HigherEducationQualifications))
{
heQualificationColumnNames = new[]
{
dfeta_hequalification.PrimaryIdAttribute,
dfeta_hequalification.Fields.dfeta_name
};

heSubjectColumnNames = new[]
{
dfeta_hesubject.PrimaryIdAttribute,
dfeta_hesubject.Fields.dfeta_name,
dfeta_hesubject.Fields.dfeta_Value
};
}

qualifications = await dataverseAdapter.GetQualificationsForTeacher(
teacher.Id,
columnNames,
heQualificationColumnNames,
heSubjectColumnNames);
qualifications = await crmQueryDispatcher.ExecuteQuery(
new GetQualificationsByContactIdQuery(
teacher.Id,
new ColumnSet(
dfeta_qualification.PrimaryIdAttribute,
dfeta_qualification.Fields.dfeta_CompletionorAwardDate,
dfeta_qualification.Fields.dfeta_Type,
dfeta_qualification.Fields.StateCode),
IncludeHigherEducationDetails: request.Include.HasFlag(GetTeacherRequestIncludes.HigherEducationQualifications)));
}

bool pendingNameChange = default, pendingDateOfBirthChange = default;
Expand Down Expand Up @@ -514,8 +492,7 @@ private static IReadOnlyCollection<GetTeacherResponseHigherEducationQualificatio
?.Where(q =>
q.dfeta_Type.HasValue &&
q.dfeta_Type.Value == dfeta_qualification_dfeta_Type.HigherEducation &&
q.StateCode == dfeta_qualificationState.Active &&
q.Extract<dfeta_hequalification>() is not null)
q.StateCode == dfeta_qualificationState.Active)
?.Select(q =>
{
var heQualification = q.Extract<dfeta_hequalification>();
Expand Down Expand Up @@ -555,7 +532,7 @@ private static IReadOnlyCollection<GetTeacherResponseHigherEducationQualificatio

return new GetTeacherResponseHigherEducationQualification
{
Name = heQualification.dfeta_name,
Name = heQualification?.dfeta_name,
Awarded = q.dfeta_CompletionorAwardDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true),
Subjects = heSubjects.ToArray()
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public record GetTeacherResponseMandatoryQualification

public record GetTeacherResponseHigherEducationQualification
{
public required string Name { get; init; }
public required string? Name { get; init; }
public required DateOnly? Awarded { get; init; }
public required IReadOnlyCollection<GetTeacherResponseHigherEducationQualificationSubject> Subjects { get; init; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5670,6 +5670,8 @@ public partial class dfeta_hesubject : Microsoft.Xrm.Sdk.Entity, System.Componen
/// </summary>
public static class Fields
{
public const string dfeta_hesubjectId = "dfeta_hesubjectid";
public const string Id = "dfeta_hesubjectid";
public const string dfeta_name = "dfeta_name";
public const string dfeta_Value = "dfeta_value";
public const string StateCode = "statecode";
Expand Down Expand Up @@ -5725,6 +5727,49 @@ private void OnPropertyChanging(string propertyName)
}
}

/// <summary>
/// Unique identifier for entity instances
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_hesubjectid")]
public System.Nullable<System.Guid> dfeta_hesubjectId
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<System.Guid>>("dfeta_hesubjectid");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("dfeta_hesubjectId");
this.SetAttributeValue("dfeta_hesubjectid", value);
if (value.HasValue)
{
base.Id = value.Value;
}
else
{
base.Id = System.Guid.Empty;
}
this.OnPropertyChanged("dfeta_hesubjectId");
}
}

[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_hesubjectid")]
public override System.Guid Id
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return base.Id;
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.dfeta_hesubjectId = value;
}
}

/// <summary>
/// The name of the custom entity.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TeachingRecordSystem.Core.Dqt.Queries;

public record GetAllHeQualificationsQuery : ICrmQuery<dfeta_hequalification[]>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace TeachingRecordSystem.Core.Dqt.Queries;

public record GetAllHeSubjectsQuery : ICrmQuery<dfeta_hesubject[]>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Microsoft.Xrm.Sdk.Query;

namespace TeachingRecordSystem.Core.Dqt.Queries;

public record GetQualificationsByContactIdQuery(Guid ContactId, ColumnSet ColumnSet, bool IncludeHigherEducationDetails = false) : ICrmQuery<dfeta_qualification[]>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using TeachingRecordSystem.Core.Dqt.Queries;

namespace TeachingRecordSystem.Core.Dqt.QueryHandlers;

public class GetAllHeQualificationsHandler : ICrmQueryHandler<GetAllHeQualificationsQuery, dfeta_hequalification[]>
{
public async Task<dfeta_hequalification[]> Execute(GetAllHeQualificationsQuery query, IOrganizationServiceAsync organizationService)
{
var queryExpression = new QueryExpression()
{
EntityName = dfeta_hequalification.EntityLogicalName,
ColumnSet = new ColumnSet(
dfeta_hequalification.Fields.dfeta_name,
dfeta_hequalification.Fields.dfeta_Value)
};

queryExpression.Criteria.AddCondition(dfeta_hequalification.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_hequalificationState.Active);

var request = new RetrieveMultipleRequest()
{
Query = queryExpression
};

var response = await organizationService.RetrieveMultipleAsync(queryExpression);

return response.Entities.Select(e => e.ToEntity<dfeta_hequalification>()).ToArray();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using TeachingRecordSystem.Core.Dqt.Queries;

namespace TeachingRecordSystem.Core.Dqt.QueryHandlers;

public class GetAllHeSubjectsHandler : ICrmQueryHandler<GetAllHeSubjectsQuery, dfeta_hesubject[]>
{
public async Task<dfeta_hesubject[]> Execute(GetAllHeSubjectsQuery query, IOrganizationServiceAsync organizationService)
{
var queryExpression = new QueryExpression()
{
EntityName = dfeta_hesubject.EntityLogicalName,
ColumnSet = new ColumnSet(
dfeta_hesubject.Fields.dfeta_name,
dfeta_hesubject.Fields.dfeta_Value)
};

queryExpression.Criteria.AddCondition(dfeta_hesubject.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_hesubjectState.Active);

var request = new RetrieveMultipleRequest()
{
Query = queryExpression
};

var response = await organizationService.RetrieveMultipleAsync(queryExpression);

return response.Entities.Select(e => e.ToEntity<dfeta_hesubject>()).ToArray();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk.Query;
using TeachingRecordSystem.Core.Dqt.Queries;

namespace TeachingRecordSystem.Core.Dqt.QueryHandlers;

public class GetQualificationsByContactIdHandler : ICrmQueryHandler<GetQualificationsByContactIdQuery, dfeta_qualification[]>
{
public async Task<dfeta_qualification[]> Execute(GetQualificationsByContactIdQuery query, IOrganizationServiceAsync organizationService)
{
var filter = new FilterExpression();
filter.AddCondition(dfeta_qualification.Fields.dfeta_PersonId, ConditionOperator.Equal, query.ContactId);
filter.AddCondition(dfeta_qualification.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_qualificationState.Active);

var qualificationTypeFilter = new FilterExpression(LogicalOperator.Or);
qualificationTypeFilter.AddCondition(dfeta_qualification.Fields.dfeta_Type, ConditionOperator.NotEqual, (int)dfeta_qualification_dfeta_Type.HigherEducation);

var heFilter = new FilterExpression(LogicalOperator.And);
heFilter.AddCondition(dfeta_qualification.Fields.dfeta_Type, ConditionOperator.Equal, (int)dfeta_qualification_dfeta_Type.HigherEducation);

var heSubjectFilter = new FilterExpression(LogicalOperator.Or);
heSubjectFilter.AddCondition(dfeta_qualification.Fields.dfeta_HE_HESubject1Id, ConditionOperator.NotNull);
heSubjectFilter.AddCondition(dfeta_qualification.Fields.dfeta_HE_HESubject2Id, ConditionOperator.NotNull);
heSubjectFilter.AddCondition(dfeta_qualification.Fields.dfeta_HE_HESubject3Id, ConditionOperator.NotNull);
heFilter.AddFilter(heSubjectFilter);

qualificationTypeFilter.AddFilter(heFilter);
filter.AddFilter(qualificationTypeFilter);

var queryExpression = new QueryExpression(dfeta_qualification.EntityLogicalName)
{
ColumnSet = query.ColumnSet,
Criteria = filter,
Orders =
{
new OrderExpression(dfeta_qualification.Fields.CreatedOn, OrderType.Ascending)
}
};

if (query.IncludeHigherEducationDetails)
{
var heLink = queryExpression.AddLink(
dfeta_hequalification.EntityLogicalName,
dfeta_qualification.Fields.dfeta_HE_HEQualificationId,
dfeta_hequalification.Fields.Id,
JoinOperator.LeftOuter);

heLink.Columns = new ColumnSet(
dfeta_hequalification.PrimaryIdAttribute,
dfeta_hequalification.Fields.dfeta_name);
heLink.EntityAlias = dfeta_hequalification.EntityLogicalName;

AddHeSubjectLink(queryExpression, dfeta_qualification.Fields.dfeta_HE_HESubject1Id, $"{dfeta_hesubject.EntityLogicalName}1");
AddHeSubjectLink(queryExpression, dfeta_qualification.Fields.dfeta_HE_HESubject2Id, $"{dfeta_hesubject.EntityLogicalName}2");
AddHeSubjectLink(queryExpression, dfeta_qualification.Fields.dfeta_HE_HESubject3Id, $"{dfeta_hesubject.EntityLogicalName}3");
}

var result = await organizationService.RetrieveMultipleAsync(queryExpression);

return result.Entities.Select(entity => entity.ToEntity<dfeta_qualification>()).ToArray();

void AddHeSubjectLink(QueryExpression query, string subjectIdField, string alias)
{
var heSubjectLink = query.AddLink(
dfeta_hesubject.EntityLogicalName,
subjectIdField,
dfeta_hesubject.PrimaryIdAttribute,
JoinOperator.LeftOuter);

heSubjectLink.Columns = new ColumnSet(
dfeta_hesubject.PrimaryIdAttribute,
dfeta_hesubject.Fields.dfeta_name,
dfeta_hesubject.Fields.dfeta_Value);
heSubjectLink.EntityAlias = alias;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class ReferenceDataCache : IStartupTask
private Task<dfeta_teacherstatus[]>? _getTeacherStatusesTask;
private Task<dfeta_earlyyearsstatus[]>? _getEarlyYearsStatusesTask;
private Task<dfeta_specialism[]>? _getSpecialismsTask;
private Task<dfeta_hequalification[]>? _getHeQualificationsTask;
private Task<dfeta_hesubject[]>? _getHeSubjectsTask;

public ReferenceDataCache(ICrmQueryDispatcher crmQueryDispatcher)
{
Expand Down Expand Up @@ -104,6 +106,32 @@ public async Task<dfeta_mqestablishment> GetMqEstablishmentById(Guid mqEstablish
return mqEstablishments.Single(s => s.dfeta_mqestablishmentId == mqEstablishmentId, $"Could not find MQ establishment with ID: '{mqEstablishmentId}'.");
}

public async Task<dfeta_hequalification[]> GetHeQualifications()
{
var heQualifications = await EnsureHeQualifications();
return heQualifications.ToArray();
}

public async Task<dfeta_hequalification> GetHeQualificationByValue(string value)
{
var heQualifications = await EnsureHeQualifications();
// build environment has some duplicate HE Qualifications, which prevent us using Single() here
return heQualifications.First(s => s.dfeta_Value == value, $"Could not find HE qualification with value: '{value}'.");
}

public async Task<dfeta_hesubject[]> GetHeSubjects()
{
var heSubjects = await EnsureHeSubjects();
return heSubjects.ToArray();
}

public async Task<dfeta_hesubject> GetHeSubjectByValue(string value)
{
var heSubjects = await EnsureHeSubjects();
// build environment has some duplicate HE Subjects, which prevent us using Single() here
return heSubjects.First(s => s.dfeta_Value == value, $"Could not find HE subject with value: '{value}'.");
}

private Task<dfeta_sanctioncode[]> EnsureSanctionCodes() =>
LazyInitializer.EnsureInitialized(
ref _getSanctionCodesTask,
Expand Down Expand Up @@ -134,6 +162,16 @@ private Task<dfeta_mqestablishment[]> EnsureMqEstablishments() =>
ref _mqEstablishmentsTask,
() => _crmQueryDispatcher.ExecuteQuery(new GetAllMqEstablishmentsQuery()));

private Task<dfeta_hequalification[]> EnsureHeQualifications() =>
LazyInitializer.EnsureInitialized(
ref _getHeQualificationsTask,
() => _crmQueryDispatcher.ExecuteQuery(new GetAllHeQualificationsQuery()));

private Task<dfeta_hesubject[]> EnsureHeSubjects() =>
LazyInitializer.EnsureInitialized(
ref _getHeSubjectsTask,
() => _crmQueryDispatcher.ExecuteQuery(new GetAllHeSubjectsQuery()));

async Task IStartupTask.Execute()
{
await EnsureSanctionCodes();
Expand All @@ -142,5 +180,7 @@ async Task IStartupTask.Execute()
await EnsureEarlyYearsStatuses();
await EnsureSpecialisms();
await EnsureMqEstablishments();
await EnsureHeQualifications();
await EnsureHeSubjects();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,17 @@ public async Task Get_ValidRequestWithInitialTeacherTraining_ReturnsExpectedInit
[Fact]
public async Task Get_ValidRequestWithNpqQualifications_ReturnsExpectedNpqQualificationsContent()
{
var contact = await CreateContact();
var qualifications = new[]
{
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.NPQLL, null, IsActive:true),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.NPQSL, new DateOnly(2022, 5, 6), IsActive:false),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.NPQEYL, new DateOnly(2022, 3, 4), IsActive:true)
};

var contact = await CreateContact(qualifications: qualifications);
var baseUrl = $"/v3/teachers/{contact.dfeta_TRN}";

await ValidRequestWithNpqQualifications_ReturnsExpectedNpqQualificationsContent(GetHttpClientWithApiKey(), baseUrl, contact, expectCertificateUrls: false);
await ValidRequestWithNpqQualifications_ReturnsExpectedNpqQualificationsContent(GetHttpClientWithApiKey(), baseUrl, contact, qualifications, expectCertificateUrls: false);
}

[Fact]
Expand Down Expand Up @@ -158,10 +165,20 @@ public async Task Get_ValidRequestWithMandatoryQualifications_ReturnsExpectedMan
[Fact]
public async Task Get_ValidRequestWithHigherEducationQualifications_ReturnsExpectedHigherEducationQualificationsContent()
{
var contact = await CreateContact();
var qualifications = new[]
{
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.HigherEducation, new DateOnly(2022, 4, 6), true, "001", "001", "002", "003"),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.HigherEducation, new DateOnly(2022, 4, 2), true, "002", "002"),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.HigherEducation, null, true, "001", "003"),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.HigherEducation, new DateOnly(2022, 4, 8), false, "001", "001", "002", "003"),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.HigherEducation, null, true, null, "003"),
new Qualification(Guid.NewGuid(), dfeta_qualification_dfeta_Type.HigherEducation, new DateOnly(2022, 4, 8), true),
};

var contact = await CreateContact(qualifications: qualifications);
var baseUrl = $"/v3/teachers/{contact.dfeta_TRN}";

await ValidRequestWithHigherEducationQualifications_ReturnsExpectedHigherEducationQualificationsContent(GetHttpClientWithApiKey(), baseUrl, contact);
await ValidRequestWithHigherEducationQualifications_ReturnsExpectedHigherEducationQualificationsContent(GetHttpClientWithApiKey(), baseUrl, contact, qualifications);
}

[Fact]
Expand Down
Loading
Loading