From 7d273cd94a994ff10dcf1a373b6f2747d2ffc9e0 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 26 Sep 2001 03:33:32 +0000 Subject: [PATCH] initial import --- BankOfAmerica.pm | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Changes | 8 ++ MANIFEST | 9 ++ Makefile.PL | 11 ++ README | 24 ++++ t/bop.t | 5 + t/load.t | 5 + t2/bad_auth.t | 32 ++++++ t2/credit_card.t | 61 ++++++++++ 9 files changed, 494 insertions(+) create mode 100644 BankOfAmerica.pm create mode 100644 Changes create mode 100644 MANIFEST create mode 100644 Makefile.PL create mode 100644 README create mode 100644 t/bop.t create mode 100644 t/load.t create mode 100644 t2/bad_auth.t create mode 100644 t2/credit_card.t diff --git a/BankOfAmerica.pm b/BankOfAmerica.pm new file mode 100644 index 0000000..adeb175 --- /dev/null +++ b/BankOfAmerica.pm @@ -0,0 +1,339 @@ +package Business::OnlinePayment::BankOfAmerica; + +# $Id: BankOfAmerica.pm,v 1.1 2001-09-26 03:33:32 ivan Exp $ + +use strict; +use Carp qw(croak); +use Business::OnlinePayment; +use Net::SSLeay qw/make_form post_https make_headers/; +#use Text::CSV; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); + +require Exporter; + +@ISA = qw(Exporter AutoLoader Business::OnlinePayment); +@EXPORT = qw(); +@EXPORT_OK = qw(); +$VERSION = '1.00'; + +sub set_defaults { + my $self = shift; + + $self->server('cart.bamart.com'); + $self->port('443'); + +} + +sub revmap_fields { + my($self, %map) = @_; + my %content = $self->content(); + foreach(keys %map) { +# warn "$_ = ". ( ref($map{$_}) +# ? ${ $map{$_} } +# : $content{$map{$_}} ). "\n"; + $content{$_} = ref($map{$_}) + ? ${ $map{$_} } + : $content{$map{$_}}; + } + $self->content(%content); +} + +sub get_fields { + my($self,@fields) = @_; + + my %content = $self->content(); + my %new = (); + foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; } + return %new; +} + +sub order_number { + my $self = shift; + if (@_) { + $self->{order_number} = shift; + } + return $self->{order_number}; +} + +sub submit { + my($self) = @_; + + my %content = $self->content; + + my $action = lc($content{'action'}); + + die 'Normal Authorization not supported' + if $action eq 'normal authorization'; + + my @fields; + my $ioc_indicator = ''; + + if ( $action eq 'authorization only' ) { + $self->path('/payment.mart'); + @fields = qw( + ioc_merchant_id ioc_order_total_amount ioc_merchant_shopper_id + ioc_merchant_order_id ecom_billto_postal_name_first + ecom_billto_postal_name_last ecom_billto_postal_street_line1 + ecom_billto_postal_street_line2 ecom_billto_postal_city + ecom_billto_postal_stateprov ecom_billto_postal_postalcode + ecom_billto_postal_countrycode ecom_billto_telecom_phone_number + ecom_billto_online_email ecom_payment_card_name + ecom_payment_card_number ecom_payment_card_expdate_month + ecom_payment_card_expdate_year + ); + } elsif ( $action eq 'credit' ) { + $self->path('/Settlement.mart'); + $ioc_indicator = 'R'; + @fields = qw( + ioc_handshake_id ioc_merchant_id ioc_user_name ioc_password + ioc_order_number ioc_indicator ioc_settlement_amount + ioc_authorization_code ioc_email_flag + ); + # ioc_email_flag ioc_close_flag ioc_invoice_notes ioc_email_notes_flag + } elsif ( $action eq 'post authorization' ) { + $self->path('/Settlement.mart'); + $ioc_indicator = 'S'; + @fields = qw( + ioc_handshake_id ioc_merchant_id ioc_user_name ioc_password + ioc_order_number ioc_indicator ioc_settlement_amount + ioc_authorization_code ioc_email_flag + ); + # ioc_email_flag ioc_close_flag ioc_invoice_notes ioc_email_notes_flag + } else { + die "unknown action $action"; + } + +# $self->required_fields(qw/type login password action amount last_name +# first_name card_number expiration/); + + my($month, $year); + unless ( $action eq 'post authorization' ) { + + if ( $self->transaction_type() =~ + /^(cc|visa|mastercard|american express|discover)$/i + ) { + } else { + Carp::croak("BankOfAmerica can't handle transaction type: ". + $self->transaction_type()); + } + + $content{'expiration'} =~ /^(\d+)\D+(\d+)$/ + or croak "unparsable expiration $content{expiration}"; + + ( $month, $year ) = ( $1, $2 ); + $year += 2000 if $year < 2000; #not y4k safe, oh shit + + } + + $self->revmap_fields( + ioc_merchant_id => \($self->merchant_id()), + ioc_user_name => 'login', + ioc_password => 'password', + ioc_invoice_notes => 'description', + ioc_order_total_amount => 'amount', + ioc_settlement_amount => 'amount', + ioc_merchant_order_id => 'invoice_number', + ioc_order_number => 'order_number', + ioc_merchant_shopper_id => 'customer_id', + ecom_billto_postal_name_last => 'last_name', + ecom_billto_postal_name_first => 'first_name', + ecom_billto_postal_street_line1 => 'address', +#!!! ecom_billto_postal_street_line2 => 'address', + ecom_billto_postal_city => 'city', + ecom_billto_postal_stateprov => 'state', + ecom_billto_postal_postalcode => 'zip', + ecom_payment_card_number => 'card_number', + ecom_billto_postal_countrycode => 'country', + ecom_billto_telecom_phone_number => 'phone', + ecom_billto_online_email => 'email', + + ecom_payment_card_name => + \( $content{'name'} || "$content{first_name} $content{last_name}" ), + + ecom_payment_card_expdate_month => \$month, + ecom_payment_card_expdate_year => \$year, + + ioc_authorization_code => 'authorization', + ioc_indicator => \$ioc_indicator, + ioc_handshake_id => 'order_number', + ioc_email_flag => \'No', + + ); + + my %post_data = $self->get_fields( @fields ); + + warn "$_ => $post_data{$_}\n" for keys %post_data; + warn "\n"; + my $pd = make_form(%post_data); + my $s = $self->server(); + my $p = $self->port(); + my $t = $self->path(); + my $headers = make_headers('Referer' => $content{'referer'} ) + unless $action eq 'post authorization'; + my($page,$server_response,%headers) = post_https($s,$p,$t,$headers,$pd); + + my %response; + if ( $action eq 'post authorization' ) { + $page =~ s/.*//s; + $page =~ s/\n+$//; + %response = + map { /^(\w+)\=(.*)$/ or /^()()$/ or die $_; lc($1) => $2 } + split(/\r/, $page); + } else { + %response = + map { /^(\w+)\=(.*)$/ or die $_; lc($1) => $2 } split(/\/i, $page); + } + + warn "$_ => $response{$_}\n" for keys %response; + + $self->server_response($page); + + if ( $response{'ioc_response_code'} eq '0' ) { + $self->is_success(1); + $self->result_code($response{'ioc_response_code'}); + $self->authorization($response{'ioc_authorization_code'}); + $self->order_number($response{'ioc_order_id'}); + } else { + $self->is_success(0); + $self->result_code($response{'ioc_response_code'}); + my $error = + $action eq 'post authorization' + ? $response{'ioc_response_desc'} + : $response{'ioc_reject_description'}; + $error .= ': '. $response{'ioc_missing_fields'} + if $response{'ioc_missing_fields'}; + $error .= ': '. $response{'ioc_invalid_fields'} + if $response{'ioc_invalid_fields'}; + $self->error_message($error); + } + +} + +1; +__END__ + +=head1 NAME + +Business::OnlinePayment::BankOfAmerica - Bank of America backend for Business::OnlinePayment + +=head1 SYNOPSIS + + use Business::OnlinePayment; + + my $tx = new Business::OnlinePayment("BankOfAmerica", 'merchant_id' => 'YOURMERCHANTID'); + $tx->content( + type => 'VISA', + action => 'Authorization Only', + description => 'Business::OnlinePayment test', + amount => '49.95', + invoice_number => '100100', + customer_id => 'jsk', + first_name => 'Jason', + last_name => 'Kohles', + address => '123 Anystreet', + city => 'Anywhere', + state => 'UT', + zip => '84058', + email => 'ivan-bofa@420.am', + card_number => '4007000000027', + expiration => '09/99', + referer => 'http://cleanwhisker.420.am/', + ); + $tx->submit(); + + if($tx->is_success()) { + print "Card processed successfully: ".$tx->authorization."\n"; + } else { + print "Card was rejected: ".$tx->error_message."\n"; + } + + if($tx->is_success()) { + + $auth = $tx->authorization; + $ordernum = $tx->order_number; + + my $capture = new Business::OnlinePayment("BankOfAmerica", 'merchant_id' => 'YOURMERCHANTID' ); + + $capture->content( + action => 'Post Authorization', + login => 'YOURLOGIN + password => 'YOURPASSWORD', + order_number => $ordernum, + amount => '0.01', + authorization => $auth, + description => 'Business::OnlinePayment::BankOfAmerica visa test', + ); + + $capture->submit(); + + if($capture->is_success()) { + print "Card captured successfully: ".$capture->authorization."\n"; + } else { + print "Card was rejected: ".$capture->error_message."\n"; + } + + } + +=head1 SUPPORTED TRANSACTION TYPES + +=head2 Visa, MasterCard, American Express, JCB, Discover/Novus, Carte blanche/Diners Club + +Content required for `Authorization Only': type, action, amount, +invoice_number, customer_id, first_name, last_name, address, city, state, zip, +email, card_number, expiration, referer + +Content required for `Post Authorization': action, login, password, +order_number, amount, authorization, description + +`Normal Authorization' is not supported by the Bank of America gateway. + +`Credit' is untested. + +=head1 DESCRIPTION + +For detailed information see L. + +=head1 NOTE + +Unlike Business::OnlinePayment or early verisons of +Business::OnlinePayment::AuthorizeNet, Business::OnlinePayment::BankOfAmerica +requires separate I and I fields. + +An additional I field is optional. By default the I and +I fields will be concatenated. + +=head1 NOTE + +Business::OnlinePayment::BankOfAmerica does not support the +B mode which combines authorization and capture into a +single tranaction. You must use the B mode followed by the +B mode. The B mode is supported. + +=head1 COMPATIBILITY + +This module implements the interface documented at +http://www.bankofamerica.com/merchantservices/index.cfm?template=merch_ic_estores_developer.cfm + +The settlement API is documented at +https://manager.bamart.com/welcome/SettlementAPI.pdf + +=head1 BUGS + +No login and password are required for B mode. Access +is restricted only by the merchant id (available in any public store webpage +which passes off to the backend system) and HTTP referer header. + +There is no way to run test transactions against the settlement API. + +=head1 AUTHOR + +Ivan Kohler + +Based on Businss::OnlinePayment::AuthorizeNet written by Jason Kohles. + +=head1 SEE ALSO + +perl(1). L. + +=cut + diff --git a/Changes b/Changes new file mode 100644 index 0000000..7e8055e --- /dev/null +++ b/Changes @@ -0,0 +1,8 @@ +Revision history for Perl extension Business::OnlinePayment::BankOfAmerica. + +1.00 Tue Sep 25 20:28:51 2001 + - upload to CPAN. + +0.01 Sun Sep 13 00:40:03 2001 + - original version; created by ivan 1.0 + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..703bd58 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,9 @@ +BankOfAmerica.pm +Changes +MANIFEST +Makefile.PL +README +t/bop.t +t/load.t +t2/bad_auth.t +t2/credit_card.t diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..cbeb20f --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,11 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Business::OnlinePayment::BankOfAmerica', + 'VERSION_FROM' => 'BankOfAmerica.pm', # finds $VERSION + 'AUTHOR' => 'Ivan Kohler ', + #'NORECURS' => 1, # dont descend into subdirectories + 'PREREQ_PM' => {'Net::SSLeay' => 0 }, #, 'Text::CSV' => 0}, + #'dist' => {CI => 'ci -l'}, +); diff --git a/README b/README new file mode 100644 index 0000000..e3fffa8 --- /dev/null +++ b/README @@ -0,0 +1,24 @@ +Copyright (c) 2001 Ivan Kohler. All rights reserved. +This program is free software; you can redistribute it and/or modify it under +the same terms as Perl itself. + +This is Business::OnlinePayment::BankOfAmerica, an Bank of America-specific +backend module for Business::OnlinePayment. It implements the interface +documented in + +http://www.bankofamerica.com/merchantservices/index.cfm?template=merch_ic_estores_developer.cfm + +The settlement API is documented at +https://manager.bamart.com/welcome/SettlementAPI.pdf + +It based on Businss::OnlinePayment::AuthorizeNet written by Jason Kohles. + +There are additional tests in t2/ that may be useful to you once you have a +merchant_id, login and password. + +Ivan Kohler + +Business::OnlinePayment is a generic interface for processing payments through +online credit card processors, online check acceptance houses, etc. (If you +like buzzwords, call it an "multiplatform ecommerce-enabling middleware +solution"). diff --git a/t/bop.t b/t/bop.t new file mode 100644 index 0000000..64332c5 --- /dev/null +++ b/t/bop.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n"; } +END {print "not ok 1\n" unless $loaded;} +use Business::OnlinePayment; +$loaded = 1; +print "ok 1\n"; diff --git a/t/load.t b/t/load.t new file mode 100644 index 0000000..d49b683 --- /dev/null +++ b/t/load.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n"; } +END {print "not ok 1\n" unless $loaded;} +use Business::OnlinePayment::BankOfAmerica; +$loaded = 1; +print "ok 1\n"; diff --git a/t2/bad_auth.t b/t2/bad_auth.t new file mode 100644 index 0000000..602c816 --- /dev/null +++ b/t2/bad_auth.t @@ -0,0 +1,32 @@ +BEGIN { $| = 1; print "1..1\n"; } + +use Business::OnlinePayment; + +my $tx = new Business::OnlinePayment("BankOfAmerica", 'merchant_id' => 'YOURMERCHANTID' ); +$tx->content( + type => 'VISA', + action => 'Authorization Only', + description => 'Business::OnlinePayment::BankOfAmerica visa test', + amount => '49.95', + invoice_number => '100', + customer_id => 'jsk', + first_name => 'Tofu', + last_name => 'Beast', + address => '123 Anystreet', + city => 'Anywhere', + state => 'UT', + zip => '84058', + country => 'US', + email => 'ivan-bofa@420.am', +# card_number => '4007000000027', + expiration => '08/2004', + referer => 'http://cleanwhisker.420.am/', +); +$tx->submit(); + +if($tx->is_success()) { + print "not ok 1\n"; +} else { +# warn '***** '. $tx->error_message. " *****\n"; + print "ok 1\n"; +} diff --git a/t2/credit_card.t b/t2/credit_card.t new file mode 100644 index 0000000..1f47875 --- /dev/null +++ b/t2/credit_card.t @@ -0,0 +1,61 @@ +BEGIN { $| = 1; print "1..2\n"; } + +use Business::OnlinePayment; + +my $tx = new Business::OnlinePayment("BankOfAmerica", 'merchant_id' => 'YOURMERCHANTID' ); +$tx->content( + type => 'VISA', + action => 'Authorization Only', + description => 'Business::OnlinePayment::BankOfAmerica visa test', + amount => '0.01', + invoice_number => '100', + customer_id => 'jsk', + first_name => 'Tofu', + last_name => 'Beast', + address => '123 Anystreet', + city => 'Anywhere', + state => 'UT', + zip => '84058', + country => 'US', + email => 'ivan-bofa@420.am', + card_number => '4007000000027', + expiration => '12/2002', + referer => 'http://cleanwhisker.420.am/', +); +$tx->submit(); + +if($tx->is_success()) { + print "ok 1\n"; + $auth = $tx->authorization; + $ordernum = $tx->order_number; + #warn "********* $auth ***********\n"; + #warn "********* $ordernum ***********\n"; +} else { + print "not ok 1\n"; +# warn '***** '. $tx->error_message. " *****\n"; + exit; +} + +#exit; +my $capture = new Business::OnlinePayment("BankOfAmerica", 'merchant_id' => 'YOURMERCHANTID' ); + +$capture->content( + action => 'Post Authorization', + login => 'YOURLOGIN + password => 'YOURPASSWORD', + order_number => $ordernum, + amount => '0.01', + authorization => $auth, + description => 'Business::OnlinePayment::BankOfAmerica visa test', +); + +$capture->submit(); + +if($capture->is_success()) { + print "ok 2\n"; +} else { +# warn '***** '. $capture->error_message. " *****\n"; + print "not ok 2\n"; +} + + -- 2.11.0