MDL-71659 completion: Consider modules without grade_item incomplete

Activity modules may not have the associated grade_item created yet. It
used to throw fatal error in that case - even when trying to view the
course or edit the activity. So there was no easy way to recover from
this situation.

The patch is based on reasoning that an activity without grade item is
same as activity without any grades. And as such it is considered
incomplete.

A new unit test is added to cover this specific scenario. The existing
unit test is modified and it does not expect the exception any more.
There does not seem to be any good reason why this situation should be
exceptional.
This commit is contained in:
David Mudrák
2021-05-18 20:56:31 +02:00
parent 62142a081a
commit 3d2b204283
2 changed files with 39 additions and 4 deletions
-3
View File
@@ -769,9 +769,6 @@ class completion_info {
item '{$item->id}', user '{$userid}'");
}
return self::internal_get_grade_state($item, reset($grades));
} else {
$this->internal_systemerror("Cannot find grade item for '{$cm->modname}'
cm '{$cm->id}' matching number '{$cm->completiongradeitemnumber}'");
}
return COMPLETION_INCOMPLETE;
+39 -1
View File
@@ -1266,7 +1266,7 @@ class core_completionlib_testcase extends advanced_testcase {
*/
public function get_grade_completion_provider() {
return [
'Grade not required' => [false, false, null, moodle_exception::class, null],
'Grade not required' => [false, false, null, null, null],
'Grade required, but has no grade yet' => [true, false, null, null, COMPLETION_INCOMPLETE],
'Grade required, grade received' => [true, true, null, null, COMPLETION_COMPLETE],
'Grade required, passing grade received' => [true, true, 70, null, COMPLETION_COMPLETE_PASS],
@@ -1312,6 +1312,44 @@ class core_completionlib_testcase extends advanced_testcase {
$gradecompletion = $completioninfo->get_grade_completion($cm, $this->user->id);
$this->assertEquals($expectedresult, $gradecompletion);
}
/**
* Test the return value for cases when the activity module does not have associated grade_item.
*/
public function test_get_grade_completion_without_grade_item() {
global $DB;
$this->setup_data();
$assign = $this->getDataGenerator()->get_plugin_generator('mod_assign')->create_instance([
'course' => $this->course->id,
'completion' => COMPLETION_ENABLED,
'completionusegrade' => true,
'gradepass' => 42,
]);
$cm = cm_info::create(get_coursemodule_from_instance('assign', $assign->id));
$DB->delete_records('grade_items', [
'courseid' => $this->course->id,
'itemtype' => 'mod',
'itemmodule' => 'assign',
'iteminstance' => $assign->id,
]);
// Without the grade_item, the activity is considered incomplete.
$completioninfo = new completion_info($this->course);
$this->assertEquals(COMPLETION_INCOMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id));
// Once the activity is graded, the grade_item is automatically created.
$assigninstance = new assign($cm->context, $cm, $this->course);
$grade = $assigninstance->get_user_grade($this->user->id, true);
$grade->grade = 40;
$assigninstance->update_grade($grade);
// The implicitly created grade_item does not have grade to pass defined so it is not distinguished.
$this->assertEquals(COMPLETION_COMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id));
}
}
class core_completionlib_fake_recordset implements Iterator {