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 my $csv = new Text::CSV_XS({ 'binary'=>1 });
214 my @col = $csv->fields();
216 $self->server_response($page);
217 $self->avs_code($col[5]);
218 $self->order_number($col[6]);
219 $self->md5($col[37]);
220 $self->cvv2_response($col[38]);
221 $self->cavv_response($col[39]);
223 if($col[0] eq "1" ) { # Authorized/Pending/Test
224 $self->is_success(1);
225 $self->result_code($col[0]);
226 $self->authorization($col[4]);
228 $self->is_success(0);
229 $self->result_code($col[2]);
230 $self->error_message($col[3]);
231 unless ( $self->result_code() ) { #additional logging information
232 #$page =~ s/\x00/\^0/g;
233 $self->error_message($col[3].
234 " DEBUG: No x_response_code from server, ".
235 "(HTTPS response: $server_response) ".
237 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
238 "(Raw HTTPS content: $page)"
249 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
253 use Business::OnlinePayment;
256 # One step transaction, the simple case.
259 my $tx = new Business::OnlinePayment("AuthorizeNet");
262 login => 'testdrive',
264 action => 'Normal Authorization',
265 description => 'Business::OnlinePayment test',
267 invoice_number => '100100',
268 customer_id => 'jsk',
269 first_name => 'Jason',
270 last_name => 'Kohles',
271 address => '123 Anystreet',
275 card_number => '4007000000027',
276 expiration => '09/02',
277 cvv2 => '1234', #optional
278 referer => 'http://valid.referer.url/',
282 if($tx->is_success()) {
283 print "Card processed successfully: ".$tx->authorization."\n";
285 print "Card was rejected: ".$tx->error_message."\n";
289 # Two step transaction, authorization and capture.
290 # If you don't need to review order before capture, you can
291 # process in one step as above.
294 my $tx = new Business::OnlinePayment("AuthorizeNet");
297 login => 'testdrive',
299 action => 'Authorization Only',
300 description => 'Business::OnlinePayment test',
302 invoice_number => '100100',
303 customer_id => 'jsk',
304 first_name => 'Jason',
305 last_name => 'Kohles',
306 address => '123 Anystreet',
310 card_number => '4007000000027',
311 expiration => '09/02',
312 cvv2 => '1234', #optional
313 referer => 'http://valid.referer.url/',
317 if($tx->is_success()) {
318 # get information about authorization
319 $authorization = $tx->authorization
320 $ordernum = $tx->order_number;
321 $avs_code = $tx->avs_code; # AVS Response Code
322 $cvv2_response = $tx->cvv2_response; # CVV2/CVC2/CID Response Code
323 $cavv_response = $tx->cavv_response; # Cardholder Authentication
324 # Verification Value (CAVV) Response
327 # now capture transaction
328 my $capture = new Business::OnlinePayment("AuthorizeNet");
332 action => 'Post Authorization',
334 password => 'YOURPASSWORD',
335 order_number => $ordernum,
341 if($capture->is_success()) {
342 print "Card captured successfully: ".$capture->authorization."\n";
344 print "Card was rejected: ".$capture->error_message."\n";
348 print "Card was rejected: ".$tx->error_message."\n";
351 =head1 SUPPORTED TRANSACTION TYPES
353 =head2 CC, Visa, MasterCard, American Express, Discover
355 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, card_number, expiration.
359 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, bank_name.
363 For detailed information see L<Business::OnlinePayment>.
365 =head1 METHODS AND FUNCTIONS
367 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
371 Returns the response reason code (this is different than the response code).
375 Returns the response reason text.
377 =head2 server_response
379 Returns the complete response from the server.
383 Unlike Business::OnlinePayment or pre-3.0 verisons of
384 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
387 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
388 Integration Method (AIM) (formerly known as ADC direct response)", sending a
389 username and transaction_key or password with every transaction. Therefore, Authorize.Net's
390 referrer "security" is not necessary. In your Authorize.Net interface at
391 https://secure.authorize.net/ make sure the list of allowable referers is
392 blank. Alternatively, set the B<referer> field in the transaction content.
394 To settle an authorization-only transaction (where you set action to
395 'Authorization Only'), submit the nine-digit transaction id code in
396 the field "order_number" with the action set to "Post Authorization".
397 You can get the transaction id from the authorization by calling the
398 order_number method on the object returned from the authorization.
399 You must also submit the amount field with a value less than or equal
400 to the amount specified in the original authorization.
402 Recently (February 2002), Authorize.Net has turned address
403 verification on by default for all merchants. If you do not have
404 valid address information for your customer (such as in an IVR
405 application), you must disable address verification in the Merchant
406 Menu page at https://secure.authorize.net/ so that the transactions
407 aren't denied due to a lack of address information.
411 This module implements Authorize.Net's API verison 3.1 using the Advanced
412 Integration Method (AIM), formerly known as ADC Direct Response. See
413 http://www.authorize.net/support/AIM_guide.pdf for details.
417 Jason Kohles, jason@mediabang.com
419 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
420 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
423 Jason Spence <jspence@lightconsulting.com> contributed support for separate
424 Authorization Only and Post Authorization steps and wrote some docs.
425 OST <services@ostel.com> paid for it.
427 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
429 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
431 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
433 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
434 card-less post authorizations.
436 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
437 key" authentication as well support for the recurring_billing flag and the md5
438 method that returns the MD5 hash which is returned by the gateway.
442 perl(1). L<Business::OnlinePayment>.