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_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
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 );
163 } elsif ( $self->{_content}->{action} eq 'CREDIT' ) {
164 push @required_fields, qw( amount order_number card_number );
166 push @required_fields, qw(
167 amount last_name first_name card_number expiration
171 Carp::croak( "AuthorizeNet can't handle transaction type: ".
172 $self->transaction_type() );
177 $self->required_fields(@required_fields);
179 my %post_data = $self->get_fields(qw/
180 x_Login x_Password x_Tran_Key x_Invoice_Num
181 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
182 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
183 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
184 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
185 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
186 x_Last_Name x_First_Name x_Company
187 x_Address x_City x_State x_Zip
189 x_Ship_To_Last_Name x_Ship_To_First_Name x_Ship_To_Company
190 x_Ship_To_Address x_Ship_To_City x_Ship_To_State x_Ship_To_Zip
192 x_Phone x_Fax x_Email x_Email_Customer x_Country
193 x_Currency_Code x_Trans_ID/);
194 $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
195 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
196 $post_data{'x_delim_char'} = ',';
197 $post_data{'x_encap_char'} = '"';
198 $post_data{'x_ADC_URL'} = 'FALSE';
199 $post_data{'x_Version'} = '3.1';
201 my $pd = make_form(%post_data);
202 my $s = $self->server();
203 my $p = $self->port();
204 my $t = $self->path();
205 my $r = $self->{_content}->{referer};
206 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
207 #escape NULL (binary 0x00) values
208 $page =~ s/\x00/\^0/g;
210 my $csv = new Text::CSV_XS({ 'binary'=>1 });
212 my @col = $csv->fields();
214 $self->server_response($page);
215 $self->avs_code($col[5]);
216 $self->order_number($col[6]);
217 $self->md5($col[37]);
218 $self->cvv2_response($col[38]);
219 $self->cavv_response($col[39]);
221 if($col[0] eq "1" ) { # Authorized/Pending/Test
222 $self->is_success(1);
223 $self->result_code($col[0]);
224 $self->authorization($col[4]);
226 $self->is_success(0);
227 $self->result_code($col[2]);
228 $self->error_message($col[3]);
229 unless ( $self->result_code() ) { #additional logging information
230 #$page =~ s/\x00/\^0/g;
231 $self->error_message($col[3].
232 " DEBUG: No x_response_code from server, ".
233 "(HTTPS response: $server_response) ".
235 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
236 "(Raw HTTPS content: $page)"
247 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
251 use Business::OnlinePayment;
254 # One step transaction, the simple case.
257 my $tx = new Business::OnlinePayment("AuthorizeNet");
260 login => 'testdrive',
262 action => 'Normal Authorization',
263 description => 'Business::OnlinePayment test',
265 invoice_number => '100100',
266 customer_id => 'jsk',
267 first_name => 'Jason',
268 last_name => 'Kohles',
269 address => '123 Anystreet',
273 card_number => '4007000000027',
274 expiration => '09/02',
275 cvv2 => '1234', #optional
276 referer => 'http://valid.referer.url/',
280 if($tx->is_success()) {
281 print "Card processed successfully: ".$tx->authorization."\n";
283 print "Card was rejected: ".$tx->error_message."\n";
287 # Two step transaction, authorization and capture.
288 # If you don't need to review order before capture, you can
289 # process in one step as above.
292 my $tx = new Business::OnlinePayment("AuthorizeNet");
295 login => 'testdrive',
297 action => 'Authorization Only',
298 description => 'Business::OnlinePayment test',
300 invoice_number => '100100',
301 customer_id => 'jsk',
302 first_name => 'Jason',
303 last_name => 'Kohles',
304 address => '123 Anystreet',
308 card_number => '4007000000027',
309 expiration => '09/02',
310 cvv2 => '1234', #optional
311 referer => 'http://valid.referer.url/',
315 if($tx->is_success()) {
316 # get information about authorization
317 $authorization = $tx->authorization
318 $ordernum = $tx->order_number;
319 $avs_code = $tx->avs_code; # AVS Response Code
320 $cvv2_response = $tx->cvv2_response; # CVV2/CVC2/CID Response Code
321 $cavv_response = $tx->cavv_response; # Cardholder Authentication
322 # Verification Value (CAVV) Response
325 # now capture transaction
326 my $capture = new Business::OnlinePayment("AuthorizeNet");
330 action => 'Post Authorization',
332 password => 'YOURPASSWORD',
333 order_number => $ordernum,
339 if($capture->is_success()) {
340 print "Card captured successfully: ".$capture->authorization."\n";
342 print "Card was rejected: ".$capture->error_message."\n";
346 print "Card was rejected: ".$tx->error_message."\n";
349 =head1 SUPPORTED TRANSACTION TYPES
351 =head2 CC, Visa, MasterCard, American Express, Discover
353 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, card_number, expiration.
357 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, bank_name.
361 For detailed information see L<Business::OnlinePayment>.
365 Unlike Business::OnlinePayment or pre-3.0 verisons of
366 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
369 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
370 Integration Method (AIM) (formerly known as ADC direct response)", sending a
371 username and transaction_key or password with every transaction. Therefore, Authorize.Net's
372 referrer "security" is not necessary. In your Authorize.Net interface at
373 https://secure.authorize.net/ make sure the list of allowable referers is
374 blank. Alternatively, set the B<referer> field in the transaction content.
376 To settle an authorization-only transaction (where you set action to
377 'Authorization Only'), submit the nine-digit transaction id code in
378 the field "order_number" with the action set to "Post Authorization".
379 You can get the transaction id from the authorization by calling the
380 order_number method on the object returned from the authorization.
381 You must also submit the amount field with a value less than or equal
382 to the amount specified in the original authorization.
384 Recently (February 2002), Authorize.Net has turned address
385 verification on by default for all merchants. If you do not have
386 valid address information for your customer (such as in an IVR
387 application), you must disable address verification in the Merchant
388 Menu page at https://secure.authorize.net/ so that the transactions
389 aren't denied due to a lack of address information.
393 This module implements Authorize.Net's API verison 3.1 using the Advanced
394 Integration Method (AIM), formerly known as ADC Direct Response. See
395 http://www.authorize.net/support/AIM_guide.pdf for details.
399 Jason Kohles, jason@mediabang.com
401 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
402 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
405 Jason Spence <jspence@lightconsulting.com> contributed support for separate
406 Authorization Only and Post Authorization steps and wrote some docs.
407 OST <services@ostel.com> paid for it.
409 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
411 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
413 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
415 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
416 card-less post authorizations.
418 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
419 key" authentication as well support for the recurring_billing flag and the md5
420 method that returns the MD5 hash which is returned by the gateway.
424 perl(1). L<Business::OnlinePayment>.