Pre-auth and voids
authorMitch Jackson <mitch@freeside.biz>
Wed, 17 Apr 2019 00:19:10 +0000 (20:19 -0400)
committerMitch Jackson <mitch@freeside.biz>
Wed, 17 Apr 2019 00:19:10 +0000 (20:19 -0400)
lib/Business/OnlinePayment/Bambora.pm
t/022-payments-card-pre-authorization-complete-void.t [new file with mode: 0755]
t/022-payments-card-pre-authorization.t [deleted file]

index c721838..c92ff09 100755 (executable)
@@ -13,7 +13,7 @@ use URI::Escape;
 
 use vars qw/ $VERSION $DEBUG /;
 $VERSION = '0.01';
-$DEBUG   = 1;
+$DEBUG   = 0;
 
 if ( $DEBUG ) {
     $Data::Dumper::Sortkeys = 1;
@@ -59,7 +59,7 @@ my %action_dispatch_table = (
   'authorization only'             => 'submit_authorization_only',
   'post authorization'             => 'submit_post_authorization',
   'reverse authorization'          => 'submit_reverse_authorization',
-  'void'                           => 'submit_viod',
+  'void'                           => 'submit_void',
   'credit'                         => 'submit_credit',
   'tokenize'                       => 'submit_tokenize',
   'recurring authorization'        => 'submit_recurring_authorization',
@@ -83,7 +83,7 @@ sub submit {
 
 =head2 submit_normal_authorization
 
-Compliete a payment transaction by with an API POST to B</payments>
+Complete a payment transaction by with an API POST to B</payments>
 
 See L<https://dev.na.bambora.com/docs/references/payment_APIs/v1-0-5>
 
@@ -136,6 +136,7 @@ sub submit_normal_authorization {
   }
 
   my $action = lc $content->{action};
+
   if ( $action eq 'normal authorization' ) {
     $self->path('/v1/payments');
   } elsif ( $action eq 'authorization only' ) {
@@ -151,7 +152,7 @@ sub submit_normal_authorization {
               unless $content->{order_number};
 
     $self->path(
-      sprintf 'v1/payments/%s/completions',
+      sprintf '/v1/payments/%s/completions',
         $content->{order_number}
     );
 
@@ -172,9 +173,6 @@ sub submit_normal_authorization {
     });
   }
 
-  
-  $self->path('/v1/payments');
-
   my $response = $self->submit_api_request( $post_body );
 
   # Error messages already populated upon failure
@@ -208,7 +206,7 @@ sub submit_authorization_only {
     $self->is_success
     && (
       ref $response
-      && $response->{type} != 'PA'
+      && $response->{type} ne 'PA'
     )
   ) {
     # Bambora API uses nearly identical API calls for normal
@@ -241,7 +239,7 @@ sub submit_reverse_authorization {
 
 =head2 submit_void
 
-Void a transaction
+Process a return against a transaction for the given amount
 
 =cut
 
@@ -249,7 +247,7 @@ sub submit_void {
   my $self = shift;
   my $content = $self->{_content};
 
-  for my $f (qw/ order_number invoice_number amount/) {
+  for my $f (qw/ order_number amount/) {
     unless ( $content->{$f} ) {
       $self->error_message("Cannot process void - missing required content $f");
       warn $self->error_message if $DEBUG;
@@ -259,7 +257,7 @@ sub submit_void {
   }
 
   my %post = (
-    order_number => $self->truncate( $content->{invoice_number}, 30 ),
+#    order_number => $self->truncate( $content->{invoice_number}, 30 ),
     amount => $content->{amount},
   );
   my $post_body = encode_json( \%post );
@@ -270,7 +268,7 @@ sub submit_void {
       post_body => $post_body,
     });
   }
-  $self->path( sprintf '/v1/payments/%s/void', $content->{order_number} );
+  $self->path( sprintf '/v1/payments/%s/returns', $content->{order_number} );
 
   my $response = $self->submit_api_request( $post_body );
 
@@ -345,12 +343,12 @@ Croak with the error message Action $action unsupported
 =cut
 
 sub submit_action_unsupported {
-  croak sprintf 'Action %s unsupported', shift->action
+  croak sprintf 'Action %s unsupported', shift->{_content}{action}
 }
 
 =head2 authorization_header
 
-Bambora POST requests authenticate via a HTTP header of the format:
+Bambora REST requests authenticate via a HTTP header of the format:
 Authorization: Passcode Base64Encoded(merchant_id:passcode)
 
 Returns a hash representing the authorization header derived from
@@ -411,7 +409,7 @@ Sets string to upper case.
 
 Dies unless country is a two-letter string.
 
-In the future, could be extended to convert country names to their respective
+Could be extended to convert country names to their respective
 country codes
 
 See: L<https://en.wikipedia.org/wiki/ISO_3166-1>
@@ -433,7 +431,7 @@ sub set_country {
 
 =head2 set_expiration_month_year
 
-Split standard expiration field, which may be in the format
+Split B::OP expiration field, which may be in the format
 MM/YY or MMYY, into separate expiry_month and expiry_year fields
 
 Will die if values are not numeric
@@ -445,6 +443,12 @@ sub set_expiration {
   my $content = $self->{_content};
   my $expiration = $content->{expiration};
 
+  unless ( $expiration ) {
+    $content->{expiry_month} = undef;
+    $content->{expiry_year}  = undef;
+    return;
+  }
+
   my ( $mm, $yy ) = (
     $expiration =~ /\//
     ? split( /\//, $expiration )
@@ -483,6 +487,11 @@ sub set_payment_method {
 
 =head2 set_phone_number
 
+Set value for field phone_number, from value in field phone
+
+Bambora API expects only digits in a phone number. Strips all non-digit
+characters
+
 =cut
 
 sub set_phone_number {
@@ -498,8 +507,11 @@ sub set_phone_number {
 
 =head2 set_province
 
+Set value for field province, from value in field state
+
 Outside the US/Canada, API expect province set to the string "--",
-otherwise to be a 2 character string
+otherwise expects a 2 character string.  Value for province is
+formatted to upper case, and truncated to 2 characters.
 
 =cut
 
diff --git a/t/022-payments-card-pre-authorization-complete-void.t b/t/022-payments-card-pre-authorization-complete-void.t
new file mode 100755 (executable)
index 0000000..00c25f9
--- /dev/null
@@ -0,0 +1,172 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use Test::More;
+
+use lib 't';
+require 'TestFixtures.pm';
+use Business::OnlinePayment;
+
+my $merchant_id = $ENV{BAMBORA_MERCHANT_ID};
+my $api_key     = $ENV{BAMBORA_API_KEY};
+
+SKIP: {
+  skip 'Missing env vars BAMBORA_MERCHANT_ID and BAMBORA_API_KEY', 3
+    unless $merchant_id && $api_key;
+
+  my %content = (
+    login          => $merchant_id,
+    password       => $api_key,
+    action         => 'Authorization Only',
+    amount         => '9.99',
+
+    owner          => 'Freeside Internet Services',
+    name           => 'Mitch Jackson',
+    address        => '1407 Graymalkin Lane',
+    city           => 'Vancouver',
+    state          => 'BC',
+    zip            => '111 111',
+    country        => 'CA',
+
+    invoice_number => time(),
+    card_number    => '4030000010001234',
+    cvv2           => '123',
+    expiration     => '1122',
+    phone          => '251-300-1300',
+    email          => 'mitch@freeside.biz',
+  );
+
+  my $tr;
+  ok( $tr = Business::OnlinePayment->new('Bambora'), 'Instantiatiate $tr' );
+  ok( $tr->content( %content ), 'Set transaction content onto $tr' );
+  {
+    local $@;
+    eval { $tr->submit };
+    ok( !$@, "Submit pre-auth (expect approve)" );
+  }
+
+  my $response;
+  my %expect = (
+    amount => '9.99',
+    approved => 1,
+    auth_code => 'TEST',
+    message => 'Approved',
+    message_id => 1,
+    payment_method => 'CC',
+    type => 'PA',
+  );
+  my @expect = qw(
+    card
+    created
+    order_number
+    risk_score
+    id
+  );
+
+  ok( $response = $tr->response_decoded, 'response_decoded' );
+
+  for my $k ( keys %expect ) {
+    ok(
+      $response->{$k} eq $expect{$k},
+      sprintf '$tr->%s == %s', $k, $expect{$k}
+    );
+  }
+
+  for my $k ( @expect ) {
+    ok(
+      defined $response->{$k},
+      sprintf '$r->%s (%s)',
+        $k, $response->{$k}
+    );
+  }
+
+  %content = (
+    %content,
+    action => 'Post Authorization',
+    order_number => $tr->order_number,
+    amount => '8.99', # $1 Less than pre-auth
+  );
+
+  my $tr_pa;
+  ok( $tr_pa = Business::OnlinePayment->new('Bambora'), 'Instantiate $tr_pa' );
+  ok( $tr_pa->content( %content ), 'Set transaction content onto $tr_pa' );
+  {
+    local $@;
+    eval { $tr_pa->submit };
+    ok( !$@, "Submit post-auth" );
+    warn "Error: $@" if $@;
+  }
+
+  %expect = (
+    amount => '8.99',
+    approved => '1',
+    message => 'Approved',
+    message_id => '1',
+    type => 'PAC',
+  );
+  @expect = (qw/
+    authorizing_merchant_id
+    card
+    created
+    order_number
+    id
+  /);
+
+  my $response_pa;
+  ok( $response_pa = $tr_pa->response_decoded, 'response_decoded' );
+
+  for my $k ( keys %expect ) {
+    ok(
+      $response_pa->{$k} eq $expect{$k},
+      sprintf '$tr->%s == %s', $k, $expect{$k}
+    );
+  }
+
+  for my $k ( @expect ) {
+    ok(
+      defined $response_pa->{$k},
+      sprintf '$r->%s (%s)',
+        $k, $response_pa->{$k}
+    );
+  }
+
+  #
+  # Void Transaction
+  #
+
+  my %content_void = (
+    action => 'Void',
+    login => $content{login},
+    password => $content{password},
+    order_number => $tr_pa->order_number,
+    amount => '8.99',
+  );
+
+  my $tr_void;
+  ok( $tr_void = Business::OnlinePayment->new('Bambora'), 'Instantiate $tr_void' );
+  ok( $tr_void->content( %content_void ), 'Set transaction content onto $tr_void' );
+  {
+      local $@;
+      eval { $tr_void->submit };
+      ok( !$@, "Submit void" );
+      warn "Error: $@" if $@;
+  }
+
+  %expect = (
+    amount => '8.99',
+    approved => '1',
+    message => 'Approved',
+    message_id => '1',
+    type => 'R',
+  );
+  @expect = (qw/
+    authorizing_merchant_id
+    card
+    created
+    order_number
+    id
+  /);
+
+}
+
+done_testing;
\ No newline at end of file
diff --git a/t/022-payments-card-pre-authorization.t b/t/022-payments-card-pre-authorization.t
deleted file mode 100644 (file)
index acceee5..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env perl
-use strict;
-use warnings;
-use Test::More;
-
-use lib 't';
-require 'TestFixtures.pm';
-use Business::OnlinePayment;
-
-my $merchant_id = $ENV{BAMBORA_MERCHANT_ID};
-my $api_key     = $ENV{BAMBORA_API_KEY};
-
-SKIP: {
-  skip 'Missing env vars BAMBORA_MERCHANT_ID and BAMBORA_API_KEY', 3
-    unless $merchant_id && $api_key;
-
-  my %content = (
-    login          => $merchant_id,
-    password       => $api_key,
-    action         => 'Authorization Only',
-    amount         => '9.99',
-
-    owner          => 'Freeside Internet Services',
-    name           => 'Mitch Jackson',
-    address        => '1407 Graymalkin Lane',
-    city           => 'Vancouver',
-    state          => 'BC',
-    zip            => '111 111',
-    country        => 'CA',
-
-    invoice_number => time(),
-    card_number    => '4030000010001234',
-    cvv2           => '123',
-    expiration     => '1122',
-    phone          => '251-300-1300',
-    email          => 'mitch@freeside.biz',
-  );
-
-  my $tr;
-  ok( $tr = Business::OnlinePayment->new('Bambora'), 'Instantiatiate $tr' );
-  ok( $tr->content( %content ), 'Set transaction content onto $tr' );
-  {
-    local $@;
-    eval { $tr->submit };
-    ok( !$@, "Submit pre-auth (expect approve)" );
-  }
-
-  my $response;
-  my %expect = (
-    amount => '9.99',
-    approved => 1,
-    auth_code => 'TEST',
-    message => 'Approved',
-    message_id => 1,
-    payment_method => 'CC',
-    type => 'PA',
-  );
-  my @expect = qw(
-    card
-    created
-    order_number
-    risk_score
-  );
-
-  ok( $response = $tr->response_decoded, 'response_decoded' );
-
-  for my $k ( keys %expect ) {
-    ok(
-      $response->{$k} eq $expect{$k},
-      sprintf '$tr->%s == %s', $k, $expect{$k}
-    );
-  }
-
-  for my $k ( @expect ) {
-    ok(
-      defined $response->{$k},
-      sprintf '$r->%s (%s)',
-        $k, $response->{$k}
-    );
-  }
-
-  %content = (
-    %content,
-    action => 'post authorization',
-    order_number => $tr->order_number,
-  );
-
-  my $tr_pa;
-  ok( $tr_pa = Business::OnlinePayment->new('Bambora'), 'Instantiate $tr_pa' );
-  ok( $tr->content( %content ), 'Set transaction content onto $tr_pa' );
-  {
-    local $@;
-    eval { $tr_pa->submit };
-    ok( !$@, "Submit post-auth" );
-    warn "Error: $@" if $@;
-  }
-
-  my $response_pa;
-  
-
-  ok( $response_pa = $tr_pa->response_decoded, 'response_decoded' );
-
-    # for my $attr (qw/
-    #   message_id
-    #   authorization
-    #   order_number
-    #   txn_date
-    #   avs_code
-    #   is_success
-    # /) {
-    #   ok(
-    #     defined $tr->$attr(),
-    #     sprintf '%s $tr->%s() = %s',
-    #       $name,
-    #       $attr,
-    #       $tr->$attr()
-    #   );
-    # }
-
-}
-
-done_testing;
\ No newline at end of file