diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedCode.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedCode.cs index 3f73c6b14..50115bbb0 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedCode.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedCode.cs @@ -7070,6 +7070,308 @@ public TeachingRecordSystem.Core.Dqt.Models.SystemUser lk_dfeta_ittsubject_modif } } + [System.Runtime.Serialization.DataContractAttribute()] + public enum dfeta_mqestablishmentState + { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Active = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Inactive = 1, + } + + /// + /// + /// + [System.Runtime.Serialization.DataContractAttribute()] + [Microsoft.Xrm.Sdk.Client.EntityLogicalNameAttribute("dfeta_mqestablishment")] + public partial class dfeta_mqestablishment : Microsoft.Xrm.Sdk.Entity, System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged + { + + /// + /// Available fields, a the time of codegen, for the dfeta_mqestablishment entity + /// + public static class Fields + { + public const string dfeta_mqestablishmentId = "dfeta_mqestablishmentid"; + public const string Id = "dfeta_mqestablishmentid"; + public const string dfeta_name = "dfeta_name"; + public const string dfeta_Value = "dfeta_value"; + public const string StateCode = "statecode"; + public const string dfeta_dfeta_mqestablishment_dfeta_qualification = "dfeta_dfeta_mqestablishment_dfeta_qualification"; + public const string lk_dfeta_mqestablishment_createdby = "lk_dfeta_mqestablishment_createdby"; + public const string lk_dfeta_mqestablishment_createdonbehalfby = "lk_dfeta_mqestablishment_createdonbehalfby"; + public const string lk_dfeta_mqestablishment_modifiedby = "lk_dfeta_mqestablishment_modifiedby"; + public const string lk_dfeta_mqestablishment_modifiedonbehalfby = "lk_dfeta_mqestablishment_modifiedonbehalfby"; + } + + /// + /// Default Constructor. + /// + [System.Diagnostics.DebuggerNonUserCode()] + public dfeta_mqestablishment() : + base(EntityLogicalName) + { + } + + public const string EntitySchemaName = "dfeta_mqestablishment"; + + public const string PrimaryIdAttribute = "dfeta_mqestablishmentid"; + + public const string PrimaryNameAttribute = "dfeta_name"; + + public const string EntityLogicalName = "dfeta_mqestablishment"; + + public const string EntityLogicalCollectionName = "dfeta_mqestablishments"; + + public const string EntitySetName = "dfeta_mqestablishments"; + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + public event System.ComponentModel.PropertyChangingEventHandler PropertyChanging; + + [System.Diagnostics.DebuggerNonUserCode()] + private void OnPropertyChanged(string propertyName) + { + if ((this.PropertyChanged != null)) + { + this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + + [System.Diagnostics.DebuggerNonUserCode()] + private void OnPropertyChanging(string propertyName) + { + if ((this.PropertyChanging != null)) + { + this.PropertyChanging(this, new System.ComponentModel.PropertyChangingEventArgs(propertyName)); + } + } + + /// + /// Unique identifier for entity instances + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_mqestablishmentid")] + public System.Nullable dfeta_mqestablishmentId + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue>("dfeta_mqestablishmentid"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_mqestablishmentId"); + this.SetAttributeValue("dfeta_mqestablishmentid", value); + if (value.HasValue) + { + base.Id = value.Value; + } + else + { + base.Id = System.Guid.Empty; + } + this.OnPropertyChanged("dfeta_mqestablishmentId"); + } + } + + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_mqestablishmentid")] + public override System.Guid Id + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return base.Id; + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.dfeta_mqestablishmentId = value; + } + } + + /// + /// The name of the custom entity. + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_name")] + public string dfeta_name + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue("dfeta_name"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_name"); + this.SetAttributeValue("dfeta_name", value); + this.OnPropertyChanged("dfeta_name"); + } + } + + /// + /// + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_value")] + public string dfeta_Value + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue("dfeta_value"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_Value"); + this.SetAttributeValue("dfeta_value", value); + this.OnPropertyChanged("dfeta_Value"); + } + } + + /// + /// Status of the MQ Establishment + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("statecode")] + public System.Nullable StateCode + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + Microsoft.Xrm.Sdk.OptionSetValue optionSet = this.GetAttributeValue("statecode"); + if ((optionSet != null)) + { + return ((TeachingRecordSystem.Core.Dqt.Models.dfeta_mqestablishmentState)(System.Enum.ToObject(typeof(TeachingRecordSystem.Core.Dqt.Models.dfeta_mqestablishmentState), optionSet.Value))); + } + else + { + return null; + } + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("StateCode"); + if ((value == null)) + { + this.SetAttributeValue("statecode", null); + } + else + { + this.SetAttributeValue("statecode", new Microsoft.Xrm.Sdk.OptionSetValue(((int)(value)))); + } + this.OnPropertyChanged("StateCode"); + } + } + + /// + /// 1:N dfeta_dfeta_mqestablishment_dfeta_qualification + /// + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("dfeta_dfeta_mqestablishment_dfeta_qualification")] + public System.Collections.Generic.IEnumerable dfeta_dfeta_mqestablishment_dfeta_qualification + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntities("dfeta_dfeta_mqestablishment_dfeta_qualification", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_dfeta_mqestablishment_dfeta_qualification"); + this.SetRelatedEntities("dfeta_dfeta_mqestablishment_dfeta_qualification", null, value); + this.OnPropertyChanged("dfeta_dfeta_mqestablishment_dfeta_qualification"); + } + } + + /// + /// N:1 lk_dfeta_mqestablishment_createdby + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("createdby")] + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_createdby")] + public TeachingRecordSystem.Core.Dqt.Models.SystemUser lk_dfeta_mqestablishment_createdby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntity("lk_dfeta_mqestablishment_createdby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_createdby"); + this.SetRelatedEntity("lk_dfeta_mqestablishment_createdby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_createdby"); + } + } + + /// + /// N:1 lk_dfeta_mqestablishment_createdonbehalfby + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("createdonbehalfby")] + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_createdonbehalfby")] + public TeachingRecordSystem.Core.Dqt.Models.SystemUser lk_dfeta_mqestablishment_createdonbehalfby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntity("lk_dfeta_mqestablishment_createdonbehalfby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_createdonbehalfby"); + this.SetRelatedEntity("lk_dfeta_mqestablishment_createdonbehalfby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_createdonbehalfby"); + } + } + + /// + /// N:1 lk_dfeta_mqestablishment_modifiedby + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("modifiedby")] + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_modifiedby")] + public TeachingRecordSystem.Core.Dqt.Models.SystemUser lk_dfeta_mqestablishment_modifiedby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntity("lk_dfeta_mqestablishment_modifiedby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_modifiedby"); + this.SetRelatedEntity("lk_dfeta_mqestablishment_modifiedby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_modifiedby"); + } + } + + /// + /// N:1 lk_dfeta_mqestablishment_modifiedonbehalfby + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("modifiedonbehalfby")] + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_modifiedonbehalfby")] + public TeachingRecordSystem.Core.Dqt.Models.SystemUser lk_dfeta_mqestablishment_modifiedonbehalfby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntity("lk_dfeta_mqestablishment_modifiedonbehalfby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_modifiedonbehalfby"); + this.SetRelatedEntity("lk_dfeta_mqestablishment_modifiedonbehalfby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_modifiedonbehalfby"); + } + } + } + [System.Runtime.Serialization.DataContractAttribute()] public enum dfeta_previousnameState { @@ -7988,7 +8290,11 @@ public static class Fields public const string dfeta_HE_HESubject2Id = "dfeta_he_hesubject2id"; public const string dfeta_HE_HESubject3Id = "dfeta_he_hesubject3id"; public const string dfeta_MQ_Date = "dfeta_mq_date"; + public const string dfeta_MQ_MQEstablishmentId = "dfeta_mq_mqestablishmentid"; public const string dfeta_MQ_SpecialismId = "dfeta_mq_specialismid"; + public const string dfeta_MQ_Status = "dfeta_mq_status"; + public const string dfeta_MQStartDate = "dfeta_mqstartdate"; + public const string dfeta_name = "dfeta_name"; public const string dfeta_NPQEL_Awarded = "dfeta_npqel_awarded"; public const string dfeta_NPQEL_Date = "dfeta_npqel_date"; public const string dfeta_npqeyl_awarded = "dfeta_npqeyl_awarded"; @@ -8008,6 +8314,7 @@ public static class Fields public const string dfeta_npqsl_awarded = "dfeta_npqsl_awarded"; public const string dfeta_npqsl_date = "dfeta_npqsl_date"; public const string dfeta_PersonId = "dfeta_personid"; + public const string dfeta_TrsDeletedEvent = "dfeta_trsdeletedevent"; public const string dfeta_Type = "dfeta_type"; public const string StateCode = "statecode"; public const string dfeta_account_dfeta_qualification_he = "dfeta_account_dfeta_qualification_he"; @@ -8017,6 +8324,7 @@ public static class Fields public const string dfeta_dfeta_hesubject_dfeta_qualification1 = "dfeta_dfeta_hesubject_dfeta_qualification1"; public const string dfeta_dfeta_hesubject_dfeta_qualification2 = "dfeta_dfeta_hesubject_dfeta_qualification2"; public const string dfeta_dfeta_hesubject_dfeta_qualification3 = "dfeta_dfeta_hesubject_dfeta_qualification3"; + public const string dfeta_dfeta_mqestablishment_dfeta_qualification = "dfeta_dfeta_mqestablishment_dfeta_qualification"; public const string dfeta_dfeta_specialism_dfeta_qualification_mq = "dfeta_dfeta_specialism_dfeta_qualification_mq"; public const string lk_dfeta_qualification_createdby = "lk_dfeta_qualification_createdby"; public const string lk_dfeta_qualification_createdonbehalfby = "lk_dfeta_qualification_createdonbehalfby"; @@ -8308,6 +8616,26 @@ public System.Nullable dfeta_MQ_Date } } + /// + /// Unique identifier for MQ Establishment associated with Qualification. + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_mq_mqestablishmentid")] + public Microsoft.Xrm.Sdk.EntityReference dfeta_MQ_MQEstablishmentId + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue("dfeta_mq_mqestablishmentid"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_MQ_MQEstablishmentId"); + this.SetAttributeValue("dfeta_mq_mqestablishmentid", value); + this.OnPropertyChanged("dfeta_MQ_MQEstablishmentId"); + } + } + /// /// Unique identifier for Specialism associated with Qualification. /// @@ -8328,6 +8656,66 @@ public Microsoft.Xrm.Sdk.EntityReference dfeta_MQ_SpecialismId } } + /// + /// + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_mq_status")] + public virtual dfeta_qualification_dfeta_MQ_Status? dfeta_MQ_Status + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return ((dfeta_qualification_dfeta_MQ_Status?)(EntityOptionSetEnum.GetEnum(this, "dfeta_mq_status"))); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_MQ_Status"); + this.SetAttributeValue("dfeta_mq_status", value.HasValue ? new Microsoft.Xrm.Sdk.OptionSetValue((int)value) : null); + this.OnPropertyChanged("dfeta_MQ_Status"); + } + } + + /// + /// + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_mqstartdate")] + public System.Nullable dfeta_MQStartDate + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue>("dfeta_mqstartdate"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_MQStartDate"); + this.SetAttributeValue("dfeta_mqstartdate", value); + this.OnPropertyChanged("dfeta_MQStartDate"); + } + } + + /// + /// The name of the custom entity. + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_name")] + public string dfeta_name + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue("dfeta_name"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_name"); + this.SetAttributeValue("dfeta_name", value); + this.OnPropertyChanged("dfeta_name"); + } + } + /// /// /// @@ -8708,6 +9096,26 @@ public Microsoft.Xrm.Sdk.EntityReference dfeta_PersonId } } + /// + /// + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_trsdeletedevent")] + public string dfeta_TrsDeletedEvent + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue("dfeta_trsdeletedevent"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_TrsDeletedEvent"); + this.SetAttributeValue("dfeta_trsdeletedevent", value); + this.OnPropertyChanged("dfeta_TrsDeletedEvent"); + } + } + /// /// /// @@ -8910,6 +9318,27 @@ public TeachingRecordSystem.Core.Dqt.Models.dfeta_hesubject dfeta_dfeta_hesubjec } } + /// + /// N:1 dfeta_dfeta_mqestablishment_dfeta_qualification + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_mq_mqestablishmentid")] + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("dfeta_dfeta_mqestablishment_dfeta_qualification")] + public TeachingRecordSystem.Core.Dqt.Models.dfeta_mqestablishment dfeta_dfeta_mqestablishment_dfeta_qualification + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntity("dfeta_dfeta_mqestablishment_dfeta_qualification", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_dfeta_mqestablishment_dfeta_qualification"); + this.SetRelatedEntity("dfeta_dfeta_mqestablishment_dfeta_qualification", null, value); + this.OnPropertyChanged("dfeta_dfeta_mqestablishment_dfeta_qualification"); + } + } + /// /// N:1 dfeta_dfeta_specialism_dfeta_qualification_mq /// @@ -9858,6 +10287,8 @@ public partial class dfeta_specialism : Microsoft.Xrm.Sdk.Entity, System.Compone public static class Fields { public const string dfeta_name = "dfeta_name"; + public const string dfeta_specialismId = "dfeta_specialismid"; + public const string Id = "dfeta_specialismid"; public const string dfeta_Value = "dfeta_value"; public const string StateCode = "statecode"; public const string dfeta_dfeta_specialism_dfeta_qualification_mq = "dfeta_dfeta_specialism_dfeta_qualification_mq"; @@ -9930,6 +10361,49 @@ public string dfeta_name } } + /// + /// Unique identifier for entity instances + /// + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_specialismid")] + public System.Nullable dfeta_specialismId + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetAttributeValue>("dfeta_specialismid"); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("dfeta_specialismId"); + this.SetAttributeValue("dfeta_specialismid", value); + if (value.HasValue) + { + base.Id = value.Value; + } + else + { + base.Id = System.Guid.Empty; + } + this.OnPropertyChanged("dfeta_specialismId"); + } + } + + [Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_specialismid")] + public override System.Guid Id + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return base.Id; + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.dfeta_specialismId = value; + } + } + /// /// /// @@ -16991,6 +17465,10 @@ public static class Fields public const string lk_dfeta_ittsubject_createdonbehalfby = "lk_dfeta_ittsubject_createdonbehalfby"; public const string lk_dfeta_ittsubject_modifiedby = "lk_dfeta_ittsubject_modifiedby"; public const string lk_dfeta_ittsubject_modifiedonbehalfby = "lk_dfeta_ittsubject_modifiedonbehalfby"; + public const string lk_dfeta_mqestablishment_createdby = "lk_dfeta_mqestablishment_createdby"; + public const string lk_dfeta_mqestablishment_createdonbehalfby = "lk_dfeta_mqestablishment_createdonbehalfby"; + public const string lk_dfeta_mqestablishment_modifiedby = "lk_dfeta_mqestablishment_modifiedby"; + public const string lk_dfeta_mqestablishment_modifiedonbehalfby = "lk_dfeta_mqestablishment_modifiedonbehalfby"; public const string lk_dfeta_previousname_createdby = "lk_dfeta_previousname_createdby"; public const string lk_dfeta_previousname_createdonbehalfby = "lk_dfeta_previousname_createdonbehalfby"; public const string lk_dfeta_previousname_modifiedby = "lk_dfeta_previousname_modifiedby"; @@ -18548,6 +19026,86 @@ public System.Collections.Generic.IEnumerable + /// 1:N lk_dfeta_mqestablishment_createdby + /// + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_createdby")] + public System.Collections.Generic.IEnumerable lk_dfeta_mqestablishment_createdby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntities("lk_dfeta_mqestablishment_createdby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_createdby"); + this.SetRelatedEntities("lk_dfeta_mqestablishment_createdby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_createdby"); + } + } + + /// + /// 1:N lk_dfeta_mqestablishment_createdonbehalfby + /// + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_createdonbehalfby")] + public System.Collections.Generic.IEnumerable lk_dfeta_mqestablishment_createdonbehalfby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntities("lk_dfeta_mqestablishment_createdonbehalfby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_createdonbehalfby"); + this.SetRelatedEntities("lk_dfeta_mqestablishment_createdonbehalfby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_createdonbehalfby"); + } + } + + /// + /// 1:N lk_dfeta_mqestablishment_modifiedby + /// + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_modifiedby")] + public System.Collections.Generic.IEnumerable lk_dfeta_mqestablishment_modifiedby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntities("lk_dfeta_mqestablishment_modifiedby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_modifiedby"); + this.SetRelatedEntities("lk_dfeta_mqestablishment_modifiedby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_modifiedby"); + } + } + + /// + /// 1:N lk_dfeta_mqestablishment_modifiedonbehalfby + /// + [Microsoft.Xrm.Sdk.RelationshipSchemaNameAttribute("lk_dfeta_mqestablishment_modifiedonbehalfby")] + public System.Collections.Generic.IEnumerable lk_dfeta_mqestablishment_modifiedonbehalfby + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.GetRelatedEntities("lk_dfeta_mqestablishment_modifiedonbehalfby", null); + } + [System.Diagnostics.DebuggerNonUserCode()] + set + { + this.OnPropertyChanging("lk_dfeta_mqestablishment_modifiedonbehalfby"); + this.SetRelatedEntities("lk_dfeta_mqestablishment_modifiedonbehalfby", null, value); + this.OnPropertyChanged("lk_dfeta_mqestablishment_modifiedonbehalfby"); + } + } + /// /// 1:N lk_dfeta_previousname_createdby /// @@ -21040,6 +21598,18 @@ public System.Linq.IQueryable + /// Gets a binding to the set of all entities. + /// + public System.Linq.IQueryable dfeta_mqestablishmentSet + { + [System.Diagnostics.DebuggerNonUserCode()] + get + { + return this.CreateQuery(); + } + } + /// /// Gets a binding to the set of all entities. /// diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedOptionSets.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedOptionSets.cs index 4dbb4e3be..08af966c1 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedOptionSets.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/GeneratedOptionSets.cs @@ -1798,6 +1798,19 @@ public enum dfeta_ittsubject_StatusCode Inactive = 2, } + [System.Runtime.Serialization.DataContractAttribute()] + public enum dfeta_mqestablishment_StatusCode + { + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Active", 0)] + Active = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Inactive", 1)] + Inactive = 2, + } + [System.Runtime.Serialization.DataContractAttribute()] public enum dfeta_MRApplicationDocumentType { @@ -1980,6 +1993,35 @@ public enum dfeta_qualification_dfeta_HLTA_ModerationOutcome TBD = 389040000, } + [System.Runtime.Serialization.DataContractAttribute()] + public enum dfeta_qualification_dfeta_MQ_Status + { + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Deferred", 1)] + Deferred = 389040001, + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Extended", 2)] + Extended = 389040002, + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Failed", 3)] + Failed = 389040003, + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("In Progress", 0)] + InProgress = 389040000, + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Passed", 4)] + Passed = 389040004, + + [System.Runtime.Serialization.EnumMemberAttribute()] + [OptionSetMetadataAttribute("Withdrawn", 5)] + Withdrawn = 389040005, + } + [System.Runtime.Serialization.DataContractAttribute()] public enum dfeta_qualification_dfeta_Type { diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateMandatoryQualificationQuery.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateMandatoryQualificationQuery.cs new file mode 100644 index 000000000..bf5194275 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/CreateMandatoryQualificationQuery.cs @@ -0,0 +1,11 @@ +namespace TeachingRecordSystem.Core.Dqt.Queries; + +public record CreateMandatoryQualificationQuery : ICrmQuery +{ + public required Guid ContactId { get; init; } + public required Guid MqEstablishmentId { get; init; } + public required Guid SpecialismId { get; init; } + public required DateOnly StartDate { get; init; } + public required dfeta_qualification_dfeta_MQ_Status Result { get; init; } + public required DateOnly? EndDate { get; init; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetAllMqEstablishmentsQuery.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetAllMqEstablishmentsQuery.cs new file mode 100644 index 000000000..a713a3ee5 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetAllMqEstablishmentsQuery.cs @@ -0,0 +1,3 @@ +namespace TeachingRecordSystem.Core.Dqt.Queries; + +public record GetAllMqEstablishmentsQuery : ICrmQuery; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetAllSpecialismsQuery.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetAllSpecialismsQuery.cs new file mode 100644 index 000000000..182767e25 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetAllSpecialismsQuery.cs @@ -0,0 +1,3 @@ +namespace TeachingRecordSystem.Core.Dqt.Queries; + +public record GetAllSpecialismsQuery : ICrmQuery; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateMandatoryQualificationHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateMandatoryQualificationHandler.cs new file mode 100644 index 000000000..63beb26c7 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/CreateMandatoryQualificationHandler.cs @@ -0,0 +1,26 @@ +using Microsoft.PowerPlatform.Dataverse.Client; +using TeachingRecordSystem.Core.Dqt.Queries; + +namespace TeachingRecordSystem.Core.Dqt.QueryHandlers; + +public class CreateMandatoryQualificationHandler : ICrmQueryHandler +{ + public async Task Execute(CreateMandatoryQualificationQuery query, IOrganizationServiceAsync organizationService) + { + var qualification = new dfeta_qualification() + { + Id = Guid.NewGuid(), + dfeta_Type = dfeta_qualification_dfeta_Type.MandatoryQualification, + dfeta_name = "Mandatory Qualification", + dfeta_PersonId = query.ContactId.ToEntityReference(Contact.EntityLogicalName), + dfeta_MQ_MQEstablishmentId = query.MqEstablishmentId.ToEntityReference(dfeta_mqestablishment.EntityLogicalName), + dfeta_MQ_SpecialismId = query.SpecialismId.ToEntityReference(dfeta_specialism.EntityLogicalName), + dfeta_MQStartDate = query.StartDate.FromDateOnlyWithDqtBstFix(isLocalTime: true), + dfeta_MQ_Status = query.Result, + dfeta_MQ_Date = query.EndDate?.FromDateOnlyWithDqtBstFix(isLocalTime: true), + }; + + var qualificationId = await organizationService.CreateAsync(qualification); + return qualificationId; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetAllMqEstablishmentsHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetAllMqEstablishmentsHandler.cs new file mode 100644 index 000000000..27a972a8a --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetAllMqEstablishmentsHandler.cs @@ -0,0 +1,33 @@ +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 GetAllMqEstablishmentsHandler : ICrmQueryHandler +{ + public async Task Execute(GetAllMqEstablishmentsQuery query, IOrganizationServiceAsync organizationService) + { + var filter = new FilterExpression(LogicalOperator.And); + filter.AddCondition(dfeta_mqestablishment.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_mqestablishmentState.Active); + + var queryExpression = new QueryExpression + { + EntityName = dfeta_mqestablishment.EntityLogicalName, + ColumnSet = new ColumnSet( + dfeta_mqestablishment.PrimaryIdAttribute, + dfeta_mqestablishment.Fields.dfeta_name, + dfeta_mqestablishment.Fields.dfeta_Value), + Criteria = filter, + }; + + var request = new RetrieveMultipleRequest + { + Query = queryExpression + }; + + var response = await organizationService.RetrieveMultipleAsync(queryExpression); + return response.Entities.Select(x => x.ToEntity()).ToArray(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetAllSpecialismsHandler.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetAllSpecialismsHandler.cs new file mode 100644 index 000000000..c9ed59dea --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetAllSpecialismsHandler.cs @@ -0,0 +1,34 @@ +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 GetAllSpecialismsHandler : ICrmQueryHandler +{ + public async Task Execute(GetAllSpecialismsQuery query, IOrganizationServiceAsync organizationService) + { + var filter = new FilterExpression(LogicalOperator.And); + filter.AddCondition(dfeta_specialism.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_specialismState.Active); + filter.AddCondition(dfeta_specialism.Fields.dfeta_Value, ConditionOperator.In, "Hearing", "Multi-Sensory", "Visual"); + + var queryExpression = new QueryExpression + { + EntityName = dfeta_specialism.EntityLogicalName, + ColumnSet = new ColumnSet( + dfeta_specialism.PrimaryIdAttribute, + dfeta_specialism.Fields.dfeta_name, + dfeta_specialism.Fields.dfeta_Value), + Criteria = filter, + }; + + var request = new RetrieveMultipleRequest + { + Query = queryExpression + }; + + var response = await organizationService.RetrieveMultipleAsync(queryExpression); + return response.Entities.Select(x => x.ToEntity()).ToArray(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/ReferenceDataCache.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/ReferenceDataCache.cs index 69d2621e9..8e4fcaf33 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/ReferenceDataCache.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/ReferenceDataCache.cs @@ -5,10 +5,12 @@ namespace TeachingRecordSystem.Core.Dqt; public class ReferenceDataCache { private readonly ICrmQueryDispatcher _crmQueryDispatcher; + private Task? _mqEstablishmentsTask; private Task? _getSanctionCodesTask; private Task? _getSubjectsTask; private Task? _getTeacherStatusesTask; private Task? _getEarlyYearsStatusesTask; + private Task? _getSpecialismsTask; public ReferenceDataCache(ICrmQueryDispatcher crmQueryDispatcher) { @@ -52,6 +54,32 @@ public async Task GetEarlyYearsStatusByValue(string valu return earlyYearsStatuses.Single(ey => ey.dfeta_Value == value); } + public async Task GetSpecialisms() + { + var specialisms = await EnsureSpecialisms(); + return specialisms.ToArray(); + } + + public async Task GetSpecialismByValue(string value) + { + var specialisms = await EnsureSpecialisms(); + // build environment has some duplicate Specialisms, which prevent us using Single() here + return specialisms.First(s => s.dfeta_Value == value); + } + + public async Task GetMqEstablishments() + { + var mqEstablishments = await EnsureMqEstablishments(); + return mqEstablishments.ToArray(); + } + + public async Task GetMqEstablishmentByValue(string value) + { + var mqEstablishments = await EnsureMqEstablishments(); + // build environment has some duplicate MQ Establishments, which prevent us using Single() here + return mqEstablishments.First(s => s.dfeta_Value == value); + } + private Task EnsureSanctionCodes() => LazyInitializer.EnsureInitialized( ref _getSanctionCodesTask, @@ -71,4 +99,14 @@ private Task EnsureEarlyYearsStatuses() => LazyInitializer.EnsureInitialized( ref _getEarlyYearsStatusesTask, () => _crmQueryDispatcher.ExecuteQuery(new GetAllEarlyYearsStatusesQuery())); + + private Task EnsureSpecialisms() => + LazyInitializer.EnsureInitialized( + ref _getSpecialismsTask, + () => _crmQueryDispatcher.ExecuteQuery(new GetAllSpecialismsQuery())); + + private Task EnsureMqEstablishments() => + LazyInitializer.EnsureInitialized( + ref _mqEstablishmentsTask, + () => _crmQueryDispatcher.ExecuteQuery(new GetAllMqEstablishmentsQuery())); } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/CheckPersonExistsFilter.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/CheckPersonExistsFilter.cs index 2722e5846..b994f46a7 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/CheckPersonExistsFilter.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/CheckPersonExistsFilter.cs @@ -7,22 +7,53 @@ namespace TeachingRecordSystem.SupportUi.Infrastructure.Filters; public class CheckPersonExistsFilter : IAsyncResourceFilter, IOrderedFilter { + private readonly bool _requireQts; + public int Order => -200; + public CheckPersonExistsFilter(bool requireQts = false) + { + _requireQts = requireQts; + } + public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next) { - var personId = context.RouteData.Values["personId"] as string; - if (personId is not null) + var personIdParam = context.RouteData.Values["personId"] as string ?? context.HttpContext.Request.Query["personId"]; + if (personIdParam is null || !Guid.TryParse(personIdParam, out Guid personId)) + { + context.Result = new BadRequestResult(); + return; + } + + var crmQueryDispatcher = context.HttpContext.RequestServices.GetRequiredService(); + var person = await crmQueryDispatcher.ExecuteQuery( + new GetContactDetailByIdQuery( + personId, + new ColumnSet( + Contact.Fields.Id, + Contact.Fields.FirstName, + Contact.Fields.MiddleName, + Contact.Fields.LastName, + Contact.Fields.dfeta_StatedFirstName, + Contact.Fields.dfeta_StatedLastName, + Contact.Fields.dfeta_StatedMiddleName, + Contact.Fields.dfeta_QTSDate))); + if (person is null) { - var crmQueryDispatcher = context.HttpContext.RequestServices.GetRequiredService(); - var person = await crmQueryDispatcher.ExecuteQuery(new GetContactDetailByIdQuery(Guid.Parse(personId), new ColumnSet(Contact.Fields.Id))); - if (person is null) + context.Result = new NotFoundResult(); + return; + } + else + { + if (_requireQts && person.Contact.dfeta_QTSDate is null) { - context.Result = new NotFoundResult(); + context.Result = new BadRequestResult(); return; } } + context.HttpContext.Items["CurrentPersonDetail"] = person; + await next(); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs index c627c39ba..688c96e9f 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs @@ -6,4 +6,5 @@ public static class JourneyNames public const string CloseAlert = nameof(CloseAlert); public const string EditName = nameof(EditName); public const string EditDateOfBirth = nameof(EditDateOfBirth); + public const string AddMq = nameof(AddMq); } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/AddMqState.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/AddMqState.cs new file mode 100644 index 000000000..3f22c7484 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/AddMqState.cs @@ -0,0 +1,26 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using TeachingRecordSystem.Core.Dqt.Models; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +public class AddMqState +{ + public string? MqEstablishmentValue { get; set; } + + public string? SpecialismValue { get; set; } + + public DateOnly? StartDate { get; set; } + + public dfeta_qualification_dfeta_MQ_Status? Result { get; set; } + + public DateOnly? EndDate { get; set; } + + [JsonIgnore] + [MemberNotNullWhen(true, nameof(MqEstablishmentValue), nameof(SpecialismValue), nameof(StartDate), nameof(Result))] + public bool IsComplete => !string.IsNullOrWhiteSpace(MqEstablishmentValue) && + !string.IsNullOrEmpty(SpecialismValue) && + StartDate.HasValue && + Result.HasValue && + (Result!.Value != dfeta_qualification_dfeta_MQ_Status.Passed || (Result.Value == dfeta_qualification_dfeta_MQ_Status.Passed && EndDate.HasValue)); +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/CheckAnswers.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/CheckAnswers.cshtml new file mode 100644 index 000000000..d83b67eba --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/CheckAnswers.cshtml @@ -0,0 +1,62 @@ +@page "/mqs/add/check-answers/{handler?}" +@using TeachingRecordSystem.Core.Dqt.Models; +@model TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.CheckAnswersModel +@{ + ViewBag.Title = "Check details and confirm mandatory qualification"; +} + +@section BeforeContent { + +} + +Add a mandatory qualification - @Model.PersonName +@ViewBag.Title + + + + + + + Training provider + @Model.MqEstablishment!.dfeta_name + + Change + + + + Specialism + @Model.Specialism!.dfeta_name + + Change + + + + Start date + @Model.StartDate!.Value.ToString("d MMMM yyyy") + + Change + + + + Result + @Model.Result + + Change + + + + End date + @(Model.EndDate.HasValue ? Model.EndDate.Value.ToString("d MMMM yyyy") : "None") + + Change + + + + + + Confirm mandatory qualification + Cancel and return to record + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/CheckAnswers.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/CheckAnswers.cshtml.cs new file mode 100644 index 000000000..efc8c9e10 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/CheckAnswers.cshtml.cs @@ -0,0 +1,89 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.Dqt.Models; +using TeachingRecordSystem.Core.Dqt.Queries; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +[Journey(JourneyNames.AddMq), RequireJourneyInstance] +public class CheckAnswersModel : PageModel +{ + private readonly ICrmQueryDispatcher _crmQueryDispatcher; + private readonly ReferenceDataCache _referenceDataCache; + private readonly TrsLinkGenerator _linkGenerator; + + public CheckAnswersModel( + ICrmQueryDispatcher crmQueryDispatcher, + ReferenceDataCache referenceDataCache, + TrsLinkGenerator linkGenerator) + { + _crmQueryDispatcher = crmQueryDispatcher; + _referenceDataCache = referenceDataCache; + _linkGenerator = linkGenerator; + } + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + public string? PersonName { get; set; } + + public dfeta_mqestablishment? MqEstablishment { get; set; } + + public dfeta_specialism? Specialism { get; set; } + + public DateOnly? StartDate { get; set; } + + public dfeta_qualification_dfeta_MQ_Status? Result { get; set; } + + public DateOnly? EndDate { get; set; } + + public async Task OnPost() + { + await _crmQueryDispatcher.ExecuteQuery( + new CreateMandatoryQualificationQuery() + { + ContactId = PersonId, + MqEstablishmentId = MqEstablishment!.Id, + SpecialismId = Specialism!.Id, + StartDate = StartDate!.Value, + Result = Result!.Value, + EndDate = Result == dfeta_qualification_dfeta_MQ_Status.Passed + ? EndDate!.Value + : null + }); + + await JourneyInstance!.CompleteAsync(); + TempData.SetFlashSuccess("Mandatory qualification added"); + + // This is temporarily set to PersonDetail rather than PersonQualifications until that page has been created in another trello card + return Redirect(_linkGenerator.PersonDetail(PersonId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(_linkGenerator.PersonDetail(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + var personDetail = (ContactDetail?)context.HttpContext.Items["CurrentPersonDetail"]; + + if (!JourneyInstance!.State.IsComplete) + { + context.Result = Redirect(_linkGenerator.MqAddProvider(PersonId, JourneyInstance.InstanceId)); + } + + PersonName = personDetail!.Contact.ResolveFullName(includeMiddleName: false); + MqEstablishment = await _referenceDataCache.GetMqEstablishmentByValue(JourneyInstance!.State.MqEstablishmentValue!); + Specialism = await _referenceDataCache.GetSpecialismByValue(JourneyInstance!.State.SpecialismValue!); + StartDate = JourneyInstance!.State.StartDate; + Result = JourneyInstance!.State.Result; + EndDate = JourneyInstance!.State.EndDate; + + await next(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Index.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Index.cshtml new file mode 100644 index 000000000..77be9f98a --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Index.cshtml @@ -0,0 +1,4 @@ +@page "/mqs/add" +@model TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.IndexModel +@{ +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Index.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Index.cshtml.cs new file mode 100644 index 000000000..f97b31b85 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Index.cshtml.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +public class IndexModel : PageModel +{ + private readonly TrsLinkGenerator _linkGenerator; + + public IndexModel(TrsLinkGenerator linkGenerator) + { + _linkGenerator = linkGenerator; + } + + [FromQuery] + public Guid PersonId { get; set; } + + public IActionResult OnGet() + { + return Redirect(_linkGenerator.MqAddProvider(PersonId, null)); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Provider.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Provider.cshtml new file mode 100644 index 000000000..ee8ccbe75 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Provider.cshtml @@ -0,0 +1,35 @@ +@page "/mqs/add/provider" +@model TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.ProviderModel +@{ + ViewBag.Title = "Training Provider"; +} + +@section BeforeContent { + Back +} + +Add a mandatory qualification - @Model.PersonName +@ViewBag.Title + + + + + + @if (Model.MqEstablishments is not null) + { + @foreach (var establishment in Model.MqEstablishments) + { + + @establishment.dfeta_name + + } + } + + + + Continue + Cancel and return to record + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Provider.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Provider.cshtml.cs new file mode 100644 index 000000000..4865fc1c6 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Provider.cshtml.cs @@ -0,0 +1,73 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.Dqt.Models; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +[Journey(JourneyNames.AddMq), ActivatesJourney, RequireJourneyInstance] +public class ProviderModel : PageModel +{ + private readonly ReferenceDataCache _referenceDataCache; + private readonly TrsLinkGenerator _linkGenerator; + + public ProviderModel( + ReferenceDataCache referenceDataCache, + TrsLinkGenerator linkGenerator) + { + _referenceDataCache = referenceDataCache; + _linkGenerator = linkGenerator; + } + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Display(Name = "Training Provider")] + public string? MqEstablishmentValue { get; set; } + + public dfeta_mqestablishment[]? MqEstablishments { get; set; } + + public async Task OnPost() + { + if (string.IsNullOrWhiteSpace(MqEstablishmentValue)) + { + ModelState.AddModelError(nameof(MqEstablishmentValue), "Select a training provider"); + } + + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => state.MqEstablishmentValue = MqEstablishmentValue); + + return Redirect(_linkGenerator.MqAddSpecialism(PersonId, JourneyInstance!.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(_linkGenerator.PersonDetail(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + var personDetail = (ContactDetail?)context.HttpContext.Items["CurrentPersonDetail"]; + + var establishments = await _referenceDataCache.GetMqEstablishments(); + MqEstablishments = establishments + .OrderBy(e => e.dfeta_name) + .ToArray(); + + PersonName = personDetail!.Contact.ResolveFullName(includeMiddleName: false); + MqEstablishmentValue ??= JourneyInstance!.State.MqEstablishmentValue; + + await next(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Result.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Result.cshtml new file mode 100644 index 000000000..eb3f83725 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Result.cshtml @@ -0,0 +1,52 @@ +@page "/mqs/add/result" +@using TeachingRecordSystem.Core.Dqt.Models; +@model TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.ResultModel +@{ + ViewBag.Title = "Result"; +} + +@section BeforeContent { + +} + +Add a mandatory qualification - @Model.PersonName +@ViewBag.Title + + + + + + + Deferred + + + Extended + + + Failed + + + In Progress + + + Passed + + + + + + + + + + Withdrawn + + + + + Continue + Cancel and return to record + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Result.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Result.cshtml.cs new file mode 100644 index 000000000..b704af17c --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Result.cshtml.cs @@ -0,0 +1,77 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.Dqt.Models; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +[Journey(JourneyNames.AddMq), RequireJourneyInstance] +public class ResultModel : PageModel +{ + private readonly TrsLinkGenerator _linkGenerator; + + public ResultModel( + TrsLinkGenerator linkGenerator) + { + _linkGenerator = linkGenerator; + } + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + public dfeta_qualification_dfeta_MQ_Status? Result { get; set; } + + [BindProperty] + [Display(Name = "End date")] + public DateOnly? EndDate { get; set; } + + public async Task OnPost() + { + if (Result is null) + { + ModelState.AddModelError(nameof(Result), "Select a result"); + } + + if (Result == dfeta_qualification_dfeta_MQ_Status.Passed && EndDate is null) + { + ModelState.AddModelError(nameof(EndDate), "Enter an end date"); + } + + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync( + state => + { + state.Result = Result; + state.EndDate = Result == dfeta_qualification_dfeta_MQ_Status.Passed ? EndDate : null; + }); + + return Redirect(_linkGenerator.MqAddCheckAnswers(PersonId, JourneyInstance!.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(_linkGenerator.PersonDetail(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + var personDetail = (ContactDetail?)context.HttpContext.Items["CurrentPersonDetail"]; + + PersonName = personDetail!.Contact.ResolveFullName(includeMiddleName: false); + Result ??= JourneyInstance!.State.Result; + EndDate ??= JourneyInstance!.State.EndDate; + + await next(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Specialism.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Specialism.cshtml new file mode 100644 index 000000000..0452ee2c0 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Specialism.cshtml @@ -0,0 +1,35 @@ +@page "/mqs/add/specialism" +@model TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.SpecialismModel +@{ + ViewBag.Title = "Specialism"; +} + +@section BeforeContent { + +} + +Add a mandatory qualification - @Model.PersonName +@ViewBag.Title + + + + + + @if (Model.Specialisms is not null) + { + @foreach (var specialism in Model.Specialisms) + { + + @specialism.dfeta_name + + } + } + + + + Continue + Cancel and return to record + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Specialism.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Specialism.cshtml.cs new file mode 100644 index 000000000..61ceed1d5 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/Specialism.cshtml.cs @@ -0,0 +1,71 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.Dqt.Models; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +[Journey(JourneyNames.AddMq), RequireJourneyInstance] +public class SpecialismModel : PageModel +{ + private readonly ReferenceDataCache _referenceDataCache; + private readonly TrsLinkGenerator _linkGenerator; + + public SpecialismModel( + ReferenceDataCache referenceDataCache, + TrsLinkGenerator linkGenerator) + { + _referenceDataCache = referenceDataCache; + _linkGenerator = linkGenerator; + } + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + public string? SpecialismValue { get; set; } + + public dfeta_specialism[]? Specialisms { get; set; } + + public async Task OnPost() + { + if (SpecialismValue is null) + { + ModelState.AddModelError(nameof(SpecialismValue), "Select a specialism"); + } + + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => state.SpecialismValue = SpecialismValue); + + return Redirect(_linkGenerator.MqAddStartDate(PersonId, JourneyInstance!.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(_linkGenerator.PersonDetail(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + var personDetail = (ContactDetail?)context.HttpContext.Items["CurrentPersonDetail"]; + + var specialisms = await _referenceDataCache.GetSpecialisms(); + Specialisms = specialisms + .OrderBy(e => e.dfeta_name) + .ToArray(); + + PersonName = personDetail!.Contact.ResolveFullName(includeMiddleName: false); + SpecialismValue ??= JourneyInstance!.State.SpecialismValue; + + await next(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/StartDate.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/StartDate.cshtml new file mode 100644 index 000000000..0a97b779e --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/StartDate.cshtml @@ -0,0 +1,28 @@ +@page "/mqs/add/start-date" +@model TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.StartDateModel +@{ + ViewBag.Title = "Start date"; +} + +@section BeforeContent { + +} + +Add a mandatory qualification - @Model.PersonName + + + + + + + + + + + + Continue + Cancel and return to record + + + + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/StartDate.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/StartDate.cshtml.cs new file mode 100644 index 000000000..0f413807b --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Mqs/AddMq/StartDate.cshtml.cs @@ -0,0 +1,63 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.Dqt.Models; + +namespace TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +[Journey(JourneyNames.AddMq), RequireJourneyInstance] +public class StartDateModel : PageModel +{ + private readonly TrsLinkGenerator _linkGenerator; + + public StartDateModel( + TrsLinkGenerator linkGenerator) + { + _linkGenerator = linkGenerator; + } + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Display(Name = "Start date")] + public DateOnly? StartDate { get; set; } + + public async Task OnPost() + { + if (StartDate is null) + { + ModelState.AddModelError(nameof(StartDate), "Enter a start date"); + } + + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => state.StartDate = StartDate); + + return Redirect(_linkGenerator.MqAddResult(PersonId, JourneyInstance!.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(_linkGenerator.PersonDetail(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + var personDetail = (ContactDetail?)context.HttpContext.Items["CurrentPersonDetail"]; + + PersonName = personDetail!.Contact.ResolveFullName(includeMiddleName: false); + StartDate ??= JourneyInstance!.State.StartDate; + + await next(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs index 2777546cb..e64c08f33 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs @@ -115,6 +115,12 @@ { model.Filters.Add(new CheckPersonExistsFilter()); }); + options.Conventions.AddFolderApplicationModelConvention( + "/Mqs", + model => + { + model.Filters.Add(new CheckPersonExistsFilter()); + }); }) .AddMvcOptions(options => { @@ -213,6 +219,12 @@ typeof(TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditDateOfBirth.EditDateOfBirthState), requestDataKeys: new[] { "personId" }, appendUniqueKey: true)); + + options.JourneyRegistry.RegisterJourney(new JourneyDescriptor( + JourneyNames.AddMq, + typeof(TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.AddMqState), + requestDataKeys: new[] { "personId" }, + appendUniqueKey: true)); }); builder.Services diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs index 5d0a2c260..1e049ddb8 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs @@ -45,12 +45,48 @@ public string AlertCloseConfirm(Guid alertId, JourneyInstanceId journeyInstanceI public string RejectCase(string ticketNumber) => GetRequiredPathByPage("/Cases/EditCase/Reject", routeValues: new { ticketNumber }); + public string MqAdd(Guid personId) => + GetRequiredPathByPage("/Mqs/AddMq/Index", routeValues: new { personId }); + + public string MqAddProvider(Guid personId, JourneyInstanceId? journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/Provider", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddProviderCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/Provider", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddSpecialism(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/Specialism", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddSpecialismCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/Specialism", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddStartDate(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/StartDate", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddStartDateCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/StartDate", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddResult(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/Result", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddResultCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/Result", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddCheckAnswers(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/CheckAnswers", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string MqAddCheckAnswersCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Mqs/AddMq/CheckAnswers", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + public string Persons(string? search = null, ContactSearchSortByOption? sortBy = null, int? pageNumber = null) => GetRequiredPathByPage("/Persons/Index", routeValues: new { search, sortBy, pageNumber }); public string PersonDetail(Guid personId, string? search = null, ContactSearchSortByOption? sortBy = null, int? pageNumber = null) => GetRequiredPathByPage("/Persons/PersonDetail/Index", routeValues: new { personId, search, sortBy, pageNumber }); + public string PersonQualifications(Guid personId, string? search = null, ContactSearchSortByOption? sortBy = null, int? pageNumber = null) => + GetRequiredPathByPage("/Persons/PersonDetail/Qualifications", routeValues: new { personId, search, sortBy, pageNumber }); + public string PersonAlerts(Guid personId, string? search = null, ContactSearchSortByOption? sortBy = null, int? pageNumber = null) => GetRequiredPathByPage("/Persons/PersonDetail/Alerts", routeValues: new { personId, search, sortBy, pageNumber }); diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/CreateMandatoryQualificationTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/CreateMandatoryQualificationTests.cs new file mode 100644 index 000000000..f330b97d7 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/CreateMandatoryQualificationTests.cs @@ -0,0 +1,53 @@ +namespace TeachingRecordSystem.Core.Dqt.Tests.QueryTests; + +public class CreateMandatoryQualificationTests : IAsyncLifetime +{ + private readonly CrmClientFixture.TestDataScope _dataScope; + private readonly CrmQueryDispatcher _crmQueryDispatcher; + + public CreateMandatoryQualificationTests(CrmClientFixture crmClientFixture) + { + _dataScope = crmClientFixture.CreateTestDataScope(); + _crmQueryDispatcher = _dataScope.CreateQueryDispatcher(); + } + + public Task InitializeAsync() => Task.CompletedTask; + + public async Task DisposeAsync() => await _dataScope.DisposeAsync(); + + [Fact] + public async Task QueryExecutesSuccessfully() + { + // Arrange + var person = await _dataScope.TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishment = await _dataScope.TestData.ReferenceDataCache.GetMqEstablishmentByValue("955"); // University of Birmingham + var specialism = await _dataScope.TestData.ReferenceDataCache.GetSpecialismByValue("Hearing"); + var startDate = new DateOnly(2023, 01, 5); + var endDate = new DateOnly(2023, 07, 10); + + var query = new CreateMandatoryQualificationQuery() + { + ContactId = person.ContactId, + MqEstablishmentId = mqEstablishment.Id, + SpecialismId = specialism.Id, + StartDate = new DateOnly(2023, 01, 5), + Result = dfeta_qualification_dfeta_MQ_Status.Passed, + EndDate = new DateOnly(2023, 07, 10), + }; + + // Act + var qualificationId = await _crmQueryDispatcher.ExecuteQuery(query); + + // Assert + using var ctx = new DqtCrmServiceContext(_dataScope.OrganizationService); + + var createdQualification = ctx.dfeta_qualificationSet.SingleOrDefault(q => q.GetAttributeValue(dfeta_qualification.PrimaryIdAttribute) == qualificationId); + Assert.NotNull(createdQualification); + Assert.Equal(person.ContactId, createdQualification.dfeta_PersonId.Id); + Assert.Equal(mqEstablishment.Id, createdQualification.dfeta_MQ_MQEstablishmentId.Id); + Assert.Equal(specialism.Id, createdQualification.dfeta_MQ_SpecialismId.Id); + Assert.Equal(startDate.FromDateOnlyWithDqtBstFix(isLocalTime: true), createdQualification.dfeta_MQStartDate); + Assert.Equal(dfeta_qualification_dfeta_MQ_Status.Passed, createdQualification.dfeta_MQ_Status); + Assert.Equal(endDate.FromDateOnlyWithDqtBstFix(isLocalTime: true), createdQualification.dfeta_MQ_Date); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/GetAllMqEstablishmentsTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/GetAllMqEstablishmentsTests.cs new file mode 100644 index 000000000..985e8c14d --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/GetAllMqEstablishmentsTests.cs @@ -0,0 +1,24 @@ +namespace TeachingRecordSystem.Core.Dqt.Tests.QueryTests; + +public class GetAllMqEstablishmentsTests +{ + private readonly CrmQueryDispatcher _crmQueryDispatcher; + + public GetAllMqEstablishmentsTests(CrmClientFixture crmClientFixture) + { + _crmQueryDispatcher = crmClientFixture.CreateQueryDispatcher(); + } + + [Fact] + public async Task QueryExecutesSuccessfully() + { + // Arrange + var query = new GetAllMqEstablishmentsQuery(); + + // Act + var result = await _crmQueryDispatcher.ExecuteQuery(query); + + // Assert + Assert.NotEmpty(result); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/GetAllSpecialismsTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/GetAllSpecialismsTests.cs new file mode 100644 index 000000000..42c421233 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Dqt.Tests/QueryTests/GetAllSpecialismsTests.cs @@ -0,0 +1,24 @@ +namespace TeachingRecordSystem.Core.Dqt.Tests.QueryTests; + +public class GetAllSpecialismsTests +{ + private readonly CrmQueryDispatcher _crmQueryDispatcher; + + public GetAllSpecialismsTests(CrmClientFixture crmClientFixture) + { + _crmQueryDispatcher = crmClientFixture.CreateQueryDispatcher(); + } + + [Fact] + public async Task QueryExecutesSuccessfully() + { + // Arrange + var query = new GetAllSpecialismsQuery(); + + // Act + var result = await _crmQueryDispatcher.ExecuteQuery(query); + + // Assert + Assert.NotEmpty(result); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/MqTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/MqTests.cs new file mode 100644 index 000000000..6d299ac2f --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/MqTests.cs @@ -0,0 +1,63 @@ +using TeachingRecordSystem.Core.Dqt.Models; + +namespace TeachingRecordSystem.SupportUi.EndToEndTests; + +public class MqTests : TestBase +{ + public MqTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task AddMQ() + { + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishment = await TestData.ReferenceDataCache.GetMqEstablishmentByValue("959"); // University of Leeds + var specialism = await TestData.ReferenceDataCache.GetSpecialismByValue("Hearing"); + var startDate = new DateOnly(2021, 3, 1); + var result = dfeta_qualification_dfeta_MQ_Status.Passed; + var endDate = new DateOnly(2021, 11, 5); + var personId = person.PersonId; + + await using var context = await HostFixture.CreateBrowserContext(); + var page = await context.NewPageAsync(); + + await page.GoToAddMqPage(personId); + + await page.AssertOnAddMqProviderPage(); + + await page.CheckAsync($"label:text-is('{mqEstablishment.dfeta_name}')"); + + await page.ClickContinueButton(); + + await page.AssertOnAddMqSpecialismPage(); + + await page.CheckAsync($"label:text-is('{specialism.dfeta_name}')"); + + await page.ClickContinueButton(); + + await page.AssertOnAddMqStartDatePage(); + + await page.FillDateInput(startDate); + + await page.ClickContinueButton(); + + await page.AssertOnAddMqResultPage(); + + await page.CheckAsync($"label:text-is('{result}')"); + + await page.FillDateInput(endDate); + + await page.ClickContinueButton(); + + await page.AssertOnAddMqCheckAnswersPage(); + + await page.ClickButton("Confirm mandatory qualification"); + + // This will be changed to PersonQualifications once that page has been created in another trello card + await page.AssertOnPersonDetailPage(personId); + + await page.AssertFlashMessage("Mandatory qualification added"); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs index 235fb80a7..a70bcd190 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs @@ -26,6 +26,11 @@ public static async Task GoToPersonDetailPage(this IPage page, Guid personId) await page.GotoAsync($"/persons/{personId}"); } + public static async Task GoToAddMqPage(this IPage page, Guid personId) + { + await page.GotoAsync($"/mqs/add?personId={personId}"); + } + public static Task ClickLinkForElementWithTestId(this IPage page, string testId) => page.GetByTestId(testId).ClickAsync(); @@ -129,6 +134,31 @@ public static async Task AssertOnPersonEditDateOfBirthConfirmPage(this IPage pag await page.WaitForUrlPathAsync($"/persons/{personId}/edit-date-of-birth/confirm"); } + public static async Task AssertOnAddMqProviderPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/mqs/add/provider"); + } + + public static async Task AssertOnAddMqSpecialismPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/mqs/add/specialism"); + } + + public static async Task AssertOnAddMqStartDatePage(this IPage page) + { + await page.WaitForUrlPathAsync($"/mqs/add/start-date"); + } + + public static async Task AssertOnAddMqResultPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/mqs/add/result"); + } + + public static async Task AssertOnAddMqCheckAnswersPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/mqs/add/check-answers"); + } + public static async Task AssertFlashMessage(this IPage page, string expectedHeader) { Assert.Equal(expectedHeader, await page.InnerTextAsync($".govuk-notification-banner__heading:text-is('{expectedHeader}')")); @@ -181,6 +211,6 @@ public static Task ClickDeactivateButton(this IPage page) public static Task ClickReactivateButton(this IPage page) => ClickButton(page, "Remove inactive status"); - private static Task ClickButton(this IPage page, string text) => + public static Task ClickButton(this IPage page, string text) => page.ClickAsync($".govuk-button:text-is('{text}')"); } diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/CheckAnswersTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/CheckAnswersTests.cs new file mode 100644 index 000000000..ba7431715 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/CheckAnswersTests.cs @@ -0,0 +1,206 @@ +using FormFlow; +using TeachingRecordSystem.Core.Dqt.Models; +using TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Mqs.AddMq; + +public class CheckAnswersTests : TestBase +{ + public CheckAnswersTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/check-answers?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_WithPersonIdForValidPersonReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishment = await TestData.ReferenceDataCache.GetMqEstablishmentByValue("959"); // University of Leeds + var specialism = await TestData.ReferenceDataCache.GetSpecialismByValue("Hearing"); + var startDate = new DateOnly(2021, 3, 1); + var result = dfeta_qualification_dfeta_MQ_Status.Passed; + DateOnly? endDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + MqEstablishmentValue = mqEstablishment.dfeta_Value, + SpecialismValue = specialism.dfeta_Value, + StartDate = startDate, + Result = result, + EndDate = endDate + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Theory] + [InlineData(dfeta_qualification_dfeta_MQ_Status.InProgress)] + [InlineData(dfeta_qualification_dfeta_MQ_Status.Failed)] + [InlineData(dfeta_qualification_dfeta_MQ_Status.Passed)] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState(dfeta_qualification_dfeta_MQ_Status result) + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishment = await TestData.ReferenceDataCache.GetMqEstablishmentByValue("959"); // University of Leeds + var specialism = await TestData.ReferenceDataCache.GetSpecialismByValue("Hearing"); + var startDate = new DateOnly(2021, 3, 1); + DateOnly? endDate = result == dfeta_qualification_dfeta_MQ_Status.Passed ? new DateOnly(2021, 11, 5) : null; + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + MqEstablishmentValue = mqEstablishment.dfeta_Value, + SpecialismValue = specialism.dfeta_Value, + StartDate = startDate, + Result = result, + EndDate = endDate + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await response.GetDocument(); + Assert.Equal(mqEstablishment.dfeta_name, doc.GetElementByTestId("provider")!.TextContent); + Assert.Equal(specialism.dfeta_name, doc.GetElementByTestId("specialism")!.TextContent); + Assert.Equal(startDate.ToString("d MMMM yyyy"), doc.GetElementByTestId("start-date")!.TextContent); + Assert.Equal(result.ToString(), doc.GetElementByTestId("result")!.TextContent); + if (result == dfeta_qualification_dfeta_MQ_Status.Passed) + { + Assert.Equal(endDate!.Value.ToString("d MMMM yyyy"), doc.GetElementByTestId("end-date")!.TextContent); + } + else + { + Assert.Equal("None", doc.GetElementByTestId("end-date")!.TextContent); + } + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/check-answers?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Theory] + [InlineData(dfeta_qualification_dfeta_MQ_Status.InProgress)] + [InlineData(dfeta_qualification_dfeta_MQ_Status.Failed)] + [InlineData(dfeta_qualification_dfeta_MQ_Status.Passed)] + public async Task Post_Confirm_CompletesJourneyAndRedirectsWithFlashMessage(dfeta_qualification_dfeta_MQ_Status result) + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishment = await TestData.ReferenceDataCache.GetMqEstablishmentByValue("959"); // University of Leeds + var specialism = await TestData.ReferenceDataCache.GetSpecialismByValue("Hearing"); + var startDate = new DateOnly(2021, 3, 1); + DateOnly? endDate = result == dfeta_qualification_dfeta_MQ_Status.Passed ? new DateOnly(2021, 11, 5) : null; + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + MqEstablishmentValue = mqEstablishment.dfeta_Value, + SpecialismValue = specialism.dfeta_Value, + StartDate = startDate, + Result = result, + EndDate = endDate + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + var redirectResponse = await response.FollowRedirect(HttpClient); + var redirectDoc = await redirectResponse.GetDocument(); + AssertEx.HtmlDocumentHasFlashSuccess(redirectDoc, "Mandatory qualification added"); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.True(journeyInstance.Completed); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishment = await TestData.ReferenceDataCache.GetMqEstablishmentByValue("959"); // University of Leeds + var specialism = await TestData.ReferenceDataCache.GetSpecialismByValue("Hearing"); + var startDate = new DateOnly(2021, 3, 1); + var result = dfeta_qualification_dfeta_MQ_Status.Passed; + DateOnly? endDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + MqEstablishmentValue = mqEstablishment.dfeta_Value, + SpecialismValue = specialism.dfeta_Value, + StartDate = startDate, + Result = result, + EndDate = endDate + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/check-answers/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddMqState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddMq, + state ?? new AddMqState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/IndexTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/IndexTests.cs new file mode 100644 index 000000000..756c799a2 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/IndexTests.cs @@ -0,0 +1,25 @@ +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Mqs.AddMq; + +public class IndexTests : TestBase +{ + public IndexTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task Get_RedirectsToMqAddProvider() + { + // Arrange + var person = await TestData.CreatePerson(); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add?personId={person.PersonId}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.Equal($"/mqs/add/provider?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/ProviderTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/ProviderTests.cs new file mode 100644 index 000000000..8aedca294 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/ProviderTests.cs @@ -0,0 +1,143 @@ +using FormFlow; +using TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Mqs.AddMq; + +public class ProviderTests : TestBase +{ + public ProviderTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/provider?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/provider?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishmentValue = "959"; // University of Leeds + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + MqEstablishmentValue = mqEstablishmentValue + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/provider?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await response.GetDocument(); + var providerList = doc.GetElementByTestId("provider-list"); + var radioButtons = providerList!.GetElementsByTagName("input"); + var selectedProvider = radioButtons.SingleOrDefault(r => r.HasAttribute("checked")); + Assert.NotNull(selectedProvider); + Assert.Equal(mqEstablishmentValue, selectedProvider.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var mqEstablishmentValue = "959"; // University of Leeds + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/provider?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "MqEstablishmentValue", mqEstablishmentValue } + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WhenNoProviderIsSelected_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/provider?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary()) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "MqEstablishmentValue", "Select a training provider"); + } + + [Fact] + public async Task Post_WhenProviderIsSelected_RedirectsToSpecialismPage() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var mqEstablishmentValue = "959"; // University of Leeds + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/provider?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "MqEstablishmentValue", mqEstablishmentValue } + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.Equal($"/mqs/add/specialism?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}", response.Headers.Location?.OriginalString); + } + + private async Task> CreateJourneyInstance(Guid personId, AddMqState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddMq, + state ?? new AddMqState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/ResultTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/ResultTests.cs new file mode 100644 index 000000000..83cdfcb52 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/ResultTests.cs @@ -0,0 +1,180 @@ +using FormFlow; +using TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Mqs.AddMq; + +public class ResultTests : TestBase +{ + public ResultTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/result?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var result = Core.Dqt.Models.dfeta_qualification_dfeta_MQ_Status.Passed; + var endDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + Result = result, + EndDate = endDate, + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/result?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await response.GetDocument(); + var resultOptions = doc.GetElementByTestId("result-options"); + var radioButtons = resultOptions!.GetElementsByTagName("input"); + var selectedResult = radioButtons.SingleOrDefault(r => r.HasAttribute("checked")); + Assert.NotNull(selectedResult); + Assert.Equal(result.ToString(), selectedResult.GetAttribute("value")); + Assert.Equal($"{endDate:%d}", doc.GetElementById("EndDate.Day")?.GetAttribute("value")); + Assert.Equal($"{endDate:%M}", doc.GetElementById("EndDate.Month")?.GetAttribute("value")); + Assert.Equal($"{endDate:yyyy}", doc.GetElementById("EndDate.Year")?.GetAttribute("value")); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/result?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var result = Core.Dqt.Models.dfeta_qualification_dfeta_MQ_Status.Passed; + var endDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/result?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "Result", result.ToString() }, + { "EndDate.Day", $"{endDate:%d}" }, + { "EndDate.Month", $"{endDate:%M}" }, + { "EndDate.Year", $"{endDate:yyyy}" }, + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WhenResultIsNotSelectedIsEntered_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/result?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary()) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "Result", "Select a result"); + } + + [Fact] + public async Task Post_WhenResultIsPassedAndEndDateHasNotBeenEntered_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var result = Core.Dqt.Models.dfeta_qualification_dfeta_MQ_Status.Passed; + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/result?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "Result", result.ToString() }, + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "EndDate", "Enter an end date"); + } + + [Fact] + public async Task Post_ValidRequest_RedirectsToResultPage() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var result = Core.Dqt.Models.dfeta_qualification_dfeta_MQ_Status.Passed; + var endDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/result?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "Result", result.ToString() }, + { "EndDate.Day", $"{endDate:%d}" }, + { "EndDate.Month", $"{endDate:%M}" }, + { "EndDate.Year", $"{endDate:yyyy}" }, + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.Equal($"/mqs/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}", response.Headers.Location?.OriginalString); + } + + private async Task> CreateJourneyInstance(Guid personId, AddMqState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddMq, + state ?? new AddMqState(), + new KeyValuePair("personId", personId)); + +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/SpecialismTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/SpecialismTests.cs new file mode 100644 index 000000000..14ecb414b --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/SpecialismTests.cs @@ -0,0 +1,128 @@ +using FormFlow; +using TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Mqs.AddMq; + +public class SpecialismTests : TestBase +{ + public SpecialismTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/specialism?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var specialismValue = "Hearing"; + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + SpecialismValue = specialismValue + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/specialism?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await response.GetDocument(); + var providerList = doc.GetElementByTestId("specialism-list"); + var radioButtons = providerList!.GetElementsByTagName("input"); + var selectedSpecialism = radioButtons.SingleOrDefault(r => r.HasAttribute("checked")); + Assert.NotNull(selectedSpecialism); + Assert.Equal(specialismValue, selectedSpecialism.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var specialismValue = "Hearing"; + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/specialism?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "SpecialismValue", specialismValue } + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WhenNoSpecialismIsSelected_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/specialism?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary()) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "SpecialismValue", "Select a specialism"); + } + + [Fact] + public async Task Post_WhenSpecialismIsSelected_RedirectsToStartDatePage() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var specialismValue = "Hearing"; + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/specialism?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "SpecialismValue", specialismValue } + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.Equal($"/mqs/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}", response.Headers.Location?.OriginalString); + } + + + private async Task> CreateJourneyInstance(Guid personId, AddMqState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddMq, + state ?? new AddMqState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/StartDateTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/StartDateTests.cs new file mode 100644 index 000000000..a72acd760 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Mqs/AddMq/StartDateTests.cs @@ -0,0 +1,145 @@ +using FormFlow; +using TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Mqs.AddMq; + +public class StartDateTests : TestBase +{ + public StartDateTests(HostFixture hostFixture) + : base(hostFixture) + { + } + + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/start-date?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var startDate = new DateOnly(2021, 10, 5); + var journeyInstance = await CreateJourneyInstance( + person.ContactId, + new AddMqState() + { + StartDate = startDate + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/mqs/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await response.GetDocument(); + Assert.Equal($"{startDate:%d}", doc.GetElementById("StartDate.Day")?.GetAttribute("value")); + Assert.Equal($"{startDate:%M}", doc.GetElementById("StartDate.Month")?.GetAttribute("value")); + Assert.Equal($"{startDate:yyyy}", doc.GetElementById("StartDate.Year")?.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + var startDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/start-date?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "StartDate.Day", $"{startDate:%d}" }, + { "StartDate.Month", $"{startDate:%M}" }, + { "StartDate.Year", $"{startDate:yyyy}" }, + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WhenStartDateIsEntered_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary()) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "StartDate", "Enter a start date"); + } + + [Fact] + public async Task Post_WhenStartDateIsEntered_RedirectsToResultPage() + { + // Arrange + var person = await TestData.CreatePerson(b => b.WithQts(qtsDate: new DateOnly(2021, 10, 5))); + var startDate = new DateOnly(2021, 11, 5); + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/mqs/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "StartDate.Day", $"{startDate:%d}" }, + { "StartDate.Month", $"{startDate:%M}" }, + { "StartDate.Year", $"{startDate:yyyy}" }, + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.Equal($"/mqs/add/result?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}", response.Headers.Location?.OriginalString); + } + + private async Task> CreateJourneyInstance(Guid personId, AddMqState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddMq, + state ?? new AddMqState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/CrmTestData.CreatePerson.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/CrmTestData.CreatePerson.cs index 4daab0a50..f321b2561 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/CrmTestData.CreatePerson.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/CrmTestData.CreatePerson.cs @@ -230,6 +230,16 @@ public async Task Execute(CrmTestData testData) dfeta_PersonId = personId.ToEntityReference(Contact.EntityLogicalName) } }); + + txnRequestBuilder.AddRequest(new CreateRequest() + { + Target = new dfeta_initialteachertraining() + { + dfeta_PersonId = personId.ToEntityReference(Contact.EntityLogicalName), + dfeta_Result = dfeta_ITTResult.Pass, + } + }); + // Plugin which updates Contact with QTS Date only fires on Update or Delete txnRequestBuilder.AddRequest(new UpdateRequest() { @@ -254,6 +264,7 @@ public async Task Execute(CrmTestData testData) dfeta_PersonId = personId.ToEntityReference(Contact.EntityLogicalName) } }); + // Plugin which updates Contact with EYTS Date only fires on Update or Delete txnRequestBuilder.AddRequest(new UpdateRequest() { diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/SeedCrmReferenceData.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/SeedCrmReferenceData.cs index 0ad476e25..2498d11ce 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/SeedCrmReferenceData.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/SeedCrmReferenceData.cs @@ -19,6 +19,8 @@ public Task Execute() AddSanctionCodes(); AddTeacherStatuses(); AddEarlyYearsStatuses(); + AddMqEstablishments(); + AddSpecialisms(); return Task.CompletedTask; } @@ -120,4 +122,52 @@ private void AddEarlyYearsStatuses() dfeta_name = "Early Years Professional Status" }); } + + private void AddMqEstablishments() + { + _xrmFakedContext.CreateEntity(new dfeta_mqestablishment() + { + dfeta_Value = "955", + dfeta_name = "University of Birmingham" + }); + + _xrmFakedContext.CreateEntity(new dfeta_mqestablishment() + { + dfeta_Value = "957", + dfeta_name = "University of Edinburgh" + }); + + _xrmFakedContext.CreateEntity(new dfeta_mqestablishment() + { + dfeta_Value = "959", + dfeta_name = "University of Leeds" + }); + + _xrmFakedContext.CreateEntity(new dfeta_mqestablishment() + { + dfeta_Value = "961", + dfeta_name = "University of Manchester" + }); + } + + private void AddSpecialisms() + { + _xrmFakedContext.CreateEntity(new dfeta_specialism() + { + dfeta_Value = "Hearing", + dfeta_name = "Hearing" + }); + + _xrmFakedContext.CreateEntity(new dfeta_specialism() + { + dfeta_Value = "Multi-Sensory", + dfeta_name = "Multi_Sensory Impairment" + }); + + _xrmFakedContext.CreateEntity(new dfeta_specialism() + { + dfeta_Value = "Visual", + dfeta_name = "Visual Impairment" + }); + } } diff --git a/crm_attributes.json b/crm_attributes.json index 4a3111312..074eb4d96 100644 --- a/crm_attributes.json +++ b/crm_attributes.json @@ -147,6 +147,12 @@ "dfeta_value", "statecode" ], + "dfeta_mqestablishment": [ + "dfeta_mqestablishmentid", + "dfeta_name", + "dfeta_value", + "statecode" + ], "dfeta_previousname": [ "createdon", "dfeta_changedon", @@ -176,6 +182,7 @@ "dfeta_he_hesubject1id", "dfeta_he_hesubject2id", "dfeta_he_hesubject3id", + "dfeta_name", "dfeta_personid", "dfeta_type", "statecode", @@ -198,11 +205,16 @@ "dfeta_npqml_awarded", "dfeta_npqsl_awarded", "dfeta_createdbyapi", - "dfeta_mq_specialismid", "dfeta_mq_date", + "dfeta_mq_mqestablishmentid", + "dfeta_mq_specialismid", + "dfeta_mq_status", + "dfeta_mqstartdate", + "dfeta_trsdeletedevent", "CreatedOn" ], "dfeta_specialism": [ + "dfeta_specialismid", "dfeta_name", "dfeta_value", "statecode" diff --git a/tools/coretools/CrmSvcUtil.exe.config b/tools/coretools/CrmSvcUtil.exe.config index a49c145e3..74a6bbe3d 100644 --- a/tools/coretools/CrmSvcUtil.exe.config +++ b/tools/coretools/CrmSvcUtil.exe.config @@ -19,14 +19,8 @@ - -<<<<<<< HEAD - -||||||| parent of 89cf2325 (Add AllowIdSignInWithProhibitions member to v3 teacher response) - -======= - ->>>>>>> 89cf2325 (Add AllowIdSignInWithProhibitions member to v3 teacher response) + +