From 408494967538cd95356e6d0c9029b70581ffd009 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 23 Jul 2021 10:00:31 +0100 Subject: [PATCH 1/6] DLSV2-83 Tweaks summary page title --- .../Views/Supervisor/EnrolDelegateSummary.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/EnrolDelegateSummary.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/EnrolDelegateSummary.cshtml index 9fc9fb2058..1418c50b72 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/EnrolDelegateSummary.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/EnrolDelegateSummary.cshtml @@ -38,7 +38,7 @@ -

Summary

+

Enrolment Summary

From c8126f0f2f56ca89635cd4228a0f1454461e7d81 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 23 Jul 2021 10:02:06 +0100 Subject: [PATCH 2/6] DLSV2-251 Fixes bug with remove query accidentally introduced with previous commit --- DigitalLearningSolutions.Data/Services/SupervisorService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Data/Services/SupervisorService.cs b/DigitalLearningSolutions.Data/Services/SupervisorService.cs index 51a4ff049f..1c175d99cd 100644 --- a/DigitalLearningSolutions.Data/Services/SupervisorService.cs +++ b/DigitalLearningSolutions.Data/Services/SupervisorService.cs @@ -414,7 +414,7 @@ FROM CandidateAssessments public bool RemoveCandidateAssessment(int candidateAssessmentId) { var numberOfAffectedRows = connection.Execute( - @"UPDATE CandidateAssessments SET RemovedDate = getUTCDate(), RemovalMethodID = 2, + @"UPDATE CandidateAssessments SET RemovedDate = getUTCDate(), RemovalMethodID = 2 WHERE ID = @candidateAssessmentId AND RemovedDate IS NULL", new { candidateAssessmentId }); if (numberOfAffectedRows < 1) From 77642a96966bc7916cc1cba0fd436e78396ab618 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 23 Jul 2021 10:24:42 +0100 Subject: [PATCH 3/6] DLSV2-274 Fixes form labelling To better distinguish from full profile assessment review --- .../Views/Supervisor/ReviewCompetencySelfAsessment.cshtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/ReviewCompetencySelfAsessment.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/ReviewCompetencySelfAsessment.cshtml index bd8ca580ac..197be0780d 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/ReviewCompetencySelfAsessment.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/ReviewCompetencySelfAsessment.cshtml @@ -46,7 +46,7 @@
-

Self Assessment Outcome

+

@Model.Competency.Vocabulary Self Assessment Result

@@ -134,7 +134,7 @@

- Review Self Assessment Outcome + Review @Model.Competency.Vocabulary Self Assessment Result

@@ -146,7 +146,7 @@
I agree with @Model.SupervisorDelegate.FirstName @Model.SupervisorDelegate.LastName's self-assessment against this @Model.Competency.Vocabulary.ToLower() From bdd50572b369ca547d0347b392c0a599c39cdc42 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 23 Jul 2021 16:12:48 +0100 Subject: [PATCH 4/6] DLSV2-86 Implements review multiple responses view Needs notification --- .../Services/SelfAssessmentService.cs | 22 ++++ .../SupervisorController/Supervisor.cs | 33 +++++- .../Shared/_AssessmentQuestionCells.cshtml | 15 +++ .../_AssessmentQuestionReviewCells.cshtml | 13 +-- .../Supervisor/VerifyMultipleResults.cshtml | 104 ++++++++++++++++++ 5 files changed, 174 insertions(+), 13 deletions(-) create mode 100644 DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionCells.cshtml create mode 100644 DigitalLearningSolutions.Web/Views/Supervisor/VerifyMultipleResults.cshtml diff --git a/DigitalLearningSolutions.Data/Services/SelfAssessmentService.cs b/DigitalLearningSolutions.Data/Services/SelfAssessmentService.cs index d3f97a5f3a..0e1268e44f 100644 --- a/DigitalLearningSolutions.Data/Services/SelfAssessmentService.cs +++ b/DigitalLearningSolutions.Data/Services/SelfAssessmentService.cs @@ -19,6 +19,7 @@ public interface ISelfAssessmentService void SetResultForCompetency(int competencyId, int selfAssessmentId, int candidateId, int assessmentQuestionId, int result, string? supportingComments); IEnumerable GetMostRecentResults(int selfAssessmentId, int candidateId); IEnumerable GetCandidateAssessmentResultsById(int candidateAssessmentId, int adminId); + IEnumerable GetCandidateAssessmentResultsForReviewById(int candidateAssessmentId, int adminId); Competency GetCompetencyByCandidateAssessmentResultId(int resultId, int candidateAssessmentId, int adminId); void UpdateLastAccessed(int selfAssessmentId, int candidateId); void SetSubmittedDateNow(int selfAssessmentId, int candidateId); @@ -340,6 +341,27 @@ public IEnumerable GetCandidateAssessmentResultsById(int candidateAs return groupedCompetency; }); } + public IEnumerable GetCandidateAssessmentResultsForReviewById(int candidateAssessmentId, int adminId) + { + var result = connection.Query( + $@"WITH {SpecificAssessmentResults} + SELECT {CompetencyFields} + FROM {SpecificCompetencyTables} + WHERE (LAR.Requested IS NOT NULL) AND (LAR.Verified IS NULL) AND (LAR.UserIsVerifier = 1)", + (competency, assessmentQuestion) => + { + competency.AssessmentQuestions.Add(assessmentQuestion); + return competency; + }, + param: new { candidateAssessmentId, adminId } + ); + return result.GroupBy(competency => competency.Id).Select(group => + { + var groupedCompetency = group.First(); + groupedCompetency.AssessmentQuestions = group.Select(competency => competency.AssessmentQuestions.Single()).ToList(); + return groupedCompetency; + }); + } public void UpdateLastAccessed(int selfAssessmentId, int candidateId) { diff --git a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs index 447066ec45..e4860ed2d4 100644 --- a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs +++ b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs @@ -189,7 +189,38 @@ public IActionResult SubmitReviewCompetencySelfAssessment(int supervisorDelegate }; return RedirectToAction("ReviewCompetencySelfAssessment", "Supervisor", new { supervisorDelegateId = supervisorDelegateId, candidateAssessmentId = candidateAssessmentId, viewMode = "View", resultId = resultId }); } - public IActionResult StartEnrolDelegateOnProfileAssessment(int supervisorDelegateId) + [Route("/Supervisor/Staff/{supervisorDelegateId}/ProfileAssessment/{candidateAssessmentId}/VerifyMultiple/")] + public IActionResult VerifyMultipleResults(int supervisorDelegateId, int candidateAssessmentId) + { + var adminId = GetAdminID(); + var superviseDelegate = supervisorService.GetSupervisorDelegateDetailsById(supervisorDelegateId); + var delegateSelfAssessment = supervisorService.GetSelfAssessmentBaseByCandidateAssessmentId(candidateAssessmentId); + var reviewedCompetencies = selfAssessmentService.GetCandidateAssessmentResultsForReviewById(candidateAssessmentId, adminId).ToList(); + var model = new ReviewSelfAssessmentViewModel() + { + SupervisorDelegateDetail = superviseDelegate, + DelegateSelfAssessment = delegateSelfAssessment, + CompetencyGroups = reviewedCompetencies.GroupBy(competency => competency.CompetencyGroup) + }; + return View("VerifyMultipleResults", model); + } + [HttpPost] + [Route("/Supervisor/Staff/{supervisorDelegateId}/ProfileAssessment/{candidateAssessmentId}/VerifyMultiple/")] + public IActionResult SubmitVerifyMultipleResults(int supervisorDelegateId, int candidateAssessmentId, List resultChecked) + { + int countResults = 0; + foreach (var result in resultChecked) + { + if (supervisorService.UpdateSelfAssessmentResultSupervisorVerifications(result, null, true, GetAdminID())) + { countResults += 1; } + } + if (countResults > 0) + { + //Send notification + } + return RedirectToAction("ReviewDelegateSelfAssessment", "Supervisor", new { supervisorDelegateId = supervisorDelegateId, candidateAssessmentId = candidateAssessmentId, viewMode = "Review" }); + } + public IActionResult StartEnrolDelegateOnProfileAssessment(int supervisorDelegateId) { TempData.Clear(); var sessionEnrolOnRoleProfile = new SessionEnrolOnRoleProfile(); diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionCells.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionCells.cshtml new file mode 100644 index 0000000000..af5ac37dac --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionCells.cshtml @@ -0,0 +1,15 @@ +@using DigitalLearningSolutions.Data.Models.SelfAssessments; +@model AssessmentQuestion + + + Questions + + + @Model.Question + + + + + Responses + + diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionReviewCells.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionReviewCells.cshtml index b7d4a62f64..16020f7e4b 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionReviewCells.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_AssessmentQuestionReviewCells.cshtml @@ -2,18 +2,7 @@ @model AssessmentQuestion - - Questions - - - @Model.Question - - - - - Responses - - + Questions diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/VerifyMultipleResults.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/VerifyMultipleResults.cshtml new file mode 100644 index 0000000000..6f6eabc2c3 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Supervisor/VerifyMultipleResults.cshtml @@ -0,0 +1,104 @@ +@using DigitalLearningSolutions.Web.ViewModels.Supervisor; +@model ReviewSelfAssessmentViewModel; +@{ + ViewData["Title"] = "Review Self Assessment"; + ViewData["Application"] = "Supervisor"; +} + + +@section NavMenuItems { + +} +@section NavBreadcrumbs { + +} +
+ +

+ @Model.SupervisorDelegateDetail.FirstName @Model.SupervisorDelegateDetail.LastName +

+
+
+ +
+
+

Sign-off Multiple Results for @Model.DelegateSelfAssessment.RoleName

+@if (Model.CompetencyGroups.Any()) +{ +

Tick each self assessment result that you wish to verify and sign-off and then click Submit

+
+ @foreach (var competencyGroup in Model.CompetencyGroups) + { + + + + + + + + + + + @foreach (var competency in competencyGroup) + { + @foreach (var question in competency.AssessmentQuestions) + { + + + + + + } + } + +

@competencyGroup.Key

+ @competencyGroup.First().Vocabulary + + Question + + Response +
+ @competency.Vocabulary +
+ + +
+
+ } +
+
+ + Cancel +
+
+
+} +else +{ +

+ Oops. There are no results awaiting sign-off. +

+ Cancel +} From 2092b792a747ed81cdf68db674406f47341ba938 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 23 Jul 2021 16:20:51 +0100 Subject: [PATCH 5/6] DLSV2-86 Nav to launch review multiple results --- .../Views/Supervisor/ReviewSelfAssessment.cshtml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/ReviewSelfAssessment.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/ReviewSelfAssessment.cshtml index 938185b4be..d250435b53 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/ReviewSelfAssessment.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/ReviewSelfAssessment.cshtml @@ -37,7 +37,21 @@
-

@Model.DelegateSelfAssessment.RoleName

+
+
+

@Model.DelegateSelfAssessment.RoleName

+
+
+ @if (Model.DelegateSelfAssessment.VerificationRequested > 0) + { + Review profile assessment + } + @if (Model.DelegateSelfAssessment.ResultsVerificationRequests > 1) + { + Verify multiple results + } +
+
@if (Model.CompetencyGroups.Any()) { foreach (var competencyGroup in Model.CompetencyGroups) From 535769ae644f9b78e6bb88e5861e113acf91ff40 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 23 Jul 2021 16:30:03 +0100 Subject: [PATCH 6/6] DLSV2-86 Adds user notification for multiple result sign off --- .../Services/FrameworkNotificationService.cs | 15 +++++++++++++++ .../SupervisorController/Supervisor.cs | 1 + 2 files changed, 16 insertions(+) diff --git a/DigitalLearningSolutions.Data/Services/FrameworkNotificationService.cs b/DigitalLearningSolutions.Data/Services/FrameworkNotificationService.cs index eb230772b9..511dfcbb99 100644 --- a/DigitalLearningSolutions.Data/Services/FrameworkNotificationService.cs +++ b/DigitalLearningSolutions.Data/Services/FrameworkNotificationService.cs @@ -20,6 +20,7 @@ public interface IFrameworkNotificationService void SendSupervisorResultReviewed(int adminId, int supervisorDelegateId, int candidateAssessmentId, int resultId); void SendSupervisorEnroledDelegate(int adminId, int supervisorDelegateId, int candidateAssessmentId, DateTime? completeByDate); void SendReminderDelegateSelfAssessment(int adminId, int supervisorDelegateId, int candidateAssessmentId); + void SendSupervisorMultipleResultsReviewed(int adminId, int supervisorDelegateId, int candidateAssessmentId, int countResults); } public class FrameworkNotificationService : IFrameworkNotificationService { @@ -291,5 +292,19 @@ public void SendReminderDelegateSelfAssessment(int adminId, int supervisorDelega builder.HtmlBody = $@"

Dear {supervisorDelegate.FirstName}

This is a reminder sent by your {delegateSelfAssessment.RoleName}, {supervisorDelegate.SupervisorName}, to complete the profile assessment '{delegateSelfAssessment.RoleName}' in the NHS Health Education England, Digital Learning Solutions platform.

Click here to access your {delegateSelfAssessment.RoleName} profile assessment.

"; emailService.SendEmail(new Email(emailSubjectLine, builder, supervisorDelegate.DelegateEmail)); } + + public void SendSupervisorMultipleResultsReviewed(int adminId, int supervisorDelegateId, int candidateAssessmentId, int countResults) + { + var supervisorDelegate = supervisorService.GetSupervisorDelegateDetailsById(supervisorDelegateId); + var delegateSelfAssessment = supervisorService.GetSelfAssessmentBaseByCandidateAssessmentId(candidateAssessmentId); + var selfAssessmentUrl = GetSelfAssessmentUrl(delegateSelfAssessment.SelfAssessmentID); + string emailSubjectLine = $"{delegateSelfAssessment.SupervisorRoleTitle} Signed-off {countResults} results - Digital Learning Solutions"; + var builder = new BodyBuilder(); + builder.TextBody = $@"Dear {supervisorDelegate.FirstName}, + {supervisorDelegate.SupervisorName} has signed-off {countResults} of your self assessment results against the {delegateSelfAssessment.RoleName} profile assessment in the NHS Health Education England, Digital Learning Solutions platform. + To access your {delegateSelfAssessment.RoleName} profile assessment, please visit {selfAssessmentUrl}."; + builder.HtmlBody = $@"

Dear {supervisorDelegate.FirstName}

{supervisorDelegate.SupervisorName} has signed-off {countResults} of your self assessment results against the {delegateSelfAssessment.RoleName} profile assessment in the NHS Health Education England, Digital Learning Solutions platform.

Click here to access your {delegateSelfAssessment.RoleName} profile assessment.

"; + emailService.SendEmail(new Email(emailSubjectLine, builder, supervisorDelegate.DelegateEmail)); + } } } diff --git a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs index e4860ed2d4..0a11f349ab 100644 --- a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs +++ b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs @@ -217,6 +217,7 @@ public IActionResult SubmitVerifyMultipleResults(int supervisorDelegateId, int c if (countResults > 0) { //Send notification + frameworkNotificationService.SendSupervisorMultipleResultsReviewed(GetAdminID(), supervisorDelegateId, candidateAssessmentId, countResults); } return RedirectToAction("ReviewDelegateSelfAssessment", "Supervisor", new { supervisorDelegateId = supervisorDelegateId, candidateAssessmentId = candidateAssessmentId, viewMode = "Review" }); }