Hi!
We're using the 2.x branch with good success on the "standard" offer types, i.e. $ off, and % off... However, we are trying to offer free shipping based on a coupon code using the "Free Shipping" offer type, and it's not working. When the user tries to redeem the coupon they are provided a success message because the inline conditions worked, but the discount doesn't actually apply to the order.
Commerce Discount implements free shipping based on a rule that gets executed when shipping rates are collected (and in our case executes on a subsequent checkout step), and as a result the discount isn't valid until after shipping rates are collected. So when you add the coupon to the order you get a "success" message, but the coupon gets immediately removed because when commerce_coupon_commerce_cart_order_refresh gets called, it doesn't find the discount on the order and as a result it removes the coupon. On the shipping calculation screen the coupon isn't actually attached to the order, so the shipping rate alteration applied by commerce_discount doesn't work because the existence of the coupon code is a condition (as we want it to be), but it's not on the order because it was removed immediately after it was added.
My initial thought is just to disable the coupon cleanup that happens in commerce_coupon_commerce_cart_order_refresh, as that does fix the issue, i.e. the coupon adds to the order and the subsequent shipping calculation correctly offers a $0 shipping rate for the correct service as expected because the coupon exists on the order. But I'm trying to think of potential problems with this solution, as the cleanup was obviously implemented for a reason.
I also tried moving coupon redemption to a checkout step after the shipping method calculation, but since commerce_discount implements free shipping as an alteration to the actual generation of shipping rates (instead of as a line item that cancels out the cost of shipping), it doesn't work because the shipping rate has already been set.
So I'm not really sure if this is a "bug", but it's a bit of a "chicken-or-the-egg" scenario because free shipping doesn't work without the coupon, but the coupon doesn't work because the free shipping discount isn't added to the order yet. Given that the module acts like the coupon should apply and it never actually does, it at least seems like it could cause a lot of confusion for users, and it's also not possible to give free shipping with a coupon, which seems like a super useful ability.
Sorry, writing this after banging my head off this for a while, so this may not be entirely coherent... But any thoughts would be greatly appreciated :)
| Comment | File | Size | Author |
|---|---|---|---|
| #26 | interdiff-2215201-22-26.txt | 1.64 KB | michfuer |
| #26 | fix_cleanup_of_shipping_discounts-2215201-26.patch | 7.63 KB | michfuer |
| #22 | interdiff-2215201-21-22.txt | 3.47 KB | michfuer |
| #22 | fix_cleanup_of_shipping_discounts-2215201-22.patch | 7.87 KB | michfuer |
| #21 | fix_cleanup_of_shipping_discounts-2215201-21.patch | 8.79 KB | joshmiller |
Comments
Comment #1
dpolant commentedThe free shipping offer is indeed problematic because of the reasons you stated. Even within the context of Commerce Discount it doesn't function completely right - the conditions for it only fire when you hit the shipping page form because it uses the collect-rates event and does not do any integrity checks for itself on cart refresh.
I've implemented a partial fix: where Commerce Coupon will not remove free shipping coupons at order refresh. This should allow you to add coupons that enable free shipping.
Here's the hitch: if some one removes the coupon, it will not recalculate unless for some reason they go back to the shipping page. This could result in some one removing the discount on the review page and getting the free shipping without using the coupon. Perhaps a workaround is to take the "remove" button off the review page view ..
I'm going to pass off fixing the underlying issue with the free shipping offer to the discount issue queue. Coupon module is designed only to act as a "gate" for discounts when they check their conditions, and if an offer does not check its conditions regularly enough then there is not much we can do from here.
Committed to dev: http://drupalcode.org/project/commerce_coupon.git/commit/490f9c7
Comment #2
dpolant commentedComment #3
stockliasteroid commentedWonderful, thank you! I was thinking along the same lines, but hadn't had a chance to look at implementation... I'll give this a try this week and report back. Thanks again!
Comment #4
mrP commented@dpolant is there an existing issue with commerce_discount for the underlying problem?
Comment #5
stockliasteroid commentedSorry for the delay in response, we're running this version now and it seems to work fine. Free shipping is still an odd exception, but commerce_coupon now handles it in an "expected" fashion, so I'm marking this RTBC.
Comment #6
guypaddock commentedSorry, but this still needs work. This temporary solution works for the specific case of free shipping, but we're implementing another module that works with shipping discounts and it doesn't work there at all. Moreover, having to add exceptions for every kind of discount to this one area of the code isn't maintainable.
I'd suggest we add a hook here instead that gives modules a chance to control how the coupons are filtered, or gives them a chance to indicate whether or not the coupon still applies.
Comment #7
guypaddock commentedCan someone try this patch on for size?
This is against the latest dev rather than stacking other changes made for this issue into the patch.
Comment #8
guypaddock commentedUgh, digging deeper the real issue lies with
commerce_coupon_order_coupon_code_discounts(). That function can only return line item discounts, rather than any generic discount on the order. As a result, free shipping discounts and all other types of discounts that don't directly affect line items for the cart require special handling.Isn't there a way for the coupon module to store the coupons on the order instead of relying on line items?
Comment #9
guypaddock commentedPlease disregard my patch in #7 and try this instead.
This patch removes the special case logic for free shipping from both
commerce_coupon_commerce_cart_order_refresh()ofcommerce_coupon.moduleandrender()incommerce_coupon_handler_field_discount_value_display.incin favor of using the new hook I've introduced for coupon clean-up.In addition, this patch fixes
commerce_coupon_code_is_in_order()so that it actually works (I'm guessing this is an old hold-over from 1.x). This function is now used incommerce_coupon_order_coupon_code_discounts()to verify that the coupon actually exists on the order in question.Please test and let me know if this works.
Comment #10
sureshpotnuru commentedSorry, This patch not working in my side. Module enable and disable functioning works fine. No errors and warnings. But nothing happens what we expected functioning. Please let me know GuyPaddock. Thankq
Comment #11
guypaddock commentedWhen you say "nothing happens when we expected", can you elaborate? What workflow?
Comment #12
guypaddock commentedJust ran it through its paces and don't see a difference with the way free shipping is handled -- the patch doesn't appear to break that existing workflow.
Can you tell me what type of discount you're trying that's not working properly? Have you confirmed that the workflow works without the patch and fails with the patch?
Comment #13
sureshpotnuru commentedhi GuyPaddock,
After i am applying patch it works fine. no errors and warnings.It does not break the workflow also. My workflow is creating coupon for free shipping who entered coupon code they will have provided by shipping service free is applicable on order discount. Details shown in above image. Here i am using discount and coupon 2.x module. What i am expected means when user applied coupon code then he will get free shipping service only, other services will be disappeared in shipping service page. Is it possible with this patch. please let me know. Thankq.
Comment #14
guypaddock commentedYour use case is definitely unrelated to this patch; I just changed the issue title to help clarify this. This patch is only intent on fixing problems with the way that Commerce cleans-up coupons on the order when it doesn't think that that they apply any longer.
To do what you want, I see two options (you may have other options, but these are just the two I can think of right now):
Comment #15
sureshpotnuru commentedhi GuyPaddock,
Thankyou for detailed justification. problem is solved with changing rules. It doesn't require any code. Follow second option by adding condition to the each of the shipping method and its working fine.
Comment #16
sureshpotnuru commentedCould you pls give clearly information about this patch. Thankq
Comment #17
mjgruta commented@GuyPaddock
Patch needs re-roll on the latest dev so we can test.
My issue is #2593251: "Unable to redeem coupon." when I use "% off of shipping"
Comment #18
joshmillerAbout to re-roll and test.
Comment #19
joshmillerUpdated patch attached. This was more than a re-roll because it interacted with some functions that no longer are included in commerce_coupon.
Note that free shipping coupons have worked since Dan posted the two hard-coded free-shipping conditions in this module. So the best outcome of this patch is to support free shipping coupons in a way that other modules can implement a similar "wait and see" if the order discount gets applied.
To test:
drush dl commerce_shipping commerce_flat_rate commerce_discount commerce_coupon-2.xdrush en commerce_shipping_ui commerce_flat_rate commerce_coupon -yPlease test and update the status as you have a chance!
Comment #20
joshmillerComment #21
joshmillerThis patch also addresses percent_off_shipping and shipping_upgrade discount types. Thanks to #2593251: "Unable to redeem coupon." when I use "% off of shipping" for point out another kind of discount that fails. This patch makes all three kinds of shipping discounts work as coupons with one hook implementation.
Comment #22
michfuer commentedCoupons can reference multiple discounts. I would expect the coupon to be removed unless ALL of its discounts existed on the order. Currently that's not the case. Updated the patch to fix this. Also simplified commerce_coupon_cleanup_process_invoke().
The label for a free shipping discount was an empty string for me. It's because the discount isn't being detected in commerce_coupon_order_discount_ids(). Specifically this line
if (!empty($component['price']['data']['discount_name']))I'm not sure if this is a commerce_discount issue or commerce_coupon because in commerce_discount_free_shipping_service() it's setting
and that's what the component for my free shipping service looks like.
Also, I thought implementing the hook this patch creates to support all the shipping discount offers was incorrect because that should be the responsibility of commerce_shipping. Than I noticed that there's a lot of shipping support in both commerce_discount and commerce_coupon. Is there a legitimate reason it's done this way? Maybe there isn't a hook to define a new discount offer type?
Comment #23
torgospizzaThere is, hook_commerce_discount_offer_type_info(). We're using it for a special discount offer type.
Free shipping discounts were something Ryan was just working on recently. You may want to look at #2560773: Add support for "Free or reduced shipping" offers.
EDIT to add, sorry if this is stuff you already know about :) Just wanted to mention it since I remember seeing Ryan's issues and patches for Free Shipping so recently!
Comment #24
torgospizzaBTW we're experiencing a problem related to this issue, so I'm testing the latest patch.
Comment #25
torgospizzaSetting to needs work. Here are my findings:
- Getting an error "undefined variable: $result", probably because that var is returned outside of the condition
if ($coupon->type == 'discount_coupon')- Also pretty sure that in the function commerce_coupon_cleanup_process_invoke() we should specifically check
if (!$eligible === FALSE)rather thanif (!$eligible)because in the event that no modules return a value then $eligible may not be defined and this could throw more errors.So unfortunately it seems like this patch did not solve anything for us, (having coupons removed during Checkout), but I do think the change itself is needed.
Comment #26
michfuer commentedSo I cleaned up commerce_coupon_commerce_coupon_cleanup_process() which should take of your undefined variable: $result error.
In commerce_coupon_cleanup_process_invoke() we foreach() over module_invoke_all() which returns an empty array() if no modules implement the hook. In PHP it's safe to foreach over an empty array().
Updated patch with interdiff provided.
Comment #27
jmsomera commentedWhen using commerce_discount_date, validation is not working. When using commerce_coupon_date, validation is working.