X-Git-Url: http://git.freeside.biz/gitweb/?p=Business-OnlinePayment-Bambora.git;a=blobdiff_plain;f=lib%2FBusiness%2FOnlinePayment%2FBambora.pm;fp=lib%2FBusiness%2FOnlinePayment%2FBambora.pm;h=c72183874d69bd511382eda05cbae656ec065d3a;hp=a61cda05516ca47c23647d0589cf1665f4766b1b;hb=4eac3eefba3e494cc771d43df1cd3fa3aaece916;hpb=a2c0deaa1ef38f442ac596cd61c6373277aa7258 diff --git a/lib/Business/OnlinePayment/Bambora.pm b/lib/Business/OnlinePayment/Bambora.pm index a61cda0..c721838 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 = 0; +$DEBUG = 1; if ( $DEBUG ) { $Data::Dumper::Sortkeys = 1; @@ -50,7 +50,7 @@ sub set_defaults { =head2 submit -Dispatch to the appropriate hanlder based on the given action +Dispatch to the appropriate handler based on the given action =cut @@ -58,7 +58,7 @@ my %action_dispatch_table = ( 'normal authorization' => 'submit_normal_authorization', 'authorization only' => 'submit_authorization_only', 'post authorization' => 'submit_post_authorization', - 'reverse authorization' => 'rsubmit_everse_authorization', + 'reverse authorization' => 'submit_reverse_authorization', 'void' => 'submit_viod', 'credit' => 'submit_credit', 'tokenize' => 'submit_tokenize', @@ -91,37 +91,90 @@ See L sub submit_normal_authorization { my $self = shift; - - # Series of methods to populate or format field values - $self->make_invoice_number; - $self->set_payment_method; - $self->set_expiration; - my $content = $self->{_content}; - # Build a JSON string - my $post_body = encode_json({ - order_number => $self->truncate( $content->{invoice_number}, 30 ), - amount => $content->{amount}, - payment_method => $content->{payment_method}, + # Use epoch time as invoice_number, if none is specified + $content->{invoice_number} ||= time(); + + # Clarifying Bambora API and Business::OnlinePayment naming conflict + # + # Bambora API: + # - order_number: user supplied identifier for the order, displayed on reports + # - transaction_id: bambora supplied identifier for the order. + # this number must be referenced for future actions like voids, + # auth captures, etc + # + # Business::OnlinePayment + # - invoice_number: contains the bambora order number + # - order_number: contains the bambora transaction id + + my %post = ( + order_number => $self->truncate( $content->{invoice_number}, 30 ), + amount => $content->{amount}, + billing => $self->jhref_billing_address, + ); - billing => $self->jhref_billing_address, + # Credit Card + if ( $content->{card_number} ) { + $post{payment_method} = 'card'; - card => { + # Parse the expiration date into expiry_month and expiry_year + $self->set_expiration; + + $post{card} = { number => $self->truncate( $content->{card_number}, 20 ), name => $self->truncate( $content->{owner}, 64 ), expiry_month => sprintf( '%02d', $content->{expiry_month} ), expiry_year => sprintf( '%02d', $content->{expiry_year} ), cvd => $content->{cvv2}, recurring_payment => $content->{recurring_payment} ? 1 : 0, + complete => 1, + }; + + } else { + die 'unknown/unsupported payment method!'; + } + + my $action = lc $content->{action}; + if ( $action eq 'normal authorization' ) { + $self->path('/v1/payments'); + } elsif ( $action eq 'authorization only' ) { + $self->path('/v1/payments'); + if ( ref $post{card} ) { + $post{card}->{complete} = 0; } - }); + } elsif ( $action eq 'post authorization' ) { + croak 'post authorization cannot be completed - '. + 'bambora transaction_id must be set as order_number '. + 'before using submit()' + unless $content->{order_number}; + + $self->path( + sprintf 'v1/payments/%s/completions', + $content->{order_number} + ); + + if ( ref $post{card} ) { + $post{card}->{complete} = 1 + } + } else { + die "unsupported action $action"; + } + + # Parse %post into a JSON string, to be attached to the request POST body + my $post_body = encode_json( \%post ); + if ( $DEBUG ) { - warn Dumper({ post_body => $post_body })."\n"; + warn Dumper({ + post_body => $post_body, + post_href => \%post, + }); } + $self->path('/v1/payments'); + my $response = $self->submit_api_request( $post_body ); # Error messages already populated upon failure @@ -134,6 +187,93 @@ sub submit_normal_authorization { $self->txn_date( $response->{created} ); $self->avs_code( $response->{card}{avs_result} ); $self->is_success( 1 ); + + $response; +} + +=head2 submit_authorization_only + +Capture a card authorization, but do not complete transaction + +=cut + +sub submit_authorization_only { + my $self = shift; + + $self->submit_normal_authorization; + + my $response = $self->response_decoded; + + if ( + $self->is_success + && ( + ref $response + && $response->{type} != 'PA' + ) + ) { + # Bambora API uses nearly identical API calls for normal + # card transactions and pre-authorization. Sanity check + # that response reported a pre-authorization code + die "Expected API Respose type=PA, but type=$response->{type}! ". + "Pre-Authorization attempt may have charged card!"; + } +} + +=head2 submit_post_authorization + +Complete a card pre-authorization + +=cut + +sub submit_post_authorization { + shift->submit_normal_authorization; +} + +=head2 submit_reverse_authorization + +Reverse a pre-authorization + +=cut + +sub submit_reverse_authorization { + shift->submit_void; +} + +=head2 submit_void + +Void a transaction + +=cut + +sub submit_void { + my $self = shift; + my $content = $self->{_content}; + + for my $f (qw/ order_number invoice_number amount/) { + unless ( $content->{$f} ) { + $self->error_message("Cannot process void - missing required content $f"); + warn $self->error_message if $DEBUG; + + return $self->is_success(0); + } + } + + my %post = ( + order_number => $self->truncate( $content->{invoice_number}, 30 ), + amount => $content->{amount}, + ); + my $post_body = encode_json( \%post ); + + if ( $DEBUG ) { + warn Dumper({ + post => \%post, + post_body => $post_body, + }); + } + $self->path( sprintf '/v1/payments/%s/void', $content->{order_number} ); + + my $response = $self->submit_api_request( $post_body ); + } =head2 submit_api_request json_string @@ -263,17 +403,6 @@ sub jhref_billing_address { }; } -=head2 make_invoice_number - -If an invoice number has not been specified, generate one using -the current epoch timestamp - -=cut - -sub make_invoice_number { - shift->{_content}{invoice_number} ||= time(); -} - =head2 set_country Country is expected to be set as an ISO-3166-1 2-letter country code