From 2b4581380de27c17f6d743c94aafb0052a031606 Mon Sep 17 00:00:00 2001 From: Mitch Jackson Date: Wed, 24 Apr 2019 01:56:54 -0400 Subject: [PATCH] POD Documentation --- lib/Business/OnlinePayment/Bambora.pm | 473 +++++++++++++++++++++++++--------- 1 file changed, 354 insertions(+), 119 deletions(-) diff --git a/lib/Business/OnlinePayment/Bambora.pm b/lib/Business/OnlinePayment/Bambora.pm index d85c2c2..8e8a322 100755 --- a/lib/Business/OnlinePayment/Bambora.pm +++ b/lib/Business/OnlinePayment/Bambora.pm @@ -1,9 +1,221 @@ package Business::OnlinePayment::Bambora; use strict; use warnings; + +=head1 NAME + +Business::OnlinePayment::Bambora - Bambora backend for Business::OnlinePayment + +=head1 SYNOPSIS + +=head2 Card Transaction + + use Business::OnlinePayment + + my $tr = Business::OnlinePayment->new('Bambora'); + $tr->content( + login => $BAMBORA_MERCHANT_ID, + password => $BAMBORA_API_KEY, + + action => 'Normal Authorization', + amount => '13.37', + + owner => 'Business OnlinePayment', + 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 => '415-462-1624', + email => 'mitch@freeside.biz', + ); + + $tr->submit; + + if ( $tr->is_success ) { + print "Card processed successfully: ".$tr->authorization."\n"; + } else { + print "Card was rejected: ".$tr->error_message."\n"; + } + +=head2 Tokenize + + use Business::OnlinePayment + + my $tr = Business::OnlinePayment->new('Bambora'); + $tr->content( + login => $BAMBORA_MERCHANT_ID, + password => $BAMBORA_API_KEY, + + action => 'Tokenize', + + owner => 'Business OnlinePayment', + 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 => '415-462-1624', + email => 'mitch@freeside.biz', + ); + + $tr->submit; + + if ( $tr->is_success ) { + print "Card tokenized successfully: ".$tr->card_token."\n"; + } else { + print "Card was rejected: ".$tr->error_message."\n"; + } + + my $tr_token = Business::OnlinePayment->new('Bambora'); + $tr_token->content( + login => $BAMBORA_MERCHANT_ID, + password => $BAMBORA_API_KEY, + + action => 'Normal Authorization', + + card_token => $card_token, + amount => '7.77', + ); + + $tr_token->submit; + + if ( $tr_token->is_success ) { + print "Card processed successfully: ".$tr_token->authorization."\n"; + } else { + print "Card was rejected: ".$tr_token->error_message."\n"; + } + +=head1 SUPPORTED TRANSACTION TYPES + +=head2 CC, Visa, Mastercard, American Express, Discover + +Content required: type, login, password, action, amount, card_number, expiration + +=head1 DESCRIPTION + +For detailed information see L + +=head1 METHODS AND FUNCTIONS + +See L for the complete list. The following methods +either override the methods inherited from L or +provide additional functions + +=head2 result_code + +Returns the response error code + +=head2 error_message + +Returns the response error description text + +=head2 response_page + +Returns the complete response from the Bambora API call + +=head2 response_decoded + +Returns hashref containing the decoded JSON response from the Bambora API call + +=head1 Handling of content(%content) data: + +=head2 action + +The following actions are valid + + Normal Authorization + Authorization Only + Reverse Authorization + Post Authorization + Void + Credit + Tokenize + +=head1 Settings Bambora parameters from content(%content) + +The following rules are applied to map data from %content into +a Bambora API request + + Bambora Business::OnlinePayment-%content + ----------------------------------------------------- + order_number invoice_number + amount amount + + transaction_id order_number + customer_code card_token + + card:number card_number + card:name owner OR name + card:expiry_month expiration + card:expiry_year expiration + card:cvd cvv2 + + billing:name name + billing:address_line1 address + billing:city city + billing:province state + billing:country country + billing:postal_code zip + billing:phone_number phone + billing:email_address email + +=head1 Bambora Authentication + +This module generates HTTP Authorization headers based on your +Bambora API Access Pascode. You must generate an API Access Passcode +within the Bambora merchant portal under the menu headings +Administration > Account Settings > Order Settings + +If you intend to use tokenization, you must also copy the same +API Access Passcode to the configuration page found at +Configuration > Payment Profile Configuration + +=head1 Tokenization Implementation + +Many use tokenization is achieved via the Bambora Payment Profile feature + +The token created by this module represents the Bambora customer_code identifier +for Payment Profile records + +This module does not support advanced management of the Payment Profile, +such as storing multiple cards onto a single profile, or updating the +stored profile detail + +Recommending configuration settings in your Bambora merchant portal: +( as of the time of this module's writing ) + + Main Manu > Configuration > Payment Profile Configuration + + General Settings: + - Uncheck "Requre unique order numbers" + - Uncheck "Do not allow profile to be created with billing information + duplicated from an existing profile" + + Security Settings: + - Select: API Access Passcode (requierd for this API) + - The API Access Passcode will be your "password" using this module + + Credit Card Settings + - Uncheck "Do not allow profile to be created with card data duplicated + from an existing profile"" + +=cut + use base qw/ Business::OnlinePayment::HTTPS /; use feature 'unicode_strings'; - use Carp qw( croak ); use Cpanel::JSON::XS; use Data::Dumper; @@ -19,11 +231,11 @@ use vars qw/ $VERSION $DEBUG /; $VERSION = '0.1'; $DEBUG = 0; -=head1 INTERNAL METHODS - -=head2 _info - -=cut +# =head1 INTERNAL METHODS +# +# =head2 _info +# +# =cut sub _info {{ info_compat => '0.01', @@ -42,11 +254,11 @@ sub _info {{ }, }} -=head2 set_defaults - -See L - -=cut +# =head2 set_defaults +# +# See L +# +# =cut sub set_defaults { my $self = shift; @@ -71,11 +283,11 @@ sub set_defaults { /); } -=head2 submit - -Dispatch to the appropriate handler based on the given action - -=cut +# =head2 submit +# +# Dispatch to the appropriate handler based on the given action +# +# =cut my %action_dispatch_table = ( 'normal authorization' => 'submit_normal_authorization', @@ -105,13 +317,13 @@ sub submit { $self->$method(@_); } -=head2 submit_normal_authorization - -Complete a payment transaction by with an API POST to B - -See L - -=cut +# =head2 submit_normal_authorization +# +# Complete a payment transaction by with an API POST to B +# +# See L +# +# =cut sub submit_normal_authorization { my $self = shift; @@ -246,11 +458,11 @@ sub submit_normal_authorization { $response; } -=head2 submit_authorization_only - -Capture a card authorization, but do not complete transaction - -=cut +# =head2 submit_authorization_only +# +# Capture a card authorization, but do not complete transaction +# +# =cut sub submit_authorization_only { my $self = shift; @@ -274,31 +486,31 @@ sub submit_authorization_only { } } -=head2 submit_post_authorization - -Complete a card pre-authorization - -=cut +# =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 +# =head2 submit_reverse_authorization +# +# Reverse a pre-authorization +# +# =cut sub submit_reverse_authorization { shift->submit_void; } -=head2 submit_void - -Process a return against a transaction for the given amount - -=cut +# =head2 submit_void +# +# Process a return against a transaction for the given amount +# +# =cut sub submit_void { my $self = shift; @@ -337,18 +549,18 @@ sub submit_void { $response; } -=head2 submit_tokenize - -Bambora tokenization is based on the Payment Profile feature of their API. - -The token created by this method represents the Bambora customer_code for the -Payment Profile. The token resembles a credit card number. It is 16 digits -long, beginning with 99. No valid card number can begin with the digits 99. - -This method creates the payment profile and reports the customer_code -as the card_token - -=cut +# =head2 submit_tokenize +# +# Bambora tokenization is based on the Payment Profile feature of their API. +# +# The token created by this method represents the Bambora customer_code for the +# Payment Profile. The token resembles a credit card number. It is 16 digits +# long, beginning with 99. No valid card number can begin with the digits 99. +# +# This method creates the payment profile and reports the customer_code +# as the card_token +# +# =cut sub submit_tokenize { my $self = shift; @@ -418,13 +630,11 @@ sub submit_tokenize { return $response; } - - -=head2 submit_api_request json_string [ POST | PUT ] - -Make the appropriate API request with the given JSON string - -=cut +# =head2 submit_api_request json_string [ POST | PUT ] +# +# Make the appropriate API request with the given JSON string +# +# =cut sub submit_api_request { my $self = shift; @@ -517,18 +727,18 @@ sub authorization_header { %authorization_header; } -=head2 jhref_billing_address - -Return a hashref for inclusion into a json object -representing the RequestBillingAddress for the API - -=cut +# =head2 jhref_billing_address +# +# Return a hashref for inclusion into a json object +# representing the RequestBillingAddress for the API +# +# =cut sub jhref_billing_address { my $self = shift; $self->parse_province; - $self->set_country; + $self->parse_country; $self->parse_phone_number; my $content = $self->{_content}; @@ -545,21 +755,21 @@ sub jhref_billing_address { }; } -=head2 jhref_card - -Return a hashref for inclusin into a json object -representing Card for the API - -If necessary values are missing from %content, will set -error_message and is_success - -=cut +# =head2 jhref_card +# +# Return a hashref for inclusin into a json object +# representing Card for the API +# +# If necessary values are missing from %content, will set +# error_message and is_success +# +# =cut sub jhref_card { my $self = shift; my $content = $self->{_content}; - $self->set_expiration; + $self->parse_expiration; $content->{owner} ||= $content->{name}; @@ -600,15 +810,8 @@ sub jhref_card { =head2 generate_token Generate a 16-digit numeric token, beginning with the digits 99, -based on the current epoch time - -Implementation note: - -If this module is somehow used to tokenize multiple cardholders within -the same microsecond, these cardholders will be assigned the same -customer_code. In the unlikely event this does happen, the Bambora system -will decline to process cards for either of the profiles with a duplicate -customer_code. +ending with a valid Luhn checksum, based on the current epoch time +to the microsecond =cut @@ -628,7 +831,7 @@ sub generate_token { # If this did become a problem for somebody, a time delay could be added # to this method to eliminate the change of collisions: # - # sleep(1); + # sleep(1); my $timestr = join '' => @@ -648,15 +851,28 @@ sub generate_token { $j -= 9 if $j > 9; $sum += $j; } -} + } my $luhn = $sum % 10 ? 10 - ( $sum % 10 ) : 0; return $token . $luhn; } -=cut - -sub set_country { +# =head2 parse_country +# +# Country is expected to be set as an ISO-3166-1 2-letter country code +# +# Sets string to upper case. +# +# Dies unless country is a two-letter string. +# +# Could be extended to convert country names to their respective +# country codes, or validate country codes +# +# See: L +# +# =cut + +sub parse_country { my $self = shift; my $content = $self->{_content}; my $country = uc $content->{country}; @@ -669,16 +885,16 @@ sub set_country { $content->{country} = $country; } -=head2 set_expiration_month_year - -Split B::OP expiration field, which may be in the format -MM/YY or MMYY, into separate expiry_month and expiry_year fields +# =head2 parse_expiration +# +# 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 +# +# =cut -Will die if values are not numeric - -=cut - -sub set_expiration { +sub parse_expiration { my $self = shift; my $content = $self->{_content}; my $expiration = $content->{expiration}; @@ -704,14 +920,14 @@ sub set_expiration { ); } -=head2 parse_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 +# =head2 parse_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 parse_phone_number { my $self = shift; @@ -724,15 +940,15 @@ sub parse_phone_number { $content->{phone_number} = $phone; } -=head2 parse_province - -Set value for field province, from value in field state - -Outside the US/Canada, API expect province set to the string "--", -otherwise expects a 2 character string. Value for province is -formatted to upper case, and truncated to 2 characters. - -=cut +# =head2 parse_province +# +# Set value for field province, from value in field state +# +# Outside the US/Canada, API expect province set to the string "--", +# otherwise expects a 2 character string. Value for province is +# formatted to upper case, and truncated to 2 characters. +# +# =cut sub parse_province { my $self = shift; @@ -797,4 +1013,23 @@ sub https_put { ( $self->response_page, $self->response_code, @response_headers ); } +=head1 AUTHORS + +Mitch Jackson + +=head1 ADVERTISEMENT + +Need a complete, open-source back-office and customer self-service solution? +The Freeside software includes support for credit card and electronic check +processing with IPPay and over 50 other gateways, invoicing, integrated +trouble ticketing, and customer signup and self-service web interfaces. + +L + +=head1 SEE ALSO + +perl(1). L. + +=cut + 1; -- 2.11.0