1 package Business::OnlinePayment::AuthorizeNet;
5 use Business::OnlinePayment;
6 use Net::SSLeay qw/make_form post_https make_headers/;
8 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
12 @ISA = qw(Exporter Business::OnlinePayment);
20 $self->server('secure.authorize.net');
22 $self->path('/gateway/transact.dll');
24 $self->build_subs(qw( order_number md5 avs_code cvv2_response
32 my %content = $self->content();
35 my %actions = ('normal authorization' => 'AUTH_CAPTURE',
36 'authorization only' => 'AUTH_ONLY',
38 'post authorization' => 'PRIOR_AUTH_CAPTURE',
41 $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
44 my %types = ('visa' => 'CC',
46 'american express' => 'CC',
50 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
51 $self->transaction_type($content{'type'});
53 $content{'referer'} = defined( $content{'referer'} )
54 ? make_headers( 'Referer' => $content{'referer'} )
57 # stuff it back into %content
58 $self->content(%content);
64 my %content = $self->content();
66 $content{$map{$_}} = $content{$_};
68 $self->content(%content);
72 my($self,@fields) = @_;
74 my %content = $self->content();
76 foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
87 password => 'x_Password',
88 transaction_key => 'x_Tran_Key',
90 description => 'x_Description',
92 currency => 'x_Currency_Code',
93 invoice_number => 'x_Invoice_Num',
94 order_number => 'x_Trans_ID',
95 auth_code => 'x_Auth_Code',
96 customer_id => 'x_Cust_ID',
97 customer_ip => 'x_Customer_IP',
98 last_name => 'x_Last_Name',
99 first_name => 'x_First_Name',
100 company => 'x_Company',
101 address => 'x_Address',
105 country => 'x_Country',
106 ship_last_name => 'x_Ship_To_Last_Name',
107 ship_first_name => 'x_Ship_To_First_Name',
108 ship_company => 'x_Ship_To_Company',
109 ship_address => 'x_Ship_To_Address',
110 ship_city => 'x_Ship_To_City',
111 ship_state => 'x_Ship_To_State',
112 ship_zip => 'x_Ship_To_Zip',
113 ship_country => 'x_Ship_To_Country',
117 card_number => 'x_Card_Num',
118 expiration => 'x_Exp_Date',
119 cvv2 => 'x_Card_Code',
120 check_type => 'x_Echeck_Type',
121 account_name => 'x_Bank_Acct_Name',
122 account_number => 'x_Bank_Acct_Num',
123 account_type => 'x_Bank_Acct_Type',
124 bank_name => 'x_Bank_Name',
125 routing_code => 'x_Bank_ABA_Code',
126 customer_org => 'x_Customer_Organization_Type',
127 customer_ssn => 'x_Customer_Tax_ID',
128 license_num => 'x_Drivers_License_Num',
129 license_state => 'x_Drivers_License_State',
130 license_dob => 'x_Drivers_License_DOB',
131 recurring_billing => 'x_Recurring_Billing',
134 my $auth_type = $self->{_content}->{transaction_key}
138 my @required_fields = ( qw(type action login), $auth_type );
140 unless ( $self->{_content}->{action} eq 'VOID' ) {
142 if ($self->transaction_type() eq "ECHECK") {
144 push @required_fields, qw(
145 amount routing_code account_number account_type bank_name
149 if (defined $self->{_content}->{customer_org} and
150 length $self->{_content}->{customer_org}
152 push @required_fields, qw( customer_org customer_ssn );
154 push @required_fields, qw(license_num license_state license_dob);
157 } elsif ($self->transaction_type() eq 'CC' ) {
159 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
160 if ( $self->{_content}->{order_number} ) {
161 push @required_fields, qw( amount order_number );
163 push @required_fields, qw( amount card_number expiration );
165 } elsif ( $self->{_content}->{action} eq 'CREDIT' ) {
166 push @required_fields, qw( amount order_number card_number );
168 push @required_fields, qw(
169 amount last_name first_name card_number expiration
173 Carp::croak( "AuthorizeNet can't handle transaction type: ".
174 $self->transaction_type() );
179 $self->required_fields(@required_fields);
181 my %post_data = $self->get_fields(qw/
182 x_Login x_Password x_Tran_Key x_Invoice_Num
183 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
184 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
185 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
186 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
187 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
188 x_Last_Name x_First_Name x_Company
189 x_Address x_City x_State x_Zip
191 x_Ship_To_Last_Name x_Ship_To_First_Name x_Ship_To_Company
192 x_Ship_To_Address x_Ship_To_City x_Ship_To_State x_Ship_To_Zip
194 x_Phone x_Fax x_Email x_Email_Customer x_Country
195 x_Currency_Code x_Trans_ID/);
196 $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
197 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
198 $post_data{'x_delim_char'} = ',';
199 $post_data{'x_encap_char'} = '"';
200 $post_data{'x_ADC_URL'} = 'FALSE';
201 $post_data{'x_Version'} = '3.1';
203 my $pd = make_form(%post_data);
204 my $s = $self->server();
205 my $p = $self->port();
206 my $t = $self->path();
207 my $r = $self->{_content}->{referer};
208 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
209 #escape NULL (binary 0x00) values
210 $page =~ s/\x00/\^0/g;
212 #trim 'ip_addr="1.2.3.4"' added by eProcessingNetwork Authorize.Net compat
213 $page =~ s/,ip_addr="[\d\.]+"$//;
215 my $csv = new Text::CSV_XS({ 'binary'=>1 });
217 my @col = $csv->fields();
219 $self->server_response($page);
220 $self->avs_code($col[5]);
221 $self->order_number($col[6]);
222 $self->md5($col[37]);
223 $self->cvv2_response($col[38]);
224 $self->cavv_response($col[39]);
226 if($col[0] eq "1" ) { # Authorized/Pending/Test
227 $self->is_success(1);
228 $self->result_code($col[0]);
229 $self->authorization($col[4]);
231 $self->is_success(0);
232 $self->result_code($col[2]);
233 $self->error_message($col[3]);
234 unless ( $self->result_code() ) { #additional logging information
235 #$page =~ s/\x00/\^0/g;
236 $self->error_message($col[3].
237 " DEBUG: No x_response_code from server, ".
238 "(HTTPS response: $server_response) ".
240 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
241 "(Raw HTTPS content: $page)"
252 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
256 use Business::OnlinePayment;
259 # One step transaction, the simple case.
262 my $tx = new Business::OnlinePayment("AuthorizeNet");
265 login => 'testdrive',
267 action => 'Normal Authorization',
268 description => 'Business::OnlinePayment test',
270 invoice_number => '100100',
271 customer_id => 'jsk',
272 first_name => 'Jason',
273 last_name => 'Kohles',
274 address => '123 Anystreet',
278 card_number => '4007000000027',
279 expiration => '09/02',
280 cvv2 => '1234', #optional
281 referer => 'http://valid.referer.url/',
285 if($tx->is_success()) {
286 print "Card processed successfully: ".$tx->authorization."\n";
288 print "Card was rejected: ".$tx->error_message."\n";
292 # Two step transaction, authorization and capture.
293 # If you don't need to review order before capture, you can
294 # process in one step as above.
297 my $tx = new Business::OnlinePayment("AuthorizeNet");
300 login => 'testdrive',
302 action => 'Authorization Only',
303 description => 'Business::OnlinePayment test',
305 invoice_number => '100100',
306 customer_id => 'jsk',
307 first_name => 'Jason',
308 last_name => 'Kohles',
309 address => '123 Anystreet',
313 card_number => '4007000000027',
314 expiration => '09/02',
315 cvv2 => '1234', #optional
316 referer => 'http://valid.referer.url/',
320 if($tx->is_success()) {
321 # get information about authorization
322 $authorization = $tx->authorization
323 $ordernum = $tx->order_number;
324 $avs_code = $tx->avs_code; # AVS Response Code
325 $cvv2_response = $tx->cvv2_response; # CVV2/CVC2/CID Response Code
326 $cavv_response = $tx->cavv_response; # Cardholder Authentication
327 # Verification Value (CAVV) Response
330 # now capture transaction
331 my $capture = new Business::OnlinePayment("AuthorizeNet");
335 action => 'Post Authorization',
337 password => 'YOURPASSWORD',
338 order_number => $ordernum,
344 if($capture->is_success()) {
345 print "Card captured successfully: ".$capture->authorization."\n";
347 print "Card was rejected: ".$capture->error_message."\n";
351 print "Card was rejected: ".$tx->error_message."\n";
354 =head1 SUPPORTED TRANSACTION TYPES
356 =head2 CC, Visa, MasterCard, American Express, Discover
358 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, card_number, expiration.
362 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, bank_name.
366 For detailed information see L<Business::OnlinePayment>.
368 =head1 METHODS AND FUNCTIONS
370 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
374 Returns the response reason code (this is different than the response code).
378 Returns the response reason text.
380 =head2 server_response
382 Returns the complete response from the server.
386 Unlike Business::OnlinePayment or pre-3.0 verisons of
387 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
390 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
391 Integration Method (AIM) (formerly known as ADC direct response)", sending a
392 username and transaction_key or password with every transaction. Therefore, Authorize.Net's
393 referrer "security" is not necessary. In your Authorize.Net interface at
394 https://secure.authorize.net/ make sure the list of allowable referers is
395 blank. Alternatively, set the B<referer> field in the transaction content.
397 To settle an authorization-only transaction (where you set action to
398 'Authorization Only'), submit the nine-digit transaction id code in
399 the field "order_number" with the action set to "Post Authorization".
400 You can get the transaction id from the authorization by calling the
401 order_number method on the object returned from the authorization.
402 You must also submit the amount field with a value less than or equal
403 to the amount specified in the original authorization.
405 Recently (February 2002), Authorize.Net has turned address
406 verification on by default for all merchants. If you do not have
407 valid address information for your customer (such as in an IVR
408 application), you must disable address verification in the Merchant
409 Menu page at https://secure.authorize.net/ so that the transactions
410 aren't denied due to a lack of address information.
414 This module implements Authorize.Net's API verison 3.1 using the Advanced
415 Integration Method (AIM), formerly known as ADC Direct Response. See
416 http://www.authorize.net/support/AIM_guide.pdf for details.
420 Jason Kohles, jason@mediabang.com
422 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
423 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
426 Jason Spence <jspence@lightconsulting.com> contributed support for separate
427 Authorization Only and Post Authorization steps and wrote some docs.
428 OST <services@ostel.com> paid for it.
430 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
432 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
434 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
436 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
437 card-less post authorizations.
439 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
440 key" authentication as well support for the recurring_billing flag and the md5
441 method that returns the MD5 hash which is returned by the gateway.
445 perl(1). L<Business::OnlinePayment>.