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 AutoLoader 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_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 if ($self->transaction_type() eq "ECHECK") {
139 if ($self->{_content}->{customer_org} ne '') {
140 $self->required_fields(qw/type login amount routing_code
141 account_number account_type bank_name
142 account_name account_type
143 customer_org customer_ssn/, $auth_type);
145 $self->required_fields(qw/type login amount routing_code
146 account_number account_type bank_name
147 account_name account_type
148 license_num license_state license_dob/, $auth_type);
150 } elsif ($self->transaction_type() eq 'CC' ) {
151 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
152 if ( $self->{_content}->{order_number}) {
153 $self->required_fields(qw/type login action amount/, $auth_type);
155 $self->required_fields(qw/type login action amount
156 card_number expiration/, $auth_type);
158 } elsif ( $self->{_content}->{action} eq 'VOID' ) {
159 $self->required_fields(qw/login action/,$auth_type);
161 $self->required_fields(qw/type login action amount last_name
162 first_name card_number expiration/, $auth_type);
165 Carp::croak("AuthorizeNet can't handle transaction type: ".
166 $self->transaction_type());
169 my %post_data = $self->get_fields(qw/x_Login x_Password x_Tran_Key x_Invoice_Num
170 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
171 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
172 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
173 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
174 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
175 x_Last_Name x_First_Name x_Company
176 x_Address x_City x_State x_Zip
178 x_Ship_To_Last_Name x_Ship_To_First_Name x_Ship_To_Company
179 x_Ship_To_Address x_Ship_To_City x_Ship_To_State x_Ship_To_Zip
181 x_Phone x_Fax x_Email x_Email_Customer x_Country
182 x_Currency_Code x_Trans_ID/);
183 $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
184 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
185 $post_data{'x_ADC_URL'} = 'FALSE';
186 $post_data{'x_Version'} = '3.1';
188 my $pd = make_form(%post_data);
189 my $s = $self->server();
190 my $p = $self->port();
191 my $t = $self->path();
192 my $r = $self->{_content}->{referer};
193 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
194 #escape NULL (binary 0x00) values
195 $page =~ s/\x00/\^0/g;
197 my $csv = new Text::CSV_XS({ 'binary'=>1 });
199 my @col = $csv->fields();
201 $self->server_response($page);
202 $self->avs_code($col[5]);
203 $self->order_number($col[6]);
204 $self->md5($col[37]);
205 $self->cvv2_response($col[38]);
206 $self->cavv_response($col[39]);
208 if($col[0] eq "1" ) { # Authorized/Pending/Test
209 $self->is_success(1);
210 $self->result_code($col[0]);
211 $self->authorization($col[4]);
213 $self->is_success(0);
214 $self->result_code($col[2]);
215 $self->error_message($col[3]);
216 unless ( $self->result_code() ) { #additional logging information
217 #$page =~ s/\x00/\^0/g;
218 $self->error_message($col[3].
219 " DEBUG: No x_response_code from server, ".
220 "(HTTPS response: $server_response) ".
222 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
223 "(Raw HTTPS content: $page)"
234 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
238 use Business::OnlinePayment;
241 # One step transaction, the simple case.
244 my $tx = new Business::OnlinePayment("AuthorizeNet");
247 login => 'testdrive',
249 action => 'Normal Authorization',
250 description => 'Business::OnlinePayment test',
252 invoice_number => '100100',
253 customer_id => 'jsk',
254 first_name => 'Jason',
255 last_name => 'Kohles',
256 address => '123 Anystreet',
260 card_number => '4007000000027',
261 expiration => '09/02',
262 cvv2 => '1234', #optional
263 referer => 'http://valid.referer.url/',
267 if($tx->is_success()) {
268 print "Card processed successfully: ".$tx->authorization."\n";
270 print "Card was rejected: ".$tx->error_message."\n";
274 # Two step transaction, authorization and capture.
275 # If you don't need to review order before capture, you can
276 # process in one step as above.
279 my $tx = new Business::OnlinePayment("AuthorizeNet");
282 login => 'testdrive',
284 action => 'Authorization Only',
285 description => 'Business::OnlinePayment test',
287 invoice_number => '100100',
288 customer_id => 'jsk',
289 first_name => 'Jason',
290 last_name => 'Kohles',
291 address => '123 Anystreet',
295 card_number => '4007000000027',
296 expiration => '09/02',
297 cvv2 => '1234', #optional
298 referer => 'http://valid.referer.url/',
302 if($tx->is_success()) {
303 # get information about authorization
304 $authorization = $tx->authorization
305 $ordernum = $tx->order_number;
306 $avs_code = $tx->avs_code; # AVS Response Code
307 $cvv2_response = $tx->cvv2_response; # CVV2/CVC2/CID Response Code
308 $cavv_response = $tx->cavv_response; # Cardholder Authentication
309 # Verification Value (CAVV) Response
312 # now capture transaction
313 my $capture = new Business::OnlinePayment("AuthorizeNet");
317 action => 'Post Authorization',
319 password => 'YOURPASSWORD',
320 order_number => $ordernum,
326 if($capture->is_success()) {
327 print "Card captured successfully: ".$capture->authorization."\n";
329 print "Card was rejected: ".$capture->error_message."\n";
333 print "Card was rejected: ".$tx->error_message."\n";
336 =head1 SUPPORTED TRANSACTION TYPES
338 =head2 Visa, MasterCard, American Express, Discover
340 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, card_number, expiration.
344 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, bank_name.
348 For detailed information see L<Business::OnlinePayment>.
352 Unlike Business::OnlinePayment or pre-3.0 verisons of
353 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
356 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
357 Integration Method (AIM) (formerly known as ADC direct response)", sending a
358 username and transaction_key or password with every transaction. Therefore, Authorize.Net's
359 referrer "security" is not necessary. In your Authorize.Net interface at
360 https://secure.authorize.net/ make sure the list of allowable referers is
361 blank. Alternatively, set the B<referer> field in the transaction content.
363 To settle an authorization-only transaction (where you set action to
364 'Authorization Only'), submit the nine-digit transaction id code in
365 the field "order_number" with the action set to "Post Authorization".
366 You can get the transaction id from the authorization by calling the
367 order_number method on the object returned from the authorization.
368 You must also submit the amount field with a value less than or equal
369 to the amount specified in the original authorization.
371 Recently (February 2002), Authorize.Net has turned address
372 verification on by default for all merchants. If you do not have
373 valid address information for your customer (such as in an IVR
374 application), you must disable address verification in the Merchant
375 Menu page at https://secure.authorize.net/ so that the transactions
376 aren't denied due to a lack of address information.
380 This module implements Authorize.Net's API verison 3.1 using the ADC
381 Direct Response method. See
382 https://secure.authorize.net/docs/developersguide.pml for details.
386 Jason Kohles, jason@mediabang.com
388 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
389 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
392 Jason Spence <jspence@lightconsulting.com> contributed support for separate
393 Authorization Only and Post Authorization steps and wrote some docs.
394 OST <services@ostel.com> paid for it.
396 T.J. Mather <tjmather@maxmind.com> sent a patch for the CVV2 field.
398 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
400 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
402 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
403 card-less post authorizations.
405 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
406 key" authentication as well support for the recurring_billing flag and the md5'
407 method that returns the MD5 hash which is returned by the gateway.
411 perl(1). L<Business::OnlinePayment>.