Index: uc_discounts.module
===================================================================
--- uc_discounts.module	(revision 511)
+++ uc_discounts.module	(revision 514)
@@ -384,6 +384,7 @@
   $action_info = _uc_discounts_get_actions();
 
   foreach ($discount_list as $discount) {
+
     // skip discounts which may not be applied with other discounts
     if ($discount->is_exclusive && !empty($apply_discounts)) {
       continue;
@@ -391,6 +392,7 @@
     // load conditions for the discount
     $condition_list = uc_discounts_get_discount_conditions($discount->id);
     $condition_groups = array();
+
     foreach ($condition_list as $condition) {
 
       // skip if this condition group has already failed
@@ -406,6 +408,7 @@
     }
 
     // did any condition groups match
+    $discount_amount = 0;
     if (array_search(TRUE, $condition_groups) !== FALSE) {
       $action_list = uc_discounts_get_discount_actions($discount->id);
       foreach ($action_list as $action) {
@@ -413,15 +416,16 @@
           continue;
         }
         $apply_callback = $action_info[$action->property]['apply_callback'];
-        $discount_amount = $apply_callback($op, $action, $total_price, $cart_copy);
-        if ($discount_amount > 0) {
-          $apply_discounts[$discount->id] = array(
-            'description' => check_plain($discount->description),
-            'amount' => $discount_amount,
-          );
-          $total_price -= $discount_amount;
-        }
+        $apply_amount = $apply_callback($op, $action, $total_price, $cart_copy);
+        $discount_amount += $apply_amount;
       }
+      if ($discount_amount > 0) {
+	$apply_discounts[$discount->id] = array(
+	  'description' => check_plain($discount->description),
+	  'amount' => $discount_amount,
+	);
+	$total_price -= $discount_amount;
+      }
     }
   }
 
@@ -827,6 +831,7 @@
     t('Op'),
     t('Item'),
     t('Value'),
+    t('Amount'),
     array('data' => t('Actions'), 'colspan' => 2),
   );
 
@@ -869,6 +874,7 @@
       $condition->op,
       $item,
       $value,
+      $condition->amount,
       l(t('edit'), $base_url.'/'.$condition->id),
       l(t('delete'), $base_url.'/'.$condition->id.'/delete'),
     );
@@ -985,6 +991,14 @@
       );
     }
 
+    $amount_field = array(
+      '#type' => 'textfield',
+      '#title' => t('Dollar Amount'),
+      '#description' => t('If set, condition will match only products whose sell price matches this amount.'),
+      '#maxlength' => 12,
+      '#size' => 6,
+    );
+
     // item field is not required
     if (isset($condition_info[$condition_property]['item_field_callback'])) {
       $item_field_callback = $condition_info[$condition_property]['item_field_callback'];
@@ -1024,10 +1038,18 @@
       '#options' => _uc_discounts_get_comparisons($condition_info[$condition_property]['compare_type']),
       '#default_value' => $condition->op,
     );
-    $form['item'] = $item_field;
-    $form['item']['#default_value'] = $condition->item_id;
+
+    if (isset($condition->item)) {
+      $form['item'] = $item_field;
+      $form['item']['#default_value'] = $condition->item;
+    } else {
+      $form['item'] = $item_field;
+      $form['item']['#default_value'] = $condition->item_id;
+    }
     $form['value'] = $value_field;
     $form['value']['#default_value'] = $condition->value;
+    $form['amount'] = $amount_field;
+    $form['amount']['#default_value'] = $condition->amount;
     $form['submit'] = array(
       '#type' => 'submit',
       '#value' => t('Submit'),
@@ -1054,6 +1076,10 @@
     form_set_error('comparison', t('@property may not have a comparison operator of @op', array('@property' => $property, '@op' => $op)));
   }
 
+  if (!is_numeric($form_values['amount'])) {
+    form_set_error('value', t('Amount must be a number'));
+  }
+
   // check value based on compare_type
   switch ($condition_info[$property]['compare_type']) {
     case 'integer':
@@ -1086,17 +1112,26 @@
     return;
   }
 
