Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
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<SelfAssessmentSelect> GetSelfAssessmentsForReportList(int centreId, int? categoryId);
IEnumerable<SelfAssessmentReportData> GetSelfAssessmentReportDataForCentre(int centreId, int selfAssessmentId);
}
public partial class SelfAssessmentReportDataService : ISelfAssessmentReportDataService
{
private readonly IDbConnection connection;
private readonly ILogger<SelfAssessmentReportDataService> logger;

public SelfAssessmentReportDataService(IDbConnection connection, ILogger<SelfAssessmentReportDataService> logger)
{
this.connection = connection;
this.logger = logger;
}

public IEnumerable<SelfAssessmentSelect> GetSelfAssessmentsForReportList(int centreId, int? categoryId)
{
return connection.Query<SelfAssessmentSelect>(
@"SELECT csa.SelfAssessmentID AS Id, sa.Name,
(SELECT COUNT(*) FROM
CandidateAssessments ca1 INNER JOIN
Candidates c1 ON ca1.CandidateID = c1.CandidateID
WHERE c1.CentreID = @centreId AND ca1.SelfAssessmentID = sa.ID AND ca1.RemovedDate IS NULL) 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.SupervisorSelfAssessmentReview = 1) AND (sa.ArchivedDate IS NULL) OR
(csa.CentreID = @centreId) AND (@categoryId = 0) AND (sa.SupervisorResultsReview = 1) AND (sa.ArchivedDate IS NULL) OR
(csa.CentreID = @centreId) AND (@categoryId = 0) AND (sa.SupervisorSelfAssessmentReview = 1) AND (sa.ArchivedDate IS NULL)
ORDER BY sa.Name",
new { centreId, categoryId = categoryId ??= 0 }
);
}

