Initial import
authorfbriere <fbriere>
Mon, 13 Feb 2006 21:10:31 +0000 (21:10 +0000)
committerfbriere <fbriere>
Mon, 13 Feb 2006 21:10:31 +0000 (21:10 +0000)
Changes [new file with mode: 0755]
InternetSecure.pm [new file with mode: 0755]
MANIFEST [new file with mode: 0755]
Makefile.PL [new file with mode: 0755]
README [new file with mode: 0755]
t/10base.t [new file with mode: 0755]
t/20emit.t [new file with mode: 0755]
t/30parse.t [new file with mode: 0755]
t/40live.t [new file with mode: 0755]

diff --git a/Changes b/Changes
new file mode 100755 (executable)
index 0000000..b543b30
--- /dev/null
+++ b/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension Business::OnlinePayment::InternetSecure.
+
+0.01  Sat Jul 10 16:33:05 2004
+       - original version; created by h2xs 1.23 with options
+               -X -A -n Business::OnlinePayment::InternetSecure -b 5.8.0
+
diff --git a/InternetSecure.pm b/InternetSecure.pm
new file mode 100755 (executable)
index 0000000..a6240bc
--- /dev/null
@@ -0,0 +1,562 @@
+package Business::OnlinePayment::InternetSecure;
+
+use 5.008;
+use strict;
+use warnings;
+
+use Carp;
+use Encode;
+use Net::SSLeay qw(make_form post_https);
+use XML::Simple qw(xml_in xml_out);
+
+use base qw(Business::OnlinePayment Exporter);
+
+
+our $VERSION = '0.01';
+
+
+use constant CARD_TYPES => {
+                               VI => 'Visa',
+                               MC => 'MasterCard',
+                               AX => 'American Express',
+                               NN => 'Discover',
+                       };
+
+
+# Convenience functions to avoid undefs and escape products strings
+sub _def($) { defined $_[0] ? $_[0] : '' }
+sub _esc($) { local $_ = shift; tr/|:/ /s; tr/"`/'/s; return $_ }
+
+
+sub set_defaults {
+       my ($self) = @_;
+
+       $self->server('secure.internetsecure.com');
+       $self->port(443);
+       $self->path('/process.cgi');
+
+       $self->build_subs(qw(
+                               receipt_number  sales_order_number
+                               cardholder      card_type
+                               total_amount
+                               avs_response    cvv2_response
+                       ));
+}
+
+# OnlinePayment's remap_fields is buggy, so we simply rewrite it
+#
+sub remap_fields {
+       my ($self, %map) = @_;
+
+       my %content = $self->content();
+       foreach (keys %map) {
+               $content{$map{$_}} = delete $content{$_};
+       }
+       $self->content(%content);
+}
+
+# Combine get_fields and remap_fields for convenience
+#
+sub get_remap_fields {
+       my ($self, %map) = @_;
+
+       $self->remap_fields(reverse %map);
+       my %data = $self->get_fields(keys %map);
+
+       foreach (values %data) {
+               $_ = '' unless defined;
+       }
+
+       return %data;
+}
+
+# Since there's no standard format for expiration dates, we try to do our best
+#
+sub parse_expdate {
+       my ($self, $str) = @_;
+
+       local $_ = $str;
+
+       my ($y, $m);
+
+       if (/^(\d{4})\W(\d{1,2})$/ ||           # 2004.07  or  2004-7
+                       /^(\d\d)\W(\d)$/ ||     # 04/7
+                       /^(\d\d)[.-](\d\d)$/) { # 04-07
+               ($y, $m) = ($1, $2);
+       } elsif (/^(\d{1,2})\W(\d{4})$/ ||      # 07-2004  or  7/2004
+                       /^(\d)\W(\d\d)$/ ||     # 7/04
+                       /^(\d\d)\/(\d\d)$/) {   # 07/04
+               ($y, $m) = ($2, $1);
+       } else {
+               croak "Unable to parse expiration date: $str";
+       }
+
+       $y += 2000 if $y < 2000;  # Aren't we glad Y2K is behind us?
+
+       return ($y, $m);
+}
+
+# Convert a single product into a product string
+#
+sub prod_string {
+       my ($self, $currency, $taxes, %data) = @_;
+
+       croak "Missing amount in product" unless defined $data{amount};
+
+       my @flags = ($currency);
+
+       $taxes = uc $data{taxes} if defined $data{taxes};
+       foreach (split ' ' => $taxes) {
+               croak "Unknown tax code $_" unless /^(GST|PST|HST)$/;
+               push @flags, $_;
+       }
+
+       if ($self->test_transaction) {
+               push @flags, $self->test_transaction < 0 ? 'TESTD' : 'TEST';
+       }
+
+       return join '::' =>
+                               sprintf('%.2f' => $data{amount}),
+                               $data{quantity} || 1,
+                               _esc _def $data{sku},
+                               _esc _def $data{description},
+                               join('' => map "{$_}" => @flags),
+                               ;
+}
+
+# Generate the XML document for this transaction
+#
+sub to_xml {
+       my ($self) = @_;
+
+       my %content = $self->content;
+
+       $self->required_fields(qw(action card_number exp_date));
+
+       croak 'Unsupported transaction type'
+               if $content{type} && $content{type} !~
+                       /^(Visa|MasterCard|American Express|Discover)$/i;
+       
+       croak 'Unsupported action'
+               unless $content{action} =~ /^Normal Authori[zs]ation$/i;
+       
+       $content{currency} ||= 'CAD';
+       $content{currency} = uc $content{currency};
+       croak "Unknown currency code ", $content{currency}
+               unless $content{currency} =~ /^(CAD|USD)$/;
+       
+       $content{taxes} ||= '';
+       $content{taxes} = uc $content{taxes};
+
+       my %data = $self->get_remap_fields(qw(
+                       xxxCardNumber           card_number
+
+                       xxxName                 name
+                       xxxCompany              company
+                       xxxAddress              address
+                       xxxCity                 city
+                       xxxProvince             state
+                       xxxPostal               zip
+                       xxxCountry              country
+                       xxxPhone                phone
+                       xxxEmail                email
+
+                       xxxShippingName         ship_name
+                       xxxShippingCompany      ship_company
+                       xxxShippingAddress      ship_address
+                       xxxShippingCity         ship_city
+                       xxxShippingProvince     ship_state
+                       xxxShippingPostal       ship_zip
+                       xxxShippingCountry      ship_country
+                       xxxShippingPhone        ship_phone
+                       xxxShippingEmail        ship_email
+               ));
+       
+       $data{MerchantNumber} = $self->merchant_id;
+
+       $data{xxxCardNumber} =~ tr/ //d;
+
+       my ($y, $m) = $self->parse_expdate($content{exp_date});
+       $data{xxxCCYear} = sprintf '%.4u' => $y;
+       $data{xxxCCMonth} = sprintf '%.2u' => $m;
+
+       if (defined $content{cvv2} && $content{cvv2} ne '') {
+               $data{CVV2} = 1;
+               $data{CVV2Indicator} = $content{cvv2};
+       } else {
+               $data{CVV2} = 0;
+               $data{CVV2Indicator} = '';
+       }
+       
+       if (ref $content{description}) {
+               $data{Products} = join '|' => map $self->prod_string(
+                                                       $content{currency},
+                                                       $content{taxes},
+                                                       %$_),
+                                               @{ $content{description} };
+       } else {
+               $self->required_fields(qw(amount));
+               $data{Products} = $self->prod_string(
+                                       $content{currency},
+                                       $content{taxes},
+                                       amount => $content{amount},
+                                       description => $content{description},
+                               );
+       }
+
+       xml_out(\%data,
+               NoAttr => 1,
+               RootName => 'TranxRequest',
+               XMLDecl => '<?xml version="1.0" encoding="utf-8" standalone="yes"?>',
+       );
+}
+
+# Map the various fields from the response, and put their values into our
+# object for retrieval.
+#
+sub infuse {
+       my ($self, $data, %map) = @_;
+
+       while (my ($k, $v) = each %map) {
+               no strict 'refs';
+               $self->$v($data->{$k});
+       }
+}
+
+# Parse the server's response and set various fields
+#
+sub parse_response {
+       my ($self, $response) = @_;
+
+       $self->server_response($response);
+       
+       # (It's not quite clear whether there should be some decoding, or if
+       # the result is already utf8.)
+
+       $response = xml_in($response,
+                       ForceArray => [qw(product flag)],
+                       GroupTags => { qw(Products product flags flag) },
+                       KeyAttr => [],
+                       SuppressEmpty => undef,
+               );
+       
+       my $code = $self->result_code($response->{Page});
+       $self->is_success($code eq '2000' || $code eq '90000' || $code eq '900P1');
+
+       $self->infuse($response, qw(
+                       ReceiptNumber           receipt_number
+                       SalesOrderNumber        sales_order_number
+                       xxxName                 cardholder
+                       CardType                card_type
+                       Page                    result_code
+                       ApprovalCode            authorization
+                       Verbiage                error_message
+                       TotalAmount             total_amount
+                       AVSResponseCode         avs_response
+                       CVV2ResponseCode        cvv2_response
+               ));
+       
+       $self->card_type(CARD_TYPES->{$self->card_type});
+       
+       $self->{products_raw} = $response->{Products};
+
+       return $self;
+}
+
+sub submit {
+       my ($self) = @_;
+
+       croak "Missing required argument 'merchant_id'"
+               unless defined $self->{merchant_id};
+
+       my ($page, $response, %headers) = 
+               post_https(
+                               $self->server,
+                               $self->port,
+                               $self->path,
+                               undef,
+                               make_form(
+                                       xxxRequestMode => 'X',
+                                       xxxRequestData => Encode::encode_utf8(
+                                                               $self->to_xml
+                                                         ),
+                               )
+                       );
+
+       croak 'Error connecting to server' unless $page;
+       croak 'Server responded, but not in XML' unless $page =~ /^<\?xml/;
+
+       $self->parse_response($page);
+}
+
+
+1;
+
+__END__
+
+
+=head1 NAME
+
+Business::OnlinePayment::InternetSecure - InternetSecure backend for Business::OnlinePayment
+
+=head1 SYNOPSIS
+
+  use Business::OnlinePayment;
+
+  $txn = new Business::OnlinePayment 'InternetSecure',
+                                       merchant_id => '0000';
+
+  $txn->content(
+       action          => 'Normal Authorization',
+
+       type            => 'Visa',
+       card_number     => '0000000000000000',
+       exp_date        => '2004-07',
+       cvv2            => '000',               # Optional
+
+       name            => "Fr\x{e9}d\x{e9}ric Bri\x{e8}re",
+       company         => '',
+       address         => '123 Street',
+       city            => 'Metropolis',
+       state           => 'ZZ',
+       zip             => 'A1A 1A1',
+       country         => 'CA',
+       phone           => '(555) 555-1212',
+       email           => 'fbriere@fbriere.net',
+
+       description     => 'Online purchase',
+       amount          => 49.95,
+       currency        => 'CAD',
+       taxes           => 'GST PST',
+       );
+
+  $txn->submit;
+
+  if ($txn->is_success) {
+       print "Card processed successfully: " . $tx->authorization . "\n";
+  } else {
+       print "Card was rejected: " . $tx->error_message . "\n";
+  }
+
+=head1 DESCRIPTION
+
+Business::OnlinePayment::InternetSecure is an implementation of
+L<Business::OnlinePayment> that allows for processing online credit card
+payments through Internet Secure.
+
+See L<Business::OnlinePayment> for more information about the generic
+Business::OnlinePayment interface.
+
+=head1 CREATOR
+
+Object creation is done via L<Business::OnlinePayment>; see its manpage for
+details.  The I<merchant_id> processor option is required, and corresponds
+to the merchant ID assigned to you by Internet Secure.
+
+=head1 METHODS
+
+(See L<Business::OnlinePayment> for more methods.)
+
+=head2 Before order submission
+
+=over 4
+
+=item content( CONTENT )
+
+Sets up the data prior to a transaction (overwriting any previous data by the
+same occasion).  CONTENT is an associative array (hash), containing some of
+the following fields:
+
+=over 4
+
+=item action (required)
+
+What to do with the transaction.  Only C<Normal Authorization> is supported
+for the moment.
+
+=item type
+
+Transaction type, being one of the following:
+
+=over 4
+
+=item - Visa
+
+=item - MasterCard
+
+=item - American Express
+
+=item - Discover
+
+=back
+
+(This is actually ignored for the moment, and can be left blank or undefined.)
+
+=item card_number (required)
+
+Credit card number.  Any spaces will be removed.
+
+=item exp_date (required)
+
+Credit card expiration date.  Since L<Business::OnlinePayment> does not
+specify any syntax, this module is rather lax in what it will accept.  It is
+recommended to use either I<YYYY-MM> or I<MM/YYYY>, to avoid any nasty
+surprises.
+
+=item cvv2
+
+Three- or four-digit verification code printed on the card.  This can be left
+blank or undefined, in which case no check will be performed.  Whether or not a
+transaction will be declined in case of a mismatch depends on the merchant.
+
+This number may be called Card Verification Value (CVV2), Card Validation
+Code (CVC2) or Card Identification number (CID).
+
+=item description
+
+A short description of the purchase.  See L<"Products list syntax"> for
+an alternate syntax that allows a list of products to be specified.
+
+=item amount
+
+Total amount to be billed, excluding taxes if they are to be added separately.
+This field is required if B<description> is a string, and should be left
+undefined if B<description> contains a list of products, as outlined in
+L<"Products list syntax">.
+
+=item currency
+
+Currency of all amounts for this order.  This can currently be either
+C<CAN> (default) or C<USD>.
+
+=item taxes
+
+Taxes to be added automatically.  These should not be included in B<amount>;
+they will be added by Internet Secure later on.
+
+Available taxes are C<GST>, C<PST> and C<HST>; multiple taxes must be
+separated by spaces.
+
+=item name / company / address / city / state / zip / country / phone / email
+
+Facultative customer information.  B<state> should be either a postal
+abbreviation or a two-letter code taken from ISO 3166-2, and B<country> should
+be a two-letter code taken from in ISO 3166-1.
+
+=back
+
+=back
+
+=head2 After order submission
+
+=over 4
+
+=item receipt_number() / sales_order_number()
+
+Receipt number and sales order number of submitted order.
+
+=item total_amount()
+
+Total amount billed for this order, including taxes.
+
+=item cardholder()
+
+Cardholder's name.  This is currently a mere copy of the B<name> field passed
+to B<submit()>.
+
+=item card_type()
+
+Type of the credit card used for the submitted order, being one of the
+following:
+
+=over 4
+
+=item - Visa
+
+=item - MasterCard
+
+=item - American Express
+
+=item - Discover
+
+=back
+
+=item avs_response() / cvv2_response()
+
+Results of the AVS and CVV2 checks.  See the Internet Secure documentation for
+the list of possible values.
+
+=back
+
+
+=head1 NOTES
+
+=head2 Products list syntax
+
+Optionally, the B<description> field of B<content()> can contain a reference
+to an array of products, instead of a simple string.  Each element of this
+array represents a different product, and must be a reference to a hash with
+the following fields:
+
+=over 4
+
+=item amount
+
+Unit price of this product.
+
+=item quantity
+
+Ordered quantity of this product.  This can be a decimal value.
+
+=item sku
+
+Internal code for this product.
+
+=item description
+
+Description of this product
+
+=item taxes
+
+Taxes that should be automatically added to this product.  If specified, this
+overrides the B<taxes> field passed to B<content()>.
+
+=back
+
+When using a products list, the B<amount> field passed to B<content()> should
+be left undefined.
+
+
+=head2 Character encodings
+
+...
+
+
+=head2 products_raw
+
+...
+
+
+=head1 EXPORT
+
+None by default.
+
+
+=head1 SEE ALSO
+
+L<Business::OnlinePayment>
+
+=head1 AUTHOR
+
+Frederic Briere, E<lt>fbriere@fbriere.netE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2004 by Frederic Briere
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/MANIFEST b/MANIFEST
new file mode 100755 (executable)
index 0000000..756d53e
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,9 @@
+InternetSecure.pm
+Changes
+Makefile.PL
+MANIFEST
+README
+t/10base.t
+t/20emit.t
+t/30parse.t
+t/40live.t
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100755 (executable)
index 0000000..e59aed9
--- /dev/null
@@ -0,0 +1,14 @@
+use 5.008;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    NAME              => 'Business::OnlinePayment::InternetSecure',
+    AUTHOR            => 'Frederic Briere <fbriere@fbriere.net>',
+    VERSION_FROM      => 'InternetSecure.pm',
+    ABSTRACT_FROM     => 'InternetSecure.pm',
+    PREREQ_PM         => {
+                               'Business::OnlinePayment'       => 0,
+                               'Net::SSLeay'                   => 0,
+                               'XML::Simple'                   => 0,
+                        },
+);
diff --git a/README b/README
new file mode 100755 (executable)
index 0000000..699e66e
--- /dev/null
+++ b/README
@@ -0,0 +1,42 @@
+Business-OnlinePayment-InternetSecure version 0.01
+==================================================
+
+ This is Business::OnlinePayment::BankOfAmerica, a Business::OnlinePayment
+ backend module for Bank of America eStores.  It is only useful if you
+ have a merchant account with Bank of America eStores:
+ http://www.bofa.com/merchantservices/index.cfm?template=merch_ic_estores_ov.cfm
+
+ It based on Business::OnlinePayment::AuthorizeNet written by Jason Kohles.
+
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+ Online tests
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+ Depends on B:OP, Net::SSLeay and XML::Simple
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2004 by Frederic Briere
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.4 or,
+at your option, any later version of Perl 5 you may have available.
+
+
diff --git a/t/10base.t b/t/10base.t
new file mode 100755 (executable)
index 0000000..2f956f2
--- /dev/null
@@ -0,0 +1,4 @@
+use Test::More tests => 2;
+
+BEGIN { use_ok('Business::OnlinePayment') };
+BEGIN { use_ok('Business::OnlinePayment::InternetSecure') };
diff --git a/t/20emit.t b/t/20emit.t
new file mode 100755 (executable)
index 0000000..a162f10
--- /dev/null
@@ -0,0 +1,143 @@
+use Test::More tests => 4 + 2;
+
+BEGIN { use_ok('Business::OnlinePayment') };
+BEGIN { use_ok('Business::OnlinePayment::InternetSecure') };
+BEGIN { use_ok('XML::Simple', qw(xml_in)) };
+BEGIN { use_ok('Encode') };
+
+use charnames ':full'; # Why doesn't this work with use_ok?
+
+use constant TRANSACTIONS => (
+       {
+               _test           => 0,
+
+               action          => 'Normal Authorization',
+
+               type            => 'Visa',
+               card_number     => '0000000000000000',
+               exp_date        => '2004-07',
+               cvv2            => '000',
+
+               name            => "Fr\N{LATIN SMALL LETTER E WITH ACUTE}d\N{LATIN SMALL LETTER E WITH ACUTE}ric Bri\N{LATIN SMALL LETTER E WITH GRAVE}re",
+               company         => '',
+               address         => '123 Street',
+               city            => 'Metropolis',
+               state           => 'ZZ',
+               zip             => 'A1A 1A1',
+               country         => 'CA',
+               phone           => '(555) 555-1212',
+               email           => 'fbriere@fbriere.net',
+
+               amount          => undef,
+               currency        => 'CAD',
+               taxes           => 'GST PST',
+
+               description => [
+                               {
+                               amount          => 9.99,
+                               quantity        => 5,
+                               sku             => 'a:001',
+                               description     => 'Some product',
+                               },
+                               {
+                               amount          => 5.65,
+                               description     => 'Shipping',
+                               },
+                               {
+                               amount          => 10.00,
+                               description     => 'Some HST example',
+                               taxes           => 'HST',
+                               },
+                               ],
+       },
+       {
+               _test           => 1,
+
+               action          => 'Normal Authorization',
+
+               type            => 'Visa',
+               card_number     => '0000000000000000',
+               exp_date        => '7/2004',
+
+               name            => "Fr\x{e9}d\x{e9}ric Bri\x{e8}re",
+
+               amount          => 12.95,
+               currency        => 'USD',
+               taxes           => '',
+               description     => "Box o' goodies",
+       },
+);
+
+
+my $txn = new Business::OnlinePayment 'InternetSecure', merchant_id => '0000';
+
+$/ = '';
+foreach (TRANSACTIONS) {
+       $txn->test_transaction(delete $_->{_test});
+       $txn->content(%$_);
+       is_deeply(
+               xml_in(Encode::encode('utf8', $txn->to_xml)),
+               xml_in(scalar <DATA>)
+       ); 
+}
+
+
+__DATA__
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<TranxRequest>
+  <MerchantNumber>0000</MerchantNumber>
+  <xxxCardNumber>0000000000000000</xxxCardNumber>
+  <xxxCCMonth>07</xxxCCMonth>
+  <xxxCCYear>2004</xxxCCYear>
+  <CVV2>1</CVV2>
+  <CVV2Indicator>000</CVV2Indicator>
+  <Products>9.99::5::a 001::Some product::{CAD}{GST}{PST}|5.65::1::::Shipping::{CAD}{GST}{PST}|10.00::1::::Some HST example::{CAD}{HST}</Products>
+  <xxxName>Frédéric Brière</xxxName>
+  <xxxCompany></xxxCompany>
+  <xxxAddress>123 Street</xxxAddress>
+  <xxxCity>Metropolis</xxxCity>
+  <xxxProvince>ZZ</xxxProvince>
+  <xxxPostal>A1A 1A1</xxxPostal>
+  <xxxCountry>CA</xxxCountry>
+  <xxxPhone>(555) 555-1212</xxxPhone>
+  <xxxEmail>fbriere@fbriere.net</xxxEmail>
+  <xxxShippingName></xxxShippingName>
+  <xxxShippingCompany></xxxShippingCompany>
+  <xxxShippingAddress></xxxShippingAddress>
+  <xxxShippingCity></xxxShippingCity>
+  <xxxShippingProvince></xxxShippingProvince>
+  <xxxShippingPostal></xxxShippingPostal>
+  <xxxShippingCountry></xxxShippingCountry>
+  <xxxShippingPhone></xxxShippingPhone>
+  <xxxShippingEmail></xxxShippingEmail>
+</TranxRequest>
+
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<TranxRequest>
+  <MerchantNumber>0000</MerchantNumber>
+  <xxxCardNumber>0000000000000000</xxxCardNumber>
+  <xxxCCMonth>07</xxxCCMonth>
+  <xxxCCYear>2004</xxxCCYear>
+  <CVV2>0</CVV2>
+  <CVV2Indicator></CVV2Indicator>
+  <Products>12.95::1::::Box o' goodies::{USD}{TEST}</Products>
+  <xxxName>Frédéric Brière</xxxName>
+  <xxxCompany></xxxCompany>
+  <xxxAddress></xxxAddress>
+  <xxxCity></xxxCity>
+  <xxxProvince></xxxProvince>
+  <xxxPostal></xxxPostal>
+  <xxxCountry></xxxCountry>
+  <xxxPhone></xxxPhone>
+  <xxxEmail></xxxEmail>
+  <xxxShippingName></xxxShippingName>
+  <xxxShippingCompany></xxxShippingCompany>
+  <xxxShippingAddress></xxxShippingAddress>
+  <xxxShippingCity></xxxShippingCity>
+  <xxxShippingProvince></xxxShippingProvince>
+  <xxxShippingPostal></xxxShippingPostal>
+  <xxxShippingCountry></xxxShippingCountry>
+  <xxxShippingPhone></xxxShippingPhone>
+  <xxxShippingEmail></xxxShippingEmail>
+</TranxRequest>
+
diff --git a/t/30parse.t b/t/30parse.t
new file mode 100755 (executable)
index 0000000..8780731
--- /dev/null
@@ -0,0 +1,163 @@
+use Test::More tests => 1 + 2 * 5;
+
+BEGIN { use_ok('Business::OnlinePayment') };
+
+
+use constant FIELDS => (qw( result_code authorization total_amount ));
+
+use constant RESULTS => (
+               [ 1, '2000', 'T00000', 3.88 ],
+               [ 0, '98e05', undef, 3.88 ],
+       );
+
+
+my $txn = new Business::OnlinePayment 'InternetSecure', merchant_id => '0000';
+
+$/ = '';
+foreach (RESULTS) {
+       my @results = @$_;
+
+       my $xml = <DATA>;
+       $txn->parse_response($xml);
+
+       is($txn->server_response, $xml, 'server_response');
+
+       if (shift @results) {
+               ok($txn->is_success, 'expecting success');
+       } else {
+               ok(!$txn->is_success, 'expecting failure');
+       }
+
+       foreach (FIELDS) {
+               no strict 'refs';
+               is($txn->$_, shift @results, $_);
+       }
+}
+
+
+__DATA__
+<?xml version="1.0" encoding="UTF-8"?>
+<TranxResponse>
+  <MerchantNumber>4994</MerchantNumber>
+  <ReceiptNumber>1096019995.5012</ReceiptNumber>
+  <SalesOrderNumber>0</SalesOrderNumber>
+  <xxxName>John Smith</xxxName>
+  <Date>2003/12/17 09:59:58</Date>
+  <CardType>Test Card Number</CardType>
+  <Page>2000</Page>
+  <ApprovalCode>T00000</ApprovalCode>
+  <Verbiage>Test Approved</Verbiage>
+  <TotalAmount>3.88</TotalAmount>
+  <Products>
+    <product>
+      <code>001</code>
+      <description>Test Product 1</description>
+      <quantity>1</quantity>
+      <price>3.10</price>
+      <subtotal>3.10</subtotal>
+      <flags>
+        <flag>{USD}</flag>
+       <flag>{GST}</flag>
+       <flag>{TEST}</flag>
+      </flags>
+    </product>
+    <product>
+      <code>010</code>
+      <description>Test Product 2</description>
+      <quantity>1</quantity>
+      <price>0.20</price>
+      <subtotal>0.20</subtotal>
+      <flags>
+       <flag>{GST}</flag>
+       <flag>{TEST}</flag>
+      </flags>
+    </product>
+    <product>
+      <code>020</code>
+      <description>Test Product 3</description>
+      <quantity>1</quantity>
+      <price>0.33</price>
+      <subtotal>0.33</subtotal>
+      <flags>
+       <flag>{GST}</flag>
+       <flag>{TEST}</flag>
+      </flags>
+    </product>
+    <product>
+      <code>GST</code>
+      <description>Canadian GST Charged</description>
+      <quantity>1</quantity>
+      <price>0.25</price>
+      <subtotal>0.25</subtotal>
+      <flags>
+        <flag>{TAX}</flag>
+       <flag>{CALCULATED}</flag>
+      </flags>
+    </product>
+  </Products>
+  <DoubleColonProducts>3.10::1::001::Test Product 1::{USD}{GST}{TEST}|0.20::1::010::Test Product 2::{GST}{TEST}|0.33::1::020::Test Product 3::{GST}{TEST}|0.25::1::GST::Canadian GST Charged::{TAX}{CALCULATED}</DoubleColonProducts>
+  <AVSResponseCode />
+  <CVV2ResponseCode />
+</TranxResponse>
+
+<?xml version="1.0" encoding="UTF-8"?>
+<TranxResponse>
+  <MerchantNumber>4994</MerchantNumber>
+  <ReceiptNumber>1096021915.5853</ReceiptNumber>
+  <SalesOrderNumber>729</SalesOrderNumber>
+  <xxxName>John Smith</xxxName>
+  <Date>2003/12/17 10:31:58</Date>
+  <CardType>VI</CardType>
+  <Page>98e05</Page>
+  <ApprovalCode />
+  <Verbiage>Incorrect Card Number - Please Retry</Verbiage>
+  <TotalAmount>3.88</TotalAmount>
+  <Products>
+    <product>
+      <code>001</code>
+      <description>Test Product 1</description>
+      <quantity>1</quantity>
+      <price>3.10</price>
+      <subtotal>3.10</subtotal>
+      <flags>
+        <flag>{USD}</flag>
+       <flag>{GST}</flag>
+      </flags>
+    </product>
+    <product>
+      <code>010</code>
+      <description>Test Product 2</description>
+      <quantity>1</quantity>
+      <price>0.20</price>
+      <subtotal>0.20</subtotal>
+      <flags>
+       <flag>{GST}</flag>
+      </flags>
+    </product>
+    <product>
+      <code>020</code>
+      <description>Test Product 3</description>
+      <quantity>1</quantity>
+      <price>0.33</price>
+      <subtotal>0.33</subtotal>
+      <flags>
+       <flag>{GST}</flag>
+      </flags>
+    </product>
+    <product>
+      <code>GST</code>
+      <description>Canadian GST Charged</description>
+      <quantity>1</quantity>
+      <price>0.25</price>
+      <subtotal>0.25</subtotal>
+      <flags>
+        <flag>{TAX}</flag>
+       <flag>{CALCULATED}</flag>
+      </flags>
+    </product>
+  </Products>
+  <DoubleColonProducts>3.10::1::001::Test Product 1::{USD}{GST}|0.20::1::010::Test Product 2::{GST}|0.33::1::020::Test Product 3::{GST}|0.25::1::GST::Canadian GST Charged::{TAX}{CALCULATED}</DoubleColonProducts>
+  <AVSResponseCode />
+  <CVV2ResponseCode />
+</TranxResponse>
+
diff --git a/t/40live.t b/t/40live.t
new file mode 100755 (executable)
index 0000000..4d59f68
--- /dev/null
@@ -0,0 +1,32 @@
+use Test::More;
+
+BEGIN {
+       plan skip_all => 'MERCHANT_ID environment variable not set'
+               unless defined $ENV{MERCHANT_ID};
+};
+
+BEGIN { plan tests => 1 + 2 };
+
+BEGIN { use_ok('Business::OnlinePayment') };
+
+
+my $txn = new Business::OnlinePayment 'InternetSecure',
+               merchant_id => $ENV{MERCHANT_ID};
+
+$txn->test_transaction(1);
+
+$txn->content(
+               action          => 'Normal Authorization',
+               type            => 'Visa',
+               card_number     => '0000000000000000',
+               exp_date        => '2004/07',
+               name            => "Fr\x{e9}d\x{e9}ric Bri\x{e8}re",
+               amount          => 0.01,
+       );
+
+$txn->submit;
+
+is($txn->result_code, '2000', 'is result_code 2000?');
+is($txn->cardholder, "Fr\x{e9}d\x{e9}ric Bri\x{e8}re",
+       'is cardholder encoded properly?');
+