commit a0029ac6906e74830ba121ceebc061cd0cf205c2
Author: Huy Hoang <hoang027@umn.edu>
Date:   Wed Jun 19 15:17:00 2013 -0500

    switched grade letter form to allow decimal input; fixed bug that
    resulted in DB error when updating the letter records.

diff --git a/grade/edit/letter/edit_form.php b/grade/edit/letter/edit_form.php
index baa4087..867452b 100644
--- a/grade/edit/letter/edit_form.php
+++ b/grade/edit/letter/edit_form.php
@@ -46,38 +46,35 @@ class edit_letter_form extends moodleform {
         $gradeletter       = get_string('gradeletter', 'grades');
         $gradeboundary     = get_string('gradeboundary', 'grades');
 
-        $percentages = array(-1 => get_string('unused', 'grades'));
-        for ($i=100; $i > -1; $i--) {
-            $percentages[$i] = "$i %";
-        }
-
-        for($i=1; $i<$num+1; $i++) {
+        for ($i=1; $i<$num+1; $i++) {
             $gradelettername = 'gradeletter'.$i;
             $gradeboundaryname = 'gradeboundary'.$i;
 
-            $mform->addElement('text', $gradelettername, $gradeletter." $i");
-            if ($i == 1) {
-                $mform->addHelpButton($gradelettername, 'gradeletter', 'grades');
-            }
+            $entry = array();
+            $entry[] = & $mform->createElement('text', $gradelettername, $gradeletter." $i");
             $mform->setType($gradelettername, PARAM_TEXT);
 
             if (!$admin) {
                 $mform->disabledIf($gradelettername, 'override', 'notchecked');
-                $mform->disabledIf($gradelettername, $gradeboundaryname, 'eq', -1);
             }
 
-            $mform->addElement('select', $gradeboundaryname, $gradeboundary." $i", $percentages);
-            if ($i == 1) {
-                $mform->addHelpButton($gradeboundaryname, 'gradeboundary', 'grades');
-            }
-            $mform->setDefault($gradeboundaryname, -1);
-            $mform->setType($gradeboundaryname, PARAM_INT);
+            $entry[] = & $mform->createElement('static', '', '', '&ge;');
+            $entry[] = & $mform->createElement('text', $gradeboundaryname, $gradeboundary." $i");
+            $entry[] = & $mform->createElement('static', '', '', '%');
+            $mform->addGroup($entry, 'gradeentry'.$i, $gradeletter." $i", array(' '), false);
+
+            $mform->setType($gradeboundaryname, PARAM_FLOAT);
 
             if (!$admin) {
                 $mform->disabledIf($gradeboundaryname, 'override', 'notchecked');
             }
         }
 
+        if ($num > 0) {
+            $mform->addHelpButton('gradeentry1', 'gradeletter', 'grades');
+        }
+
+
         // hidden params
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
diff --git a/grade/edit/letter/index.php b/grade/edit/letter/index.php
index d0dc35a..0b6a761 100644
--- a/grade/edit/letter/index.php
+++ b/grade/edit/letter/index.php
@@ -137,7 +137,7 @@ if (!$edit) {
         }
 
         $letters = array();
-        for($i=1; $i<$num+1; $i++) {
+        for ($i=1; $i < $num+1; $i++) {
             $gradelettername = 'gradeletter'.$i;
             $gradeboundaryname = 'gradeboundary'.$i;
 
@@ -146,32 +146,54 @@ if (!$edit) {
                 if ($letter == '') {
                     continue;
                 }
-                $letters[$data->$gradeboundaryname] = $letter;
+
+                $boundary = floatval($data->$gradeboundaryname);
+
+                if ($boundary < 0 || $boundary > 100) {
+                    continue;    // skip if out of range
+                }
+
+                $letters[number_format($boundary, 5)] = $letter;
             }
         }
-        krsort($letters, SORT_NUMERIC);
 
-        $old_ids = array();
-        if ($records = $DB->get_records('grade_letters', array('contextid' => $context->id), 'lowerboundary ASC', 'id')) {
-            $old_ids = array_keys($records);
+        $pool = array();
+        if ($records = $DB->get_records('grade_letters', array('contextid' => $context->id), 'lowerboundary ASC')) {
+            foreach ($records as $r) {
+                // will re-use the lowerboundary to avoid duplicate during the update process
+                $pool[number_format($r->lowerboundary, 5)] = $r;
+            }
         }
 
-        foreach($letters as $boundary=>$letter) {
+        foreach ($letters as $boundary => $letter) {
             $record = new stdClass();
             $record->letter        = $letter;
             $record->lowerboundary = $boundary;
             $record->contextid     = $context->id;
 
-            if ($old_id = array_pop($old_ids)) {
-                $record->id = $old_id;
+            // re-use the existing boundary to avoid key constraint
+            if (isset($pool[$boundary])) {
+                // skip if the letter has been assigned to the boundary already
+                if (strtolower($letter) == strtolower($pool[$boundary]->letter)) {
+                    unset($pool[$boundary]); // take it out of the pool
+                }
+                else {
+                    $record->id = $pool[$boundary]->id;
+                    $DB->update_record('grade_letters', $record);
+                    unset($pool[$boundary]);    // remove the ID from the pool
+                }
+            }
+            else if ($candidate = array_pop($pool)) {
+                $record->id = $candidate->id;
                 $DB->update_record('grade_letters', $record);
             } else {
                 $DB->insert_record('grade_letters', $record);
             }
         }
 
-        foreach($old_ids as $old_id) {
-            $DB->delete_records('grade_letters', array('id' => $old_id));
+        // delete the unused records
+        foreach($pool as $leftover) {
+            $DB->delete_records('grade_letters', array('id' => $leftover->id));
         }
 
         redirect($returnurl);
