[ic] Summary of Payment modules
arogerso at uwaterloo.ca
Tue Apr 1 12:45:03 UTC 2014
We have used beanstream's hosted payment service for credit cards on our 5.4.x interchange for a number of years. As we upgrade to 5.8.0 we started looking at updating the interface to beanstream. As part of that process I have reviewed the payment modules distributed with the current release IC 5.8.0. I have summarized my notes below in the hope that it may be helpful for others choosing a module to use, choosing a module as a basis for a module they may develop, or possibly for the IC 6 team.
The payment module appears to have been developed with server-server processing in mind. That is, when the customer selects credit card payment and fills in their credit card information, the payment module sends the information to the credit card processor's server, waits for a response, assesses the results and either completes or fails the interchange transaction.
The payment module exports two functions, and allows export of a third. It requires a sub be defined for the particular gateway, either as a GlobalSub or in Vend::Payment::Gateway.
The main function is the charge function which is called when an &charge or [charge ] are processed. It sets up the data, calls an appropriate processor specific function defined as a GlobalSub or in Vend::Payment::Gateway then interprets the results and sets up interchange to complete or fail the transaction.
The payment module also defines:
- charge_param (@EXPORT): looks up a parameter in the Route repository, mv_payment_* in options, MV_PAYMENT_* in Variables
- map_actual (@EXPORT_OK): returns an array of of 'actual' values needed by the gateway, derived from interchange Values or CGI:Values based on a standard mapping, plus charge_param('remap') to change names and MV_PAYMENT_BILLING_SET, MV_PAYMENT_BILLING_INDICATOR to control billing information.
- gen_order_id: generates an order id for the transaction
- post_data: builds a URL string and posts it using one of wget, SSLeay, LWP and returns %result
- test* : set up test environments
Each payment gateway module typically exports a single function, named for the gateway, which is called by Vend::Payment charge(), and may use the various functions defined in the payment module. Many developers have chosen to reimplement code found in the payment module.
Most (all?) modules create a module Payment::ABC to force the require to notice that the module is missing, but simply add subs to the Payment module to implement their functionality. Some programmers note this as a bug in their documentation, presumably preferring a stricter OO implementation.
Some modules implement other protocols (not server-server) such as hosted payment, transparent redirect, multi-step server-server, tokens etc. Typically this is involves two invocations of the charge function, each with different parameters. First, the user completes the interchange portion of the transaction and selects a payment mode which requires a hosted/redirect protocol. The charge function calls the gateway function which bounces the user to the gateway's website. The gateway servers do their thing and eventually bounce the user back to interchange. On the return to interchange, the charge function is called again. This time the gateway function recognizes that the user is returning from the gateway's servers and assess the results and completes or fails the transaction.
In these cases the gateway function typically has a large if-then-else structure to perform the bounce to the server and to select from one or more appropriate responses depending on how the gateway returned the user to the interchange. Typically, developers do not claim compatibility on a call level, and additional configuration steps are required including creating pages for return targets from the gateway and modifying etc/log_transaction to handle the two step protocols.
Some modules use a check_sub to test whether the transaction meets AVS/CVV requirements. Apparently these gateways perform the tests but do not fail a transaction based on the AVS/CVV test results. These require a protocol to pre-authorize and check AVS/CVV then complete the transaction if the AVS/CVV results are satisfactory.
There are three main techniques used for redirecting to a gateway's server:
- insert an iframe in the page delivered by interchange, with the gateway's server's form displayed in the iframe
- display an interchange page with a [bounce ] tag sending the user to the gateway's server
- in perl code, use $Tag->tag() to send the user to the gateway's server
Users typically return to interchange by defining a page in pages/ which contains a [charge ]? Different modules have different ways of completing the interchange transaction, some returning from the charge through Vend::Payment and some requiring changes in etc/log_transaction.
Below is a list summarizing the types of techniques used. There may be better examples of some of the things mentioned - no offence is intended to any developer whose code I misrepresented. For developers unlucky enough to not be able to find the module they need, this list might help find a starting point for developing a new module.
Server-server using external module: Business::OnlinePayment
5 types of XML for different transactions including 3DS, acs
more OO than most
check_sub for AVS/CVV
incl support for Paypal express checkout
Server-server using external module: OpenECHO
notes problems with &, < and >
processes variety of callbacks from Google both in transactions and from admin interface
documents setup of buttons and routes
uses $Tag->tag to bounce to google
uses callback page charge route="googlecheckout" gcorequest="callback"
variety of multistep protocols for charge, add_order_number, refund, cancel
Server-server using lpperl
check_sub for AVS/CVV
Server-server using external module (MCVE) and low level calls
request then poll for response
complex module, not by zolotek
bounce pages: pages/ord/paypalcheckout.html
return pages with
[charge route="payflowpro" action="get"]
[charge route="payflowpro" action="set"]
[bounce href="[area href=__CHECKOUT_PAGE__]"]
check_sub for AVS/CVV
lots of steps, tokens, back and forth
does not support 3DS
checks for server availability and fails over to offline processing otherwise, also logs $0 transactions
iframe to go to bank
tdsreturn.html: charge route="sagepay" sagepayrequest="3dsreturn"
multi-step - check for 3DSecure available for card, then process transaction
Server-server using external module: Net::TCILink
see examples of use of %result for different success and error conditions
uses call back pages
logs temporary transaction before going to bank
redirects to bank using Tag->tag
bank takes call back page and displays it on their page
If you are developing a new module, I would suggest looking at:
Vend::Payment - for what it has to offer
TestPayment - for the interchange side of how to complete or fail a transaction, use of the %result array
iTransact or Tclink - for the shortest (not necessarily best) examples of Server-Server
SagePay - use Tag->tag to bounce to a page with an embedded iFrame (See Quick Start Summary #7), then using [charge] to return from there to interchange (See Quick Start Summary #7), good documentation
WorldPay - for logging temporary transaction while waiting for the bank to return a response
Protx2 - for a server-server module with documentation on "cooperating with GoogleCheckout and PaypalExpress"
PayfloPro - for multiple callback pages with different charge route actions and bounces
Netbilling - if you have a provider which requires polling for a response
CyberSource - for a more OO approach, using buttons and bounce to go places
When you have a handle on things, then read one or more of the 'big' modules which do most things, but are a little harder read because they are so big:
HTH someone sometime.
Angus Rogerson, BMath, BScN, RN
Duct Tape Programmer
University of Waterloo | Retail Services | Information Systems
Visit Us Online & Right On Campus www.retailservices.uwaterloo.ca
More information about the interchange-users