So far I haven't been able to figure out how to suppress the emails from webform when the payment fails. Has this been implemented or will it be?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

quicksketch’s picture

This would be better handled by #1009446: Validate credit card numbers against the payment gateway in form_validate(), which would fix the problem in Pay module.

jdwfly’s picture

Thanks, I'll follow that issue and see what happens. You can close this or leave it open for others to find I guess.

stella’s picture

Title: Suppress webform emails on payment failure » Handling of failed transactions

Renaming this as there's also a confirmation message displayed on transaction failure, as well as emails sent and data saved to the db. It's not necessarily just invalid credit card numbers that cause transactions to fail and we can't rely on pay's validate functions to capture every scenario. For example, there's cards suspended/cancelled, credit limit exceeded and comms errors. Ideally webform_pay would allow the pay_submit() function to progress first and check the success / failure of that before invoking the webform_client_form_submit() routine.

I'm not sure if the moving pay_submit() to the #validate routines is the best way to do this, but maybe it is. Or maybe we need to control the order of the submit routines and only proceed to the next one if payment one has succeeded. I'd like to hear your feedback on how it would be best to proceed and I can try to work on a patch for this.

The rest of the module works really well, other than this critical piece, and I'd really like to use it for a project I'm working on.

stella’s picture

Version: 6.x-1.0-alpha2 » 6.x-1.0-alpha3
Status: Active » Needs review
FileSize
3.29 KB

Here's a patch which does this. Admittedly this was against the D7 version of the module, but it's a straight port so it should work the same way even if the line numbering is off. Sorry, I just don't have time to roll a D6 version.

