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('order_number'); #no idea how it worked for jason w/o this
25 $self->build_subs('md5');
31 my %content = $self->content();
34 my %actions = ('normal authorization' => 'AUTH_CAPTURE',
35 'authorization only' => 'AUTH_ONLY',
37 'post authorization' => 'PRIOR_AUTH_CAPTURE',
40 $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
43 my %types = ('visa' => 'CC',
45 'american express' => 'CC',
49 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
50 $self->transaction_type($content{'type'});
52 $content{'referer'} = defined( $content{'referer'} )
53 ? make_headers( 'Referer' => $content{'referer'} )
56 # stuff it back into %content
57 $self->content(%content);
63 my %content = $self->content();
65 $content{$map{$_}} = $content{$_};
67 $self->content(%content);
71 my($self,@fields) = @_;
73 my %content = $self->content();
75 foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
86 password => 'x_Password',
87 transaction_key => 'x_Tran_Key',
89 description => 'x_Description',
91 currency => 'x_Currency_Code',
92 invoice_number => 'x_Invoice_Num',
93 order_number => 'x_Trans_ID',
94 auth_code => 'x_Auth_Code',
95 customer_id => 'x_Cust_ID',
96 customer_ip => 'x_Customer_IP',
97 last_name => 'x_Last_Name',
98 first_name => 'x_First_Name',
99 address => 'x_Address',
103 country => 'x_Country',
107 company => 'x_Company',
108 card_number => 'x_Card_Num',
109 expiration => 'x_Exp_Date',
110 cvv2 => 'x_Card_Code',
111 check_type => 'x_Echeck_Type',
112 account_name => 'x_Bank_Acct_Name',
113 account_number => 'x_Bank_Acct_Num',
114 account_type => 'x_Bank_Acct_Type',
115 bank_name => 'x_Bank_Name',
116 routing_code => 'x_Bank_ABA_Code',
117 customer_org => 'x_Customer_Organization_Type',
118 customer_ssn => 'x_Customer_Tax_ID',
119 license_num => 'x_Drivers_License_Num',
120 license_state => 'x_Drivers_License_State',
121 license_dob => 'x_Drivers_License_DOB',
122 recurring_billing => 'x_Recurring_Billing',
124 my $auth_type = $self->{_content}->{transaction_key}?'transaction_key':'password';
126 if ($self->transaction_type() eq "ECHECK") {
127 if ($self->{_content}->{customer_org} ne '') {
128 $self->required_fields(qw/type login amount routing_code
129 account_number account_type bank_name
130 account_name account_type
131 customer_org customer_ssn/, $auth_type);
133 $self->required_fields(qw/type login amount routing_code
134 account_number account_type bank_name
135 account_name account_type
136 license_num license_state license_dob/, $auth_type);
138 } elsif ($self->transaction_type() eq 'CC' ) {
139 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
140 if ( $self->{_content}->{order_number}) {
141 $self->required_fields(qw/type login action amount/, $auth_type);
143 $self->required_fields(qw/type login action amount
144 card_number expiration/, $auth_type);
146 } elsif ( $self->{_content}->{action} eq 'VOID' ) {
147 $self->required_fields(qw/login action/,$auth_type);
149 $self->required_fields(qw/type login action amount last_name
150 first_name card_number expiration/, $auth_type);
153 Carp::croak("AuthorizeNet can't handle transaction type: ".
154 $self->transaction_type());
157 my %post_data = $self->get_fields(qw/x_Login x_Password x_Tran_Key x_Invoice_Num
158 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
159 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
160 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
161 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
162 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
163 x_Last_Name x_First_Name x_Address x_City x_State x_Zip x_Country
164 x_Phone x_Fax x_Email x_Email_Customer x_Company x_Country
165 x_Currency_Code x_Trans_ID/);
166 $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
167 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
168 $post_data{'x_ADC_URL'} = 'FALSE';
169 $post_data{'x_Version'} = '3.1';
171 my $pd = make_form(%post_data);
172 my $s = $self->server();
173 my $p = $self->port();
174 my $t = $self->path();
175 my $r = $self->{_content}->{referer};
176 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
177 #escape NULL (binary 0x00) values
178 $page =~ s/\x00/\^0/g;
180 my $csv = new Text::CSV_XS({ 'binary'=>1 });
182 my @col = $csv->fields();
184 $self->server_response($page);
185 $self->md5($col[37]);
186 if($col[0] eq "1" ) { # Authorized/Pending/Test
187 $self->is_success(1);
188 $self->result_code($col[0]);
189 $self->authorization($col[4]);
190 $self->order_number($col[6]);
192 $self->is_success(0);
193 $self->result_code($col[2]);
194 $self->error_message($col[3]);
195 unless ( $self->result_code() ) { #additional logging information
196 #$page =~ s/\x00/\^0/g;
197 $self->error_message($col[3].
198 " DEBUG: No x_response_code from server, ".
199 "(HTTPS response: $server_response) ".
201 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
202 "(Raw HTTPS content: $page)"
213 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
217 use Business::OnlinePayment;
219 my $tx = new Business::OnlinePayment("AuthorizeNet");
222 login => 'testdrive',
224 action => 'Normal Authorization',
225 description => 'Business::OnlinePayment test',
227 invoice_number => '100100',
228 customer_id => 'jsk',
229 first_name => 'Jason',
230 last_name => 'Kohles',
231 address => '123 Anystreet',
235 card_number => '4007000000027',
236 expiration => '09/02',
237 cvv2 => '1234', #optional
238 referer => 'http://valid.referer.url/',
242 if($tx->is_success()) {
243 print "Card processed successfully: ".$tx->authorization."\n";
245 print "Card was rejected: ".$tx->error_message."\n";
248 =head1 SUPPORTED TRANSACTION TYPES
250 =head2 Visa, MasterCard, American Express, Discover
252 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, card_number, expiration.
256 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, bank_name.
260 For detailed information see L<Business::OnlinePayment>.
264 Unlike Business::OnlinePayment or pre-3.0 verisons of
265 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
268 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
269 Integration Method (AIM) (formerly known as ADC direct response)", sending a
270 username and transaction_key or password with every transaction. Therefore, Authorize.Net's
271 referrer "security" is not necessary. In your Authorize.Net interface at
272 https://secure.authorize.net/ make sure the list of allowable referers is
273 blank. Alternatively, set the B<referer> field in the transaction content.
275 To settle an authorization-only transaction (where you set action to
276 'Authorization Only'), submit the nine-digit transaction id code in
277 the field "order_number" with the action set to "Post Authorization".
278 You can get the transaction id from the authorization by calling the
279 order_number method on the object returned from the authorization.
280 You must also submit the amount field with a value less than or equal
281 to the amount specified in the original authorization.
283 Recently (February 2002), Authorize.Net has turned address
284 verification on by default for all merchants. If you do not have
285 valid address information for your customer (such as in an IVR
286 application), you must disable address verification in the Merchant
287 Menu page at https://secure.authorize.net/ so that the transactions
288 aren't denied due to a lack of address information.
292 This module implements Authorize.Net's API verison 3.1 using the ADC
293 Direct Response method. See
294 https://secure.authorize.net/docs/developersguide.pml for details.
298 Jason Kohles, jason@mediabang.com
300 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
301 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
304 Jason Spence <jspence@lightconsulting.com> contributed support for separate
305 Authorization Only and Post Authorization steps and wrote some docs.
306 OST <services@ostel.com> paid for it.
308 T.J. Mather <tjmather@maxmind.com> sent a patch for the CVV2 field.
310 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
312 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
314 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
315 card-less post authorizations.
317 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
318 key" authentication as well support for the recurring_billing flag and the md5'
319 method that returns the MD5 hash which is returned by the gateway.
323 perl(1). L<Business::OnlinePayment>.