public IEnumerable<SelfAssessmentReportData> GetSelfAssessmentReportDataForCentre(int centreId, int selfAssessmentId)
{
return connection.Query<SelfAssessmentReportData>(
@"WITH LatestAssessmentResults AS
(
SELECT s.CandidateID
, CASE WHEN COALESCE (rr.LevelRAG, 0) = 3 THEN s.ID ELSE 0 END AS SelfAssessed
, CASE WHEN sv.Verified IS NOT NULL AND sv.SignedOff = 1 AND COALESCE (rr.LevelRAG, 0) = 3 THEN s.ID ELSE 0 END AS Confirmed
, CASE WHEN sas.Optional = 1 THEN s.CompetencyID ELSE 0 END AS Optional
FROM SelfAssessmentResults AS s INNER JOIN
(SELECT MAX(ID) AS ID
FROM SelfAssessmentResults as sar1 INNER JOIN
Candidates as ca1 on sar1.CandidateID = ca1.CandidateID AND ca1.CentreID = @centreId
WHERE (SelfAssessmentID = @selfAssessmentId)
GROUP BY ca1.CandidateID, CompetencyID, AssessmentQuestionID) AS t ON s.ID = t.ID INNER JOIN
SelfAssessmentStructure AS sas ON s.SelfAssessmentID = sas.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 s.SelfAssessmentID = rr.SelfAssessmentID AND s.Result = rr.LevelValue
WHERE (s.SelfAssessmentID = @selfAssessmentId)
)
SELECT
sa.Name AS SelfAssessment
, can.LastName + ', ' + can.FirstName AS Learner
, can.ProfessionalRegistrationNumber AS PRN
, jg.JobGroupName AS JobGroup
, CASE WHEN c.CustomField1PromptID = 10 THEN can.Answer1 WHEN c.CustomField2PromptID = 10 THEN can.Answer2 WHEN c.CustomField3PromptID = 10 THEN can.Answer3 WHEN c.CustomField4PromptID = 10 THEN can.Answer4 WHEN c.CustomField5PromptID = 10 THEN can.Answer5 WHEN c.CustomField6PromptID = 10 THEN can.Answer6 ELSE '' END AS 'ProgrammeCourse'
, CASE WHEN c.CustomField1PromptID = 4 THEN can.Answer1 WHEN c.CustomField2PromptID = 4 THEN can.Answer2 WHEN c.CustomField3PromptID = 4 THEN can.Answer3 WHEN c.CustomField4PromptID = 4 THEN can.Answer4 WHEN c.CustomField5PromptID = 4 THEN can.Answer5 WHEN c.CustomField6PromptID = 4 THEN can.Answer6 ELSE '' END AS 'Organisation'
, CASE WHEN c.CustomField1PromptID = 1 THEN can.Answer1 WHEN c.CustomField2PromptID = 1 THEN can.Answer2 WHEN c.CustomField3PromptID = 1 THEN can.Answer3 WHEN c.CustomField4PromptID = 1 THEN can.Answer4 WHEN c.CustomField5PromptID = 1 THEN can.Answer5 WHEN c.CustomField6PromptID = 1 THEN can.Answer6 ELSE '' END AS 'DepartmentTeam'
, CASE
WHEN au.AdminID IS NULL THEN 'Learner'
WHEN au.IsCentreManager = 1 THEN 'Centre Manager'
WHEN au.CentreAdmin = 1 AND au.IsCentreManager = 0 THEN 'Centre Admin'
WHEN au.Supervisor = 1 THEN 'Supervisor'
WHEN au.NominatedSupervisor = 1 THEN 'Nominated supervisor'
END AS DLSRole
, can.DateRegistered AS Registered
, ca.StartedDate AS Started
, ca.LastAccessed
, COALESCE(COUNT(DISTINCT LAR.Optional), 0) AS [OptionalProficiencies]
, COALESCE(COUNT(DISTINCT LAR.SelfAssessed),0) AS [SelfAssessedAchieved]
, COALESCE(COUNT(DISTINCT LAR.Confirmed), 0) AS [ConfirmedResults]
, max(casv.Requested) AS SignOffRequested
, max(1*casv.SignedOff) AS SignOffAchieved
, min(casv.Verified) AS ReviewedDate
FROM
CandidateAssessments AS ca INNER JOIN
Candidates AS can ON ca.CandidateID = can.CandidateID AND can.CentreID = @centreId 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 can.CentreID = c.CentreID AND ca.SelfAssessmentID = sa.ID INNER JOIN
JobGroups AS jg ON can.JobGroupID = jg.JobGroupID LEFT OUTER JOIN
AdminUsers AS au ON can.EmailAddress = au.Email AND can.CentreID = au.CentreID 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.CandidateID = can.CandidateID
WHERE
(sa.ID = @SelfAssessmentID) AND (sa.ArchivedDate IS NULL) AND (c.Active = 1) AND (ca.RemovedDate IS NULL)
Group by sa.Name
, can.LastName + ', ' + can.FirstName
, can.ProfessionalRegistrationNumber
, c.CustomField1PromptID
, c.CustomField2PromptID
, c.CustomField3PromptID
, c.CustomField4PromptID
, c.CustomField5PromptID
, c.CustomField6PromptID
, jg.JobGroupName
, can.CandidateID
, can.Answer1
, can.Answer2
, can.Answer3
, can.Answer4
, can.Answer5
, can.Answer6
, can.DateRegistered
, au.AdminID
, au.IsCentreManager
, au.CentreAdmin
, au.Supervisor
, au.NominatedSupervisor
, ca.StartedDate
, ca.LastAccessed
ORDER BY
SelfAssessment, can.LastName + ', ' + can.FirstName",
new { centreId, selfAssessmentId }
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace DigitalLearningSolutions.Data.Models.SelfAssessments.Export
{
using System;
public class SelfAssessmentReportData
{
public string? SelfAssessment { get; set; }
public string? Learner { 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? DLSRole { get; set; }
public DateTime? Registered { get; set; }
public DateTime? Started { get; set; }
public DateTime? LastAccessed { get; set; }
public int? OptionalProficiencies { 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; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace DigitalLearningSolutions.Data.Models.SelfAssessments
{
public class SelfAssessmentSelect
{
public int Id { get; set; }
public string? Name { get; set; }
public int LearnerCount { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,38 @@
{
using ClosedXML.Excel;
using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService;
using DigitalLearningSolutions.Data.Models.SelfAssessments;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public interface ISelfAssessmentReportService
{
byte[] GetDigitalCapabilityExcelExportForCentre(int centreId);
byte[] GetSelfAssessmentExcelExportForCentre(int centreId, int selfAssessmentId);
IEnumerable<SelfAssessmentSelect> GetSelfAssessmentsForReportList(int centreId, int? categoryId);
}
public class SelfAssessmentReportService : ISelfAssessmentReportService
{
private readonly IDCSAReportDataService dcsaReportDataService;
private readonly ISelfAssessmentReportDataService selfAssessmentReportDataService;

public SelfAssessmentReportService(
IDCSAReportDataService dcsaReportDataService
IDCSAReportDataService dcsaReportDataService,
ISelfAssessmentReportDataService selfAssessmentReportDataService
)
{
this.dcsaReportDataService = dcsaReportDataService;
this.selfAssessmentReportDataService = selfAssessmentReportDataService;
}
private static void AddSheetToWorkbook(IXLWorkbook workbook, string sheetName, IEnumerable<object>? dataObjects)
{
var sheet = workbook.Worksheets.Add(sheetName);
var table = sheet.Cell(1, 1).InsertTable(dataObjects);
table.Theme = XLTableTheme.TableStyleLight9;
sheet.Columns().AdjustToContents();
}

public byte[] GetDigitalCapabilityExcelExportForCentre(int centreId)
{
var delegateCompletionStatus = dcsaReportDataService.GetDelegateCompletionStatusForCentre(centreId);
Expand Down Expand Up @@ -71,12 +85,41 @@ public byte[] GetDigitalCapabilityExcelExportForCentre(int centreId)
workbook.SaveAs(stream);
return stream.ToArray();
}
private static void AddSheetToWorkbook(IXLWorkbook workbook, string sheetName, IEnumerable<object>? dataObjects)
public IEnumerable<SelfAssessmentSelect> GetSelfAssessmentsForReportList(int centreId, int? categoryId)
{
var sheet = workbook.Worksheets.Add(sheetName);
var table = sheet.Cell(1, 1).InsertTable(dataObjects);
table.Theme = XLTableTheme.TableStyleLight9;
sheet.Columns().AdjustToContents();
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.PRN,
x.JobGroup,
x.ProgrammeCourse,
x.Organisation,
x.DepartmentTeam,
x.DLSRole,
x.Registered,
x.Started,
x.LastAccessed,
x.OptionalProficiencies,
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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using DigitalLearningSolutions.Web.Models.Enums;
using DigitalLearningSolutions.Data.Enums;
using System;
using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.SelfAssessmentReports;

[FeatureGate(FeatureFlags.RefactoredTrackingSystem)]
[Authorize(Policy = CustomPolicies.UserCentreAdmin)]
[SetDlsSubApplication(nameof(DlsSubApplication.TrackingSystem))]
Expand All @@ -26,10 +28,13 @@ ISelfAssessmentReportService selfAssessmentReportService
}
public IActionResult Index()
{
return View();
var centreId = User.GetCentreId();
var categoryId = User.GetAdminCourseCategoryFilter();
var model = new SelfAssessmentReportsViewModel(selfAssessmentReportService.GetSelfAssessmentsForReportList(centreId, categoryId));
return View(model);
}
[HttpGet]
[Route("Download")]
[Route("DownloadDcsa")]
public IActionResult DownloadDigitalCapabilityToExcel()
{
var centreId = User.GetCentreId();
Expand All @@ -41,5 +46,18 @@ public IActionResult DownloadDigitalCapabilityToExcel()
fileName
);
}
[HttpGet]
[Route("DownloadReport")]
public IActionResult DownloadSelfAssessmentReport(int selfAssessmentId)
{
var centreId = User.GetCentreId();
var dataFile = selfAssessmentReportService.GetSelfAssessmentExcelExportForCentre(centreId, selfAssessmentId);
var fileName = $"Competency Self Assessment Report - Centre {centreId} - downloaded {DateTime.Today:yyyy-MM-dd}.xlsx";
return File(
dataFile,
FileHelper.GetContentTypeFromFileName(fileName),
fileName
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@
<TypeScriptCompile Include="Scripts\trackingSystem\reports.ts" />
</ItemGroup>

<ItemGroup>
<Folder Include="ViewModels\TrackingSystem\Centre\NewFolder\" />
</ItemGroup>

<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec Command="yarn install --frozen-lockfile" />
Expand Down
1 change: 1 addition & 0 deletions DigitalLearningSolutions.Web/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ private static void RegisterDataServices(IServiceCollection services)
services.AddScoped<ICandidateAssessmentDownloadFileService, CandidateAssessmentDownloadFileService>();
services.AddScoped<IBrandsDataService, BrandsDataService>();
services.AddScoped<IDCSAReportDataService, DCSAReportDataService>();
services.AddScoped<ISelfAssessmentReportDataService, SelfAssessmentReportDataService>();
}

private static void RegisterHelpers(IServiceCollection services)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Centre.SelfAssessmentReports
{
using DigitalLearningSolutions.Data.Models.SelfAssessments;
using System.Collections;
using System.Collections.Generic;

public class SelfAssessmentReportsViewModel
{
public SelfAssessmentReportsViewModel(
IEnumerable<SelfAssessmentSelect> selfAssessmentSelects
)
{
SelfAssessmentSelects = selfAssessmentSelects;
}

public IEnumerable<SelfAssessmentSelect> SelfAssessmentSelects { get; set; }
}
}
Loading