I initially tried to move pay_submit to the validation step, however this produced errors and unforeseen consequences that I really should have thought of from the outset. For example, if you submit the form and another validation routine fails (e.g. a required field wasn't filled in), the transaction would still be submitted to the payment gateway. And then, even worse, when they fill out the missing required field and submitted it again, another transaction would be sent to the payment gateway, meaning the customer would be charged twice! Argh!

Fixing that problem would probably be no different, or potentially harder, than fixing the original one, so I went back to making sure that the confirmation message isn't displayed and emails aren't sent until the payment has been successfully processed.

To do this, I unset the pay_submit and webform_client_form_submit submit handlers in the after_build function and instead set a custom "webform_pay_submit" handler which calls each of these manually and in the correct order. Only potential problem is if another module does a hook_form_alter() and adds in a custom submit handler - only a problem if they need to have it run after the payment has processed. I guess one workaround is for it to set a higher weight on the module in the system table?

So first it submits the transaction to the payment gateway and checks the outcome of that. If it fails, it currently just returns to the first page of the form and assumes the payment gateway prints the appropriate error message (which it does in my case). This could be improved upon by allowing the user to customise a 'failure message' or redirect to a failure page - a bit like they can do for the 'confirmation message'.

If the transaction succeeds, then it continues to call webform_client_form_submit which saves the submitted data to the database, displays the confirmation message and sends the submission emails. Some people may want it to display the submitted data in case of a failure too but I couldn't figure out how to separate that out and it suited me fine anyway. One other small change I made was to save the pxid (transaction id) and paid (activity id) to the webform_submitted_data table too so there is now a link between the webform submission and the pay_transaction/activity records in the database.

So far with our initial testing, this is working well. We tested good and bad transactions, including card declined and communication errors.

krisrobinson’s picture

subscribing

theoracleprodigy’s picture

Status: Patch (to be ported) » Needs review

The patch has to be manually added for version 6. I was able to get that to work only after doing a comparison line by line. The only real issue was the webform_pay_submit function. I am not sure why it didn't automatically patch correctly.

stella’s picture

Yeah sorry, the patch is against the D7 version as I didn't have time to roll a D6 version. Can you upload a D6 patch from against what you've done?

theoracleprodigy’s picture

I would need to pull down the latest version then manually add it in again. I have made several other changes because I needed webform conditionals to work as well. This way when someone decides not to pay now this whole section has to disappear which required adding a prefix and suffix and other changes had to go into the processing. So when I get moment I will create a version 6 patch.

zach.corbitt’s picture

I successfully applied the patch; however, the form values were clearing. So, I added a $form_state['rebuild'] = TRUE; before the return; on line 343. This seems to work for all fields except the credit card fields.

stella’s picture

Can you roll a new version of the patch so we can see what you've done?

Credit card fields have some attribute set on them to prevent them from being autocompleted or filled in by the browser - it's probably the same attribute causing them not to remember those values. I'd say it's a by design feature tbh.

zach.corbitt’s picture

This made sense for cc info.

So bear with me, I am not sure I know how to roll a new version of the patch...I am still learning some of the more advanced methods of interacting with Drupal and its community.

theoracleprodigy’s picture

Status: Needs review » Patch (to be ported)
FileSize
3.85 KB

I have created the new patch for version 6 of drupal with the fix on #9 as well.

quicksketch’s picture

Status: Needs review » Needs work

To do this, I unset the pay_submit and webform_client_form_submit submit handlers in the after_build function and instead set a custom "webform_pay_submit" handler which calls each of these manually and in the correct order. Only potential problem is if another module does a hook_form_alter() and adds in a custom submit handler - only a problem if they need to have it run after the payment has processed. I guess one workaround is for it to set a higher weight on the module in the system table?

Perhaps a safer route would simply be to set $form_state['webform_completed'] = FALSE here. That would prevent the normal webform_client_form_submit() from triggering. Even better, you could set that to FALSE and then set $form_state['storage']['page_num'] to a particular page to return to.

I'm not comfortable with this patch's current approach of just completely removing webform_client_form_submit from #submit. Seems likely to break modules like Webform PHP or Webform Validation.

quicksketch’s picture

This patch takes a different but similar approach of modifying the submit handlers, but instead of removing Webform's handlers, it remove the Pay module handlers (and calls them manually).

However unlike the other approaches, this one should work with multi-page forms, and return the user back to the previous (or last) page of the form, with all their data intact. So effectively, this actually acts like you would expect validation to work, no lost data and just an error from the CC processor.

The unfortunate thing though is that this also requires a patch to Webform module. Since Webform unset()'s the $form_state['storage'] in its first #submit handler, we don't have it to use any more by the time our submit handlers run. This just means that we need to move the cleanup of $form_state['storage'] in webform.module to the last submit handler, which is probably where it should be anyway.

Attached are two patches: one for Webform Pay and one for Webform. Additional testing would be appreciated.

quicksketch’s picture

Status: Needs work » Needs review

Oh, also we have this funky line:

+    // TODO: Figure out where Pay module discards storage and fix it.
+    $storage = $form_state['storage'];

Somehow Pay module is throwing away $form_state['storage'], so we need to keep it and then restore it again after it's done with its submission code. We need to figure out what stuff Pay is keeping in storage and remove it individually instead of just blowing away all of $form_state['storage'].

quicksketch’s picture

We need to figure out what stuff Pay is keeping in storage and remove it individually instead of just blowing away all of $form_state['storage'].

I've submitted an issue to the Pay queue: #1296392: Pay submit handlers unnecessarily destroy $form_state['storage'].

quicksketch’s picture

FileSize
3.72 KB

Small reroll to include the new issue number.

kevinquillen’s picture

This patch appears to be blocking all transactions.

jpamental’s picture

@quicksketch - I've applied #17 and it works great to block the submission of a failed transaction but your other patch from #14 'webform_unset_storage.patch' won't apply to Webform 6.x-3.18 (and I couldn't see where to try it manually as it seems to be a different beastie now). Ideally it would be great to have the user brought back to that previous page (in my case, a single-page donation form) with the rest of the form preserved, an error message about the failure and the chance to resubmit the CC data. If I'm understanding it correctly this is what should be happening with both patches. Do I have that right? Any suggestions for applying the patch to the latest Webform module? (I checked to see if there was progress in the Pay module but didn't see any real progress since you posted there)

Thanks-

quicksketch’s picture

@jpamental: In order for this patch to work the Pay module patch also needs to be committed. I've pretty well abandoned this approach (Webform Pay) I'm afraid, we'll need to look for better solutions in Drupal 7.