diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index 2a7fc8723b..983bdba073 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -23,13 +23,15 @@ public interface ICompetencyAssessmentDataService CompetencyAssessmentBase? GetCompetencyAssessmentBaseByName(string competencyAssessmentName, int adminId); CompetencyAssessment? GetCompetencyAssessmentById(int competencyAssessmentId, int adminId); IEnumerable GetNRPProfessionalGroups(); + IEnumerable GetNRPSubGroups(int? nRPProfessionalGroupID); + IEnumerable GetNRPRoles(int? nRPSubGroupID); CompetencyAssessmentTaskStatus GetOrInsertAndReturnAssessmentTaskStatus(int assessmentId, bool frameworkBased); //UPDATE DATA bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int adminId, string competencyAssessmentName); - bool UpdateCompetencyAssessmentProfessionalGroup(int competencyAssessmentId, int adminId, int? nrpProfessionalGroupID); + bool UpdateCompetencyRoleProfileLinks(int competencyAssessmentId, int adminId, int? professionalGroupId, int? subGroupId, int? roleId); bool UpdateCompetencyAssessmentBranding( int competencyAssessmentId, int adminId, @@ -41,6 +43,7 @@ int categoryId bool UpdateIntroductoryTextTaskStatus(int assessmentId, bool taskStatus); bool UpdateBrandingTaskStatus(int assessmentId, bool taskStatus); bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus); + bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus); //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName); bool InsertSelfAssessmentFramework(int adminId, int selfAssessmentId, int frameworkId); @@ -225,11 +228,11 @@ ORDER BY ProfessionalGroup" ).FirstOrDefault(); } - public bool UpdateCompetencyAssessmentProfessionalGroup(int competencyAssessmentId, int adminId, int? nrpProfessionalGroupID) + public bool UpdateCompetencyRoleProfileLinks(int competencyAssessmentId, int adminId, int? professionalGroupId, int? subGroupId, int? roleId) { var result = connection.ExecuteScalar( - @"SELECT COUNT(*) FROM CompetencyAssessments WHERE ID = @competencyAssessmentId AND NRPProfessionalGroupID = @nrpProfessionalGroupID", - new { competencyAssessmentId, nrpProfessionalGroupID } + @"SELECT COUNT(*) FROM SelfAssessments WHERE ID = @competencyAssessmentId AND NRPProfessionalGroupID = @professionalGroupId AND NRPSubGroupID = @subGroupId AND NRPRoleID = @roleId", + new { competencyAssessmentId, professionalGroupId, subGroupId, roleId } ); int sameCount = Convert.ToInt32(result); if (sameCount > 0) @@ -240,9 +243,9 @@ public bool UpdateCompetencyAssessmentProfessionalGroup(int competencyAssessment //needs updating: var numberOfAffectedRows = connection.Execute( - @"UPDATE SelfAssessments SET NRPProfessionalGroupID = @nrpProfessionalGroupID, NRPSubGroupID = NULL, NRPRoleID = NULL, UpdatedByAdminID = @adminId + @"UPDATE SelfAssessments SET NRPProfessionalGroupID = @professionalGroupId, NRPSubGroupID = @subGroupId, NRPRoleID = @roleId, UpdatedByAdminID = @adminId WHERE ID = @competencyAssessmentId", - new { nrpProfessionalGroupID, adminId, competencyAssessmentId } + new { adminId, competencyAssessmentId, professionalGroupId, subGroupId, roleId } ); if (numberOfAffectedRows > 0) { @@ -418,5 +421,43 @@ public bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus) } return true; } + + public IEnumerable GetNRPSubGroups(int? nRPProfessionalGroupID) + { + return connection.Query( + @"SELECT ID, SubGroup, Active + FROM NRPSubGroups + WHERE (Active = 1) AND (NRPProfessionalGroupID = @nRPProfessionalGroupID) + ORDER BY SubGroup", new { nRPProfessionalGroupID } + ); + } + + public IEnumerable GetNRPRoles(int? nRPSubGroupID) + { + return connection.Query( + @"SELECT ID, RoleProfile AS ProfileName, Active + FROM NRPRoles + WHERE (Active = 1) AND (NRPSubGroupID = @nRPSubGroupID) + ORDER BY RoleProfile", new { nRPSubGroupID } + ); + } + + public bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus) + { + var numberOfAffectedRows = connection.Execute( + @"UPDATE SelfAssessmentTaskStatus SET NationalRoleProfileTaskStatus = @taskStatus + WHERE SelfAssessmentId = @assessmentId", + new { assessmentId, taskStatus } + ); + if (numberOfAffectedRows < 1) + { + logger.LogWarning( + "Not updating NationalRoleProfileTaskStatus as db update failed. " + + $"assessmentId: {assessmentId}, taskStatus: {taskStatus}" + ); + return false; + } + return true; + } } } diff --git a/DigitalLearningSolutions.Data/DataServices/CourseCategoriesDataService.cs b/DigitalLearningSolutions.Data/DataServices/CourseCategoriesDataService.cs index 1135172708..ad6e96166c 100644 --- a/DigitalLearningSolutions.Data/DataServices/CourseCategoriesDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CourseCategoriesDataService.cs @@ -9,7 +9,7 @@ public interface ICourseCategoriesDataService { IEnumerable GetCategoriesForCentreAndCentrallyManagedCourses(int centreId); - string? GetCourseCategoryName(int categoryId); + string? GetCourseCategoryName(int? categoryId); } public class CourseCategoriesDataService : ICourseCategoriesDataService @@ -34,7 +34,7 @@ FROM CourseCategories ); } - public string? GetCourseCategoryName(int categoryId) + public string? GetCourseCategoryName(int? categoryId) { var name = connection.QueryFirstOrDefault( @"SELECT CategoryName diff --git a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs index fee4f1b696..06196293a0 100644 --- a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs @@ -551,7 +551,7 @@ BEGIN TRANSACTION UPDATE CandidateAssessmentSupervisors SET Removed = NULL {((selfAssessmentSupervisorRoleId > 0) ? " ,SelfAssessmentSupervisorRoleID = @selfAssessmentSupervisorRoleID" : string.Empty)} - WHERE CandidateAssessmentID = @candidateAssessmentId AND SupervisorDelegateId = @supervisorDelegateId + WHERE CandidateAssessmentID = @candidateAssessmentId AND SupervisorDelegateId = @supervisorDelegateId AND SelfAssessmentSupervisorRoleID = @selfAssessmentSupervisorRoleID COMMIT TRANSACTION"; diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs index 2390d54147..bb1dc7649f 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs @@ -298,6 +298,13 @@ INNER JOIN CompetencyGroups AS CG } } + public void RemoveSignoffRequestById(int candidateAssessmentSupervisorVerificationsId) + { + var numberOfAffectedRows = connection.Execute( + @" DELETE FROM CandidateAssessmentSupervisorVerifications WHERE ID = @candidateAssessmentSupervisorVerificationsId ", + new { candidateAssessmentSupervisorVerificationsId }); + } + public void SetCompleteByDate(int selfAssessmentId, int delegateUserId, DateTime? completeByDate) { diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CompetencyDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CompetencyDataService.cs index 76a1a199bd..3c333e78e8 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CompetencyDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CompetencyDataService.cs @@ -635,7 +635,7 @@ FROM SelfAssessmentResults s inner join SelfAssessmentResultSupervisorVerifications sv ON s.ID = sv.SelfAssessmentResultId AND sv.Superceded = 0 WHERE s.CompetencyID = @competencyId AND s.SelfAssessmentID = @selfAssessmentId - AND s.DelegateUserID = @delegateUserId", + AND s.DelegateUserID = @delegateUserId AND sv.Verified IS NULL", new { selfAssessmentId, delegateUserId, competencyId } ); } @@ -643,8 +643,6 @@ FROM SelfAssessmentResults s inner join public void RemoveReviewCandidateAssessmentOptionalCompetencies(int id) { - connection.Execute(@"UPDATE SelfAssessmentResults SET Result = NULL WHERE ID = @id", new { id}); - connection.Execute( @"delete from SelfAssessmentResultSupervisorVerifications WHERE SelfAssessmentResultId = @id", new { id }); diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs index d4b87c6f78..324a1050a7 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs @@ -78,6 +78,7 @@ int competencyId void UpdateLastAccessed(int selfAssessmentId, int delegateUserId); void RemoveSignoffRequests(int selfAssessmentId, int delegateUserId, int competencyGroupsId); + void RemoveSignoffRequestById(int candidateAssessmentSupervisorVerificationsId); void SetCompleteByDate(int selfAssessmentId, int delegateUserId, DateTime? completeByDate); void SetSubmittedDateNow(int selfAssessmentId, int delegateUserId); @@ -173,7 +174,7 @@ int GetSelfAssessmentActivityDelegatesExportCount(string searchString, string so bool IsCentreSelfAssessment(int selfAssessmentId, int centreId); bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId); int GetSelfAssessmentCategoryId(int selfAssessmentId); - void RemoveReviewCandidateAssessmentOptionalCompetencies(int id); + void RemoveReviewCandidateAssessmentOptionalCompetencies(int id); public IEnumerable GetSelfAssessmentResultswithSupervisorVerificationsForDelegateSelfAssessmentCompetency( int delegateUserId, int selfAssessmentId, @@ -683,9 +684,6 @@ BEGIN TRANSACTION UPDATE CandidateAssessments SET RemovedDate = GETUTCDATE(), RemovalMethodID = 2 WHERE ID = @candidateAssessmentsId AND RemovedDate IS NULL - UPDATE CandidateAssessmentSupervisors SET Removed = GETUTCDATE() - WHERE CandidateAssessmentID = @candidateAssessmentsId AND Removed IS NULL - COMMIT TRANSACTION END TRY BEGIN CATCH diff --git a/DigitalLearningSolutions.Data/DataServices/SupervisorDataService.cs b/DigitalLearningSolutions.Data/DataServices/SupervisorDataService.cs index c97ecf67a8..3409396ab1 100644 --- a/DigitalLearningSolutions.Data/DataServices/SupervisorDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SupervisorDataService.cs @@ -620,20 +620,21 @@ FROM CandidateAssessmentSupervisors AS cas INNER JOIN { return connection.Query( @$"SELECT ca.ID, sa.ID AS SelfAssessmentID, sa.Name AS RoleName, sa.QuestionLabel, sa.DescriptionLabel, sa.ReviewerCommentsLabel, - sa.SupervisorSelfAssessmentReview, sa.SupervisorResultsReview, ca.StartedDate, - COALESCE(ca.LastAccessed, ca.StartedDate) AS LastAccessed, - ca.CompleteByDate, ca.LaunchCount, ca.CompletedDate, - (SELECT COUNT(*) AS Expr1 - FROM CandidateAssessmentSupervisorVerifications AS casv - WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Requested IS NOT NULL) AND (Verified IS NULL)) AS SignOffRequested, - {signedOffFields} - (SELECT COUNT(*) AS Expr1 - FROM SelfAssessmentResultSupervisorVerifications AS sarsv - WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Verified IS NULL) AND (sarsv.Superceded = 0)) AS ResultsVerificationRequests - FROM CandidateAssessmentSupervisors AS cas INNER JOIN - CandidateAssessments AS ca ON cas.CandidateAssessmentID = ca.ID INNER JOIN - SelfAssessments AS sa ON sa.ID = ca.SelfAssessmentID - WHERE (ca.ID = @candidateAssessmentId) AND (ISNULL(@adminIdCategoryID, 0) = 0 OR sa.CategoryID = @adminIdCategoryId)", new { candidateAssessmentId, adminIdCategoryId } + sa.SupervisorSelfAssessmentReview, sa.SupervisorResultsReview, ca.StartedDate, + COALESCE(ca.LastAccessed, ca.StartedDate) AS LastAccessed, + ca.CompleteByDate, ca.LaunchCount, ca.CompletedDate, + (SELECT COUNT(*) AS Expr1 + FROM CandidateAssessmentSupervisorVerifications AS casv + WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Requested IS NOT NULL) AND (Verified IS NULL)) AS SignOffRequested, + {signedOffFields} + (SELECT COUNT(*) AS Expr1 + FROM SelfAssessmentResultSupervisorVerifications AS sarsv + WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Verified IS NULL) AND (sarsv.Superceded = 0)) AS ResultsVerificationRequests, + sa.Vocabulary + FROM CandidateAssessmentSupervisors AS cas INNER JOIN + CandidateAssessments AS ca ON cas.CandidateAssessmentID = ca.ID INNER JOIN + SelfAssessments AS sa ON sa.ID = ca.SelfAssessmentID + WHERE (ca.ID = @candidateAssessmentId) AND (ISNULL(@adminIdCategoryID, 0) = 0 OR sa.CategoryID = @adminIdCategoryId)", new { candidateAssessmentId, adminIdCategoryId } ).FirstOrDefault(); } public DelegateSelfAssessment? GetSelfAssessmentBySupervisorDelegateCandidateAssessmentId(int candidateAssessmentId, int supervisorDelegateId) @@ -695,24 +696,25 @@ FROM SelfAssessmentResults AS sar2 public DelegateSelfAssessment? GetSelfAssessmentByCandidateAssessmentId(int candidateAssessmentId, int adminId, int? adminIdCategoryId) { return connection.Query( - @$"SELECT ca.ID, sa.ID AS SelfAssessmentID, sa.Name AS RoleName, sa.SupervisorSelfAssessmentReview, sa.SupervisorResultsReview, sa.ReviewerCommentsLabel, COALESCE (sasr.RoleName, 'Supervisor') AS SupervisorRoleTitle, ca.StartedDate, ca.LastAccessed, ca.CompleteByDate, ca.LaunchCount, ca.CompletedDate, r.CompetencyAssessment, sg.SubGroup, pg.ProfessionalGroup, sa.SupervisorResultsReview AS IsSupervisorResultsReviewed, - (SELECT COUNT(*) AS Expr1 - FROM CandidateAssessmentSupervisorVerifications AS casv - WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Requested IS NOT NULL) AND (Verified IS NULL)) AS SignOffRequested, - {signedOffFields} - (SELECT COUNT(*) AS Expr1 - FROM SelfAssessmentResultSupervisorVerifications AS sarsv - WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Verified IS NULL) AND (Superceded = 0)) AS ResultsVerificationRequests, - ca.NonReportable,ca.DelegateUserID + @$"SELECT ca.ID, sa.ID AS SelfAssessmentID, sa.Name AS RoleName, sa.SupervisorSelfAssessmentReview, sa.SupervisorResultsReview, sa.ReviewerCommentsLabel, COALESCE (sasr.RoleName, 'Supervisor') AS SupervisorRoleTitle, ca.StartedDate, ca.LastAccessed, ca.CompleteByDate, ca.LaunchCount, ca.CompletedDate, r.RoleProfile, sg.SubGroup, pg.ProfessionalGroup, sa.SupervisorResultsReview AS IsSupervisorResultsReviewed, + (SELECT COUNT(*) AS Expr1 + FROM CandidateAssessmentSupervisorVerifications AS casv + WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Requested IS NOT NULL) AND (Verified IS NULL)) AS SignOffRequested, + {signedOffFields} + (SELECT COUNT(*) AS Expr1 + FROM SelfAssessmentResultSupervisorVerifications AS sarsv + WHERE (CandidateAssessmentSupervisorID = cas.ID) AND (Verified IS NULL) AND (Superceded = 0)) AS ResultsVerificationRequests, + ca.NonReportable,ca.DelegateUserID, + sa.Vocabulary FROM CandidateAssessmentSupervisors AS cas INNER JOIN - CandidateAssessments AS ca ON cas.CandidateAssessmentID = ca.ID INNER JOIN - SelfAssessments AS sa ON sa.ID = ca.SelfAssessmentID INNER JOIN - SupervisorDelegates AS sd ON cas.SupervisorDelegateId = sd.ID LEFT OUTER JOIN - NRPProfessionalGroups AS pg ON sa.NRPProfessionalGroupID = pg.ID LEFT OUTER JOIN - NRPSubGroups AS sg ON sa.NRPSubGroupID = sg.ID LEFT OUTER JOIN - NRPRoles AS r ON sa.NRPRoleID = r.ID - LEFT OUTER JOIN SelfAssessmentSupervisorRoles AS sasr ON cas.SelfAssessmentSupervisorRoleID = sasr.ID - WHERE (ca.ID = @candidateAssessmentId) AND (cas.Removed IS NULL) AND (sd.SupervisorAdminID = @adminId) AND (ISNULL(@adminIdCategoryID, 0) = 0 OR sa.CategoryID = @adminIdCategoryId)", + CandidateAssessments AS ca ON cas.CandidateAssessmentID = ca.ID INNER JOIN + SelfAssessments AS sa ON sa.ID = ca.SelfAssessmentID INNER JOIN + SupervisorDelegates AS sd ON cas.SupervisorDelegateId = sd.ID LEFT OUTER JOIN + NRPProfessionalGroups AS pg ON sa.NRPProfessionalGroupID = pg.ID LEFT OUTER JOIN + NRPSubGroups AS sg ON sa.NRPSubGroupID = sg.ID LEFT OUTER JOIN + NRPRoles AS r ON sa.NRPRoleID = r.ID + LEFT OUTER JOIN SelfAssessmentSupervisorRoles AS sasr ON cas.SelfAssessmentSupervisorRoleID = sasr.ID + WHERE (ca.ID = @candidateAssessmentId) AND (cas.Removed IS NULL) AND (sd.SupervisorAdminID = @adminId) AND (ISNULL(@adminIdCategoryID, 0) = 0 OR sa.CategoryID = @adminIdCategoryId)", new { candidateAssessmentId, adminId, adminIdCategoryId } ).FirstOrDefault(); } @@ -941,18 +943,45 @@ FROM CandidateAssessmentSupervisors if (candidateAssessmentSupervisorsId == 0) { + //For a candidate assessment, only one supervisor role should be active (Removed = null) var numberOfAffectedRows = connection.Execute( - @"INSERT INTO CandidateAssessmentSupervisors (CandidateAssessmentID, SupervisorDelegateId, SelfAssessmentSupervisorRoleID) - VALUES (@candidateAssessmentId, @supervisorDelegateId, @selfAssessmentSupervisorRoleId)", new { candidateAssessmentId, supervisorDelegateId, selfAssessmentSupervisorRoleId } + @"BEGIN TRY + BEGIN TRANSACTION + UPDATE CandidateAssessmentSupervisors SET Removed = getUTCDate() WHERE CandidateAssessmentID = @candidateAssessmentId + AND SupervisorDelegateId = @supervisorDelegateId + AND Removed IS NULL + + INSERT INTO CandidateAssessmentSupervisors (CandidateAssessmentID, SupervisorDelegateId, SelfAssessmentSupervisorRoleID) + VALUES (@candidateAssessmentId, @supervisorDelegateId, @selfAssessmentSupervisorRoleId) + + COMMIT TRANSACTION + END TRY + BEGIN CATCH + ROLLBACK TRANSACTION + END CATCH", + new { candidateAssessmentId, supervisorDelegateId, selfAssessmentSupervisorRoleId } ); } else { + //For a candidate assessment, only one supervisor role should be active (Removed = null) int numberOfAffectedRows = connection.Execute( - @"UPDATE CandidateAssessmentSupervisors SET Removed = NULL WHERE CandidateAssessmentID = @candidateAssessmentId - AND SupervisorDelegateId = @supervisorDelegateId - AND SelfAssessmentSupervisorRoleId=@selfAssessmentSupervisorRoleId", - new { candidateAssessmentId, supervisorDelegateId, selfAssessmentSupervisorRoleId }); + @"BEGIN TRY + BEGIN TRANSACTION + UPDATE CandidateAssessmentSupervisors SET Removed = getUTCDate() WHERE CandidateAssessmentID = @candidateAssessmentId + AND SupervisorDelegateId = @supervisorDelegateId + AND Removed IS NULL + + UPDATE CandidateAssessmentSupervisors SET Removed = NULL WHERE CandidateAssessmentID = @candidateAssessmentId + AND SupervisorDelegateId = @supervisorDelegateId + AND SelfAssessmentSupervisorRoleId = @selfAssessmentSupervisorRoleId + + COMMIT TRANSACTION + END TRY + BEGIN CATCH + ROLLBACK TRANSACTION + END CATCH", + new { candidateAssessmentId, supervisorDelegateId, selfAssessmentSupervisorRoleId }); } } return candidateAssessmentId; @@ -966,9 +995,6 @@ BEGIN TRANSACTION UPDATE CandidateAssessments SET RemovedDate = getUTCDate(), RemovalMethodID = 2 WHERE ID = @candidateAssessmentId AND RemovedDate IS NULL - UPDATE CandidateAssessmentSupervisors SET Removed = getUTCDate() - WHERE CandidateAssessmentID = @candidateAssessmentId AND Removed IS NULL - COMMIT TRANSACTION END TRY BEGIN CATCH diff --git a/DigitalLearningSolutions.Data/DigitalLearningSolutions.Data.csproj b/DigitalLearningSolutions.Data/DigitalLearningSolutions.Data.csproj index 05556966ee..2d7bea0631 100644 --- a/DigitalLearningSolutions.Data/DigitalLearningSolutions.Data.csproj +++ b/DigitalLearningSolutions.Data/DigitalLearningSolutions.Data.csproj @@ -14,7 +14,7 @@ - + diff --git a/DigitalLearningSolutions.Data/Models/CompetencyAssessments/NRPSubGroups.cs b/DigitalLearningSolutions.Data/Models/CompetencyAssessments/NRPSubGroups.cs index fda19bcb09..f100a6b2e2 100644 --- a/DigitalLearningSolutions.Data/Models/CompetencyAssessments/NRPSubGroups.cs +++ b/DigitalLearningSolutions.Data/Models/CompetencyAssessments/NRPSubGroups.cs @@ -4,7 +4,6 @@ public class NRPSubGroups { public int ID { get; set; } - public int NRPProfessionalGroupID { get; set; } [StringLength(255, MinimumLength = 3)] [Required] public string SubGroup { get; set; } = string.Empty; diff --git a/DigitalLearningSolutions.Data/Models/Supervisor/DelegateSelfAssessment.cs b/DigitalLearningSolutions.Data/Models/Supervisor/DelegateSelfAssessment.cs index 014de6be9f..212089f305 100644 --- a/DigitalLearningSolutions.Data/Models/Supervisor/DelegateSelfAssessment.cs +++ b/DigitalLearningSolutions.Data/Models/Supervisor/DelegateSelfAssessment.cs @@ -28,5 +28,6 @@ public class DelegateSelfAssessment public bool IsSupervisorResultsReviewed { get; set; } public bool IsAssignedToSupervisor { get; set; } public bool NonReportable { get; set; } + public string? Vocabulary { get; set; } } } diff --git a/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/PromoteToAdminControllerTests.cs b/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/PromoteToAdminControllerTests.cs index 5b84a3c962..9abc93259d 100644 --- a/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/PromoteToAdminControllerTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/PromoteToAdminControllerTests.cs @@ -94,7 +94,7 @@ public void Summary_post_registers_delegate_with_expected_values() A._, A._, A._, A._, A._, A._, A._, A._, A._, A._, A._, A._, - A._, A._ + A._, A._, A._ )).Returns(adminRolesEmail); // When diff --git a/DigitalLearningSolutions.Web.Tests/Services/EmailGenerationServiceTests.cs b/DigitalLearningSolutions.Web.Tests/Services/EmailGenerationServiceTests.cs index 96178e2220..47cb0eff9d 100644 --- a/DigitalLearningSolutions.Web.Tests/Services/EmailGenerationServiceTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Services/EmailGenerationServiceTests.cs @@ -45,6 +45,7 @@ bool isCmsManager const string supervisorFirstName = "TestAdminFirstName"; const string supervisorLastName = "TestAdminFirstName"; const string supervisorEmail = "admin@example.com"; + const string categoryName = "Digital Workplace"; const string centreName = "Test Centre Name"; @@ -65,7 +66,8 @@ bool isCmsManager isCmsAdministrator, isCmsManager, delegateEmail, - centreName + centreName, + categoryName ); // Then @@ -164,6 +166,11 @@ bool isCmsManager returnedEmail.Body.HtmlBody.Should().NotContain("
  • CMS manager
  • "); returnedEmail.Body.TextBody.Should().NotContain("CMS manager"); } + if (!string.IsNullOrEmpty(categoryName)) + { + returnedEmail.Body.HtmlBody.Should().Contain("In the Digital Workplace category."); + returnedEmail.Body.TextBody.Should().Contain("In the Digital Workplace category."); + } returnedEmail.Body.HtmlBody.Should().Contain("the next time you log in to " + centreName + "."); returnedEmail.Body.TextBody.Should().Contain("the next time you log in to " + centreName + "."); diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index 652f2e087e..aee8442d14 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Mvc.Rendering; using DigitalLearningSolutions.Data.Models.Centres; using DigitalLearningSolutions.Data.Models.Frameworks; + using Microsoft.CodeAnalysis.CSharp.Syntax; public partial class CompetencyAssessmentsController { @@ -187,10 +188,9 @@ public IActionResult ManageCompetencyAssessment(int competencyAssessmentId, int? return View("ManageCompetencyAssessment", model); } - [Route("/CompetencyAssessments/ProfessionalGroup/{actionName}/{competencyAssessmentId}")] - [Route("/CompetencyAssessments/ProfessionalGroup/{actionName}")] + [Route("/CompetencyAssessments/{competencyAssessmentId}/NationalRoleProfileLinks/{actionName}")] [SetSelectedTab(nameof(NavMenuTab.CompetencyAssessments))] - public IActionResult CompetencyAssessmentProfessionalGroup(string actionName, int competencyAssessmentId = 0) + public IActionResult EditRoleProfileLinks(int competencyAssessmentId = 0, string actionName = "EditGroup") { var adminId = GetAdminID(); CompetencyAssessmentBase? competencyAssessmentBase; @@ -212,45 +212,68 @@ public IActionResult CompetencyAssessmentProfessionalGroup(string actionName, in competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); } var professionalGroups = competencyAssessmentService.GetNRPProfessionalGroups(); - var model = new ProfessionalGroupViewModel() - { - NRPProfessionalGroups = professionalGroups, - CompetencyAssessmentBase = competencyAssessmentBase - }; - return View("ProfessionalGroup", model); + var subGroups = competencyAssessmentService.GetNRPSubGroups(competencyAssessmentBase.NRPProfessionalGroupID); + var roles = competencyAssessmentService.GetNRPRoles(competencyAssessmentBase.NRPSubGroupID); + var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null); + var model = new EditRoleProfileLinksViewModel(competencyAssessmentBase, professionalGroups, subGroups, roles, actionName, competencyAssessmentTaskStatus.NationalRoleProfileTaskStatus); + return View(model); } [HttpPost] - [Route("/CompetencyAssessments/ProfessionalGroup/{actionName}/{competencyAssessmentId}")] - [Route("/CompetencyAssessments/ProfessionalGroup/{actionName}")] - [SetSelectedTab(nameof(NavMenuTab.CompetencyAssessments))] - public IActionResult SaveProfessionalGroup(CompetencyAssessmentBase competencyAssessmentBase, string actionName, int competencyAssessmentId = 0) + [Route("/CompetencyAssessments/{competencyAssessmentId}/NationalRoleProfileLinks/{actionName}")] + public IActionResult EditRoleProfileLinks(EditRoleProfileLinksViewModel model, string actionName, int competencyAssessmentId = 0) { - if (competencyAssessmentBase.NRPProfessionalGroupID == null) + var adminId = GetAdminID(); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + competencyAssessmentService.UpdateRoleProfileLinksTaskStatus(model.ID, model.TaskStatus ?? false); + if (competencyAssessmentBase == null) { - ModelState.Remove(nameof(CompetencyAssessmentBase.NRPProfessionalGroupID)); - ModelState.AddModelError(nameof(CompetencyAssessmentBase.NRPProfessionalGroupID), "Please choose a professional group" + (competencyAssessmentId == 0 ? "or Skip this step" : "") + "."); - // do something - return View("Name", competencyAssessmentBase); + logger.LogWarning($"Failed to submit role links page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); } - if (actionName == "New") + if (competencyAssessmentBase.UserRole < 2) { - //TO DO Store to self assessment - - return RedirectToAction("CompetencyAssessmentSubGroup", "CompetencyAssessments", new { actionName }); + return StatusCode(403); } - else + if (competencyAssessmentBase.NRPProfessionalGroupID != model.ProfessionalGroupId) { - var adminId = GetAdminID(); - var isUpdated = competencyAssessmentService.UpdateCompetencyAssessmentProfessionalGroup(competencyAssessmentBase.ID, adminId, competencyAssessmentBase.NRPProfessionalGroupID); - if (isUpdated) + model.SubGroupId = null; + model.RoleId = null; + } + if (competencyAssessmentBase.NRPSubGroupID != model.SubGroupId) + { + model.RoleId = null; + } + var isUpdated = competencyAssessmentService.UpdateCompetencyRoleProfileLinks(model.ID, adminId, model.ProfessionalGroupId, model.SubGroupId, model.RoleId); + if (model.ActionName == "EditGroup") + { + if (model.ProfessionalGroupId == null) { - return RedirectToAction("CompetencyAssessmentSubGroup", "CompetencyAssessments", new { actionName, competencyAssessmentId }); + return RedirectToAction("EditRoleProfileLinks", new { actionName = "Summary", competencyAssessmentId }); } else { - return RedirectToAction("ManageCompetencyAssessment", new { tabname = "Details", competencyAssessmentId }); + return RedirectToAction("EditRoleProfileLinks", new { actionName = "EditSubGroup", competencyAssessmentId }); + } + } + else if (model.ActionName == "EditSubGroup") + { + if (model.SubGroupId == null) + { + return RedirectToAction("EditRoleProfileLinks", new { actionName = "Summary", competencyAssessmentId }); } + else + { + return RedirectToAction("EditRoleProfileLinks", new { actionName = "EditRole", competencyAssessmentId }); + } + } + else if (model.ActionName == "EditRole") + { + return RedirectToAction("EditRoleProfileLinks", new { actionName = "Summary", competencyAssessmentId }); + } + else + { + return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId }); } } @@ -323,11 +346,11 @@ public IActionResult EditBranding(EditBrandingViewModel model) model.CategorySelectList = categorySelectList; return View("EditBranding", model); } - if(model.BrandID == 0) + if (model.BrandID == 0) { model.BrandID = commonService.InsertBrandAndReturnId(model.Brand, (int)centreId); } - if(model.CategoryID == 0) + if (model.CategoryID == 0) { model.CategoryID = commonService.InsertCategoryAndReturnId(model.Category, (int)centreId); } diff --git a/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs b/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs index 2234f7d9eb..4947c6bd75 100644 --- a/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs +++ b/DigitalLearningSolutions.Web/Controllers/LearningPortalController/SelfAssessment.cs @@ -1565,7 +1565,18 @@ ManageOptionalCompetenciesViewModel model } } - + + if (!selfAssessmentService.HasMinimumOptionalCompetencies(selfAssessmentId, delegateUserId)) + { + var supervisorsSignOffs = selfAssessmentService.GetSupervisorSignOffsForCandidateAssessment(selfAssessmentId, delegateUserId); + + if (supervisorsSignOffs.FirstOrDefault() is { Verified: null, Removed: null }) + { + selfAssessmentService.RemoveSignoffRequestById(supervisorsSignOffs.FirstOrDefault().ID); + } + } + + return RedirectToAction("SelfAssessmentOverview", new { selfAssessmentId, vocabulary }); } @@ -1577,9 +1588,9 @@ public IActionResult RequestSignOff(int selfAssessmentId) var delegateId = User.GetCandidateIdKnownNotNull(); var recentResults = selfAssessmentService.GetMostRecentResults(selfAssessmentId, delegateId).ToList(); var competencySummaries = CertificateHelper.CompetencySummation(recentResults); - - if (competencySummaries.QuestionsCount != competencySummaries.VerifiedCount) return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); - + + if (competencySummaries.QuestionsCount != competencySummaries.VerifiedCount) return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); + var assessment = selfAssessmentService.GetSelfAssessmentForCandidateById(delegateUserId, selfAssessmentId); var supervisors = selfAssessmentService.GetSignOffSupervisorsForSelfAssessmentId(selfAssessmentId, delegateUserId); @@ -1591,7 +1602,7 @@ public IActionResult RequestSignOff(int selfAssessmentId) NumberOfSelfAssessedOptionalCompetencies = optionalCompetencies.Count(x => x.IncludedInSelfAssessment) }; if (model.NumberOfSelfAssessedOptionalCompetencies < model.SelfAssessment.MinimumOptionalCompetencies) return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); - + return View("SelfAssessments/RequestSignOff", model); } diff --git a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs index 93c8e1f610..21b555391c 100644 --- a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs +++ b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs @@ -1061,8 +1061,8 @@ public IActionResult QuickAddSupervisor(int selfAssessmentId, int supervisorDele var sessionEnrolOnCompetencyAssessment = new SessionEnrolOnCompetencyAssessment() { - SelfAssessmentID = supervisorRoles.FirstOrDefault().SelfAssessmentID, - SelfAssessmentSupervisorRoleId = supervisorRoles.FirstOrDefault().ID + SelfAssessmentID = supervisorRoles.FirstOrDefault() != null ? supervisorRoles.FirstOrDefault().SelfAssessmentID : selfAssessmentId, + SelfAssessmentSupervisorRoleId = supervisorRoles.FirstOrDefault() != null ? supervisorRoles.FirstOrDefault().ID : 0 }; multiPageFormService.SetMultiPageFormData( @@ -1070,7 +1070,7 @@ public IActionResult QuickAddSupervisor(int selfAssessmentId, int supervisorDele MultiPageFormDataFeature.EnrolDelegateOnProfileAssessment, TempData ); - var supervisorRoleName = supervisorRoles.FirstOrDefault().RoleName; + var supervisorRoleName = supervisorRoles.FirstOrDefault() != null ? supervisorRoles.FirstOrDefault().RoleName : ""; var model = new EnrolDelegateSummaryViewModel { CompetencyAssessment = competencyAssessment, @@ -1328,6 +1328,9 @@ public IActionResult ConfirmNominateSupervisor(SupervisorDelegateViewModel super { registrationService.PromoteDelegateToAdmin(adminRoles, supervisorDelegate.SelfAssessmentCategory, (int)supervisorDelegateDetail.DelegateUserID, (int)User.GetCentreId(), true); + int? learningCategory = supervisorDelegate.SelfAssessmentCategory == 0 ? null : supervisorDelegate.SelfAssessmentCategory; + var learningCategoryName = courseCategoriesService.GetCourseCategoryName(learningCategory); + if (delegateUser != null && adminUser != null) { var adminRolesEmail = emailGenerationService.GenerateDelegateAdminRolesNotificationEmail( @@ -1344,7 +1347,8 @@ public IActionResult ConfirmNominateSupervisor(SupervisorDelegateViewModel super isCmsAdmin: adminRoles.IsCmsAdministrator, isCmsManager: adminRoles.IsCmsManager, primaryEmail: delegateUser.EmailAddress, - centreName: centreName + centreName: centreName, + learningCategoryName ); emailService.SendEmail(adminRolesEmail); diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs index 317eec01ad..57fa350f35 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/Administrator/AdministratorController.cs @@ -177,8 +177,10 @@ public IActionResult EditAdminRoles(AdminRolesFormData model, int adminId) adminRoles, AdminCategoryHelper.AdminCategoryToCategoryId(model.LearningCategory) ); + int? learningCategory = model.LearningCategory == 0 ? null : model.LearningCategory; + var learningCategoryName = courseCategoriesService.GetCourseCategoryName(learningCategory); - SendNotificationEmail(adminId, adminRoles); + SendNotificationEmail(adminId, adminRoles, learningCategoryName); return RedirectToAction( "Index", @@ -190,7 +192,8 @@ public IActionResult EditAdminRoles(AdminRolesFormData model, int adminId) private void SendNotificationEmail( int adminIdToPromote, - AdminRoles adminRoles + AdminRoles adminRoles, + string learningCategoryName ) { var adminId = User.GetAdminId(); @@ -215,7 +218,8 @@ AdminRoles adminRoles isCmsAdmin: adminRoles.IsCmsAdministrator, isCmsManager: adminRoles.IsCmsManager, primaryEmail: delegateUserEmailDetails.EmailAddress, - centreName: centreName + centreName: centreName, + learningCategoryName ); emailService.SendEmail(adminRolesEmail); diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/SelfAssessmentReports/SelfAssessmentReportsController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/SelfAssessmentReports/SelfAssessmentReportsController.cs index 7af1d2f4ca..0491429fd3 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/SelfAssessmentReports/SelfAssessmentReportsController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Centre/SelfAssessmentReports/SelfAssessmentReportsController.cs @@ -8,11 +8,9 @@ using DigitalLearningSolutions.Web.Attributes; using DigitalLearningSolutions.Web.Models.Enums; using DigitalLearningSolutions.Data.Enums; - using System; using DigitalLearningSolutions.Data.Utilities; using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.Reports; using DigitalLearningSolutions.Web.Helpers.ExternalApis; - using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using DigitalLearningSolutions.Data.Extensions; using DigitalLearningSolutions.Web.Services; @@ -75,8 +73,9 @@ public IActionResult DownloadDigitalCapabilityToExcel() public IActionResult DownloadSelfAssessmentReport(int selfAssessmentId) { var centreId = User.GetCentreId(); + var selfAssessmentName = selfAssessmentService.GetSelfAssessmentNameById(selfAssessmentId); var dataFile = selfAssessmentReportService.GetSelfAssessmentExcelExportForCentre((int)centreId, selfAssessmentId); - var fileName = $"Competency Self Assessment Report - Centre {centreId} - downloaded {DateTime.Today:yyyy-MM-dd}.xlsx"; + var fileName = $"{((selfAssessmentName.Length > 50) ? selfAssessmentName.Substring(0, 50) : selfAssessmentName)} Report - Centre {centreId} - downloaded {clockUtility.UtcNow:yyyy-MM-dd}.xlsx"; return File( dataFile, FileHelper.GetContentTypeFromFileName(fileName), diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/CourseSetup/CourseSetupController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/CourseSetup/CourseSetupController.cs index 775e52ecdb..93eb9dc09e 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/CourseSetup/CourseSetupController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/CourseSetup/CourseSetupController.cs @@ -365,7 +365,8 @@ public IActionResult SetCourseOptions(EditCourseOptionsFormData model) data!.CourseOptionsData = model.ToCourseOptionsTempData(); multiPageFormService.SetMultiPageFormData(data, MultiPageFormDataFeature.AddNewCourse, TempData); - return RedirectToAction("SetCourseContent", false); + bool editCourseContent = data?.EditCourseContent ?? false; + return RedirectToAction("SetCourseContent", editCourseContent); } [HttpGet("AddCourse/SetCourseContent")] @@ -381,7 +382,7 @@ public IActionResult SetCourseContent(bool editCourseContent) { return RedirectToAction("Summary"); } - data.EditCourseContent = editCourseContent; + data.EditCourseContent = data.EditCourseContent || editCourseContent; multiPageFormService.SetMultiPageFormData(data, MultiPageFormDataFeature.AddNewCourse, TempData); var model = data!.CourseContentData != null @@ -459,17 +460,15 @@ public IActionResult SetSectionContent(int sectionIndex) } var showDiagnostic = data.Application!.DiagAssess; - if (data.EditCourseContent) + var tutorial = GetTutorialsFromSectionContentData(data.SectionContentData, tutorials); + if (tutorial.Count() == 0) { - var tutorial = GetTutorialsFromSectionContentData(data.SectionContentData, tutorials); - var model = new SetSectionContentViewModel(section, sectionIndex, showDiagnostic, tutorial); - return View("AddNewCentreCourse/SetSectionContent", model); - } - else - { - var model = new SetSectionContentViewModel(section, sectionIndex, showDiagnostic, tutorials); - return View("AddNewCentreCourse/SetSectionContent", model); + var models = new SetSectionContentViewModel(section, sectionIndex, showDiagnostic, tutorials); + return View("AddNewCentreCourse/SetSectionContent", models); } + var model = new SetSectionContentViewModel(section, sectionIndex, showDiagnostic, tutorial); + return View("AddNewCentreCourse/SetSectionContent", model); + } @@ -500,6 +499,21 @@ string action public IActionResult Summary() { var data = multiPageFormService.GetMultiPageFormData(MultiPageFormDataFeature.AddNewCourse, TempData).GetAwaiter().GetResult(); + var updatedSections = new List(); + foreach (var item in data.CourseContentData.SelectedSectionIds) + { + var tutorialsForSection = tutorialService.GetTutorialsForSection(item).ToList(); + + var matchingSections = data.SectionContentData + .Where(section => section.Tutorials.Any(t => tutorialsForSection.Any(tf => tf.TutorialId == t.TutorialId))) + .ToList(); + + updatedSections.AddRange(matchingSections); + } + + updatedSections = updatedSections.Distinct().ToList(); + data.SectionContentData = updatedSections; + multiPageFormService.SetMultiPageFormData(data, MultiPageFormDataFeature.AddNewCourse, TempData); var model = new SummaryViewModel(data!); @@ -651,11 +665,23 @@ private IActionResult SaveSectionAndRedirect(SetSectionContentViewModel model) { data.SectionContentData = new List(); } - if (data.EditCourseContent) + var sectionsToRemove = new List(); + foreach (var section in data.SectionContentData) { - return RedirectToNextSectionOrSummary( - model.Index, - new SetCourseContentViewModel(data.CourseContentData!)); + section.Tutorials = section.Tutorials + .Where(t => !model.Tutorials.Any(newT => newT.TutorialId == t.TutorialId)) + .ToList(); + if (!section.Tutorials.Any()) + { + sectionsToRemove.Add(section); + } + } + if (sectionsToRemove.Count > 0) + { + foreach (var section in sectionsToRemove) + { + data.SectionContentData.Remove(section); + } } data!.SectionContentData!.Add( new SectionContentTempData( @@ -732,18 +758,19 @@ private static IEnumerable UpdateC private IEnumerable GetTutorialsFromSectionContentData(List sectionContentData, List sectionTutorial) { if (sectionContentData == null || sectionTutorial == null) return new List(); - var updatedRecords = sectionContentData - .SelectMany(data => data.Tutorials) - .Join(sectionTutorial, - tempData => new { tempData.TutorialId, tempData.TutorialName }, // Match on both TutorialId and TutorialName - index => new { index.TutorialId, index.TutorialName }, - (tempData, index) => new Tutorial + var updatedRecords = sectionTutorial + .GroupJoin( + sectionContentData.SelectMany(data => data.Tutorials), + tutorial => new { tutorial.TutorialId, tutorial.TutorialName }, + tempData => new { tempData.TutorialId, tempData.TutorialName }, + (tutorial, matchingTempData) => new Tutorial { - TutorialId = index.TutorialId, - TutorialName = index.TutorialName, - Status = tempData.LearningEnabled, // Updated from sectionContentData - DiagStatus = tempData.DiagnosticEnabled // Updated from sectionContentData - }) + TutorialId = tutorial.TutorialId, + TutorialName = tutorial.TutorialName, + Status = matchingTempData.Any() ? matchingTempData.First().LearningEnabled : tutorial.Status, + DiagStatus = matchingTempData.Any() ? matchingTempData.First().DiagnosticEnabled : tutorial.DiagStatus + } + ) .ToList(); return updatedRecords; diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/PromoteToAdminController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/PromoteToAdminController.cs index c579516102..21d02d0ef5 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/PromoteToAdminController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/PromoteToAdminController.cs @@ -139,6 +139,9 @@ public IActionResult Index(AdminRolesFormData formData, int delegateId) var delegateUserEmailDetails = userService.GetDelegateById(delegateId); + int? learningCategory = formData.LearningCategory == 0 ? null : formData.LearningCategory; + var learningCategoryName = courseCategoriesService.GetCourseCategoryName(learningCategory); + if (delegateUserEmailDetails != null) { var adminRolesEmail = emailGenerationService.GenerateDelegateAdminRolesNotificationEmail( @@ -155,7 +158,8 @@ public IActionResult Index(AdminRolesFormData formData, int delegateId) isCmsAdmin: adminRoles.IsCmsAdministrator, isCmsManager: adminRoles.IsCmsManager, primaryEmail: delegateUserEmailDetails.EmailForCentreNotifications, - centreName: centreName + centreName: centreName, + categoryName: learningCategoryName ); emailService.SendEmail(adminRolesEmail); diff --git a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs index 3b19d98920..7e8cf37fdb 100644 --- a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs @@ -2,6 +2,7 @@ using DigitalLearningSolutions.Data.Models.Common; using DigitalLearningSolutions.Data.Models.CompetencyAssessments; using System.Collections.Generic; +using System.Threading.Tasks; namespace DigitalLearningSolutions.Web.Services { @@ -18,23 +19,24 @@ public interface ICompetencyAssessmentService CompetencyAssessment? GetCompetencyAssessmentById(int competencyAssessmentId, int adminId); IEnumerable GetNRPProfessionalGroups(); + IEnumerable GetNRPSubGroups(int? nRPProfessionalGroupID); + IEnumerable GetNRPRoles(int? nRPSubGroupID); CompetencyAssessmentTaskStatus GetCompetencyAssessmentTaskStatus(int assessmentId, int? frameworkId); //UPDATE DATA bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int adminId, string competencyAssessmentName); - - bool UpdateCompetencyAssessmentProfessionalGroup(int competencyAssessmentId, int adminId, int? nrpProfessionalGroupID); + bool UpdateCompetencyRoleProfileLinks(int competencyAssessmentId, int adminId, int? professionalGroupId, int? subGroupId, int? roleId); bool UpdateIntroductoryTextTaskStatus(int assessmentId, bool taskStatus); bool UpdateCompetencyAssessmentDescription(int assessmentId, int adminId, string description); bool UpdateCompetencyAssessmentBranding(int assessmentId, int adminId, int brandID, int categoryID); bool UpdateBrandingTaskStatus(int assessmentId, bool taskStatus); bool UpdateCompetencyAssessmentVocabulary(int assessmentId, int adminId, string vocabulary); bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus); + bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus); //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName, int? frameworkId); - } public class CompetencyAssessmentService : ICompetencyAssessmentService { @@ -91,9 +93,9 @@ public bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int admin return competencyAssessmentDataService.UpdateCompetencyAssessmentName(competencyAssessmentId, adminId, competencyAssessmentName); } - public bool UpdateCompetencyAssessmentProfessionalGroup(int competencyAssessmentId, int adminId, int? nrpProfessionalGroupID) + public bool UpdateCompetencyRoleProfileLinks(int competencyAssessmentId, int adminId, int? professionalGroupId, int? subGroupId, int? roleId) { - return competencyAssessmentDataService.UpdateCompetencyAssessmentProfessionalGroup(competencyAssessmentId, adminId, nrpProfessionalGroupID); + return competencyAssessmentDataService.UpdateCompetencyRoleProfileLinks(competencyAssessmentId, adminId, professionalGroupId, subGroupId, roleId); } public CompetencyAssessmentTaskStatus GetCompetencyAssessmentTaskStatus(int assessmentId, int? frameworkId) { @@ -132,5 +134,20 @@ bool ICompetencyAssessmentService.UpdateVocabularyTaskStatus(int assessmentId, b { return competencyAssessmentDataService.UpdateVocabularyTaskStatus(assessmentId, taskStatus); } + + public IEnumerable GetNRPSubGroups(int? nRPProfessionalGroupID) + { + return competencyAssessmentDataService.GetNRPSubGroups(nRPProfessionalGroupID); + } + + public IEnumerable GetNRPRoles(int? nRPSubGroupID) + { + return competencyAssessmentDataService.GetNRPRoles(nRPSubGroupID); + } + + public bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus) + { + return competencyAssessmentDataService.UpdateRoleProfileLinksTaskStatus(assessmentId, taskStatus); + } } } diff --git a/DigitalLearningSolutions.Web/Services/CourseCategoriesService.cs b/DigitalLearningSolutions.Web/Services/CourseCategoriesService.cs index fc136f598e..9b475e9286 100644 --- a/DigitalLearningSolutions.Web/Services/CourseCategoriesService.cs +++ b/DigitalLearningSolutions.Web/Services/CourseCategoriesService.cs @@ -7,7 +7,7 @@ namespace DigitalLearningSolutions.Web.Services public interface ICourseCategoriesService { IEnumerable GetCategoriesForCentreAndCentrallyManagedCourses(int centreId); - string? GetCourseCategoryName(int categoryId); + string? GetCourseCategoryName(int? categoryId); } public class CourseCategoriesService : ICourseCategoriesService { @@ -22,7 +22,7 @@ public IEnumerable GetCategoriesForCentreAndCentrallyManagedCourses(in return courseCategoriesDataService.GetCategoriesForCentreAndCentrallyManagedCourses(centreId); } - public string? GetCourseCategoryName(int categoryId) + public string? GetCourseCategoryName(int? categoryId) { return courseCategoriesDataService.GetCourseCategoryName(categoryId); } diff --git a/DigitalLearningSolutions.Web/Services/EmailGenerationService.cs b/DigitalLearningSolutions.Web/Services/EmailGenerationService.cs index b631d48adc..ff7a924f82 100644 --- a/DigitalLearningSolutions.Web/Services/EmailGenerationService.cs +++ b/DigitalLearningSolutions.Web/Services/EmailGenerationService.cs @@ -19,7 +19,8 @@ Email GenerateDelegateAdminRolesNotificationEmail( bool isCmsAdmin, bool isCmsManager, string primaryEmail, - string centreName + string centreName, + string categoryName ); } @@ -39,7 +40,8 @@ public Email GenerateDelegateAdminRolesNotificationEmail( bool isCmsAdmin, bool isCmsManager, string primaryEmail, - string centreName + string centreName, + string categoryName ) { const string emailSubjectLine = "New Digital Learning Solutions permissions granted"; @@ -101,6 +103,13 @@ string centreName builder.HtmlBody += ""; + if (!string.IsNullOrEmpty(categoryName)) + { + builder.TextBody += $@"In the {categoryName} category."; + builder.HtmlBody += $@" +

    In the {categoryName} category.

    "; + } + builder.TextBody += $@"You will be able to access the Digital Learning Solutions platform with these new access permissions the next time you log in to {centreName}."; builder.HtmlBody += $@"You will be able to access the Digital Learning Solutions platform with these new access permissions the next time you log in to {centreName}."; diff --git a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs index ce7afea305..c9a50014fa 100644 --- a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs @@ -27,6 +27,7 @@ public interface ISelfAssessmentService void UpdateLastAccessed(int selfAssessmentId, int delegateUserId); void RemoveSignoffRequests(int selfAssessmentId, int delegateUserId, int competencyGroupsId); + void RemoveSignoffRequestById(int candidateAssessmentSupervisorVerificationsId); void IncrementLaunchCount(int selfAssessmentId, int delegateUserId); void SetCompleteByDate(int selfAssessmentId, int delegateUserId, DateTime? completeByDate); @@ -160,7 +161,7 @@ public IEnumerable GetSelfAssessmentResultswithSupervisorV int selfAssessmentId, int competencyId ); - void RemoveReviewCandidateAssessmentOptionalCompetencies(int id); + void RemoveReviewCandidateAssessmentOptionalCompetencies(int id); } public class SelfAssessmentService : ISelfAssessmentService @@ -201,6 +202,10 @@ public void RemoveSignoffRequests(int selfAssessmentId, int delegateUserId, int { selfAssessmentDataService.RemoveSignoffRequests(selfAssessmentId, delegateUserId, competencyGroupId); } + public void RemoveSignoffRequestById(int candidateAssessmentSupervisorVerificationsId) + { + selfAssessmentDataService.RemoveSignoffRequestById(candidateAssessmentSupervisorVerificationsId); + } public void IncrementLaunchCount(int selfAssessmentId, int delegateUserId) { selfAssessmentDataService.IncrementLaunchCount(selfAssessmentId, delegateUserId); @@ -467,10 +472,10 @@ public void RemoveEnrolment(int selfAssessmentId, int delegateUserId) var selfAssessmentCategoryId = selfAssessmentDataService.GetSelfAssessmentCategoryId((int)selfAssessmentId); - if (adminCategoryId > 0 && adminCategoryId != selfAssessmentCategoryId) + if (adminCategoryId > 0 && adminCategoryId != selfAssessmentCategoryId) { // return null variants of the object when the categoryID mismatches - return (new SelfAssessmentDelegatesData(), null); + return (new SelfAssessmentDelegatesData(), null); } (var delegateselfAssessments, int resultCount) = selfAssessmentDataService.GetSelfAssessmentDelegates(searchString, offSet, itemsPerPage, sortBy, sortDirection, @@ -603,7 +608,7 @@ int competencyId } public void RemoveReviewCandidateAssessmentOptionalCompetencies(int id) { - selfAssessmentDataService.RemoveReviewCandidateAssessmentOptionalCompetencies(id); + selfAssessmentDataService.RemoveReviewCandidateAssessmentOptionalCompetencies(id); } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/EditRoleProfileLinksViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/EditRoleProfileLinksViewModel.cs new file mode 100644 index 0000000000..54ddd177b5 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/EditRoleProfileLinksViewModel.cs @@ -0,0 +1,43 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + using DigitalLearningSolutions.Data.Models.CompetencyAssessments; + using Humanizer; + using System.Collections.Generic; + using System.Linq; + + public class EditRoleProfileLinksViewModel + { + public EditRoleProfileLinksViewModel() { } + public EditRoleProfileLinksViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable professionalGroups, IEnumerable subGroups, IEnumerable roles, string actionName, bool? taskStatus) + { + ID = competencyAssessmentBase.ID; + CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; + ProfessionalGroupId = competencyAssessmentBase.NRPProfessionalGroupID; + SubGroupId = competencyAssessmentBase.NRPSubGroupID; + RoleId = competencyAssessmentBase.NRPRoleID; + UserRole = competencyAssessmentBase.UserRole; + TaskStatus = taskStatus; + ProfessionalGroups = professionalGroups; + SubGroups = subGroups; + Roles = roles; + ActionName = actionName; + RoleName = Roles.FirstOrDefault(r => r.ID == RoleId)?.ProfileName ?? "Don't link assessment to a role."; + SubGroupName = SubGroups.FirstOrDefault(s => s.ID == SubGroupId)?.SubGroup ?? "Don't link assessment to a sub group."; + GroupName = ProfessionalGroups.FirstOrDefault(p => p.ID == ProfessionalGroupId)?.ProfessionalGroup ?? "Don't link assessment to a professional group."; + } + public IEnumerable ProfessionalGroups { get; set; } + public IEnumerable SubGroups { get; set; } + public IEnumerable Roles { get; set; } + public int ID { get; set; } + public string CompetencyAssessmentName { get; set; } + public string ActionName { get; set; } + public int? ProfessionalGroupId { get; set; } + public int? SubGroupId { get; set; } + public int? RoleId { get; set; } + public int UserRole { get; set; } + public bool? TaskStatus { get; set; } + public string? GroupName { get; set; } + public string? SubGroupName { get; set; } + public string? RoleName { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ProfessionalGroupViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ProfessionalGroupViewModel.cs deleted file mode 100644 index 86ba83228b..0000000000 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/ProfessionalGroupViewModel.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments -{ - using DigitalLearningSolutions.Data.Models.CompetencyAssessments; - using System.Collections.Generic; - - public class ProfessionalGroupViewModel - { - public IEnumerable NRPProfessionalGroups { get; set; } - public CompetencyAssessmentBase CompetencyAssessmentBase { get; set; } - } -} diff --git a/DigitalLearningSolutions.Web/ViewModels/Supervisor/EnrolDelegateSummaryViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Supervisor/EnrolDelegateSummaryViewModel.cs index 681213e53f..ad66e71ac8 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Supervisor/EnrolDelegateSummaryViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Supervisor/EnrolDelegateSummaryViewModel.cs @@ -12,5 +12,6 @@ public class EnrolDelegateSummaryViewModel public string SupervisorRoleName { get; set; } public int SupervisorRoleCount { get; set; } public bool AllowSupervisorRoleSelection { get; set; } + public bool HasSupervisorRoles => !string.IsNullOrWhiteSpace(SupervisorRoleName); } } diff --git a/DigitalLearningSolutions.Web/ViewModels/Supervisor/ReviewSelfAssessmentViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Supervisor/ReviewSelfAssessmentViewModel.cs index ea19f92d35..9a6463e28f 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Supervisor/ReviewSelfAssessmentViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Supervisor/ReviewSelfAssessmentViewModel.cs @@ -1,6 +1,5 @@ namespace DigitalLearningSolutions.Web.ViewModels.Supervisor { - using DigitalLearningSolutions.Data.Models.Frameworks; using DigitalLearningSolutions.Data.Models.SelfAssessments; using DigitalLearningSolutions.Data.Models.Supervisor; using DigitalLearningSolutions.Web.Helpers; @@ -15,9 +14,9 @@ public class ReviewSelfAssessmentViewModel public IEnumerable? SupervisorSignOffs { get; set; } public bool IsSupervisorResultsReviewed { get; set; } public SearchSupervisorCompetencyViewModel SearchViewModel { get; set; } - public string VocabPlural(string vocabulary) + public string VocabPlural() { - return FrameworkVocabularyHelper.VocabularyPlural(vocabulary); + return FrameworkVocabularyHelper.VocabularyPlural(DelegateSelfAssessment.Vocabulary); } public int CandidateAssessmentId { get; set; } public bool ExportToExcelHide { get; set; } diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml new file mode 100644 index 0000000000..b5faad6214 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml @@ -0,0 +1,256 @@ +@using DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments; +@model EditRoleProfileLinksViewModel; +@{ + ViewData["Title"] = "Edit National Role Profile Links"; + ViewData["Application"] = "Framework Service"; +} + +@section NavMenuItems { + +} + +@section NavBreadcrumbs { + +} + +

    Edit @Model.CompetencyAssessmentName national NHS role profile links

    +@if (Model.TaskStatus != null | Model.ActionName != "EditGroup") +{ +
    + +
    +
    + Professional group +
    +
    + @Model.GroupName +
    +
    + + Change professional group link + +
    +
    + @if (Model.ProfessionalGroupId != null && Model.ActionName != "EditSubGroup") + { +
    +
    + Sub group +
    +
    + @Model.SubGroupName +
    +
    + + Change sub group link + +
    +
    + } + @if (Model.SubGroupId != null && Model.ActionName == "Summary") + { +
    +
    + Role +
    +
    + @Model.RoleName +
    +
    + + Change role profile link + +
    +
    + } +
    +} +@if (Model.ActionName == "EditGroup") +{ +
    + @if (!ViewData.ModelState.IsValid) + { + + } + +
    + +

    + Choose the NHS national role profile professional group to associate with this assessment. +

    +
    + +
    + @foreach (var professionalGroup in Model.ProfessionalGroups) + { +
    + + +
    + } +
    + +
    + + +
    +
    +
    +
    + + + + + + + + + + + + +} +else if (Model.ActionName == "EditSubGroup" && Model.ProfessionalGroupId != null) +{ +
    + @if (!ViewData.ModelState.IsValid) + { + + } + +
    + +

    + Choose the role sub group to associate with this assessment. +

    +
    + +
    + @foreach (var subGroup in Model.SubGroups) + { +
    + + +
    + } +
    + +
    + + +
    +
    +
    +
    + + + + + + + + + + + +} +else if (Model.ActionName == "EditRole" && Model.SubGroupId != null) +{ +
    + @if (!ViewData.ModelState.IsValid) + { + + } + +
    + +

    + Choose the role to associate with this assessment. +

    +
    + +
    + @foreach (var role in Model.Roles) + { +
    + + +
    + } +
    + +
    + + +
    +
    +
    +
    + + + + + + + + + + + +} +else if (Model.ActionName == "Summary") +{ +
    + + + + + + + + + + + + + + +
    +} + diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml index 92a8691086..3e4f9f34be 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml @@ -107,7 +107,7 @@