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.
This commit is contained in:
Matthew Hilton
2022-10-17 08:00:20 +10:00
parent 3bc792b9b8
commit cfb643293c
11 changed files with 418 additions and 17 deletions
@@ -0,0 +1,69 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Course competency override grade element.
*
* @package tool_lp
* @copyright 2022 Matthew Hilton <[email protected]>
* @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 <[email protected]>
* @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);
}
}
+1
View File
@@ -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';
+10 -1
View File
@@ -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);
}
}
+2 -2
View File
@@ -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
+1
View File
@@ -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();
}
+27 -12
View File
@@ -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
);
}
}
@@ -71,6 +71,10 @@ class course_module_competency extends persistent {
'default' => self::OUTCOME_EVIDENCE,
'type' => PARAM_INT,
),
'overridegrade' => array(
'default' => false,
'type' => PARAM_BOOL
),
);
}
@@ -0,0 +1,289 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_competency;
/**
* Competency ruleoutcome override grade tests
*
* @package core_competency
* @copyright 2022 Matthew Hilton <[email protected]>
* @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];
}
}
+2 -1
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20220825" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20221009" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
@@ -3889,6 +3889,7 @@
<FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The field used to naturally sort this link."/>
<FIELD NAME="competencyid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The course competency this activity is linked to."/>
<FIELD NAME="ruleoutcome" TYPE="int" LENGTH="2" NOTNULL="true" SEQUENCE="false" COMMENT="The outcome when an activity is completed."/>
<FIELD NAME="overridegrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Enables the ability to override an existing competencys grade."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
+12
View File
@@ -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;
}
+1 -1
View File
@@ -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