Skip to content

Commit 92d73e8

Browse files
committed
TD-4697-added AddOptionalCompetencies page. modified code to display this page when selected optional competencies less than minmum required
1 parent bbb9d4f commit 92d73e8

File tree

8 files changed

+210
-32
lines changed

8 files changed

+210
-32
lines changed

DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ int GetSelfAssessmentActivityDelegatesExportCount(string searchString, string so
171171
ActivitySummaryCompetencySelfAssesment? GetActivitySummaryCompetencySelfAssesment(int CandidateAssessmentSupervisorVerificationsId);
172172
bool IsUnsupervisedSelfAssessment(int selfAssessmentId);
173173
bool IsCentreSelfAssessment(int selfAssessmentId, int centreId);
174+
bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId);
174175
}
175176

176177
public partial class SelfAssessmentDataService : ISelfAssessmentDataService
@@ -729,5 +730,24 @@ public bool IsCentreSelfAssessment(int selfAssessmentId, int centreId)
729730
);
730731
return ResultCount > 0;
731732
}
733+
734+
public bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId)
735+
{
736+
return connection.ExecuteScalar<bool>(
737+
@"SELECT CASE WHEN COUNT(SAS.ID)>=(SELECT MinimumOptionalCompetencies FROM SelfAssessments WHERE ID = @selfAssessmentId)
738+
THEN 1 ELSE 0 END AS HasMinimumOptionalCompetencies
739+
FROM CandidateAssessmentOptionalCompetencies AS CAOC
740+
INNER JOIN CandidateAssessments AS CA
741+
ON CAOC.CandidateAssessmentID = CA.ID AND CA.SelfAssessmentID = @selfAssessmentId
742+
AND CA.DelegateUserID = @delegateUserId AND CA.RemovedDate IS NULL
743+
INNER JOIN SelfAssessmentStructure AS SAS
744+
ON CAOC.CompetencyID = SAS.CompetencyID AND CAOC.CompetencyGroupID = SAS.CompetencyGroupID
745+
AND SAS.SelfAssessmentID = @selfAssessmentId
746+
INNER JOIN SelfAssessments AS SA
747+
ON SAS.SelfAssessmentID = SA.ID
748+
WHERE (CAOC.IncludedInSelfAssessment = 1)",
749+
new { selfAssessmentId, delegateUserId }
750+
);
751+
}
732752
}
733753
}

DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
using Microsoft.Extensions.Logging;
2424
using GDS.MultiPageFormData.Enums;
2525
using DigitalLearningSolutions.Data.Helpers;
26-
using DigitalLearningSolutions.Web.Services;
27-
using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.ViewDelegate;
28-
using DocumentFormat.OpenXml.EMMA;
29-
using DigitalLearningSolutions.Data.Models.Supervisor;
3026
using DigitalLearningSolutions.Data.Models.Common;
3127
using Microsoft.AspNetCore.Mvc.Rendering;
3228
using Microsoft.AspNetCore.Mvc.ViewEngines;
@@ -426,6 +422,52 @@ public IActionResult AddSelfAssessmentOverviewFilter(SearchSelfAssessmentOvervie
426422
return RedirectToAction("FilteredSelfAssessmentGroups", model);
427423
}
428424

