diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAsssessmentReportDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAsssessmentReportDataService.cs index 50168d4e64..0bd5d38f37 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAsssessmentReportDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAsssessmentReportDataService.cs @@ -1,135 +1,139 @@ -namespace DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService -{ - using Dapper; - using DigitalLearningSolutions.Data.Models.SelfAssessments.Export; - using DigitalLearningSolutions.Data.Models.SelfAssessments; - using Microsoft.Extensions.Logging; - using System.Collections.Generic; - using System.Data; - - public interface ISelfAssessmentReportDataService - { - IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId); - IEnumerable GetSelfAssessmentReportDataForCentre(int centreId, int selfAssessmentId); - } - public partial class SelfAssessmentReportDataService : ISelfAssessmentReportDataService - { - private readonly IDbConnection connection; - private readonly ILogger logger; - - public SelfAssessmentReportDataService(IDbConnection connection, ILogger logger) - { - this.connection = connection; - this.logger = logger; - } - - public IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId) - { - return connection.Query( - @"SELECT csa.SelfAssessmentID AS Id, sa.Name, - (SELECT COUNT (DISTINCT da.UserID) AS Learners - FROM CandidateAssessments AS ca1 INNER JOIN - DelegateAccounts AS da ON ca1.DelegateUserID = da.UserID - WHERE (da.CentreID = @centreId) AND (ca1.RemovedDate IS NULL) AND (ca1.SelfAssessmentID = csa.SelfAssessmentID) AND ca1.NonReportable=0) AS LearnerCount - FROM CentreSelfAssessments AS csa INNER JOIN - SelfAssessments AS sa ON csa.SelfAssessmentID = sa.ID - WHERE (csa.CentreID = @centreId) AND (sa.CategoryID = @categoryId) AND (sa.SupervisorResultsReview = 1) AND (sa.ArchivedDate IS NULL) OR - (csa.CentreID = @centreId) AND (sa.CategoryID = @categoryId) AND (sa.ArchivedDate IS NULL) AND (sa.SupervisorSelfAssessmentReview = 1) OR - (csa.CentreID = @centreId) AND (sa.SupervisorResultsReview = 1) AND (sa.ArchivedDate IS NULL) AND (@categoryId = 0) OR - (csa.CentreID = @centreId) AND (sa.ArchivedDate IS NULL) AND (sa.SupervisorSelfAssessmentReview = 1) AND (@categoryId = 0) - ORDER BY sa.Name", - new { centreId, categoryId = categoryId ??= 0 } - ); - } - - public IEnumerable GetSelfAssessmentReportDataForCentre(int centreId, int selfAssessmentId) - { - return connection.Query( - @"WITH LatestAssessmentResults AS - ( - SELECT s.DelegateUserID - , CASE WHEN COALESCE (rr.LevelRAG, 0) = 3 THEN s.ID ELSE NULL END AS SelfAssessed - , CASE WHEN sv.Verified IS NOT NULL AND sv.SignedOff = 1 AND COALESCE (rr.LevelRAG, 0) = 3 THEN s.ID ELSE NULL END AS Confirmed - , CASE WHEN sas.Optional = 1 THEN s.CompetencyID ELSE NULL END AS Optional - FROM SelfAssessmentResults AS s LEFT OUTER JOIN - SelfAssessmentStructure AS sas ON sas.SelfAssessmentID = @selfAssessmentId AND s.CompetencyID = sas.CompetencyID LEFT OUTER JOIN - SelfAssessmentResultSupervisorVerifications AS sv ON s.ID = sv.SelfAssessmentResultId AND sv.Superceded = 0 LEFT OUTER JOIN - CompetencyAssessmentQuestionRoleRequirements AS rr ON s.CompetencyID = rr.CompetencyID AND s.AssessmentQuestionID = rr.AssessmentQuestionID AND sas.SelfAssessmentID = rr.SelfAssessmentID AND s.Result = rr.LevelValue - WHERE (sas.SelfAssessmentID = @selfAssessmentId) - ) - SELECT - sa.Name AS SelfAssessment - , u.LastName + ', ' + u.FirstName AS Learner - , da.Active AS LearnerActive - , u.ProfessionalRegistrationNumber AS PRN - , jg.JobGroupName AS JobGroup - , CASE WHEN c.CustomField1PromptID = 10 THEN da.Answer1 WHEN c.CustomField2PromptID = 10 THEN da.Answer2 WHEN c.CustomField3PromptID = 10 THEN da.Answer3 WHEN c.CustomField4PromptID = 10 THEN da.Answer4 WHEN c.CustomField5PromptID = 10 THEN da.Answer5 WHEN c.CustomField6PromptID = 10 THEN da.Answer6 ELSE '' END AS 'ProgrammeCourse' - , CASE WHEN c.CustomField1PromptID = 4 THEN da.Answer1 WHEN c.CustomField2PromptID = 4 THEN da.Answer2 WHEN c.CustomField3PromptID = 4 THEN da.Answer3 WHEN c.CustomField4PromptID = 4 THEN da.Answer4 WHEN c.CustomField5PromptID = 4 THEN da.Answer5 WHEN c.CustomField6PromptID = 4 THEN da.Answer6 ELSE '' END AS 'Organisation' - , CASE WHEN c.CustomField1PromptID = 1 THEN da.Answer1 WHEN c.CustomField2PromptID = 1 THEN da.Answer2 WHEN c.CustomField3PromptID = 1 THEN da.Answer3 WHEN c.CustomField4PromptID = 1 THEN da.Answer4 WHEN c.CustomField5PromptID = 1 THEN da.Answer5 WHEN c.CustomField6PromptID = 1 THEN da.Answer6 ELSE '' END AS 'DepartmentTeam' - , dbo.GetOtherCentresForSelfAssessment(da.UserID, @SelfAssessmentID, c.CentreID) AS OtherCentres - , CASE - WHEN aa.ID IS NULL THEN 'Learner' - WHEN aa.IsCentreManager = 1 THEN 'Centre Manager' - WHEN aa.IsCentreAdmin = 1 AND aa.IsCentreManager = 0 THEN 'Centre Admin' - WHEN aa.IsSupervisor = 1 THEN 'Supervisor' - WHEN aa.IsNominatedSupervisor = 1 THEN 'Nominated supervisor' - END AS DLSRole - , da.DateRegistered AS Registered - , ca.StartedDate AS Started - , ca.LastAccessed - , COALESCE(COUNT(DISTINCT LAR.Optional), NULL) AS [OptionalProficienciesAssessed] - , COALESCE(COUNT(DISTINCT LAR.SelfAssessed), NULL) AS [SelfAssessedAchieved] - , COALESCE(COUNT(DISTINCT LAR.Confirmed), NULL) AS [ConfirmedResults] - , max(casv.Requested) AS SignOffRequested - , max(1*casv.SignedOff) AS SignOffAchieved - , min(casv.Verified) AS ReviewedDate - FROM - CandidateAssessments AS ca INNER JOIN - DelegateAccounts AS da ON ca.DelegateUserID = da.UserID and da.CentreID = @centreId INNER JOIN - Users as u ON u.ID = da.UserID INNER JOIN - SelfAssessments AS sa INNER JOIN - CentreSelfAssessments AS csa ON sa.ID = csa.SelfAssessmentID INNER JOIN - Centres AS c ON csa.CentreID = c.CentreID ON da.CentreID = c.CentreID AND ca.SelfAssessmentID = sa.ID INNER JOIN - JobGroups AS jg ON u.JobGroupID = jg.JobGroupID LEFT OUTER JOIN - AdminAccounts AS aa ON da.UserID = aa.UserID AND aa.CentreID = da.CentreID AND aa.Active = 1 LEFT OUTER JOIN - CandidateAssessmentSupervisors AS cas ON ca.ID = cas.CandidateAssessmentID left JOIN - CandidateAssessmentSupervisorVerifications AS casv ON casv.CandidateAssessmentSupervisorID = cas.ID LEFT JOIN - SupervisorDelegates AS sd ON cas.SupervisorDelegateId = sd.ID - LEFT OUTER JOIN LatestAssessmentResults AS LAR ON LAR.DelegateUserID = ca.DelegateUserID - WHERE - (sa.ID = @SelfAssessmentID) AND (sa.ArchivedDate IS NULL) AND (c.Active = 1) AND (ca.RemovedDate IS NULL AND ca.NonReportable = 0) - Group by sa.Name - , u.LastName + ', ' + u.FirstName - , da.Active - , u.ProfessionalRegistrationNumber - , c.CustomField1PromptID - , c.CustomField2PromptID - , c.CustomField3PromptID - , c.CustomField4PromptID - , c.CustomField5PromptID - , c.CustomField6PromptID - , c.CentreID - , jg.JobGroupName - , da.ID - , da.Answer1 - , da.Answer2 - , da.Answer3 - , da.Answer4 - , da.Answer5 - , da.Answer6 - , da.DateRegistered - , da.UserID - , aa.ID - , aa.IsCentreManager - , aa.IsCentreAdmin - , aa.IsSupervisor - , aa.IsNominatedSupervisor - , ca.StartedDate - , ca.LastAccessed - ORDER BY - SelfAssessment, u.LastName + ', ' + u.FirstName", - new { centreId, selfAssessmentId } - ); - } - } -} +namespace DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService +{ + using Dapper; + using DigitalLearningSolutions.Data.Models.SelfAssessments.Export; + using DigitalLearningSolutions.Data.Models.SelfAssessments; + using Microsoft.Extensions.Logging; + using System.Collections.Generic; + using System.Data; + using ClosedXML.Excel; + + public interface ISelfAssessmentReportDataService + { + IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId); + IEnumerable GetSelfAssessmentReportDataForCentre(int centreId, int selfAssessmentId); + } + public partial class SelfAssessmentReportDataService : ISelfAssessmentReportDataService + { + private readonly IDbConnection connection; + private readonly ILogger logger; + + public SelfAssessmentReportDataService(IDbConnection connection, ILogger logger) + { + this.connection = connection; + this.logger = logger; + } + + public IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId) + { + return connection.Query( + @"SELECT csa.SelfAssessmentID AS Id, sa.Name, + (SELECT COUNT (DISTINCT da.UserID) AS Learners + FROM CandidateAssessments AS ca1 INNER JOIN + DelegateAccounts AS da ON ca1.DelegateUserID = da.UserID + WHERE (da.CentreID = @centreId) AND (ca1.RemovedDate IS NULL) AND (ca1.SelfAssessmentID = csa.SelfAssessmentID) AND ca1.NonReportable=0) AS LearnerCount + FROM CentreSelfAssessments AS csa INNER JOIN + SelfAssessments AS sa ON csa.SelfAssessmentID = sa.ID + WHERE (csa.CentreID = @centreId) AND (sa.CategoryID = @categoryId) AND (sa.SupervisorResultsReview = 1) AND (sa.ArchivedDate IS NULL) OR + (csa.CentreID = @centreId) AND (sa.CategoryID = @categoryId) AND (sa.ArchivedDate IS NULL) AND (sa.SupervisorSelfAssessmentReview = 1) OR + (csa.CentreID = @centreId) AND (sa.SupervisorResultsReview = 1) AND (sa.ArchivedDate IS NULL) AND (@categoryId = 0) OR + (csa.CentreID = @centreId) AND (sa.ArchivedDate IS NULL) AND (sa.SupervisorSelfAssessmentReview = 1) AND (@categoryId = 0) + ORDER BY sa.Name", + new { centreId, categoryId = categoryId ??= 0 } + ); + } + + public IEnumerable GetSelfAssessmentReportDataForCentre(int centreId, int selfAssessmentId) + { + return connection.Query( + @"WITH LatestAssessmentResults AS + ( + SELECT s.DelegateUserID + , CASE WHEN COALESCE (rr.LevelRAG, 0) = 3 THEN s.ID ELSE NULL END AS SelfAssessed + , CASE WHEN sv.Verified IS NOT NULL AND sv.SignedOff = 1 AND COALESCE (rr.LevelRAG, 0) = 3 THEN s.ID ELSE NULL END AS Confirmed + , CASE WHEN sas.Optional = 1 THEN s.CompetencyID ELSE NULL END AS Optional + FROM SelfAssessmentResults AS s LEFT OUTER JOIN + SelfAssessmentStructure AS sas ON sas.SelfAssessmentID = @selfAssessmentId AND s.CompetencyID = sas.CompetencyID LEFT OUTER JOIN + SelfAssessmentResultSupervisorVerifications AS sv ON s.ID = sv.SelfAssessmentResultId AND sv.Superceded = 0 LEFT OUTER JOIN + CompetencyAssessmentQuestionRoleRequirements AS rr ON s.CompetencyID = rr.CompetencyID AND s.AssessmentQuestionID = rr.AssessmentQuestionID AND sas.SelfAssessmentID = rr.SelfAssessmentID AND s.Result = rr.LevelValue + WHERE (sas.SelfAssessmentID = @selfAssessmentId) + ) + SELECT + sa.Name AS SelfAssessment + , u.LastName + ', ' + u.FirstName AS Learner + , da.Active AS LearnerActive + , u.ProfessionalRegistrationNumber AS PRN + , jg.JobGroupName AS JobGroup + , da.Answer1 AS RegistrationAnswer1 + , da.Answer2 AS RegistrationAnswer2 + , da.Answer3 AS RegistrationAnswer3 + , da.Answer4 AS RegistrationAnswer4 + , da.Answer5 AS RegistrationAnswer5 + , da.Answer6 AS RegistrationAnswer6 + , dbo.GetOtherCentresForSelfAssessment(da.UserID, @SelfAssessmentID, c.CentreID) AS OtherCentres + , CASE + WHEN aa.ID IS NULL THEN 'Learner' + WHEN aa.IsCentreManager = 1 THEN 'Centre Manager' + WHEN aa.IsCentreAdmin = 1 AND aa.IsCentreManager = 0 THEN 'Centre Admin' + WHEN aa.IsSupervisor = 1 THEN 'Supervisor' + WHEN aa.IsNominatedSupervisor = 1 THEN 'Nominated supervisor' + END AS DLSRole + , da.DateRegistered AS Registered + , ca.StartedDate AS Started + , ca.LastAccessed + , COALESCE(COUNT(DISTINCT LAR.Optional), NULL) AS [OptionalProficienciesAssessed] + , COALESCE(COUNT(DISTINCT LAR.SelfAssessed), NULL) AS [SelfAssessedAchieved] + , COALESCE(COUNT(DISTINCT LAR.Confirmed), NULL) AS [ConfirmedResults] + , max(casv.Requested) AS SignOffRequested + , max(1*casv.SignedOff) AS SignOffAchieved + , min(casv.Verified) AS ReviewedDate + FROM + CandidateAssessments AS ca INNER JOIN + DelegateAccounts AS da ON ca.DelegateUserID = da.UserID and da.CentreID = @centreId INNER JOIN + Users as u ON u.ID = da.UserID INNER JOIN + SelfAssessments AS sa INNER JOIN + CentreSelfAssessments AS csa ON sa.ID = csa.SelfAssessmentID INNER JOIN + Centres AS c ON csa.CentreID = c.CentreID ON da.CentreID = c.CentreID AND ca.SelfAssessmentID = sa.ID INNER JOIN + JobGroups AS jg ON u.JobGroupID = jg.JobGroupID LEFT OUTER JOIN + AdminAccounts AS aa ON da.UserID = aa.UserID AND aa.CentreID = da.CentreID AND aa.Active = 1 LEFT OUTER JOIN + CandidateAssessmentSupervisors AS cas ON ca.ID = cas.CandidateAssessmentID left JOIN + CandidateAssessmentSupervisorVerifications AS casv ON casv.CandidateAssessmentSupervisorID = cas.ID LEFT JOIN + SupervisorDelegates AS sd ON cas.SupervisorDelegateId = sd.ID + LEFT OUTER JOIN LatestAssessmentResults AS LAR ON LAR.DelegateUserID = ca.DelegateUserID + WHERE + (sa.ID = @SelfAssessmentID) AND (sa.ArchivedDate IS NULL) AND (c.Active = 1) AND (ca.RemovedDate IS NULL AND ca.NonReportable = 0) + Group by sa.Name + , u.LastName + ', ' + u.FirstName + , da.Active + , u.ProfessionalRegistrationNumber + , c.CustomField1PromptID + , c.CustomField2PromptID + , c.CustomField3PromptID + , c.CustomField4PromptID + , c.CustomField5PromptID + , c.CustomField6PromptID + , c.CentreID + , jg.JobGroupName + , da.ID + , da.Answer1 + , da.Answer2 + , da.Answer3 + , da.Answer4 + , da.Answer5 + , da.Answer6 + , da.DateRegistered + , da.UserID + , aa.ID + , aa.IsCentreManager + , aa.IsCentreAdmin + , aa.IsSupervisor + , aa.IsNominatedSupervisor + , ca.StartedDate + , ca.LastAccessed + ORDER BY + SelfAssessment, u.LastName + ', ' + u.FirstName", + new { centreId, selfAssessmentId } + ); + } + } +} diff --git a/DigitalLearningSolutions.Data/Models/SelfAssessments/Export/SelfAssessmentReportData.cs b/DigitalLearningSolutions.Data/Models/SelfAssessments/Export/SelfAssessmentReportData.cs index 27c3d31bc7..847162bf47 100644 --- a/DigitalLearningSolutions.Data/Models/SelfAssessments/Export/SelfAssessmentReportData.cs +++ b/DigitalLearningSolutions.Data/Models/SelfAssessments/Export/SelfAssessmentReportData.cs @@ -1,26 +1,41 @@ -namespace DigitalLearningSolutions.Data.Models.SelfAssessments.Export -{ - using System; - public class SelfAssessmentReportData - { - public string? SelfAssessment { get; set; } - public string? Learner { get; set; } - public bool LearnerActive { get; set; } - public string? PRN { get; set; } - public string? JobGroup { get; set; } - public string? ProgrammeCourse { get; set; } - public string? Organisation { get; set; } - public string? DepartmentTeam { get; set; } - public string? OtherCentres { get; set; } - public string? DLSRole { get; set; } - public DateTime? Registered { get; set; } - public DateTime? Started { get; set; } - public DateTime? LastAccessed { get; set; } - public int? OptionalProficienciesAssessed { get; set; } - public int? SelfAssessedAchieved { get; set; } - public int? ConfirmedResults { get; set; } - public DateTime? SignOffRequested { get; set; } - public bool SignOffAchieved { get; set; } - public DateTime? ReviewedDate { get; set; } - } -} +namespace DigitalLearningSolutions.Data.Models.SelfAssessments.Export +{ + using System; + public class SelfAssessmentReportData + { + public string? SelfAssessment { get; set; } + public string? Learner { get; set; } + public bool LearnerActive { get; set; } + public string? PRN { get; set; } + public string? JobGroup { get; set; } + public string? RegistrationAnswer1 { get; set; } + public string? RegistrationAnswer2 { get; set; } + public string? RegistrationAnswer3 { get; set; } + public string? RegistrationAnswer4 { get; set; } + public string? RegistrationAnswer5 { get; set; } + public string? RegistrationAnswer6 { get; set; } + public string? OtherCentres { get; set; } + public string? DLSRole { get; set; } + public DateTime? Registered { get; set; } + public DateTime? Started { get; set; } + public DateTime? LastAccessed { get; set; } + public int? OptionalProficienciesAssessed { get; set; } + public int? SelfAssessedAchieved { get; set; } + public int? ConfirmedResults { get; set; } + public DateTime? SignOffRequested { get; set; } + public bool SignOffAchieved { get; set; } + public DateTime? ReviewedDate { get; set; } + + // we need this for iteration across the registration answers from Delegate Accounts which match the custom fields of Centres. + public string?[] CentreRegistrationPrompts => + new[] + { + RegistrationAnswer1, + RegistrationAnswer2, + RegistrationAnswer3, + RegistrationAnswer4, + RegistrationAnswer5, + RegistrationAnswer6, + }; + } +} diff --git a/DigitalLearningSolutions.Web/Services/SelfAssessmentReportService.cs b/DigitalLearningSolutions.Web/Services/SelfAssessmentReportService.cs index 18b6c46cdc..33c7c71160 100644 --- a/DigitalLearningSolutions.Web/Services/SelfAssessmentReportService.cs +++ b/DigitalLearningSolutions.Web/Services/SelfAssessmentReportService.cs @@ -1,129 +1,261 @@ -namespace DigitalLearningSolutions.Data.Services -{ - using ClosedXML.Excel; - using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService; - using DigitalLearningSolutions.Data.Models.Email; - using DigitalLearningSolutions.Data.Models.SelfAssessments; - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - - public interface ISelfAssessmentReportService - { - byte[] GetSelfAssessmentExcelExportForCentre(int centreId, int selfAssessmentId); - byte[] GetDigitalCapabilityExcelExportForCentre(int centreId); - IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId); - } - public class SelfAssessmentReportService : ISelfAssessmentReportService - { - private readonly IDCSAReportDataService dcsaReportDataService; - private readonly ISelfAssessmentReportDataService selfAssessmentReportDataService; - public SelfAssessmentReportService( - IDCSAReportDataService dcsaReportDataService, - ISelfAssessmentReportDataService selfAssessmentReportDataService - ) - { - this.dcsaReportDataService = dcsaReportDataService; - this.selfAssessmentReportDataService = selfAssessmentReportDataService; - } - private static void AddSheetToWorkbook(IXLWorkbook workbook, string sheetName, IEnumerable? dataObjects) - { - var sheet = workbook.Worksheets.Add(sheetName); - var table = sheet.Cell(1, 1).InsertTable(dataObjects); - table.Theme = XLTableTheme.TableStyleLight9; - sheet.Columns().AdjustToContents(); - } - - public IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId) - { - return selfAssessmentReportDataService.GetSelfAssessmentsForReportList(centreId, categoryId); - } - - public byte[] GetSelfAssessmentExcelExportForCentre(int centreId, int selfAssessmentId) - { - var selfAssessmentReportData = selfAssessmentReportDataService.GetSelfAssessmentReportDataForCentre(centreId, selfAssessmentId); - var reportData = selfAssessmentReportData.Select( - x => new - { - x.SelfAssessment, - x.Learner, - x.LearnerActive, - x.PRN, - x.JobGroup, - x.ProgrammeCourse, - x.Organisation, - x.DepartmentTeam, - x.OtherCentres, - x.DLSRole, - x.Registered, - x.Started, - x.LastAccessed, - x.OptionalProficienciesAssessed, - x.SelfAssessedAchieved, - x.ConfirmedResults, - x.SignOffRequested, - x.SignOffAchieved, - x.ReviewedDate - } - ); - using var workbook = new XLWorkbook(); - AddSheetToWorkbook(workbook, "SelfAssessmentLearners", reportData); - using var stream = new MemoryStream(); - workbook.SaveAs(stream); - return stream.ToArray(); - } - public byte[] GetDigitalCapabilityExcelExportForCentre(int centreId) - { - var delegateCompletionStatus = dcsaReportDataService.GetDelegateCompletionStatusForCentre(centreId); - var outcomeSummary = dcsaReportDataService.GetOutcomeSummaryForCentre(centreId); - var summary = delegateCompletionStatus.Select( - x => new - { - x.EnrolledMonth, - x.EnrolledYear, - x.FirstName, - x.LastName, - Email = (Guid.TryParse(x.Email, out _) ? string.Empty : x.Email), - x.CentreField1, - x.CentreField2, - x.CentreField3, - x.Status - } - ); - var details = outcomeSummary.Select( - x => new - { - x.EnrolledMonth, - x.EnrolledYear, - x.JobGroup, - x.CentreField1, - x.CentreField2, - x.CentreField3, - x.Status, - x.LearningLaunched, - x.LearningCompleted, - x.DataInformationAndContentConfidence, - x.DataInformationAndContentRelevance, - x.TeachinglearningAndSelfDevelopmentConfidence, - x.TeachinglearningAndSelfDevelopmentRelevance, - x.CommunicationCollaborationAndParticipationConfidence, - x.CommunicationCollaborationAndParticipationRelevance, - x.TechnicalProficiencyConfidence, - x.TechnicalProficiencyRelevance, - x.CreationInnovationAndResearchConfidence, - x.CreationInnovationAndResearchRelevance, - x.DigitalIdentityWellbeingSafetyAndSecurityConfidence, - x.DigitalIdentityWellbeingSafetyAndSecurityRelevance - } - ); - using var workbook = new XLWorkbook(); - AddSheetToWorkbook(workbook, "Delegate Completion Status", summary); - AddSheetToWorkbook(workbook, "Assessment Outcome Summary", outcomeSummary); - using var stream = new MemoryStream(); - workbook.SaveAs(stream); - return stream.ToArray(); - } - } - -} +namespace DigitalLearningSolutions.Data.Services +{ + using ClosedXML.Excel; + using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService; + using DigitalLearningSolutions.Data.Models.CustomPrompts; + using DigitalLearningSolutions.Data.Models.SelfAssessments; + using DigitalLearningSolutions.Data.Models.SelfAssessments.Export; + using DigitalLearningSolutions.Web.Services; + using System; + using System.Collections.Generic; + using System.Data; + using System.IO; + using System.Linq; + + public interface ISelfAssessmentReportService + { + byte[] GetSelfAssessmentExcelExportForCentre(int centreId, int selfAssessmentId); + byte[] GetDigitalCapabilityExcelExportForCentre(int centreId); + IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId); + } + public class SelfAssessmentReportService : ISelfAssessmentReportService + { + private const string SelfAssessment = "SelfAssessment"; + private const string Learner = "Leaner"; + private const string LearnerActive = "LearnerActive"; + private const string PRN = "PRN"; + private const string JobGroup = "JobGroup"; + private const string OtherCentres = "OtherCentres"; + private const string DLSRole = "DLSRole"; + private const string Registered = "Registered"; + private const string Started = "Started"; + private const string LastAccessed = "LastAccessed"; + private const string OptionalProficienciesAssessed = "OptionalProficienciesAssessed"; + private const string SelfAssessedAchieved = "SelfAssessedAchieved"; + private const string ConfirmedResults = "ConfirmedResults"; + private const string SignOffRequested = "SignOffRequested"; + private const string SignOffAchieved = "SignOffAchieved"; + private const string ReviewedDate = "ReviewedDate"; + + private readonly IDCSAReportDataService dcsaReportDataService; + private readonly ISelfAssessmentReportDataService selfAssessmentReportDataService; + private readonly ICentreRegistrationPromptsService registrationPromptsService; + public SelfAssessmentReportService( + IDCSAReportDataService dcsaReportDataService, + ISelfAssessmentReportDataService selfAssessmentReportDataService, + ICentreRegistrationPromptsService registrationPromptsService + ) + { + this.dcsaReportDataService = dcsaReportDataService; + this.selfAssessmentReportDataService = selfAssessmentReportDataService; + this.registrationPromptsService = registrationPromptsService; + } + private static void AddSheetToWorkbook(IXLWorkbook workbook, string sheetName, IEnumerable? dataObjects) + { + var sheet = workbook.Worksheets.Add(sheetName); + var table = sheet.Cell(1, 1).InsertTable(dataObjects); + table.Theme = XLTableTheme.TableStyleLight9; + sheet.Columns().AdjustToContents(); + } + + public IEnumerable GetSelfAssessmentsForReportList(int centreId, int? categoryId) + { + return selfAssessmentReportDataService.GetSelfAssessmentsForReportList(centreId, categoryId); + } + + public byte[] GetSelfAssessmentExcelExportForCentre(int centreId, int selfAssessmentId) + { + using var workbook = new XLWorkbook(); + var selfAssessmentReportData = selfAssessmentReportDataService.GetSelfAssessmentReportDataForCentre(centreId, selfAssessmentId); + PopulateSelfAssessmentSheetForCentre(workbook, centreId, selfAssessmentReportData); + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + return stream.ToArray(); + } + public byte[] GetDigitalCapabilityExcelExportForCentre(int centreId) + { + var delegateCompletionStatus = dcsaReportDataService.GetDelegateCompletionStatusForCentre(centreId); + var outcomeSummary = dcsaReportDataService.GetOutcomeSummaryForCentre(centreId); + var summary = delegateCompletionStatus.Select( + x => new + { + x.EnrolledMonth, + x.EnrolledYear, + x.FirstName, + x.LastName, + Email = (Guid.TryParse(x.Email, out _) ? string.Empty : x.Email), + x.CentreField1, + x.CentreField2, + x.CentreField3, + x.Status + } + ); + var details = outcomeSummary.Select( + x => new + { + x.EnrolledMonth, + x.EnrolledYear, + x.JobGroup, + x.CentreField1, + x.CentreField2, + x.CentreField3, + x.Status, + x.LearningLaunched, + x.LearningCompleted, + x.DataInformationAndContentConfidence, + x.DataInformationAndContentRelevance, + x.TeachinglearningAndSelfDevelopmentConfidence, + x.TeachinglearningAndSelfDevelopmentRelevance, + x.CommunicationCollaborationAndParticipationConfidence, + x.CommunicationCollaborationAndParticipationRelevance, + x.TechnicalProficiencyConfidence, + x.TechnicalProficiencyRelevance, + x.CreationInnovationAndResearchConfidence, + x.CreationInnovationAndResearchRelevance, + x.DigitalIdentityWellbeingSafetyAndSecurityConfidence, + x.DigitalIdentityWellbeingSafetyAndSecurityRelevance + } + ); + using var workbook = new XLWorkbook(); + AddSheetToWorkbook(workbook, "Delegate Completion Status", summary); + AddSheetToWorkbook(workbook, "Assessment Outcome Summary", outcomeSummary); + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + return stream.ToArray(); + } + + private void PopulateSelfAssessmentSheetForCentre(IXLWorkbook workbook, int centreId, IEnumerable selfAssessmentReportData) + { + var sheet = workbook.Worksheets.Add("SelfAssessmentLearners"); + // Set sheet to have outlining expand buttons at the top of the expanded section. + sheet.Outline.SummaryVLocation = XLOutlineSummaryVLocation.Top; + var customRegistrationPrompts = + registrationPromptsService.GetCentreRegistrationPromptsByCentreId(centreId); + var dataTable = new DataTable(); + + // did this to sequqence the element into a new form based on the order below + var reportData = selfAssessmentReportData.Select( + x => new + { + x.SelfAssessment, + x.Learner, + x.LearnerActive, + x.PRN, + x.JobGroup, + x.OtherCentres, + x.DLSRole, + x.Registered, + x.Started, + x.LastAccessed, + x.OptionalProficienciesAssessed, + x.SelfAssessedAchieved, + x.ConfirmedResults, + x.SignOffRequested, + x.SignOffAchieved, + x.ReviewedDate + } + ); + + // set the common header table for the excel sheet + SetUpCommonTableColumnsForSelfAssessment(customRegistrationPrompts, dataTable); + + // insert the header table into the sheet starting at the first position + var headerTable = sheet.Cell(1, 1).InsertTable(dataTable); + + foreach (var report in selfAssessmentReportData) + { + //iterate and add every record from the query to the datatable + AddSelfAssessmentReportToSheet(sheet, dataTable, customRegistrationPrompts, report); + } + + var insertedDataRange = sheet.Cell(GetNextEmptyRowNumber(sheet), 1).InsertData(dataTable.Rows); + if (dataTable.Rows.Count > 0) + { + sheet.Rows(insertedDataRange.FirstRow().RowNumber(), insertedDataRange.LastRow().RowNumber()) + .Group(true); + } + + //format the sheet rows and content + sheet.Rows().Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; + headerTable.Theme = XLTableTheme.TableStyleLight9; + + sheet.Columns().AdjustToContents(); + } + + private static void SetUpCommonTableColumnsForSelfAssessment(CentreRegistrationPrompts centreRegistrationPrompts, DataTable dataTable) + { + dataTable.Columns.AddRange( + new[] {new DataColumn(SelfAssessment), new DataColumn(Learner), new DataColumn(LearnerActive), new DataColumn(PRN), + new DataColumn(JobGroup)} + ); + foreach (var prompt in centreRegistrationPrompts.CustomPrompts) + { + dataTable.Columns.Add( + !dataTable.Columns.Contains(prompt.PromptText) + ? prompt.PromptText + : $"{prompt.PromptText} (Prompt {prompt.RegistrationField.Id})" + ); + } + + dataTable.Columns.AddRange( + new[] + { + new DataColumn(OtherCentres), + new DataColumn(DLSRole), + new DataColumn(Registered), + new DataColumn(Started), + new DataColumn(LastAccessed), + new DataColumn(OptionalProficienciesAssessed), + new DataColumn(SelfAssessedAchieved), + new DataColumn(ConfirmedResults), + new DataColumn(SignOffRequested), + new DataColumn(SignOffAchieved), + new DataColumn(ReviewedDate) + } + ); + } + + private static void AddSelfAssessmentReportToSheet(IXLWorksheet sheet, DataTable dataTable, CentreRegistrationPrompts centreRegistrationPrompts, + SelfAssessmentReportData report) + { + var row = dataTable.NewRow(); + row[SelfAssessment] = report.SelfAssessment; + row[Learner] = report.Learner; + row[LearnerActive] = report.LearnerActive; + row[PRN] = report.PRN; + row[JobGroup] = report.JobGroup; + + // map the individual registration fields with the centre registration custom prompts + foreach (var prompt in centreRegistrationPrompts.CustomPrompts) + { + if (dataTable.Columns.Contains($"{prompt.PromptText} (Prompt {prompt.RegistrationField.Id})")) + { + row[$"{prompt.PromptText} (Prompt {prompt.RegistrationField.Id})"] = + report.CentreRegistrationPrompts[prompt.RegistrationField.Id - 1]; + } + else + { + row[prompt.PromptText] = + report.CentreRegistrationPrompts[prompt.RegistrationField.Id - 1]; + } + } + row[OtherCentres] = report.OtherCentres; + row[DLSRole] = report.DLSRole; + row[Registered] = report.Registered?.ToString("dd/MM/yyyy"); + row[Started] = report.Started?.ToString("dd/MM/yyyy"); + row[LastAccessed] = report.LastAccessed?.ToString("dd/MM/yyyy"); + row[OptionalProficienciesAssessed] = report.OptionalProficienciesAssessed; + row[SelfAssessedAchieved] = report.SelfAssessedAchieved; + row[ConfirmedResults] = report.ConfirmedResults; + row[SignOffRequested] = report.SignOffRequested?.ToString("dd/MM/yyyy"); + row[SignOffAchieved] = report.SignOffAchieved ? "Yes" : "No"; + row[ReviewedDate] = report.ReviewedDate?.ToString("dd/MM/yyyy"); + dataTable.Rows.Add(row); + } + + private static int GetNextEmptyRowNumber(IXLWorksheet sheet) + { + return sheet.LastRowUsed().RowNumber() + 1; + } + } +}