Skip to content

Commit 691fbe8

Browse files
Merge remote-tracking branch 'origin/release-v1.0.0' into Develop/Features/TD-4790-Writeunittestsfortagsaddedonoptionalcompetenciesinthesupervisorview
2 parents 419faa7 + 3098eaa commit 691fbe8

File tree

11 files changed

+503
-113
lines changed

11 files changed

+503
-113
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+

2+
namespace DigitalLearningSolutions.Data.Migrations
3+
{
4+
using FluentMigrator;
5+
6+
[Migration(202410071401)]
7+
public class UpdateCandidateAssessmentSupervisorsTabl : ForwardOnlyMigration
8+
{
9+
public override void Up()
10+
{
11+
Execute.Sql($@"UPDATE cas
12+
SET SelfAssessmentSupervisorRoleID = (SELECT ID FROM SelfAssessmentSupervisorRoles
13+
WHERE SelfAssessmentID = ssr.SelfAssessmentID and AllowDelegateNomination = 1)
14+
FROM CandidateAssessmentSupervisors cas INNER JOIN
15+
SelfAssessmentSupervisorRoles ssr ON cas.SelfAssessmentSupervisorRoleID = ssr.ID
16+
AND cas.Removed IS NULL AND ssr.AllowDelegateNomination = 0 INNER JOIN
17+
SupervisorDelegates sd ON cas.SupervisorDelegateId = sd.ID INNER JOIN
18+
AdminAccounts aa ON sd.SupervisorAdminID = aa.ID WHERE aa.IsSupervisor = 0 AND aa.IsNominatedSupervisor = 1");
19+
}
20+
}
21+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace DigitalLearningSolutions.Data.Migrations
2+
{
3+
using FluentMigrator;
4+
5+
[Migration(202410091524)]
6+
public class UpdateCandidateAssessmentSupervisorsDuplicateRows : ForwardOnlyMigration
7+
{
8+
public override void Up()
9+
{
10+
Execute.Sql(@$"WITH CAS_Duplicates AS (
11+
SELECT ID,
12+
ROW_NUMBER() OVER (PARTITION BY CandidateAssessmentID,SupervisorDelegateId ORDER BY Id DESC) AS RowNum
13+
FROM CandidateAssessmentSupervisors
14+
WHERE CandidateAssessmentSupervisors.Removed is null
15+
)
16+
UPDATE CandidateAssessmentSupervisors
17+
SET Removed = GETUTCDATE()
18+
FROM CandidateAssessmentSupervisors cas INNER JOIN
19+
CAS_Duplicates casd ON cas.ID = casd.ID
20+
WHERE casd.RowNum > 1;");
21+
}
22+
23+
}
24+
}

DigitalLearningSolutions.Data/DataServices/CourseDataService.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,9 @@ LEFT OUTER JOIN UserCentreDetails AS UCD ON
541541
new { candidateAssessmentId, enrolmentMethodId, completeByDateDynamic }
542542
);
543543
}
544-
if (candidateAssessmentId > 1 && supervisorDelegateId !=0)
544+
545+
if (candidateAssessmentId > 1 && supervisorDelegateId !=0)
546+
545547
{
546548
string sqlQuery = $@"
547549
BEGIN TRANSACTION
@@ -558,6 +560,23 @@ BEGIN TRANSACTION
558560
, new { candidateAssessmentId, selfAssessmentSupervisorRoleId, enrolmentMethodId, completeByDateDynamic });
559561
}
560562

563+
if (supervisorId > 0)
564+
{
565+
566+
var adminUserId = Convert.ToInt32(connection.ExecuteScalar(@"SELECT UserID FROM AdminAccounts WHERE (AdminAccounts.ID = @supervisorId)",
567+
new { supervisorId })
568+
);
569+
570+
if (delegateUserId == adminUserId)
571+
{
572+
connection.Execute(
573+
@"UPDATE CandidateAssessments SET NonReportable = 1 WHERE ID = @candidateAssessmentId",
574+
new { candidateAssessmentId }
575+
);
576+
577+
}
578+
}
579+
561580
if (candidateAssessmentId < 1)
562581
{
563582
logger.LogWarning(

DigitalLearningSolutions.Data/Helpers/NameQueryHelper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,12 @@ public static string GetSortableFullName(string? firstName, string lastName)
66
{
77
return string.IsNullOrWhiteSpace(firstName) ? lastName : $"{lastName}, {firstName}";
88
}
9+
10+
public static string GetSortableFullName(string? firstName, string lastName, string? primaryEmail, string? centreEmail)
11+
{
12+
var name = string.IsNullOrWhiteSpace(firstName) ? lastName : $"{lastName}, {firstName}";
13+
var email = CentreEmailHelper.GetEmailForCentreNotifications( primaryEmail!, centreEmail );
14+
return $"{name} ({email})";
15+
}
916
}
1017
}

