I think I either don't understand the workings of the uc_discount module, or I've found a bug. In uc_discount.module, the function uc_discount_calculate_discounts, we have the code to evaluate the order discounts:
//Calculate overall order discounts
// Pull the "calculate_discounts" trigger in such a way to get the results.
$predicates = ca_load_trigger_predicates('calculate_order_discounts');
foreach ($predicates as $predicate) {
if (ca_evaluate_conditions($predicate, $arguments)) {
$discounts = ca_perform_actions($predicate, $arguments);
foreach ((array) $discounts as $i => $discount) {
if ($predicate['#actions'][$i]['#name'] == 'uc_discount_action_get_order_discount' && $discount) {
// Allow successive discounts to inspect this discount by putting
// it in the order object.
$order->discounts[$id] = array(
'id' => $id,
'title' => check_plain($predicate['#actions'][$i]['#title']),
'amount' => $discount,
'weight' => variable_get('uc_li_discount_weight', 5) + $predicate['#actions'][$i]['#settings']['line_item_weight'] / 10,
);
$id++;
}
}
}
}
My problem is with this line:
if ($predicate['#actions'][$i]['#name'] == 'uc_discount_action_get_order_discount' && $discount) {
I want to add my own action/logic that is executed on an order to add an overall order discount, not on any specific line item or product. No matter what, however, it looks like the predicates and discounts are only being applied if the action is "uc_discount_action_get_order_discount". This means that if we're using a custom hook/action, or if we're using a php executed action, or really anything that is not the "Apply Discount", then it doesn't get picked up by the discount module. This is happening, even though in the Conditional Actions config, I made a predicate that is of type "calculate_order_discounts". This means that the check "$predicate['#actions'][$i]['#name'] == 'uc_discount_action_get_order_discount'" is unnecessarily limiting, and incredibly limits the usability of this type of predicate. In other words, the only type of product discount that can be applied is to the apply discount action.
I propose that we modify the above to the following:
//Calculate overall order discounts
// Pull the "calculate_discounts" trigger in such a way to get the results.
$predicates = ca_load_trigger_predicates('calculate_order_discounts');
foreach ($predicates as $predicate) {
if (ca_evaluate_conditions($predicate, $arguments)) {
$discounts = ca_perform_actions($predicate, $arguments);
foreach ((array) $discounts as $i => $discount) {
if ($discount) {
// Allow successive discounts to inspect this discount by putting
// it in the order object.
$order->discounts[$id] = array(
'id' => $id,
'title' => check_plain($predicate['#actions'][$i]['#title']),
'amount' => $discount,
'weight' => variable_get('uc_li_discount_weight', 5) + $predicate['#actions'][$i]['#settings']['line_item_weight'] / 10,
);
$id++;
}
}
}
}
Only one line changed. This reduces the if statement to only check for the discount. If so, it applies as appropriate. I believe that this is correct, and it implements the behavior as I understand that it should.
If this is correct, please let me know and I can supply a patch file.
If this is incorrect, please let me know, and let me know why it is incorrect.
| Comment | File | Size | Author |
|---|---|---|---|
| #5 | uc_discount-744320.patch | 1.41 KB | jantoine |
Comments
Comment #1
charlie-s commentedYou're a smart guy. Am I correct in assuming that this is why none of my discounts were working until I tried "Calculate product discounts on the order"?
Comment #2
supersport commentedMy guess is yes. Try the update I proposed and see if it fixes that for you.
Comment #3
charlie-s commentedThis works, just saved me. +1 for supersport.
Comment #4
ezra-g commentedCould you roll a patch for this?
Comment #5
jantoine commentedAttaching a patch that modifies two lines. It does exactly what is described in #1 and also applies the same fix to product specific discounts in case the same type of flexibility would like to be used with product specific discounts.
Cheers,
Antoine
Comment #6
jazzitup commentedShouldn't this patch be ported already?
Comment #7
joachim commentedPeople need to try the patch and report back on whether it fixes the bug and whether it affects anything else before a maintainer will commit it -- see http://drupal.org/patch/review.
Comment #8
justageek commentedI have a question concerning this patch, since this is a framework, how was it supposed to work? Did you intend to provide a mechanism so that developers could implement their own discount functions as mentioned by the person providing the patch?
Comment #9
joachim commentedDo you mean this part of the original post?
I've had to read that three times and scratch my head, but I think I get it now.
I didn't write this module, I just co-maintain it (and I confess I don't understand large parts of it), so I don't know what the answer to your question is. My guess would be that no, the intention with this module was not that custom actions would be written; rather that you'd just set up the conditional actions in the UI.
I *think* I get what the patch is trying to do. I also *think* I get what is going on in uc_discount_action_get_order_discount(). It looks to me -- correct me if I'm wrong -- that it's a bit of a hack so that discounts can be shown in certain circumstances. At least, it looks like that function is doing the work of pulling a CA trigger without actually pulling it. I'm not entirely sure why.
I'd really appreciate more explanations on what sort of situation this patch fixes (and if anyone can shed more light on this part of the module code that would be great!).
Comment #10
richygecko commentedI needed to create a custom action to discount items that have a particular attribute option only after a certain number of items with the attribute options where added to the order. For example T-shirts with custom printing... if you buy three t-shirts with custom printing attribute, then the 4th, 5th, 6th and so on have the custom printing attribute option discounted.
I could not get any of the standard actions to work for this use case(feel free to enlighten me if this is indeed possible), so i created a custom condition and action. This patched allowed my new action to be added to the total. Without it, it was not picking up the value returned in my callback function.