1 package Business::OnlinePayment::AuthorizeNet;
3 # $Id: AuthorizeNet.pm,v 1.19 2003-02-26 03:46:54 ivan Exp $
7 use Business::OnlinePayment;
8 use Net::SSLeay qw/make_form post_https make_headers/;
10 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
14 @ISA = qw(Exporter AutoLoader Business::OnlinePayment);
22 $self->server('secure.authorize.net');
24 $self->path('/gateway/transact.dll');
26 $self->build_subs('order_number'); #no idea how it worked for jason w/o this
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',
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_Account_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',
124 if ($self->transaction_type() eq "ECHECK") {
125 if ($self->{_content}->{customer_org} ne '') {
126 $self->required_fields(qw/type login password amount routing_code
127 account_number account_type bank_name
128 account_name account_type check_type
129 customer_org customer_ssn/);
131 $self->required_fields(qw/type login password amount routing_code
132 account_number account_type bank_name
133 account_name account_type check_type
134 license_num license_state license_dob/);
136 } elsif ($self->transaction_type() eq 'CC' ) {
137 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
138 $self->required_fields(qw/type login password action amount
139 card_number expiration/);
140 } elsif ( $self->{_content}->{action} eq 'VOID' ) {
141 $self->required_fields(qw/login password action/);
143 $self->required_fields(qw/type login password action amount last_name
144 first_name card_number expiration/);
147 Carp::croak("AuthorizeNet can't handle transaction type: ".
148 $self->transaction_type());
151 my %post_data = $self->get_fields(qw/x_Login x_Password x_Invoice_Num
152 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
153 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
154 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
155 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
156 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
157 x_Last_Name x_First_Name x_Address x_City x_State x_Zip x_Country
158 x_Phone x_Fax x_Email x_Email_Customer x_Company x_Country
159 x_Currency_Code x_Trans_ID/);
160 $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
161 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
162 $post_data{'x_ADC_URL'} = 'FALSE';
163 $post_data{'x_Version'} = '3.1';
165 my $pd = make_form(%post_data);
166 my $s = $self->server();
167 my $p = $self->port();
168 my $t = $self->path();
169 my $r = $self->{_content}->{referer};
170 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
171 #escape NULL (binary 0x00) values
172 $page =~ s/\x00/\^0/g;
174 my $csv = new Text::CSV_XS({ 'binary'=>1 });
176 my @col = $csv->fields();
178 $self->server_response($page);
179 if($col[0] eq "1" ) { # Authorized/Pending/Test
180 $self->is_success(1);
181 $self->result_code($col[0]);
182 $self->authorization($col[4]);
183 $self->order_number($col[6]);
185 $self->is_success(0);
186 $self->result_code($col[2]);
187 $self->error_message($col[3]);
188 unless ( $self->result_code() ) { #additional logging information
189 #$page =~ s/\x00/\^0/g;
190 $self->error_message($col[3].
191 " DEBUG: No x_response_code from server, ".
192 "(HTTPS response: $server_response) ".
194 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
195 "(Raw HTTPS content: $page)"
206 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
210 use Business::OnlinePayment;
212 my $tx = new Business::OnlinePayment("AuthorizeNet");
215 login => 'testdrive',
217 action => 'Normal Authorization',
218 description => 'Business::OnlinePayment test',
220 invoice_number => '100100',
221 customer_id => 'jsk',
222 first_name => 'Jason',
223 last_name => 'Kohles',
224 address => '123 Anystreet',
228 card_number => '4007000000027',
229 expiration => '09/02',
230 cvv2 => '1234', #optional
231 referer => 'http://valid.referer.url/',
235 if($tx->is_success()) {
236 print "Card processed successfully: ".$tx->authorization."\n";
238 print "Card was rejected: ".$tx->error_message."\n";
241 =head1 SUPPORTED TRANSACTION TYPES
243 =head2 Visa, MasterCard, American Express, Discover
245 Content required: type, login, password, action, amount, first_name, last_name, card_number, expiration.
249 Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code, bank_name.
253 For detailed information see L<Business::OnlinePayment>.
257 Unlike Business::OnlinePayment or pre-3.0 verisons of
258 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
261 Business::OnlinePayment::AuthorizeNet uses the ADC direct response method,
262 and sends a username and password with every transaction. Therefore,
263 Authorize.Net's referrer "security" is not necessary. In your Authorize.Net
264 interface at https://secure.authorize.net/ make sure the list of allowable
265 referers is blank. Alternatively, set the B<referer> field in the transaction
268 To settle an authorization-only transaction (where you set action to
269 'Authorization Only'), submit the nine-digit transaction id code in
270 the field "order_number" with the action set to "Post Authorization".
271 You can get the transaction id from the authorization by calling the
272 order_number method on the object returned from the authorization.
273 You must also submit the amount field with a value less than or equal
274 to the amount specified in the original authorization.
276 Recently (February 2002), Authorize.Net has turned address
277 verification on by default for all merchants. If you do not have
278 valid address information for your customer (such as in an IVR
279 application), you must disable address verification in the Merchant
280 Menu page at https://secure.authorize.net/ so that the transactions
281 aren't denied due to a lack of address information.
285 This module implements Authorize.Net's API verison 3.1 using the ADC
286 Direct Response method. See
287 https://secure.authorize.net/docs/developersguide.pml for details.
291 Jason Kohles, jason@mediabang.com
293 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
294 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
297 Jason Spence <jspence@lightconsulting.com> contributed support for separate
298 Authorization Only and Post Authorization steps and wrote some docs.
299 OST <services@ostel.com> paid for it.
301 T.J. Mather <tjmather@maxmind.com> sent a patch for the CVV2 field.
303 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
305 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
309 perl(1). L<Business::OnlinePayment>.