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