X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=AuthorizeNet.pm;h=82c2be1d6f10836b3ddcb1d4d334c68cebe3ed40;hb=0a22d2dbe888f956e8ffc3e66ee390a2877c8a62;hp=80fcbbbc9a86d3a50e0de0cd6cfab350492535db;hpb=a906edd8acfc363934aecc7b035e92aad117f602;p=Business-OnlinePayment-AuthorizeNet.git diff --git a/AuthorizeNet.pm b/AuthorizeNet.pm index 80fcbbb..82c2be1 100644 --- a/AuthorizeNet.pm +++ b/AuthorizeNet.pm @@ -1,11 +1,10 @@ package Business::OnlinePayment::AuthorizeNet; -# $Id: AuthorizeNet.pm,v 1.1 2001-09-01 21:47:31 ivan Exp $ - use strict; +use Carp; use Business::OnlinePayment; -use Net::SSLeay qw/make_form post_https/; -use Text::CSV; +use Net::SSLeay qw/make_form post_https make_headers/; +use Text::CSV_XS; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); require Exporter; @@ -13,7 +12,7 @@ require Exporter; @ISA = qw(Exporter AutoLoader Business::OnlinePayment); @EXPORT = qw(); @EXPORT_OK = qw(); -$VERSION = '3.00'; +$VERSION = '3.13'; sub set_defaults { my $self = shift; @@ -21,6 +20,8 @@ sub set_defaults { $self->server('secure.authorize.net'); $self->port('443'); $self->path('/gateway/transact.dll'); + + $self->build_subs('order_number'); #no idea how it worked for jason w/o this } sub map_fields { @@ -33,6 +34,7 @@ sub map_fields { 'authorization only' => 'AUTH_ONLY', 'credit' => 'CREDIT', 'post authorization' => 'PRIOR_AUTH_CAPTURE', + 'void' => 'VOID', ); $content{'action'} = $actions{lc($content{'action'})} || $content{'action'}; @@ -46,6 +48,10 @@ sub map_fields { $content{'type'} = $types{lc($content{'type'})} || $content{'type'}; $self->transaction_type($content{'type'}); + $content{'referer'} = defined( $content{'referer'} ) + ? make_headers( 'Referer' => $content{'referer'} ) + : ""; + # stuff it back into %content $self->content(%content); } @@ -80,59 +86,94 @@ sub submit { action => 'x_Type', description => 'x_Description', amount => 'x_Amount', + currency => 'x_Currency_Code', invoice_number => 'x_Invoice_Num', + order_number => 'x_Trans_ID', + auth_code => 'x_Auth_Code', customer_id => 'x_Cust_ID', + customer_ip => 'x_Customer_IP', last_name => 'x_Last_Name', first_name => 'x_First_Name', address => 'x_Address', city => 'x_City', state => 'x_State', zip => 'x_Zip', - card_number => 'x_Card_Num', - expiration => 'x_Exp_Date', - account_number => 'x_Bank_Acct_Num', - routing_code => 'x_Bank_ABA_Code', - bank_name => 'x_Bank_Name', country => 'x_Country', phone => 'x_Phone', fax => 'x_Fax', email => 'x_Email', company => 'x_Company', + card_number => 'x_Card_Num', + expiration => 'x_Exp_Date', + cvv2 => 'x_Card_Code', + check_type => 'x_Echeck_Type', + account_name => 'x_Bank_Account_Name', + account_number => 'x_Bank_Acct_Num', + account_type => 'x_Bank_Acct_Type', + bank_name => 'x_Bank_Name', + routing_code => 'x_Bank_ABA_Code', + customer_org => 'x_Customer_Organization_Type', + customer_ssn => 'x_Customer_Tax_ID', + license_num => 'x_Drivers_License_Num', + license_state => 'x_Drivers_License_State', + license_dob => 'x_Drivers_License_DOB', ); - if($self->transaction_type() eq "ECHECK") { - $self->required_fields(qw/type login password action amount last_name - first_name account_number routing_code - bank_name/); - } elsif($self->transaction_type() eq 'CC' ) { + if ($self->transaction_type() eq "ECHECK") { + if ($self->{_content}->{customer_org} ne '') { + $self->required_fields(qw/type login password amount routing_code + account_number account_type bank_name + account_name account_type check_type + customer_org customer_ssn/); + } else { + $self->required_fields(qw/type login password amount routing_code + account_number account_type bank_name + account_name account_type check_type + license_num license_state license_dob/); + } + } elsif ($self->transaction_type() eq 'CC' ) { + if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) { + if ( $self->{_content}->{order_number}) { + $self->required_fields(qw/type login password action amount/); + } else { + $self->required_fields(qw/type login password action amount + card_number expiration/); + } + } elsif ( $self->{_content}->{action} eq 'VOID' ) { + $self->required_fields(qw/login password action/); + } else { $self->required_fields(qw/type login password action amount last_name first_name card_number expiration/); + } } else { Carp::croak("AuthorizeNet can't handle transaction type: ". $self->transaction_type()); } my %post_data = $self->get_fields(qw/x_Login x_Password x_Invoice_Num - x_Description x_Amount x_Cust_ID - x_Method x_Type x_Card_Num x_Exp_Date - x_Auth_Code x_Bank_Acct_Num - x_Bank_ABA_Code x_Bank_Name - x_Last_Name x_First_Name x_Address - x_City x_State x_Zip x_Country x_Phone - x_Fax x_Email x_Email_Customer - x_Company x_Country/); + x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date + x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num + x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type + x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP + x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB + x_Last_Name x_First_Name x_Address x_City x_State x_Zip x_Country + x_Phone x_Fax x_Email x_Email_Customer x_Company x_Country + x_Currency_Code x_Trans_ID/); $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE"; $post_data{'x_ADC_Delim_Data'} = 'TRUE'; $post_data{'x_ADC_URL'} = 'FALSE'; - $post_data{'x_Version'} = '3.0'; + $post_data{'x_Version'} = '3.1'; my $pd = make_form(%post_data); my $s = $self->server(); my $p = $self->port(); my $t = $self->path(); - my($page,$server_response,%headers) = post_https($s,$p,$t,'',$pd); + my $r = $self->{_content}->{referer}; + my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd); + #escape NULL (binary 0x00) values + $page =~ s/\x00/\^0/g; - my $csv = new Text::CSV(); + my $csv = new Text::CSV_XS({ 'binary'=>1 }); $csv->parse($page); my @col = $csv->fields(); @@ -141,10 +182,21 @@ sub submit { $self->is_success(1); $self->result_code($col[0]); $self->authorization($col[4]); + $self->order_number($col[6]); } else { $self->is_success(0); $self->result_code($col[2]); $self->error_message($col[3]); + unless ( $self->result_code() ) { #additional logging information + #$page =~ s/\x00/\^0/g; + $self->error_message($col[3]. + " DEBUG: No x_response_code from server, ". + "(HTTPS response: $server_response) ". + "(HTTPS headers: ". + join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ". + "(Raw HTTPS content: $page)" + ); + } } } @@ -176,7 +228,9 @@ Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::Onlin state => 'UT', zip => '84058', card_number => '4007000000027', - expiration => '09/99', + expiration => '09/02', + cvv2 => '1234', #optional + referer => 'http://valid.referer.url/', ); $tx->submit(); @@ -202,20 +256,58 @@ For detailed information see L. =head1 NOTE -Unlike Business::OnlinePayment or previous verisons of -Business::OnlinePayment::AuthorizeNet, 3.0 requires separate first_name and +Unlike Business::OnlinePayment or pre-3.0 verisons of +Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and last_name fields. +Business::OnlinePayment::AuthorizeNet uses the ADC direct response method, +and sends a username and password with every transaction. Therefore, +Authorize.Net's referrer "security" is not necessary. In your Authorize.Net +interface at https://secure.authorize.net/ make sure the list of allowable +referers is blank. Alternatively, set the B field in the transaction +content. + +To settle an authorization-only transaction (where you set action to +'Authorization Only'), submit the nine-digit transaction id code in +the field "order_number" with the action set to "Post Authorization". +You can get the transaction id from the authorization by calling the +order_number method on the object returned from the authorization. +You must also submit the amount field with a value less than or equal +to the amount specified in the original authorization. + +Recently (February 2002), Authorize.Net has turned address +verification on by default for all merchants. If you do not have +valid address information for your customer (such as in an IVR +application), you must disable address verification in the Merchant +Menu page at https://secure.authorize.net/ so that the transactions +aren't denied due to a lack of address information. + =head1 COMPATIBILITY -This module implements Authorize.Net's API verison 3.0. +This module implements Authorize.Net's API verison 3.1 using the ADC +Direct Response method. See +https://secure.authorize.net/docs/developersguide.pml for details. =head1 AUTHOR Jason Kohles, jason@mediabang.com Ivan Kohler updated it for Authorize.Net protocol -3.0 and is the current maintainer. +3.0/3.1 and is the current maintainer. Please send patches as unified diffs +(diff -u). + +Jason Spence contributed support for separate +Authorization Only and Post Authorization steps and wrote some docs. +OST paid for it. + +T.J. Mather sent a patch for the CVV2 field. + +Mike Barry sent in a patch for the referer field. + +Yuri V. Mkrtumyan sent in a patch to add the void action. + +Paul Zimmer sent in a patch for +card-less post authorizations. =head1 SEE ALSO