make ACH work, more tests
authorjeff <jeff>
Thu, 17 May 2007 23:52:19 +0000 (23:52 +0000)
committerjeff <jeff>
Thu, 17 May 2007 23:52:19 +0000 (23:52 +0000)
Changes
MANIFEST
META.yml
Makefile.PL
TransFirsteLink.pm
t/credit_card.t
t/echeck.t
t/live_card.t [new file with mode: 0644]
t/live_check.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index 9c28ff8..6d07a9e 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,4 +1,11 @@
 Revision history for Perl extension Business::OnlinePayment::TransFirsteLink.
 
+0.02  Wed May 17 19:19:10 EDT 2007
+       - more tests
+        - make echeck conform to behavior rather than documentation
+        - hush warnings where appropriate
+        - transfirst indicates query order is significant, so order
+          hashes with Tie::IxHash (testing seems to indicate order unimportant)
+
 0.01  Wed Apr 29 07:55:25 EDT 2007
        - original version; created by jeff
index 6ee934e..94180f3 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -7,6 +7,8 @@ t/00load.t
 t/bop.t
 t/credit_card.t
 t/echeck.t
+t/live_card.t
+t/live_check.t
 t/pod.t
 t/pod-coverage.t
 META.yml                                 Module meta-data (added by MakeMaker)
index 91619fc..bd93942 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -1,12 +1,13 @@
 # http://module-build.sourceforge.net/META-spec.html
 #XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
 name:         Business-OnlinePayment-TransFirsteLink
-version:      0.01
+version:      0.02
 version_from: TransFirsteLink.pm
 installdirs:  site
 requires:
     Business::OnlinePayment:       3
     Business::OnlinePayment::HTTPS: 0.05
+    Tie::IxHash:                   0
 
 distribution_type: module
 generated_by: ExtUtils::MakeMaker version 6.17