425+
[ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))]
426+
[Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}/AddOptional")]
427+
public IActionResult AddOptionalCompetencies(int selfAssessmentId, string vocabulary)
428+
{
429+
var delegateUserId = User.GetUserIdKnownNotNull();
430+
var assessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId);
431+
if (assessment == null)
432+
{
433+
logger.LogWarning(
434+
$"Attempt to display self assessment overview for user {delegateUserId} with no self assessment"
435+
);
436+
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
437+
}
438+
439+
var optionalCompetencies = selfAssessmentService.GetCandidateAssessmentOptionalCompetencies(selfAssessmentId, delegateUserId);
440+
if (optionalCompetencies.Any())
441+
{
442+
if (!selfAssessmentService.HasMinimumOptionalCompetencies(selfAssessmentId, delegateUserId))
443+
{
444+
var model = new AddOptionalCompetenciesViewModel { SelfAssessment = assessment };
445+
return View("SelfAssessments/AddOptionalCompetencies", model);
446+
}
447+
}
448+
449+
return RedirectToAction("SelfAssessmentOverview", new { selfAssessmentId, vocabulary });
450+
}
451+
452+
[HttpPost]
453+
[Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}/AddOptional")]
454+
public IActionResult AddOptionalCompetencies(string vocabulary, int selfAssessmentId)
455+
{
456+
var delegateUserId = User.GetUserIdKnownNotNull();
457+
var assessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId);
458+
if (assessment == null)
459+
{
460+
logger.LogWarning(
461+
$"Attempt to display self assessment overview for user {delegateUserId} with no self assessment"
462+
);
463+
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
464+
}
465+
466+
TempData["FromAddOptional"] = "true";
467+
468+
return RedirectToAction("ManageOptionalCompetencies", new { selfAssessmentId, vocabulary });
469+
}
470+
429471
[ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))]
430472
[Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}/{competencyGroupId}")]
431473
[Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}")]
@@ -479,7 +521,7 @@ public IActionResult SelfAssessmentOverview(int selfAssessmentId, string vocabul
479521
CompetencyGroups = competencies.GroupBy(competency => competency.CompetencyGroup),
480522
PreviousCompetencyNumber = Math.Max(competencies.Count(), 1),
481523
NumberOfOptionalCompetencies = optionalCompetencies.Count(),
482-
NumberOfSelfAssessedOptionalCompetencies = optionalCompetencies.Count(x => x.IncludedInSelfAssessment ) ,
524+
NumberOfSelfAssessedOptionalCompetencies = optionalCompetencies.Count(x => x.IncludedInSelfAssessment),
483525
SupervisorSignOffs = supervisorSignOffs,
484526
SearchViewModel = searchViewModel
485527
};
@@ -1463,6 +1505,13 @@ public IActionResult ManageOptionalCompetencies(int selfAssessmentId)
14631505
CompetencyGroups = optionalCompetencies.GroupBy(competency => competency.CompetencyGroup),
14641506
IncludedSelfAssessmentStructureIds = includedSelfAssessmentStructureIds,
14651507
};
1508+
1509+
if (TempData["FromAddOptional"] != null)
1510+
{
1511+
ViewBag.FromAddOptionalPage = "true";
1512+
TempData.Remove("FromAddOptional");
1513+
}
1514+
14661515
return View("SelfAssessments/ManageOptionalCompetencies", model);
14671516
}
14681517

@@ -1645,7 +1694,7 @@ public IActionResult WithdrawSupervisorSignOffRequest(
16451694
);
16461695
}
16471696

1648-
1697+
16491698
[Route("/LearningPortal/selfAssessments/{CandidateAssessmentId:int}/{vocabulary}/Certificate")]
16501699

16511700
public IActionResult CompetencySelfAssessmentCertificate(int CandidateAssessmentId, string vocabulary)
@@ -1654,12 +1703,12 @@ public IActionResult CompetencySelfAssessmentCertificate(int CandidateAssessment
16541703
var adminId = User.GetAdminId();
16551704
var userId = User.GetUserIdKnownNotNull();
16561705
var competencymaindata = selfAssessmentService.GetCompetencySelfAssessmentCertificate(CandidateAssessmentId);
1657-
if ((competencymaindata == null)|| ( competencymaindata.LearnerId != User.GetUserIdKnownNotNull()) || (CandidateAssessmentId == 0) || (userId != competencymaindata.LearnerId))
1706+
if ((competencymaindata == null) || (competencymaindata.LearnerId != User.GetUserIdKnownNotNull()) || (CandidateAssessmentId == 0) || (userId != competencymaindata.LearnerId))
16581707
{
16591708
return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
16601709
}
16611710
var delegateUserId = competencymaindata.LearnerId;
1662-
var recentResults = selfAssessmentService.GetMostRecentResults(competencymaindata.SelfAssessmentID, competencymaindata.LearnerDelegateAccountId).ToList();
1711+
var recentResults = selfAssessmentService.GetMostRecentResults(competencymaindata.SelfAssessmentID, competencymaindata.LearnerDelegateAccountId).ToList();
16631712
var supervisorSignOffs = selfAssessmentService.GetSupervisorSignOffsForCandidateAssessment(competencymaindata.SelfAssessmentID, delegateUserId);
16641713
if (!CertificateHelper.CanViewCertificate(recentResults, supervisorSignOffs))
16651714
{
@@ -1723,7 +1772,7 @@ public async Task<IActionResult> DownloadCertificate(int candidateAssessmentId,
17231772
if (vocabulary == "Proficiencies")
17241773
{
17251774
var userId = User.GetUserIdKnownNotNull();
1726-
if(userId != competencymaindata.LearnerId ) return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
1775+
if (userId != competencymaindata.LearnerId) return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 });
17271776

17281777
}
17291778
if (vocabulary == "ProfileAssessment")

DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6-
using AngleSharp.Attributes;
76
using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService;
8-
using DigitalLearningSolutions.Data.Models.Centres;
97
using DigitalLearningSolutions.Data.Models.Common.Users;
108
using DigitalLearningSolutions.Data.Models.External.Filtered;
119
using DigitalLearningSolutions.Data.Models.Frameworks;
@@ -150,6 +148,7 @@ public int GetSelfAssessmentActivityDelegatesExportCount(string searchString, st
150148
bool IsUnsupervisedSelfAssessment(int selfAssessmentId);
151149
IEnumerable<CandidateAssessment> GetCandidateAssessments(int delegateUserId, int selfAssessmentId);
152150
bool IsCentreSelfAssessment(int selfAssessmentId, int centreId);
151+
bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId);
153152

154153
}
155154

