1 package Business::OnlinePayment::AuthorizeNet::AIM;
5 use Business::OnlinePayment::AuthorizeNet;
6 use Net::SSLeay qw/make_form post_https make_headers/;
8 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
12 @ISA = qw(Exporter Business::OnlinePayment::AuthorizeNet);
20 $self->server('secure.authorize.net') unless $self->server;
21 $self->port('443') unless $self->port;
22 $self->path('/gateway/transact.dll') unless $self->path;
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'});
54 my %account_types = ('personal checking' => 'CHECKING',
55 'personal savings' => 'SAVINGS',
56 'business checking' => 'CHECKING',
57 'business savings' => 'SAVINGS',
59 $content{'account_type'} = $account_types{lc($content{'account_type'})}
60 || $content{'account_type'};
62 $content{'referer'} = defined( $content{'referer'} )
63 ? make_headers( 'Referer' => $content{'referer'} )
66 if (length $content{'password'} == 15) {
67 $content{'transaction_key'} = delete $content{'password'};
70 # stuff it back into %content
71 $self->content(%content);
77 my %content = $self->content();
79 $content{$map{$_}} = $content{$_};
81 $self->content(%content);
85 my($self,@fields) = @_;
87 my %content = $self->content();
89 foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
100 password => 'x_Password',
101 transaction_key => 'x_Tran_Key',
103 description => 'x_Description',
104 amount => 'x_Amount',
105 currency => 'x_Currency_Code',
106 invoice_number => 'x_Invoice_Num',
107 order_number => 'x_Trans_ID',
108 auth_code => 'x_Auth_Code',
109 customer_id => 'x_Cust_ID',
110 customer_ip => 'x_Customer_IP',
111 last_name => 'x_Last_Name',
112 first_name => 'x_First_Name',
113 company => 'x_Company',
114 address => 'x_Address',
118 country => 'x_Country',
119 ship_last_name => 'x_Ship_To_Last_Name',
120 ship_first_name => 'x_Ship_To_First_Name',
121 ship_company => 'x_Ship_To_Company',
122 ship_address => 'x_Ship_To_Address',
123 ship_city => 'x_Ship_To_City',
124 ship_state => 'x_Ship_To_State',
125 ship_zip => 'x_Ship_To_Zip',
126 ship_country => 'x_Ship_To_Country',
130 email_customer => 'x_Email_Customer',
131 card_number => 'x_Card_Num',
132 expiration => 'x_Exp_Date',
133 cvv2 => 'x_Card_Code',
134 check_type => 'x_Echeck_Type',
135 account_name => 'x_Bank_Acct_Name',
136 account_number => 'x_Bank_Acct_Num',
137 account_type => 'x_Bank_Acct_Type',
138 bank_name => 'x_Bank_Name',
139 routing_code => 'x_Bank_ABA_Code',
140 check_number => 'x_Bank_Check_Number',
141 customer_org => 'x_Customer_Organization_Type',
142 customer_ssn => 'x_Customer_Tax_ID',
143 license_num => 'x_Drivers_License_Num',
144 license_state => 'x_Drivers_License_State',
145 license_dob => 'x_Drivers_License_DOB',
146 recurring_billing => 'x_Recurring_Billing',
147 duplicate_window => 'x_Duplicate_Window',
148 track1 => 'x_Track1',
149 track2 => 'x_Track2',
152 my $auth_type = $self->{_content}->{transaction_key}
156 my @required_fields = ( qw(type action login), $auth_type );
158 unless ( $self->{_content}->{action} eq 'VOID' ) {
160 if ($self->transaction_type() eq "ECHECK") {
162 push @required_fields, qw(
163 amount routing_code account_number account_type bank_name
167 if (defined $self->{_content}->{customer_org} and
168 length $self->{_content}->{customer_org}
170 push @required_fields, qw( customer_org customer_ssn );
172 push @required_fields, qw(license_num license_state license_dob);
175 } elsif ($self->transaction_type() eq 'CC' ) {
177 if ( $self->{_content}->{action} eq 'PRIOR_AUTH_CAPTURE' ) {
178 if ( $self->{_content}->{order_number} ) {
179 push @required_fields, qw( amount order_number );
181 push @required_fields, qw( amount card_number expiration );
183 } elsif ( $self->{_content}->{action} eq 'CREDIT' ) {
184 push @required_fields, qw( amount order_number card_number );
186 push @required_fields, qw(
187 amount last_name first_name card_number expiration
191 Carp::croak( "AuthorizeNet can't handle transaction type: ".
192 $self->transaction_type() );
197 $self->required_fields(@required_fields);
199 my %post_data = $self->get_fields(qw/
200 x_Login x_Password x_Tran_Key x_Invoice_Num
201 x_Description x_Amount x_Cust_ID x_Method x_Type x_Card_Num x_Exp_Date
202 x_Card_Code x_Auth_Code x_Echeck_Type x_Bank_Acct_Num
203 x_Bank_Account_Name x_Bank_ABA_Code x_Bank_Name x_Bank_Acct_Type
205 x_Customer_Organization_Type x_Customer_Tax_ID x_Customer_IP
206 x_Drivers_License_Num x_Drivers_License_State x_Drivers_License_DOB
207 x_Last_Name x_First_Name x_Company
208 x_Address x_City x_State x_Zip
210 x_Ship_To_Last_Name x_Ship_To_First_Name x_Ship_To_Company
211 x_Ship_To_Address x_Ship_To_City x_Ship_To_State x_Ship_To_Zip
213 x_Phone x_Fax x_Email x_Email_Customer x_Country
214 x_Currency_Code x_Trans_ID x_Duplicate_Window x_Track1 x_Track2/);
216 $post_data{'x_Test_Request'} = $self->test_transaction() ? 'TRUE' : 'FALSE';
218 #deal with perl-style bool
219 if ( $post_data{'x_Email_Customer'}
220 && $post_data{'x_Email_Customer'} !~ /^FALSE$/i ) {
221 $post_data{'x_Email_Customer'} = 'TRUE';
223 $post_data{'x_Email_Customer'} = 'FALSE';
226 $post_data{'x_ADC_Delim_Data'} = 'TRUE';
227 $post_data{'x_delim_char'} = ',';
228 $post_data{'x_encap_char'} = '"';
229 $post_data{'x_ADC_URL'} = 'FALSE';
230 $post_data{'x_Version'} = '3.1';
232 my $pd = make_form(%post_data);
233 my $s = $self->server();
234 my $p = $self->port();
235 my $t = $self->path();
236 my $r = $self->{_content}->{referer};
237 my($page,$server_response,%headers) = post_https($s,$p,$t,$r,$pd);
238 #escape NULL (binary 0x00) values
239 $page =~ s/\x00/\^0/g;
241 #trim 'ip_addr="1.2.3.4"' added by eProcessingNetwork Authorize.Net compat
242 $page =~ s/,ip_addr="[\d\.]+"$//;
244 my $csv = new Text::CSV_XS({ binary=>1, escape_char=>'' });
246 my @col = $csv->fields();
248 $self->server_response($page);
249 $self->avs_code($col[5]);
250 $self->order_number($col[6]);
251 $self->md5($col[37]);
252 $self->cvv2_response($col[38]);
253 $self->cavv_response($col[39]);
255 if($col[0] eq "1" ) { # Authorized/Pending/Test
256 $self->is_success(1);
257 $self->result_code($col[0]);
258 if ($col[4] =~ /^(.*)\s+(\d+)$/) { #eProcessingNetwork extra bits..
259 $self->authorization($2);
261 $self->authorization($col[4]);
264 $self->is_success(0);
265 $self->result_code($col[2]);
266 $self->error_message($col[3]);
267 unless ( $self->result_code() ) { #additional logging information
268 #$page =~ s/\x00/\^0/g;
269 $self->error_message($col[3].
270 " DEBUG: No x_response_code from server, ".
271 "(HTTPS response: $server_response) ".
273 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
274 "(Raw HTTPS content: $page)"
285 Business::OnlinePayment::AuthorizeNet::AIM - AuthorizeNet AIM backend for Business::OnlinePayment
289 Jason Kohles, jason@mediabang.com
291 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
292 3.0/3.1 and is the current maintainer. Please send patches as unified diffs
295 Jason Spence <jspence@lightconsulting.com> contributed support for separate
296 Authorization Only and Post Authorization steps and wrote some docs.
297 OST <services@ostel.com> paid for it.
299 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
301 Mike Barry <mbarry@cos.com> sent in a patch for the referer field.
303 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
305 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
306 card-less post authorizations.
308 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
309 key" authentication as well support for the recurring_billing flag and the md5
310 method that returns the MD5 hash which is returned by the gateway.
312 Steve Simitzis contributed a patch for better compatibility with
313 eProcessingNetwork's AuthorizeNet compatability mode.
317 perl(1). L<Business::OnlinePayment> L<Business::OnlinePayment::AuthorizeNet>.