Skip to content

Commit

Permalink
MDL-75719 completion: Fix completion state for hidden grade items.
Browse files Browse the repository at this point in the history
For hidden grade items we used to mark students as completed if
they have any grade. But this was not working correctly when we
also set pass grade for activity and completion criteria based
on pass grade. So we will have these completion states

Competion criteria 'Receive grade':
No grade - COMPLETION_INCOMPLETE
Grade visible, achieved passing grade - COMPLETION_COMPLETE_PASS
Grade visible, failed passing grade - COMPLETION_COMPLETE_FAIL
Grade hidden - COMPLETION_COMPLETE

Completion criteris 'Receive passing grade'
No grade - COMPLETION_INCOMPLETE
Grade visible, achieved passing grade - COMPLETION_COMPLETE_PASS
Grade visible, failed passing grade - COMPLETION_COMPLETE_FAIL
Grade hidden, achieved passing grade - COMPLETION_COMPLETE_PASS
Grade hidden, failed passing grade - COMPLETION_COMPLETE_FAIL_HIDDEN
  • Loading branch information
ilyatregubov committed Mar 2, 2023
1 parent 9ee4f8d commit fbb01b4
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
29 changes: 22 additions & 7 deletions lib/completionlib.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@
*/
define('COMPLETION_COMPLETE_FAIL', 3);

/**
* Indicates that the user has received a failing grade for a hidden grade item.
*/
define('COMPLETION_COMPLETE_FAIL_HIDDEN', 4);

/**
* The effect of this change to completion status is unknown.
* A completion effect changes (used only in update_state)
Expand Down Expand Up @@ -784,7 +789,8 @@ public function get_grade_completion(cm_info $cm, int $userid): int {
$this->internal_systemerror("Unexpected result: multiple grades for
item '{$item->id}', user '{$userid}'");
}
return self::internal_get_grade_state($item, reset($grades));
$returnpassfail = !empty($cm->completionpassgrade);
return self::internal_get_grade_state($item, reset($grades), $returnpassfail);
}

return COMPLETION_INCOMPLETE;
Expand Down Expand Up @@ -1171,12 +1177,16 @@ public function get_core_completion_state(cm_info $cm, int $userid): array {
$newstate = COMPLETION_COMPLETE_PASS;
}

// The activity is using 'passing grade' criteria therefore fail indication should be on this criteria.
// The user has received a (failing) grade so 'completiongrade' should properly indicate this.
if ($newstate == COMPLETION_COMPLETE_FAIL) {
// No need to show failing status for the completiongrade condition when passing grade condition is set.
if (in_array($newstate, [COMPLETION_COMPLETE_FAIL, COMPLETION_COMPLETE_FAIL_HIDDEN])) {
$data['completiongrade'] = COMPLETION_COMPLETE;
}

// If the grade received by the user is a failing grade for a hidden grade item,
// the 'Require passing grade' criterion is considered incomplete.
if ($newstate == COMPLETION_COMPLETE_FAIL_HIDDEN) {
$newstate = COMPLETION_INCOMPLETE;
}
}
$data['passgrade'] = $newstate;
}
}
Expand Down Expand Up @@ -1547,25 +1557,30 @@ public function inform_grade_changed($cm, $item, $grade, $deleted, $isbulkupdate
*
* @param grade_item $item an instance of grade_item
* @param grade_grade $grade an instance of grade_grade
* @param bool $returnpassfail If course module has pass grade completion criteria
* @return int Completion state e.g. COMPLETION_INCOMPLETE
*/
public static function internal_get_grade_state($item, $grade) {
public static function internal_get_grade_state($item, $grade, bool $returnpassfail = false) {
// If no grade is supplied or the grade doesn't have an actual value, then
// this is not complete.
if (!$grade || (is_null($grade->finalgrade) && is_null($grade->rawgrade))) {
return COMPLETION_INCOMPLETE;
}

// Conditions to show pass/fail:
// a) Completion criteria to achieve pass grade is enabled
// or
// a) Grade has pass mark (default is 0.00000 which is boolean true so be careful)
// b) Grade is visible (neither hidden nor hidden-until)
if ($item->gradepass && $item->gradepass > 0.000009 && !$item->hidden) {
if ($item->gradepass && $item->gradepass > 0.000009 && ($returnpassfail || !$item->hidden)) {
// Use final grade if set otherwise raw grade
$score = !is_null($grade->finalgrade) ? $grade->finalgrade : $grade->rawgrade;

// We are displaying and tracking pass/fail
if ($score >= $item->gradepass) {
return COMPLETION_COMPLETE_PASS;
} else if ($item->hidden) {
return COMPLETION_COMPLETE_FAIL_HIDDEN;
} else {
return COMPLETION_COMPLETE_FAIL;
}
Expand Down
3 changes: 3 additions & 0 deletions lib/upgrade.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ information provided here is intended especially for developers.

=== 4.2 ===

* A new constant COMPLETION_COMPLETE_FAIL_HIDDEN is introduced to mark that user has received a failing grade
for a hidden grade item. This state can be currently returned only by get_core_completion_state() and
internal_get_grade_state() so we don't store it in database (for now).
* \single_button constructor signature has been changed to manage more types than just primary buttons.
The boolean "primary" parameter has been deprecated and replaced by a more generic type allowing to use
Bootstrap styles of buttons (danger, warning...). The constructor will still manage the boolean primary
Expand Down

0 comments on commit fbb01b4

Please sign in to comment.