Provided by: interchange_5.7.7-2_amd64 bug

Interchange Sagepay Support

       Vend::Payment::SagePay $Revision: 0.8.7 $

       http://kiwi.zolotek.net is the home page with the latest version.

This package is for the 'SagePay Direct' payment system.

       Note that their 'Direct' system is the only one which leaves the customer on your own site and takes
       payment in real time. Their other systems, eg Terminal or Server, do not require this module.

Quick Start Summary

       1 Place this module in <IC_root>/lib/Vend/Payment/SagePay.pm

       2 Call it in interchange.cfg with:
           Require module Vend::Payment::SagePay

       3 Add into variable.txt (tab separated):
           MV_PAYMENT_MODE   sagepay
         Add a new route into catalog.cfg (options for the last entry in parentheses):
           Route sagepay id YourSagePayID
           Route sagepay host live.sagepay.com (test.sagepay.com)
           Route sagepay currency GBP (USD, EUR, others, defaults to GBP)
           Route sagepay txtype PAYMENT (AUTHENTICATE, DEFERRED)
           Route sagepay available yes (no, empty)
           Route sagepay logzero yes (no, empty)
           Route sagepay logorder yes (no, empty)
           Route sagepay logsagepay yes (no, empty)
           Route sagepay applyavscv2 '0': if enabled then check, and if rules apply use.
                           '1': force checks even if not enabled; if rules apply use.
                           '2': force NO checks even if enabled on account.
                           '3': force checks even if not enabled; do NOT apply rules.
           Route sagepay giftaidpayment 0 (1 to donate tax to Gift Aid)

       4 Create a new locale setting for en_GB as noted in "item currency" below, and copy the public space
       interchange/en_US/ directory to a new interchange/en_GB/ one. Ensure that any other locales you might use
       have a correctly named directory as well. Ensure that this locale is found in your version of locale.txt
       (and set up GB as opposed to US language strings to taste).

       5 Create entry boxes on your checkout page for: 'mv_credit_card_issue_number',
       'mv_credit_card_start_month', 'mv_credit_card_start_year', 'mv_credit_card_type' and
       'mv_credit_card_cvv2'.

       6 The new fields in API 2.23 are: BillingAddress, BillingPostCode, DeliveryAddress, DeliveryPostCode,
       BillingFirstnames, BillingSurname, DeliveryFirstnames, DeliverySurname,
       ContactNumber,ContactFax,CustomerEmail.  CustomerName has been removed. Billing and Delivery State must
       be sent if the destination country is the US, otherwise they are not required. State must be only 2
       letters if sent. Other fields may default to a space if there is no proper value to send, though this may
       conflict with your AVS checking rules. SagePay currently accept a space as of time of writing - if they
       change this without changing the API version then send either a series of '0' or '-' characters to stop
       their error messages.

       7. Add a page in pages/ord/, tdsfinal.html, being a minimal page with only the header and side bar, and
       in the middle of the page put: [if scratch acsurl]        <tr>           <td align=center height=600
       valign=middle colspan=2>             <iframe src="__CGI_URL__/ord/tdsauth.html" frameborder=0 width=600
       height=600></iframe>           </td>        </tr> [/if]

       Add a page in pages/ord/, tdsauth.html, consisting of this: <body onload="document.form.submit();"> <FORM
       name="form" action="[scratchd acsurl]" method="POST" /> <input type="hidden" name="PaReq" value="[scratch
       pareq]" /> <input type="hidden" name="TermUrl" value="[scratch termurl]" /> <input type="hidden"
       name="MD" value="[scratch md]" /> </form> </body> along with whatever <noscript> equivalent you want.
       This will retrieve the bank's page within the iframe.

       Add a page in pages/ord/, tdsreturn.html, consisting of this:      [charge route="sagepay"
       sagepayrequest="3dsreturn"]      <p>         <blockquote>
               <font color="__CONTRAST__">
                       [error all=1 keep=1 show_error=1 show_label=1 joiner="<br>"]
               </font>
              </blockquote>

       The iframe in 'tdsfinal' will be populated with the contents of 'tdsauth', and the javascript will
       automatically display the bank's authentication page. When the customer clicks 'Submit' at the bank's
       page, the iframe contents will be replaced with the 'tdsreturn' page, which will complete the route and
       display the receipt inside the iframe. If the customer clicks 'cancel' at the bank, then this 'tdsreturn'
       page will stay put and display whatever message you have put there along with the error message.  The
       value of [scratch tds] is set true for a 3DSecure transaction only, so can be used for messages etc on
       the receipt page.

       8. When running a card through 3DSecure, the route is run twice: firstly to Sagepay who check whether or
       not the card is part of 3DSecure - if it is they send the customer to the bank's authentication page and
       upon returning from that the route must be run a second time to send the authentication results to
       Sagepay. The second run is initiated from the 'ord/tdsreturn' page, not from etc/log_transaction as it
       normally would be. To handle this change to the normal system flow you need to alter log_transaction to
       make the call to the payment module conditional,ie, wrap the following code around the "[charge
       route...]" call found in ln 172 (or nearby):      [if scratchd mstatus eq success]      [tmp
       name="charge_succeed"][scratch order_id][/tmp]      [else]      [tmp name="charge_succeed"][charge
       route="[var MV_PAYMENT_MODE]" amount="[scratch tmp_remaining]" order_id="[value
       mv_transaction_id]"][/tmp]      [/else]      [/if] If the first call to Sagepay returns a request to send
       the customer to the 3DSecure server, then IC will write a payment route error to the error log prior to
       sending the customer there. This error stops the route completing and lets the 3DSecure process proceed
       as it should. This error is not raised if the card is not part of 3DSecure, and instead the route
       completes as it normally would.

       Also add this line just after '&final = yes' near the end of the credit_card section of
       etc/profiles.order:      &set=mv_payment_route sagepay

       9. Add these new fields into log_transaction, to record the values returned from Sagepay (these will be
       key in identifying transactions and problems in any dispute with them):

       mv_credit_card_type: [calc]$Session->{payment_result}{CardType}[/calc] mv_credit_card_issue_number:
       [value mv_credit_card_issue_number] txtype:  [calc]$Session->{payment_result}{TxType};[/calc] vpstxid:
       [calc]$Session->{payment_result}{VPSTxID};[/calc] txauthno:
       [calc]$Session->{payment_result}{TxAuthNo};[/calc] securitykey:
       [calc]$Session->{payment_result}{SecurityKey};[/calc] vendortxcode:
       [calc]$Session->{payment_result}{VendorTxCode};[/calc] avscv2:
       [calc]$Session->{payment_result}{AVSCV2};[/calc]
       addressresult:[calc]$Session->{payment_result}{AddressResult};[/calc] postcoderesult:
       [calc]$Session->{payment_result}{PostCodeResult};[/calc] cv2result:
       [calc]$Session->{payment_result}{CV2Result};[/calc]
       securestatus:[calc]$Session->{payment_result}{SecureStatus};[/calc] pares:
       [calc]$Session->{payment_result}{PaRes};[/calc] md: [calc]$Session->{payment_result}{MD};[/calc] cavv:
       [calc]$Session->{payment_result}{CAVV};[/calc] and add these into your MySQL or Postgres transactions
       table, as type varchar(128) except for 'pares' which should be type 'text'.

       Note that there is no 'TxAuthNo' returned for a successful AUTHENTICATE.

