See #13 / #15 for more detail.
Original report:
PayPal for payment is used in combination with payment commerce for a large drupal commerce webshop.
When the cancel link is used on the paypal website, the order will get the status finished and the client is redirected to the order completed confirmation page.
The client should be redirected to the review page of the current order.
The order has the status payment when the client is forwarded to PayPal.
When returning, the order gets the status finished.
I have done a lot of searching true the code but unfortunately didn't found the issue.
The finish method is called and after that a lot of things happen.
It looks like there is something going wrong in the commerce payment module (I have an almost similar issue with iDeal).
Comment | File | Size | Author |
---|---|---|---|
#31 | payment_commerce-back_button_failed-2118575-31-D7.patch | 1.25 KB | valentin schmid |
| |||
#30 | payment_commerce-back_button_failed-2118575_30.patch | 1.12 KB | getu-lar |
| |||
#29 | payment_commerce-back_button_failed-2118575_29.patch | 1.42 KB | dmsmidt |
Comments
Comment #1
XanoAre you using Payment for Drupal Commerce 7.x-1.4?
Comment #2
mvdve CreditAttribution: mvdve commentedIndeed, the payment for commerce 7.x-1.4 is used.
It looks like there is an extra check needed on the status of the payment item.
Totally off topic but an other example is with the iDeal module:
When the back button of the browser is used, when the customer is in the iDeal environment and they get back at the checkout page.
The order status is updated to finished after a refresh of the browser.
This shouldn't be possible as the payment status is still "pending".
Comment #3
XanoCan you please provide steps to reproduce the problem on a completely new and clean installation of Drupal with the latest dev versions of core and the required modules?
This does sound like #2118675: Do not require that payment methods influence the checkout process, though, which is a fundamental problem in Drupal Commerce.
Comment #4
mvdve CreditAttribution: mvdve commentedIt will be a lot of work to get a fully fresh commerce system up and running but I will try to make time for this.
Comment #5
mvdve CreditAttribution: mvdve commentedJust to be sure, where are talking about two scenarios/issues:
payment iDeal V3:
- When the payment cancel link in the ideal environment is used, the client is redirected back to the review order (with payment select) page. This works as it should be.
- When a previous link from the history is selected (back button) the client lands on the review order page, but ajax keeps loading endlessly. When refreshing the page twice (sometimes ones) the order is spontaneously finished.
payment PayPal:
- When the payment cancel link in the PayPal environment is selected, the client is redirected to the shop (always), and the order is instantly finished.
- The history link issue is the same as with iDeal.
I will do more research tomorrow.
Comment #6
XanoThe only AJAX when making iDEAL payments is from Commerce.
Note that this is probably about completed checkouts and no torders that are fully paid for. Your site config should accommodate for that.
Comment #7
mvdve CreditAttribution: mvdve commentedYour correct on the Ajax issue. That's a commerce thing and has nothing to do with this one.
Back on this issue: I did a lot of testing, with my current installation and a installation with all de dev modules.
Unfortunately the issue still exists on the installation with dev modules.
The where and how did got much clearer. The error occurs when:
1 - A order is created -> goto checkout pane
2 - The customer fills in there billing and shipping information -> goto shipping pane
3 - The customer selects a shipping service -> goto preview pane
4 - The customer selects the payment method -> forwarded to the external payment service (iDeal or PayPal. the same error occurs on both).
5 - When the review pane is loaded (http://www.sitename.com/checkout/[order-number]/review) by hitting the back button of the browser, or selecting the link from the history, the customer gets forwarded again tot the payment service.
The error
6 - When repeating step 5, the customer is not redirected to the payment service again, but to the checkout-complete page.
I did a cross-check with the commerce_paypal module. This module does not have this behaviour. It keeps forwarding the customer to the payment service.
Comment #8
mvdve CreditAttribution: mvdve commentedAdditional information the post #7:
On step 5, the customer is forwarded to the payment service. At the same time, the status of the order is set to processing and the checkout is completed (e-mail is send to the customer by the checkout complete event in rules).
1 - A order is created -> goto checkout pane. Order status: shopping cart
2 - The customer fills in there billing and shipping information -> goto shipping pane. Order status: Checkout: Shipping
3 - The customer selects a shipping service -> goto preview pane. Order status: Checkout: Review
4 - The customer selects the payment method -> forwarded to the external payment service (iDeal or PayPal. the same error occurs on both). Order status: Checkout: Payment
5 - When the review pane is loaded (http://www.sitename.com/checkout/[order-number]/review) by hitting the back button of the browser, or selecting the link from the history, the customer gets forwarded again tot the payment service.
Order status: Processing (no payment so the order is not set to complete).
6 - When repeating step 5, the customer is not redirected to the payment service again, but to the checkout-complete page.
Comment #9
mvdve CreditAttribution: mvdve commentedAnother update on this issue after some code searching:
When the customer is forwarded to the PayPal environment, the status of the payment is set to pending instead of new.
Now, when the review pane is loaded again, the payment_commerce_payment_status_change() function sets the order status to the next pane (line 98 of payment_commerce.module).
This is why the checkout gets completed but the customer is still in the external payment environment.
Comment #10
XanoThat's not what happens. If you look closely, line 98 explicitly prevents moving the checkout pane if the old status was PAYMENT_STATUS_NEW and the new status is PAYMENT_STATUS_PENDING.
Comment #11
mvdve CreditAttribution: mvdve commentedI'm sorry. I was not clear in my explanation.
When the customer is forwarded to the external payment service for the first time, the payment status is directly set to pending.
The status new is skipped.
This is a very big assumption but should is be like this?
- Customer is forwarded to external service -> payment status = new
- Customer completes payment -> payment status is pending or completed when fulfilled.
Comment #12
XanoSee
Payment::__construct()
. New means new. Pending means pending, and not completed.Comment #13
mvdve CreditAttribution: mvdve commentedAs discussed on IRC:
When the customer is forwarded to the external payment service for the first time, the payment status is set to pending.
When the review page is now reloaded the if statement on line 98 gets "pending" as previous and current status.
Now the payment_commerce_redirect_pane() gets executed and the order is set to complete.
Not sure how to catch this one.
For example, when a customers chooses to pay with a delayed payment (with PayPal) the previous and current statuses are also "pending" when completing the payment. This would result in an error when the customer is redirected back to the shop.
Comment #14
XanoThis looks like it's caused by Commerce's limited ability to deal with checkout status changes. #2118675: Do not require that payment methods influence the checkout process tries to address this. #1982544: Call commerce_payment_redirect_pane_next/previous_page() in hook_payment_status_change() is when we decided to let Payment for Drupal Commerce do what it does now.
Comment #15
roderik(Note: I'm on purpose not setting 'needs review', because this is not a general patch. This is only meant
* as a detailed summary of what I encountered in the code flow
* to give people who encounter this issue and are OK with coding / applying patches, a hint, where to look.)
Thanks for this discussion; it gives some perspective on why this bug is still here. I traced the code last august to 'when/where this happens', but still had no idea 'how to fix it'.
'when/where it happens':
(mvde/#13 also said this, but in more detail):
When a user presses the browser "back" button, it goes back to
checkout/N/PREVIOUS_PANE
. commerce_checkout_router() says "Oh no you don't! Your cart is locked!" and drupal_goto()'s back tocheckout/N/payment
. What happens now, depends on my browser(!):* e.g. on my Chrome/MacOS, the browser remembers that
checkout/N/payment
actually redirected to[exernal-payment-page]
last time, so it sends you there directly. So nothing bad happens (except if you press your browser "back" button enough to get out of the checkout pages... you're back on the website, with an empty cart. Does not have anything to do with this issue.)* e.g. on my Safari/MacOS and on someone else's Chrome/Windows, a HTTP request goes out to
checkout/N/payment
. This will redirect back to[exernal-payment-page]
, but before doing that, it changes the order status**! (Meaning that the next time the user will press back/visit a checkout page, they'll be redirected to the "order completed" page.)** hook_payment_status_change() is called when the payment status changes from PAYMENT_STATUS_PENDING to PAYMENT_STATUS_PENDING. Even though there is no status change, payment_commerce_redirect_pane() is still called, which changes the order status to 'completed' and calls
rules_invoke_all('commerce_checkout_complete')
.'how to fix it':
I don't know a general solution because, as I get from this discussion + talking IRL to Xano,
- a non-change from PAYMENT_STATUS_PENDING to PAYMENT_STATUS_PENDING should still invoke hook_payment_status_change().
- Payment cannot know when (not) to advance and this should be handled by Commerce. (I don't get 100% of the reasoning but I take this as a given :) )
@#12:
Just a remark: as an outsider, this sounds to me like there should be different statuses for this, since 'set to "pending" initially by Payment module' and 'confirmed by PayPal as being recorded in their system, but still "pending"' are two slightly different things. Am I wrong?
'how to hack it':
OK, so we can't make a general fix, but your website needs a fix now because this is a major issue:
I 'fixed' it by preventing a 'change from pending to pending' from calling
payment_commerce_redirect_pane()
, as in the following patch. The issue with this is: it hardcodes the machine name for the payment method (in my case 'ideal') so it's not general code.Comment #16
roderikAfter all that typing I forgot to attach the patch...
Comment #17
XanoRoderik and discussed this problem in more detail at DrupalCon Amsterdam and we believe the problem here may be caused by the fact that Payment for Drupal Commerce should only move the checkout when the payment has been successfully completed. The attached patch shows this.
Comment #19
mvdve CreditAttribution: mvdve commentedCorrect me if i am wrong but what happens when the consumer cancels the payment in the external environment? The returned status will be cancelled, but the order payment status is set to payment. In this case a checkout redirect to the previous state is needed.
Comment #20
XanoI talked to @bojanz (one of the Drupal Commerce maintainers) this morning and he confirmed that the way payment methods have to manipulate the checkout process is completely messed up.
In short: there may not always be one single answer to this particular problem.
What I'm thinking about doing is allowing Payment for Drupal Commerce users to manipulate the checkout process using Rules, so they can choose the configuration that best fits their particular needs.
Comment #21
XanoComment #22
Xano@roderik and I discussed the Rules solution and concluded that it's probably best to create one rule per payment method, because different methods need different behavior. When using different rules, bridge modules can also add or alter the behavior for a specific payment method.
Comment #23
XanoThis is blocked on #2353383: Branch test failures.
Comment #24
XanoMoving this to the newly created 7.x-2.x branch, so we do not have to worry about backwards compatibility breaks.
Comment #25
Xano#2350709: Provide Rules actions to move the checkout panes has been fixed now.
Comment #26
lmeurs CreditAttribution: lmeurs commentedWe are also experiencing order statuses getting set to "Completed" after a user leaves the payment provider's site using the browser's back button. I tried the following rule which seems to work, but has two problems:
Can someone tell me the correct way to prevent the order's status from changing?
Can this solely be done by Rules or is the patch from #17 still required (which seems to be to no avail in this case)?
The great thing about this method is that the order is not being completed and products remain in the cart so the user can easily continue the checkout process.
We are using Commerce 7.x-1.11, Payment 7.x-1.x-dev, Payment Commerce 7.x-1.7 and OmniKassa (the only payment provider for this site).
Comment #27
dmsmidtI've tried a lot with rules, but it seems rules alone can't fix the strange 'back' behavior.
Due to the way the commerce payment checkout page is setup, going back isn't allowed because
"buttons" is set to FALSE. (Why?)
You can change this behavior as follows:
In combination with the patch in #28 this seems to fix the problem.
Note that in that patch I don't redirect to the previous page on failure. But rather set the order status back to the checkout page if the payment is not new or successful. This give a consistent behavior in our case, but should maybe be a setting because we can't be sure about everybody's flow. Using commerce_payment_redirect_pane_previous_page() however not always results in what you might expect.
(Patch against 1.7, but could work against 2.x (line number mismatch).)
Comment #28
dmsmidtThis one makes sure that Basic Payment Methods still work (payments which don't need any additional processing).
Comment #29
dmsmidtAnd this one prevents calling commerce_checkout_complete() twice.
Comment #30
getu-lar CreditAttribution: getu-lar as a volunteer commentedAfter reading all of this, I think I have a fairly clear understanding of what is going wrong in my commerce site, but to come up with a reasonable fix I have one very specific question:
In what circumstance / use case _exactly_ does it make sense for payment_commerce_payment_status_change to trigger a commerce_payment_redirect_pane_next_page, thereby presumably transitioning the order to the next state if the "status change" of the payment was from status X to status X (i.e. no actual status change at all)?
Seing as the Payment class (payment.classes.inc in payment module) while still triggering the payment_status_change hook, makes sure to not track duplicate status changes
I don't see why payment_commerce couldn't/shouldn't do the same thing (that's what my attached patch does).
Comment #31
valentin schmid CreditAttribution: valentin schmid commentedUnfortunatelly neither patch #30 nor patch #29 solved this issue for us.
Here's a patch that solved the problem for us. Hopefully for you as well.
Comment #32
getu-lar CreditAttribution: getu-lar as a volunteer commented@valentin schmid: from my (admittedly limited) understanding of the module, the logic in your code seems kinda ... strange. Do you know what combination of previous/current payment status is causing you trouble? From your code I'd have to guess that your payment is transitioning _from_ a failed state into something else. If that is true, then I would like to know what mechanism triggers that payment status change and why.
Comment #33
gnvinod CreditAttribution: gnvinod commentedI also face the same issue in my installation.
Thanks
Comment #34
Ronino CreditAttribution: Ronino as a volunteer commentedHello. My scenario is this: After clicking the cancel button on PayPal, I get correctly sent back to the review page. If I click the continue button again though (to go PayPal again), all order statuses are set to pending which finishes the order before I have finished the payment.
Patch #31 works great, it takes me back to the previous stage (review) and no orders are finished no matter how often I cancel the payment process. Awesome, thanks!
Patch #29 also fixes the finished order issue, but takes me back to the checkout page (I'd prefer going to the last stage/review though).
Patch #30 doesn't change anything for me.
My modules:
payment 7.x-1.17
paypal_payment 7.x-1.4
payment_commerce 7.x-1.7
Comment #35
Ronino CreditAttribution: Ronino as a volunteer commentedComment #37
StryKaizerChanging priority to critical
Encountered the same issue (using payment + payment_commerce + mollie).
#31 seems to fix the issue31 did not solve the issue, testing #29, will report back