70410d6fc4adb49a27d878f74839c1155e8dd017
[Business-OnlinePayment-AuthorizeNet.git] / AuthorizeNet.pm
1 package Business::OnlinePayment::AuthorizeNet;
2
3 use strict;
4 use Carp;
5 use Business::OnlinePayment;
6 use vars qw($VERSION @ISA $me);
7
8 @ISA = qw(Business::OnlinePayment);
9 $VERSION = '3.21';
10 $me = 'Business::OnlinePayment::AuthorizeNet';
11
12 sub set_defaults {
13     my $self = shift;
14
15     $self->build_subs(qw( order_number md5 avs_code cvv2_response
16                           cavv_response
17                      ));
18 }
19
20 sub _map_processor {
21     my($self) = @_;
22
23     my %content = $self->content();
24     my %processors = ('recurring authorization'          => 'ARB',
25                       'modify recurring authorization'   => 'ARB',
26                       'cancel recurring authorization'   => 'ARB',
27                      );
28     $processors{lc($content{'action'})} || 'AIM';
29 }
30
31 sub submit {
32     my($self) = @_;
33
34     my $processor = $me. "::". $self->_map_processor();
35
36     eval "use $processor";
37     croak("unknown processor $processor ($@)") if $@;
38     
39     my $object = bless $self, $processor;
40     $object->set_defaults();
41     $object->submit();
42     bless $self, $me;
43 }
44
45 1;
46 __END__
47
48 =head1 NAME
49
50 Business::OnlinePayment::AuthorizeNet - AuthorizeNet backend for Business::OnlinePayment
51
52 =head1 SYNOPSIS
53
54   use Business::OnlinePayment;
55
56   ####
57   # One step transaction, the simple case.
58   ####
59
60   my $tx = new Business::OnlinePayment("AuthorizeNet");
61   $tx->content(
62       type           => 'VISA',
63       login          => 'testdrive',
64       password       => '', #password or transaction key
65       action         => 'Normal Authorization',
66       description    => 'Business::OnlinePayment test',
67       amount         => '49.95',
68       invoice_number => '100100',
69       customer_id    => 'jsk',
70       first_name     => 'Jason',
71       last_name      => 'Kohles',
72       address        => '123 Anystreet',
73       city           => 'Anywhere',
74       state          => 'UT',
75       zip            => '84058',
76       card_number    => '4007000000027',
77       expiration     => '09/02',
78       cvv2           => '1234', #optional
79       referer        => 'http://valid.referer.url/',
80   );
81   $tx->submit();
82
83   if($tx->is_success()) {
84       print "Card processed successfully: ".$tx->authorization."\n";
85   } else {
86       print "Card was rejected: ".$tx->error_message."\n";
87   }
88
89   ####
90   # Two step transaction, authorization and capture.
91   # If you don't need to review order before capture, you can
92   # process in one step as above.
93   ####
94
95   my $tx = new Business::OnlinePayment("AuthorizeNet");
96   $tx->content(
97       type           => 'VISA',
98       login          => 'testdrive',
99       password       => '',  #password or transaction key
100       action         => 'Authorization Only',
101       description    => 'Business::OnlinePayment test',
102       amount         => '49.95',
103       invoice_number => '100100',
104       customer_id    => 'jsk',
105       first_name     => 'Jason',
106       last_name      => 'Kohles',
107       address        => '123 Anystreet',
108       city           => 'Anywhere',
109       state          => 'UT',
110       zip            => '84058',
111       card_number    => '4007000000027',
112       expiration     => '09/02',
113       cvv2           => '1234', #optional
114       referer        => 'http://valid.referer.url/',
115   );
116   $tx->submit();
117
118   if($tx->is_success()) {
119       # get information about authorization
120       $authorization = $tx->authorization
121       $ordernum = $tx->order_number;
122       $avs_code = $tx->avs_code; # AVS Response Code
123       $cvv2_response = $tx->cvv2_response; # CVV2/CVC2/CID Response Code
124       $cavv_response = $tx->cavv_response; # Cardholder Authentication
125                                            # Verification Value (CAVV) Response
126                                            # Code
127
128       # now capture transaction
129       my $capture = new Business::OnlinePayment("AuthorizeNet");
130
131       $capture->content(
132           type           => 'CC',
133           action         => 'Post Authorization',
134           login          => 'YOURLOGIN
135           password       => 'YOURPASSWORD', #or transaction key
136           order_number   => $ordernum,
137           amount         => '49.95',
138       );
139
140       $capture->submit();
141
142       if($capture->is_success()) { 
143           print "Card captured successfully: ".$capture->authorization."\n";
144       } else {
145           print "Card was rejected: ".$capture->error_message."\n";
146       }
147
148   } else {
149       print "Card was rejected: ".$tx->error_message."\n";
150   }
151
152   ####
153   # One step subscription, the simple case.
154   ####
155
156   my $tx = new Business::OnlinePayment("AuthorizeNet::ARB");
157   $tx->content(
158       type           => 'CC',
159       login          => 'testdrive',
160       password       => 'testpass', #or transaction key
161       action         => 'Recurring Authorization',
162       interval       => '7 days',
163       start          => '2008-3-10',
164       periods        => '16',
165       amount         => '99.95',
166       trialperiods   => '4',
167       trialamount    => '0',
168       description    => 'Business::OnlinePayment test',
169       invoice_number => '1153B33F',
170       customer_id    => 'vip',
171       first_name     => 'Tofu',
172       last_name      => 'Beast',
173       address        => '123 Anystreet',
174       city           => 'Anywhere',
175       state          => 'GA',
176       zip            => '84058',
177       card_number    => '4111111111111111',
178       expiration     => '09/02',
179   );
180   $tx->submit();
181
182   if($tx->is_success()) {
183       print "Card processed successfully: ".$tx->order_number."\n";
184   } else {
185       print "Card was rejected: ".$tx->error_message."\n";
186   }
187   my $subscription = $tx->order_number
188
189
190   ####
191   # Subscription change.   Modestly more complicated.
192   ####
193
194   $tx->content(
195       type           => 'CC',
196       subscription   => '99W2C',
197       login          => 'testdrive',
198       password       => 'testpass', #or transaction key
199       action         => 'Modify Recurring Authorization',
200       interval       => '7 days',
201       start          => '2008-3-10',
202       periods        => '16',
203       amount         => '29.95',
204       trialperiods   => '4',
205       trialamount    => '0',
206       description    => 'Business::OnlinePayment test',
207       invoice_number => '1153B340',
208       customer_id    => 'vip',
209       first_name     => 'Tofu',
210       last_name      => 'Beast',
211       address        => '123 Anystreet',
212       city           => 'Anywhere',
213       state          => 'GA',
214       zip            => '84058',
215       card_number    => '4111111111111111',
216       expiration     => '09/02',
217   );
218   $tx->submit();
219
220   if($tx->is_success()) {
221       print "Update processed successfully."\n";
222   } else {
223       print "Update was rejected: ".$tx->error_message."\n";
224   }
225   $tx->content(
226       subscription   => '99W2D',
227       login          => 'testdrive',
228       password       => 'testpass', # or transaction key
229       action         => 'Cancel Recurring Authorization',
230   );
231   $tx->submit();
232
233   ####
234   # Subscription cancellation.   It happens.
235   ####
236
237   if($tx->is_success()) {
238       print "Cancellation processed successfully."\n";
239   } else {
240       print "Cancellation was rejected: ".$tx->error_message."\n";
241   }
242
243
244 =head1 SUPPORTED TRANSACTION TYPES
245
246 =head2 CC, Visa, MasterCard, American Express, Discover
247
248 Content required: type, login, password, action, amount, first_name, last_name, card_number, expiration.
249
250 =head2 Check
251
252 Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code, bank_name (non-subscription), account_type (subscription), check_type (subscription).
253
254 =head2 Subscriptions
255
256 Additional content required: interval, start, periods.
257
258 =head1 DESCRIPTION
259
260 For detailed information see L<Business::OnlinePayment>.
261
262 =head1 METHODS AND FUNCTIONS
263
264 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.  
265
266 =head2 result_code
267
268 Returns the response reason code (from the message.code field for subscriptions).
269
270 =head2 error_message
271
272 Returns the response reason text (from the message.text field for subscriptions.
273
274 =head2 server_response
275
276 Returns the complete response from the server.
277
278 =head1 Handling of content(%content) data:
279
280 =head2 action
281
282 The following actions are valid
283
284   normal authorization
285   authorization only
286   credit
287   post authorization
288   void
289   recurring authorization
290   modify recurring authorization
291   cancel recurring authorization
292
293 =head2 interval
294
295   Interval contains a number of digits, whitespace, and the units of days or months in either singular or plural form.
296   
297
298 =head1 Setting AuthorizeNet ARB parameters from content(%content)
299
300 The following rules are applied to map data to AuthorizeNet ARB parameters
301 from content(%content):
302
303       # ARB param => $content{<key>}
304       merchantAuthentication
305         name                     =>  'login',
306         transactionKey           =>  'password',
307       subscription
308         paymentSchedule
309           interval
310             length               => \( the digits in 'interval' ),
311             unit                 => \( days or months gleaned from 'interval' ),          startDate              => 'start',
312           totalOccurrences       => 'periods',
313           trialOccurrences       => 'trialperiods',
314         amount                   => 'amount',
315         trialAmount              => 'trialamount',
316         payment
317           creditCard
318             cardNumber           => 'card_number',
319             expiration           => \( $year.'-'.$month ), # YYYY-MM from 'expiration'
320           bankAccount
321             accountType          => 'account_type',
322             routingNumber        => 'routing_code',
323             accountNumber        => 'account_number,
324             nameOnAccount        => 'name',
325             bankName             => 'bank_name',
326             echeckType           => 'check_type',
327         order
328           invoiceNumber          => 'invoice_number',
329           description            => 'description',
330         customer
331           type                   => 'customer_org',
332           id                     => 'customer_id',
333           email                  => 'email',
334           phoneNumber            => 'phone',
335           faxNumber              => 'fax',
336           driversLicense
337             number               => 'license_num',
338             state                => 'license_state',
339             dateOfBirth          => 'license_dob',
340           taxid                  => 'customer_ssn',
341         billTo
342           firstName              => 'first_name',
343           lastName               => 'last_name',
344           company                => 'company',
345           address                => 'address',
346           city                   => 'city',
347           state                  => 'state',
348           zip                    => 'zip',
349           country                => 'country',
350         shipTo
351           firstName              => 'ship_first_name',
352           lastName               => 'ship_last_name',
353           company                => 'ship_company',
354           address                => 'ship_address',
355           city                   => 'ship_city',
356           state                  => 'ship_state',
357           zip                    => 'ship_zip',
358           country                => 'ship_country',
359
360 =head1 NOTES
361
362 Use your transaction key in the password field.
363
364 Unlike Business::OnlinePayment or pre-3.0 verisons of
365 Business::OnlinePayment::AuthorizeNet, 3.1 requires separate first_name and
366 last_name fields.
367
368 Business::OnlinePayment::AuthorizeNet uses Authorize.Net's "Advanced
369 Integration Method (AIM) (formerly known as ADC direct response)" and
370 "Automatic Recurring Billing (ARB)", sending a username and password (or
371 transaction_key) with every transaction.  Therefore, Authorize.Net's
372 referrer "security" is not necessary.  In your Authorize.Net interface at
373 https://secure.authorize.net/ make sure the list of allowable referers is
374 blank.  Alternatively, set the B<referer> field in the transaction content.
375
376 To settle an authorization-only transaction (where you set action to
377 'Authorization Only'), submit the nine-digit transaction id code in
378 the field "order_number" with the action set to "Post Authorization".
379 You can get the transaction id from the authorization by calling the
380 order_number method on the object returned from the authorization.
381 You must also submit the amount field with a value less than or equal
382 to the amount specified in the original authorization.
383
384 For the subscription actions an authorization code is never returned by
385 the module.  Instead it returns the value of subscriptionId in order_number.
386 This is the value to use for changing or cancelling subscriptions.
387
388 Authorize.Net has turned address verification on by default for all merchants
389 since 2002.  If you do not have valid address information for your customer
390 (such as in an IVR application), you must disable address verification in the
391 Merchant Menu page at https://secure.authorize.net/ so that the transactions
392 aren't denied due to a lack of address information.
393
394 =head1 COMPATIBILITY
395
396 This module implements Authorize.Net's API using the Advanced Integration
397 Method (AIM) version 3.1, formerly known as ADC Direct Response and the 
398 Automatic Recurring Billing version 1.0 using the XML interface.  See
399 http://www.authorize.net/support/AIM_guide.pdf and http://www.authorize.net/support/ARB_guide.pdf for details.
400
401 =head1 AUTHORS
402
403 Original author: Jason Kohles, jason@mediabang.com
404
405 Ivan Kohler <ivan-authorizenet@freeside.biz> updated it for Authorize.Net
406 protocol 3.0/3.1 and is the current maintainer.  Please see the next section
407 for for information on contributing.
408
409 Jason Spence <jspence@lightconsulting.com> contributed support for separate
410 Authorization Only and Post Authorization steps and wrote some docs.
411 OST <services@ostel.com> paid for it.
412
413 Jeff Finucane <authorizenetarb@weasellips.com> added the ARB support.
414 ARB support sponsored by Plus Three, LP. L<http://www.plusthree.com>.
415
416 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
417
418 Mike Barry <mbarry@cos.com> sent in a patch for the referer field and a fix for
419 ship_company.
420
421 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
422
423 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
424 card-less post authorizations.
425
426 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
427 key" authentication as well support for the recurring_billing flag and the md5
428 method that returns the MD5 hash which is returned by the gateway.
429
430 Steve Simitzis contributed a patch for better compatibility with
431 eProcessingNetwork's AuthorizeNet compatability mode.
432
433 Michael G. Schwern contributed cleanups, test fixes, and more.
434
435 Erik Hollensbe implemented card-present data (track1/track2), the
436 duplicate_window parameter, and test fixes.
437
438 Paul Timmins added the check_number field.
439
440 Nate Nuss implemented the ("Additional Shipping Information (Level 2 Data)"
441 fields: tax, freight, duty, tax_exempt, po_number.
442
443 Michael Peters fixed a bug in email address handling.
444
445 =head1 CONTRIBUTIONS AND REPOSITORY
446
447 Please send patches as unified diffs (diff -u) to (in order of preference):
448
449 =over 4
450
451 =item CPAN RT
452
453 http://rt.cpan.org/Public/Bug/Report.html?Queue=Business-OnlinePayment-AuthorizeNet
454
455 =item The bop-devel mailing list
456
457 http://420.am/cgi-bin/mailman/listinfo/bop-devel
458
459 =item Ivan
460
461 Ivan Kohler <ivan-authorizenet@freeside.biz>
462
463 =back
464
465 The code is available from our public CVS repository:
466
467   export CVSROOT=":pserver:anonymous@cvs.freeside.biz:/home/cvs/cvsroot"
468   cvs login
469   # The password for the user `anonymous' is `anonymous'.
470   cvs checkout Business-OnlinePayment-AuthorizeNet
471
472 Or on the web:
473
474   http://freeside.biz/cgi-bin/viewvc.cgi/Business-OnlinePayment-AuthorizeNet/
475
476 =head1 SEE ALSO
477
478 perl(1). L<Business::OnlinePayment>.
479
480 =cut
481