PREREQUISITES

         Net::SSLeay
           or
         LWP::UserAgent and Crypt::SSLeay

         wget - a recent version built with SSL and supporting the 'connect' timeout function.

DESCRIPTION

       The Vend::Payment::SagePay module implements the SagePay() routine for use with Interchange. It is _not_
       compatible on a call level with the other Interchange payment modules - SagePay does things rather
       differently.

       To enable this module, place this directive in "interchange.cfg":

           Require module Vend::Payment::SagePay

       This must be in interchange.cfg or a file included from it.

       Make sure CreditCardAuto is off (default in Interchange demos).

The active settings.

       The module uses several of the standard settings from the Interchange payment routes.  Any such setting,
       as a general rule, is obtained first from the tag/call options on a page, then from an Interchange order
       Route named for the mode in catalog.cfg, then a default global payment variable in products/variable.txt,
       and finally in some cases a default will be hard-coded into the module.

       Mode
           The  mode can be named anything, but the "gateway" parameter must be set to "sagepay". To make it the
           default payment gateway for all credit card transactions in  a  specific  catalog,  you  can  set  in
           "catalog.cfg":

               Variable   MV_PAYMENT_MODE  sagepay
           or in variable.txt:
               MV_PAYMENT_MODE sagepay (tab separated)

           if  you  want  this  to  cooperate  with  other  payment  systems,  eg  PaypalExpress,  then  see the
           documentation that comes with that system - it should be fully explained there.

       id  Your SagePay vendor ID, supplied by SagePay when  you  sign  up.  Various  ways  to  state  this:  in
           variable.txt:
               MV_PAYMENT_ID   YourSagePayID Payment or in catalog.cfg either of:
               Route sagepay id YourSagePayID
               Variable MV_PAYMENT_ID      YourSagePayID or on the page
               [charge route=sagepay id=YourSagePayID]

       txtype
           The  transaction  type is one of: PAYMENT, AUTHENTICATE, DEFERRED for an initial purchase through the
           catalogue, and then can be one of: AUTHORISE, REFUND, RELEASE, VOID,  ABORT  for  payment  operations
           through the virtual terminal.

           The  transaction  type  is taken firstly from a dynamic variable in the page, meant primarily for use
           with the 'virtual payment terminal', viz: 'transtype' in a select box though this could  usefully  be
           taken  from  a  possible  entry in the products database if you have different products to be sold on
           different terms; then falling back to a 'Route txtype PAYMENT' entry  in  catalog.cfg;  then  falling
           back  to  a  global  variable  in  variable.txt,  eg 'MV_PAYMENT_TXTYPE PAYMENT Payment'; and finally
           defaulting to 'PAYMENT' hard-coded into the module. This variable  is  returned  to  the  module  and
           logged  using  the  value returned from SagePay, rather than a value from the page which possibly may
           not exist.

       available
           If 'yes', then the module will check that the gateway is responding before sending  the  transaction.
           If  it  fails to respond within 9 seconds, then the module will go 'off line' and log the transaction
           as though this module had not been called. It will also log the txtype as 'OFFLINE' so that you  know
           you  have  to put the transaction through manually later (you will need to capture the card number to
           do this). The point of this is that your customer has the transaction done and  dusted,  rather  than
           being  told to 'try again later' and leaving for ever. If not explicitly 'yes', defaults to 'no'. NB:
           if  you  set  this  to  'yes',  then  add  into  the  etc/report  that  is  sent  to  you:  Txtype  =
           [calc]$Session->{payment_result}{TxType};[/calc]. Note that you need to have a recent version of wget
           which  supports  '--connect-timeout'  to  run this check. Note also that, as this transaction has not
           been logged anywhere on the SagePay server, you cannot use their terminal to process it. You must use
           a virtual terminal which includes a function for this purpose, and updates the existing order  number
           with  the new payment information returned from SagePay. Note further that if you have SagePay set up
           to require the CV2 value, then virtual terminal should disable CV2 checking at  run-time  by  default
           for  such  a  transaction  (logging  the  CV2  value  breaks Visa/MC rules and so it can't be legally
           available for this process).

       logzero
           If 'yes', then the module will log a transaction even if the amount sent is zero (which  the  gateway
           would  normally  reject). The point of this is to allow a zero amount in the middle of a subscription
           billing series for audit purposes. If not explicitly 'yes', defaults to 'no'.   Note:  this  is  only
           useful if you are using an invoicing system or the Payment Terminal, both of which by-pass the normal
           IC  processes.  IC  will  allow  an  item to be processed at zero total price but simply bypasses the
           gateway when doing so.

       logempty If 'yes, then if the response from SagePay is read as empty (ie, zero bytes) then the module
       will use the VendorTxID to check on the Sagepay txstatus page to see if that transaction has been logged.
       If it has then the result found on that page will be used to push the result to either success or failure
       and log accordingly. There are two markers set to warn of this: $Session->{payment_result}{TxType} will
       be NULL, $Session->{payment_result}{StatusDetail} will be: 'UNKNOWN status - check with SagePay before
       dispatching goods' and you should include these into the report emailed to you. It will also call a
       logorder Usertag to log a backup of the order: if you don't already have this then get it from
       ftp.zolotek.net/mv/logorder.tag
           If the result is not found on that txstatus page then the result  is  forced  to  'failure'  and  the
           transaction shown as failed to the customer.

       card_type
           SagePay  requires  that the card type be sent. Valid types are: VISA, MC, AMEX, DELTA, SOLO, MAESTRO,
           UKE, JCB, DINERS (UKE is Visa Electron issued in the UK).

           You may display a select box on the checkout page like so:

                         <select name=mv_credit_card_type>
                     [loop
                             option=mv_credit_card_type
                             acclist=1
                             list=|
           VISA=Visa,
           MC=MasterCard,
           SOLO=Solo,
           DELTA=Delta,
           MAESTRO=Maestro,
           AMEX=Amex,
           UKE=Electron,
           JCB=JCB,
           DINERS=Diners|]
                     <option value="[loop-code]"> [loop-param label]
                     [/loop]
                     </select>

       currency
           SagePay requires that a currency code be sent, using the 3 letter ISO  currency  code  standard,  eg,
           GBP,  EUR,  USD.  The  value  is  taken firstly from either a page setting or a possible value in the
           products database, viz 'iso_currency_code'; then falling back to the locale setting -  for  this  you
           need to add to locale.txt:

               code    en_GB   en_EUR  en_US
               iso_currency_code   GBP EUR USD

           It  then falls back to a 'Route sagepay currency EUR' type entry in catalog.cfg; then falls back to a
           global variable (eg MV_PAYMENT_CURRENCY EUR Payment); and finally defaults to GBP hard-coded into the
           module. This variable is returned to the module and logged using the  value  returned  from  SagePay,
           rather than a value from the page which possibly may not exist.

       cvv2
           This is sent to SagePay as mv_credit_card_cvv2. Put this on the checkout page:

               <b>CVV2: &nbsp; <input type=text name=mv_credit_card_cvv2 size=6></b>

           but note that under Card rules you must not log this value anywhere.

       issue_number
           This is used for some debit cards, and taken from an input box on the checkout page:

               Card issue number: <input type=text name=mv_credit_card_issue_number value='' size=6>

       mvccStartDate
           This  is  used for some debit cards, and is taken from select boxes on the checkout page in a similar
           style to those for the card expiry date. The labels to  be  used  are:  'mv_credit_card_start_month',
           'mv_credit_card_start_year'. Eg:

                             <select name=mv_credit_card_start_year>
                             [loop option=start_date_year lr=1 list=`
                             my $year = $Tag->time( '', { format => '%Y' }, '%Y' );
                             my $out = '';
                             for ($year - 7 .. $year) {
                                             /\d\d(\d\d)/;
                                             $last_two = $1;
                                             $out .= "$last_two\t$_\n";
                             }
                             return $out;
                             `]
                             <option value="[loop-code]"> [loop-pos 1]
                             [/loop]
                             </select>

           Make the select box for the start month a copy of the existing one for the expiry month, but with the
           label  changed  and  the  addition  of  = --select --, as the first entry. This intentionally returns
           nothing for that selection and prevents the StartDate being sent.

       SagePay API v2.23 extra functions ApplyAVSCV2 set to: 0 = If AVS/CV2 enabled then check them.  If rules
       apply, use rules. (default) 1 = Force AVS/CV2 checks even if not enabled for the account. If rules apply,
       use rules. 2 = Force NO AVS/CV2 checks even if enabled on account. 3 = Force AVS/CV2 checks even if not
       enabled for the account but DON'T apply any rules. You may pass this value from the page as 'applyavscv2'
       to override the payment route setting. They also have Paypal integrated into this version, but I have no
       interest in implementing Paypal through Sagepay. There is a separate PaypalExpress module for that.
           ContactFax: optional GiftAidPayment: set to -      0 = This transaction is not a Gift Aid  charitable
           donation(default)      1 = This payment is a Gift Aid charitable donation and the customer has AGREED
           to donate the tax.       You may pass this value from the page as 'giftaidpayment'

           ClientIPAddress: will show in SagePay reports, and they will attempt to Geo-locate the IP.

       AVSCV2 SagePay do not use your rulebase or return any checks for these when using 3ds and AUTHORISE. As
       this data is essential for many business models you should use DEFERRED instead. While thought was given
       to running a PAYMENT and VOID for AX1 first, simply to get the AVSCV2 results, this cannot be done with
       Maestro cards which legally must go through 3ds and so I have abandoned the idea.
       Encrypted email with card info
           If  you  want  to add the extra fields (issue no, start date) to the PGP message emailed back to you,
           then set the following in catalog.cfg:

           Variable<tab>MV_CREDIT_CARD_INFO_TEMPLATE    Card    type:    {MV_CREDIT_CARD_TYPE};     Card     no:
           {MV_CREDIT_CARD_NUMBER};   Expiry:  {MV_CREDIT_CARD_EXP_MONTH}/{MV_CREDIT_CARD_EXP_YEAR};  Issue  no:
           {MV_CREDIT_CARD_ISSUE_NUMBER}; StartDate: {MV_CREDIT_CARD_START_MONTH}/{MV_CREDIT_CARD_START_YEAR}

       testing
           The SagePay test site is test.sagepay.com, and their live site is  live.sagepay.com.  Enable  one  of
           these  in  MV_PAYMENT_HOST in variable.txt (*without* any leading https://) or as 'Route sagepay host
           test.sagepay.com' in catalog.cfg. Be aware that the test site is not an exact  replica  of  the  live
           site,  and  errors  there  can be misleading. In particular the "SecureStatus" returned from the test
           site is liable to be 'NOTAUTHED' when the live site will return 'OK'.

       methods
           An AUTHENTICATE will check that the card is not stolen and contains sufficient funds.   SagePay  will
           keep  the details, so that you may settle against this a month or more later. Against an AUTHENTICATE
           you may do an AUTHORISE (which settles the transaction).

           A DEFERRED will place a shadow ('block') on the funds  for  seven  days  (or  so,  depending  on  the
           acquiring bank). Against a DEFERRED you may do a RELEASE to settle the transaction.

           A PAYMENT will take the funds immediately. Against a PAYMENT, you may do a REFUND or REPEAT.

           A REPEAT may be performed against an AUTHORISE or a PAYMENT. This will re-check and take the funds in
           real time. You may then REPEAT a REPEAT, eg for regular subscriptions. As you need to send the amount
           and  currency  with  each  REPEAT,  you  may  vary  the  amount  of the REPEAT to suit a variation in
           subscription fees.

           A RELEASE is performed to settle a DEFERRED. Payment of the originally specified amount is guaranteed
           if the RELEASE is performed within the seven days for which the card-holder's funds are 'blocked'.

           A REFUND may be performed against a PAYMENT, RELEASE, or REPEAT. It may be for a  partial  amount  or
           the  entire  amount,  and  may be repeated with several partial REFUNDs so long as the total does not
           exceed the original amount.

           A DIRECTREFUND sends funds from your registered bank account to the nominated credit card.  This does
           not need to refer to any previous transaction codes, and is useful if you need to make a  refund  but
           the customer's card has changed or the original purchase was not made by card.

   Troubleshooting
       Try a sale with  any other test number given by SagePay, eg:      Visa VISA 4929 0000 0000 6
           Mastercard  MC 5404 0000 0000 0001
           Delta DELTA 4462 0000 0000 0000 0003
           Visa Electron UK Debit   UKE       4917300000000008
           Solo SOLO 6334 9000 0000 0000 0005 issue no 1
           Switch (UK Maestro) MAESTRO 5641 8200 0000 0005 issue no 01.
           Maestro MAESTRO 300000000000000004      AmericanExpress AMEX     3742 0000 0000 004

       You  need  these  following  values  to  ensure a positive response: CV2: 123 Billing Address: 88 Billing
       PostCode: 412 and the password at their test server is 'password'.

       If nothing works:

       •   Make sure you "Require"d the module in interchange.cfg:

               Require module Vend::Payment::SagePay

       •   Make sure either Net::SSLeay or Crypt::SSLeay and LWP::UserAgent are installed and working.  You  can
           test to see whether your Perl thinks they are:

               perl -MNet::SSLeay -e 'print "It works\n"'
           or
               perl -MLWP::UserAgent -MCrypt::SSLeay -e 'print "It works\n"'

           If  either  one  prints "It works." and returns to the prompt you should be OK (presuming they are in
           working order otherwise).

       •   Check the error logs, both catalogue and global. Make sure you set your payment parameters  properly.
           Try an order, then put this code in a page:

               <XMP>
               [calc]
                   my $string = $Tag->uneval( { ref => $Session->{payment_result} });
                   $string =~ s/{/{\n/;
                   $string =~ s/,/,\n/g;
                   return $string;
               [/calc]
               </XMP>

           That should show what happened.

       •   If  you  have  a PGP/GPG failure when placing an order through your catalogue then this may cause the
           module to be immediately re-run. As the first run would have been successful, meaning that  both  the
           basket  and the credit card information would have been emptied, the second run will fail. The likely
           error message within the catalogue will be: "Can't figure out credit card expiration". Fixing PGP/GPG
           will fix this error.

           If you get the same error message within the Virtual Terminal, then you haven't set the  order  route
           as noted above.

       •   If all else fails, Zolotek and other consultants are available to help with integration for a fee.

AUTHORS

       Lyn St George <info@zolotek.net>, based on original code by Mike Heins <mike@perusion.com> and others.

   CREDITS Hillary Corney (designersilversmiths.co.uk), Jamie Neil (versado.net), Andy Mayer (andymayer.net) for
       testing and suggestions.
perl v5.14.2                                       2011-03-09                        Vend::Payment::SagePay(3pm)