diff --git a/DigitalLearningSolutions.Data.Tests/DataServices/CompetencyLearningResourcesDataServiceTests.cs b/DigitalLearningSolutions.Data.Tests/DataServices/CompetencyLearningResourcesDataServiceTests.cs
index cab3b825a6..7604bfd4ff 100644
--- a/DigitalLearningSolutions.Data.Tests/DataServices/CompetencyLearningResourcesDataServiceTests.cs
+++ b/DigitalLearningSolutions.Data.Tests/DataServices/CompetencyLearningResourcesDataServiceTests.cs
@@ -78,7 +78,7 @@ public void GetCompetencyResourceAssessmentQuestionParameters_returns_expected_r
testHelper.InsertLearningResourceReference(2, 2, adminId, "Resource 2");
testHelper.InsertCompetencyLearningResource(1, 1, 2, adminId);
- testHelper.InsertCompetencyResourceAssessmentQuestionParameters(1, 1, true, 2, false);
+ testHelper.InsertCompetencyResourceAssessmentQuestionParameters(1, 1, true, 2, false, 1, 10);
var expectedItem = new CompetencyResourceAssessmentQuestionParameter
{
CompetencyLearningResourceId = 1,
@@ -86,6 +86,8 @@ public void GetCompetencyResourceAssessmentQuestionParameters_returns_expected_r
Essential = true,
RelevanceAssessmentQuestionId = 2,
CompareToRoleRequirements = false,
+ MinResultMatch = 1,
+ MaxResultMatch = 10,
};
// When
diff --git a/DigitalLearningSolutions.Data.Tests/DigitalLearningSolutions.Data.Tests.csproj b/DigitalLearningSolutions.Data.Tests/DigitalLearningSolutions.Data.Tests.csproj
index 426bc90d5a..1e96c40bbc 100644
--- a/DigitalLearningSolutions.Data.Tests/DigitalLearningSolutions.Data.Tests.csproj
+++ b/DigitalLearningSolutions.Data.Tests/DigitalLearningSolutions.Data.Tests.csproj
@@ -42,6 +42,7 @@
+
diff --git a/DigitalLearningSolutions.Data.Tests/Extensions/EnumerableExtensionsTests.cs b/DigitalLearningSolutions.Data.Tests/Extensions/EnumerableExtensionsTests.cs
new file mode 100644
index 0000000000..e5b7ad9c65
--- /dev/null
+++ b/DigitalLearningSolutions.Data.Tests/Extensions/EnumerableExtensionsTests.cs
@@ -0,0 +1,23 @@
+namespace DigitalLearningSolutions.Data.Tests.Extensions
+{
+ using System.Collections.Generic;
+ using DigitalLearningSolutions.Data.Extensions;
+ using FluentAssertions;
+ using NUnit.Framework;
+
+ public class EnumerableExtensionsTests
+ {
+ [Test]
+ public void WhereNotNull_filters_items_correctly()
+ {
+ // Given
+ var list = new List { "1", "2", null, "3", null, "4" };
+
+ // When
+ var result = list.WhereNotNull();
+
+ // Then
+ result.Should().BeEquivalentTo(new List { "1", "2", "3", "4" });
+ }
+ }
+}
diff --git a/DigitalLearningSolutions.Data.Tests/Services/RecommendedLearningServiceTests.cs b/DigitalLearningSolutions.Data.Tests/Services/RecommendedLearningServiceTests.cs
index fa4c83746f..6788d0f3dc 100644
--- a/DigitalLearningSolutions.Data.Tests/Services/RecommendedLearningServiceTests.cs
+++ b/DigitalLearningSolutions.Data.Tests/Services/RecommendedLearningServiceTests.cs
@@ -20,11 +20,13 @@ public class RecommendedLearningServiceTests
{
private const int SelfAssessmentId = 1;
private const int CompetencyId = 2;
+ private const int SecondCompetencyId = 3;
private const int LearningResourceReferenceId = 3;
private const int LearningHubResourceReferenceId = 4;
private const int DelegateId = 5;
private const int LearningLogId = 6;
private const int CompetencyLearningResourceId = 1;
+ private const int SecondCompetencyLearningResourceId = 2;
private const int CompetencyAssessmentQuestionId = 1;
private const int RelevanceAssessmentQuestionId = 2;
private const string ResourceName = "Resource";
@@ -61,10 +63,13 @@ public async Task
{
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenQuestionParametersAreReturned(true, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
+
A.CallTo(() => learningLogItemsDataService.GetLearningLogItems(DelegateId))
.Returns(new List());
- var expectedResource = GetExpectedResource(false, false, null);
+ var expectedResource = GetExpectedResource(false, false, null, 175);
// When
var result =
@@ -82,6 +87,8 @@ public async Task
{
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenQuestionParametersAreReturned(true, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var learningLogItems = Builder.CreateListOfSize(5).All()
.With(i => i.LearningHubResourceReferenceId = LearningHubResourceReferenceId + 1)
@@ -89,7 +96,7 @@ public async Task
A.CallTo(() => learningLogItemsDataService.GetLearningLogItems(DelegateId))
.Returns(learningLogItems);
- var expectedResource = GetExpectedResource(false, false, null);
+ var expectedResource = GetExpectedResource(false, false, null, 175);
// When
var result =
@@ -107,6 +114,8 @@ public async Task
{
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenQuestionParametersAreReturned(true, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var learningLogItem = Builder.CreateNew()
.With(i => i.LearningHubResourceReferenceId = LearningHubResourceReferenceId)
@@ -116,7 +125,7 @@ public async Task
A.CallTo(() => learningLogItemsDataService.GetLearningLogItems(DelegateId))
.Returns(new List { learningLogItem });
- var expectedResource = GetExpectedResource(false, true, null);
+ var expectedResource = GetExpectedResource(false, true, null, 175);
// When
var result =
@@ -134,6 +143,8 @@ public async Task
{
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenQuestionParametersAreReturned(true, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var learningLogItem = Builder.CreateNew()
.With(i => i.LearningHubResourceReferenceId = LearningHubResourceReferenceId)
@@ -143,7 +154,7 @@ public async Task
A.CallTo(() => learningLogItemsDataService.GetLearningLogItems(DelegateId))
.Returns(new List { learningLogItem });
- var expectedResource = GetExpectedResource(true, false, LearningLogId);
+ var expectedResource = GetExpectedResource(true, false, LearningLogId, 175);
// When
var result =
@@ -161,21 +172,23 @@ public async Task
{
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenQuestionParametersAreReturned(true, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
- var completeLearningLogItem = Builder.CreateNew()
+ var learningLogItems = Builder.CreateListOfSize(2)
+ .All()
.With(i => i.LearningHubResourceReferenceId = LearningHubResourceReferenceId)
- .And(i => i.CompletedDate = DateTime.UtcNow)
.And(i => i.LearningLogItemId = LearningLogId)
- .And(i => i.ArchivedDate = null).Build();
- var incompleteLearningLogItem = Builder.CreateNew()
- .With(i => i.LearningHubResourceReferenceId = LearningHubResourceReferenceId)
- .And(i => i.CompletedDate = null)
- .And(i => i.LearningLogItemId = LearningLogId)
- .And(i => i.ArchivedDate = null).Build();
+ .And(i => i.ArchivedDate = null)
+ .TheFirst(1)
+ .With(i => i.CompletedDate = DateTime.UtcNow)
+ .TheRest()
+ .With(i => i.CompletedDate = null)
+ .Build();
A.CallTo(() => learningLogItemsDataService.GetLearningLogItems(DelegateId))
- .Returns(new List { completeLearningLogItem, incompleteLearningLogItem });
+ .Returns(learningLogItems);
- var expectedResource = GetExpectedResource(true, true, LearningLogId);
+ var expectedResource = GetExpectedResource(true, true, LearningLogId, 175);
// When
var result =
@@ -201,26 +214,7 @@ public async Task GetRecommendedLearningForSelfAssessment_calls_learning_hub_api
() => competencyLearningResourcesDataService.GetCompetencyLearningResourcesByCompetencyId(A._)
).Returns(competencyLearningResources);
- var clientResponse = new BulkResourceReferences
- {
- ResourceReferences = new List
- {
- new ResourceReferenceWithResourceDetails
- {
- ResourceId = 0,
- RefId = LearningHubResourceReferenceId,
- Title = ResourceName,
- Description = ResourceDescription,
- Catalogue = new Catalogue { Name = ResourceCatalogue },
- ResourceType = ResourceType,
- Rating = 0,
- Link = ResourceLink,
- },
- },
- };
-
- A.CallTo(() => learningHubApiClient.GetBulkResourcesByReferenceIds(A>._))
- .Returns(clientResponse);
+ GivenLearningHubApiReturnsResources(0);
// When
await recommendedLearningService.GetRecommendedLearningForSelfAssessment(SelfAssessmentId, DelegateId);
@@ -235,12 +229,10 @@ public async Task GetRecommendedLearningForSelfAssessment_calls_learning_hub_api
}
[Test]
- [TestCase(1, true, 100)]
- [TestCase(1, false, 30)]
- [TestCase(0, true, 0)]
+ [TestCase(true, 175)]
+ [TestCase(false, 105)]
public async Task
- GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with_essential_question_parameters_only(
- int numberOfQuestionParameters,
+ GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with_essential_question_parameters(
bool essential,
decimal expectedScore
)
@@ -248,19 +240,8 @@ decimal expectedScore
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
GivenGetLearningLogItemsReturnsAnItem();
-
- var questionParameters =
- numberOfQuestionParameters == 0
- ? new List()
- : Builder
- .CreateListOfSize(numberOfQuestionParameters).All()
- .With(qp => qp.Essential = essential).Build();
-
- A.CallTo(
- () => competencyLearningResourcesDataService.GetCompetencyResourceAssessmentQuestionParameters(
- A>._
- )
- ).Returns(questionParameters);
+ GivenQuestionParametersAreReturned(essential, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var expectedResource = GetExpectedResource(true, false, LearningLogId, expectedScore);
@@ -276,17 +257,26 @@ decimal expectedScore
[Test]
public async Task
- GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with__multiple_essential_question_parameters_of_different_value()
+ GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with_multiple_competencies_with_essential_question_parameters_of_different_value()
{
// Given
- GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenResourceHasTwoCompetencies();
+ GivenLearningHubApiReturnsResources(0);
GivenGetLearningLogItemsReturnsAnItem();
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var questionParameters = Builder
- .CreateListOfSize(5).TheFirst(2)
- .With(qp => qp.Essential = true)
- .TheRest()
- .With(qp => qp.Essential = false).Build();
+ .CreateListOfSize(2)
+ .All()
+ .With(qp => qp.MinResultMatch = 1)
+ .And(qp => qp.MaxResultMatch = 10)
+ .TheFirst(1)
+ .With(qp => qp.Essential = true)
+ .And(qp => qp.CompetencyLearningResourceId = CompetencyLearningResourceId)
+ .TheRest()
+ .With(qp => qp.Essential = false)
+ .And(qp => qp.CompetencyLearningResourceId = 2)
+ .Build();
A.CallTo(
() => competencyLearningResourcesDataService.GetCompetencyResourceAssessmentQuestionParameters(
@@ -294,7 +284,7 @@ public async Task
)
).Returns(questionParameters);
- var expectedResource = GetExpectedResource(true, false, LearningLogId, 100);
+ var expectedResource = GetExpectedResource(true, false, LearningLogId, 175);
// When
var result =
@@ -312,7 +302,7 @@ public async Task
[TestCase(2.4, 9.6)]
[TestCase(5, 20)]
public async Task
- GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with_learning_hub_ratings_only(
+ GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with_learning_hub_ratings_and_no_question_parameters(
decimal learningHubRating,
decimal expectedScore
)
@@ -320,6 +310,7 @@ decimal expectedScore
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi(learningHubRating);
GivenGetLearningLogItemsReturnsAnItem();
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var expectedResource = GetExpectedResource(true, false, LearningLogId, expectedScore);
@@ -347,16 +338,8 @@ decimal expectedScore
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
GivenGetLearningLogItemsReturnsAnItem();
-
- var questionParameters = Builder
- .CreateListOfSize(1).All()
- .With(qp => qp.Essential = true)
- .And(qp => qp.CompareToRoleRequirements = true).Build();
- A.CallTo(
- () => competencyLearningResourcesDataService.GetCompetencyResourceAssessmentQuestionParameters(
- A>._
- )
- ).Returns(questionParameters);
+ GivenQuestionParametersAreReturned(true, true, 1, 10);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
var roleRequirement = Builder.CreateNew()
.With(rr => rr.LevelRag = levelRag).Build();
@@ -400,26 +383,7 @@ decimal expectedScore
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
GivenGetLearningLogItemsReturnsAnItem();
GivenNotComparingToRoleRequirements();
-
- var assessmentResults = Builder.CreateListOfSize(2)
- .All()
- .With(r => r.SelfAssessmentId = SelfAssessmentId)
- .And(r => r.CandidateId = DelegateId)
- .And(r => r.CompetencyId = CompetencyId)
- .TheFirst(1)
- .With(r => r.AssessmentQuestionId = CompetencyAssessmentQuestionId)
- .And(r => r.Result = confidenceResult)
- .TheRest()
- .With(r => r.AssessmentQuestionId = RelevanceAssessmentQuestionId)
- .And(r => r.Result = relevanceResult)
- .Build();
- A.CallTo(
- () => selfAssessmentDataService.GetSelfAssessmentResultsForDelegateSelfAssessmentCompetency(
- DelegateId,
- SelfAssessmentId,
- CompetencyId
- )
- ).Returns(assessmentResults);
+ GivenSelfAssessmentHasResultsForFirstCompetency(relevanceResult, confidenceResult);
var expectedResource = GetExpectedResource(true, false, LearningLogId, expectedScore);
@@ -441,7 +405,7 @@ decimal expectedScore
[Test]
public async Task
- GetRecommendedLearningForSelfAssessment_returns_correct_recommendation_score_for_resource_with_missing_self_assessment_results()
+ GetRecommendedLearningForSelfAssessment_does_not_return_resources_relating_to_unanswered_optional_competencies()
{
// Given
GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
@@ -456,16 +420,13 @@ public async Task
)
).Returns(new List());
- var expectedResource = GetExpectedResource(true, false, LearningLogId, 100);
-
// When
var result =
(await recommendedLearningService.GetRecommendedLearningForSelfAssessment(SelfAssessmentId, DelegateId))
.ToList();
// Then
- result.Should().HaveCount(1);
- result.Single().Should().BeEquivalentTo(expectedResource);
+ result.Should().BeEmpty();
A.CallTo(
() => selfAssessmentDataService.GetCompetencyAssessmentQuestionRoleRequirements(
A._,
@@ -474,7 +435,83 @@ public async Task
).MustNotHaveHappened();
}
+ [Test]
+ public async Task
+ GetRecommendedLearningForSelfAssessment_does_return_resources_with_some_unanswered_optional_competencies()
+ {
+ // Given
+ GivenResourceHasTwoCompetencies();
+ GivenLearningHubApiReturnsResources(0);
+ GivenGetLearningLogItemsReturnsAnItem();
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, 5);
+
+ var questionParameters = Builder
+ .CreateListOfSize(2)
+ .All()
+ .With(qp => qp.MinResultMatch = 1)
+ .And(qp => qp.MaxResultMatch = 10)
+ .TheFirst(1)
+ .With(qp => qp.Essential = true)
+ .And(qp => qp.CompetencyLearningResourceId = CompetencyLearningResourceId)
+ .TheRest()
+ .With(qp => qp.Essential = false)
+ .And(qp => qp.CompetencyLearningResourceId = SecondCompetencyLearningResourceId)
+ .Build();
+
+ A.CallTo(
+ () => competencyLearningResourcesDataService.GetCompetencyResourceAssessmentQuestionParameters(
+ A>._
+ )
+ ).Returns(questionParameters);
+
+ var expectedResource = GetExpectedResource(true, false, LearningLogId, 175);
+
+ // When
+ var result =
+ (await recommendedLearningService.GetRecommendedLearningForSelfAssessment(SelfAssessmentId, DelegateId))
+ .ToList();
+
+ // Then
+ result.Should().HaveCount(1);
+ result.Single().Should().BeEquivalentTo(expectedResource);
+ }
+
+ [Test]
+ [TestCase(1, 10, 5, 1)]
+ [TestCase(5, 10, 4, 0)]
+ [TestCase(1, 5, 6, 0)]
+ [TestCase(3, 7, 3, 1)]
+ [TestCase(3, 7, 7, 1)]
+ public async Task
+ GetRecommendedLearningForSelfAssessment_returns_expected_number_of_resources_for_answers_in_and_out_of_range(
+ int minScore,
+ int maxScore,
+ int confidenceResult,
+ int expectedResultCount
+ )
+ {
+ // Given
+ GivenResourceForSelfAssessmentIsReturnedByLearningHubApi();
+ GivenGetLearningLogItemsReturnsAnItem();
+ GivenQuestionParametersAreReturned(true, true, minScore, maxScore);
+ GivenSelfAssessmentHasResultsForFirstCompetency(5, confidenceResult);
+
+ // When
+ var result =
+ (await recommendedLearningService.GetRecommendedLearningForSelfAssessment(SelfAssessmentId, DelegateId))
+ .ToList();
+
+ // Then
+ result.Should().HaveCount(expectedResultCount);
+ }
+
private void GivenResourceForSelfAssessmentIsReturnedByLearningHubApi(decimal rating = 0)
+ {
+ GivenSingleCompetencyExistsForResource();
+ GivenLearningHubApiReturnsResources(rating);
+ }
+
+ private void GivenSingleCompetencyExistsForResource()
{
A.CallTo(() => selfAssessmentDataService.GetCompetencyIdsForSelfAssessment(SelfAssessmentId))
.Returns(new[] { CompetencyId });
@@ -491,7 +528,33 @@ private void GivenResourceForSelfAssessmentIsReturnedByLearningHubApi(decimal ra
A.CallTo(
() => competencyLearningResourcesDataService.GetCompetencyLearningResourcesByCompetencyId(CompetencyId)
).Returns(new List { competencyLearningResource });
+ }
+
+ private void GivenResourceHasTwoCompetencies()
+ {
+ A.CallTo(() => selfAssessmentDataService.GetCompetencyIdsForSelfAssessment(SelfAssessmentId))
+ .Returns(new[] { CompetencyId, SecondCompetencyId });
+
+ var competencyLearningResources = Builder.CreateListOfSize(2)
+ .All()
+ .With(clr => clr.LearningResourceReferenceId = LearningResourceReferenceId)
+ .And(clr => clr.LearningHubResourceReferenceId = LearningHubResourceReferenceId)
+ .And(clr => clr.AdminId = 7)
+ .TheFirst(1)
+ .With(clr => clr.Id = CompetencyLearningResourceId)
+ .And(clr => clr.CompetencyId = CompetencyId)
+ .TheRest()
+ .With(clr => clr.Id = SecondCompetencyLearningResourceId)
+ .And(clr => clr.CompetencyId = SecondCompetencyId)
+ .Build();
+ A.CallTo(
+ () => competencyLearningResourcesDataService.GetCompetencyLearningResourcesByCompetencyId(CompetencyId)
+ ).Returns(competencyLearningResources);
+ }
+
+ private void GivenLearningHubApiReturnsResources(decimal rating)
+ {
var clientResponse = new BulkResourceReferences
{
ResourceReferences = new List
@@ -531,8 +594,34 @@ private void GivenNotComparingToRoleRequirements()
.CreateListOfSize(1).All()
.With(qp => qp.Essential = true)
.And(qp => qp.CompareToRoleRequirements = false)
+ .And(qp => qp.CompetencyLearningResourceId = CompetencyLearningResourceId)
.And(qp => qp.AssessmentQuestionId = CompetencyAssessmentQuestionId)
- .And(qp => qp.RelevanceAssessmentQuestionId = RelevanceAssessmentQuestionId).Build();
+ .And(qp => qp.RelevanceAssessmentQuestionId = RelevanceAssessmentQuestionId)
+ .And(qp => qp.MinResultMatch = 1)
+ .And(qp => qp.MaxResultMatch = 10)
+ .Build();
+ A.CallTo(
+ () => competencyLearningResourcesDataService.GetCompetencyResourceAssessmentQuestionParameters(
+ A>._
+ )
+ ).Returns(questionParameters);
+ }
+
+ private void GivenQuestionParametersAreReturned(
+ bool essential,
+ bool compareToRoleRequirements,
+ int minMatch,
+ int maxMatch
+ )
+ {
+ var questionParameters = Builder
+ .CreateListOfSize(1).All()
+ .With(qp => qp.Essential = essential)
+ .And(qp => qp.CompareToRoleRequirements = compareToRoleRequirements)
+ .And(qp => qp.MinResultMatch = minMatch)
+ .And(qp => qp.MaxResultMatch = maxMatch)
+ .And(qp => qp.CompetencyLearningResourceId = CompetencyLearningResourceId)
+ .Build();
A.CallTo(
() => competencyLearningResourcesDataService.GetCompetencyResourceAssessmentQuestionParameters(
A>._
@@ -540,6 +629,29 @@ private void GivenNotComparingToRoleRequirements()
).Returns(questionParameters);
}
+ private void GivenSelfAssessmentHasResultsForFirstCompetency(int relevanceResult, int confidenceResult)
+ {
+ var assessmentResults = Builder.CreateListOfSize(2)
+ .All()
+ .With(r => r.SelfAssessmentId = SelfAssessmentId)
+ .And(r => r.CandidateId = DelegateId)
+ .And(r => r.CompetencyId = CompetencyId)
+ .TheFirst(1)
+ .With(r => r.AssessmentQuestionId = CompetencyAssessmentQuestionId)
+ .And(r => r.Result = confidenceResult)
+ .TheRest()
+ .With(r => r.AssessmentQuestionId = RelevanceAssessmentQuestionId)
+ .And(r => r.Result = relevanceResult)
+ .Build();
+ A.CallTo(
+ () => selfAssessmentDataService.GetSelfAssessmentResultsForDelegateSelfAssessmentCompetency(
+ DelegateId,
+ SelfAssessmentId,
+ CompetencyId
+ )
+ ).Returns(assessmentResults);
+ }
+
private RecommendedResource GetExpectedResource(
bool isInActionPlan,
bool isCompleted,
diff --git a/DigitalLearningSolutions.Data.Tests/TestHelpers/CompetencyLearningResourcesTestHelper.cs b/DigitalLearningSolutions.Data.Tests/TestHelpers/CompetencyLearningResourcesTestHelper.cs
index 94280a115a..b71410cb21 100644
--- a/DigitalLearningSolutions.Data.Tests/TestHelpers/CompetencyLearningResourcesTestHelper.cs
+++ b/DigitalLearningSolutions.Data.Tests/TestHelpers/CompetencyLearningResourcesTestHelper.cs
@@ -47,14 +47,20 @@ public void InsertCompetencyResourceAssessmentQuestionParameters(
int assessmentQuestionId,
bool essential,
int? relevanceQuestionId,
- bool compareToRoleRequirements
+ bool compareToRoleRequirements,
+ int minMatchResult,
+ int maxMatchResult
)
{
connection.Execute(
@"INSERT INTO CompetencyResourceAssessmentQuestionParameters
(CompetencyLearningResourceId, AssessmentQuestionID, Essential, RelevanceAssessmentQuestionID, CompareToRoleRequirements, MinResultMatch, MaxResultMatch)
- VALUES (@competencyLearningResourceId, @assessmentQuestionId, @essential, @relevanceQuestionId, @compareToRoleRequirements, 0, 0)",
- new { competencyLearningResourceId, assessmentQuestionId, essential, relevanceQuestionId, compareToRoleRequirements }
+ VALUES (@competencyLearningResourceId, @assessmentQuestionId, @essential, @relevanceQuestionId, @compareToRoleRequirements, @minMatchResult, @maxMatchResult)",
+ new
+ {
+ competencyLearningResourceId, assessmentQuestionId, essential, relevanceQuestionId,
+ compareToRoleRequirements, minMatchResult, maxMatchResult,
+ }
);
}
}
diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyLearningResourcesDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyLearningResourcesDataService.cs
index e594c73092..b280331c58 100644
--- a/DigitalLearningSolutions.Data/DataServices/CompetencyLearningResourcesDataService.cs
+++ b/DigitalLearningSolutions.Data/DataServices/CompetencyLearningResourcesDataService.cs
@@ -96,7 +96,9 @@ public IEnumerable
AssessmentQuestionID,
Essential,
RelevanceAssessmentQuestionID,
- CompareToRoleRequirements
+ CompareToRoleRequirements,
+ MinResultMatch,
+ MaxResultMatch
FROM CompetencyResourceAssessmentQuestionParameters
WHERE CompetencyLearningResourceId IN @competencyLearningResourceIds",
new { competencyLearningResourceIds }
diff --git a/DigitalLearningSolutions.Data/Extensions/EnumerableExtensions.cs b/DigitalLearningSolutions.Data/Extensions/EnumerableExtensions.cs
new file mode 100644
index 0000000000..00ab26d727
--- /dev/null
+++ b/DigitalLearningSolutions.Data/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,13 @@
+namespace DigitalLearningSolutions.Data.Extensions
+{
+ using System.Collections.Generic;
+ using System.Linq;
+
+ public static class EnumerableExtensions
+ {
+ public static IEnumerable WhereNotNull(this IEnumerable enumerable) where T : class
+ {
+ return enumerable.Where(e => e != null).Select(e => e!);
+ }
+ }
+}
diff --git a/DigitalLearningSolutions.Data/Models/SelfAssessments/CompetencyResourceAssessmentQuestionParameter.cs b/DigitalLearningSolutions.Data/Models/SelfAssessments/CompetencyResourceAssessmentQuestionParameter.cs
index 915c6fb33a..c0dc1ae4f7 100644
--- a/DigitalLearningSolutions.Data/Models/SelfAssessments/CompetencyResourceAssessmentQuestionParameter.cs
+++ b/DigitalLearningSolutions.Data/Models/SelfAssessments/CompetencyResourceAssessmentQuestionParameter.cs
@@ -11,5 +11,9 @@ public class CompetencyResourceAssessmentQuestionParameter
public int? RelevanceAssessmentQuestionId { get; set; }
public bool CompareToRoleRequirements { get; set; }
+
+ public int MinResultMatch { get; set; }
+
+ public int MaxResultMatch { get; set; }
}
}
diff --git a/DigitalLearningSolutions.Data/Services/RecommendedLearningService.cs b/DigitalLearningSolutions.Data/Services/RecommendedLearningService.cs
index 17aebe527f..2294aced17 100644
--- a/DigitalLearningSolutions.Data/Services/RecommendedLearningService.cs
+++ b/DigitalLearningSolutions.Data/Services/RecommendedLearningService.cs
@@ -6,6 +6,7 @@
using DigitalLearningSolutions.Data.ApiClients;
using DigitalLearningSolutions.Data.DataServices;
using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService;
+ using DigitalLearningSolutions.Data.Extensions;
using DigitalLearningSolutions.Data.Models.External.LearningHubApiClient;
using DigitalLearningSolutions.Data.Models.LearningResources;
using DigitalLearningSolutions.Data.Models.SelfAssessments;
@@ -67,40 +68,119 @@ int delegateId
var delegateLearningLogItems = learningLogItemsDataService.GetLearningLogItems(delegateId);
var recommendedResources = resources.ResourceReferences.Select(
- rr =>
- {
- var learningLogItemsForResource = delegateLearningLogItems.Where(
- ll => ll.ArchivedDate == null && ll.LearningHubResourceReferenceId == rr.RefId
- ).ToList();
- var incompleteLearningLogItem =
- learningLogItemsForResource.SingleOrDefault(ll => ll.CompletedDate == null);
- return new RecommendedResource(
- resourceReferences[rr.RefId],
- rr,
- incompleteLearningLogItem,
- learningLogItemsForResource.Any(ll => ll.CompletedDate != null),
- CalculateRecommendedLearningScore(rr, competencyLearningResources, selfAssessmentId, delegateId)
- );
- }
+ rr => GetPopulatedRecommendedResource(
+ selfAssessmentId,
+ delegateId,
+ resourceReferences[rr.RefId],
+ delegateLearningLogItems,
+ rr,
+ competencyLearningResources
+ )
);
- return recommendedResources;
+ return recommendedResources.WhereNotNull();
}
- private decimal CalculateRecommendedLearningScore(
- ResourceReferenceWithResourceDetails resource,
- List competencyLearningResources,
+ private RecommendedResource? GetPopulatedRecommendedResource(
int selfAssessmentId,
- int delegateId
+ int delegateId,
+ int learningHubResourceReferenceId,
+ IEnumerable delegateLearningLogItems,
+ ResourceReferenceWithResourceDetails rr,
+ List competencyLearningResources
)
{
+ var learningLogItemsForResource = delegateLearningLogItems.Where(
+ ll => ll.ArchivedDate == null && ll.LearningHubResourceReferenceId == rr.RefId
+ ).ToList();
+ var incompleteLearningLogItem =
+ learningLogItemsForResource.SingleOrDefault(ll => ll.CompletedDate == null);
+
var clrsForResource =
- competencyLearningResources.Where(clr => clr.LearningHubResourceReferenceId == resource.RefId).ToList();
+ competencyLearningResources.Where(clr => clr.LearningHubResourceReferenceId == rr.RefId)
+ .ToList();
var competencyResourceAssessmentQuestionParameters =
competencyLearningResourcesDataService
- .GetCompetencyResourceAssessmentQuestionParameters(clrsForResource.Select(clr => clr.Id)).ToList();
+ .GetCompetencyResourceAssessmentQuestionParameters(clrsForResource.Select(clr => clr.Id))
+ .ToList();
+ if (!AreDelegateAnswersWithinRangeToDisplayResource(
+ clrsForResource,
+ competencyResourceAssessmentQuestionParameters,
+ selfAssessmentId,
+ delegateId
+ ))
+ {
+ return null;
+ }
+
+ return new RecommendedResource(
+ learningHubResourceReferenceId,
+ rr,
+ incompleteLearningLogItem,
+ learningLogItemsForResource.Any(ll => ll.CompletedDate != null),
+ CalculateRecommendedLearningScore(
+ rr,
+ clrsForResource,
+ competencyResourceAssessmentQuestionParameters,
+ selfAssessmentId,
+ delegateId
+ )
+ );
+ }
+
+ private bool AreDelegateAnswersWithinRangeToDisplayResource(
+ List clrsForResource,
+ List competencyResourceAssessmentQuestionParameters,
+ int selfAssessmentId,
+ int delegateId
+ )
+ {
+ foreach (var competencyLearningResource in clrsForResource)
+ {
+ var delegateResults = selfAssessmentDataService
+ .GetSelfAssessmentResultsForDelegateSelfAssessmentCompetency(
+ delegateId,
+ selfAssessmentId,
+ competencyLearningResource.CompetencyId
+ ).ToList();
+
+ var competencyResourceAssessmentQuestionParametersForClr =
+ competencyResourceAssessmentQuestionParameters.SingleOrDefault(
+ qp => qp.CompetencyLearningResourceId == competencyLearningResource.Id
+ );
+
+ if (competencyResourceAssessmentQuestionParametersForClr == null)
+ {
+ return true;
+ }
+
+ var latestConfidenceResult = delegateResults
+ .Where(
+ dr => dr.AssessmentQuestionId ==
+ competencyResourceAssessmentQuestionParametersForClr.AssessmentQuestionId
+ )
+ .OrderByDescending(dr => dr.DateTime).FirstOrDefault();
+
+ if (competencyResourceAssessmentQuestionParametersForClr.MinResultMatch <= latestConfidenceResult?.Result &&
+ latestConfidenceResult.Result <= competencyResourceAssessmentQuestionParametersForClr.MaxResultMatch)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private decimal CalculateRecommendedLearningScore(
+ ResourceReferenceWithResourceDetails resource,
+ List clrsForResource,
+ List competencyResourceAssessmentQuestionParameters,
+ int selfAssessmentId,
+ int delegateId
+ )
+ {
var essentialnessValue = CalculateEssentialnessValue(competencyResourceAssessmentQuestionParameters);
var learningHubRating = resource.Rating;
@@ -134,17 +214,17 @@ int delegateId
foreach (var competencyLearningResource in competencyLearningResources)
{
- var competencyResourceAssessmentQuestionParameterForClr =
+ var competencyResourceAssessmentQuestionParametersForClr =
competencyResourceAssessmentQuestionParameters.SingleOrDefault(
c => c.CompetencyLearningResourceId == competencyLearningResource.Id
);
- if (competencyResourceAssessmentQuestionParameterForClr == null)
+ if (competencyResourceAssessmentQuestionParametersForClr == null)
{
break;
}
- if (competencyResourceAssessmentQuestionParameterForClr.CompareToRoleRequirements)
+ if (competencyResourceAssessmentQuestionParametersForClr.CompareToRoleRequirements)
{
requirementAdjusters.Add(
CalculateRoleRequirementValue(competencyLearningResource.CompetencyId, selfAssessmentId)
@@ -158,7 +238,7 @@ int delegateId
.CompetencyId,
selfAssessmentId,
delegateId,
- competencyResourceAssessmentQuestionParameterForClr
+ competencyResourceAssessmentQuestionParametersForClr
)
);
}