.. _custom-payment-modules:

Custom Payment Modules
======================

While Satchmo currently has support for several different payment modules, you may
have unique needs or the desire to create your own payment processor module. This
document will discuss how to create your own payment modules.  If you do decide
to create your own module, please let us know so we can include it back into the
satchmo core and make the framework that much more robust.

Overview
--------

Satchmo's payment processor modules are meant to be as modular as possible.  For
many types of payment processors, you should be able to use one of the existing
modules as a basis for creating your own.

All of the modules are stored in the ``/payment/modules`` directory.  If you take a
quick look at any one of the subdirectories, you will see a number of files:

 - __init__.py
 - config.py
 - processor.py
 - urls.py
 - views.py

The ``__init__.py`` is required so that satchmo can import the files.  There is no need
to put any code in this file.  Just be sure it exists!

The rest of the files are described below.

Building your processor
-----------------------

The ``processor.py`` file is where the majority of the heavy lifting is done.  The processor
does 4 things:

 - Sets up its configuration for the service (``__init__``)
 - Takes order data and formats it in the appropriate manner (``prepareData``)
 - Sends the data to the processing server/url (``authorize_payment``, ``capture_payment``, ``capture_authorized_payment``) and returns the results.

Of them, only ``capture_payment`` is required.  If the processor can both authorize and process, then you need to add a function ``can_authorize``, which returns True, and implement the other two methods.  See the ``dummy`` module for an example.

Optionally, the processor can include include test code so that it is easy to verify from
the command line.

Here is a stub you can use to create your own processor::

    from payment.modules.base import BasePaymentProcessor, ProcessorResult

    class PaymentProcessor(BasePaymentProcessor):
        def __init__(self, settings):
            # Set up your configuration for items like
            # Test server, url, various flags and settings
            super(PaymentProcessor, self).__init__('example', settings)

        def capture_payment(self):
            # Send the data via the appropriate manner and return a ProcessorResult
            # object.


Refer to the dummy, authorize.net, cybersource or trustcommerce modules for various examples to
help you through the process.

Configuration
-------------

Each processor will have unique variables that need to be set.  The ``config.py`` file is where
you can leverage the Satchmo settings capability to add your unique variables.  Please
refer to the :doc:`configuration` in order to understand how the system works. For more examples, 
the existing working modules are great examples of what to setup.  The basic format is:

Create the new configuration group::

    PAYMENT_GROUP = ConfigurationGroup('PAYMENT_MYNEWPROCESSOR',
        _('My New Processor Payment Settings'),
        ordering=102)

.. Note:: The key of the ``ConfigurationGroup`` must be the module name, upper-cased.

For example, if your custom payment module was located in ``mypaymentmodules.mynewprocessor``,
the ``ConfigurationGroup`` should be given the key ``PAYMENT_MYNEWPROCESSOR``.
The reason for this is that the ``active_gateways()`` function in ``payment/__init__.py`` attempts 
to automatically determine these keys by appending the upper-cased module name to ``PAYMENT_``.

Now register the settings you need::

    config_register_list(
        BooleanValue(PAYMENT_GROUP,
            'LIVE',
            description=_("Accept real payments"),
            help_text=_("False if you want to be in test mode"),
            default=False),

        StringValue(PAYMENT_GROUP,
            'LABEL',
            description=_('English name for this group on the checkout screens'),
            default = 'Credit Cards',
            help_text = _('This will be passed to the translation utility')),

        StringValue(PAYMENT_GROUP,
            'URL_BASE',
            description=_('The url base used for constructing urlpatterns which will use this module'),
            default = r'^credit/'),

        MultipleStringValue(PAYMENT_GROUP,
            'CREDITCHOICES',
            description=_('Available credit cards'),
            choices = (
                (('Amex', 'American Express')),
                (('Visa','Visa')),
                (('Mastercard','Mastercard')),
                (('Discover','Discover'))),
            default = ('Visa', 'Mastercard', 'Discover')),

        StringValue(PAYMENT_GROUP,
            'PASSWORD',
            description=_('Your Processor password'),
            default=""),

        BooleanValue(PAYMENT_GROUP,
            'EXTRA_LOGGING',
            description=_("Verbose logs"),
            help_text=_("Add extensive logs during post."),
            default=False)
    )

All of these settings can be accessed in your ``__init__`` method (shown above).
For example, the LIVE value above can be accessed by using ``settings.LIVE.value``

Views
-----

Most payment processing have similar steps:

 - Collect demographic information
 - Collect payment information
 - Confirm info is correct
 - Return a status


The ``views.py`` file contains the information that maps your processor views to the existing
views or your own custom view.

For most people, the views contained in payment.views will be sufficient.  The example below
maps these views to views already available in Satchmo::

    from livesettings import config_get_group
    from payment.views import confirm, payship

    def pay_ship_info(request):
        return payship.credit_pay_ship_info(request, config_get_group('PAYMENT_MYNEWPROCESSOR'))

    def confirm_info(request):
        return confirm.credit_confirm_info(request, config_get_group('PAYMENT_MYNEWPROCESSOR'))


However, there is nothing stopping you from creating your own view::

    def confirm_info(request):
        # Do a lot of custom stuff here
        return render_to_response(template, context)


All of the current satchmo payment views are in ``/payment/views``.
Please review these before trying to build one of your own!

Url configuration
-----------------

Now that you have built your processor, configured your settings and built your views, you
need to tell Satchmo how to access these views.  This is where the ``urls.py`` file is useful.

For most processors, a simple file would look like this::

    from django.conf.urls.defaults import *
    from livesettings import config_value, config_get_group


    config = config_get_group('PAYMENT_MYNEWPROCESSOR')

    urlpatterns = patterns('satchmo',
         (r'^$', 'mypaymentmodules.myprocessor.views.pay_ship_info',
                        {'SSL':config.SSL.value}, 'MYNEWPROCESSOR_satchmo_checkout-step2'),
         (r'^confirm/$', 'payment.modules.trustcommerce.views.confirm_info',
                        {'SSL':config.SSL.value}, 'MYNEWPROCESSOR_satchmo_checkout-step3'),
         (r'^success/$', 'payment.views.checkout.success',
                        {'SSL':config.SSL.value}, 'MYNEWPROCESSOR_satchmo_checkout-success'),
    )


The nice thing about this file is that it allows you to easily plug in the views
you need and rename the urls to whatever form you need.  Just make sure to
maintain the naming convention for the urls as shown above.

Enabling the new module
-----------------------

In order to enable your new payment processor, you must add it to your INSTALLED_APPS setting in your settings.py. For example::

    INSTALLED_APPS = (
            ...
            'payment',
            'mypaymentmodules.myprocessor',
            ...


Conclusion
----------

Hopefully this document will help you get started in creating your own payment
modules.  Before trying to tackle one on your own, take some time to look at
the existing models and get a feel for how things have been done.  Once you are
comfortable, we suggest copying one of the modules and using it as a starting
point for your subsequent efforts.  If you get stuck, please feel free to ask
the `mailing list`_ for help.

.. _mailing list: http://groups.google.com/group/satchmo-users
