Add PayFlow Pro wrapper to standard library?

M

Mark McEahern

I just wrote a very simple wrapper for the PayFlow Pro SDK (see below).

A friend of mine did this before, but I didn't have access to his
source, so I took it as a learning opportunity for me to write a C
wrapper. I did a little searching to see whether anyone had done
anything like this for Python. I didn't find anything.

I did find that PHP comes with an extension for PayFlow Pro that you can
compile into the language:

http://www.phpbuilder.com/manual/ref.pfpro.php

This inspired me to imagine something similar being added to Python's
standard library. The basic idea: This would mean someone like me
wouldn't have to reinvent the wheel over and over. Do other folks use
Python for payment processing? Do they use something other than
Verisign? Verisign--with all its warts--is particularly nice because it
supports recurring billing, which means I don't have to store the credit
card number, I just setup a recurring billing profile and they do the
recurring billing. You can't beat that.

I'd be willing to do most of the work, but I'm probably going to need
help.

What I imagine is there would be a pure Python module that provides a
high level interface to process transactions like this:

import pfpro
result = pfpro.process(details)

This will then use a C wrapper to call the PayFlow Pro dynamic library.

The Python wrapper would also support using the context functions:

import pfpro
context = pfpro.context(details)
for tx in transactions:
tx.result = context.process(tx.details)

# context's __del__ could handle destroying itself, etc.

What's the next step? I don't know since I've never been involved in
adding anything to the standard library.

Further, I can imagine Zope/CMF/Plone wrappers on top of this too.

Thanks,

// m

p.s. Here's the code; consider it 0.0.0.1. ;-)

# setup.py

"""
Before you run this, you need to:

1. Copy the dynamic library from the PayFlow Pro SDK for your
platform to /usr/local/lib.

2. Copy the pfpro.h from the PayFlow Pro SDK for your platform
to /usr/local/include.

TODO:

- For Windows, there's a COM server--use that or use the dynamic
library?

- Add a pure Python module "on top" of the C wrapper.
"""

from distutils.core import setup, Extension

pfpro = Extension('pfpro',
sources = ['pfpromodule.c'],
libraries = ['pfpro'],
runtime_library_dirs = ['/usr/local/lib'],
include_dirs = ['/usr/local/include'])

setup (name = 'pfpro',
version = '1.0',
description = 'PayFlowPro',
ext_modules = [pfpro])

# pfpromodule.c

#include <Python.h>
#include <string.h>
#include "pfpro.h"

/* This is very, very raw. */

static PyObject *ErrorObject;

static PyObject *
pfpro_process(PyObject *self, PyObject *args)
{
int ok;
char *server;
int port;
int timeout;
char *proxyAddress = NULL;
int proxyPort = 0;
char *proxyLogon = NULL;
char *proxyPassword = NULL;
int context;
char *request;
int requestLength;
char *response;
PyObject *returnValue;

ok = PyArg_ParseTuple(args, "siis", &server, &port, &timeout,
&request);

if (pfproInit()) {
// "raise"
return Py_BuildValue("i", 1);
}

if (pfproCreateContext(&context, server, port, timeout, proxyAddress,
proxyPort, proxyLogon, proxyPassword)) {
// "raise"
return Py_BuildValue("i", 2);
}

requestLength = strlen(request);
pfproSubmitTransaction(context, request, requestLength, &response);
returnValue = Py_BuildValue("s", response);
pfproCompleteTransaction(response);
pfproDestroyContext(context);
pfproCleanup();

return returnValue;
}

static PyMethodDef pfpro_methods[] = {
{"process", pfpro_process, METH_VARARGS,
"Process a PayFlowPro transaction and return the result."},
{NULL, NULL, 0, NULL} /* Sentinel */
};

static char pfpro_module_documentation[] =
"pfpro - Python wrapper for the PayFlowPro library."
;

void
initpfpro()
{
PyObject *m, *d;

/* Create the module and add the functions */
m = Py_InitModule4("pfpro",
pfpro_methods,
pfpro_module_documentation,
(PyObject*)NULL,
PYTHON_API_VERSION);

/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
ErrorObject = PyString_FromString("pfpro.error");
PyDict_SetItemString(d, "error", ErrorObject);

/* XXXX Add constants here */

/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module pfpro");
}

# test.py
#!/usr/bin/env python

import pfpro

username = # your username
password = # your password
cardExpiration = '1209'
cardNumber = '5105105105105100'
amount = '1.00'

values = {'VENDOR': username,
'TRXTYPE': 'S',
'ExpDate': cardExpiration,
'PWD': password,
'USER': username,
'ACCT': cardNumber,
'TENDER': 'C',
'PARTNER': 'verisign',
'AMT': amount}

server = 'test-payflow.verisign.com'
port = 443
timeout = 10

request = '&'.join(['%s=%s' % (k, v) for k, v in values.iteritems()])
response = pfpro.process(server, port, timeout, request)
print response
 
D

Duncan Booth

What I imagine is there would be a pure Python module that provides a
high level interface to process transactions like this:

import pfpro
result = pfpro.process(details)

This will then use a C wrapper to call the PayFlow Pro dynamic library.

The Python wrapper would also support using the context functions:

import pfpro
context = pfpro.context(details)
for tx in transactions:
tx.result = context.process(tx.details)

# context's __del__ could handle destroying itself, etc.

What's the next step? I don't know since I've never been involved in
adding anything to the standard library.

First off, forget about adding it to the standard library until a long way
down the line, if at all. This sounds like a useful but specialised module,
so it doesn't need to be shipped as standard.

Next, I suggest you have a look at Greg Ewing's Pyrex, which is a language
specifically for writing Python Extension modules. This should make your
life much easier than handling the C api directly. (There are plenty of
other options, but I prefer Pyrex).

Pyrex should make it easy for you to define an appropriate context type
directly in your extension module. This is probably a better solution than
trying to put a Python wrapper around a set of procedures as it means you
can control access to the C functions much more tightly.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top