Index: lib/grade/grade_category.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/grade/grade_category.php,v retrieving revision 1.96.2.30 diff -u -r1.96.2.30 grade_category.php --- lib/grade/grade_category.php 29 Apr 2009 13:44:18 -0000 1.96.2.30 +++ lib/grade/grade_category.php 28 Jan 2010 07:02:05 -0000 @@ -209,13 +209,18 @@ $this->apply_forced_settings(); - // these are exclusive + // these are exclusive if ($this->droplow > 0) { $this->keephigh = 0; } else if ($this->keephigh > 0) { $this->droplow = 0; } + // If we're switching away from "Sum of grades" mode we should set the maxgrade for this + // category's grade item back to whatever it was before we entered "Sum of grades" in the + // first place. + $this->restore_non_sum_grademax(); + // Recalculate grades if needed if ($this->qualifies_for_regrading()) { $this->force_regrading(); @@ -1423,5 +1428,49 @@ $sql = "UPDATE {$CFG->prefix}grade_items SET needsupdate=1 WHERE itemtype='course' or itemtype='category'"; execute_sql($sql, false); } + + /** + * Intended to be called while updating the category. Checks to see whether the category is + * switching away from "Sum of grades" aggregation, and if so, restores the maxgrade for the + * category's gradeitem back to what it was before the category entered "Sum of grades" mode in + * the first place. + * + * This is because "Sum of grades" calculates the field completely differently from all other + * aggregation modes (in which it's an arbitrarily editable text field), so the user could + * otherwise lose information and be confused when switching between "Sum of grades" and other + * grade aggregation methods. (MDL-21449) + * + * @return void + */ + function restore_non_sum_grademax() { + global $CFG; + if ($this->aggregation != GRADE_AGGREGATE_SUM) { + $catprevstate = grade_category::fetch(array('id'=>$this->id)); + if ($catprevstate->aggregation == GRADE_AGGREGATE_SUM ) { + $gradeitem = $this->load_grade_item(); + + // The last history entry before the current "Sum of grades" setting was entered + $lastnonsumtime = get_field_select('grade_categories_history', + 'max(timemodified)', 'oldid = ' . $this->id . ' and aggregation <> 13'); + + // When the current "Sum of grades" setting actually started + $earliestsumtime = get_field_select('grade_categories_history', + 'min(timemodified)', 'oldid = ' . $this->id . ' and aggregation = 13 and ' + . 'timemodified >= ' . $lastnonsumtime ); + + // The grademax for the last grade_item entry before the "Sum of grades" started + $prevmaxgradearray = get_records_select('grade_items_history', 'timemodified < ' + . $earliestsumtime . ' and oldid = ' . $gradeitem->id, + 'timemodified desc', 'grademax', 0, 1); + if (!$prevmaxgradearray || count($prevmaxgradearray) == 0) { + $gradeitem->grademax = 100; + } else { + $prevmaxgrade = current($prevmaxgradearray); + $gradeitem->grademax = $prevmaxgrade->grademax; + } + $gradeitem->update(); + } + } + } } ?>