+  if (is_array($form_values['item'])) {
+    // encode the array into a serialized string.
+    $ids = array();
+    foreach ($form_values['item'] as $id => $value) {
+      if ($value) { $ids[] = $id; }
+    }
+    $form_values['item'] = serialize($ids);
+  }
+
   if ($form_values['condition_id'] == 0) {
     $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', '%s', '%s', %d, %d)";
+      (discount_id, condition_group, property, op, item_id, value, amount, weight, id)
+      VALUES (%d, %d, '%s', '%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='%s', value='%s', weight=%d WHERE id=%d";
+      item_id='%s', value='%s', amount='%s', weight=%d WHERE id=%d";
   }
 
   db_query($sql,
@@ -1106,6 +1141,7 @@
     $form_values['comparison'],
     $form_values['item'],
     $form_values['value'],
+    $form_values['amount'],
     $form_values['weight'],
     $id
   );
@@ -1297,7 +1333,7 @@
     if (isset($action_info[$action_property]['item_field_callback'])) {
       $item_field_callback = $action_info[$action_property]['item_field_callback'];
       $item_field = $item_field_callback();
-      $item_field['#default_value'] = $action->item_id;
+      #$item_field['#default_value'] = $action->item_id;
     }
     else {
       $item_field = array(
@@ -1337,7 +1373,13 @@
       '#title' => t('Weight'),
       '#default_value' => $action->weight,
     );
-    $form['item_id'] = $item_field;
+    if (isset($action->item)) {
+      $form['item'] = $item_field;
+      $form['item']['#default_value'] = $action->item;
+    } else {
+      $form['item'] = $item_field;
+      $form['item']['#default_value'] = $action->item_id;
+    }
     $form['qty'] = $qty_field;
     $form['amount'] = array(
       '#type' => 'textfield',
@@ -1365,6 +1407,15 @@
     return;
   }
 
+  if (is_array($form_values['item'])) {
+    // encode the array into a serialized string.
+    $ids = array();
+    foreach ($form_values['item'] as $id => $value) {
+      if ($value) { $ids[] = $id; }
+    }
+    $form_values['item'] = serialize($ids);
+  }
+
   if ($form_values['action_id'] == 0) {
     $id = db_next_id('{uc_discounts_actions}_id');
     $sql = "INSERT INTO {uc_discounts_actions}
@@ -1381,7 +1432,7 @@
   db_query($sql,
     $form_values['discount_id'],
     $form_values['property'],
-    $form_values['item_id'],
+    $form_values['item'],
     $form_values['qty'],
     $form_values['amount'],
     $form_values['weight'],
@@ -1463,6 +1514,7 @@
     $condition->op = '';
     $condition->item_id = 0;
     $condition->value = '';
+    $condition->amount = '';
     $condition->weight = 0;
   }
   else {
@@ -1471,6 +1523,9 @@
     if (!$condition) {
       drupal_goto('admin/store/discounts');
     }
+    if (substr($condition->item_id,0,2) == 'a:') {
+      $condition->item = unserialize($condition->item_id);
+    }
   }
 
   return $condition;
@@ -1498,6 +1553,9 @@
     if (!$action) {
       drupal_goto('admin/store/discounts');
     }
+    if (substr($action->item_id,0,2) == 'a:') {
+      $action->item = unserialize($action->item_id);
+    }
   }
 
   return $action;
@@ -1538,12 +1596,12 @@
  *   array of conditions
  */
 function uc_discounts_get_discount_conditions($discount_id) {
-  $sql = "SELECT * FROM {uc_discounts_conditions} WHERE discount_id=%d ";
+  $sql = "SELECT id FROM {uc_discounts_conditions} WHERE discount_id=%d ";
   $sql .= "ORDER BY condition_group, weight";
   $result = db_query($sql, $discount_id);
   $conditions = array();
   while ($row = db_fetch_object($result)) {
-    $conditions[$row->id] = $row;
+    $conditions[$row->id] = uc_discounts_load_condition($row->id);
   }
   return $conditions;
 }
@@ -1556,12 +1614,12 @@
  *   array of actions
  */
 function uc_discounts_get_discount_actions($discount_id) {
-  $sql = "SELECT * FROM {uc_discounts_actions} WHERE discount_id=%d ";
+  $sql = "SELECT id FROM {uc_discounts_actions} WHERE discount_id=%d ";
   $sql .= "ORDER BY weight";
   $result = db_query($sql, $discount_id);
   $actions = array();
   while ($row = db_fetch_object($result)) {
-    $actions[$row->id] = $row;
+    $actions[$row->id] = uc_discounts_load_action($row->id);
   }
   return $actions;
 }
@@ -1703,6 +1761,7 @@
     case 'numeric':
     case 'money':
     case 'date':
+    case 'multi':
       $valid_compare_types = array(
         '<' => '<',
         '<=' => '<=',
Index: uc_discounts.install
===================================================================
--- uc_discounts.install	(revision 511)
+++ uc_discounts.install	(revision 514)
@@ -26,7 +26,7 @@
         `condition_group` smallint NOT NULL default '1',
         `property` varchar(255) NOT NULL,
         `op` char(2) NOT NULL,
-        `item_id` varchar(32),
+        `item_id` varchar(255),
         `value` text NOT NULL,
         `weight` int NOT NULL,
 	`amount` varchar(8) NOT NULL default '',
@@ -37,7 +37,7 @@
         `id` int NOT NULL,
         `discount_id` int NOT NULL,
         `property` varchar(255) NOT NULL,
-        `item_id` varchar(32),
+        `item_id` varchar(255),
         `qty` smallint NOT NULL default '1',
         `amount` varchar(8) NOT NULL,
         `weight` int NOT NULL,
@@ -66,3 +66,10 @@
   $items[] = update_sql("ALTER TABLE {uc_discounts_conditions} add amount varchar(8) NOT NULL default ''");
   return $items;
 }
+
+function uc_discounts_update_3() {
+  $items = array();
+  $items[] = update_sql("alter table uc_discounts_actions modify item_id varchar(255) DEFAULT NULL");
+  $items[] = update_sql("alter table uc_discounts_conditions modify item_id varchar(255) DEFAULT NULL");
+  return $items;
+}
Index: discounts/uc_discounts_multi_product.module
===================================================================
--- discounts/uc_discounts_multi_product.module	(revision 0)
+++ discounts/uc_discounts_multi_product.module	(revision 514)
@@ -0,0 +1,160 @@
+<?php
+
+/*******************************************************************************
+ * Hook Functions (Ubercart)
+ ******************************************************************************/
+
+function uc_discounts_multi_product_discounts_condition() {
+  $conditions[] = array(
+    'property' => 'product_multi',
+    'description' => t('Multi Product'),
+    'compare_type' => 'integer',
+    'check_callback' => 'uc_discounts_multi_product_check',
+    'product_class_callback' => 'uc_discounts_multi_product_class_name',
+    'item_name_callback' => 'uc_discounts_multi_product_item_name',
+    'item_field_callback' => 'uc_discounts_multi_product_item_field',
+    'value_field_callback' => 'uc_discounts_multi_product_value_field',
+  );
+
+  return $conditions;
+}
+
+function uc_discounts_multi_product_discounts_action() {
+  $actions[] = array(
+    'property' => 'product_multi_items',
+    'description' => t('Discount multiple products from order'),
+    'has_qty_field' => TRUE,
+    'item_field_callback' => 'uc_discounts_multi_product_item_field', // recycle
+    'product_class_callback' => 'uc_discounts_multi_product_class_name', // recycle
+    'apply_callback' => 'uc_discounts_multi_product_apply',
+  );
+  
+  return $actions;
+}
+ 	
+/*******************************************************************************
+ * Callback Functions (Ubercart)
+ ******************************************************************************/
+
+function uc_discounts_multi_product_check($condition, $total_price, $cart) { 
+
+  if (isset($condition->item)) {
+    $product_count = 0;
+    foreach ($cart as $product) {
+      if ( (in_array($product->type, $condition->item) || in_array($product->nid, $condition->item)) && (($condition->amount > 0)?($product->price == (float)$condition->amount):TRUE) ) {
+	$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; }
+
+}
+
+function uc_discounts_multi_product_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_multi_product_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;
+}
+
+function uc_discounts_multi_product_item_field() { 
+  $options = array();
+  $result = db_query("SELECT pcid,name FROM {uc_product_classes} ORDER BY pcid");
+  while ($row = db_fetch_object($result)) {
+    $options[$row->pcid] = check_plain($row->name);
+  }
+
+  $products = array();
+  $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)) {
+    $options[$row->nid] = check_plain($row->title);
+  }
+
+  $field = array(
+    '#type' => 'select',
+    '#multiple' => TRUE,
+    '#options' => $options,
+    '#title' => t('Multiple Product/Types'),
+    #'#size' => 'size="'. min(50, count($options)) .'"',
+  );
+
+  return $field;
+}
+
+function uc_discounts_multi_product_value_field() { 
+  $field = array(
+    '#type' => 'textfield',
+    '#title' => t('Quantity'),
+    '#maxlength' => 12,
+    '#size' => 6,
+    '#required' => TRUE,
+  ); 
+  return $field;
+}
+
+function uc_discounts_multi_product_apply($op, $action, $total_price, &$cart) { 
+
+  $action = uc_discounts_load_action($action->id);
+
+  $sql = "SELECT id FROM (uc_discounts_conditions) WHERE discount_id=%d ";
+  $sql .= "AND property='product_multi' ";
+  $sql .= "ORDER BY condition_group, weight";
+  $result = db_query($sql, $action->discount_id);
+  $condition_list = array();
+  while ($row = db_fetch_object($result)) {
+    $c = uc_discounts_load_condition($row->id);
+    foreach ($action->item as $ai) {
+      if ($c->amount && in_array($ai,$c->item)) {
+        $action->condition_amount = $c->amount;
+      }
+    }
+  }
+
+  $product_price = 0;
+  foreach ($cart as $index => $product) {
+    if ( (in_array($product->nid,$action->item) || in_array($product->type,$action->item)) && (($action->condition_amount > 0)?($product->price == (float)$action->condition_amount):TRUE) ) {
+      $product_count += $product->qty;
+      $product_total += ($product->qty * $product->price);
+      $product_found[$index] = $product->qty;
+    }
+  }
+
+  if (empty($product_count) || empty($product_found)) { return 0; }
+
+  if (substr($action->amount,0,1) == '$') {
+    $discount_amount = substr($action->amount, 1);
+  } else {
+    $discount_amount = $action->amount;
+  }
+  $discount = $discount_amount * $product_count;
+  if ($discount > $product_total) {
+    $discount = $product_total;
+  }
+
+  if ($discount > $total_price) {
+    $discount = $total_price;
+  }
+
+  foreach ($product_found as $cart_index => $product_count) {
+    $cart[$cart_index]->qty -= $product_count;
+  } 
+
+  return $discount;
+}
+
+?>
Index: discounts/uc_discounts_multi_product.info
===================================================================
--- discounts/uc_discounts_multi_product.info	(revision 0)
+++ discounts/uc_discounts_multi_product.info	(revision 514)
@@ -0,0 +1,5 @@
+; $Id;
+name = "Multi-Product"
+description = "Discounts based on multiple products/types"
+dependencies = "uc_discounts"
+package = "Ubercart - discounts"
Index: discounts/uc_discounts_product_class.module
===================================================================
--- discounts/uc_discounts_product_class.module	(revision 511)
+++ discounts/uc_discounts_product_class.module	(revision 514)
@@ -39,7 +39,7 @@
 function uc_discounts_product_class_check($condition, $total_price, $cart) {
   $product_count = 0;
   foreach ($cart as $product) {
-    if ($product->type == $condition->item_id) {
+    if ($product->type == $condition->item_id && (($condition->amount > 0)?($product->price == (float)$condition->amount):TRUE)) {
       $product_count += $product->qty;
     }
   }
@@ -47,7 +47,7 @@
   if ($product_count == 0) {
     return FALSE;
   }
-  elseif ($condition->op == '=' && $product_count >= $condition->value) {
+  elseif ($condition->op == '=' && $product_count == $condition->value) {
     return TRUE;
   }
   elseif ($condition->op == '!=' && $product_count != $conditions->value) {
@@ -131,6 +131,7 @@
 }
 
 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 ";
@@ -140,6 +141,9 @@
   $condition_list = array();
   while ($row = db_fetch_object($result)) {
     $condition_list[$row->id] = $row;
+    if ($row->amount) {
+      $action->condition_amount = $row->amount;
+    }
   }
 
   if (empty($condition_list)) {
@@ -149,7 +153,7 @@
   // 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) {
+    if ($product->type == $action->item_id && (($action->condition_amount > 0)?($product->price == (float)$action->condition_amount):TRUE)) {
       $product_count += $product->qty;
       $product_price = $product->price;
       $product_found[$index] = $product->qty;

