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