=== modified file 'modules/uc_product_minmax/uc_product_minmax.module'
--- modules/uc_product_minmax/uc_product_minmax.module	2010-09-24 18:27:06 +0000
+++ modules/uc_product_minmax/uc_product_minmax.module	2010-09-24 21:00:56 +0000
@@ -14,7 +14,6 @@
  * Original development sponsored by Plum Drama - http://www.plumdrama.com
  */
 
-
 /*******************************************************************************
  * Product Feature API (Ubercart)
  ******************************************************************************/
@@ -57,7 +56,6 @@
   return $form;
 }
 
-
 /**
  * This form gets displayed when a product feature is added or edited for this
  * product feature type.
@@ -67,20 +65,18 @@
       $minmax = uc_product_minmax_values_load($feature['pfid']);
     }
     $form['nid'] = array(
-    '#type' => 'hidden',
-    '#value' => $node->nid,
+      '#type' => 'hidden',
+      '#value' => $node->nid,
     );
     $form['min_fieldset'] = array(
       '#type' => 'fieldset',
       '#title' => t('Minimum'),
-      '#collapsed' => FALSE,
-      '#collapsible' => FALSE,
     );
     $form['min_fieldset']['product_min'] = array(
       '#type' => 'textfield',
       '#title' => t('Minimum quantity to checkout'),
       '#description' => t('Enter the minimum quantity of this product needed to checkout.'),
-      '#default_value' => !empty($minmax->product_min) ? $minmax->product_min : 1,
+      '#default_value' => $minmax->product_min,
       '#size' => 10,
     );
     $form['min_fieldset']['display_min'] = array(
@@ -104,8 +100,6 @@
     $form['max_fieldset'] = array(
       '#type' => 'fieldset',
       '#title' => t('Maxmimum'),
-      '#collapsed' => FALSE,
-      '#collapsible' => FALSE,
     );
     $form['max_fieldset']['product_max'] = array(
       '#type' => 'textfield',
@@ -113,7 +107,7 @@
       '#description' => t('Enter the maximum quantity of this product allowed to checkout. Set 0 for no limit.'),
       '#default_value' => !empty($minmax->product_max) ? $minmax->product_max : 0,
       '#size' => 10,
-    );  
+    );
     $form['max_fieldset']['display_max'] = array(
       '#type' => 'checkbox',
       '#title' => t('Display the Maximum text on product page'),
@@ -131,26 +125,18 @@
 }
 
 function uc_product_minmax_feature_form_validate($form, &$form_state) {
-  $exists = db_result(db_query("SELECT pfid FROM {uc_product_minmax} WHERE nid = %d", $form_state['values']['nid']));
-  $pass = TRUE;
-  if ($exists && $exists != $form_state['values']['pfid']) {
-  	form_set_error('minmax_exists', t('Product Minimum & Maximum feature already exists for this product.'));
-  	$pass = FALSE;
+  $minmax = uc_product_minmax_feature_load($form_state['values']['nid']);
+  if ($minmax && $minmax->pfid != $form_state['values']['pfid']) {
+    form_set_error('minmax_exists', t('Product Minimum & Maximum feature already exists for this product.'));
   }
-  if (empty($form_state['values']['product_min']) || !ctype_digit($form_state['values']['product_min'])) {
-    form_set_error('product_min', t('The value for Minimum may not contain anything but numeric characters of 1 or greater.'));
-    $pass = FALSE;
+  if (!ctype_digit($form_state['values']['product_min'])) {
+    form_set_error('product_min', t('The value for Minimum must be zero or a positive integer.'));
   }
   if (empty($form_state['values']['pmin_multiple']) || !ctype_digit($form_state['values']['pmin_multiple'])) {
-    form_set_error('pmin_multiple', t('The value for Multiple may not contain anything but numeric characters of 1 or greater.'));
-    $pass = FALSE;
-  }
-  if (!is_numeric($form_state['values']['product_max']) || $form_state['values']['product_max'] < 0) {
-    form_set_error('product_max', t('The value for Maximim may not contain anything but numeric characters.'));
-    $pass = FALSE;
-  }
-  if (!$pass) {
-    drupal_set_message(t('Please check your settings and try again.'), 'error');
+    form_set_error('pmin_multiple', t('The value for Multiple must be an integer greater than zero'));
+  }
+  if (!ctype_digit($form_state['values']['product_max'])) {
+    form_set_error('product_max', t('The value for Maximum must be zero or a positive integer.'));
   }
 }
 
@@ -159,7 +145,7 @@
   if (!empty($form_state['values']['pfid'])) {
     $pfid = $form_state['values']['pfid'];
   }
-  
+
   $minmax->pfid = $pfid;
   $minmax->nid = $form_state['values']['nid'];
   $minmax->product_min = intval($form_state['values']['product_min']);
@@ -169,19 +155,20 @@
   $minmax->display_multiple = $form_state['values']['display_multiple'];
   $minmax->display_max = $form_state['values']['display_max'];
   $minmax->display_weight = $form_state['values']['display_weight'];
-  
+
   $args =array(
-  	'@min' => $minmax->pmin_multiple ? t('Requires item to be purchased in multiples of @multiple.', array('@multiple' => $minmax->pmin_multiple)) : t('Requires a minimum of @minimum to checkout.', array('@minimum' => $minmax->product_min)),
-  	'@max' => $minmax->product_max >= 1 ? t('Limits checkout to a maximum of @maximum.', array('@maximum' => $minmax->product_max)) : '',
+    '@min' => $minmax->pmin_multiple > 1 ? t('Requires item to be purchased in multiples of @multiple.', array('@multiple' => $minmax->pmin_multiple))
+          : $minmax->minimum > 0 ? t('Requires a minimum of @minimum to checkout.', array('@minimum' => $minmax->product_min)) : '',
+    '@max' => $minmax->product_max >= 1 ? t('Limits checkout to a maximum of @maximum.', array('@maximum' => $minmax->product_max)) : '',
   );
-  
+
   $data = array(
     'pfid' => $form_state['values']['pfid'],
     'nid' => $form_state['values']['nid'],
     'fid' => 'minmax',
     'description' => t('@min @max', $args),
   );
-  
+
   // Save the product feature and store the returned URL as our redirect.
   $form_state['redirect'] = uc_product_feature_save($data);
 
@@ -206,22 +193,28 @@
  * Implementation of hook_add_to_cart().
  */
 function uc_product_minmax_add_to_cart($nid, $qty, $data) {
-  $minmaxresult = db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE nid = %s", $nid));
-  $fail = 0;
-  if ($qty < $minmaxresult->product_min) {
-    $fail = 1;
-    $message[] = t('The minimum order quantity for this item is @qty.', array('@qty' => $minmaxresult->product_min));
-  }
-  if ($minmaxresult->pmin_multiple && $qty % $minmaxresult->pmin_multiple != 0) {
-    $fail = 1;
-    $message[] = t('This item must be ordered in multiples of @qty.', array('@qty' => $minmaxresult->pmin_multiple));
-  }
-  if ($minmaxresult->product_max && $qty > $minmaxresult->product_max && $minmaxresult->product_max != 0) {
-    $fail = 1;
-    $message[] = t('The maximum order quantity for this item is @qty.', array('@qty' => $minmaxresult->product_max));
-  }
-  if ($fail) {
-    $message[] = t('Please check your quantity and try again.');
+  $minmax = uc_product_minmax_feature_load($nid);
+
+  $cart_total = 0;
+  $items = uc_cart_get_contents();
+  foreach($items as $item) {
+    if($item->nid === $nid) {
+      $cart_total++;
+    }
+  }
+
+  $node = node_load($nid);
+
+  if ($minmax->product_min && $qty + $cart_total < $minmax->product_min) {
+    $message[] = t('The minimum order quantity for <em>!item</em> is @qty.', array('@qty' => $minmax->product_min, '!item' => $node->title));
+  }
+  if ($minmax->product_max && $qty + $cart_total > $minmax->product_max) {
+    $message[] = t('The maximum order quantity for <em>!item</em> is @qty.', array('@qty' => $minmax->product_max, '!item' => $node->title));
+  }
+  if ($minmax->pmin_multiple && ($qty + $cart_total) % $minmax->pmin_multiple) {
+    $message[] = t('Orders for <em>!item</em> must be in multiples of @qty.', array('@qty' => $minmax->pmin_multiple, '!item' => $node->title));
+  }
+  if (count($message)) {
     $result[] = array(
       'success' => FALSE,
       'message' => theme('item_list', $message),
@@ -230,7 +223,6 @@
   return $result;
 }
 
-
 /**
  * Implementation of hook_checkout_pane().
  */
@@ -246,14 +238,16 @@
   return $panes;
 }
 
-// Checks the cart at checkout to make sure it's valid.
+/**
+ * Checks the cart at checkout to make sure it's valid.
+ */
 function uc_checkout_pane_product_minmax($op, &$arg1, $arg2) {
   switch ($op) {
     case 'view':
       $items = uc_cart_get_contents();
       $pass = TRUE;
 
-      /* Check minimums */
+      // Check minimums
       $nids = array();
       foreach ($items as $item) {
         $nids[] = $item->nid;
@@ -268,17 +262,17 @@
       }
 
       foreach ($items as $item) {
-          if ($min[$item->nid]['multiple'] && $item->qty % $min[$item->nid]['multiple'] != 0) {
-            drupal_set_message(t('!item must be ordered in multiples of !qty.', array('!item' => $item->title, '!qty' => $min[$item->nid]['multiple'])), 'error');
-            $pass = FALSE;
-          }                
-          if ($item->qty < $min[$item->nid]['min']) {
-            drupal_set_message(t('You must order at least !qty of !item to proceed to checkout.', array('!qty' => $min[$item->nid]['min'], '!item' => $item->title)), 'error');
-            $pass = FALSE;
-          }
+        if ($min[$item->nid]['multiple'] && $item->qty % $min[$item->nid]['multiple'] != 0) {
+          drupal_set_message(t('!item must be ordered in multiples of !qty.', array('!item' => $item->title, '!qty' => $min[$item->nid]['multiple'])), 'error');
+          $pass = FALSE;
+        }
+        if ($item->qty < $min[$item->nid]['min']) {
+          drupal_set_message(t('You must order at least !qty of !item to proceed to checkout.', array('!qty' => $min[$item->nid]['min'], '!item' => $item->title)), 'error');
+          $pass = FALSE;
+        }
       }
 
-      /* Check maximums */
+      // Check maximums
       $buying = array();
       $titles = array();
       foreach ($items as $item) {
@@ -293,23 +287,20 @@
       }
 
       foreach ($buying as $nid => $qty) {
-		if (!empty($max[$nid]) && $qty > $max[$nid] && $max[$nid] != 0) {
-		  drupal_set_message(t('The maximum allowed quantity for item !item is !qty.', array('!qty' => $max[$nid], '!item' => $titles[$nid])), 'error');
-		  $pass = FALSE;
-		}
+        if (!empty($max[$nid]) && $qty > $max[$nid] && $max[$nid] != 0) {
+          drupal_set_message(t('The maximum allowed quantity for item !item is !qty.', array('!qty' => $max[$nid], '!item' => $titles[$nid])), 'error');
+          $pass = FALSE;
+        }
       }
 
-      
       if (!$pass) {
         drupal_set_message(t('Please update your cart contents and try again.'), 'error');
         drupal_goto('cart');
       }
+      break;
   }
 }
 
-/*******************************************************************************
- * Hook Functions (Drupal)
- ******************************************************************************/
 /**
  * Implementation of hook_theme()
  * Themes the product minimum notice line on product view pages.
@@ -337,7 +328,6 @@
   if ($min > 1 && $display_min) {
     $output .= '<div class="uc_product_min">' . t('A minimum order of at least !qty is required.', array('!qty' => $min)) . '</div>';
   }
-  
   if ($max >= 1 && $display_max) {
     $output .= '<div class="uc_product_max">' . t('A maximum order of !qty is allowed.', array('!qty' => $max)) . '</div>';
   }
@@ -349,89 +339,118 @@
  */
 function uc_product_minmax_nodeapi(&$node, $op, $a3 = null, $a4 = null) {
   if (variable_get('uc_product_minmax_position', 0) == 0) {
-  switch($op) {
-
-    case 'load':
-      $result = db_query("SELECT * FROM {uc_product_minmax} WHERE nid = %d", $node->nid);
-      if ($row = db_fetch_object($result)) {
-        return array('product_min' => $row->product_min, 'pmin_multiple' => $row->pmin_multiple, 'product_max' => $row->product_max, 'display_min' => $row->display_min, 'display_multiple' => $row->display_multiple, 'display_max' => $row->display_max, 'display_weight' => $row->display_weight); 
-      }
-      break;
-
-    case 'view':
-     if ($node->display_min || $node->display_max || $node->display_multiple) {
-      if ($node->product_min > 1 || $node->display_multiple >1 || $node->product_max >= 1) {
-        drupal_add_css(drupal_get_path('module', 'uc_product_minmax') .'/uc_product_minmax.css');
-
-        $node->content['product_minmax'] = array(
-          '#value' => theme('uc_product_minmax', $node->product_min, $node->pmin_multiple, $node->product_max, $node->display_min, $node->display_multiple, $node->display_max, $minmax->display_weight),
-          '#weight' => !empty($node->display_weight) ? $node->display_weight : variable_get('uc_product_minmax_weight', -9),
-        );
-      }
-     }
-      break;
-  }
+    switch($op) {
+      case 'load':
+        return (array) uc_product_minmax_feature_load($node->nid);
+
+      case 'view':
+        if ($node->display_min || $node->display_max || $node->display_multiple) {
+          if ($node->product_min > 1 || $node->display_multiple > 1 || $node->product_max >= 1) {
+            drupal_add_css(drupal_get_path('module', 'uc_product_minmax') .'/uc_product_minmax.css');
+
+            $node->content['product_minmax'] = array(
+              '#value' => theme('uc_product_minmax', $node->product_min, $node->pmin_multiple, $node->product_max, $node->display_min, $node->display_multiple, $node->display_max, $minmax->display_weight),
+              '#weight' => !empty($node->display_weight) ? $node->display_weight : variable_get('uc_product_minmax_weight', -9),
+            );
+          }
+        }
+        break;
+    }
   }
 }
 
-/**
- * Alters the product feature add form to restrict multiple minmax features from being added to a single product.
- */
 function uc_product_minmax_form_alter(&$form, &$form_state, $form_id) {
-  if ($form_id == 'uc_product_feature_add_form') {
-    // If a minmax feature has already been added to this product...
-    if (db_result(db_query("SELECT COUNT(*) FROM {uc_product_features} WHERE nid = %d AND fid = '%s'", arg(1), 'minmax'))) {
-      // Remove minmax from the available list of features to add.
-      unset($form['feature']['#options']['minmax']);
-    }
-  }
-  
+  // Add text for "Add to cart" and "Buy it now" forms
   if (variable_get('uc_product_minmax_position', 0) == 1) {
-    if ((strpos($form_id, 'add_to_cart_form') > 0 || strpos($form_id, 'uc_catalog_buy_it_now_form_') === 0)) { 
-      $row = db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE nid = %d", $form['nid']['#value']));
-      if ($row->pmin_multiple > 1 && $row->display_multiple) {
-        $output = '<div class="uc_product_multiple">' . t('This product must be ordered in sets of !qty.', array('!qty' => $row->pmin_multiple)) . '</div>';
-      }
-      if ($row->product_min > 1 && $row->display_min) {
-        $output .= '<div class="uc_product_min">' . t('A minimum order of at least !qty is required.', array('!qty' => $row->product_min)) . '</div>';
-      }
-  
-      if ($row->product_max >= 1 && $row->display_max) {
-        $output .= '<div class="uc_product_max">' . t('A maximum order of !qty is allowed.', array('!qty' => $row->product_max)) . '</div>';
-      }
-      
+    if ((strpos($form_id, 'add_to_cart_form') > 0 || strpos($form_id, 'uc_catalog_buy_it_now_form_') === 0)) {
+      $minmax = uc_product_minmax_feature_load($form['nid']['#value']);
+
+      if ($minmax->pmin_multiple > 1 && $minmax->display_multiple) {
+        $output = '<div class="uc_product_multiple">' . t('This product must be ordered in sets of !qty.', array('!qty' => $minmax->pmin_multiple)) . '</div>';
+      }
+      if ($minmax->product_min > 1 && $minmax->display_min) {
+        $output .= '<div class="uc_product_min">' . t('A minimum order of at least !qty is required.', array('!qty' => $minmax->product_min)) . '</div>';
+      }
+      if ($minmax->product_max >= 1 && $minmax->display_max) {
+        $output .= '<div class="uc_product_max">' . t('A maximum order of !qty is allowed.', array('!qty' => $minmax->product_max)) . '</div>';
+      }
+
       $form['qty']['#description'] = $output;
     }
   }
 }
 
-/*******************************************************************************
- * Callback Functions, Forms, and Tables
- ******************************************************************************/
+/**
+ * Restrict multiple minmax features from being added to a single product
+ */
+function uc_product_minmax_form_uc_product_feature_add_form_alter(&$form, &$form_state) {
+  if (uc_product_minmax_feature_load(arg(1))) {
+    unset($form['feature']['#options']['minmax']);
+  }
+}
+
+/**
+ * Prevent illegal modifications of quantities in cart
+ */
+function uc_product_minmax_form_uc_cart_view_form_alter(&$form, &$form_state) {
+  foreach(element_children($form['items']) as $i) {
+    if(!$form['items'][$i]['nid']) continue;
+
+    $nid = $form['items'][$i]['nid']['#value'];
+    $minmax = uc_product_minmax_feature_load($nid);
+
+    if(!$minmax) continue;
+
+    $form['items'][$i]['#element_validate'][] = 'uc_product_minmax_cart_validate';
+  }
+}
+
+function uc_product_minmax_cart_validate($element, &$form_state) {
+  $nid = $element['nid']['#value'];
+  $qty = $element['qty']['#value'];
+  $minmax = uc_product_minmax_feature_load($nid);
+
+  if($minmax->multiple && $qty % $minmax->multiple) {
+    form_error($element['qty'], t('!item must be ordered in multiples of !qty.',
+      array('!item' => $element['title']['#value'], '!qty' => $minmax->multiple)));
+  }
+  if($minmax->product_min && $qty < $minmax->product_min) {
+    form_error($element['qty'], t('You must order !min or more of !item.', array('!item' => $element['title']['#value'], '!min' => $minmax->product_min)));
+  }
+  if($minmax->product_max && $qty > $minmax->product_max) {
+    form_error($element['qty'], t('You cannot order more than !max of !item.', array('!item' => $element['title']['#value'], '!max' => $minmax->product_max)));
+  }
+}
+
+/**
+ * Load minmax product feature for the given node
+ */
+function uc_product_minmax_feature_load($nid) {
+  return db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE nid = %d", $nid));
+}
+
 /**
  * Saves the min & max values.
  *
- * @param $values
+ * @param $minmax
  *   A min and max value object.
  */
 function uc_product_minmax_values_save($minmax) {
   // Allow other modules to change the saved data.
   drupal_alter('product_minmax_values_save', $minmax);
-  
+
   db_query("DELETE FROM {uc_product_minmax} WHERE pfid = %d", $minmax->pfid);
   drupal_write_record('uc_product_minmax', $minmax);
 }
 
-
 /**
  * Loads min and max value based on pfid.
  *
  * @param $pfid
- *   The value ID to load.
+ *   The product feature ID to load.
  * @return
- *   The min & max object.
+ *   The min and max object.
  */
 function uc_product_minmax_values_load($pfid) {
-  $minmax = db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE pfid = %d", $pfid));
-return $minmax;
+  return db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE pfid = %d", $pfid));
 }