index 0469740..4ee8933 100644 (file)
@@ -8,6 +8,7 @@ WriteMakefile(
     PREREQ_PM    => {
         Business::OnlinePayment        => '3',
         Business::OnlinePayment::HTTPS => '0.05',
+        Tie::IxHash                    => '0',
     },
     (
         $] >= 5.005
index c5dcfe6..80cc4c2 100644 (file)
@@ -3,10 +3,11 @@ package Business::OnlinePayment::TransFirsteLink;
 use strict;
 use vars qw($VERSION $DEBUG %error_messages);
 use Carp qw(carp croak);
+use Tie::IxHash;
 
 use base qw(Business::OnlinePayment::HTTPS);
 
-$VERSION = '0.01';
+$VERSION = '0.02';
 $VERSION = eval $VERSION;
 $DEBUG   = 0;
 
@@ -325,8 +326,8 @@ sub submit {
     my %content = $self->content;
 
     my %required;
-    $required{CC_20} = [ qw( ePayAccountNum Password OrderNumber
-                             TransactionAmount AccountNumber ExpirationDate
+    $required{CC_20} = [ qw( ePayAccountNum Password OrderNum
+                             TransactionAmount CardAccountNum ExpirationDate
                              MerchantCustServNum ) ];
     $required{CC_30} = [ qw( ePayAccountNum Password TransactionCode OrderNum
                              TransactionAmount CardAccountNum ExpirationDate
@@ -336,7 +337,7 @@ sub submit {
                              ReferenceNum ) ];
     $required{ECHECK_20} = [ qw( ePayAccountNum Password AccountNumber
                                  RoutingNumber DollarAmount OrderNumber
-                                 CustomerNumber ) ];
+                                 CustomerNumber CustomerName ) ];
     $required{ECHECK_32} = [ qw( ePayAccountNum Password OrderNumber
                                  AccountNumber RoutingNumber CheckNumber
                                  DollarAmount CustomerName CustomerAddress
@@ -406,6 +407,7 @@ sub submit {
 
         RoutingNumber       => 'routing_code',
         AccountNumber       => \$account_number,
+        AccountNum          => \$account_number,
         CheckNumber         => \$check_number,
 
         CardHolderName      => 'name',
@@ -431,15 +433,21 @@ sub submit {
         ReferenceNum        => 'order_number'
     );
 
-    my %params = $self->get_fields( @{$required{$type_action}},
-                                    @{$optional{$type_action}},
-                                  );
+    tie my %params, 'Tie::IxHash',
+      $self->get_fields( @{$required{$type_action}},
+                         @{$optional{$type_action}},
+                       );
 
     $params{TestTransaction}='Y' if $self->test_transaction;
 
     $params{InstallmentNum} = $params{InstallmentOf} = '01'
       unless ($params{InstallmentNum} && $params{InstallmentOf}); 
 
+    if ($self->transaction_type() eq 'ECHECK') {
+      delete $params{InstallmentNum};
+      delete $params{InstallmentOf};
+    }
+
     if ( $type_action eq "CC_30" || $type_action eq "CC_32" ) {
       $self->path($self->path."elink/authpd.asp");
     } elsif ( $type_action eq "CC_61" ) {
@@ -468,13 +476,14 @@ sub submit {
     $self->required_fields(@{$required{$type_action}});
 
     my $status ='';
+    my @rarray = ();
 
     if ( $type_action eq "CC_30" || $type_action eq "CC_32" ) {
       my ($format,$account,$tcode,$seq,$moi,$cardnum,$exp,$authamt,$authdate,
           $authtime,$tstat,$custnum,$ordernum,$refnum,$rcode,$authsrc,$achar,
           $transid,$vcode,$sic,$country,$avscode,$storenum,$cvv2resp,$cavvcode,
           $crossrefnum,$etstat,$cavvresponse,$xid,$eci,@junk)
-         = split '\|', $page;
+        = split '\|', $page;
 
       # AVS and CVS values may be set on success or failure
       $self->avs_code($avscode);
@@ -485,30 +494,52 @@ sub submit {
       $self->junk( \@junk );
       $self->error_message($error_messages{$status});
 
+
     } elsif ( $type_action eq "CC_61" ) {
-      my ($format,$account,$tcode,$voidamt,$seq,$voiddate,$voidtime,$tstat,
+      $self->avs_code('');
+      $self->cvv2_response('');
+      my ($format,$account,$tcode,$seq,$voiddate,$voidtime,$tstat, # flaky docs
           $refnum,$filler1,$filler2,$filler3,$etstat,@junk)
          = split '\|', $page;
       $self->result_code( $status = $etstat );
       $self->order_number( $refnum );
+      $self->authorization('');
       $self->junk( \@junk );
       $self->error_message($error_messages{$status});
 
     } elsif ( $type_action eq "CC_20" ) {
+      $self->avs_code('');
+      $self->cvv2_response('');
       my ($format,$account,$tcode,$seq,$moi,$authamt,$authdate,$authtime,
           $tstat,$refnum,$crossrefnum,$custnum,$ordernum,$etstat,@junk)
          = split '\|', $page;
       $self->result_code( $status = $etstat );
       $self->order_number( $refnum );
+      $self->authorization('');
       $self->junk( \@junk );
       $self->error_message($error_messages{$status});
 
-    } elsif ( $type_action eq "ECHECK_32" || $type_action eq "ECHECK_20" ) {
+    } elsif ( $type_action eq "ECHECK_32" ) {
       my ($responsecode,$response,$transactionid,$note,$errors,@junk)
          = split '\|', $page;
-      # AVS and CVS values may be set on success or failure
+      $self->avs_code('');
+      $self->cvv2_response('');
       $self->result_code( $status = $responsecode );
       $self->order_number( $transactionid );
+      $self->authorization('');
+      $errors = $errors ? $errors : '';
+      $self->error_message("$response $errors");
+      $self->junk( \@junk );
+
+    } elsif ( $type_action eq "ECHECK_20" ) {
+      my ($response,$transactionid,$note,$errors,@junk) # very flaky docs
+         = split '\|', $page;
+      $self->avs_code('');
+      $self->cvv2_response('');
+      $self->result_code( $status = $response );
+      $self->order_number( $transactionid );
+      $self->authorization('');
+      $errors = $errors ? $errors : '';
       $self->error_message("$response $errors");
       $self->junk( \@junk );
 
@@ -516,7 +547,7 @@ sub submit {
       croak "can't interpret response for unexpected type and action $type_action";
     }
 
-    if ( $resp eq "200" && ($status eq "000" || $status eq "011" || $status eq "085" || $status eq "0P0" || $status eq "P00") ) {
+    if ( $resp eq "200" && ($status eq "000" || $status eq "011" || $status eq "085" || $status eq "0P0" || $status eq "P00" || $status eq 'ACCEPTED') ) {
         $self->is_success(1);
     }
     else {
index fe04da2..83e9eb5 100644 (file)
@@ -13,7 +13,7 @@ my $runinfo =
 
 plan(
       ( $ENV{"ELINK_ACCOUNT"} && $ENV{"ELINK_PASSWORD"} )
-    ? ( tests => 70 )
+    ? ( tests => 56 )
     : ( skip_all => $runinfo )
 );
 
@@ -75,97 +75,68 @@ my %content = (
 
 SKIP: {    # avs_code() / AVSZIP and AVSADDR tests
 
-    skip "AVS tests broken", 28;
+    skip "AVS tests broken", 21;
 
     my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
 
-    # IF first 3 chars of STREET <= 334 and >= 666 THEN AVSADDR == "N"
     $tx->content( %content, "address" => "500 Any street" );
     tx_check(
         $tx,
         desc          => "AVSADDR=N,AVSZIP=Y",
-        is_success    => 0,
-        result_code   => 126,
-        authorization => "010101",
-        avs_code      => "Z",
-        cvv2_response => "Y",
-    );
-
-    # IF first 3 chars of STREET >= 667 THEN AVSADDR == "X" (and AVSZIP="X")
-    $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
-    $tx->content( %content, "address" => "700 Any street" );
-    tx_check(
-        $tx,
-        desc          => "AVSADDR=X,AVSZIP=X",
         is_success    => 1,
-        result_code   => 0,
-        authorization => "010101",
-        avs_code      => "",
-        cvv2_response => "Y",
+        result_code   => "000",
+        authorization => "999999",
+        avs_code      => "Z",
+        cvv2_response => "M",
     );
 
-#    # IF ZIP <= 50001 and >= 99999 THEN AVSZIP == "N"
     $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
     $tx->content( %content, "zip" => "99999" );
     tx_check(
         $tx,
         desc          => "AVSADDR=Y,AVSZIP=N",
-        is_success    => 0,
-        result_code   => 126,
-        authorization => "010101",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => "999999",
         avs_code      => "A",
-        cvv2_response => "Y",
+        cvv2_response => "M",
     );
 
-    # Both AVSADDR and AVSZIP == "N"
     $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
     $tx->content( %content, "address" => "500 Any street", "zip" => "99999" );
     tx_check(
         $tx,
         desc          => "AVSADDR=N,AVSZIP=N",
-        is_success    => 0,
-        result_code   => 126,
-        authorization => "010101",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => "999999",
         avs_code      => "N",
-        cvv2_response => "Y",
+        cvv2_response => "M",
     );
 }
 
 SKIP: {    # cvv2_response() / CVV2MATCH
 
-    skip "CVV2 tests broken", 14;
+    skip "CVV2 tests broken", 7;
 
     my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
 
-    # IF CVV2 >= 301 and <= 600 THEN CVV2MATCH == "N"
     $tx->content( %content, "cvv2" => "301" );
     tx_check(
         $tx,
-        desc          => "cvv2(301)",
-        is_success    => 0,
-        result_code   => 126,
-        authorization => "010101",
+        desc          => "wrong cvv2",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => "999999",
         avs_code      => "Y",
         cvv2_response => "N",
     );
 
-    # IF CVV2 >= 601 THEN CVV2MATCH == "X"
-    $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
-    $tx->content( %content, "cvv2" => "601" );
-    tx_check(
-        $tx,
-        desc          => "cvv2(601)",
-        is_success    => 0,
-        result_code   => 126,
-        authorization => "010101",
-        avs_code      => "Y",
-        cvv2_response => "X",
-    );
 }
 
 SKIP: {    # refund test
 
-    skip "credit/refund tests broken", 7;
+    #skip "credit/refund tests broken", 7;
 
     my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
     $tx->content( %content, 'action' => "Credit",
@@ -174,7 +145,7 @@ SKIP: {    # refund test
     tx_check(
         $tx,
         desc          => "refund/credit",
-        is_success    => 0,
+        is_success    => 1,
         result_code   => "000",
         authorization => '',
         avs_code      => '',
@@ -184,7 +155,7 @@ SKIP: {    # refund test
 
 SKIP: {    # void test
 
-    skip "void tests broken", 7;
+    #skip "void tests broken", 7;
 
     my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
     $tx->content( %content, 'action' => "Void",
@@ -193,7 +164,7 @@ SKIP: {    # void test
     tx_check(
         $tx,
         desc          => "void",
-        is_success    => 0,
+        is_success    => 1,
         result_code   => "000",
         authorization => '',
         avs_code      => '',
index 2d3de74..386efee 100644 (file)
@@ -9,10 +9,18 @@ use Business::OnlinePayment;
 
 my $runinfo =
     "to test set environment variables:"
-  . " (required) ELINK_ACH_ACCOUNT and ELINK_ACH_PASSWORD";
+  . " (required) ELINK_ACH_ACCOUNT, ELINK_ACH_PASSWORD"
+  . " ELINK_ROUTING_CODE, ELINK_BANK_ACCOUNT, ELINK_ACH_NAME"
+  . " ELINK_ACH_ADDRESS, ELINK_ACH_CITY, ELINK_ACH_STATE"
+  . " ELINK_ACH_ZIP, ELINK_ACH_PHONE";
 
 plan(
-      ( $ENV{"ELINK_ACH_ACCOUNT"} && $ENV{"ELINK_ACH_PASSWORD"} )
+      ( $ENV{"ELINK_ACH_ACCOUNT"} && $ENV{"ELINK_ACH_PASSWORD"} &&
+        $ENV{"ELINK_ROUTING_CODE"} && $ENV{"ELINK_BANK_ACCOUNT"} &&
+        $ENV{"ELINK_ACH_NAME"} && $ENV{"ELINK_ACH_ADDRESS"} &&
+        $ENV{"ELINK_ACH_CITY"} && $ENV{"ELINK_ACH_STATE"} &&
+        $ENV{"ELINK_ACH_ZIP"} && $ENV{"ELINK_ACH_PHONE"} 
+      )
     ? ( tests => 12 )
     : ( skip_all => $runinfo )
 );
@@ -27,23 +35,19 @@ my %content = (
     password       => $ENV{"ELINK_ACH_PASSWORD"},
     action         => "Normal Authorization",
     type           => "CHECK",
-    description    => "Business::OnlinePayment::TransFirsteLink test",
-    routing_code   => "052000113",
-    account_number => "000000000001",
-    check_number   => "100",
-    cvv2           => "123",
-    expiration     => "12/" . strftime( "%y", localtime ),
-    amount         => "0.01",
-    invoice_number => "1999",
-    account_name   => "Tofu Beast",
-    customer_id    => "TB01",
-    email          => 'transfirst@weasellips.com',
-    address        => "123 Anystreet",
-    city           => "Anywhere",
-    state          => "GA",
-    zip            => "30004",
-    country        => "US",
-    phone          => "4045551212",
+    description    => "Business::OnlinePayment::TransFirsteLink live test",
+    routing_code   => $ENV{"ELINK_ROUTING_CODE"},
+    account_number => $ENV{"ELINK_BANK_ACCOUNT"},
+    check_number   => "99",
+    amount         => "1.01",
+    invoice_number => "LiveTest",
+    customer_id    => "LiveTestCust",
+    account_name   => $ENV{"ELINK_ACH_NAME"},
+    address        => $ENV{"ELINK_ACH_ADDRESS"},
+    city           => $ENV{"ELINK_ACH_CITY"},
+    state          => $ENV{"ELINK_ACH_STATE"},
+    zip            => $ENV{"ELINK_ACH_ZIP"},
+    phone          => $ENV{"ELINK_ACH_PHONE"},
 );
 
 {    # valid account test
@@ -57,9 +61,7 @@ my %content = (
     );
 }
 
-SKIP: {    # invalid account test
-
-    skip "invalid account tests broken", 4;
+{    # invalid account test
 
     my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
     $tx->content( %content, routing_code   => "052000113",
@@ -70,13 +72,11 @@ SKIP: {    # invalid account test
         $tx,
         desc          => "invalid account",
         is_success    => 0,
-        result_code   => 214,
+        result_code   => 'D10',
     );
 }
 
-SKIP: {    # credit/refund test
-
-    skip "credit/refund tests broken", 4;
+{    # credit/refund test
 
     my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
     $tx->content( %content, action => "Credit");
@@ -84,15 +84,15 @@ SKIP: {    # credit/refund test
     tx_check(
         $tx,
         desc          => "credit/refund",
-        is_success    => 0,
-        result_code   => "P00",
+        is_success    => 1,
+        result_code   => "ACCEPTED",
     );
 }
 
 sub tx_check {
     my $tx = shift;
     my %o  = @_;
-
     $tx->test_transaction(1);
     $tx->submit;
 
diff --git a/t/live_card.t b/t/live_card.t
new file mode 100644 (file)
index 0000000..3dd5a63
--- /dev/null
@@ -0,0 +1,210 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use POSIX qw(strftime);
+use Test::More;
+
+use Business::OnlinePayment;
+
+my $runinfo =
+    "to test set environment variables:"
+  . " (required) ELINK_ACCOUNT, ELINK_PASSWORD, ELINK_CARD,"
+  . " ELINK_CVV2, ELINK_EXP, ELINK_CARD_NAME, ELINK_CARD_ADDRESS,"
+  . " ELINK_CARD_CITY, ELINK_CARD_STATE, ELINK_CARD_ZIP, and ELINK_DO_LIVE ";
+
+plan(
+      ( $ENV{"ELINK_ACCOUNT"} && $ENV{"ELINK_PASSWORD"} &&
+        $ENV{"ELINK_CARD"} && $ENV{"ELINK_CVV2"} &&
+        $ENV{"ELINK_EXP"} && $ENV{"ELINK_CARD_NAME"} &&
+        $ENV{"ELINK_CARD_ADDRESS"} && $ENV{"ELINK_CARD_CITY"} &&
+        $ENV{"ELINK_CARD_STATE"} && $ENV{"ELINK_CARD_ZIP"} &&
+        $ENV{"ELINK_DO_LIVE"}
+      )
+    ? ( tests => 56 )
+    : ( skip_all => $runinfo )
+);
+
+my %opts = (
+    "debug"    => 0,
+    "merchantcustservnum" => "8005551212",
+);
+
+my %content = (
+    login          => $ENV{"ELINK_ACCOUNT"},
+    password       => $ENV{"ELINK_PASSWORD"},
+    action         => "Normal Authorization",
+    type           => "CC",
+    description    => "Business::OnlinePayment::TransFirsteLink live test",
+    card_number    => $ENV{"ELINK_CARD"},
+    cvv2           => $ENV{"ELINK_CVV2"},
+    expiration     => $ENV{"ELINK_EXP"},
+    amount         => "0.01",
+    invoice_number => "LiveTest",
+    name           => $ENV{"ELINK_CARD_NAME"},
+    address        => $ENV{"ELINK_CARD_ADDRESS"},
+    city           => $ENV{"ELINK_CARD_CITY"},
+    state          => $ENV{"ELINK_CARD_STATE"},
+    zip            => $ENV{"ELINK_CARD_ZIP"},
+);
+
+my $voidable;
+my $credit_amount = 0;
+
+{    # valid card number test
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content(%content);
+    tx_check(
+        $tx,
+        desc          => "valid card_number",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^\w{6}$/,
+        avs_code      => "Y",      # useless
+        cvv2_response => "M",
+    );
+   $voidable = $tx->order_number if $tx->is_success;
+}
+
+{    # invalid card number test
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, card_number => "4111111111111112" );
+    tx_check(
+        $tx,
+        desc          => "invalid card_number",
+        is_success    => 0,
+        result_code   => 214,
+        authorization => qr/^$/,
+        avs_code      => '',
+        cvv2_response => '',
+    );
+}
+
+
+{    # avs_code() / AVSZIP and AVSADDR tests
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+
+    $tx->content( %content, "address" => "500 Any street" );
+    tx_check(
+        $tx,
+        desc          => "AVSADDR=N,AVSZIP=Y",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^\w{6}$/,
+        avs_code      => "Z",
+        cvv2_response => "M",
+    );
+    $credit_amount += $content{amount} if $tx->is_success;
+
+    $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, "zip" => "99999" );
+    tx_check(
+        $tx,
+        desc          => "AVSADDR=Y,AVSZIP=N",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^\w{6}$/,
+        avs_code      => "A",
+        cvv2_response => "M",
+    );
+    $credit_amount += $content{amount} if $tx->is_success;
+
+    $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, "address" => "500 Any street", "zip" => "99999" );
+    tx_check(
+        $tx,
+        desc          => "AVSADDR=N,AVSZIP=N",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^\w{6}$/,
+        avs_code      => "N",
+        cvv2_response => "M",
+    );
+    $credit_amount += $content{amount} if $tx->is_success;
+}
+
+{    # cvv2_response() / CVV2MATCH
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+
+    $tx->content( %content, "cvv2" => $content{cvv2}+1 );
+    tx_check(
+        $tx,
+        desc          => "wrong cvv2",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^\w{6}$/,
+        avs_code      => "Y",
+        cvv2_response => "N",
+    );
+
+}
+
+{    # refund test
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, 'action' => "Credit",
+                            'amount' => sprintf("%.2f", $credit_amount),
+                );
+    tx_check(
+        $tx,
+        desc          => "refund/credit",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^$/,
+        avs_code      => '',
+        cvv2_response => '',
+    );
+}
+
+{    # void test
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, 'action' => "Void",
+                            'order_number' => $voidable
+                );
+    tx_check(
+        $tx,
+        desc          => "void",
+        is_success    => 1,
+        result_code   => "000",
+        authorization => qr/^$/,
+        avs_code      => '',
+        cvv2_response => '',
+    );
+}
+
+sub tx_check {
+    my $tx = shift;
+    my %o  = @_;
+
+    $tx->submit;
+
+    is( $tx->is_success,    $o{is_success},    "$o{desc}: " . tx_info($tx) );
+    is( $tx->result_code,   $o{result_code},   "result_code(): RESULT" );
+    like( $tx->authorization, $o{authorization}, "authorization() / AUTHCODE" );
+    is( $tx->avs_code,  $o{avs_code},  "avs_code() / AVSADDR and AVSZIP" );
+    is( $tx->cvv2_response, $o{cvv2_response}, "cvv2_response() / CVV2MATCH" );
+    is( scalar(@{$tx->junk}), 0, "junk() / JUNK " );
+    like( $tx->order_number, qr/^(\d{14}|)$/, "order_number() / PNREF" );
+}
+
+sub tx_info {
+    my $tx = shift;
+
+    no warnings 'uninitialized';
+
+    return (
+        join( "",
+            "is_success(",     $tx->is_success,    ")",
+            " order_number(",  $tx->order_number,  ")",
+            " result_code(",   $tx->result_code,   ")",
+            " auth_info(",     $tx->authorization, ")",
+            " avs_code(",      $tx->avs_code,      ")",
+            " cvv2_response(", $tx->cvv2_response, ")",
+            $tx->junk ? " junk(". join('|', @{$tx->junk}). ")" : '',
+        )
+    );
+}
diff --git a/t/live_check.t b/t/live_check.t
new file mode 100644 (file)
index 0000000..7e272cd
--- /dev/null
@@ -0,0 +1,120 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use POSIX qw(strftime);
+use Test::More;
+
+use Business::OnlinePayment;
+
+my $runinfo =
+    "to test set environment variables:"
+  . " (required) ELINK_ACH_ACCOUNT, ELINK_ACH_PASSWORD"
+  . " ELINK_ROUTING_CODE, ELINK_BANK_ACCOUNT, ELINK_ACH_NAME"
+  . " ELINK_ACH_ADDRESS, ELINK_ACH_CITY, ELINK_ACH_STATE"
+  . " ELINK_ACH_ZIP, ELINK_ACH_PHONE, ELINK_DO_LIVE";
+
+plan(
+      ( $ENV{"ELINK_ACH_ACCOUNT"} && $ENV{"ELINK_ACH_PASSWORD"} &&
+        $ENV{"ELINK_ROUTING_CODE"} && $ENV{"ELINK_BANK_ACCOUNT"} &&
+        $ENV{"ELINK_ACH_NAME"} && $ENV{"ELINK_ACH_ADDRESS"} &&
+        $ENV{"ELINK_ACH_CITY"} && $ENV{"ELINK_ACH_STATE"} &&
+        $ENV{"ELINK_ACH_ZIP"} && $ENV{"ELINK_ACH_PHONE"} &&
+        $ENV{"ELINK_DO_LIVE"}
+      )
+    ? ( tests => 12 )
+    : ( skip_all => $runinfo )
+);
+
+my %opts = (
+    "debug"    => 0,
+    "merchantcustservnum" => "8005551212",
+);
+
+my %content = (
+    login          => $ENV{"ELINK_ACH_ACCOUNT"},
+    password       => $ENV{"ELINK_ACH_PASSWORD"},
+    action         => "Normal Authorization",
+    type           => "CHECK",
+    description    => "Business::OnlinePayment::TransFirsteLink live test",
+    routing_code   => $ENV{"ELINK_ROUTING_CODE"},
+    account_number => $ENV{"ELINK_BANK_ACCOUNT"},
+    check_number   => "99",
+    amount         => "1.01",
+    invoice_number => "LiveTest",
+    customer_id    => "LiveTestCust",
+    account_name   => $ENV{"ELINK_ACH_NAME"},
+    address        => $ENV{"ELINK_ACH_ADDRESS"},
+    city           => $ENV{"ELINK_ACH_CITY"},
+    state          => $ENV{"ELINK_ACH_STATE"},
+    zip            => $ENV{"ELINK_ACH_ZIP"},
+    phone          => $ENV{"ELINK_ACH_PHONE"},
+);
+
+{    # valid account test
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content(%content);
+    tx_check(
+        $tx,
+        desc          => "valid account",
+        is_success    => 1,
+        result_code   => "P00",
+    );
+}
+
+SKIP: {    # invalid account test
+
+    skip "invalid account tests broken", 4;
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, routing_code   => "052000113",
+                            account_number => "000000000001",
+                );
+
+    tx_check(
+        $tx,
+        desc          => "invalid account",
+        is_success    => 0,
+        result_code   => 214,
+    );
+}
+
+{    # credit/refund test
+
+    my $tx = new Business::OnlinePayment( "TransFirsteLink", %opts );
+    $tx->content( %content, action => "Credit");
+
+    tx_check(
+        $tx,
+        desc          => "credit/refund",
+        is_success    => 1,
+        result_code   => "ACCEPTED",
+    );
+}
+
+sub tx_check {
+    my $tx = shift;
+    my %o  = @_;
+
+    $tx->submit;
+
+    is( $tx->is_success,    $o{is_success},    "$o{desc}: " . tx_info($tx) );
+    is( $tx->result_code,   $o{result_code},   "result_code(): RESULT" );
+    is( scalar(@{$tx->junk}), 0, "junk() / JUNK " );
+    like( $tx->order_number, qr/^(\d{9}|)$/, "order_number() / PNREF" );
+}
+
+sub tx_info {
+    my $tx = shift;
+
+    no warnings 'uninitialized';
+
+    return (
+        join( "",
+            "is_success(",     $tx->is_success,    ")",
+            " order_number(",  $tx->order_number,  ")",
+            " result_code(",   $tx->result_code,   ")",
+            $tx->junk ? " junk(". join('|', @{$tx->junk}). ")" : '',
+        )
+    );
+}