From cfb643293c554214d9ae8a45eae7d4393b496a94 Mon Sep 17 00:00:00 2001 From: Matthew Hilton Date: Tue, 20 Sep 2022 16:01:52 +1000 Subject: [PATCH] MDL-56567 competency: Course module competency option to override grade Previously, if a course module had already been graded, course module completion linked to the course module would not update. This commit adds the option to enable overriding the grade at the course module competency level. This ensures that if enabled and a user completes a module associated with a competency, that competency will be graded appropriately. --- ..._competency_overridegrade_form_element.php | 69 +++++ admin/tool/lp/lang/en/tool_lp.php | 1 + admin/tool/lp/lib.php | 11 +- backup/moodle2/backup_stepslib.php | 4 +- backup/moodle2/restore_stepslib.php | 1 + competency/classes/api.php | 39 ++- .../classes/course_module_competency.php | 4 + competency/tests/competency_override_test.php | 289 ++++++++++++++++++ lib/db/install.xml | 3 +- lib/db/upgrade.php | 12 + version.php | 2 +- 11 files changed, 418 insertions(+), 17 deletions(-) create mode 100644 admin/tool/lp/classes/course_competency_overridegrade_form_element.php create mode 100644 competency/tests/competency_override_test.php diff --git a/admin/tool/lp/classes/course_competency_overridegrade_form_element.php b/admin/tool/lp/classes/course_competency_overridegrade_form_element.php new file mode 100644 index 00000000000..462add46e83 --- /dev/null +++ b/admin/tool/lp/classes/course_competency_overridegrade_form_element.php @@ -0,0 +1,69 @@ +. + + +/** + * Course competency override grade element. + * + * @package tool_lp + * @copyright 2022 Matthew Hilton + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +require_once($CFG->libdir . '/form/advcheckbox.php'); + +/** + * Course competency override grade element. + * + * @package tool_lp + * @copyright 2022 Matthew Hilton + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_lp_course_competency_overridegrade_form_element extends MoodleQuickForm_advcheckbox { + + /** + * Constructor + * + * @param string $elementname Element name + * @param mixed $elementlabel Label(s) for an element + * @param array $options Options to control the element's display + */ + public function __construct($elementname=null, $elementlabel=null, $options=[]) { + if ($elementname == null) { + // This is broken quickforms messing with the constructors. + return; + } + + if (!empty($options['cmid'])) { + $cmid = $options['cmid']; + + $current = \core_competency\api::list_course_module_competencies_in_course_module($cmid); + + // Note: We just pick the override grade value set on the first course_module_competency. + // Because in the UI we force them to be the same for all. + if (!empty($current)) { + $one = array_pop($current); + $this->setValue($one->get('overridegrade')); + } + } + + parent::__construct($elementname, $elementlabel); + } +} diff --git a/admin/tool/lp/lang/en/tool_lp.php b/admin/tool/lp/lang/en/tool_lp.php index c4db7ba16aa..77edf1aaf8a 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -165,6 +165,7 @@ $string['nouserevidence'] = 'No evidence of prior learning has been added yet.'; $string['nouserplans'] = 'No learning plans have been created yet.'; $string['oneplanwascreated'] = 'A learning plan was created'; $string['outcome'] = 'Outcome'; +$string['overridegrade'] = 'Override existing competency grade when completed.'; $string['path'] = 'Path:'; $string['parentcompetency'] = 'Parent'; $string['parentcompetency_edit'] = 'Edit parent'; diff --git a/admin/tool/lp/lib.php b/admin/tool/lp/lib.php index d6c2560e98c..1160a63093b 100644 --- a/admin/tool/lp/lib.php +++ b/admin/tool/lp/lib.php @@ -161,6 +161,12 @@ function tool_lp_coursemodule_standard_elements($formwrapper, $mform) { 'tool_lp_course_competency_rule_form_element'); // Reuse the same options. $mform->addElement('course_competency_rule', 'competency_rule', get_string('uponcoursemodulecompletion', 'tool_lp'), $options); + + $overrideelementfile = "$CFG->dirroot/$CFG->admin/tool/lp/classes/course_competency_overridegrade_form_element.php"; + MoodleQuickForm::registerElementType('course_competency_overridegrade', $overrideelementfile, + 'tool_lp_course_competency_overridegrade_form_element'); + $mform->addElement('course_competency_overridegrade', 'override_grade', get_string('overridegrade', 'tool_lp'), $options); + $mform->hideIf('override_grade', 'competency_rule', 'noteq', \core_competency\competency::OUTCOME_COMPLETE + 1); } /** @@ -201,10 +207,13 @@ function tool_lp_coursemodule_edit_post_actions($data, $course) { } if (isset($data->competency_rule)) { + $overridegrade = isset($data->override_grade) ? $data->override_grade : false; + // Now update the rules for each course_module_competency. $current = \core_competency\api::list_course_module_competencies_in_course_module($data->coursemodule); foreach ($current as $coursemodulecompetency) { - \core_competency\api::set_course_module_competency_ruleoutcome($coursemodulecompetency, $data->competency_rule); + \core_competency\api::set_course_module_competency_ruleoutcome($coursemodulecompetency, $data->competency_rule, + $overridegrade); } } diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index 2d2552dbe4b..bd72e795dec 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -1843,10 +1843,10 @@ class backup_activity_competencies_structure_step extends backup_structure_step $wrapper->add_child($competencies); $competency = new backup_nested_element('competency', null, array('idnumber', 'ruleoutcome', - 'sortorder', 'frameworkidnumber')); + 'sortorder', 'frameworkidnumber', 'overridegrade')); $competencies->add_child($competency); - $sql = 'SELECT c.idnumber, cmc.ruleoutcome, cmc.sortorder, f.idnumber AS frameworkidnumber + $sql = 'SELECT c.idnumber, cmc.ruleoutcome, cmc.overridegrade, cmc.sortorder, f.idnumber AS frameworkidnumber FROM {' . \core_competency\course_module_competency::TABLE . '} cmc JOIN {' . \core_competency\competency::TABLE . '} c ON c.id = cmc.competencyid JOIN {' . \core_competency\competency_framework::TABLE . '} f ON f.id = c.competencyframeworkid diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index 4d4cd316de6..a035e21f090 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -3738,6 +3738,7 @@ class restore_activity_competencies_structure_step extends restore_structure_ste // Sortorder is ignored by precaution, anyway we should walk through the records in the right order. $record = (object) $params; $record->ruleoutcome = $data->ruleoutcome; + $record->overridegrade = $data->overridegrade; $coursemodulecompetency = new \core_competency\course_module_competency(0, $record); $coursemodulecompetency->create(); } diff --git a/competency/classes/api.php b/competency/classes/api.php index f5df09ea15f..e7e3e573fff 100644 --- a/competency/classes/api.php +++ b/competency/classes/api.php @@ -1582,9 +1582,11 @@ class api { * * @param int|course_module_competency $coursemodulecompetencyorid The course_module_competency, or its ID. * @param int $ruleoutcome The value of ruleoutcome. + * @param bool $overridegrade If true, will override existing grades in related competencies. * @return bool True on success. */ - public static function set_course_module_competency_ruleoutcome($coursemodulecompetencyorid, $ruleoutcome) { + public static function set_course_module_competency_ruleoutcome($coursemodulecompetencyorid, $ruleoutcome, + $overridegrade = false) { static::require_enabled(); $coursemodulecompetency = $coursemodulecompetencyorid; if (!is_object($coursemodulecompetency)) { @@ -1599,6 +1601,8 @@ class api { require_capability('moodle/competency:coursecompetencymanage', $context); $coursemodulecompetency->set('ruleoutcome', $ruleoutcome); + $coursemodulecompetency->set('overridegrade', $overridegrade); + return $coursemodulecompetency->update(); } @@ -4279,7 +4283,7 @@ class api { */ public static function add_evidence($userid, $competencyorid, $contextorid, $action, $descidentifier, $desccomponent, $desca = null, $recommend = false, $url = null, $grade = null, $actionuserid = null, - $note = null) { + $note = null, $overridegrade = false) { global $DB; static::require_enabled(); @@ -4350,8 +4354,8 @@ class api { $usercompetencycourse = user_competency_course::create_relation($userid, $competencyid, $courseid); $usercompetencycourse->create(); } - // Only update the grade and proficiency if there is not already a grade. - if ($usercompetencycourse->get('grade') === null) { + // Only update the grade and proficiency if there is not already a grade or the override option is enabled. + if ($usercompetencycourse->get('grade') === null || $overridegrade) { // Set grade. $usercompetencycourse->set('grade', $grade); // Set proficiency. @@ -4363,8 +4367,8 @@ class api { $setucgrade = $coursesettings->get('pushratingstouserplans'); if ($setucgrade) { - // Only push to user plans if there is not already a grade. - if ($usercompetency->get('grade') !== null) { + // Only push to user plans if there is not already a grade or the override option is enabled. + if ($usercompetency->get('grade') !== null && !$overridegrade) { $setucgrade = false; } else { $ucgrade = $grade; @@ -4374,8 +4378,9 @@ class api { } else { // When completing the competency we fetch the default grade from the competency. But we only mark - // the user competency when a grade has not been set yet. Complete is an action to use with automated systems. - if ($usercompetency->get('grade') === null) { + // the user competency when a grade has not been set yet or if override option is enabled. + // Complete is an action to use with automated systems. + if ($usercompetency->get('grade') === null || $overridegrade) { $setucgrade = true; $ucgrade = $grade; $ucproficiency = $proficiency; @@ -4498,7 +4503,7 @@ class api { // The competency was marked as completed, apply the rules. if ($wascompleted) { - self::apply_competency_rules_from_usercompetency($usercompetency, $competency); + self::apply_competency_rules_from_usercompetency($usercompetency, $competency, $overridegrade); } return $evidence; @@ -4557,7 +4562,7 @@ class api { * @return void */ protected static function apply_competency_rules_from_usercompetency(user_competency $usercompetency, - competency $competency = null) { + competency $competency = null, $overridegrade = false) { // Perform some basic checks. if (!$usercompetency->get('proficiency')) { @@ -4624,7 +4629,12 @@ class api { 'evidence_competencyrule', 'core_competency', null, - $recommend + $recommend, + null, + null, + null, + null, + $overridegrade ); } @@ -4659,6 +4669,7 @@ class api { $action = null; $recommend = false; $strdesc = 'evidence_coursemodulecompleted'; + $overridegrade = $coursemodulecompetency->get('overridegrade'); if ($outcome == course_module_competency::OUTCOME_NONE) { continue; @@ -4686,7 +4697,11 @@ class api { 'core_competency', $cmname, $recommend, - $url + $url, + null, + null, + null, + $overridegrade ); } } diff --git a/competency/classes/course_module_competency.php b/competency/classes/course_module_competency.php index 026ac4492b7..ebadd02b921 100644 --- a/competency/classes/course_module_competency.php +++ b/competency/classes/course_module_competency.php @@ -71,6 +71,10 @@ class course_module_competency extends persistent { 'default' => self::OUTCOME_EVIDENCE, 'type' => PARAM_INT, ), + 'overridegrade' => array( + 'default' => false, + 'type' => PARAM_BOOL + ), ); } diff --git a/competency/tests/competency_override_test.php b/competency/tests/competency_override_test.php new file mode 100644 index 00000000000..d0e4fb48b78 --- /dev/null +++ b/competency/tests/competency_override_test.php @@ -0,0 +1,289 @@ +. + +namespace core_competency; + +/** + * Competency ruleoutcome override grade tests + * + * @package core_competency + * @copyright 2022 Matthew Hilton + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class competency_override_test extends \advanced_testcase { + + public function setUp(): void { + $this->resetAfterTest(true); + $this->setAdminUser(); + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('core_competency'); + + // Create user in course. + $c1 = $dg->create_course((object) ['enablecompletion' => true]); + $u1 = $dg->create_user(); + $dg->enrol_user($u1->id, $c1->id); + + // Create framework with three values. + $scale = $dg->create_scale(["scale" => "not,partially,fully"]); + $scaleconfiguration = json_encode([ + ['scaleid' => $scale->id], + ['id' => 1, 'scaledefault' => 1, 'proficient' => 1] + ]); + $framework = $lpg->create_framework([ + 'scaleid' => $scale->id, + 'scaleconfiguration' => $scaleconfiguration + ]); + + $plan = $lpg->create_plan(['userid' => $u1->id]); + + $comp1 = $lpg->create_competency([ + 'competencyframeworkid' => $framework->get('id'), + 'scaleid' => $scale->id, + 'scaleconfiguration' => $scaleconfiguration + ]); + + $comp2 = $lpg->create_competency([ + 'competencyframeworkid' => $framework->get('id'), + 'scaleid' => $scale->id, + 'scaleconfiguration' => $scaleconfiguration + ]); + + api::add_competency_to_plan($plan->get('id'), $comp1->get('id')); + api::add_competency_to_plan($plan->get('id'), $comp2->get('id')); + + $lpg->create_course_competency([ + 'courseid' => $c1->id, + 'competencyid' => $comp1->get('id'), + 'ruleoutcome' => \core_competency\course_competency::OUTCOME_COMPLETE, + ]); + + $lpg->create_course_competency([ + 'courseid' => $c1->id, + 'competencyid' => $comp2->get('id'), + 'ruleoutcome' => \core_competency\course_competency::OUTCOME_COMPLETE, + ]); + + $label = $dg->create_module('label', ['course' => $c1, 'completion' => COMPLETION_VIEWED, 'completionview' => 1]); + $cm = get_coursemodule_from_instance('label', $label->id); + $completion = new \completion_info($c1); + $this->assertEquals(COMPLETION_ENABLED, $completion->is_enabled($cm)); + + // Link course module with the competency and setup a rule to complete the competency when the module is completed. + api::add_competency_to_course_module($cm, $comp1->get('id')); + api::add_competency_to_course_module($cm, $comp2->get('id')); + + $coursemodulecomps = api::list_course_module_competencies_in_course_module($cm); + $this->assertCount(2, $coursemodulecomps); + api::set_course_module_competency_ruleoutcome($coursemodulecomps[0], \core_competency\course_competency::OUTCOME_COMPLETE); + api::set_course_module_competency_ruleoutcome($coursemodulecomps[1], \core_competency\course_competency::OUTCOME_COMPLETE); + + $this->course = $c1; + $this->user = $u1; + $this->scale = $scale; + $this->framework = $framework; + $this->plan = $plan; + $this->comp1 = $comp1; + $this->comp2 = $comp2; + $this->cm = $cm; + $this->completion = new \completion_info($c1); + $this->context = \context_course::instance($this->course->id); + } + + /** + * Test ruleoutcome overridegrade is correctly applied when coursemodule completion is processed. + * + * @covers \core_competency\api::set_course_module_competency_ruleoutcome + */ + public function test_ruleoutcome_overridegrade(): void { + // Initially the competency (and hence all the child competencies) should not be complete for the user. + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(0, $plancomp->usercompetency->get('grade')); + $this->assertEquals(0, $usercomp->get('grade')); + $this->assertEquals(0, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(0, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(0, $usercomp2->get('grade')); + $this->assertEquals(0, $coursecomp2->get('grade')); + + // Update the course module completion state to complete and trigger a competency update. + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_COMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + // Comptency should now be complete for user, plan, and course now that the course module is completed. + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(1, $plancomp->usercompetency->get('grade')); + $this->assertEquals(1, $usercomp->get('grade')); + $this->assertEquals(1, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(1, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(1, $usercomp2->get('grade')); + $this->assertEquals(1, $coursecomp2->get('grade')); + + // Change the competency completion for the user by adding evidence. + api::add_evidence($this->user->id, $this->comp1, $this->context, + evidence::ACTION_OVERRIDE, 'commentincontext', 'core', null, false, null, 2); + api::add_evidence($this->user->id, $this->comp2, $this->context, + evidence::ACTION_OVERRIDE, 'commentincontext', 'core', null, false, null, 2); + + // After adding evidence, the competencies should now reflect the new grade value. + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(2, $plancomp->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp->get('grade')); + $this->assertEquals(2, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(2, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp2->get('grade')); + $this->assertEquals(2, $coursecomp2->get('grade')); + + // Update the course module competency to incomplete. This will not change the competency status. + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_INCOMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(2, $plancomp->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp->get('grade')); + $this->assertEquals(2, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(2, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp2->get('grade')); + $this->assertEquals(2, $coursecomp2->get('grade')); + + // Re-complete the course module, so that it attempts to re-complete the competencies. + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_COMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + // By default, this will not override the existing grade, so it should remain the same as before. + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(2, $plancomp->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp->get('grade')); + $this->assertEquals(2, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(2, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp2->get('grade')); + $this->assertEquals(2, $coursecomp2->get('grade')); + + // Update the completion rule for only competency 1 to $overridegrade = true. + $coursemodulecomps = api::list_course_module_competencies_in_course_module($this->cm); + api::set_course_module_competency_ruleoutcome($coursemodulecomps[0], \core_competency\course_competency::OUTCOME_COMPLETE, + true); + + // Mark as incomplete then re-complete the course module. + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_INCOMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_COMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + // Because the rule is now set to override existing grades, the grade should have now updated as per the ruleoutcome. + // However the second competency didn't have this rule set, so it will not be overriden. + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(1, $plancomp->usercompetency->get('grade')); + $this->assertEquals(1, $usercomp->get('grade')); + $this->assertEquals(1, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(2, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(2, $usercomp2->get('grade')); + $this->assertEquals(2, $coursecomp2->get('grade')); + + // If competency 2 is changed now to override and re-completed, it will update the same as competency 1. + api::set_course_module_competency_ruleoutcome($coursemodulecomps[1], \core_competency\course_competency::OUTCOME_COMPLETE, + true); + + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_INCOMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + $data = $this->completion->get_data($this->cm, false, $this->user->id); + $data->completionstate = COMPLETION_COMPLETE; + $data->timemodified = time(); + $this->completion->internal_set_data($this->cm, $data); + + // Now both the competencies have $overridegrade = true, + // they should both reflect the ruleoutcome after the completion above was processed. + [$coursecomp, $plancomp, $usercomp] = $this->get_related_competencies($this->comp1->get('id')); + $this->assertEquals(1, $plancomp->usercompetency->get('grade')); + $this->assertEquals(1, $usercomp->get('grade')); + $this->assertEquals(1, $coursecomp->get('grade')); + + [$coursecomp2, $plancomp2, $usercomp2] = $this->get_related_competencies($this->comp2->get('id')); + $this->assertEquals(1, $plancomp2->usercompetency->get('grade')); + $this->assertEquals(1, $usercomp2->get('grade')); + $this->assertEquals(1, $coursecomp2->get('grade')); + } + + /** + * Test competency backup and restore correctly restores the ruleoutcome overridegrade value. + * + * @covers \core_competency\api::set_course_module_competency_ruleoutcome + */ + public function test_override_backup_restore(): void { + global $CFG; + require_once($CFG->dirroot . '/course/externallib.php'); + + // Set one to override grade and another to not override grade. + $coursemodulecomps = api::list_course_module_competencies_in_course_module($this->cm); + api::set_course_module_competency_ruleoutcome($coursemodulecomps[0], \core_competency\course_competency::OUTCOME_COMPLETE, + false); + api::set_course_module_competency_ruleoutcome($coursemodulecomps[1], \core_competency\course_competency::OUTCOME_COMPLETE, + true); + + // Duplicate the course (backup and restore). + $duplicated = \core_course_external::duplicate_course($this->course->id, 'test', 'test', $this->course->category); + + // Get the new course modules. + $newcoursemodules = get_coursemodules_in_course('label', $duplicated['id']); + $this->assertCount(1, $newcoursemodules); + $cm = array_pop($newcoursemodules); + + // Get the comeptencies for this cm. + $newcoursemodulecomps = api::list_course_module_competencies_in_course_module($cm); + $this->assertCount(2, $newcoursemodulecomps); + + // Ensure the override grade settings are restored properly. + $this->assertEquals($coursemodulecomps[0]->get('overridegrade'), $newcoursemodulecomps[0]->get('overridegrade')); + $this->assertEquals($coursemodulecomps[1]->get('overridegrade'), $newcoursemodulecomps[1]->get('overridegrade')); + } + + /** + * Gets the course, user and plan competency for the given competency ID + * + * @param int $compid ID of the competency. + * @return array array containing the three related competencies + */ + private function get_related_competencies(int $compid): array { + $coursecomp = api::get_user_competency_in_course($this->course->id, $this->user->id, $compid); + $usercomp = api::get_user_competency($this->user->id, $compid); + $plancomp = api::get_plan_competency($this->plan, $compid); + return [$coursecomp, $plancomp, $usercomp]; + } +} diff --git a/lib/db/install.xml b/lib/db/install.xml index 12e63fa531c..3309fa0d851 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1,5 +1,5 @@ - @@ -3889,6 +3889,7 @@ + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 97776ccba2f..995f624251d 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -2925,5 +2925,17 @@ privatefiles,moodle|/user/files.php'; upgrade_main_savepoint(true, 2022092200.01); } + if ($oldversion < 2022101400.01) { + $table = new xmldb_table('competency_modulecomp'); + $field = new xmldb_field('overridegrade', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'ruleoutcome'); + + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2022101400.01); + } + return true; } diff --git a/version.php b/version.php index 74291bc3439..a891d20e0ab 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2022101400.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2022101400.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. $release = '4.1dev+ (Build: 20221014)'; // Human-friendly version name