@@ -554,5 +553,10 @@ public bool IsCentreSelfAssessment(int selfAssessmentId, int centreId)
554553
{
555554
return selfAssessmentDataService.IsCentreSelfAssessment(selfAssessmentId, centreId);
556555
}
556+
557+
public bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId)
558+
{
559+
return selfAssessmentDataService.HasMinimumOptionalCompetencies(selfAssessmentId, delegateUserId);
560+
}
557561
}
558562
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using DigitalLearningSolutions.Data.Models.SelfAssessments;
2+
using DigitalLearningSolutions.Web.Helpers;
3+
4+
namespace DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments
5+
{
6+
public class AddOptionalCompetenciesViewModel
7+
{
8+
public CurrentSelfAssessment SelfAssessment { get; set; }
9+
public string VocabPlural()
10+
{
11+
return FrameworkVocabularyHelper.VocabularyPlural(SelfAssessment.Vocabulary);
12+
}
13+
}
14+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@using DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments
2+
@model AddOptionalCompetenciesViewModel
3+
@{
4+
ViewData["Title"] = "Add optional " + Model.VocabPlural().ToLower();
5+
Layout = "SelfAssessments/_Layout";
6+
}
7+
@section breadcrumbs {
8+
<li class="nhsuk-breadcrumb__item">
9+
<a class="nhsuk-breadcrumb__link" asp-action="SelfAssessment" asp-route-selfAssessmentId="@Model.SelfAssessment.Id">@(Model.SelfAssessment.Name) introduction</a>
10+
</li>
11+
<li class="nhsuk-breadcrumb__item">Add optional @(Model.VocabPlural().ToLower())?</li>
12+
}
13+
14+
@section mobilebacklink
15+
{
16+
<p class="nhsuk-breadcrumb__back">
17+
<a class="nhsuk-breadcrumb__backlink" asp-action="SelfAssessment"
18+
asp-route-selfAssessmentId="@Model.SelfAssessment.Id">
19+
Back to @Model.SelfAssessment.Name
20+
</a>
21+
</p>
22+
}
23+
<form method="post" asp-action="AddOptionalCompetencies" asp-route-selfAssessmentId="@Model.SelfAssessment.Id" asp-route-vocabulary="@Model.VocabPlural()">
24+
<div class="nhsuk-grid-row">
25+
<div class="nhsuk-grid-column-full">
26+
<h1 id="page-heading" class="nhsuk-heading-xl">Add optional proficiency to your assessment?</h1>
27+
</div>
28+
<div class="nhsuk-grid-column-two-thirds">
29+
<p class="nhsuk-u-padding-top-5">During your assessment you will need to add one or more optional proficiencies to your assessment to be certified within your role</p>
30+
<details class="nhsuk-details">
31+
<summary class="nhsuk-details__summary nhsuk-u-padding-10">
32+
<span class="nhsuk-u-margin-bottom-0">
33+
<span class="nhsuk-details__summary-text">What are optional proficiencies?</span>
34+
</span>
35+
</summary>
36+
<div class="nhsuk-details__text nhsuk-u-margin-left-6 nhsuk-u-margin-top-2">
37+
<p>Optional proficiencies refer to specific skills or competencies that are not part of the core requirements but may be added based on your role, specialisation, or the needs of your workplace.</p>
38+
</div>
39+
</details>
40+
<p class="nhsuk-u-padding-bottom-5">These proficiencies might be different depending on your role or organization so you may need to discuss this with your educator or manager</p>
41+
42+
<button class="nhsuk-button" type="submit">Add optional @Model.VocabPlural().ToLower() to assessment</button>
43+
<a class="nhsuk-button nhsuk-button--secondary trigger-loader" role="button" asp-action="SelfAssessmentOverview" asp-route-vocabulary="@Model.VocabPlural()" asp-route-selfAssessmentId="@Model.SelfAssessment.Id">Remind me later</a>
44+
</div>
45+
</div>
46+
</form>

DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/ManageOptionalCompetencies.cshtml

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,59 @@
11
@using DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments
2+
@using DigitalLearningSolutions.Web.Extensions
23
@model ManageOptionalCompetenciesViewModel
34
@{
45
var errorHasOccurred = !ViewData.ModelState.IsValid;
56
Layout = "SelfAssessments/_Layout";
67
ViewData["Title"] = "Self Assessment - Optional Proficiencies";
78
ViewData["SelfAssessmentTitle"] = @Model.SelfAssessment.Name;
9+
var backLinkData = Html.GetRouteValues();
810
}
9-
10-
@section breadcrumbs {
11+
@if (ViewBag.FromAddOptionalPage != null)
12+
{
13+
@section breadcrumbs {
14+
<li class="nhsuk-breadcrumb__item">
15+
<div style="max-height:10px">
16+
<vc:back-link asp-controller="LearningPortal" asp-action="AddOptionalCompetencies" asp-all-route-data="@backLinkData" link-text="Go back" />
17+
</div>
18+
</li>
19+
}
20+
}
21+
else
22+
{
23+
@section breadcrumbs {
1124
<li class="nhsuk-breadcrumb__item">
1225
<a class="nhsuk-breadcrumb__link" asp-action="SelfAssessment" asp-route-selfAssessmentId="@Model.SelfAssessment.Id">@(Model.SelfAssessment.Name) introduction</a>
1326
</li>
1427
<li class="nhsuk-breadcrumb__item">
1528
<a class="nhsuk-breadcrumb__link" asp-action="SelfAssessmentOverview" asp-route-vocabulary="@Model.VocabPlural()" asp-route-selfAssessmentId="@Model.SelfAssessment.Id">@Model.VocabPlural() home</a>
1629
</li>
1730
<li class="nhsuk-breadcrumb__item">Manage optional @Model.VocabPlural()</li>
31+
}
1832
}
1933

34+
2035
@section mobilebacklink
2136
{
22-
<p class="nhsuk-breadcrumb__back">
23-
<a class="nhsuk-breadcrumb__backlink" asp-action="SelfAssessmentOverview"
24-
asp-route-vocabulary="@Model.VocabPlural()"
25-
asp-route-selfAssessmentId="@Model.SelfAssessment.Id">
26-
Back to @Model.VocabPlural()
27-
</a>
28-
</p>
37+
@if (ViewBag.FromAddOptionalPage != null)
38+
{
39+
<p class="nhsuk-breadcrumb__back">
40+
<a class="nhsuk-breadcrumb__backlink" asp-action="AddOptionalCompetencies"
41+
asp-route-vocabulary="@Model.VocabPlural()"
42+
asp-route-selfAssessmentId="@Model.SelfAssessment.Id">
43+
Back to add optional @Model.VocabPlural().ToLower()?
44+
</a>
45+
</p>
46+
}
47+
else
48+
{
49+
<p class="nhsuk-breadcrumb__back">
50+
<a class="nhsuk-breadcrumb__backlink" asp-action="SelfAssessmentOverview"
51+
asp-route-vocabulary="@Model.VocabPlural()"
52+
asp-route-selfAssessmentId="@Model.SelfAssessment.Id">
53+
Back to @Model.VocabPlural()
54+
</a>
55+
</p>
56+
}
2957
}
3058

3159
<link rel="stylesheet" href="@Url.Content("~/css/learningPortal/selfAssessment.css")" asp-append-version="true">
@@ -96,14 +124,28 @@
96124
</form>
97125

98126
<div class="nhsuk-back-link">
99-
<a class="nhsuk-back-link__link"
100-
asp-action="SelfAssessmentOverview"
101-
asp-route-selfAssessmentId="@Model.SelfAssessment.Id" asp-route-vocabulary="@Model.VocabPlural()">
102-
<svg class="nhsuk-icon nhsuk-icon__chevron-left" focusable='false' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
103-
<path d="M13.41 12l5.3-5.29a1 1 0 1 0-1.42-1.42L12 10.59l-5.29-5.3a1 1 0 0 0-1.42 1.42l5.3 5.29-5.3 5.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l5.29-5.3 5.29 5.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"></path>
104-
</svg>
105-
Cancel
106-
</a>
127+
@if (ViewBag.FromAddOptionalPage != null)
128+
{
129+
<a class="nhsuk-back-link__link"
130+
asp-action="AddOptionalCompetencies"
131+
asp-route-selfAssessmentId="@Model.SelfAssessment.Id" asp-route-vocabulary="@Model.VocabPlural()">
132+
<svg class="nhsuk-icon nhsuk-icon__chevron-left" focusable='false' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
133+
<path d="M13.41 12l5.3-5.29a1 1 0 1 0-1.42-1.42L12 10.59l-5.29-5.3a1 1 0 0 0-1.42 1.42l5.3 5.29-5.3 5.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l5.29-5.3 5.29 5.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"></path>
134+
</svg>
135+
Cancel
136+
</a>
137+
}
138+
else
139+
{
140+
<a class="nhsuk-back-link__link"
141+
asp-action="SelfAssessmentOverview"
142+
asp-route-selfAssessmentId="@Model.SelfAssessment.Id" asp-route-vocabulary="@Model.VocabPlural()">
143+
<svg class="nhsuk-icon nhsuk-icon__chevron-left" focusable='false' xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
144+
<path d="M13.41 12l5.3-5.29a1 1 0 1 0-1.42-1.42L12 10.59l-5.29-5.3a1 1 0 0 0-1.42 1.42l5.3 5.29-5.3 5.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l5.29-5.3 5.29 5.3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"></path>
145+
</svg>
146+
Cancel
147+
</a>
148+
}
107149
</div>
108150

109151
@section scripts {

DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/SelfAssessmentDescription.cshtml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<li class="nhsuk-breadcrumb__item">@Model.Name introduction</li>
1818
}
1919
@section mobilebacklink
20-
{
20+
{
2121
<p class="nhsuk-breadcrumb__back">
2222
<a class="nhsuk-breadcrumb__link trigger-loader" asp-action="Current">
2323
Back to Current activities
@@ -37,7 +37,7 @@
3737
</div>
3838
<div class="nhsuk-grid-column-one-third">
3939
<partial name="Shared/_SupervisorsCard"
40-
model="@Model.Supervisors" />
40+
model="@Model.Supervisors" />
4141
</div>
4242
</div>
4343
}
@@ -66,7 +66,7 @@ else
6666
}
6767
else
6868
{
69-
<a class="nhsuk-button trigger-loader" role="button" asp-action="SelfAssessmentOverview" asp-route-vocabulary="@Model.VocabPlural" asp-route-selfAssessmentId="@Model.Id">View @Model.VocabPlural</a>
69+
<a class="nhsuk-button trigger-loader" role="button" asp-action="AddOptionalCompetencies" asp-route-vocabulary="@Model.VocabPlural" asp-route-selfAssessmentId="@Model.Id">View @Model.VocabPlural</a>
7070
@if (Model.UserBookmark != null && bookmarkIsRelevant)
7171
{
7272
<a role="button" class="nhsuk-button nhsuk-button--secondary trigger-loader" href="@Configuration["AppRootPath"]@Model.UserBookmark">Continue where I left off</a>

0 commit comments

Comments
 (0)