[bop-devel] Proposed - Barclaycard EPDQextra Plus API Direct Link Integration

Simon Waters simonw at zynet.net
Wed Jan 23 07:15:24 PST 2013


Okay, my first stab - which works with my test scripts for "Normal 
Authorization" only.

Basically:

1) It multiplies "amount" by 100 (or sets to invalid)
2) Remaps fields
3) Ensure the SHA hash parameter is created correctly
4) Parses the response codes

Otherwise it is fairly vanilla HTTPS

Heavily based on TCLink.pm

Currently the test server is "hardwired", and I haven't tried 
implementing any of the authentication only responses.

I've mostly answered my own questions.

Things I know now.....

Yes I should use Business::OnlinePayment::HTTPS

get_fields and remap_fields methods are in OnlinePayment.pm now - it was 
in the copy of TCLink.pm I worked from, but that one needs bringing up 
to speed as well. So I should just be able to delete these.

I still don't know the preferred format for expiration date in the caller.

This provider wants a "customer name" but BOP seems to offer both "name" 
and "first_name" "last_name. I suspect it can be safely left to 
implementers.

Wouldn't recommend anyone else uses the code yet, on the other hand it 
may save someone a little time if they are using BOP already.

I've no idea how to do the error handling. Fortunately most things that 
don't make sense already fail in "required fields" or fail at 
Barclaycard end and thus get a suitable error back.

EPDQ also has optional ECI field for whether card is present etc. I've 
ignored it for the moment, although some transactions failed with "CVC 
is required" which makes me think that I may need to set it to 9 for 
some types of request we do.

Any constructive criticism or advice welcome.

  Simon



Business::OnlinePayment::EPDQPLUS.pm

package Business::OnlinePayment::EPDQPLUS;

use base qw( Business::OnlinePayment::HTTPS );

use strict;
use warnings;

use Business::OnlinePayment::HTTPS;
use URI::Escape qw/uri_escape/;
use Digest::SHA qw/sha1_base64/;
use XML::Simple;

use vars qw($VERSION $DEBUG);

$VERSION = '0.01';
$DEBUG=1;

sub set_defaults {
     my $self = shift;

     $self->server('mdepayments.epdq.co.uk') unless $self->server; # 
Test server - live is "payments.epdq.co.uk"
     $self->port('443') unless $self->port;
     $self->path('/ncol/test/orderdirect.asp') unless $self->path; # 
Test server - live is "/ncol/prod/orderdirect.asp

}

sub map_fields {
     my($self) = @_;

     my %content = $self->content();

     my %actions = ('normal authorization' => 'SAL', # Only one implemented
                    'authorization only'   => 'RES', # from Barclays 
docs 4.3.3
                    'credit'               => 'RFD', # from Barclays 
docs 4.3.3
                   );

     $content{'action'} = $actions{lc($content{'action'} || '')} || 
$content{'action'};

     my $amount = $content{'amount'};

     if ( $amount =~ /-?\d*\.\d\d/ ) { # Match a number with two decimal 
places
       $content{'amount'} = int(100*$amount);
     } else {
       $content{'amount'}='invalid amount';
     }


     $self->content(%content);
}

sub remap_fields {
     my($self,%map) = @_;

     my %content = $self->content();
     foreach(keys %map) {
         $content{$map{$_}} = $content{$_};
     }
     $self->content(%content);
}

sub get_fields {
     my($self, at fields) = @_;

     my %content = $self->content();
     my %new = ();
     foreach( grep defined $content{$_}, @fields) { $new{$_} = 
$content{$_}; }
     return %new;
}

