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
30 my %content = $self->content();
33 my %actions = ('normal authorization' => 'AUTH_CAPTURE',
34 'authorization only' => 'AUTH_ONLY',
36 'post authorization' => 'PRIOR_AUTH_CAPTURE',
39 $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
42 my %types = ('visa' => 'CC',
44 'american express' => 'CC',
48 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
49 $self->transaction_type($content{'type'});
51 $content{'referer'} = defined( $content{'referer'} )
52 ? make_headers( 'Referer' => $content{'referer'} )
55 # stuff it back into %content
56 $self->content(%content);
62 my %content = $self->content();
64 $content{$map{$_}} = $content{$_};
66 $self->content(%content);
70 my($self,@fields) = @_;
72 my %content = $self->content();
74 foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
85 password => 'x_Password',
87 description => 'x_Description',
89 currency => 'x_Currency_Code',
90 invoice_number => 'x_Invoice_Num',
91 order_number => 'x_Trans_ID',
92 auth_code => 'x_Auth_Code',
93 customer_id => 'x_Cust_ID',
94 customer_ip => 'x_Customer_IP',
95 last_name => 'x_Last_Name',
96 first_name => 'x_First_Name',
97 address => 'x_Address',
101 country => 'x_Country',
105 company => 'x_Company',
106 card_number => 'x_Card_Num',
107 expiration => 'x_Exp_Date',
108 cvv2 => 'x_Card_Code',
109 check_type => 'x_Echeck_Type',
110 account_name => 'x_Bank_Account_Name',
111 account_number => 'x_Bank_Acct_Num',
112 account_type => 'x_Bank_Acct_Type',
113 bank_name => 'x_Bank_Name',
114 routing_code => 'x_Bank_ABA_Code',
115 customer_org => 'x_Customer_Organization_Type',
116 customer_ssn => 'x_Customer_Tax_ID',
117 license_num => 'x_Drivers_License_Num',
118 license_state => 'x_Drivers_License_State',
119 license_dob => 'x_Drivers_License_DOB',
122 if ($self->transaction_type() eq "ECHECK") {
123 if ($self->{_content}->{customer_org} ne '') {
124 $self->required_fields(qw/type login password amount routing_code
125 account_number account_type bank_name
126 account_name account_type check_type
127 customer_org customer_ssn/);
129 $self->required_fields(qw/type login password amount routing_code
130 account_number account_type bank_name
131 account_name account_type check_type
132 license_num license_state license_dob/);
134 } elsif ($self->transaction_type() eq 'CC' ) {
135 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
136 if ( $self->{_content}->{order_number}) {
137 $self->required_fields(qw/type login password action amount/);
139 $self->required_fields(qw/type login password action amount
140 card_number expiration/);
142 } elsif ( $self->{_content}->{action} eq 'VOID' ) {
143 $self->required_fields(qw/login password action/);
145 $self->required_fields(qw/type login password action amount last_name
146 first_name card_number expiration/);
149 Carp::croak("AuthorizeNet can't handle transaction type: ".
150 $self->transaction_type());
153 my %post_data = $self->get_fields(qw/x_Login x_Password x_Invoice_Num
154 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
155 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
156 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
157 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
158 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
159 x_Last_Name x_First_Name x_Address x_City x_State x_Zip x_Country
160 x_Phone x_Fax x_Email x_Email_Customer x_Company x_Country
161 x_Currency_Code x_Trans_ID/);
162 $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
163 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
164 $post_data{'x_ADC_URL'} = 'FALSE';
165 $post_data{'x_Version'} = '3.1';
167 my $pd = make_form(%post_data);
168 my $s = $self->server();
169 my $p = $self->port();
170 my $t = $self->path();
171 my $r = $self->{_content}->{referer};
172 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
173 #escape NULL (binary 0x00) values
174 $page =~ s/\x00/\^0/g;
176 my $csv = new Text::CSV_XS({ 'binary'=>1 });
178 my @col = $csv->fields();
180 $self->server_response($page);
181 if($col[0] eq "1" ) { # Authorized/Pending/Test
182 $self->is_success(1);
183 $self->result_code($col[0]);
184 $self->authorization($col[4]);
185 $self->order_number($col[6]);
187 $self->is_success(0);
188 $self->result_code($col[2]);
189 $self->error_message($col[3]);
190 unless ( $self->result_code() ) { #additional logging information
191 #$page =~ s/\x00/\^0/g;
192 $self->error_message($col[3].
193 " DEBUG: No x_response_code from server, ".
194 "(HTTPS response: $server_response) ".
196 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
197 "(Raw HTTPS content: $page)"
208 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
212 use Business::OnlinePayment;
214 my $tx = new Business::OnlinePayment("AuthorizeNet");
217 login => 'testdrive',
219 action => 'Normal Authorization',
220 description => 'Business::OnlinePayment test',
222 invoice_number => '100100',
223 customer_id => 'jsk',
224 first_name => 'Jason',
225 last_name => 'Kohles',
226 address => '123 Anystreet',
230 card_number => '4007000000027',
231 expiration => '09/02',
232 cvv2 => '1234', #optional
233 referer => 'http://valid.referer.url/',
237 if($tx->is_success()) {
238 print "Card processed successfully: ".$tx->authorization."\n";
240 print "Card was rejected: ".$tx->error_message."\n";
243 =head1 SUPPORTED TRANSACTION TYPES
245 =head2 Visa, MasterCard, American Express, Discover
247 Content required: type, login, password, action, amount, first_name, last_name, card_number, expiration.
251 Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code, bank_name.
255 For detailed information see L<Business::OnlinePayment>.
259 Unlike Business::OnlinePayment or pre-3.0 verisons of
260 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
263 Business::OnlinePayment::AuthorizeNet uses the ADC direct response method,
264 and sends a username and password with every transaction. Therefore,
265 Authorize.Net's referrer "security" is not necessary. In your Authorize.Net
266 interface at https://secure.authorize.net/ make sure the list of allowable
267 referers is blank. Alternatively, set the B<referer> field in the transaction
270 To settle an authorization-only transaction (where you set action to
271 'Authorization Only'), submit the nine-digit transaction id code in
272 the field "order_number" with the action set to "Post Authorization".
273 You can get the transaction id from the authorization by calling the
274 order_number method on the object returned from the authorization.
275 You must also submit the amount field with a value less than or equal
276 to the amount specified in the original authorization.
278 Recently (February 2002), Authorize.Net has turned address
279 verification on by default for all merchants. If you do not have
280 valid address information for your customer (such as in an IVR
281 application), you must disable address verification in the Merchant
282 Menu page at https://secure.authorize.net/ so that the transactions
283 aren't denied due to a lack of address information.
287 This module implements Authorize.Net's API verison 3.1 using the ADC
288 Direct Response method. See
289 https://secure.authorize.net/docs/developersguide.pml for details.
293 Jason Kohles, jason@mediabang.com
295 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
296 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
299 Jason Spence <jspence@lightconsulting.com> contributed support for separate
300 Authorization Only and Post Authorization steps and wrote some docs.
301 OST <services@ostel.com> paid for it.
303 T.J. Mather <tjmather@maxmind.com> sent a patch for the CVV2 field.
305 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
307 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
309 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
310 card-less post authorizations.
314 perl(1). L<Business::OnlinePayment>.