mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 13:02:07 +02:00
MDL-52206 core: Add completion based on pass grade
Add new completion based on pass grade to the completion criteria.
This commit is contained in:
parent
1a9bee69e6
commit
663137748e
@ -2806,12 +2806,13 @@ class backup_completion_defaults_structure_step extends backup_structure_step {
|
||||
$cc = new backup_nested_element('course_completion_defaults');
|
||||
|
||||
$defaults = new backup_nested_element('course_completion_default', array('id'), array(
|
||||
'modulename', 'completion', 'completionview', 'completionusegrade', 'completionexpected', 'customrules'
|
||||
'modulename', 'completion', 'completionview', 'completionusegrade', 'completionpassgrade',
|
||||
'completionexpected', 'customrules'
|
||||
));
|
||||
|
||||
// Use module name instead of module id so we can insert into another site later.
|
||||
$sourcesql = "SELECT d.id, m.name as modulename, d.completion, d.completionview, d.completionusegrade,
|
||||
d.completionexpected, d.customrules
|
||||
d.completionpassgrade, d.completionexpected, d.customrules
|
||||
FROM {course_completion_defaults} d join {modules} m on d.module = m.id
|
||||
WHERE d.course = ?";
|
||||
$defaults->set_source_sql($sourcesql, array(backup::VAR_COURSEID));
|
||||
|
@ -137,7 +137,8 @@ class core_completion_bulkedit_form extends core_completion_edit_base_form {
|
||||
// Completion: Don't let them choose automatic completion without turning
|
||||
// on some conditions.
|
||||
if (array_key_exists('completion', $data) &&
|
||||
$data['completion'] == COMPLETION_TRACKING_AUTOMATIC && !empty($data['completionusegrade'])) {
|
||||
$data['completion'] == COMPLETION_TRACKING_AUTOMATIC &&
|
||||
(!empty($data['completionusegrade']) || !empty($data['completionpassgrade']))) {
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
$moduleswithoutgradeitem = [];
|
||||
foreach ($this->cms as $cm) {
|
||||
|
@ -199,10 +199,19 @@ abstract class core_completion_edit_base_form extends moodleform {
|
||||
|
||||
// Automatic completion once it's graded.
|
||||
if ($this->support_grades()) {
|
||||
$mform->addElement('advcheckbox', 'completionusegrade', get_string('completionusegrade', 'completion'),
|
||||
$group = [];
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionusegrade', get_string('completionusegrade', 'completion'),
|
||||
get_string('completionusegrade_desc', 'completion'));
|
||||
$mform->disabledIf('completionusegrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->addHelpButton('completionusegrade', 'completionusegrade', 'completion');
|
||||
$mform->addHelpButton('completionusegrade', 'completionusegrade', 'completion', '', true);
|
||||
|
||||
$group[] = $mform->createElement('advcheckbox', 'completionpassgrade', get_string('completionpassgrade', 'completion'),
|
||||
get_string('completionpassgrade_desc', 'completion'));
|
||||
$mform->addHelpButton('completionpassgrade', 'completionpassgrade', 'completion', '', true);
|
||||
$mform->disabledIf('completionpassgrade', 'completionusegrade', 'notchecked');
|
||||
|
||||
$mform->addGroup($group, 'completionpassgroup', get_string('completionpassgrade', 'completion'), ' ', false);
|
||||
$mform->disabledIf('completionpassgroup', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
|
||||
$autocompletionpossible = true;
|
||||
}
|
||||
|
||||
@ -247,7 +256,7 @@ abstract class core_completion_edit_base_form extends moodleform {
|
||||
// on some conditions.
|
||||
if (array_key_exists('completion', $data) &&
|
||||
$data['completion'] == COMPLETION_TRACKING_AUTOMATIC) {
|
||||
if (empty($data['completionview']) && empty($data['completionusegrade']) &&
|
||||
if (empty($data['completionview']) && empty($data['completionusegrade']) && empty($data['completionpassgrade']) &&
|
||||
!$this->completion_rule_enabled($data)) {
|
||||
$errors['completion'] = get_string('badautocompletion', 'completion');
|
||||
}
|
||||
|
@ -176,7 +176,13 @@ class manager {
|
||||
}
|
||||
if ($moduledata instanceof cm_info && !is_null($moduledata->completiongradeitemnumber) ||
|
||||
($moduledata instanceof stdClass && !empty($moduledata->completionusegrade))) {
|
||||
$activeruledescriptions[] = get_string('completionusegrade_desc', 'completion');
|
||||
|
||||
$description = 'completionusegrade_desc';
|
||||
if (!empty($moduledata->completionpassgrade)) {
|
||||
$description = 'completionpassgrade_desc';
|
||||
}
|
||||
|
||||
$activeruledescriptions[] = get_string($description, 'completion');
|
||||
}
|
||||
|
||||
// Now, ask the module to provide descriptions for its custom conditional completion rules.
|
||||
@ -351,8 +357,11 @@ class manager {
|
||||
protected function apply_completion_cm(\cm_info $cm, $data, $updateinstance) {
|
||||
global $DB;
|
||||
|
||||
$defaults = ['completion' => COMPLETION_DISABLED, 'completionview' => COMPLETION_VIEW_NOT_REQUIRED,
|
||||
'completionexpected' => 0, 'completiongradeitemnumber' => null];
|
||||
$defaults = [
|
||||
'completion' => COMPLETION_DISABLED, 'completionview' => COMPLETION_VIEW_NOT_REQUIRED,
|
||||
'completionexpected' => 0, 'completiongradeitemnumber' => null,
|
||||
'completionpassgrade' => 0
|
||||
];
|
||||
|
||||
$data += ['completion' => $cm->completion,
|
||||
'completionexpected' => $cm->completionexpected,
|
||||
|
@ -240,6 +240,10 @@ class completion_criteria_activity extends completion_criteria {
|
||||
if (!is_null($cm->completiongradeitemnumber)) {
|
||||
$details['requirement'][] = get_string('achievinggrade', 'completion');
|
||||
}
|
||||
|
||||
if ($cm->completionpassgrade) {
|
||||
$details['requirement'][] = get_string('achievingpassinggrade', 'completion');
|
||||
}
|
||||
}
|
||||
|
||||
$details['requirement'] = implode(', ', $details['requirement']);
|
||||
|
@ -370,6 +370,9 @@ abstract class moodleform_mod extends moodleform {
|
||||
if ($mform->elementExists('completionusegrade')) {
|
||||
$mform->freeze('completionusegrade');
|
||||
}
|
||||
if ($mform->elementExists('completionpassgrade')) {
|
||||
$mform->freeze('completionpassgrade');
|
||||
}
|
||||
if ($mform->elementExists('completiongradeitemnumber')) {
|
||||
$mform->freeze('completiongradeitemnumber');
|
||||
}
|
||||
@ -468,6 +471,28 @@ abstract class moodleform_mod extends moodleform {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($data['completionpassgrade']) && $data['completionpassgrade']) {
|
||||
// We need to check whether there's a valid gradepass value.
|
||||
// This can either be in completiongradeitemnumber when there are multiple options OR,
|
||||
// The first grade item if completionusegrade is specified.
|
||||
$validategradepass = false;
|
||||
if (isset($data['completiongradeitemnumber'])) {
|
||||
if ($data['completiongradeitemnumber'] == (string)$itemnumber) {
|
||||
$validategradepass = true;
|
||||
}
|
||||
} else if (isset($data['completionusegrade']) && $data['completionusegrade']) {
|
||||
$validategradepass = true;
|
||||
}
|
||||
|
||||
// Confirm gradepass is a valid non-zero value.
|
||||
if ($validategradepass && (!isset($data[$gradepassfieldname]) || grade_floatval($data[$gradepassfieldname]) == 0)) {
|
||||
$errors['completionpassgrade'] = get_string(
|
||||
'activitygradetopassnotset',
|
||||
'completion'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Completion: Don't let them choose automatic completion without turning
|
||||
@ -482,7 +507,7 @@ abstract class moodleform_mod extends moodleform {
|
||||
$rulesenabled = !empty($data['completionview']);
|
||||
|
||||
// Use grade to complete (only one grade item).
|
||||
$rulesenabled = $rulesenabled || !empty($data['completionusegrade']);
|
||||
$rulesenabled = $rulesenabled || !empty($data['completionusegrade']) || !empty($data['completionpassgrade']);
|
||||
|
||||
// Use grade to complete (specific grade item).
|
||||
if (!$rulesenabled && isset($data['completiongradeitemnumber'])) {
|
||||
@ -724,16 +749,28 @@ abstract class moodleform_mod extends moodleform {
|
||||
$mform->hideIf('completionusegrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->addHelpButton('completionusegrade', 'completionusegrade', 'completion');
|
||||
|
||||
// Complete if the user has reached the pass grade.
|
||||
$mform->addElement(
|
||||
'checkbox',
|
||||
'completionpassgrade', null,
|
||||
get_string('completionpassgrade_desc', 'completion')
|
||||
);
|
||||
$mform->hideIf('completionpassgrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->disabledIf('completionpassgrade', 'completionusegrade', 'notchecked');
|
||||
$mform->addHelpButton('completionpassgrade', 'completionpassgrade', 'completion');
|
||||
|
||||
// The disabledIf logic differs between ratings and other grade items due to different field types.
|
||||
if ($this->_features->rating) {
|
||||
// If using the rating system, there is no grade unless ratings are enabled.
|
||||
$mform->disabledIf('completionusegrade', 'assessed', 'eq', 0);
|
||||
$mform->disabledIf('completionpassgrade', 'assessed', 'eq', 0);
|
||||
} else {
|
||||
// All other field types use the '$gradefieldname' field's modgrade_type.
|
||||
$itemnumbers = array_keys($itemnames);
|
||||
$itemnumber = array_shift($itemnumbers);
|
||||
$gradefieldname = component_gradeitems::get_field_name_for_itemnumber($component, $itemnumber, 'grade');
|
||||
$mform->disabledIf('completionusegrade', "{$gradefieldname}[modgrade_type]", 'eq', 'none');
|
||||
$mform->disabledIf('completionpassgrade', "{$gradefieldname}[modgrade_type]", 'eq', 'none');
|
||||
}
|
||||
} else if (count($itemnames) > 1) {
|
||||
// There are multiple grade items in this activity.
|
||||
@ -752,6 +789,16 @@ abstract class moodleform_mod extends moodleform {
|
||||
$options
|
||||
);
|
||||
$mform->hideIf('completiongradeitemnumber', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
|
||||
// Complete if the user has reached the pass grade.
|
||||
$mform->addElement(
|
||||
'checkbox',
|
||||
'completionpassgrade', null,
|
||||
get_string('completionpassgrade_desc', 'completion')
|
||||
);
|
||||
$mform->hideIf('completionpassgrade', 'completion', 'ne', COMPLETION_TRACKING_AUTOMATIC);
|
||||
$mform->disabledIf('completionpassgrade', 'completiongradeitemnumber', 'eq', '');
|
||||
$mform->addHelpButton('completionpassgrade', 'completionpassgrade', 'completion');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
$string['achievinggrade'] = 'Achieving grade';
|
||||
$string['achievingpassinggrade'] = 'Achieving passing grade';
|
||||
$string['activities'] = 'Activities';
|
||||
$string['activitieslabel'] = 'Activities / resources';
|
||||
$string['activityaggregation'] = 'Condition requires';
|
||||
@ -35,6 +36,7 @@ $string['activitiescompletednote'] = 'Note: Activity completion must be set for
|
||||
$string['activitycompletion'] = 'Activity completion';
|
||||
$string['activitycompletionupdated'] = 'Changes saved';
|
||||
$string['activitygradenotrequired'] = 'Grade not required';
|
||||
$string['activitygradetopassnotset'] = 'This activity does not have a valid grade to pass set. It may be set in the Grade section of the activity settings.';
|
||||
$string['affectedactivities'] = 'The changes will affect the following <b>{$a}</b> activities or resources:';
|
||||
$string['aggregationmethod'] = 'Aggregation method';
|
||||
$string['all'] = 'All';
|
||||
@ -106,6 +108,9 @@ $string['completionondate'] = 'Date';
|
||||
$string['completionondatevalue'] = 'Date when course will be marked as complete';
|
||||
$string['completionduration'] = 'Enrolment';
|
||||
$string['completionsettingslocked'] = 'Completion settings locked';
|
||||
$string['completionpassgrade'] = 'Require passing grade';
|
||||
$string['completionpassgrade_desc'] = 'Student must receive a passing grade to complete this activity';
|
||||
$string['completionpassgrade_help'] = 'If enabled, the activity is considered complete when a student receives a passing grade.';
|
||||
$string['completionusegrade'] = 'Require grade';
|
||||
$string['completionusegrade_desc'] = 'Student must receive a grade to complete this activity';
|
||||
$string['completionusegrade_help'] = 'If enabled, the activity is considered complete when a student receives a grade. If a pass grade for the activity is set, then pass and fail icons are displayed in the activity completion report.';
|
||||
@ -141,6 +146,7 @@ $string['deletecompletiondata'] = 'Delete completion data';
|
||||
$string['dependencies'] = 'Dependencies';
|
||||
$string['dependenciescompleted'] = 'Completion of other courses';
|
||||
$string['detail_desc:receivegrade'] = 'Receive a grade';
|
||||
$string['detail_desc:receivepassgrade'] = 'Receive a passing grade';
|
||||
$string['detail_desc:view'] = 'View';
|
||||
$string['hiddenrules'] = 'Some settings specific to <b>{$a}</b> have been hidden. To view unselect other activities';
|
||||
$string['editcoursecompletionsettings'] = 'Edit course completion settings';
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20210728" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20211001" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -304,6 +304,7 @@
|
||||
<FIELD NAME="completiongradeitemnumber" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Grade-item number used to track automatic completion, if applicable."/>
|
||||
<FIELD NAME="completionview" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Controls whether a page view is part of the automatic completion requirements for this activity. 0 = view not required 1 = view required"/>
|
||||
<FIELD NAME="completionexpected" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Date at which students are expected to complete this activity. This field is used when displaying student progress."/>
|
||||
<FIELD NAME="completionpassgrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Enable completion check on passing grade."/>
|
||||
<FIELD NAME="showdescription" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Some module types support a 'description' which shows within the module pages. This option controls whether it also displays on the course main page. 0 = does not display (default), 1 = displays"/>
|
||||
<FIELD NAME="availability" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Availability restrictions for viewing this activity, in JSON format. Null if no restrictions."/>
|
||||
<FIELD NAME="deletioninprogress" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
@ -3866,6 +3867,7 @@
|
||||
<FIELD NAME="completion" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionview" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionusegrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionpassgrade" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="completionexpected" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="customrules" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
|
@ -2862,5 +2862,21 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2021092400.03);
|
||||
}
|
||||
|
||||
if ($oldversion < 2021100300.01) {
|
||||
$table = new xmldb_table('course_completion_defaults');
|
||||
|
||||
// Adding fields to table course_completion_defaults.
|
||||
$field = new xmldb_field('completionpassgrade', XMLDB_TYPE_INTEGER, '1', null,
|
||||
XMLDB_NOTNULL, null, '0', 'completionusegrade');
|
||||
|
||||
// Conditionally launch add field for course_completion_defaults.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2021100300.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ require_once($CFG->dirroot . '/course/moodleform_mod.php');
|
||||
require_once(__DIR__ . '/locallib.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
use core_grades\component_gradeitems;
|
||||
/**
|
||||
* Module settings form for Workshop instances
|
||||
*/
|
||||
@ -462,6 +463,23 @@ class mod_workshop_mod_form extends moodleform_mod {
|
||||
}
|
||||
}
|
||||
|
||||
// We need to do a custom completion validation because workshop grade items identifiers divert from standard.
|
||||
// Refer to validation defined in moodleform_mod.php.
|
||||
if (isset($data['completionpassgrade']) && $data['completionpassgrade'] &&
|
||||
isset($data['completiongradeitemnumber'])) {
|
||||
$itemnames = component_gradeitems::get_itemname_mapping_for_component('mod_workshop');
|
||||
$gradepassfield = $itemnames[(int) $data['completiongradeitemnumber']] . 'gradepass';
|
||||
if (!isset($data[$gradepassfield]) || grade_floatval($data[$gradepassfield]) == 0) {
|
||||
$errors['completionpassgrade'] = get_string(
|
||||
'activitygradetopassnotset',
|
||||
'completion'
|
||||
);
|
||||
} else {
|
||||
// We have validated grade pass. Unset any errors.
|
||||
unset($errors['completionpassgrade']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$data['submissiontypetextavailable'] && !$data['submissiontypefileavailable']) {
|
||||
// One submission type must be available.
|
||||
$errors['submissiontypes'] = get_string('nosubmissiontype', 'workshop');
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2021100300.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2021100300.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.0dev (Build: 20211003)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user