sub submit {
     my($self) = @_;

     $self->map_fields();
     $self->remap_fields(
#        type              => '',
	pspid		  => 'PSPID',
         login             => 'USERID',
         password          => 'PSWD',
	shasign		  => 'SHASIGN',
         action            => 'OPERATION',
         description       => 'COM',
         name		  => 'CN',
         amount            => 'AMOUNT', # Note Barclays expect this in 
cents or pence thus $13.23 is transformed to 1323 and £142.00 is 14200
         currency          => 'CURRENCY', # USD GBP EUR other - must 
have Multi-currency store with Barclays
	order_number      => 'ORDERID',
         customer_ip       => 'REMOTE_ADDR',
         address           => 'OWNERADDRESS',
         city              => 'OWNERTOWN',
         zip               => 'OWNERZIP',
         country           => 'OWNERCTY', # As ISO country code GB, US, etc
         ship_last_name    => 'ECOM_SHIPTO_POSTAL_NAME_LAST', # SHIPTO 
fields not yet tested
         ship_first_name   => 'ECOM_SHIPTO_POSTAL_NAME_FIRST',
         ship_company      => 'ECOM_SHIPTO_COMPANY',
         ship_address      => 'ECOM_SHIPTO_POSTAL_STREET_LINE1',
         ship_city         => 'ECOM_SHIPTO_POSTAL_CITY',
         ship_zip          => 'ECOM_SHIPTO_POSTAL_POSTCODE',
         ship_country      => 'ECOM_SHIPTO_POSTAL_COUNTRYCODE', # ISO 
country code GB, US, etc
         phone             => 'OWNERTELNO',
         email_customer    => 'EMAIL',
         card_number       => 'CARDNO',
         expiration        => 'ED',
         cvv2              => 'CVC',
     );

     my @required_fields = ( qw(pspid login password shasign action 
amount currency card_number expiration) );

     $self->required_fields(@required_fields);

     my %post_data = $self->get_fields(qw/
       PSPID USERID PSWD
       OPERATION COM CN AMOUNT CURRENCY ORDERID CARDNO ED CVC
       REMOTE_ADDR
       OWNERADDRESS OWNERTOWN OWNERZIP OWNERCTY OWNERTELNO EMAIL
       ECOM_SHIPTO_POSTAL_NAME_LAST ECOM_SHIPTO_POSTAL_NAME_FIRST 
ECOM_SHIPTO_COMPANYi
       ECOM_SHIPTO_POSTAL_STREET_LINE1 ECOM_SHIPTO_POSTAL_CITY 
ECOM_SHIPTO_POSTAL_POSTCODE ECOM_SHIPTO_POSTAL_COUNTRYCODE
         /);

      # Compute a suitable SHA1 sum for the transaction.

      my $SHATEXT;
      my %content = $self->content();
      foreach my $key (sort keys %post_data) {

     	$SHATEXT.=$key."=".$post_data{$key}.$content{'SHASIGN'};
      }


      my $SHAHASH= sha1_base64($SHATEXT);

      print "SHA TEXT IS $SHATEXT\n" if $DEBUG;
      print "Hash is $SHAHASH\n" if $DEBUG;

      $post_data{'SHASIGN'}=$SHAHASH;


     my $opt = {};

     my($page, $server_response, %headers) =
       $self->https_post( $opt, \%post_data );

     $self->server_response($page);
     $self->response_headers(%headers);

#??? IF SUCCEEDED

     my $result = XMLin($page);

#print Dumper($result);

#print "Result is: ",$result->{STATUS},"\n";
#print "Error is: ",$result->{NCERROR},"\n";
#print "Error message is: ",$result->{NCERRORPLUS},"\n";

     my $status=$result->{STATUS};
     my $ncerror=$result->{NCERROR};

     if ( $status eq 9 and $ncerror eq 0 ){

       $self->is_success(1);
       $self->result_code($result->{ACCEPTANCE});
       $self->authorization($result->{PAYID});

     } else {

       $self->is_success(0);
       $self->result_code($result->{ACCEPTANCE});
       $self->error_message("Failed: Status: $status, Error: $ncerror, 
Message:".$result->{NCERRORPLUS});
     }

}

1;
__END__

=head1 NAME

Business::OnlinePayment::EPDQPLUS - Barclaycard EPDQplus API Direct Link

Dev version - not released

=head1 DESCRIPTION

This module provides access to the Barclaycard EPDQplus Direct Link API 
and documented in v4.3.3 of the
Barclay Integration guide.

It is currently a work in progress.

To use/test this module you will need:
  PSPID - Barclaycard supplied credential
  "admin" user for the api with password (login and password) in the 
Barclaycard backend as per the online help.
  SHA signing secret defined for API access (strictly this is optional 
the Barclaycard interface by the module assumed you will use it)

Currently implemented - "Normal Authorization" (Operation "SAL").

=head USAGE

use Business::OnlinePayment;

   my $tx = Business::OnlinePayment->new("EPDQPLUS");

   $tx->content(
       pspid          => 'see above',
       login          => 'added via Barclaycard Backoffice',
       password       => 'set via Barclaycard Backoffice'
       shasign	     => 'set via Barclaycard Backoffice',

       action         => 'Normal Authorization',
       description    => '20 English Roses',
       amount         => '49.95',
       currency       => 'USD',
       order_number   => 'ORDER0001',

       name           => 'B Obama',
       address        => 'Whitehouse, 1600 Pennsylvannia Road',

       city           => 'Washington DC',
       zip            => 'DC 20500',
       country        => 'US',
       phone          => '',

       card_number    => '5569510117486571',
       expiration     => '0515', # MMYY is a Barclay card format -- what 
does BOP expect
       cvv2            => '377',
   );

   $tx->submit();

   print "server_response = ", $tx->server_response, "\n";
   print "is_success      = ", $tx->is_success,      "\n";
   print "authorization   = ", $tx->authorization,   "\n";
   print "error_message   = ", $tx->error_message,   "\n\n";
   print "result_code     = ", $tx->result_code,     "\n";

=head1 AUTHOR

Simon Waters <simonw at zynet.net>

Derived from code by Jason Kohles and Ivan Kohler and Dan Helfman

=head1 SEE ALSO

perl(1). L<Business::OnlinePayment>

=cut


More information about the bop-devel mailing list