mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 20:50:21 +01:00
MDL-48634 grades: Add an option to rescale when changing the maxgrade
This commit is contained in:
parent
9d5d9c64ff
commit
d629c601c5
@ -453,6 +453,11 @@ function can_update_moduleinfo($cm) {
|
||||
function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$data = new stdClass();
|
||||
if ($mform) {
|
||||
$data = $mform->get_data();
|
||||
}
|
||||
|
||||
// Attempt to include module library before we make any changes to DB.
|
||||
include_modulelib($moduleinfo->modulename);
|
||||
|
||||
@ -523,9 +528,44 @@ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
|
||||
$moduleinfo->introformat = $moduleinfo->introeditor['format'];
|
||||
unset($moduleinfo->introeditor);
|
||||
}
|
||||
// Get the a copy of the grade_item before it is modified incase we need to scale the grades.
|
||||
$oldgradeitem = null;
|
||||
$newgradeitem = null;
|
||||
if (!empty($data->grade_rescalegrades)) {
|
||||
// Fetch the grade item before it is updated.
|
||||
$oldgradeitem = grade_item::fetch(array('itemtype' => 'mod',
|
||||
'itemmodule' => $moduleinfo->modulename,
|
||||
'iteminstance' => $moduleinfo->instance,
|
||||
'itemnumber' => 0,
|
||||
'courseid' => $moduleinfo->course));
|
||||
}
|
||||
|
||||
$updateinstancefunction = $moduleinfo->modulename."_update_instance";
|
||||
if (!$updateinstancefunction($moduleinfo, $mform)) {
|
||||
print_error('cannotupdatemod', '', course_get_url($course, $cw->section), $moduleinfo->modulename);
|
||||
print_error('cannotupdatemod', '', course_get_url($course, $cm->section), $moduleinfo->modulename);
|
||||
}
|
||||
|
||||
// This needs to happen AFTER the grademin/grademax have already been updated.
|
||||
if (!empty($data->grade_rescalegrades)) {
|
||||
// Get the grade_item after the update call the activity to scale the grades.
|
||||
$newgradeitem = grade_item::fetch(array('itemtype' => 'mod',
|
||||
'itemmodule' => $moduleinfo->modulename,
|
||||
'iteminstance' => $moduleinfo->instance,
|
||||
'itemnumber' => 0,
|
||||
'courseid' => $moduleinfo->course));
|
||||
if ($newgradeitem && $oldgradeitem->gradetype == GRADE_TYPE_VALUE && $newgradeitem->gradetype == GRADE_TYPE_VALUE) {
|
||||
$params = array(
|
||||
$course,
|
||||
$cm,
|
||||
$oldgradeitem->grademin,
|
||||
$oldgradeitem->grademax,
|
||||
$newgradeitem->grademin,
|
||||
$newgradeitem->grademax
|
||||
);
|
||||
if (!component_callback('mod_' . $moduleinfo->modulename, 'rescale_activity_grades', $params)) {
|
||||
print_error('cannotreprocessgrades', '', course_get_url($course, $cm->section), $moduleinfo->modulename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure visibility is set correctly (in particular in calendar).
|
||||
|
@ -109,9 +109,9 @@ abstract class moodleform_mod extends moodleform {
|
||||
$this->_features->defaultcompletion = plugin_supports('mod', $this->_modname, FEATURE_MODEDIT_DEFAULT_COMPLETION, true);
|
||||
$this->_features->rating = plugin_supports('mod', $this->_modname, FEATURE_RATE, false);
|
||||
$this->_features->showdescription = plugin_supports('mod', $this->_modname, FEATURE_SHOW_DESCRIPTION, false);
|
||||
|
||||
$this->_features->gradecat = ($this->_features->outcomes or $this->_features->hasgrades);
|
||||
$this->_features->advancedgrading = plugin_supports('mod', $this->_modname, FEATURE_ADVANCED_GRADING, false);
|
||||
$this->_features->canrescale = (component_callback_exists('mod_' . $this->_modname, 'rescale_activity_grades') !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -641,6 +641,11 @@ abstract class moodleform_mod extends moodleform {
|
||||
public function standard_grading_coursemodule_elements() {
|
||||
global $COURSE, $CFG;
|
||||
$mform =& $this->_form;
|
||||
$isupdate = !empty($this->_cm);
|
||||
$gradeoptions = array('isupdate' => $isupdate,
|
||||
'currentgrade' => false,
|
||||
'hasgrades' => false,
|
||||
'canrescale' => $this->_features->canrescale);
|
||||
|
||||
if ($this->_features->hasgrades) {
|
||||
|
||||
@ -650,7 +655,18 @@ abstract class moodleform_mod extends moodleform {
|
||||
|
||||
//if supports grades and grades arent being handled via ratings
|
||||
if (!$this->_features->rating) {
|
||||
$mform->addElement('modgrade', 'grade', get_string('grade'));
|
||||
|
||||
if ($isupdate) {
|
||||
$gradeitem = grade_item::fetch(array('itemtype' => 'mod',
|
||||
'itemmodule' => $this->_cm->modname,
|
||||
'iteminstance' => $this->_cm->instance,
|
||||
'itemnumber' => 0,
|
||||
'courseid' => $COURSE->id));
|
||||
|
||||
$gradeoptions['currentgrade'] = $gradeitem->grademax;
|
||||
$gradeoptions['hasgrades'] = $gradeitem->has_grades();
|
||||
}
|
||||
$mform->addElement('modgrade', 'grade', get_string('grade'), $gradeoptions);
|
||||
$mform->addHelpButton('grade', 'modgrade', 'grades');
|
||||
$mform->setDefault('grade', $CFG->gradepointdefault);
|
||||
}
|
||||
|
@ -156,6 +156,8 @@ if ($mform->is_cancelled()) {
|
||||
}
|
||||
|
||||
$grade_item = new grade_item(array('id'=>$id, 'courseid'=>$courseid));
|
||||
$oldmin = $grade_item->grademin;
|
||||
$oldmax = $grade_item->grademax;
|
||||
grade_item::set_properties($grade_item, $data);
|
||||
$grade_item->outcomeid = null;
|
||||
|
||||
@ -175,6 +177,12 @@ if ($mform->is_cancelled()) {
|
||||
|
||||
} else {
|
||||
$grade_item->update();
|
||||
|
||||
if (!empty($data->rescalegrades)) {
|
||||
$newmin = $grade_item->grademin;
|
||||
$newmax = $grade_item->grademax;
|
||||
$grade_item->rescale_grades_keep_percentage($oldmin, $oldmax, $newmin, $newmax, 'gradebook');
|
||||
}
|
||||
}
|
||||
|
||||
// update hiding flag
|
||||
|
@ -97,6 +97,10 @@ class edit_item_form extends moodleform {
|
||||
$mform->setType('grademin', PARAM_RAW);
|
||||
}
|
||||
|
||||
$mform->addElement('selectyesno', 'rescalegrades', get_string('modgraderescalegrades', 'grades'));
|
||||
$mform->addHelpButton('rescalegrades', 'modgraderescalegrades', 'grades');
|
||||
$mform->disabledIf('rescalegrades', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
|
||||
|
||||
$mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
|
||||
$mform->addHelpButton('gradepass', 'gradepass', 'grades');
|
||||
$mform->disabledIf('gradepass', 'gradetype', 'eq', GRADE_TYPE_NONE);
|
||||
@ -269,6 +273,7 @@ class edit_item_form extends moodleform {
|
||||
// the idnumber of grade itemnumber 0 is synced with course_modules
|
||||
$mform->hardFreeze('idnumber');
|
||||
}
|
||||
$mform->removeElement('rescalegrades');
|
||||
//$mform->removeElement('calculation');
|
||||
}
|
||||
}
|
||||
@ -342,6 +347,7 @@ class edit_item_form extends moodleform {
|
||||
// all new items are manual, children of course category
|
||||
$mform->removeElement('plusfactor');
|
||||
$mform->removeElement('multfactor');
|
||||
$mform->removeElement('rescalegrades');
|
||||
}
|
||||
|
||||
// no parent header for course category
|
||||
@ -353,12 +359,15 @@ class edit_item_form extends moodleform {
|
||||
/// perform extra validation before submission
|
||||
function validation($data, $files) {
|
||||
global $COURSE;
|
||||
$grade_item = false;
|
||||
if ($data['id']) {
|
||||
$grade_item = new grade_item(array('id' => $data['id'], 'courseid' => $data['courseid']));
|
||||
}
|
||||
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
if (array_key_exists('idnumber', $data)) {
|
||||
if ($data['id']) {
|
||||
$grade_item = new grade_item(array('id'=>$data['id'], 'courseid'=>$data['courseid']));
|
||||
if ($grade_item) {
|
||||
if ($grade_item->itemtype == 'mod') {
|
||||
$cm = get_coursemodule_from_instance($grade_item->itemmodule, $grade_item->iteminstance, $grade_item->courseid);
|
||||
} else {
|
||||
|
76
grade/tests/behat/grade_grade_minmax_change.feature
Normal file
76
grade/tests/behat/grade_grade_minmax_change.feature
Normal file
@ -0,0 +1,76 @@
|
||||
@core @core_grades
|
||||
Feature: We can change the maximum and minimum number of points for manual items with existing grades
|
||||
In order to verify existing grades are modified as expected
|
||||
As an teacher
|
||||
I need to modify a grade item with exiting grades
|
||||
I need to ensure existing grades are modified in an expected manner
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
|
||||
| student1 | Student | 1 | student1@example.com | s1 |
|
||||
| student2 | Student | 2 | student2@example.com | s2 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Gradebook setup" node in "Grade administration > Setup"
|
||||
And I press "Add grade item"
|
||||
And I set the following fields to these values:
|
||||
| Item name | Manual item 1 |
|
||||
| Minimum grade | 0 |
|
||||
| Maximum grade | 100 |
|
||||
And I press "Save changes"
|
||||
And I navigate to "Course grade settings" node in "Grade administration > Setup"
|
||||
And I set the field "Show weightings" to "Show"
|
||||
And I set the field "Show contribution to course total" to "Show"
|
||||
And I press "Save changes"
|
||||
|
||||
Scenario: Change maximum number of points on a graded item.
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "10.00" to the user "Student 1" for the grade item "Manual item 1"
|
||||
And I give the grade "8.00" to the user "Student 2" for the grade item "Manual item 1"
|
||||
And I press "Save changes"
|
||||
When I navigate to "Gradebook setup" node in "Grade administration > Setup"
|
||||
And I click on "Edit" "link" in the "Manual item 1" "table_row"
|
||||
And I click on "Edit settings" "link" in the "Manual item 1" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Maximum grade | 10 |
|
||||
| Rescale existing grades | No |
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
And I select "Student 1" from the "Select all or one user" singleselect
|
||||
Then the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Contribution to course total |
|
||||
| Manual item 1 | 100.00 % | 10.00 | 100.00 % |
|
||||
And I select "Student 2" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Contribution to course total |
|
||||
| Manual item 1 | 100.00 % | 8.00 | 80.00 % |
|
||||
And I navigate to "Gradebook setup" node in "Grade administration > Setup"
|
||||
And I click on "Edit" "link" in the "Manual item 1" "table_row"
|
||||
And I click on "Edit settings" "link" in the "Manual item 1" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Maximum grade | 20 |
|
||||
| Rescale existing grades | Yes |
|
||||
And I press "Save changes"
|
||||
And I follow "User report"
|
||||
And I select "Student 1" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Contribution to course total |
|
||||
| Manual item 1 | 100.00 % | 20.00 | 100.00 % |
|
||||
And I select "Student 2" from the "Select all or one user" singleselect
|
||||
And the following should exist in the "user-grade" table:
|
||||
| Grade item | Calculated weight | Grade | Contribution to course total |
|
||||
| Manual item 1 | 100.00 % | 16.00 | 80.00 % |
|
@ -123,6 +123,7 @@ $string['cannotreadfile'] = 'Cannot read file ({$a})';
|
||||
$string['cannotreadtmpfile'] = 'Error reading temporary file';
|
||||
$string['cannotreaduploadfile'] = 'Could not read uploaded file';
|
||||
$string['cannotremovefrommeta'] = 'Could not remove the selected course from this meta course!';
|
||||
$string['cannotreprocessgrades'] = 'Could not reprocess grades for this activity {$a}';
|
||||
$string['cannotresetguestpwd'] = 'You cannot reset the guest password';
|
||||
$string['cannotresetmail'] = 'Error resetting password and mailing you';
|
||||
$string['cannotresetthisrole'] = 'Cannot reset this role';
|
||||
|
@ -472,11 +472,21 @@ $string['minimum_show_help'] = 'Minimum grade is used in calculating grades and
|
||||
$string['missingitemtypeoreid'] = 'Array key (itemtype or eid) missing from 2nd param of grade_edit_tree_column_select::get_item_cell($item, $params)';
|
||||
$string['missingscale'] = 'Scale must be selected';
|
||||
$string['mode'] = 'Mode';
|
||||
$string['modgradeerrorbadpoint'] = 'Invalid Grade Value. This must be an integer between 1 and {$a}';
|
||||
$string['modgradeerrorbadscale'] = 'Invalid scale selected. Please make sure you select a scale from the selections below.';
|
||||
$string['modgrade'] = 'Grade';
|
||||
$string['modgrade_help'] = 'Select the type of grading used for this activity. If "scale" is chosen, you can then choose the scale from the "scale" dropdown. If using "point" grading, you can then enter the maximum grade available for this activity.';
|
||||
$string['modgradedonotmodify'] = 'Do not modify existing grades';
|
||||
$string['modgradeerrorbadpoint'] = 'Invalid Grade Value. This must be an integer between 0 and {$a}';
|
||||
$string['modgradeerrorbadscale'] = 'Invalid scale selected. Please make sure you select a scale from the selections below.';
|
||||
$string['modgrademaxgrade'] = 'Maximum points';
|
||||
$string['modgraderescalegrades'] = 'Rescale existing grades';
|
||||
$string['modgraderescalegrades_help'] = 'Changing the maximum points value for an activity has an effect on the percentage of any existing grades for that activity. If this "Rescale existing grades" option is enabled, all existing grades will be scaled so that the same percentage grade is maintained.
|
||||
|
||||
Example (with "Rescale existing grades" set to "Yes"):
|
||||
|
||||
A student grade of "6 / 10 ( 60 % )" would change to "12 / 20 ( 60 % )" when the maximum points is changed to 20.
|
||||
|
||||
';
|
||||
$string['modgraderescalegrades_link'] = 'Scaling_Activity_Grades';
|
||||
$string['modgradetype'] = 'Type';
|
||||
$string['modgradetypenone'] = 'None';
|
||||
$string['modgradetypepoint'] = 'Point';
|
||||
|
@ -43,14 +43,29 @@ require_once($CFG->dirroot.'/lib/grade/grade_scale.php');
|
||||
* @copyright 2006 Jamie Pratt <me@jamiep.org>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
class MoodleQuickForm_modgrade extends MoodleQuickForm_group {
|
||||
|
||||
/** @var boolean $isupdate Is this an add or an update ? */
|
||||
public $isupdate = false;
|
||||
|
||||
/** @var float $currentgrade The current grademax for the grade_item */
|
||||
public $currentgrade = false;
|
||||
|
||||
/** @var boolean $hasgrades Has this grade_item got any real grades (with values) */
|
||||
public $hasgrades = false;
|
||||
|
||||
/** @var boolean $canrescale Does this activity support rescaling grades? */
|
||||
public $canrescale = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $elementname Element's name
|
||||
* @param mixed $elementlabel Label(s) for an element
|
||||
* @param array $options Options to control the element's display. Not used.
|
||||
* @param array $options Options to control the element's display. Required - must contain the following options:
|
||||
* 'isupdate' - is this a new module or are we editing an existing one?
|
||||
* 'currentgrade' - the current grademax in the database for this gradeitem
|
||||
* 'hasgrades' - whether or not the grade_item has existing grade_grades
|
||||
* @param mixed $attributes Either a typical HTML attribute string or an associative array
|
||||
*/
|
||||
public function __construct($elementname = null, $elementlabel = null, $options = array(), $attributes = null) {
|
||||
@ -59,6 +74,13 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
$this->_persistantFreeze = true;
|
||||
$this->_appendName = true;
|
||||
$this->_type = 'modgrade';
|
||||
$this->isupdate = !empty($options['isupdate']);
|
||||
$this->currentgrade = false;
|
||||
if (isset($options['currentgrade'])) {
|
||||
$this->currentgrade = $options['currentgrade'];
|
||||
}
|
||||
$this->hasgrades = !empty($options['hasgrades']);
|
||||
$this->canrescale = !empty($options['canrescale']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,7 +97,7 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
* Create elements for this group.
|
||||
*/
|
||||
public function _createElements() {
|
||||
global $COURSE, $CFG;
|
||||
global $COURSE, $CFG, $OUTPUT;
|
||||
$attributes = $this->getAttributes();
|
||||
if (is_null($attributes)) {
|
||||
$attributes = array();
|
||||
@ -113,6 +135,16 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
$typeselectid = $this->generate_modgrade_subelement_id('modgrade_type');
|
||||
$typeselect->updateAttributes(array('id' => $typeselectid));
|
||||
|
||||
// Check box for options for processing existing grades.
|
||||
if ($this->isupdate && $this->hasgrades && $this->canrescale) {
|
||||
$langrescalegrades = get_string('modgraderescalegrades', 'grades');
|
||||
$rescalegradesselect = @MoodleQuickForm::createElement('selectyesno',
|
||||
'modgrade_rescalegrades',
|
||||
$langrescalegrades);
|
||||
$rescalegradesselect->_generateId();
|
||||
$rescalegradesid = $rescalegradesselect->getAttribute('id');
|
||||
}
|
||||
|
||||
// Add elements.
|
||||
|
||||
// Grade type select box.
|
||||
@ -132,6 +164,15 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
$this->_elements[] = @MoodleQuickForm::createElement('static', 'pointlabel', '', $label);
|
||||
$this->_elements[] = $maxgrade;
|
||||
$this->_elements[] = @MoodleQuickForm::createElement('static', 'pointspacer', '', '<br />');
|
||||
|
||||
if ($this->isupdate && $this->hasgrades && $this->canrescale) {
|
||||
// We need to know how to apply any changes to maxgrade - ie to either update, or don't touch exising grades.
|
||||
$label = html_writer::tag('label', $rescalegradesselect->getLabel(), array('for' => $rescalegradesid));
|
||||
$labelhelp = new help_icon('modgraderescalegrades', 'grades');
|
||||
$this->_elements[] = @MoodleQuickForm::createElement('static', 'scalelabel', '', $label . $OUTPUT->render($labelhelp));
|
||||
$this->_elements[] = $rescalegradesselect;
|
||||
$this->_elements[] = @MoodleQuickForm::createElement('static', 'scalespacer', '', '<br />');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,8 +197,9 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
$type = (isset($vals['modgrade_type'])) ? $vals['modgrade_type'] : 'none';
|
||||
$point = (isset($vals['modgrade_point'])) ? $vals['modgrade_point'] : null;
|
||||
$scale = (isset($vals['modgrade_scale'])) ? $vals['modgrade_scale'] : null;
|
||||
$rescalegrades = (isset($vals['modgrade_rescalegrades'])) ? $vals['modgrade_rescalegrades'] : null;
|
||||
$return = $this->process_value($type, $scale, $point);
|
||||
return array($this->getName() => $return);
|
||||
return array($this->getName() => $return, $this->getName() . '_rescalegrades' => $rescalegrades);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,6 +273,7 @@ class MoodleQuickForm_modgrade extends MoodleQuickForm_group{
|
||||
// Set disable actions.
|
||||
$caller->disabledIf($name.'[modgrade_scale]', $name.'[modgrade_type]', 'neq', 'scale');
|
||||
$caller->disabledIf($name.'[modgrade_point]', $name.'[modgrade_type]', 'neq', 'point');
|
||||
$caller->disabledIf($name.'[modgrade_rescalegrades]', $name.'[modgrade_type]', 'neq', 'point');
|
||||
|
||||
// Set validation rules for the sub-elements belonging to this element.
|
||||
// A handy note: the parent scope of a closure is the function in which the closure was declared.
|
||||
|
@ -354,6 +354,20 @@ class grade_item extends grade_object {
|
||||
return grade_object::fetch_helper('grade_items', 'grade_item', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if there are any existing grades for this grade_item.
|
||||
*
|
||||
* @return boolean - true if there are valid grades for this grade_item.
|
||||
*/
|
||||
public function has_grades() {
|
||||
global $DB;
|
||||
|
||||
$count = $DB->count_records_select('grade_grades',
|
||||
'itemid = :gradeitemid AND finalgrade IS NOT NULL',
|
||||
array('gradeitemid' => $this->id));
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns all grade_item instances based on params.
|
||||
*
|
||||
@ -819,6 +833,60 @@ class grade_item extends grade_object {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the rawgrademax and rawgrademin for all grade_grades records for this item.
|
||||
* Scale every rawgrade to maintain the percentage. This function should be called
|
||||
* after the gradeitem has been updated to the new min and max values.
|
||||
*
|
||||
* @param float $oldgrademin The previous grade min value
|
||||
* @param float $oldgrademax The previous grade max value
|
||||
* @param float $newgrademin The new grade min value
|
||||
* @param float $newgrademax The new grade max value
|
||||
* @param string $source from where was the object inserted (mod/forum, manual, etc.)
|
||||
* @return bool True on success
|
||||
*/
|
||||
public function rescale_grades_keep_percentage($oldgrademin, $oldgrademax, $newgrademin, $newgrademax, $source = null) {
|
||||
global $DB;
|
||||
|
||||
if (empty($this->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($oldgrademax <= $oldgrademin) {
|
||||
// Grades cannot be scaled.
|
||||
return false;
|
||||
}
|
||||
$scale = ($newgrademax - $newgrademin) / ($oldgrademax - $oldgrademin);
|
||||
if (($newgrademax - $newgrademin) <= 1) {
|
||||
// We would lose too much precision, lets bail.
|
||||
return false;
|
||||
}
|
||||
|
||||
$rs = $DB->get_recordset('grade_grades', array('itemid' => $this->id));
|
||||
|
||||
foreach ($rs as $graderecord) {
|
||||
// For each record, create an object to work on.
|
||||
$grade = new grade_grade($graderecord, false);
|
||||
// Set this object in the item so it doesn't re-fetch it.
|
||||
$grade->grade_item = $this;
|
||||
|
||||
// Updating the raw grade automatically updates the min/max.
|
||||
if ($this->is_raw_used()) {
|
||||
$rawgrade = (($grade->rawgrade - $oldgrademin) * $scale) + $newgrademin;
|
||||
$this->update_raw_grade(false, $rawgrade, $source, false, FORMAT_MOODLE, null, null, null, $grade);
|
||||
} else {
|
||||
$finalgrade = (($grade->finalgrade - $oldgrademin) * $scale) + $newgrademin;
|
||||
$this->update_final_grade($grade->userid, $finalgrade, $source);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Mark this item for regrading.
|
||||
$this->force_regrading();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this grade_item's needsupdate to true. Also marks the course item as needing update.
|
||||
*
|
||||
@ -1649,6 +1717,8 @@ class grade_item extends grade_object {
|
||||
$oldgrade->overridden = $grade->overridden;
|
||||
$oldgrade->feedback = $grade->feedback;
|
||||
$oldgrade->feedbackformat = $grade->feedbackformat;
|
||||
$oldgrade->rawgrademin = $grade->rawgrademin;
|
||||
$oldgrade->rawgrademax = $grade->rawgrademax;
|
||||
|
||||
// MDL-31713 rawgramemin and max must be up to date so conditional access %'s works properly.
|
||||
$grade->rawgrademin = $this->grademin;
|
||||
@ -1687,6 +1757,8 @@ class grade_item extends grade_object {
|
||||
} else if (grade_floats_different($grade->finalgrade, $oldgrade->finalgrade)
|
||||
or $grade->feedback !== $oldgrade->feedback
|
||||
or $grade->feedbackformat != $oldgrade->feedbackformat
|
||||
or grade_floats_different($grade->rawgrademin, $oldgrade->rawgrademin)
|
||||
or grade_floats_different($grade->rawgrademax, $oldgrade->rawgrademax)
|
||||
or ($oldgrade->overridden == 0 and $grade->overridden > 0)) {
|
||||
$grade->timemodified = time(); // hack alert - date graded
|
||||
$result = $grade->update($source);
|
||||
|
@ -50,6 +50,7 @@ class core_grade_item_testcase extends grade_base_testcase {
|
||||
$this->sub_test_grade_item_load_item_category();
|
||||
$this->sub_test_grade_item_regrade_final_grades();
|
||||
$this->sub_test_grade_item_adjust_raw_grade();
|
||||
$this->sub_test_grade_item_rescale_grades_keep_percentage();
|
||||
$this->sub_test_grade_item_set_locked();
|
||||
$this->sub_test_grade_item_is_locked();
|
||||
$this->sub_test_grade_item_set_hidden();
|
||||
@ -371,6 +372,46 @@ class core_grade_item_testcase extends grade_base_testcase {
|
||||
$this->assertEquals(round(1.6), round($grade_item->adjust_raw_grade($grade_raw->rawgrade, $grade_raw->grademin, $grade_raw->grademax)));
|
||||
}
|
||||
|
||||
protected function sub_test_grade_item_rescale_grades_keep_percentage() {
|
||||
global $DB;
|
||||
$gradeitem = new grade_item($this->grade_items[10], false); // 10 is the manual grade item.
|
||||
|
||||
// Create some grades to go with the grade item.
|
||||
$gradeids = array();
|
||||
$grade = new stdClass();
|
||||
$grade->itemid = $gradeitem->id;
|
||||
$grade->userid = $this->user[2]->id;
|
||||
$grade->finalgrade = 10;
|
||||
$grade->rawgrademax = $gradeitem->grademax;
|
||||
$grade->rawgrademin = $gradeitem->grademin;
|
||||
$grade->timecreated = time();
|
||||
$grade->timemodified = time();
|
||||
$gradeids[] = $DB->insert_record('grade_grades', $grade);
|
||||
|
||||
$grade->userid = $this->user[3]->id;
|
||||
$grade->finalgrade = 50;
|
||||
$grade->rawgrademax = $gradeitem->grademax;
|
||||
$grade->rawgrademin = $gradeitem->grademin;
|
||||
$gradeids[] = $DB->insert_record('grade_grades', $grade);
|
||||
|
||||
// Run the function.
|
||||
$gradeitem->grademax = 33;
|
||||
$gradeitem->grademin = 3;
|
||||
$gradeitem->update();
|
||||
$gradeitem->rescale_grades_keep_percentage(0, 100, 3, 33, 'test');
|
||||
|
||||
// Check that the grades were updated to match the grade item.
|
||||
$grade = $DB->get_record('grade_grades', array('id' => $gradeids[0]));
|
||||
$this->assertEquals($gradeitem->grademax, $grade->rawgrademax, 'Max grade mismatch', 0.0001);
|
||||
$this->assertEquals($gradeitem->grademin, $grade->rawgrademin, 'Min grade mismatch', 0.0001);
|
||||
$this->assertEquals(6, $grade->finalgrade, 'Min grade mismatch', 0.0001);
|
||||
|
||||
$grade = $DB->get_record('grade_grades', array('id' => $gradeids[1]));
|
||||
$this->assertEquals($gradeitem->grademax, $grade->rawgrademax, 'Max grade mismatch', 0.0001);
|
||||
$this->assertEquals($gradeitem->grademin, $grade->rawgrademin, 'Min grade mismatch', 0.0001);
|
||||
$this->assertEquals(18, $grade->finalgrade, 'Min grade mismatch', 0.0001);
|
||||
}
|
||||
|
||||
protected function sub_test_grade_item_set_locked() {
|
||||
// Getting a grade_item from the DB as set_locked() will fail if the grade items needs to be updated
|
||||
// also needs to have at least one grade_grade or $grade_item->get_final(1) returns null.
|
||||
|
@ -1315,6 +1315,52 @@ function assign_user_complete($course, $user, $coursemodule, $assign) {
|
||||
echo $assignment->view_student_summary($user, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescale all grades for this activity and push the new grades to the gradebook.
|
||||
*
|
||||
* @param stdClass $course Course db record
|
||||
* @param stdClass $cm Course module db record
|
||||
* @param float $oldmin
|
||||
* @param float $oldmax
|
||||
* @param float $newmin
|
||||
* @param float $newmax
|
||||
*/
|
||||
function assign_rescale_activity_grades($course, $cm, $oldmin, $oldmax, $newmin, $newmax) {
|
||||
global $DB;
|
||||
|
||||
if ($oldmax <= $oldmin) {
|
||||
// Grades cannot be scaled.
|
||||
return false;
|
||||
}
|
||||
$scale = ($newmax - $newmin) / ($oldmax - $oldmin);
|
||||
if (($newmax - $newmin) <= 1) {
|
||||
// We would lose too much precision, lets bail.
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'p1' => $oldmin,
|
||||
'p2' => $scale,
|
||||
'p3' => $newmin,
|
||||
'a' => $cm->instance
|
||||
);
|
||||
|
||||
$sql = 'UPDATE {assign_grades} set grade = (((grade - :p1) * :p2) + :p3) where assignment = :a';
|
||||
$dbupdate = $DB->execute($sql, $params);
|
||||
if (!$dbupdate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now re-push all grades to the gradebook.
|
||||
$dbparams = array('id' => $cm->instance);
|
||||
$assign = $DB->get_record('assign', $dbparams);
|
||||
$assign->cmidnumber = $cm->idnumber;
|
||||
|
||||
assign_update_grades($assign);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the grade information for the assignment for this user.
|
||||
*
|
||||
|
49
mod/assign/tests/behat/rescale_grades.feature
Normal file
49
mod/assign/tests/behat/rescale_grades.feature
Normal file
@ -0,0 +1,49 @@
|
||||
@mod @mod_assign
|
||||
Feature: Check that the assignment grade can be rescaled when the max grade is changed
|
||||
In order to ensure that the percentages are not affected by changes to the max grade
|
||||
As a teacher
|
||||
I need to rescale all grades when updating the max grade
|
||||
|
||||
@javascript
|
||||
Scenario: Update the max grade for an assignment and rescale existing grades
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student10@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Group 1 | C1 | G1 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Test assignment description |
|
||||
When I follow "Test assignment name"
|
||||
Then I follow "View/grade all submissions"
|
||||
And I click on "Grade Student 1" "link" in the "Student 1" "table_row"
|
||||
And I set the field "Grade out of 100" to "40"
|
||||
And I press "Save changes"
|
||||
And I press "Continue"
|
||||
And "Student 1" row "Grade" column of "generaltable" table should contain "40.00"
|
||||
And I follow "Edit settings"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Maximum points" to "80"
|
||||
And I press "Save and display"
|
||||
And I follow "View/grade all submissions"
|
||||
And "Student 1" row "Grade" column of "generaltable" table should contain "40.00"
|
||||
And I follow "Edit settings"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Maximum points" to "100"
|
||||
And I set the field "Rescale existing grades" to "Yes"
|
||||
And I press "Save and display"
|
||||
Then I follow "View/grade all submissions"
|
||||
And "Student 1" row "Grade" column of "generaltable" table should contain "50.00"
|
||||
|
Loading…
x
Reference in New Issue
Block a user