Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
When apply coupon in cart page and go to checkout page the coupon removed and the total back to the old total (without coupon).
Comments
Comment #1
Ahmad Abbad CreditAttribution: Ahmad Abbad commentedComment #2
torgosPizzaProbably a duplicate of #2328357: Discount amount goes away when checkout completed.
Comment #3
torgosPizzaIt is definitely Coupon's implementation of cart_order_refresh() that is the culprit. I added a debug_backtrace and it's clearly happening when this method gets called, but I'm trying to figure out how or why all of those conditions would be satisfied. This is the function (with my added debugging functions):
I looked at the function _commerce_coupon_free_shipping_single_discount() and it tends to return NULL, which is then evaluated with a negated condition. I'm not sure but perhaps there is a funkiness with PHP 5.5 that interprets "NOT NULL" as true? The other condition function returns an empty array, which is (I think) generally a Drupal best practice, or at least one that's easier to read than the current method.
@dpolant: Any thoughts? I'm confirming that it is these conditions are somehow met, one time out of ten (or sometimes fewer).
EDIT: I'm going to try this condition next, checking for FALSE specifically.
Comment #4
torgosPizzaIt turns out the actual condition that was returning what it shouldn't was this:
For some reason, the field $coupon_wrapper->commerce_discount_reference->raw() would return as empty. Looking at the "Discount reference" field on the Discount Coupon type's settings page, it looks like that field is set to allow multiple values. I'm not sure if this is something custom to mine or not, because I can no longer edit the field values.
In any case, for whatever reason the function is trying to load an empty array into entity_load_multiple (to load and return the discounts if any are found). When the empty value is passed into those conditions it renders as TRUE (coupon is invalid because it does not have any discounts associated with it).
As a temporary fix, I went into the coupon type's management page for its fields, edited the Discount reference, and re-saved it. So far I do not see any coupons being removed from orders but I will let the logs stream for a bit to know for sure.
EDIT: It also looks like that old coupons still get loaded and conditions executed, if you have disabled a Discount but not also disabled the associated Coupon. I'm not sure if this is related but seems like possibly another bug anyway.
Comment #5
torgosPizzaDigging more into our watchdog logs, it seems that this normally happens in two places:
1) during the call to "system/ajax" after the "Add coupon to order" button is pressed, or
2) loading the Review stage.
It also seems whenever there is a discount coupon that fails, two things are observed:
1) The discount_ids and condition arguments sent to commerce_coupon_discount_load_multiple() are both empty;
2) because array_intersect() on discount_reference->raw() and discount_ids returns an empty string (" ")
At this point I'm not sure if the root cause is actually Coupons, or if it's deeper integration for instance the Entityreference module or some other form of field caching-related problems. One issue I am looking at testing is #1969018: Field schema foreign keys is always hard-coded to 'node' despite target type not set to node entity type though I'm not sure of how responsible is Entityreference vs. the Entity API (which we use to extract values like the commerce_discount_reference->value() for doing array_intersect for finding a coupon's discounts) since I haven't really a great grasp of the nuts and bolts of those systems.
I'm trying the patch from that issue to see if it has any effect.
Comment #6
torgosPizzaPossibly related: #2362799: Clarify and strengthen the logic when checking an order for coupons
Comment #7
torgosPizzaI got a related error when I ran the latest Entityreference update (version 7003):
Notice: Undefined index: in commerce_discount_default_rules_configuration() (line 26 of commerce_discount/commerce_discount.rules_defaults.inc)
That code looks like this (line 26 is where it checks for getBundle()):
Digging in, the Rule that was auto-created for this broken discount was marked dirty, with the note "Unknown action .". So, somehow, the Discount Offer (which was a percentage off discount) had lost its relationship to the Discount.
Going deeper I dpm'd the CommerceDiscount object, and the target_id for the Discount Offer in field commerce_discount_offer is 756... but when I look in the {commerce_discount} table, there is no associated row for that discount ID. It's like the row was either deleted or changed, but I can't imagine why.
EDIT: There is an issue regarding this type of bug at #2299013: Undefined index: in commerce_discount_default_rules_configuration() when update or cron is run
One thing I discovered also, is that you can edit the dirty Rule itself at admin/config/workflow/rules - Delete the "Unknown Action" and then re-add the correct Discount Offer - and then it appears to work fine. But if you REVERT the Rule back to its default state, the default rules get rebuilt, and once again the relationship in the field is broken.
I will continue to dig but so far my money is on something wonky going on with the commerce_discount_offer field, and/or the field being "seen" in places it shouldn't (for instance, Gift Card Coupons) causing all kinds of havoc with the Order Refresh system (including the line items "out of sync" issue described in #2328357: Discount amount goes away when checkout completed).
Comment #8
torgosPizzaComment #9
torgosPizzaComment #10
Ahmad Abbad CreditAttribution: Ahmad Abbad commentedThanks torgosPizza ,
i have solved this issue by create new rule when the amount be zero go to checkout complete page and skip payment tap
Comment #11
torgosPizzaOur issue ended up being that the order was being refreshed by external services pinging the checkout URLs - for example if a user is using Chrome and they hit a checkout/ORDER-ID link, moments afterward a social sharing widget would ping that URL to see if it was valid/shareable. Due to our permissions settings, we had it setup so that Anon users could access checkout (for Checkout Redirect, where they are required to login) but Anon users could not redeem coupons.
I did more digging and found that even if Anonymous users CAN'T access checkout, because of the way Drupal's menu object autoloading classes (such as checkout/%commerce_order) works, the full order is loaded and refreshed before returning Access Denied. Thus, due to our combination of settings, the order was refreshed and the coupon was removed by the anonymous user.
Our solution there was to just allow Anony users to "redeem coupons". Since then we haven't seen this issue pop up at all, after several subsequent coupon promotions. So for me this issue is FIXED - just make sure Permissions are configured as you might expect.
Comment #13
torgosPizzaTagging for sprint. Reopening because this problem still exists and is reproducible.
I'm fairly certain now that the issue is a race condition of some type. Essentially during a cart_order_refresh, the Discounts implementation removes all discount price components from a line item, but the Coupons module inspects the price components on a line item to determine if a product discount has been applied. This creates a bit of circular logic during a race condition if the Coupons module hasn't had a chance to re-add its price components before the order is refreshed and the components are inspected. (Did everyone follow all that?)
The issue #2263315: Allow discount_coupon on orders without the discount has one solution, but to me it's a bit of a workaround and doesn't really address the root issue.
Comment #14
torgosPizzaConfirmed from the other issue that this appears to have been caused by #1268472: Recursion in price calculation causes cart to skip calculation rules but I still think the logic is a tad bit circular. (This may be why the OP was able to fix this issue but calling an additional commerce_cart_order_refresh() during the complete_order() hook.
I'm not sure we can always ensure that the line items will have discount price components during the Discount cart refresh, so we should either a) remove that check, since we're already checking the coupon for a discount reference, or b) find a better way to chain these events together so we know that one runs after the other in a specific sequence.
Comment #15
torgosPizzaOur problem is actually #2619448: Cart Refresh check for discount price components causes Coupon removal since checkout isn't really involved here, though I suspect the two are related.
Comment #16
joelpittetLet's assume this is still fixed;)
Comment #17
mishac CreditAttribution: mishac commented> Let's assume this is still fixed;)
It's definitely not fixed for me :(
Comment #18
joelpittetOh sorry to hear that @mishac. Because this is a tricky problem to solve and I'd rather not confuse two separate issues could you please write up the steps, modules, patches you are using to recreate this problem so we can solve your problem.
I would rather not muddy the waters as we have clear steps on the follow up regarding pricing rules and product pages and this issue may be a mix of unrelated info. If yours is on checkout please make a new issue.
I'll do my best to follow your steps and reproduce the problem.
Comment #19
torgosPizza@mishac: We'll definitely need some steps to try and reproduce the error.
Some fixes I have found in the past for various issues:
1. Check your permissions for coupons, and check your Apache logs for any requests that might be hitting the checkout page (for example web-crawling "social sharing" plugins such as AddThis). In some cases, if an anonymous request from one of those sites hits the checkout page, what happens in Commerce is that the entire order is loaded and refreshed before it checks permissions (which to me seems strange). During that load and refresh, permissions on Coupons are also checked; so if you have Anonymous users NOT allowed to "redeem any coupon" then the coupon will get stripped away.
2. If you've recently updated Coupons and/or Discounts modules, make sure any Discount rules that are enabled and customized have been reverted to their defaults. It's possible some architectural changes have caused the Discounts to essentially become broken.
IF neither one solves it for you, we'll need to know a) what versions of the modules you're using, b) any patches applied to those modules, c) the steps to reproduce the problem if you can. Without that information we'll have no way of attempting to debug this problem.
Comment #20
mishac CreditAttribution: mishac commentedI'm using commerce_discount 7.x-1.0-alpha7 and commerce_coupon 7.x-2.0-rc2+6-dev, and coupons with product disscounts disappear when I hit the review page of checkout.
For now I've applied the following patches, and set the coupons to apply even when the discount doesn't apply, which mostly fixes the symptom for now, but not the underlying issue.
> commerce_coupon-auto_unserialize_data-2280505-6.patch
> ommerce_coupon-apply_without_discount-2263315-25.patch
Comment #21
joelpittet@mishac yes please open a new issue with exactly what you said in #20 and link it here for the 'review page'. Those patches shouldn't be necessary to reproduce the bug but mention them nontheless.
Comment #22
arunkumarkHi All,
I am also facing the same problem on single page checkout. Am using Commerce Shipping and Commerce gift wrapper along with the latest version of Rules(7.x-2.10). Am tries above patch that won't helps me.
After some deep analysis, i will find that The discount is added initially to the order. But before
commerce_checkout_form_validate()
it will removes from the order object. This is because of discount is calculated fromcommerce_discount_commerce_cart_order_refresh()
function. So we need to update the order total from bothcommerce_checkout_form_validate()
andcommerce_checkout_form_submit()
by calling the functioncommerce_cart_order_refresh($order);
so it will update from latest object from database.[Am not sure am correct]Comment #23
4kant CreditAttribution: 4kant commentedI tried every patch that sounds like it was related to this issue but none of them worked for me (coupon 2.x and all related modules with the latest version).
Since this issue`s title meets the subject best I suggest to reopen it.
Comment #24
torgosPizza@4kant:
I would also check the issue at #2621526: Compatibility settings other than "all" causes Discount+Coupon to be removed which seems to have a lot of overlap with this issue. If you do not use compatibility settings then you can ignore it. Otherwise - please post some steps to reproduce the issue if you can.
However I don't believe this issue actually can be reopened, so you may want to start a new one.
Comment #25
4kant CreditAttribution: 4kant commentedIn my case (#23) I found that the module commerce checkout paths conflicts in some way with discount module - discounts get lost even without coupon installed.
As soon as I deactivate commerce checkout paths everything works as expected.
The issue about commerce checkout paths is here: https://www.drupal.org/node/2580951
Sorry and thanks for your support!