UI Error message: "We encountered an error processing your payment method. Please verify your details and try again."
UI Error: "A card payment method was expected to be present, but this PaymentIntent does not have a payment method and none was provided. Try again with a payment method or card data."
Log error message: "payment_details must contain the stripe_payment_method_id key."

Steps to reproduce:
1. Checkout as an anonymous user
2. Use the 3d secure 2d authentication card: 4000000000003220
3. When prompted click fail
4. Now whenever you re-enter the above card information or use a different card details you get the above error.

Commerce: 2.14

Comments

vanlindholm created an issue. See original summary.

vanlindholm’s picture

Issue summary: View changes
mglaman’s picture

Status: Active » Postponed (maintainer needs more info)

Shoot. We need an update hook, I think, that flushes libraries and CSS/JS. Did you try a cache rebuild? Just to see if it's JavaScript related.

Also, I think Stripe has weird errors when re-using card info. Can you check your database logs as well for more context?

I'll try to review the tests to replicate the above.

vanlindholm’s picture

I'll re-test tonight and provide more information. Thank you!

vanlindholm’s picture

Hi Matt,

Unfortunately clearing the cache made not difference and no error is reported in the database log. The network traffic however chose that a status code of 400 is returned from the confirm post:

Request URL: https://api.stripe.com/v1/payment_intents/pi_1FHEjAEW5KsiT3KIyTEBOe0f/co...
Request Method: POST
Status Code: 400
Remote Address: 34.240.123.193:443
Referrer Policy: no-referrer-when-downgrade

Response Headers
access-control-allow-credentials: true
access-control-allow-methods: GET, POST, HEAD, OPTIONS, DELETE
access-control-allow-origin: https://js.stripe.com
access-control-expose-headers: Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required
access-control-max-age: 300
cache-control: no-cache, no-store
content-length: 1584
content-type: application/json
date: Tue, 10 Sep 2019 19:15:26 GMT
request-id: req_cX6H92ItFRbRtz
server: nginx
status: 400
strict-transport-security: max-age=31556926; includeSubDomains; preload
stripe-version: 2017-06-05
timing-allow-origin: https://js.stripe.com

vanlindholm’s picture

Just one more note on this. Re-starting clearing the server cache made no difference but re-starting the browser did clear the issue.. Cookie?

kmbremner’s picture

Status: Postponed (maintainer needs more info) » Active

Looks like requested info has been provided

bojanz’s picture

You'll also want to check your checkout flow to ensure you're not running into #3078967: 3D secure fails if StripeReview and PaymentInformation are on the same checkout step.

vanlindholm’s picture

Hi, The stripe review and payment information are on different steps.

kmbremner’s picture

If the initial attempt fails, it looks like $intent = \Stripe\PaymentIntent::retrieve($intent_id); returns an intent with status = 'requires_source' and sets $order->set('payment_method', NULL);.

This then causes the next payment attempt to error with:
A card payment method was expected to be present, but this PaymentIntent does not have a payment method and none was provided. Try again with a payment method or card data.

