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 @@ + '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;