Got settlements working by adding an order_number method for submitting the transacti...
[Business-OnlinePayment-AuthorizeNet.git] / AuthorizeNet.pm
1 package Business::OnlinePayment::AuthorizeNet;
2
3 # $Id: AuthorizeNet.pm,v 1.5 2002-02-16 06:54:36 thalakan Exp $
4
5 use strict;
6 use Business::OnlinePayment;
7 use Net::SSLeay qw/make_form post_https/;
8 use Text::CSV_XS;
9 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
10
11 require Exporter;
12
13 @ISA = qw(Exporter AutoLoader Business::OnlinePayment);
14 @EXPORT = qw();
15 @EXPORT_OK = qw();
16 $VERSION = '3.02';
17
18 sub set_defaults {
19     my $self = shift;
20
21     $self->server('secure.authorize.net');
22     $self->port('443');
23     $self->path('/gateway/transact.dll');
24 }
25
26 sub map_fields {
27     my($self) = @_;
28
29     my %content = $self->content();
30
31     # ACTION MAP
32     my %actions = ('normal authorization' => 'AUTH_CAPTURE',
33                    'authorization only'   => 'AUTH_ONLY',
34                    'credit'               => 'CREDIT',
35                    'post authorization'   => 'PRIOR_AUTH_CAPTURE',
36                   );
37     $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
38
39     # TYPE MAP
40     my %types = ('visa'               => 'CC',
41                  'mastercard'         => 'CC',
42                  'american express'   => 'CC',
43                  'discover'           => 'CC',
44                  'check'              => 'ECHECK',
45                 );
46     $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
47     $self->transaction_type($content{'type'});
48
49     # stuff it back into %content
50     $self->content(%content);
51 }
52
53 sub remap_fields {
54     my($self,%map) = @_;
55
56     my %content = $self->content();
57     foreach(keys %map) {
58         $content{$map{$_}} = $content{$_};
59     }
60     $self->content(%content);
61 }
62
63 sub get_fields {
64     my($self,@fields) = @_;
65
66     my %content = $self->content();
67     my %new = ();
68     foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
69     return %new;
70 }
71
72 sub submit {
73     my($self) = @_;
74
75     $self->map_fields();
76     $self->remap_fields(
77         type           => 'x_Method',
78         login          => 'x_Login',
79         password       => 'x_Password',
80         action         => 'x_Type',
81         description    => 'x_Description',
82         amount         => 'x_Amount',
83         invoice_number => 'x_Invoice_Num',
84         customer_id    => 'x_Cust_ID',
85         last_name      => 'x_Last_Name',
86         first_name     => 'x_First_Name',
87         address        => 'x_Address',
88         city           => 'x_City',
89         state          => 'x_State',
90         zip            => 'x_Zip',
91         card_number    => 'x_Card_Num',
92         expiration     => 'x_Exp_Date',
93         account_number => 'x_Bank_Acct_Num',
94         routing_code   => 'x_Bank_ABA_Code',
95         bank_name      => 'x_Bank_Name',
96         country        => 'x_Country',
97         phone          => 'x_Phone',
98         fax            => 'x_Fax',
99         email          => 'x_Email',
100         company        => 'x_Company',
101         order_number   => 'x_Trans_ID',
102     );
103
104     if($self->transaction_type() eq "ECHECK") {
105         $self->required_fields(qw/type login password action amount last_name
106                                   first_name account_number routing_code
107                                   bank_name/);
108     } elsif($self->transaction_type() eq 'CC' ) {
109         $self->required_fields(qw/type login password action amount last_name
110                                   first_name card_number expiration/);
111     } else {
112         Carp::croak("AuthorizeNet can't handle transaction type: ".
113                     $self->transaction_type());
114     }
115
116     my %post_data = $self->get_fields(qw/x_Login x_Password x_Invoice_Num
117                                          x_Description x_Amount x_Cust_ID
118                                          x_Method x_Type x_Card_Num x_Exp_Date
119                                          x_Auth_Code x_Bank_Acct_Num
120                                          x_Bank_ABA_Code x_Bank_Name
121                                          x_Last_Name x_First_Name x_Address
122                                          x_City x_State x_Zip x_Country x_Phone
123                                          x_Fax x_Email x_Email_Customer
124                                          x_Company x_Country x_Trans_ID/); 
125     $post_data{'x_Test_Request'} = $self->test_transaction()?"TRUE":"FALSE";
126     $post_data{'x_ADC_Delim_Data'} = 'TRUE';
127     $post_data{'x_ADC_URL'} = 'FALSE';
128     $post_data{'x_Version'} = '3.0';
129
130     my $pd = make_form(%post_data);
131     my $s = $self->server();
132     my $p = $self->port();
133     my $t = $self->path();
134     my($page,$server_response,%headers) = post_https($s,$p,$t,'',$pd);
135
136     my $csv = new Text::CSV_XS();
137     $csv->parse($page);
138     my @col = $csv->fields();
139
140     $self->server_response($page);
141     if($col[0] eq "1" ) { # Authorized/Pending/Test
142         $self->is_success(1);
143         $self->result_code($col[0]);
144         $self->authorization($col[4]);
145         $self->order_number($col[6]);
146     } else {
147         $self->is_success(0);
148         $self->result_code($col[2]);
149         $self->error_message($col[3]);
150     }
151 }
152
153 1;
154 __END__
155
156 =head1 NAME
157
158 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
159
160 =head1 SYNOPSIS
161
162   use Business::OnlinePayment;
163
164   my $tx = new Business::OnlinePayment("AuthorizeNet");
165   $tx->content(
166       type           => 'VISA',
167       login          => 'testdrive',
168       password       => '',
169       action         => 'Normal Authorization',
170       description    => 'Business::OnlinePayment test',
171       amount         => '49.95',
172       invoice_number => '100100',
173       customer_id    => 'jsk',
174       first_name     => 'Jason',
175       last_name      => 'Kohles',
176       address        => '123 Anystreet',
177       city           => 'Anywhere',
178       state          => 'UT',
179       zip            => '84058',
180       card_number    => '4007000000027',
181       expiration     => '09/02',
182   );
183   $tx->submit();
184
185   if($tx->is_success()) {
186       print "Card processed successfully: ".$tx->authorization."\n";
187   } else {
188       print "Card was rejected: ".$tx->error_message."\n";
189   }
190
191 =head1 SUPPORTED TRANSACTION TYPES
192
193 =head2 Visa, MasterCard, American Express, Discover
194
195 Content required: type, login, password, action, amount, first_name, last_name, card_number, expiration.
196
197 =head2 Check
198
199 Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code, bank_name.
200
201 =head1 DESCRIPTION
202
203 For detailed information see L<Business::OnlinePayment>.
204
205 =head1 NOTE
206
207 Unlike Business::OnlinePayment or previous verisons of
208 Business::OnlinePayment::AuthorizeNet, 3.0 requires separate first_name and
209 last_name fields.
210
211 To settle an authorization-only transaction (where you set action to
212 'Authorization Only'), submit the nine-digit transaction id code in
213 the field "order_number" with the action set to "Post Authorization".
214 You can get the transaction id from the authorization by calling the
215 order_number method on the object returned from the authorization.
216 You must also submit the amount field with a value less than or equal
217 to the amount specified in the original authorization.
218
219 Recently (February 2002), Authorize.Net has turned address
220 verification on by default for all merchants.  If you do not have
221 valid address information for your customer (such as in an IVR
222 application), you must disable address verification in the Merchant
223 Menu page at https://secure.authorize.net/ so that the transactions
224 aren't denied due to a lack of addres information.
225
226 =head1 COMPATIBILITY
227
228 This module implements Authorize.Net's API verison 3.0 using the ADC
229 Direct Response method.  See
230 https://secure.authorize.net/docs/developersguide.pml for details.
231
232 =head1 AUTHOR
233
234 Jason Kohles, jason@mediabang.com
235
236 Ivan Kohler <ivan-authorizenet@420.am> updated it for Authorize.Net protocol
237 3.0 and is the current maintainer.
238
239 Jason Spence <jspence@lightconsulting.com> got settlements working and
240 wrote some docs.  OST <services@ostel.com> paid for it.
241
242 =head1 SEE ALSO
243
244 perl(1). L<Business::OnlinePayment>.
245
246 =cut
247