diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs index d774c28509..f085dedccd 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs @@ -1,9 +1,5 @@ namespace DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService { - using System; - using System.Collections.Generic; - using System.Data; - using System.Linq; using Dapper; using DigitalLearningSolutions.Data.Models.Common.Users; using DigitalLearningSolutions.Data.Models.External.Filtered; @@ -11,6 +7,10 @@ using DigitalLearningSolutions.Data.Models.SelfAssessments; using DigitalLearningSolutions.Data.Models.SelfAssessments.Export; using Microsoft.Extensions.Logging; + using System; + using System.Collections.Generic; + using System.Data; + using System.Linq; public interface ISelfAssessmentDataService { @@ -171,6 +171,7 @@ int GetSelfAssessmentActivityDelegatesExportCount(string searchString, string so ActivitySummaryCompetencySelfAssesment? GetActivitySummaryCompetencySelfAssesment(int CandidateAssessmentSupervisorVerificationsId); bool IsUnsupervisedSelfAssessment(int selfAssessmentId); bool IsCentreSelfAssessment(int selfAssessmentId, int centreId); + bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId); } public partial class SelfAssessmentDataService : ISelfAssessmentDataService @@ -729,5 +730,24 @@ public bool IsCentreSelfAssessment(int selfAssessmentId, int centreId) ); return ResultCount > 0; } + + public bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId) + { + return connection.ExecuteScalar( + @"SELECT CASE WHEN COUNT(SAS.ID)>=(SELECT MinimumOptionalCompetencies FROM SelfAssessments WHERE ID = @selfAssessmentId) + THEN 1 ELSE 0 END AS HasMinimumOptionalCompetencies + FROM CandidateAssessmentOptionalCompetencies AS CAOC + INNER JOIN CandidateAssessments AS CA + ON CAOC.CandidateAssessmentID = CA.ID AND CA.SelfAssessmentID = @selfAssessmentId + AND CA.DelegateUserID = @delegateUserId AND CA.RemovedDate IS NULL + INNER JOIN SelfAssessmentStructure AS SAS + ON CAOC.CompetencyID = SAS.CompetencyID AND CAOC.CompetencyGroupID = SAS.CompetencyGroupID + AND SAS.SelfAssessmentID = @selfAssessmentId + INNER JOIN SelfAssessments AS SA + ON SAS.SelfAssessmentID = SA.ID + WHERE (CAOC.IncludedInSelfAssessment = 1)", + new { selfAssessmentId, delegateUserId } + ); + } } } diff --git a/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs b/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs index 94afc3a453..656918a4c7 100644 --- a/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs +++ b/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs @@ -1,13 +1,9 @@ namespace DigitalLearningSolutions.Web.Controllers.LearningPortalController { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Net; - using System.Text.Json; - using System.Threading.Tasks; using DigitalLearningSolutions.Data.Enums; + using DigitalLearningSolutions.Data.Helpers; using DigitalLearningSolutions.Data.Models.Centres; + using DigitalLearningSolutions.Data.Models.Common; using DigitalLearningSolutions.Data.Models.SearchSortFilterPaginate; using DigitalLearningSolutions.Data.Models.SelfAssessments; using DigitalLearningSolutions.Data.Models.SessionData.SelfAssessments; @@ -19,19 +15,19 @@ using DigitalLearningSolutions.Web.ViewModels.Common.SearchablePage; using DigitalLearningSolutions.Web.ViewModels.LearningPortal.Current; using DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments; - using Microsoft.AspNetCore.Mvc; - using Microsoft.Extensions.Logging; using GDS.MultiPageFormData.Enums; - using DigitalLearningSolutions.Data.Helpers; - using DigitalLearningSolutions.Web.Services; - using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.ViewDelegate; - using DocumentFormat.OpenXml.EMMA; - using DigitalLearningSolutions.Data.Models.Supervisor; - using DigitalLearningSolutions.Data.Models.Common; + using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; + using Microsoft.Extensions.Logging; + using System; + using System.Collections.Generic; using System.IO; + using System.Linq; + using System.Net; + using System.Text.Json; + using System.Threading.Tasks; public partial class LearningPortalController { @@ -426,6 +422,55 @@ public IActionResult AddSelfAssessmentOverviewFilter(SearchSelfAssessmentOvervie return RedirectToAction("FilteredSelfAssessmentGroups", model); } + [ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))] + [Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}/AddOptional")] + public IActionResult AddOptionalCompetencies(int selfAssessmentId, string vocabulary) + { + var delegateUserId = User.GetUserIdKnownNotNull(); + var assessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId); + if (assessment == null) + { + logger.LogWarning( + $"Attempt to display self assessment overview for user {delegateUserId} with no self assessment" + ); + return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); + } + + var optionalCompetencies = selfAssessmentService.GetCandidateAssessmentOptionalCompetencies(selfAssessmentId, delegateUserId); + if (optionalCompetencies.Any()) + { + if (!selfAssessmentService.HasMinimumOptionalCompetencies(selfAssessmentId, delegateUserId)) + { + var model = new AddOptionalCompetenciesViewModel { SelfAssessment = assessment }; + return View("SelfAssessments/AddOptionalCompetencies", model); + } + } + + return RedirectToAction("SelfAssessmentOverview", new { selfAssessmentId, vocabulary }); + } + + [HttpPost] + [Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}/AddOptional")] + public IActionResult AddOptionalCompetencies(AddOptionalCompetenciesViewModel test) + { + //var delegateUserId = User.GetUserIdKnownNotNull(); + //var selfAssessmentId = test.SelfAssessment.Id; + //var vocabulary = test.VocabPlural().ToString(); + + //var assessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, test.SelfAssessment.Id); + //if (assessment == null) + //{ + // logger.LogWarning( + // $"Attempt to display self assessment overview for user {delegateUserId} with no self assessment" + // ); + // return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); + //} + var a = 1; + var b = "2"; + + return RedirectToAction("SelfAssessmentOverview", new { a, b }); + } + [ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))] [Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}/{competencyGroupId}")] [Route("LearningPortal/SelfAssessment/{selfAssessmentId}/{vocabulary}")] @@ -479,7 +524,7 @@ public IActionResult SelfAssessmentOverview(int selfAssessmentId, string vocabul CompetencyGroups = competencies.GroupBy(competency => competency.CompetencyGroup), PreviousCompetencyNumber = Math.Max(competencies.Count(), 1), NumberOfOptionalCompetencies = optionalCompetencies.Count(), - NumberOfSelfAssessedOptionalCompetencies = optionalCompetencies.Count(x => x.IncludedInSelfAssessment ) , + NumberOfSelfAssessedOptionalCompetencies = optionalCompetencies.Count(x => x.IncludedInSelfAssessment), SupervisorSignOffs = supervisorSignOffs, SearchViewModel = searchViewModel }; @@ -495,6 +540,7 @@ public IActionResult SelfAssessmentOverview(int selfAssessmentId, string vocabul ViewBag.SupervisorSelfAssessmentReview = assessment.SupervisorSelfAssessmentReview; return View("SelfAssessments/SelfAssessmentOverview", model); } + [HttpPost] [ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))] [SetDlsSubApplication(nameof(DlsSubApplication.LearningPortal))] @@ -1440,8 +1486,9 @@ public IActionResult SubmitVerification() [ServiceFilter(typeof(IsCentreAuthorizedSelfAssessment))] [Route("/LearningPortal/SelfAssessment/{selfAssessmentId:int}/{vocabulary}/Optional")] - public IActionResult ManageOptionalCompetencies(int selfAssessmentId) + public IActionResult ManageOptionalCompetencies(int selfAssessmentId, string isFromAddOptional = null) { + ModelState.Remove("isFromAddOptional"); var delegateUserId = User.GetUserIdKnownNotNull(); var assessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId); var optionalCompetencies = @@ -1463,6 +1510,12 @@ public IActionResult ManageOptionalCompetencies(int selfAssessmentId) CompetencyGroups = optionalCompetencies.GroupBy(competency => competency.CompetencyGroup), IncludedSelfAssessmentStructureIds = includedSelfAssessmentStructureIds, }; + + if (!string.IsNullOrEmpty(isFromAddOptional)) + { + ViewBag.AddOptionalVocab = model.VocabPlural(); + } + return View("SelfAssessments/ManageOptionalCompetencies", model); } @@ -1645,15 +1698,15 @@ public IActionResult WithdrawSupervisorSignOffRequest( ); } - + [Route("/LearningPortal/selfAssessments/{CandidateAssessmentId:int}/{vocabulary}/Certificate")] public IActionResult CompetencySelfAssessmentCertificate(int CandidateAssessmentId, string vocabulary) { int supervisorDelegateId = 0; var adminId = User.GetAdminId(); - var competencymaindata = selfAssessmentService.GetCompetencySelfAssessmentCertificate(CandidateAssessmentId); - if ((competencymaindata == null)|| ( competencymaindata.LearnerId != User.GetUserIdKnownNotNull()) || (CandidateAssessmentId == 0)) + var competencymaindata = selfAssessmentService.GetCompetencySelfAssessmentCertificate(CandidateAssessmentId); + if ((competencymaindata == null) || (competencymaindata.LearnerId != User.GetUserIdKnownNotNull()) || (CandidateAssessmentId == 0)) { return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); } @@ -1661,7 +1714,7 @@ public IActionResult CompetencySelfAssessmentCertificate(int CandidateAssessment if (vocabulary == "Supervise") { var supervisorDelegateDetails = supervisorService.GetSupervisorDelegateDetailsForAdminId(adminId.Value); - var checkSupervisorDelegate = supervisorDelegateDetails.Where(x=> x.DelegateUserID == competencymaindata.LearnerId).FirstOrDefault(); + var checkSupervisorDelegate = supervisorDelegateDetails.Where(x => x.DelegateUserID == competencymaindata.LearnerId).FirstOrDefault(); if (checkSupervisorDelegate == null) { return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); diff --git a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs index cacd2f17b9..bd57735ed0 100644 --- a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs @@ -1,16 +1,14 @@ namespace DigitalLearningSolutions.Web.Services { - using System; - using System.Collections.Generic; - using System.Linq; - using AngleSharp.Attributes; using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService; - using DigitalLearningSolutions.Data.Models.Centres; using DigitalLearningSolutions.Data.Models.Common.Users; using DigitalLearningSolutions.Data.Models.External.Filtered; using DigitalLearningSolutions.Data.Models.Frameworks; using DigitalLearningSolutions.Data.Models.SelfAssessments; using DigitalLearningSolutions.Data.Models.SelfAssessments.Export; + using System; + using System.Collections.Generic; + using System.Linq; public interface ISelfAssessmentService { @@ -150,6 +148,7 @@ public int GetSelfAssessmentActivityDelegatesExportCount(string searchString, st bool IsUnsupervisedSelfAssessment(int selfAssessmentId); IEnumerable GetCandidateAssessments(int delegateUserId, int selfAssessmentId); bool IsCentreSelfAssessment(int selfAssessmentId, int centreId); + bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId); } @@ -554,5 +553,10 @@ public bool IsCentreSelfAssessment(int selfAssessmentId, int centreId) { return selfAssessmentDataService.IsCentreSelfAssessment(selfAssessmentId, centreId); } + + public bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId) + { + return selfAssessmentDataService.HasMinimumOptionalCompetencies(selfAssessmentId, delegateUserId); + } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/LearningPortal/SelfAssessments/AddOptionalCompetenciesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/LearningPortal/SelfAssessments/AddOptionalCompetenciesViewModel.cs new file mode 100644 index 0000000000..d8957898db --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/LearningPortal/SelfAssessments/AddOptionalCompetenciesViewModel.cs @@ -0,0 +1,14 @@ +using DigitalLearningSolutions.Data.Models.SelfAssessments; +using DigitalLearningSolutions.Web.Helpers; + +namespace DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments +{ + public class AddOptionalCompetenciesViewModel + { + public CurrentSelfAssessment SelfAssessment { get; set; } + public string VocabPlural() + { + return FrameworkVocabularyHelper.VocabularyPlural(SelfAssessment.Vocabulary); + } + } +} diff --git a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/AddOptionalCompetencies.cshtml b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/AddOptionalCompetencies.cshtml new file mode 100644 index 0000000000..6ec6d41a06 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/AddOptionalCompetencies.cshtml @@ -0,0 +1,56 @@ +@using DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments +@model AddOptionalCompetenciesViewModel +@{ + ViewData["Title"] = "Add optional " + Model.VocabPlural(); + Layout = "SelfAssessments/_Layout"; +} +@section breadcrumbs { +
  • + @(Model.SelfAssessment.Name) introduction +
  • +
  • Add optional @(Model.VocabPlural().ToLower())?
  • +} + +@section mobilebacklink +{ +

    + + Back to @Model.SelfAssessment.Name + +

    +} +
    +
    + +
    +

    Add optional proficiency to your assessment?

    +
    +
    +

    During your assessment you will need to add one or more optional proficiencies to your assessment to be certified within your role

    +
    + + + What are optional proficiencies? + + +
    +

    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.

    +

    These proficiencies might be different depending on your role or organisation, you may need to discuss this with your educator or manager.

    +
    +
    +

    These proficiencies might be different depending on your role or organization so you may need to discuss this with your educator or manager

    + + @* + Add optional @Model.VocabPlural().ToLower() to assessment + *@ + + Remind me later +
    +
    +
    diff --git a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/ManageOptionalCompetencies.cshtml b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/ManageOptionalCompetencies.cshtml index 7806c53130..6b820a6e12 100644 --- a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/ManageOptionalCompetencies.cshtml +++ b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/ManageOptionalCompetencies.cshtml @@ -1,13 +1,58 @@ @using DigitalLearningSolutions.Web.ViewModels.LearningPortal.SelfAssessments +@using DigitalLearningSolutions.Web.Extensions @model ManageOptionalCompetenciesViewModel @{ var errorHasOccurred = !ViewData.ModelState.IsValid; Layout = "SelfAssessments/_Layout"; ViewData["Title"] = "Self Assessment - Optional Proficiencies"; ViewData["SelfAssessmentTitle"] = @Model.SelfAssessment.Name; + if (ViewBag.AddOptionalVocab != null) + { + ViewData["FromAddOptionalPage"] = "true"; + } + var backLinkData = Html.GetRouteValues(); } -@section breadcrumbs { +@* @section breadcrumbs { +
  • + @(Model.SelfAssessment.Name) introduction +
  • + @if (ViewBag.AddOptionalVocab != null) + { +
  • + Add Optional @Model.VocabPlural().ToLower()? +
  • + } + else + { +
  • + @Model.VocabPlural() home +
  • + } + +
  • Manage optional @Model.VocabPlural()
  • +} *@ +@if (ViewBag.AddOptionalVocab != null) +{ + @* *@ + @section breadcrumbs { +
  • +
    + +
    + @* +
    < Go back
    +
    *@ +
  • + } +} +else +{ + @section breadcrumbs {
  • @(Model.SelfAssessment.Name) introduction
  • @@ -15,17 +60,33 @@ @Model.VocabPlural() home
  • Manage optional @Model.VocabPlural()
  • + } } + @section mobilebacklink { -

    - - Back to @Model.VocabPlural() - -

    + @if (ViewBag.AddOptionalVocab != null) + { +

    + + Back to add optional @Model.VocabPlural().ToLower()? + +

    + } + else + { +

    + + Back to @Model.VocabPlural() + +

    + } + } @@ -96,14 +157,28 @@ @section scripts { diff --git a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/SelfAssessmentDescription.cshtml b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/SelfAssessmentDescription.cshtml index b71095a9c8..d5c2dd92ca 100644 --- a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/SelfAssessmentDescription.cshtml +++ b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/SelfAssessmentDescription.cshtml @@ -17,7 +17,7 @@
  • @Model.Name introduction
  • } @section mobilebacklink - { +{

    Back to Current activities @@ -37,7 +37,7 @@

    } @@ -66,7 +66,7 @@ else } else { - View @Model.VocabPlural + View @Model.VocabPlural @if (Model.UserBookmark != null && bookmarkIsRelevant) { Continue where I left off diff --git a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/_Layout.cshtml b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/_Layout.cshtml index a96cfa0f6f..f025a64b32 100644 --- a/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/_Layout.cshtml +++ b/DigitalLearningSolutions.Web/Views/LearningPortal/SelfAssessments/_Layout.cshtml @@ -78,7 +78,10 @@