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
Expand Up @@ -248,5 +248,29 @@ public void GetCourseStatisticsAtCentreForCategoryID_should_return_course_statis
result.Should().HaveCount(260);
result.First().Should().BeEquivalentTo(expectedFirstCourse);
}

[Test]
public void GetCourseDetailsByIdAtCentreForCategoryId_should_return_course_details_correctly()
{
// Given
const int customisationId = 100;
const int centreId = 101;
const int categoryId = 0;
var fixedCreationDateTime = DateTime.UtcNow;
var expectedLastAccess = new DateTime(2014, 03, 31, 13, 00, 23, 457);
var expectedCourseDetails = CourseDetailsTestHelper.GetDefaultCourseDetails(
createdTime: fixedCreationDateTime,
lastAccessed: expectedLastAccess
);

// When
var result =
courseDataService.GetCourseDetails(customisationId, centreId, categoryId)!;
// Overwrite the created time as it is populated by a default constraint and not consistent over different databases
result.CreatedTime = fixedCreationDateTime;

// Then
result.Should().BeEquivalentTo(expectedCourseDetails);
}
}
}
121 changes: 121 additions & 0 deletions DigitalLearningSolutions.Data.Tests/Models/CourseDetailsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
namespace DigitalLearningSolutions.Data.Tests.Models
{
using DigitalLearningSolutions.Data.Models.Courses;
using FluentAssertions;
using NUnit.Framework;

public class CourseDetailsTests
{
[Test]
public void RefreshedToCourseName_should_be_Same_Course_if_RefreshToId_is_Zero()
{
// When
var courseDetails = new CourseDetails
{
ApplicationName = "Original course",
CustomisationName = "name",
RefreshToCustomisationId = 0
};

// Then
courseDetails.RefreshToCourseName.Should().BeEquivalentTo("Same course");
}

[Test]
public void RefreshedToCourseName_should_be_CourseName_if_RefreshToId_is_CustomisationId()
{
// When
var courseDetails = new CourseDetails
{
ApplicationName = "Original course",
CustomisationName = "name",
CustomisationId = 5,
RefreshToCustomisationId = 5
};

// Then
courseDetails.RefreshToCourseName.Should().BeEquivalentTo("Same course");
}


[Test]
public void RefreshedToCourseName_should_be_from_refresh_course_if_RefreshToId_is_not_zero_or_CustomisationId()
{
// When
var courseDetails = new CourseDetails
{
ApplicationName = "Original course",
CustomisationName = "name",
CustomisationId = 5,
RefreshToCustomisationId = 10,
RefreshToApplicationName = "Refreshed course",
RefreshToCustomisationName = "refreshing"
};

// Then
courseDetails.RefreshToCourseName.Should().BeEquivalentTo("Refreshed course - refreshing");
}

[Test]
public void RefreshedToCourseName_should_be_from_refresh_course_application_if_RefreshToId_is_not_zero_or_CustomisationId_and_customisation_name_is_null()
{
// When
var courseDetails = new CourseDetails
{
ApplicationName = "Original course",
CustomisationName = "name",
CustomisationId = 5,
RefreshToCustomisationId = 10,
RefreshToApplicationName = "Refreshed course",
RefreshToCustomisationName = null
};

// Then
courseDetails.RefreshToCourseName.Should().BeEquivalentTo("Refreshed course");
}

[Test]
public void CourseName_should_be_ApplicationName_and_CustomisationName_if_CustomisationName_not_null()
{
// When
var courseDetails = new CourseDetails
{
ApplicationName = "Original course",
CustomisationName = "name",
};

// Then
courseDetails.CourseName.Should().BeEquivalentTo("Original course - name");
}


[Test]
public void CourseName_should_be_ApplicationName_if_CustomisationName_is_blank()
{
// When
var courseDetails = new CourseDetails
{
ApplicationName = "Original course",
CustomisationName = string.Empty
};

// Then
courseDetails.CourseName.Should().BeEquivalentTo("Original course");
}

[Test]
public void InProgressCount_should_be_TotalDelegates_minus_CompletedCount()
{
// When
var courseDetails = new CourseDetails
{
DelegateCount = 123,
CompletedCount = 81
};

// Then
courseDetails.InProgressCount.Should().Be(42);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace DigitalLearningSolutions.Data.Tests.TestHelpers
{
using System;
using DigitalLearningSolutions.Data.Models.Courses;

public static class CourseDetailsTestHelper
{
public static CourseDetails GetDefaultCourseDetails(
int customisationId = 100,
int centreId = 101,
string applicationName = "Entry Level - Win XP, Office 2003/07 OLD",
string customisationName = "Standard",
int currentVersion = 12,
DateTime? createdTime = null,
DateTime? lastAccessed = null,
string? password = null,
string? notificationEmails = null,
bool postLearningAssessment = false,
bool isAssessed = true,
int tutCompletionThreshold = 100,
bool diagAssess = false,
int diagCompletionThreshold = 85,
bool selfRegister = true,
bool diagObjSelect = true,
bool hideInLearnerPortal = false,
bool active = false,
int delegateCount = 25,
int completedCount = 5,
int completeWithinMonths = 0,
int validityMonths = 0,
bool mandatory = false,
bool autoRefresh = false,
int refreshToCustomisationId = 0,
string? refreshToApplicationName = null,
string? refreshToCustomisationName = null,
int autoRefreshMonths = 0,
bool applyLpDefaultsToSelfEnrol = false
)
{
return new CourseDetails
{
CustomisationId = customisationId,
CentreId = centreId,
ApplicationName = applicationName,
CustomisationName = customisationName,
CurrentVersion = currentVersion,
CreatedTime = createdTime ?? DateTime.UtcNow,
LastAccessed = lastAccessed ?? DateTime.UtcNow,
Password = password,
NotificationEmails = notificationEmails,
PostLearningAssessment = postLearningAssessment,
IsAssessed = isAssessed,
TutCompletionThreshold = tutCompletionThreshold,
DiagAssess = diagAssess,
DiagCompletionThreshold = diagCompletionThreshold,
SelfRegister = selfRegister,
DiagObjSelect = diagObjSelect,
HideInLearnerPortal = hideInLearnerPortal,
Active = active,
DelegateCount = delegateCount,
CompletedCount = completedCount,
CompleteWithinMonths = completeWithinMonths,
ValidityMonths = validityMonths,
Mandatory = mandatory,
AutoRefresh = autoRefresh,
RefreshToCustomisationId = refreshToCustomisationId,
RefreshToApplicationName = refreshToApplicationName,
RefreshToCustomisationName = refreshToCustomisationName,
AutoRefreshMonths = autoRefreshMonths,
ApplyLpDefaultsToSelfEnrol = applyLpDefaultsToSelfEnrol
};
}
}
}
60 changes: 59 additions & 1 deletion DigitalLearningSolutions.Data/DataServices/CourseDataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Dapper;
using DigitalLearningSolutions.Data.Models.Courses;
using Microsoft.Extensions.Logging;
Expand All @@ -17,6 +18,7 @@ public interface ICourseDataService
void EnrolOnSelfAssessment(int selfAssessmentId, int candidateId);
int GetNumberOfActiveCoursesAtCentreForCategory(int centreId, int categoryId);
IEnumerable<CourseStatistics> GetCourseStatisticsAtCentreForCategoryId(int centreId, int categoryId);
CourseDetails? GetCourseDetails(int customisationId, int centreId, int categoryId);
}

public class CourseDataService : ICourseDataService
Expand All @@ -26,7 +28,8 @@ public class CourseDataService : ICourseDataService
FROM dbo.Progress AS pr
INNER JOIN dbo.Candidates AS can ON can.CandidateID = pr.CandidateID
WHERE pr.CustomisationID = cu.CustomisationID
AND can.CentreID = @centreId) AS DelegateCount";
AND can.CentreID = @centreId
AND RemovedDate IS NULL) AS DelegateCount";

