I've looked through the django documentation, done lots of googling and have tried quite a few different solutions but to no avail.
I've created a 3 part form using Django's FormWizard. Once the last form (a payment form) is validated, I send a payment request to a payment gateway.
I'm doing the payment processing in the 'process_step' method of the FormWizard.
I'm having difficulty figuring out how to have the FormWizard show the payment page again when the payment fails. As it is now, the FormWizard's 'done' method gets called (after I've done my processing in process_step), as all of the forms have been validated.
I'm wondering if I need to override the call method. Not really sure how to do that, but I'm currently trying to figure that out.
Any help would be much appreciated. Regards, Shawn
class TrainingWizard(FormWizard):
def process_step(self,request,form,step):
if step == 0:
self.extra_context = {'stepOne': "One"}
if step == 1:
self.extra_context = {'stepTwo': "Two"}
if step == 2:
if self.get_response != "Success":
#Payment Failed
#Add error message
#Show Payment Form Again to allow user to retry
return
def get_response(self):
#return "Success"
return "Declined"
def done(self, request, form_list):
return HttpResponseRedirect('/training-registration-complete/')
I finally hit upon a solution. I'm using the SessionWizardView class in Django 1.4.
I overrode the render_done() function (copied it directly out of django/django/contrib/formtools/wizard/views.py and tweaked it.
Between 'final_form_list.append(form_obj)' and the last three lines (starting with 'done_response = self.done(final_form_list, **kwargs)') I handle talking with the payment gateway.
If there's an error, I redirect back to the last step in the form (using self.render.revalidation_failure()) and they can try again.
Here's a snippet of code:
try:
charge = stripe.Charge.create(
amount=price_in_cents,
currency="usd",
card=token,
description="BlahStore Order Number: %s" %(self.order.pk),
)
except (stripe.APIConnectionError, stripe.APIError, stripe.AuthenticationError, stripe.CardError, stripe.InvalidRequestError, stripe.StripeError) as e:
from django.forms import forms
from django.forms.util import ErrorList
errors = final_form_list[3]._errors.setdefault(forms.NON_FIELD_ERRORS, ErrorList())
errors.append(e.message)
return self.render_revalidation_failure(3, final_form_list[3], **kwargs)
You'll notice I have '3' hard-coded in a few places--this is because my wizard has four steps and the array is zero based. I set the error message to display and then redirect. I'm sure it would be fairly easy to adapt this if you wanted to stick with process_step(), but I personally think TheRightWay is to override the render_done() function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With