Using Authorize.net in a TurboGears Form

The goal of this tutorial is to get a tw.forms form to go through two layers of validation before passing:

  1. Use the validation packages provided by tw.forms and formencode
  2. 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

The authorize package handles authorize.net requests, and can be found here or by typing: easy_install authorize

Defining The Validator

First we will need to define our ProcessCard() class which will be the chained FancyValidator for processing the card:

import tw.forms as twf
from authorize import aim as aim_api

# FancyValidator to process the Credit Card using the authorize package
class ProcessCard(twf.validators.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 twf.validators.Invalid(result_dict['reason_text'], value, state)

Defining The Form

Next we’ll define our form class that will end up being passed to the view:

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)

Using It In A Controller

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!'