When using a known declined test card, forms with a stripe element are still able to be submitted successfully. The error is not captured until the Stripe webhook receives a response, and then the error displayed in the Drupal message queue after the form is submitted.

There should be a way to validate successful charges before the form gets submitted, and the error should be available to the webform to display to users.

Using one of the following cards can help you test this issue: https://stripe.com/docs/testing#cards-responses

Comments

AdamBernstein created an issue. See original summary.

adambernstein’s picture

Issue summary: View changes
johncronan’s picture

StatusFileSize
new864.84 KB

This is a serious bug! It causes payments to be entered into our webform results (and our CRM) that actually failed! I am seeing this "in the wild" with spam-like submissions that have obviously fake data. I don't know why anyone bothers. Just making trouble, I guess.

Using the test card "4000 0000 0000 0101" I was able to replicate this on our development site:

screen shot

hanoii’s picture

A small update that I am working on a solution to this that seems promising, might do a few tests and commit and ask you to test the dev version, would that be OK?

johncronan’s picture

Awesome. I'd be happy to test it!

nshower’s picture

Any updated information on this patch? I would be happy to test as well.

nshower’s picture

Not sure if this formatted properly, but the solution I came up with is attached. It moves the validation logic from the postSave Webform hook to the validateForm Webform hook.

pingevt’s picture

Thanks @nshower for the patch you provided. Its given me some ideas. I'm also thinking we should place a hold on validation, then capture the charge on submit.

For some reason I feel like charging the card on validation could result in charging the card, but erring out on something else therefore never submitting the webform. I haven't been able to force that just yet, but seems like it could be a possibility. Below are the API docs. I think combining your code and the original, this could be done. I'll see what I can come up with.

https://stripe.com/docs/charges

pingevt’s picture

StatusFileSize
new10.86 KB

So I ended up creating my own Webform Handler. Just wanted to share the code. This is still in a little bit of development, so there are a lot of `ksm()`'s and still testing through it. But hopefully can provide some help to others if need be.

- On validateForm(), I'm creating a hold on the card, and releasing the hold if there is an error.
- On postSave(), I'm updating the metadata (more could be updated if need be), and capturing the charge

Some Notes:
- I removed the subscription related code, as I didn't need it for my project.
- I can't seem to edit a webform due to the Strip field being there... so is that a known bug? Once that is figured out, the validateForm() would need some additional functionality so it doesn't create a hold if the webform is edited.
- If the AJAXing bugs are fixed, not sure how this will react to all of that.

Hope that helps others out.

chris matthews’s picture

Version: 8.x-1.1 » 8.x-1.x-dev
Priority: Normal » Major

Bumping the priority level to Major.

coxy0001’s picture

Has there been any movement on this? It's a big, big issue, is there a patch coming? I've been leaking sales as customers have got wise that by entering in random card numbers they can still submit the form!!!!

mlncn’s picture

Another approach, which i think should be an option / happen in the background anyway, is to allow the submission to go through, but clearly indicate in a data column whether or not payment succeeded. Agree that failing form validation when payment fails should be the default though.

kthull’s picture

StatusFileSize
new5.1 KB

#7 worked for me, but I added the following to handle the error thrown from stripe's test bad card:

catch (\Stripe\Exception\CardException $e) {
  //drupal_set_message($this->t('Stripe card error: %error', ['%error' => $e->getMessage()]), 'error');
  $stripe_validation_error = $e->getMessage();
}
hanoii’s picture

Hi all,

Just some heads up to this thread that I am currently working on a major refactor to both the stripe module and this subsequently this one and that refactor should account for SCA properly and probably include other things like paymentrequest buttons.

It should also cover this issue as well as the payment will succeed on the client before posting the form.

A lot changed stripe wise and started to relay heavily on client-side logic as opposed to server side, which makes things harder in a server side process like drupal forms in general and webforms specifically, however I think I have a working approach that should make it at least workable for most of the users of this module.

I hope you all will be willing to try the betas when they are out.

hanoii’s picture

Status: Active » Fixed

I just released Stripe 2.0.0-beta1 and Stripe webform 2.0.0-beta1, so I am closing this as the validation of the card happens after form validation and locally in the client, so I consider this one fixed. Please open follow-ups otherwise.

hanoii’s picture

Version: 8.x-1.x-dev » 2.0.0-beta1

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

jbarone716’s picture

Using 2.0.0-beta4 forms can still easily be submitted without verifying payment or even filling out the field at all. Even on webforms with a single element and the Stripe element the form can just be submitted and the Stripe error will appear below the input field, then the webform will submit anyways. Because there is no way to mark the field as "required", any submissions can simply bypass payment by hitting the submit button and waiting. Validation will appear for incorrect cards, etc, but will not stop submission. This combined with the creation of payment_intents every time someone opens the webform containing the Stripe element really makes it difficult to justify the use of this module. Is there any fix being looked at or have we been stagnant for years?