Skip to content

Commit

Permalink
Allow HE quals with no link to dfeta_hequalification table
Browse files Browse the repository at this point in the history
Amended to only return HE quals with at least one subject + added tests

Removed commented out code
  • Loading branch information
hortha committed Mar 28, 2024
1 parent e7b893e commit fabb1ea
Show file tree
Hide file tree
Showing 20 changed files with 747 additions and 137 deletions.
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

0 comments on commit fabb1ea

Please sign in to comment.