MOBILE-4362 scorm: Fix grade calculation when using LASTATTEMPT

The app always used the last attempt, but LMS uses the last attempt that has at least 1 SCO with completed or passed status
main
Dani Palou 2023-10-05 17:00:04 +02:00
parent 8af557bbc6
commit 77bd638fb1
2 changed files with 34 additions and 24 deletions

View File

@ -301,12 +301,7 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
return; return;
} }
const grade = await AddonModScorm.getAttemptGrade(this.scorm, attempt, offline); attempts[attempt] = await AddonModScorm.getAttemptGrade(this.scorm, attempt, offline);
attempts[attempt] = {
num: attempt,
grade: grade,
};
} }
/** /**
@ -344,10 +339,10 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
// Now format the grades. // Now format the grades.
this.onlineAttempts.forEach((attempt) => { this.onlineAttempts.forEach((attempt) => {
attempt.gradeFormatted = AddonModScorm.formatGrade(scorm, attempt.grade); attempt.gradeFormatted = AddonModScorm.formatGrade(scorm, attempt.score);
}); });
this.offlineAttempts.forEach((attempt) => { this.offlineAttempts.forEach((attempt) => {
attempt.gradeFormatted = AddonModScorm.formatGrade(scorm, attempt.grade); attempt.gradeFormatted = AddonModScorm.formatGrade(scorm, attempt.score);
}); });
this.gradeFormatted = AddonModScorm.formatGrade(scorm, this.grade); this.gradeFormatted = AddonModScorm.formatGrade(scorm, this.grade);

View File

@ -119,17 +119,22 @@ export class AddonModScormProvider {
switch (scorm.whatgrade) { switch (scorm.whatgrade) {
case AddonModScormProvider.FIRSTATTEMPT: case AddonModScormProvider.FIRSTATTEMPT:
return onlineAttempts[1] ? onlineAttempts[1].grade : -1; return onlineAttempts[1] ? onlineAttempts[1].score : -1;
case AddonModScormProvider.LASTATTEMPT: { case AddonModScormProvider.LASTATTEMPT: {
// Search the last attempt number. // Search the last completed attempt number.
let max = 0; let lastCompleted = 0;
Object.keys(onlineAttempts).forEach((attemptNumber) => { for (const attemptNumber in onlineAttempts) {
max = Math.max(Number(attemptNumber), max); if (onlineAttempts[attemptNumber].hasCompletedPassedSCO) {
}); lastCompleted = Math.max(onlineAttempts[attemptNumber].num, lastCompleted);
}
}
if (max > 0) { if (lastCompleted > 0) {
return onlineAttempts[max].grade; return onlineAttempts[lastCompleted].score;
} else if (onlineAttempts[1]) {
// If no completed attempt found, use the first attempt for consistency with LMS.
return onlineAttempts[1].score;
} }
return -1; return -1;
@ -139,7 +144,7 @@ export class AddonModScormProvider {
// Search the highest grade. // Search the highest grade.
let grade = 0; let grade = 0;
for (const attemptNumber in onlineAttempts) { for (const attemptNumber in onlineAttempts) {
grade = Math.max(onlineAttempts[attemptNumber].grade, grade); grade = Math.max(onlineAttempts[attemptNumber].score, grade);
} }
return grade; return grade;
@ -151,7 +156,7 @@ export class AddonModScormProvider {
let total = 0; let total = 0;
for (const attemptNumber in onlineAttempts) { for (const attemptNumber in onlineAttempts) {
sumGrades += onlineAttempts[attemptNumber].grade; sumGrades += onlineAttempts[attemptNumber].score;
total++; total++;
} }
@ -589,8 +594,8 @@ export class AddonModScormProvider {
} }
/** /**
* Get the grade for a certain SCORM and attempt. * Get the grade data for a certain attempt.
* Based on Moodle's scorm_grade_user_attempt. * Mostly based on Moodle's scorm_grade_user_attempt.
* *
* @param scorm SCORM. * @param scorm SCORM.
* @param attempt Attempt number. * @param attempt Attempt number.
@ -598,7 +603,12 @@ export class AddonModScormProvider {
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @returns Promise resolved with the grade. If the attempt hasn't reported grade/completion, it will be -1. * @returns Promise resolved with the grade. If the attempt hasn't reported grade/completion, it will be -1.
*/ */
async getAttemptGrade(scorm: AddonModScormScorm, attempt: number, offline?: boolean, siteId?: string): Promise<number> { async getAttemptGrade(
scorm: AddonModScormScorm,
attempt: number,
offline?: boolean,
siteId?: string,
): Promise<AddonModScormAttemptGrade> {
const attemptScore = { const attemptScore = {
scos: 0, scos: 0,
values: 0, values: 0,
@ -654,7 +664,11 @@ export class AddonModScormProvider {
score = attemptScore.max; // Remote Learner GRADEHIGHEST is default. score = attemptScore.max; // Remote Learner GRADEHIGHEST is default.
} }
return score; return {
num: attempt,
score,
hasCompletedPassedSCO: attemptScore.scos > 0,
};
} }
/** /**
@ -2052,11 +2066,12 @@ export type AddonModScormOrganization = {
}; };
/** /**
* Grade for an attempt. * Grade data for an attempt.
*/ */
export type AddonModScormAttemptGrade = { export type AddonModScormAttemptGrade = {
num: number; num: number;
grade: number; score: number;
hasCompletedPassedSCO: boolean; // Whether it has at least 1 SCO with status completed or passed.
}; };
/** /**