Table of Contents
The goal of this tutorial is to get a tw.forms form to go through two layers of validation before passing:
- Use the validation packages provided by tw.forms and formencode
- If the first layer of validation passes, try to run the authorize.net charge using the authorize package. If this returns a response code of 1 (approved) then all validation has passed. Otherwise, invalidate the form and flash the authorize.net error.
The authorize package handles authorize.net requests, and can be found here or by typing: easy_install authorize
First we will need to define our ProcessCard() class which will be the chained FancyValidator for processing the card:
from formencode import FancyValidator, Invalid
from authorize import aim as aim_api
# FancyValidator to process the Credit Card using the authorize package
class ProcessCard(FancyValidator):
def _to_python(self, value, state):
# Setup the aim Api object.
aim = aim_api.Api(AUTHNET_LOGIN, AUTHNET_KEY, is_test=False)
# Create a transaction against a credit card
result_dict = aim.transaction(
amount=u"16.00",
card_num=unicode(value['card_number']),
exp_date=unicode(value['card_expiry']),
# ...and others...
)
if result_dict['code'] == '1':
# success
return value
else:
# failure
raise Invalid(result_dict['reason_text'], value, state)
Next we’ll define our form class that will end up being passed to the view. This example defines the form using ToscaWidgets1, but it should be fairly simple to adapt it to ToscaWidgets2 which is now the default:
from tw.api import WidgetsList
class AuthnetForm(twf.TableForm):
submit_text='Process Card'
# specify chained validators
validator = twf.validators.Schema(
chained_validators = [
twf.validators.CreditCardValidator('card_type','card_number'),
twf.validators.CreditCardSecurityCode('card_type','card_cvv'),
# you could also add an expiry validator, but authnet will handle this for you
ProcessCard()
]
)
# specify form fields
class fields(WidgetsList):
name = twf.TextField(validator=twf.validators.String(not_empty=True))
# ...and others like address, city, state, zip...
spacer = twf.Spacer(suppress_label=True)
card_type = twf.SingleSelectField(options=[('visa', 'Visa'),
('mastercard', 'Master Card'),
('discover', 'Discover'),
('amex', 'American Express')], validator=twf.validators.NotEmpty)
card_expiry = twf.CalendarDatePicker(date_format="%m/%Y", validator=twf.validators.NotEmpty)
card_number = twf.TextField(label_text='Card #', validator=twf.validators.NotEmpty)
card_cvv = twf.TextField(label_text='CVV Code', validator=twf.validators.NotEmpty)
Now all you have to do is set up your controller class methods to use the form:
# Assign a name to the form
authnet_form = AuthnetForm('authnet_form', action='/authnet/process/')
class AuthnetController(BaseController):
@expose('authnet.templates.index')
def index(self, **kw):
if '_the_form' in tmpl_context.form_errors:
# if we have top-level form errors, use flash() to display them
flash(tmpl_context.form_errors['_the_form'], 'error')
# Use ${form()} to print the form in your template
return dict(form=authnet_form)
@validate(authnet_form, error_handler=index)
@expose()
def process(self, **kw):
# if validation passes, this method will run (specified by form action)
return 'Card was successfully charged!'