The status value 'requires_source' is never checked for (there isn't a constant for it in vendor/stripe/stripe-php/lib/PaymentIntent.php) and the payment intent isn't removed (like it would be with a cancellation). So the payment intent remains, destined to fail again next time.

If /commerce_stripe/src/Plugin/Commerce/PaymentGateway/Stripe.php line 206 is changed to if ($intent->status === PaymentIntent::STATUS_CANCELED || $intent->status === 'requires_source') { then the card intent is deleted and the next attempt with the card can succeed.

However, I don't know the code well enough to say whether that is the best solution.

kmbremner’s picture

ivan616’s picture

StatusFileSize
new989 bytes

This 3079830-payment-method-1.patch is what fixed it for me.
Altho I have also extended and reworked StripeReview pane.

vanlindholm’s picture

FYI: I can't replicate this anymore with the latest dev build and no patches..

xsdx’s picture

Confirming that this is ok on latest dev without patches

mglaman’s picture

Status: Active » Postponed (maintainer needs more info)

kmbremner, CroIvan can you try the latest dev? We have two reports that it has been fixed.

kmbremner’s picture

I confirm that I can't reproduce this issue with the latest version of dev.

mglaman’s picture

Priority: Major » Normal
Status: Postponed (maintainer needs more info) » Closed (outdated)

I'm going to mark this as outdated, thanks @kmbremner.

berdir’s picture

Status: Closed (outdated) » Needs review
StatusFileSize
new63.77 KB
new1.67 KB

Re-opening because I can still reproduce this with 8.x-1.0-rc4. My problem might actually be slightly different, because I can only reproduce this on live with a real credit card but invalid expiration/cvc and I'm then already getting a validation error directly on the payment information pane.

I can see that the message comes from \Drupal\commerce_payment\PluginForm\PaymentMethodAddForm::submitConfigurationForm(), and I can reproduce this problem if I throw such an exception above the try, always. But this calls createPaymentMethod(), not createPayment().

In the logs, the error is "Your card was declined.". So I assume it's thrown in \Drupal\commerce_stripe\Plugin\Commerce\PaymentGateway\Stripe::doCreatePaymentMethod(), and error is then logged there. I suspect the problem is that the stripe_payment_method_id value is kept by the form system and isn't updated? I see that commerce_stripe.form.js has a check for $('#stripe-payment-method-id', $form).val().length > 0, which I assume is then exactly what happens? You enter the new values, but they are never used. I'm not sure why that is there? I'm not sure if that's the correct solution, likely we'd need to instead ensure that the value is not filled out again, but not sure how easy that is.

That might also explain what fixed the problem for others, when the error happens on the stripe review pane, then it will redirect back to the form, build it from scratch without the old form values.

I'm also having a second problem when this is used in combination with inline form errors, then you get this:

With the attached patch, I'm only getting the message once.

berdir’s picture

Status: Needs review » Needs work

Ok, this is definitely not working yet, that check is also required to actually do the submission then apparently on the second re-entry. Need to find a different solution.

berdir’s picture

Status: Needs work » Needs review
StatusFileSize
new1.6 KB

Ok, new attempt that isn't very pretty either, but seems to work. I'm unsetting the current value when initializing Stripe. I didn't try very hard, but I suspect it would be quite hard to remove the form input values from $form_state at the right time, due to how separated into different places this all is.

nicolas bouteille’s picture

berdir’s picture

No, that's not related, the error that this fixes happens while adding a payment method.

johnpitcairn’s picture

Thanks for the patch @Berdir.

I have been seeing the same repeated IFE error message as comment #18. The patch at #20 does not fix this correctly for me - with the patch I see only the main Drupal message, no inline field errors are displayed. I think perhaps IFE problems should be a separate issue, right?

jeff veit’s picture

Cannot reproduce.

BUT I am trying on a re-installed commerce_stripe, at HEAD now, with only these patches currently:

I was seeing something which conceivably may have been the bug, and I wonder if it was due to this patch that I had installed:

I can imagine that not deleting a payment method upon failure is an easy way to have it immediately rejected again.

If you are seeing these errors, do you perhaps have that patch installed too?

johnpitcairn’s picture

@Jeff Veit: I can no longer reproduce what I may have been seeing. It's possible I had patched with #3125969: Do not delete stored payment method on 3DS 2 failure or cancel ? for testing. The whole saga has been a moving feast ;-)

jeff veit’s picture

I think that patch may be implicated, but it's certainly not the whole story. I've managed to duplicate the error for a logged in user without the patch. Perhaps. Same symptoms, but it may turn out to be a different cause. I have not been able to replicate with a a logged out user as per the issue.

jeff veit’s picture

@John, I have a dev system that I can definitely reproduce this bug on - or at least one that looks the same. The dev system does have a stack of patches, so it's not clear that https://www.drupal.org/project/commerce_stripe/issues/3125969 is the cause, but it turns out that that patch does have a problem.

I've been testing, then adding patches, and testing again on another dev system, and I've yet to reproduce this bug. Even with the patch above.

cchoe1’s picture

I'm on the latest version of commerce_stripe. I'm testing using one of Stripe's error cards to trigger a CVC error. After triggering this error, it sends me back to the order_information step with the message 'We have encountered an error processing...'. The form is in a new state though since PaymentGatewayForm::setError() changes the form state and then the default choice for payment methods gets set to a new credit card. If you don't hit another payment method and simply attempt to enter in a card number again (even if it's a valid card that should be going through) then it will again trigger this same error. The stripe-payment-method-id doesn't ever seem to update and any subsequent attempts to submit a new credit card will keep attempting to submit with the initial payment method (the error card). It never actually updates the payment method with the new card details you just entered in and thus it just perpetually triggers the same error.

This only happens if you don't interact with any other elements on the page after the error triggers. If you select a saved card and then go back to a new credit card, it seems to reset things. Refreshing the page will attempt to submit the form again with the past state which will just trigger the error again. But navigating directly back to the page will start you off fresh and you can enter in a good card and proceed as normal. However, this is unintuitive.

It's pretty problematic since in practice, if a customer fails a CVC or AVS check, their first instinct would just be to re-enter their card in. However, this will keep triggering the same error over and over, even if they submit their card correctly the next time. Refreshing the page again just submits the form so it won't fix the problem and most people don't understand what difference it makes to re-navigate back to the page vs simply refreshing the page. The customer would have to specifically click into their address bar and navigate back to that page to reset the form state entirely to a fresh slate.

cchoe1’s picture

After applying #20, it seems to have fixed the issue