- Incorporate Business::OnlinePayment::AuthorizeNet::AIM::ErrorCodes by
[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.22';
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 as password) with every transaction.  Therefore,
372 Authorize.Net's referrer "security" is not necessary.  In your Authorize.Net
373 interface at https://secure.authorize.net/ make sure the list of allowable
374 referers is blank.  Alternatively, set the B<referer> field in the transaction
375 content.
376
377 To settle an authorization-only transaction (where you set action to
378 'Authorization Only'), submit the nine-digit transaction id code in
379 the field "order_number" with the action set to "Post Authorization".
380 You can get the transaction id from the authorization by calling the
381 order_number method on the object returned from the authorization.
382 You must also submit the amount field with a value less than or equal
383 to the amount specified in the original authorization.
384
385 For the subscription actions an authorization code is never returned by
386 the module.  Instead it returns the value of subscriptionId in order_number.
387 This is the value to use for changing or cancelling subscriptions.
388
389 Authorize.Net has turned address verification on by default for all merchants
390 since 2002.  If you do not have valid address information for your customer
391 (such as in an IVR application), you must disable address verification in the
392 Merchant Menu page at https://secure.authorize.net/ so that the transactions
393 aren't denied due to a lack of address information.
394
395 =head1 COMPATIBILITY
396
397 This module implements Authorize.Net's API using the Advanced Integration
398 Method (AIM) version 3.1, formerly known as ADC Direct Response and the 
399 Automatic Recurring Billing version 1.0 using the XML interface.  See
400 http://www.authorize.net/support/AIM_guide.pdf and http://www.authorize.net/support/ARB_guide.pdf for details.
401
402 =head1 AUTHORS
403
404 Original author: Jason Kohles, jason@mediabang.com
405
406 Ivan Kohler <ivan-authorizenet@freeside.biz> updated it for Authorize.Net
407 protocol 3.0/3.1 and is the current maintainer.  Please see the next section
408 for for information on contributing.
409
410 Jason Spence <jspence@lightconsulting.com> contributed support for separate
411 Authorization Only and Post Authorization steps and wrote some docs.
412 OST <services@ostel.com> paid for it.
413
414 Jeff Finucane <authorizenetarb@weasellips.com> added the ARB support.
415 ARB support sponsored by Plus Three, LP. L<http://www.plusthree.com>.
416
417 T.J. Mather <tjmather@maxmind.com> sent a number of CVV2 patches.
418
419 Mike Barry <mbarry@cos.com> sent in a patch for the referer field and a fix for
420 ship_company.
421
422 Yuri V. Mkrtumyan <yuramk@novosoft.ru> sent in a patch to add the void action.
423
424 Paul Zimmer <AuthorizeNetpm@pzimmer.box.bepress.com> sent in a patch for
425 card-less post authorizations.
426
427 Daemmon Hughes <daemmon@daemmonhughes.com> sent in a patch for "transaction
428 key" authentication as well support for the recurring_billing flag and the md5
429 method that returns the MD5 hash which is returned by the gateway.
430
431 Steve Simitzis contributed a patch for better compatibility with
432 eProcessingNetwork's AuthorizeNet compatability mode.
433
434 Michael G. Schwern contributed cleanups, test fixes, and more.
435
436 Erik Hollensbe implemented card-present data (track1/track2), the
437 duplicate_window parameter, and test fixes.
438
439 Paul Timmins added the check_number field.
440
441 Nate Nuss implemented the ("Additional Shipping Information (Level 2 Data)"
442 fields: tax, freight, duty, tax_exempt, po_number.
443
444 Michael Peters fixed a bug in email address handling.
445
446 Thomas Sibley <trs@bestpractical.com> wrote B:OP:AuthorizeNet::AIM::ErrorCodes
447 which was borged and used to provide more descriptive error messages.
448
449 =head1 CONTRIBUTIONS AND REPOSITORY
450
451 Please send patches as unified diffs (diff -u) to (in order of preference):
452
453 =over 4
454
455 =item CPAN RT
456
457 http://rt.cpan.org/Public/Bug/Report.html?Queue=Business-OnlinePayment-AuthorizeNet
458
459 =item The bop-devel mailing list
460
461 http://420.am/cgi-bin/mailman/listinfo/bop-devel
462
463 =item Ivan
464
465 Ivan Kohler <ivan-authorizenet@freeside.biz>
466
467 =back
468
469 The code is available from our public CVS repository:
470
471   export CVSROOT=":pserver:anonymous@cvs.freeside.biz:/home/cvs/cvsroot"
472   cvs login
473   # The password for the user `anonymous' is `anonymous'.
474   cvs checkout Business-OnlinePayment-AuthorizeNet
475
476 Or on the web:
477
478   http://freeside.biz/cgi-bin/viewvc.cgi/Business-OnlinePayment-AuthorizeNet/
479
480 =head1 A WORD FROM OUR SPONSOR
481
482 This module and the Business::OnlinePayment framework are maintained by by
483 Freeside Internet Services.  If you need a complete, open-source web-based
484 application to manage your customers, billing and trouble ticketing, please
485 visit http://freeside.biz/
486
487 =head1 COPYRIGHT & LICENSE
488
489 Copyright 2010 Freeside Internet Services, Inc.
490 Copyright 2008 Thomas Sibley
491 All rights reserved.
492
493 This program is free software; you can redistribute it and/or modify it
494 under the same terms as Perl itself.
495
496 =head1 SEE ALSO
497
498 perl(1). L<Business::OnlinePayment>.
499
500 =cut
501