DigitalLearningSolutions.Data/Models/User/AdminEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public AdminEntity(
4848
public override string SearchableName
4949
{
5050
get => SearchableNameOverrideForFuzzySharp ??
51-
NameQueryHelper.GetSortableFullName(UserAccount.FirstName, UserAccount.LastName);
51+
NameQueryHelper.GetSortableFullName(UserAccount.FirstName, UserAccount.LastName, UserAccount.PrimaryEmail, UserCentreDetails?.Email);
5252
set => SearchableNameOverrideForFuzzySharp = value;
5353
}
5454

DigitalLearningSolutions.Web.Tests/Controllers/LearningPortal/SelfAssessmentTests.cs

Lines changed: 181 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
using System.Collections.ObjectModel;
66
using System.Linq;
77
using DigitalLearningSolutions.Data.Models.SelfAssessments;
8-
using DigitalLearningSolutions.Data.Models.Supervisor;
9-
using DigitalLearningSolutions.Data.Models.User;
108
using DigitalLearningSolutions.Web.Tests.TestHelpers;
119
using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage;
1210
using DigitalLearningSolutions.Web.ViewModels.LearningPortal.Current;
@@ -274,7 +272,7 @@ public void SelfAssessmentCompetency_Post_Redirects_To_Next_Question()
274272
[Test]
275273
public void SelfAssessmentCompetency_Post_without_self_assessment_should_return_403()
276274
{
277-
var assessmentQuestion = new List<AssessmentQuestion>();
275+
var assessmentQuestion = new List<AssessmentQuestion>();
278276
// Given
279277
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
280278
.Returns(null);
@@ -423,6 +421,44 @@ public void SelfAssessmentOverview_Should_Return_View()
423421
.Model.Should().BeEquivalentTo(expectedModel);
424422
}
425423

424+
[Test]
425+
public void SelfAssessmentOverview_Should_Return_View_With_Optional_Competency()
426+
{
427+
// Given
428+
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
429+
var appliedFilterViewModel = new List<AppliedFilterViewModel>();
430+
var competencies = new List<Competency>
431+
{
432+
new Competency { CompetencyGroup = "A", Id = 1, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = true },
433+
new Competency { CompetencyGroup = "A", Id = 2, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = false },
434+
};
435+
var supervisorSignOffs = new List<SupervisorSignOff>();
436+
var expectedModel = new SelfAssessmentOverviewViewModel
437+
{
438+
SelfAssessment = selfAssessment,
439+
CompetencyGroups = competencies.GroupBy(competency => competency.CompetencyGroup),
440+
PreviousCompetencyNumber = 2,
441+
SupervisorSignOffs = supervisorSignOffs,
442+
SearchViewModel = new SearchSelfAssessmentOverviewViewModel("", SelfAssessmentId, selfAssessment.Vocabulary!, false, false, appliedFilterViewModel),
443+
AllQuestionsVerifiedOrNotRequired = true
444+
};
445+
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
446+
.Returns(selfAssessment);
447+
A.CallTo(() => selfAssessmentService.GetMostRecentResults(selfAssessment.Id, DelegateUserId))
448+
.Returns(competencies);
449+
450+
// When
451+
var result = controller.SelfAssessmentOverview(SelfAssessmentId, selfAssessment.Vocabulary!);
452+
453+
// Then
454+
result.Should().BeViewResult()
455+
.WithViewName("SelfAssessments/SelfAssessmentOverview")
456+
.Model.Should().BeEquivalentTo(expectedModel);
457+
458+
result.Should().BeViewResult().ModelAs<SelfAssessmentOverviewViewModel>().CompetencyGroups.ToList()[0].ToList()[0].Optional.Should().Be(true);
459+
result.Should().BeViewResult().ModelAs<SelfAssessmentOverviewViewModel>().CompetencyGroups.ToList()[0].ToList()[1].Optional.Should().Be(false);
460+
}
461+
426462
[Test]
427463
public void SelfAssessmentOverview_action_should_update_last_accessed()
428464
{
@@ -692,5 +728,147 @@ public void WithdrawSupervisorSignOffRequest_calls_remove_sign_off_and_defaults_
692728
.BeRedirectToActionResult()
693729
.WithActionName("SelfAssessmentOverview");
694730
}
731+
732+
[Test]
733+
public void ManageOptionalCompetencies_Should_Return_View_With_Flag()
734+
{
735+
// Given
736+
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
737+
var appliedFilterViewModel = new List<AppliedFilterViewModel>();
738+
var CompetencyFlags = new List<Data.Models.Frameworks.CompetencyFlag> { new Data.Models.Frameworks.CompetencyFlag { CompetencyId = 1, FlagId = 1, FlagGroup = "Purple", FlagName = "Supernumerary", FlagTagClass = "nhsuk-tag--purple", FrameworkId = 1, Selected = true }, };
739+
740+
var optionalCompetencies = new List<Competency>
741+
{
742+
new Competency { CompetencyGroup = "A", Id = 1, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = true },
743+
new Competency { CompetencyGroup = "A", Id = 2, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = true },
744+
};
745+
var competencyIds = optionalCompetencies.Select(c => c.Id).ToArray();
746+
var includedSelfAssessmentStructureIds = new List<int> { 1, 2 };
747+
748+
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
749+
.Returns(selfAssessment);
750+
A.CallTo(() => selfAssessmentService.GetCandidateAssessmentOptionalCompetencies(selfAssessment.Id, DelegateUserId))
751+
.Returns(optionalCompetencies);
752+
A.CallTo(() => frameworkService.GetSelectedCompetencyFlagsByCompetecyIds(A<int[]>.That.Matches(ids => ids.Length == 2 && ids[0] == 1 && ids[1] == 2)))
753+
.Returns(CompetencyFlags);
754+
A.CallTo(() => selfAssessmentService.GetCandidateAssessmentIncludedSelfAssessmentStructureIds(selfAssessment.Id, DelegateUserId))
755+
.Returns(includedSelfAssessmentStructureIds);
756+
757+
var model = new ManageOptionalCompetenciesViewModel
758+
{
759+
SelfAssessment = selfAssessment,
760+
CompetencyGroups = optionalCompetencies.GroupBy(competency => competency.CompetencyGroup),
761+
IncludedSelfAssessmentStructureIds = includedSelfAssessmentStructureIds
762+
};
763+
764+
// When
765+
var result = controller.ManageOptionalCompetencies(SelfAssessmentId);
766+
767+
// Then
768+
result.Should().BeViewResult()
769+
.WithViewName("SelfAssessments/ManageOptionalCompetencies")
770+
.Model.Should().BeEquivalentTo(model);
771+
772+
result.Should().BeViewResult().ModelAs<ManageOptionalCompetenciesViewModel>().CompetencyGroups?.ToList()[0].ToList()[0].CompetencyFlags.Count().Should().Be(1);
773+
result.Should().BeViewResult().ModelAs<ManageOptionalCompetenciesViewModel>().CompetencyGroups?.ToList()[0].ToList()[0].CompetencyFlags.ToList()[0].FlagName.Should().Be("Supernumerary");
774+
775+
result.Should().BeViewResult().ModelAs<ManageOptionalCompetenciesViewModel>().CompetencyGroups?.ToList()[0].ToList()[1].CompetencyFlags.Count().Should().Be(0);
776+
}
777+
778+
779+
[Test]
780+
public void SelfAssessmentOverview_Should_Return_View_With_All_Competencies()
781+
{
782+
// Given
783+
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
784+
var appliedFilterViewModel = new List<AppliedFilterViewModel>();
785+
var competencies = new List<Competency>
786+
{
787+
new Competency { CompetencyGroup = "A", Id = 1, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = true },
788+
new Competency { CompetencyGroup = "A", Id = 2, CompetencyGroupID = 1,SelfAssessmentStructureId=2, Optional = false },
789+
new Competency { CompetencyGroup = "A", Id = 3, CompetencyGroupID = 1,SelfAssessmentStructureId=3, Optional = false },
790+
};
791+
var supervisorSignOffs = new List<SupervisorSignOff>();
792+
var expectedModel = new SelfAssessmentOverviewViewModel
793+
{
794+
SelfAssessment = selfAssessment,
795+
CompetencyGroups = competencies.GroupBy(competency => competency.CompetencyGroup),
796+
PreviousCompetencyNumber = 3,
797+
SupervisorSignOffs = supervisorSignOffs,
798+
SearchViewModel = new SearchSelfAssessmentOverviewViewModel("", SelfAssessmentId, selfAssessment.Vocabulary!, false, false, appliedFilterViewModel),
799+
AllQuestionsVerifiedOrNotRequired = true
800+
};
801+
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
802+
.Returns(selfAssessment);
803+
A.CallTo(() => selfAssessmentService.GetMostRecentResults(selfAssessment.Id, DelegateUserId))
804+
.Returns(competencies);
805+
806+
// When
807+
var result = controller.SelfAssessmentOverview(SelfAssessmentId, selfAssessment.Vocabulary!);
808+
809+
// Then
810+
result.Should().BeViewResult()
811+
.WithViewName("SelfAssessments/SelfAssessmentOverview")
812+
.Model.Should().BeEquivalentTo(expectedModel);
813+
814+
result.Should().BeViewResult().ModelAs<SelfAssessmentOverviewViewModel>().CompetencyGroups.ToList()[0].Count().Should().Be(3);
815+
}
816+
817+
[Test]
818+
public void SelfAssessmentOverview_Should_Return_View_With_Optional_Filter_Applied()
819+
{
820+
// Given
821+
var selfAssessment = SelfAssessmentTestHelper.CreateDefaultSelfAssessment();
822+
var appliedFilterViewModel = new List<AppliedFilterViewModel>
823+
{
824+
new AppliedFilterViewModel{DisplayText = "Optional", FilterCategory = null!, FilterValue ="-4", TagClass = ""},
825+
};
826+
var search = new SearchSelfAssessmentOverviewViewModel
827+
{
828+
AppliedFilters = appliedFilterViewModel,
829+
SelfAssessmentId = SelfAssessmentId,
830+
Vocabulary = selfAssessment.Vocabulary!,
831+
SearchText = "",
832+
CompetencyFlags = null!,
833+
834+
};
835+
var competencies = new List<Competency>
836+
{
837+
new Competency { CompetencyGroup = "A", Id = 1, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = true },
838+
new Competency { CompetencyGroup = "A", Id = 2, CompetencyGroupID = 1,SelfAssessmentStructureId=2, Optional = false },
839+
new Competency { CompetencyGroup = "A", Id = 3, CompetencyGroupID = 1,SelfAssessmentStructureId=3, Optional = false },
840+
};
841+
var optionalCompetencies = new List<Competency>
842+
{
843+
new Competency { CompetencyGroup = "A", Id = 1, CompetencyGroupID = 1,SelfAssessmentStructureId=1, Optional = true },
844+
};
845+
var supervisorSignOffs = new List<SupervisorSignOff>();
846+
var expectedModel = new SelfAssessmentOverviewViewModel
847+
{
848+
SelfAssessment = selfAssessment,
849+
CompetencyGroups = optionalCompetencies.GroupBy(competency => competency.CompetencyGroup),
850+
PreviousCompetencyNumber = 1,
851+
SupervisorSignOffs = supervisorSignOffs,
852+
SearchViewModel = search,
853+
AllQuestionsVerifiedOrNotRequired = true,
854+
NumberOfOptionalCompetencies = 1,
855+
};
856+
A.CallTo(() => selfAssessmentService.GetSelfAssessmentForCandidateById(DelegateUserId, SelfAssessmentId))
857+
.Returns(selfAssessment);
858+
A.CallTo(() => selfAssessmentService.GetMostRecentResults(selfAssessment.Id, DelegateUserId))
859+
.Returns(competencies);
860+
A.CallTo(() => selfAssessmentService.GetCandidateAssessmentOptionalCompetencies(selfAssessment.Id, DelegateUserId))
861+
.Returns(optionalCompetencies);
862+
863+
// When
864+
var result = controller.SelfAssessmentOverview(SelfAssessmentId, selfAssessment.Vocabulary!, searchModel: search);
865+
866+
// Then
867+
result.Should().BeViewResult()
868+
.WithViewName("SelfAssessments/SelfAssessmentOverview")
869+
.Model.Should().BeEquivalentTo(expectedModel);
870+
871+
result.Should().BeViewResult().ModelAs<SelfAssessmentOverviewViewModel>().CompetencyGroups.ToList()[0].Count().Should().Be(1);
872+
}
695873
}
696874
}

0 commit comments

Comments
 (0)