Index: uc_discounts.module
===================================================================
--- uc_discounts.module	(revision 449)
+++ uc_discounts.module	(revision 487)
@@ -371,6 +374,8 @@
   // get and store total price
   $total_price = 0;
   foreach ($cart_copy as $product) {
+    $n = node_load($product->nid);
+    $product->type = $n->type;
     $total_price += $product->price * $product->qty;
   }
 
@@ -382,6 +387,8 @@
   $action_info = _uc_discounts_get_actions();
 
   foreach ($discount_list as $discount) {
+#drupal_set_message("testing discount:(".$discount->id.") ".$discount->name);
+    $discount_amount = 0;
     // skip discounts which may not be applied with other discounts
     if ($discount->is_exclusive && !empty($apply_discounts)) {
       continue;
@@ -389,17 +396,40 @@
     // load conditions for the discount
     $condition_list = uc_discounts_get_discount_conditions($discount->id);
     $condition_groups = array();
+    $condition_counts = array();
     foreach ($condition_list as $condition) {
+
+#drupal_set_message("checking condition:(".$condition->id.") ".$condition->condition_group.": ".$condition_info[$condition->property]['check_callback']);
       // skip if this condition group has already failed
-      if (isset($condition_groups[$condition->condition_group]) && $condition_groups[$condition->condition_group] == FALSE) {
-        continue;
-      }
+#      if (isset($condition_groups[$condition->condition_group]) && $condition_groups[$condition->condition_group] == FALSE) {
+#        continue;
+#      }
 
       // check if condition matches
       if (isset($condition_info[$condition->property]['check_callback'])) {
         $check_callback = $condition_info[$condition->property]['check_callback'];
         $condition_groups[$condition->condition_group] = $check_callback($condition, $total_price, $cart_copy);
+
+#drupal_set_message("condition group status: ".$condition_groups[$condition->condition_group]);
       }
+
+      if (isset($condition_info[$condition->property]['count_callback'])) {
+	$count_callback = $condition_info[$condition->property]['count_callback'];
+	$condition_counts[$condition->condition_group] += $count_callback($condition, $cart_copy);
+      }
+
+      foreach ($condition_groups as $i => $check) {
+        $c = isset($condition_counts[$i])?$condition_counts[$i]:0;
+
+	if ($c == 0) { $condition_groups[$i] = FALSE; }
+	elseif ($condition->op == '=' && $c >= $condition->value) { $condition_groups[$i] =  TRUE; }
+	elseif ($condition->op == '!=' && $c != $condition->value) { $condition_groups[$i] =  TRUE; }
+	elseif ($condition->op == '>=' && $c >= $condition->value) { $condition_groups[$i] =  TRUE; }
+	elseif ($condition->op == '>' && $c > $condition->value) { $condition_groups[$i] =  TRUE; }
+	elseif ($condition->op == '<=' && $c <= $condition->value) { $condition_groups[$i] =  TRUE; }
+	elseif ($condition->op == '<' && $c < $condition->value) { $condition_groups[$i] =  TRUE; }
+	else { $condition_groups[$i] =  FALSE; }
+      }
     }
 
     // did any condition groups match
@@ -409,8 +439,10 @@
         if (!isset($action_info[$action->property]['apply_callback'])) {
           continue;
         }
+#drupal_set_message("DISCOUNTS: applying action(".$action->id.") ".$action_info[$action->property]['apply_callback']);
         $apply_callback = $action_info[$action->property]['apply_callback'];
-        $discount_amount = $apply_callback($op, $action, $total_price, $cart_copy);
+        $discount_amount += $apply_callback($op, $action, $total_price, $cart_copy);
+#drupal_set_message("DISCOUNTS: discount amount: $discount_amount");
         if ($discount_amount > 0) {
           $apply_discounts[$discount->id] = array(
             'description' => check_plain($discount->description),
@@ -842,6 +874,14 @@
       $item = '';
     }
 
+    // get product type
+    if (isset($condition_info[$condition->property]['product_class_callback'])) {
+      $product_class_callback = $condition_info[$condition->property]['product_class_callback'];
+      $class = $product_class_callback($condition->item_id);
+    } else {
+      $class = '';
+    }
+
     // format value
     if (isset($condition_info[$condition->property]['value_format_callback'])) {
       $value_format_callback = $condition_info[$condition->property]['value_format_callback'];
@@ -1047,12 +1087,12 @@
   switch ($condition_info[$property]['compare_type']) {
     case 'integer':
       // this will also catch negative integers, but that's okay here
-      if (!ctype_digit($form_values['values'])) {
+      if (!ctype_digit($form_values['value'])) {
         form_set_error('value', t('Value must be an integer'));
       }
       break;
     case 'numeric':
-      if (!is_numeric($form_values['values'])) {
+      if (!is_numeric($form_values['value'])) {
         form_set_error('value', t('Value must be a number'));
       }
       break;
@@ -1079,13 +1119,13 @@
     $id = db_next_id('{uc_discounts_conditions}_id');
     $sql = "INSERT INTO {uc_discounts_conditions}
       (discount_id, condition_group, property, op, item_id, value, weight, id)
-      VALUES (%d, %d, '%s', '%s', %d, '%s', %d, %d)";
+      VALUES (%d, %d, '%s', '%s', '%s', '%s', %d, %d)";
   }
   else {
     $id = $form_values['condition_id'];
     $sql = "UPDATE {uc_discounts_conditions} SET
       discount_id=%d, condition_group=%d, property='%s', op='%s',
-      item_id=%d, value='%s', weight=%d WHERE id=%d";
+      item_id='%s', value='%s', weight=%d WHERE id=%d";
   }
 
   db_query($sql,
@@ -1155,6 +1195,14 @@
       $item = $action->item_id;
     }
 
+    // get class name
+    if (isset($action_info[$action->property]['product_class_callback'])) {
+      $class_name_callback = $action_info[$action->property]['product_class_callback'];
+      $class = $class_name_callback($action->item_id);
+    } else {
+      $class = $action->item_id;
+    }
+
     // format amount
     if (isset($action_info[$action->property]['amount_callback'])) {
       $amount_callback = $action_info[$action->property]['amount_callback'];
@@ -1500,7 +1548,7 @@
   else {
     $now = time();
     $result = db_query(
-      "SELECT * FROM {uc_discounts} WHERE start_time <= %d AND end_time >= %d ORDER BY weight",
+      "SELECT * FROM {uc_discounts} WHERE start_time <= %d AND end_time >= %d AND is_active = 1 ORDER BY weight",
       $now, $now
     );
   }
Index: uc_discounts.install
===================================================================
--- uc_discounts.install	(revision 449)
+++ uc_discounts.install	(revision 487)
@@ -26,7 +26,7 @@
         `condition_group` smallint NOT NULL default '1',
         `property` varchar(255) NOT NULL,
         `op` char(2) NOT NULL,
-        `item_id` int,
+        `item_id` varchar(32),
         `value` text NOT NULL,
         `weight` int NOT NULL,
         PRIMARY KEY(`id`),
@@ -36,7 +36,7 @@
         `id` int NOT NULL,
         `discount_id` int NOT NULL,
         `property` varchar(255) NOT NULL,
-        `item_id` int,
+        `item_id` varchar(32),
         `qty` smallint NOT NULL default '1',
         `amount` varchar(8) NOT NULL,
         `weight` int NOT NULL,
@@ -53,3 +53,9 @@
   db_query("DROP TABLE IF EXISTS {uc_discounts_actions}");
 }
 
+function uc_discounts_update_1() {
+  $items = array();
+  $items[] = update_sql("ALTER TABLE {uc_discounts_conditions} modify item_id varchar(32) default NULL");
+  $items[] = update_sql("ALTER TABLE {uc_discounts_actions}  modify item_id varchar(32) default NULL");
+  return $items;
+}
Index: discounts/uc_discounts_product_class.info
===================================================================
--- discounts/uc_discounts_product_class.info	(revision 0)
+++ discounts/uc_discounts_product_class.info	(revision 487)
@@ -0,0 +1,6 @@
+; $Id$
+name = "Product Type"
+description = "Discounts on product classes"
+dependencies = "uc_discounts"
+package = "Ubercart - discounts"
+
Index: discounts/uc_discounts_product.module
===================================================================
--- discounts/uc_discounts_product.module	(revision 449)
+++ discounts/uc_discounts_product.module	(revision 487)
@@ -8,8 +8,9 @@
   $conditions[] = array(
     'property' => 'product',
     'description' => t('Product'),
-    'compare_type' => 'text',
+    'compare_type' => 'integer',
     'check_callback' => 'uc_discounts_product_check',
+    'count_callback' => 'uc_discounts_product_count',
     'item_name_callback' => 'uc_discounts_product_item_name',
     'item_field_callback' => 'uc_discounts_product_item_field',
     'value_field_callback' => 'uc_discounts_product_value_field',
@@ -38,24 +39,40 @@
 function uc_discounts_product_check($condition, $total_price, $cart) {
   $product_count = 0;
   foreach ($cart as $product) {
-    if ($product->nid = $condition->item_id) {
+#drupal_set_message(t("checking condition(%c) item_id(%i) against product(%n) %t",array('%c' => $condition->id,'%n' => $product->nid, '%t' => $product->title,'%i' => $condition->item_id)));
+    if ($product->nid == intval($condition->item_id)) {
       $product_count = $product->qty;
+#drupal_set_message(t("testing condition(!c) item(!i) value(!v) !o product(!n) qty(!q)",array('!c' => $condition->id,
+#											      '!i' => $condition->item_id,
+#											      '!v' => $condition->value,
+#											      '!o' => $condition->op,
+#											      '!n' => $product->nid,
+#											      '!q' => $product_count)));
+      break;
     }
-    break;
   }
 
+
   if ($product_count == 0) {
     return FALSE;
   }
-  elseif ($condition->op == '=' && $product_count >= $condition->qty) {
-    return TRUE;
+  elseif ($condition->op == '=' && $product_count >= $condition->value) { return TRUE; }
+  elseif ($condition->op == '!=' && $product_count != $condition->value) { return TRUE; }
+  elseif ($condition->op == '>=' && $product_count >= $condition->value) { return TRUE; }
+  elseif ($condition->op == '>' && $product_count > $condition->value) { return TRUE; }
+  elseif ($condition->op == '<=' && $product_count <= $condition->value) { return TRUE; }
+  elseif ($condition->op == '<' && $product_count < $condition->value) { return TRUE; }
+  else { return FALSE; }
+}
+
+function uc_discounts_product_count($condition, $cart) {
+  $product_count = 0;
+  foreach ($cart as $product) {
+    if ($product->nid == intval($condition->item_id)) {
+      $product_count = $product->qty;
+    }
   }
-  elseif ($condition->op == '!=' && $product_count == 0) {
-    return TRUE;
-  }
-  else {
-    return FALSE;
-  }
+  return $product_count;
 }
 
 /**
@@ -75,7 +92,7 @@
   // no function in uc_products to do this.  This may need refining later
   $products = array();
 
-  $result = db_query("SELECT nid, title FROM {node} WHERE type='product' ORDER BY title");
+  $result = db_query("SELECT n.nid,n.title FROM {uc_products} p LEFT JOIN {node} n ON n.nid=p.nid ORDER BY title");
   while ($row = db_fetch_object($result)) {
     $products[$row->nid] = check_plain($row->title);
   }
@@ -115,10 +132,17 @@
 function uc_discounts_product_apply($op, $action, $total_price, &$cart) {
   // get conditions to make sure products can't be used more than once for
   // a discount
+
   $sql = "SELECT * FROM {uc_discounts_conditions} WHERE discount_id=%d ";
-  $sql .= "AND property='product' AND item_id=%d ";
+  $sql .= "AND property='product' AND item_id='%s' ";
   $sql .= "ORDER BY condition_group, weight";
   $result = db_query($sql, $action->discount_id, $action->item_id);
+
+#ob_start(); print_r($action);
+#drupal_set_message(" hit uc_discounts_product_apply: ");
+#drupal_set_message(ob_get_contents()); ob_end_clean();
+#drupal_set_message(t("[$sql]",array('%d'=> $action->discount_id,'%s' => $action->item_id)));
+
   $condition_list = array();
   while ($row = db_fetch_object($result)) {
     $condition_list[$row->id] = $row;
@@ -131,44 +155,59 @@
   // make sure condition is satisfied and action is possible
   $condition_found = FALSE;
   $product_price = 0;
+#drupal_set_message("  stepping through cart items to see if condition is met and action is possible:");
   foreach ($cart as $index => $product) {
+#ob_start(); print_r($product);
+#drupal_set_message("cart product: ".ob_get_contents()); ob_end_clean();
     // has the condition already been satisified
     if (empty($condition_found)) {
+#drupal_set_message("   stepping through condition_list:"); 
       foreach ($condition_list as $condition) {
-        if ($product->nid == $condition->item_id) {
-          // product id matches condition item
+#ob_start(); print_r($condition);
+#drupal_set_message("condition: ".ob_get_contents()); ob_end_clean();
+        if ($product->nid == intval($condition->item_id)) {
+          // product id (or type) matches condition item
+#drupal_set_message("   condition ".$condition->id."(".$condition->item_id.") matched ".$product->nid." (".$product->title.")");
           $required_qty = $condition->value;
-          if ($condition->item_id == $action->item_id) {
+          if ($condition->item_id == intval($action->item_id)) {
             // condition item and action item are the same
             $product_price = $product->price;
-            $required_qty += $action->qty;
+#            $product_found[$index] = $product->qty;
+#	    $product_count += $product->qty;
           }
-          if ($product->qty >= $required_qty) {
-            // save to apply discoounts later
-            $product_found[$index] = $required_qty;
-            $condition_found = TRUE;
-            break;
-          }
+
+          #if ($product->qty >= $required_qty) {
+            // save to apply discounts later
+          #  $condition_found = TRUE;
+          #  break;
+          #}
         }
       }
-    }
+    } // foreach $condition
+
     if ($product_price && $condition_found) {
       // condition and action have been found
+#drupal_set_message("  condition and action are satisfied.. applying discount:");
       break;
     }
     if ($product->nid == $action->item_id) {
-      if ($product->qty >= $action->qty) {
-        $product_found[$index] = $action->qty;
+#drupal_set_message("product nid matches ACTION id");
+#ob_start(); print_r($product);
+#drupal_set_message(ob_get_contents()); ob_end_clean();
+      #if ($product->qty >= $action->qty) {
+        $product_found[$index] = $product->qty;
+	$product_count += $product->qty;
         $product_price = $product->price;
         continue;
-      }
+      #}
     }
-  }
+  } // foreach $product
 
-  if (empty($condition_found) || empty($product_price)) {
+  if (empty($product_price)) {
     return 0;
   }
 
+#drupal_set_message("  calculating discount amount..");
   // calculate discount amount
   if (substr($action->amount, -1) == '%') {
     $discount_percent = substr($action->amount, 0, -1) / 100;
@@ -190,9 +229,9 @@
       // do not allow discounting greater than the product price
       $discount_amount = $product_price;
     }
-    $discount = $discount_amount * $action->qty;
+    $discount = $discount_amount * $product_count;
+#drupal_set_message("discount_amount: $discount_amount * product_count: ".$product_count);
   }
-
   // no refunds
   if ($discount > $total_price) {
     $discount = $total_price;
@@ -204,4 +243,4 @@
   }
 
   return $discount;
-}
\ No newline at end of file
+}
Index: discounts/uc_discounts_product_class.module
===================================================================
--- discounts/uc_discounts_product_class.module	(revision 0)
+++ discounts/uc_discounts_product_class.module	(revision 487)
@@ -0,0 +1,198 @@
+<?php
+
+/*******************************************************************************
+ * Hook Functions (Ubercart)
+ ******************************************************************************/
+
+function uc_discounts_product_class_discounts_condition() {
+  $conditions[] = array(
+    'property' => 'product_class',
+    'description' => t('Product Type'),
+    'compare_type' => 'integer',
+    'check_callback' => 'uc_discounts_product_class_check',
+    'product_class_callback' => 'uc_discounts_product_class_class_name',
+    'item_name_callback' => 'uc_discounts_product_class_item_name',
+    'item_field_callback' => 'uc_discounts_product_class_item_field',
+    'value_field_callback' => 'uc_discounts_product_class_value_field',
+  );
+
+  return $conditions;
+}
+
+function uc_discounts_product_class_discounts_action() {
+  $actions[] = array(
+    'property' => 'product_class_items',
+    'description' => t('Discount all products of a type from order'),
+    'has_qty_field' => TRUE,
+    'item_field_callback' => 'uc_discounts_product_class_item_field', //recycle
+    'product_class_callback' => 'uc_discounts_product_class_class_name', //recycle
+    'apply_callback' => 'uc_discounts_product_class_apply',
+  );
+
+  return $actions;
+}
+
+/*******************************************************************************
+ * Callback Functions, Forms, and Tables
+ ******************************************************************************/
+
+function uc_discounts_product_class_check($condition, $total_price, $cart) {
+  $product_count = 0;
+  foreach ($cart as $product) {
+    if ($product->type == $condition->item_id) {
+      $product_count += $product->qty;
+    }
+  }
+
+  if ($product_count == 0) {
+    return FALSE;
+  }
+  elseif ($condition->op == '=' && $product_count >= $condition->value) {
+    return TRUE;
+  }
+  elseif ($condition->op == '!=' && $product_count != $conditions->value) {
+    return TRUE;
+  }
+  elseif ($condition->op == '>=' && $product_count >= $condition->value) {
+    return TRUE;
+  }
+  elseif ($condition->op == '>' && $product_count > $condition->value) {
+    return TRUE;
+  }
+  elseif ($condition->op == '<=' && $product_count <= $condition->value) {
+    return TRUE;
+  }
+  elseif ($condition->op == '<' && $product_count < $condition->value) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Given a product id (nid), return the product name
+ */
+function uc_discounts_product_class_class_name($product_id) {
+  $result = db_query('SELECT type FROM {node} WHERE nid=%d', $product_id);
+  $product_name = check_plain(db_result($result));
+  return $product_name;
+}
+
+function uc_discounts_product_class_item_name($class_id) {
+  $result = db_query("SELECT name FROM {uc_product_classes} WHERE pcid='%s'", $class_id);
+  $class_name = check_plain(db_result($result));
+  return $class_name;
+}
+
+/**
+ * Generate the condition item field
+ */
+function uc_discounts_product_class_item_field() {
+  // load list of products from the database
+  // no function in uc_products to do this.  This may need refining later
+  $classes = array();
+
+  $result = db_query("SELECT pcid,name FROM {uc_product_classes} ORDER BY pcid");
+  while ($row = db_fetch_object($result)) {
+    $classes[$row->pcid] = check_plain($row->name);
+  }
+
+  if (empty($classes)) {
+    $field = array(
+      '#type' => 'item',
+      '#title' => t('Product Type'),
+      '#description' => t('No product classes available'),
+    );
+  }
+  else {
+    $field = array(
+      '#type' => 'select',
+      '#title' => t('Product Types'),
+      '#options' => $classes,
+    );
+  }
+
+  return $field;
+}
+
+/**
+ * Generate the condition value field
+ */
+function uc_discounts_product_class_value_field() {
+  $field = array(
+    '#type' => 'textfield',
+    '#title' => t('Quantity'),
+    '#maxlength' => 12,
+    '#size' => 6,
+    '#required' => TRUE,
+  );
+  return $field;
+}
+
+function uc_discounts_product_class_apply($op, $action, $total_price, &$cart) {
+  // get conditions to make sure products can't be used more than once for
+  // a discount
+  $sql = "SELECT * FROM {uc_discounts_conditions} WHERE discount_id=%d ";
+  $sql .= "AND property='product_class' AND item_id='%s' ";
+  $sql .= "ORDER BY condition_group, weight";
+  $result = db_query($sql, $action->discount_id, $action->item_id);
+  $condition_list = array();
+  while ($row = db_fetch_object($result)) {
+    $condition_list[$row->id] = $row;
+  }
+
+  if (empty($condition_list)) {
+    return 0;
+  }
+
+  // make sure condition is satisfied and action is possible
+  $product_price = 0;
+  foreach ($cart as $index => $product) {
+    if ($product->nid == $action->item_id || $product->type == $action->item_id) {
+      $product_count += $product->qty;
+      $product_price = $product->price;
+      $product_found[$index] = $product->qty;
+    }
+  } // foreach product
+
+  if (empty($product_count) || empty($product_price)) {
+    return 0;
+  }
+
+  // calculate discount amount
+  if (substr($action->amount, -1) == '%') {
+    $discount_percent = substr($action->amount, 0, -1) / 100;
+    if ($discount_percent > 1) {
+      // invalid percentage
+      drupal_set_message(t('Cannot apply product discount greater than 100%', 'error'));
+      $discount_percent = 0;
+    }
+    $discount = $product_price * ($discount_percent * $product_count);
+  }
+  else {
+    if (substr($action->amount, 0, 1) == '$') {
+      $discount_amount = substr($action->amount, 1);
+    }
+    else {
+      $discount_amount = $action->amount;
+    }
+    if ($discount_amount > $product_price) {
+      // do not allow discounting greater than the product price
+      $discount_amount = $product_price;
+    }
+    $discount = $discount_amount * $product_count;
+  }
+
+  // no refunds
+  if ($discount > $total_price) {
+    $discount = $total_price;
+  }
+
+  // remove affected items from cart
+  foreach ($product_found as $cart_index => $product_count) {
+    $cart[$cart_index]->qty -= $product_count;
+  }
+
+  return $discount;
+}