private const string CompletedCountQuery =
@"(SELECT COUNT(pr.CandidateID)
Expand All @@ -49,6 +52,15 @@ FROM dbo.AssessAttempts AS aa
WHERE aa.CustomisationID = cu.CustomisationID AND aa.[Status] = 1
AND can.CentreID = @centreId) AS AttemptsPassed";

private const string LastAccessedQuery =
@"(SELECT TOP 1 SubmittedTime
FROM dbo.Progress AS pr
INNER JOIN dbo.Candidates AS can ON can.CandidateID = pr.CandidateID
WHERE pr.CustomisationID = cu.CustomisationID
AND can.CentreID = @centreId
AND RemovedDate IS NULL
ORDER BY SubmittedTime DESC) AS LastAccessed";

private readonly IDbConnection connection;
private readonly ILogger<CourseDataService> logger;

Expand Down Expand Up @@ -185,5 +197,51 @@ FROM dbo.Customisations AS cu
new { centreId, categoryId }
);
}

public CourseDetails? GetCourseDetails(int customisationId, int centreId, int categoryId)
{
return connection.Query<CourseDetails>(
@$"SELECT
cu.CustomisationID,
cu.CentreID,
cu.Active,
ap.ApplicationName,
cu.CustomisationName,
cu.CurrentVersion,
cu.CreatedTime,
cu.[Password],
cu.NotificationEmails,
ap.PLAssess AS PostLearningAssessment,
cu.IsAssessed,
ap.DiagAssess,
cu.TutCompletionThreshold,
cu.DiagCompletionThreshold,
cu.SelfRegister,
cu.DiagObjSelect,
cu.HideInLearnerPortal,
cu.CompleteWithinMonths,
cu.ValidityMonths,
cu.Mandatory,
cu.AutoRefresh,
cu.RefreshToCustomisationID,
refreshToCu.CustomisationName AS refreshToCustomisationName,
refreshToAp.ApplicationName AS refreshToApplicationName,
cu.AutoRefreshMonths,
cu.ApplyLPDefaultsToSelfEnrol,
{LastAccessedQuery},
{DelegateCountQuery},
{CompletedCountQuery}
FROM dbo.Customisations AS cu
INNER JOIN dbo.Applications AS ap ON ap.ApplicationID = cu.ApplicationID
LEFT JOIN dbo.Customisations AS refreshToCu ON refreshToCu.CustomisationID = cu.RefreshToCustomisationId
LEFT JOIN dbo.Applications AS refreshToAp ON refreshToAp.ApplicationID = refreshToCu.ApplicationID
WHERE
(ap.CourseCategoryID = @categoryId OR @categoryId = 0)
AND cu.CentreID = @centreId
AND ap.ArchivedDate IS NULL
AND cu.CustomisationID = @customisationId",
new { customisationId, centreId, categoryId }
).FirstOrDefault();
}
}
}
63 changes: 63 additions & 0 deletions DigitalLearningSolutions.Data/Models/Courses/CourseDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace DigitalLearningSolutions.Data.Models.Courses
{
using System;

public class CourseDetails
{
public int CustomisationId { get; set; }
public int CentreId { get; set; }
public string ApplicationName { get; set; }
public string CustomisationName { get; set; }
public int CurrentVersion { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime? LastAccessed { get; set; }
public string? Password { get; set; }
public string? NotificationEmails { get; set; }
public bool PostLearningAssessment { get; set; }
public bool IsAssessed { get; set; }
public int TutCompletionThreshold { get; set; }
public bool DiagAssess { get; set; }
public int DiagCompletionThreshold { get; set; }
public bool SelfRegister { get; set; }
public bool DiagObjSelect { get; set; }
public bool HideInLearnerPortal { get; set; }
public bool Active { get; set; }
public int DelegateCount { get; set; }
public int CompletedCount { get; set; }
public int CompleteWithinMonths { get; set; }
public int ValidityMonths { get; set; }
public bool Mandatory { get; set; }
public bool AutoRefresh { get; set; }
public int RefreshToCustomisationId { get; set; }
public string? RefreshToApplicationName { get; set; }
public string? RefreshToCustomisationName { get; set; }
public int AutoRefreshMonths { get; set; }
public bool ApplyLpDefaultsToSelfEnrol { get; set; }

public int InProgressCount => DelegateCount - CompletedCount;

public string CourseName => string.IsNullOrWhiteSpace(CustomisationName)
? ApplicationName
: ApplicationName + " - " + CustomisationName;

public string? RefreshToCourseName
{
get
{
if (RefreshToCustomisationId == 0 || RefreshToCustomisationId == CustomisationId)
{
return "Same course";
}

if (string.IsNullOrWhiteSpace(RefreshToApplicationName))
{
return null;
}

return string.IsNullOrWhiteSpace(RefreshToCustomisationName)
? RefreshToApplicationName
: RefreshToApplicationName + " - " + RefreshToCustomisationName;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public void Page_has_no_accessibility_errors(string url, string pageTitle)
[InlineData("/TrackingSystem/Centre/TopCourses", "Top courses")]
[InlineData("/TrackingSystem/CourseSetup", "Centre course setup")]
[InlineData("/TrackingSystem/CourseSetup/10716/AdminFields", "Manage course admin fields")]
[InlineData("/TrackingSystem/CourseSetup/10716/Manage", "Level 1 - Microsoft Excel 2010 - Inductions")]
[InlineData("/TrackingSystem/Delegates/All", "Delegates")]
[InlineData("/TrackingSystem/Delegates/View/1", "xxxxx xxxxxxxxx")]
[InlineData("/TrackingSystem/Delegates/Approve", "Approve delegate registrations")]
Expand Down
Loading