From: Mitch Jackson Date: Wed, 17 Apr 2019 00:19:10 +0000 (-0400) Subject: Pre-auth and voids X-Git-Url: http://git.freeside.biz/gitweb/?a=commitdiff_plain;h=775e7c0cd1eea41d5f7d5fa980db865e44162a80;p=Business-OnlinePayment-Bambora.git Pre-auth and voids --- diff --git a/lib/Business/OnlinePayment/Bambora.pm b/lib/Business/OnlinePayment/Bambora.pm index c721838..c92ff09 100755 --- a/lib/Business/OnlinePayment/Bambora.pm +++ b/lib/Business/OnlinePayment/Bambora.pm @@ -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 +Complete a payment transaction by with an API POST to B See L @@ -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 @@ -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 index 0000000..00c25f9 --- /dev/null +++ b/t/022-payments-card-pre-authorization-complete-void.t @@ -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 index acceee5..0000000 --- a/t/022-payments-card-pre-authorization.t +++ /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