don't die when we do not know how to perform the transaction
[Business-OnlinePayment-TransFirsteLink.git] / TransFirsteLink.pm
1 package Business::OnlinePayment::TransFirsteLink;
2
3 use strict;
4 use vars qw($VERSION $DEBUG %error_messages);
5 use Carp qw(carp croak);
6 use Tie::IxHash;
7
8 use base qw(Business::OnlinePayment::HTTPS);
9
10 $VERSION = '0.04';
11 $VERSION = eval $VERSION;
12 $DEBUG   = 0;
13
14 %error_messages = (
15   '000' => 'Approval',
16   '001' => 'Call Issuer',
17   '002' => 'Referral special',
18   '003' => 'Invalid merchant number',
19   '004' => 'Pick up',
20   '005' => 'Declined',
21   '006' => 'General error',
22   '007' => 'Pick up special',
23   '008' => 'Honor with ID',
24   '009' => 'General Decline',
25   '010' => 'Network Error',
26   '011' => 'Approval',
27   '012' => 'Invalid transaction type',
28   '013' => 'Invalid amount field',
29   '014' => 'Invalid card number',
30   '015' => 'Invalid issuer',
31   '016' => 'General Decline',
32   '017' => 'General Decline',
33   '018' => 'General Decline',
34   '019' => 'Re-enter',
35   '020' => 'General Decline',
36   '021' => 'No action taken',
37   '022' => 'General Decline',
38   '023' => 'General Decline',
39   '024' => 'General Decline',
40   '025' => 'Acct num miss',
41   '026' => 'General Decline',
42   '027' => 'General Decline',
43   '028' => 'File unavailable',
44   '029' => 'General Decline',
45   '030' => 'Format Error - Decline',
46   '031' => 'General Decline',
47   '032' => 'General Decline',
48   '033' => 'General Decline',
49   '034' => 'General Decline',
50   '036' => 'General Decline',
51   '037' => 'General Decline',
52   '038' => 'General Decline',
53   '039' => 'No card acct',
54   '040' => 'General Decline',
55   '041' => 'Lost card',
56   '042' => 'General Decline',
57   '043' => 'Stolen card',
58   '044' => 'General Decline',
59   '045' => 'General Decline',
60   '046' => 'General Decline',
61   '048' => 'General Decline',
62   '049' => 'General Decline',
63   '050' => 'General Decline',
64   '051' => 'Over limit',
65   '052' => 'No checking acct',
66   '053' => 'No saving acct',
67   '054' => 'Expired card',
68   '055' => 'Invalid pin',
69   '056' => 'General Decline',
70   '057' => 'TXN not allowed',
71   '058' => 'TXN not allowed term',
72   '059' => 'TXN not allowed - Merchant',
73   '060' => 'General Decline',
74   '061' => 'Over cash limit',
75   '062' => 'Restricted card',
76   '063' => 'Security violate',
77   '064' => 'General Decline',
78   '065' => 'Excessive authorizations',
79   '066' => 'General Decline',
80   '067' => 'General Decline',
81   '069' => 'General Decline',
82   '070' => 'General Decline',
83   '071' => 'General Decline',
84   '072' => 'General Decline',
85   '073' => 'General Decline',
86   '074' => 'General Decline',
87   '075' => 'Excessive pin entry tries',
88   '076' => 'Unable locate previous msg (ref# not found)',
89   '077' => 'Mismatched info',
90   '078' => 'No account',
91   '079' => 'Already reversed',
92   '080' => 'Invalid date',
93   '081' => 'Crypto error',
94   '082' => 'CVV failure',
95   '083' => 'Unable verify pin',
96   '084' => 'Duplicate trans',
97   '085' => 'No reason 2 decline',
98   '086' => 'Cannot verify pin',
99   '088' => 'General Decline',
100   '089' => 'General Decline',
101   '090' => 'General Decline',
102   '091' => 'Issuer unavailable',
103   '092' => 'Destination route not found',
104   '093' => 'Law violation',
105   '094' => 'Duplicate trans',
106   '096' => 'System malfunction',
107   '098' => 'General Decline',
108   '099' => 'General Decline',
109   '0B1' => 'Surcharge amount not permitted on Visa cards or EBT food stamps',
110   '0B2' => 'Surcharge amount not supported by debit network issuer',
111   '0EB' => 'Check digit error',
112   '0EC' => 'Cid format error',
113   '0N0' => 'FORCE STIP',
114   '0N3' => 'Service not available',
115   '0N4' => 'Exceeds limit issuer',
116   '0N5' => 'Ineligible for resubmission',
117   '0N7' => 'CVV2 failure',
118   '0N8' => 'Trans amount exceeds preauth amt',
119   '0P0' => 'Approved pvid miss',
120   '0P1' => 'Declined pvid miss',
121   '0P2' => 'Invalid bill info',
122   '0Q1' => 'Card auth failed',
123   '0R0' => 'Multipay stopped',
124   '0R1' => 'Multipay stopped merch',
125   '0R3' => 'Revocation of all authorizations order',
126   '0XA' => 'Forward to issue1',
127   '0XD' => 'Forward to issue2',
128   '0VD' => 'General Decline',
129   '0T0' => 'First Time Check',
130   '0T1' => 'Check is OK, but cannot be converted',
131   '0T2' => 'Invalid routing transit number or check belongs to a category that is not eligible for conversion',
132   '0T3' => 'Amount greater than established service limit',
133   '0T4' => 'Unpaid items, failed negative check',
134   '0T5' => 'Duplicate check number',
135   '0T6' => 'MICR Error',
136   '0T7' => 'Too many checks (over merchant or bank limit)',
137   '203' => 'Invalid merchant number',
138   '212' => 'Invalid transaction type',
139   '213' => 'Invalid amount field',
140   '214' => 'Invalid card number',
141   '254' => 'Expired card',
142   '257' => 'Txn not allowed',
143   '276' => 'Unable to locate prvious msg (ref # not found)',
144   '278' => 'No account',
145   '284' => 'General Decline',
146   '296' => 'System malfunction',
147   '2Q1' => 'Card authorization failed',
148   '300' => 'Invalid request format',
149   '301' => 'Missing file header',
150   '303' => 'Invalid sender ID',
151   '306' => 'Duplicate file number',
152   '307' => 'General Decline',
153   '309' => 'Comm link down',
154   '310' => 'Missing batch header',
155   '317' => 'Invalid MOTO ID',
156   '338' => 'General Decline',
157   '380' => 'Missing batch trailer',
158   '382' => 'Record count does not match number records in batch',
159   '383' => 'Net amount does not match file amount',
160   '384' => 'Duplicate transaction',
161   '385' => 'Invalid request format',
162   '394' => 'Record count does not match records in file',
163   '395' => 'Net amount does not match file amount',
164   '396' => 'Declined post - reauthorization attempt',
165   '318' => 'Invalid account data source',
166   '319' => 'Invalid POS entry mode',
167   '320' => 'Auth date invalid (transaction date)',
168   '321' => 'Invalid auth source code',
169   '322' => 'Invalid ACI code',
170   'REJ' => 'Rejected transaction that has been re-keyed',
171   '3AC' => 'Invalid authorization code (must be uppercase, no special chars)',
172   '3TI' => 'Invalid tax indicator',
173   '3VD' => 'Voided transaction',
174   '3AD' => 'AVS response code declined',
175   '3AR' => 'AVS required/address information not provided',
176   '3BD' => 'AVS and CVV2 response Code Declined',
177   '3BR' => 'AVS and CVV2 required/information not provided',
178   '3CD' => 'CVV2 response code declined',
179   '3CR' => 'CVV2 required/inrormation not provided',
180   '3L5' => 'No data sent',
181   '3L6' => 'Order number missing',
182   '3M1' => 'Auth date blank',
183   '3M2' => 'Auth amount blank',
184   '3MT' => 'Managed transaction',
185   '3RV' => 'Reversed transaction',
186   '3TO' => 'Timeout',
187   '600' => 'General Decline',
188   '990' => 'Voided',
189   '991' => 'Voided',
190   '992' => 'Voided',
191   '993' => 'Voided',
192   '994' => 'Voided',
193   '995' => 'Voided',
194   '996' => 'Voided',
195   '997' => 'Voided',
196   '998' => 'Voided',
197   '999' => 'Voided',
198   'XXX' => 'General Decline',
199 );
200
201 sub debug {
202     my $self = shift;
203
204     if (@_) {
205         my $level = shift || 0;
206         if ( ref($self) ) {
207             $self->{"__DEBUG"} = $level;
208         }
209         else {
210             $DEBUG = $level;
211         }
212         $Business::OnlinePayment::HTTPS::DEBUG = $level;
213     }
214     return ref($self) ? ( $self->{"__DEBUG"} || $DEBUG ) : $DEBUG;
215 }
216
217 sub set_defaults {
218     my $self = shift;
219     my %opts = @_;
220
221     # standard B::OP methods/data
222     $self->server("epaysecure1.transfirst.com");
223     $self->port("443");
224     $self->path("/");
225
226     $self->build_subs(qw( 
227                           merchantcustservnum
228                           order_number avs_code cvv2_response
229                           response_page response_code response_headers
230                           junk
231                      ));
232
233     # module specific data
234     if ( $opts{debug} ) {
235         $self->debug( $opts{debug} );
236         delete $opts{debug};
237     }
238
239     if ( $opts{merchantcustservnum} ) {
240         $self->merchantcustservnum( $opts{merchantcustservnum} );
241         delete $opts{merchantcustservnum};
242     }
243
244 }
245
246 sub _map_fields {
247     my ($self) = @_;
248
249     my %content = $self->content();
250
251     #ACTION MAP
252     my %actions = (
253         'normal authorization' => 32,    # Authorization/Settle transaction
254         'credit'               => 20,    # Credit (refund)
255         'authorization only'   => 30,    # Authorization only
256         'post authorization'   => 40,    # Settlement
257         'void'                 => 61,    # Void
258     );
259
260     $content{'TransactionCode'} = $actions{ lc( $content{'action'} ) }
261       || $content{'action'};
262
263     # TYPE MAP
264     my %types = (
265         'visa'             => 'CC',
266         'mastercard'       => 'CC',
267         'american express' => 'CC',
268         'discover'         => 'CC',
269         'cc'               => 'CC',
270
271         'check'            => 'ECHECK',
272     );
273
274     $content{'type'} = $types{ lc( $content{'type'} ) } || $content{'type'};
275
276     $self->transaction_type( $content{'type'} );
277
278     # stuff it back into %content
279     $self->content(%content);
280 }
281
282 sub _revmap_fields {
283     my ( $self, %map ) = @_;
284     my %content = $self->content();
285     foreach ( keys %map ) {
286         $content{$_} =
287           ref( $map{$_} )
288           ? ${ $map{$_} }
289           : $content{ $map{$_} };
290     }
291     $self->content(%content);
292 }
293
294 sub expdate_mmyy {
295     my $self       = shift;
296     my $expiration = shift;
297     my $expdate_mmyy;
298     if ( defined($expiration) and $expiration =~ /^(\d+)\D+\d*(\d{2})$/ ) {
299         my ( $month, $year ) = ( $1, $2 );
300         $expdate_mmyy = sprintf( "%02d", $month ) . $year;
301     }
302     return defined($expdate_mmyy) ? $expdate_mmyy : $expiration;
303 }
304
305 sub required_fields {
306     my($self,@fields) = @_;
307
308     my @missing;
309     my %content = $self->content();
310     foreach(@fields) {
311       next
312         if (exists $content{$_} && defined $content{$_} && $content{$_}=~/\S+/);
313       push(@missing, $_);
314     }
315
316     Carp::croak("missing required field(s): " . join(", ", @missing) . "\n")
317       if(@missing);
318
319 }
320
321 sub submit {
322     my ($self) = @_;
323
324     $self->_map_fields();
325
326     my %content = $self->content;
327
328     my %required;
329     $required{CC_20} = [ qw( ePayAccountNum Password OrderNum
330                              TransactionAmount CardAccountNum ExpirationDate
331                              MerchantCustServNum ) ];
332     $required{CC_30} = [ qw( ePayAccountNum Password TransactionCode OrderNum
333                              TransactionAmount CardAccountNum ExpirationDate
334                              CardHolderZip MerchantCustServNum ) ];
335     $required{CC_32} = $required{CC_30};
336     $required{CC_61} = [ qw( ePayAccountNum Password TransactionCode
337                              ReferenceNum ) ];
338     $required{ECHECK_20} = [ qw( ePayAccountNum Password AccountNumber
339                                  RoutingNumber DollarAmount OrderNumber
340                                  CustomerNumber CustomerName ) ];
341     $required{ECHECK_32} = [ qw( ePayAccountNum Password OrderNumber
342                                  AccountNumber RoutingNumber CheckNumber
343                                  DollarAmount CustomerName CustomerAddress
344                                  CustomerCity CustomerState CustomerZip
345                                  CustomerPhone ) ];
346
347     my %optional;
348     $optional{CC_20} = [ qw( CardHolderName CardHolderAddress CardHolderCity
349                              CardHolderState CardHolderZip CardHolderEmail
350                              CardHolderPhone CustomerNum Misc1 Misc2 CVV2
351                              Ecommerce DuplicateChecking AuthorizedAmount
352                              AutorizedDate AuthorizedTime FulfillmentDate
353                              CardHolderCountry POSEntryMode MerchantStoreNum
354                              CardHolderIDSource SICCATCode MerchantZipCode
355                              AccountDataSource AuthResponseCode AuthSourceCode
356                              AuthACICode AuthValidationCode AuthAVSResponse
357                              MerchantCustServNum CrossReferenceNum
358                              PaymentDescription ReferenceNum ) ];
359     $optional{CC_32} = $optional{CC_30};
360     $optional{CC_30} = [ qw( CardHolderName CardHolderAddress CardHolderCity
361                              CardHolderState CardHolderEmail CardHolderPhone
362                              CustomerNum Misc1 Misc2 CVV2 Ecommerce
363                              DuplicateChecking MessageSequenceNum
364                              CardHolderCountry POSEntryMode MerchantStoreNum
365                              CardHolderIDSource SICCATCode MerchantZipCode
366                              PaymenntDiscriptor CAVVCode ECIValue XID
367                              TaxIndicator TotalTaxAmount ) ];
368     $optional{CC_32} = $optional{CC_30};
369     $optional{CC_61} = [ qw( MessageSequenceNum CrossReferenceNum OrderNum
370                              CustomerNum ) ];
371     $optional{ECHECK_20} = ();
372     $optional{ECHECK_32} = [ qw( CustomerNumber Misc1 Misc2 CustomerEmail
373                                  DriversLicense DriversLicenseState
374                                  BirthDate SocSecNum ) ];
375
376     my $type_action = $self->transaction_type(). '_'. $content{TransactionCode};
377     unless ( exists($required{$type_action}) ) {
378 #        croak( "TransFirst eLink can't (yet?) handle transaction type: ".
379 #              "$content{action} on " . $self->transaction_type() );
380       $self->error_message("TransFirst eLink can't handle transaction type: ".
381         "$content{action} on " . $self->transaction_type() );
382       $self->is_success(0);
383       return;
384     }
385
386     my $expdate_mmyy = $self->expdate_mmyy( $content{"expiration"} );
387     my $zip          = $content{'zip'};
388     $zip =~ s/[^[:alnum:]]//g;
389
390     my $merchantcustservnum = $self->merchantcustservnum;
391     my $account_number = $self->transaction_type() eq 'CC'
392                            ? $content{card_number}
393                            : $content{account_number} ;
394
395     my $invoice_number = $content{invoice_number} || "PAYMENT";  # make one up
396     my $check_number = $content{check_number} || "100";  # make one up
397
398     $self->_revmap_fields(
399
400         ePayAccountNum      => 'login',
401         Password            => 'password',
402         OrderNum            => \$invoice_number,
403         OrderNumber         => \$invoice_number,
404         MerchantCustServNum => \$merchantcustservnum,
405
406         TransactionAmount   => 'amount',
407         DollarAmount        => 'amount',
408         CardAccountNum      => 'card_number',
409         ExpirationDate      => \$expdate_mmyy,    # MMYY from 'expiration'
410         CVV2                => 'cvv2',
411
412         RoutingNumber       => 'routing_code',
413         AccountNumber       => \$account_number,
414         AccountNum          => \$account_number,
415         CheckNumber         => \$check_number,
416
417         CardHolderName      => 'name',
418         CustomerName        => 'account_name',
419         CardHolderAddress   => 'address',
420         CustomerAddress     => 'address',
421         CardHolderCity      => 'city',
422         CustomerCity        => 'city',
423         CardHolderState     => 'state',
424         CustomerState       => 'state',
425         CardHolderZip       => \$zip,          # 'zip' with non-alnums removed
426         CustomerZip         => \$zip,          # 'zip' with non-alnums removed
427         CardHolderEmail     => 'email',
428         CustomerEmail       => 'email',
429         CardHolderPhone     => 'phone',
430         CustomerPhone       => 'phone',
431         CustomerNum         => 'customer_id',
432         CustomerNumber      => 'customer_id',
433         CardHolderCountry   => 'country',
434
435         PaymentDescriptor   => 'description',
436
437         ReferenceNum        => 'order_number'
438     );
439
440     tie my %params, 'Tie::IxHash',
441       $self->get_fields( @{$required{$type_action}},
442                          @{$optional{$type_action}},
443                        );
444
445     $params{TestTransaction}='Y' if $self->test_transaction;
446
447     $params{InstallmentNum} = $params{InstallmentOf} = '01'
448       unless ($params{InstallmentNum} && $params{InstallmentOf}); 
449
450     if ($self->transaction_type() eq 'ECHECK') {
451       delete $params{InstallmentNum};
452       delete $params{InstallmentOf};
453     }
454
455     if ( $type_action eq "CC_30" || $type_action eq "CC_32" ) {
456       $self->path($self->path."elink/authpd.asp");
457     } elsif ( $type_action eq "CC_61" ) {
458       $self->path($self->path."eLink/voidpd.asp");
459     } elsif ( $type_action eq "CC_20" ) {
460       $self->path($self->path."eLink/creditpd.asp");
461     } elsif ( $type_action eq "ECHECK_32" ) {
462       $self->path($self->path."eLink/checkPD.asp");
463     } elsif ( $type_action eq "ECHECK_20" ) {
464       $self->path($self->path."eLink/checkcreditPD.asp");
465     } else {
466       croak "don't know path for unexpected type and action $type_action";
467     }
468
469     warn join("\n", map{ "$_ => $params{$_}" } keys(%params)) if $DEBUG > 1;
470     my ( $page, $resp, %resp_headers ) =
471       $self->https_post( %params );
472
473     $self->response_code( $resp );
474     $self->response_page( $page );
475     $self->response_headers( \%resp_headers );
476
477     warn "$page\n" if $DEBUG > 1;
478     # $page should contain | separated values
479
480     $self->required_fields(@{$required{$type_action}});
481
482     my $status ='';
483     my @rarray = ();
484
485     if ( $type_action eq "CC_30" || $type_action eq "CC_32" ) {
486       my ($format,$account,$tcode,$seq,$moi,$cardnum,$exp,$authamt,$authdate,
487           $authtime,$tstat,$custnum,$ordernum,$refnum,$rcode,$authsrc,$achar,
488           $transid,$vcode,$sic,$country,$avscode,$storenum,$cvv2resp,$cavvcode,
489           $crossrefnum,$etstat,$cavvresponse,$xid,$eci,@junk)
490         = split '\|', $page;
491
492       # AVS and CVS values may be set on success or failure
493       $self->avs_code($avscode);
494       $self->cvv2_response( $cvv2resp );
495       $self->result_code( $status = $etstat );
496       $self->order_number( $refnum );
497       $self->authorization( $rcode );
498       $self->junk( \@junk );
499       $self->error_message($error_messages{$status});
500
501
502     } elsif ( $type_action eq "CC_61" ) {
503       $self->avs_code('');
504       $self->cvv2_response('');
505       my ($format,$account,$tcode,$seq,$voiddate,$voidtime,$tstat, # flaky docs
506           $refnum,$filler1,$filler2,$filler3,$etstat,@junk)
507          = split '\|', $page;
508       $self->result_code( $status = $etstat );
509       $self->order_number( $refnum );
510       $self->authorization('');
511       $self->junk( \@junk );
512       $self->error_message($error_messages{$status});
513
514     } elsif ( $type_action eq "CC_20" ) {
515       $self->avs_code('');
516       $self->cvv2_response('');
517       my ($format,$account,$tcode,$seq,$moi,$authamt,$authdate,$authtime,
518           $tstat,$refnum,$crossrefnum,$custnum,$ordernum,$etstat,@junk)
519          = split '\|', $page;
520       $self->result_code( $status = $etstat );
521       $self->order_number( $refnum );
522       $self->authorization('');
523       $self->junk( \@junk );
524       $self->error_message($error_messages{$status});
525
526     } elsif ( $type_action eq "ECHECK_32" ) {
527       my ($responsecode,$response,$transactionid,$note,$errors,@junk)
528          = split '\|', $page;
529       $self->avs_code('');
530       $self->cvv2_response('');
531       $self->result_code( $status = $responsecode );
532       $self->order_number( $transactionid );
533       $self->authorization('');
534       $errors = $errors ? $errors : '';
535       $self->error_message("$response $errors");
536       $self->junk( \@junk );
537
538     } elsif ( $type_action eq "ECHECK_20" ) {
539       my ($response,$transactionid,$note,$errors,@junk) # very flaky docs
540          = split '\|', $page;
541       $self->avs_code('');
542       $self->cvv2_response('');
543       $self->result_code( $status = $response );
544       $self->order_number( $transactionid );
545       $self->authorization('');
546       $errors = $errors ? $errors : '';
547       $self->error_message("$response $errors");
548       $self->junk( \@junk );
549
550     } else {
551       croak "can't interpret response for unexpected type and action $type_action";
552     }
553
554     if ( $resp =~ /^(HTTP\S+ )?200/ && ($status eq "000" || $status eq "011" || $status eq "085" || $status eq "0P0" || $status eq "P00" || $status eq 'ACCEPTED') ) {
555         $self->is_success(1);
556     }
557     else {
558         $self->is_success(0);
559     }
560 }
561
562 1;
563
564 __END__
565
566 =head1 NAME
567
568 Business::OnlinePayment::TransFirsteLink - Transfirst eLink backend for Business::OnlinePayment
569
570 =head1 SYNOPSIS
571
572   use Business::OnlinePayment;
573   
574   my $tx = new Business::OnlinePayment(
575       'TransFirsteLink',
576       'merchantcustservnum' => "8005551212",
577   );
578   
579   # See the module documentation for details of content()
580   $tx->content(
581       type           => 'CC',
582       action         => 'Normal Authorization',
583       description    => 'Business::OnlinePayment::TransFirsteLink test',
584       amount         => '49.95',
585       invoice_number => '100100',
586       customer_id    => 'jef',
587       name           => 'Jeff Finucane',
588       address        => '123 Anystreet',
589       city           => 'Anywhere',
590       state          => 'GA',
591       zip            => '30004',
592       email          => 'transfirst@weasellips.com',
593       card_number    => '4111111111111111',
594       expiration     => '12/09',
595       cvv2           => '123',
596       order_number   => 'string',
597   );
598   
599   $tx->submit();
600   
601   if ( $tx->is_success() ) {
602       print(
603           "Card processed successfully: ", $tx->authorization, "\n",
604           "order number: ",                $tx->order_number,  "\n",
605           "CVV2 response: ",               $tx->cvv2_response, "\n",
606           "AVS code: ",                    $tx->avs_code,      "\n",
607       );
608   }
609   else {
610       my $info = "";
611       $info = " (CVV2 mismatch)" if ( $tx->result_code == 114 );
612       
613       print(
614           "Card was rejected: ", $tx->error_message, $info, "\n",
615           "order number: ",      $tx->order_number,         "\n",
616       );
617   }
618
619 =head1 DESCRIPTION
620
621 This module is a back end driver that implements the interface
622 specified by L<Business::OnlinePayment> to support payment handling
623 via TransFirst's eLink Internet payment solution.
624
625 See L<Business::OnlinePayment> for details on the interface this
626 modules supports.
627
628 =head1 Standard methods
629
630 =over 4
631
632 =item set_defaults()
633
634 This method sets the 'server' attribute to 'epaysecure1.transfirst.com' and
635 the port attribute to '443'.  This method also sets up the
636 L</Module specific methods> described below.
637
638 =item submit()
639
640 =back
641
642 =head1 Unofficial methods
643
644 This module provides the following methods which are not officially part of the
645 standard Business::OnlinePayment interface (as of 3.00_06) but are nevertheless
646 supported by multiple gateways modules and expected to be standardized soon:
647
648 =over 4
649
650 =item L<order_number()|/order_number()>
651
652 =item L<avs_code()|/avs_code()>
653
654 =item L<cvv2_response()|/cvv2_response()>
655
656 =back
657
658 =head1 Module specific methods
659
660 This module provides the following methods which are not currently
661 part of the standard Business::OnlinePayment interface:
662
663 =over 4
664
665 =item L<expdate_mmyy()|/expdate_mmyy()>
666
667 =item L<debug()|/debug()>
668
669 =back
670
671 =head1 Settings
672
673 The following default settings exist:
674
675 =over 4
676
677 =item server
678
679 epaysecure1.transfirst.com
680
681 =item port
682
683 443
684
685 =back
686
687 =head1 Handling of content(%content)
688
689 The following rules apply to content(%content) data:
690
691 =head2 type
692
693 If 'type' matches one of the following keys it is replaced by the
694 right hand side value:
695
696   'visa'               => 'CC',
697   'mastercard'         => 'CC',
698   'american express'   => 'CC',
699   'discover'           => 'CC',
700   'check'              => 'ECHECK',
701
702 The value of 'type' is used to set transaction_type().  Currently this
703 module only supports the above values.
704
705 =head1 Setting TransFirst eLink parameters from content(%content)
706
707 The following rules are applied to map data to TransFirst eLink parameters
708 from content(%content):
709
710     # eLink param       => $content{<key>}
711       ePayAccountNum    => 'login',
712       Password          => 'password',
713       OrderNum          => 'invoice_number',
714       OrderNumber       => 'invoice_number',
715
716       TransactionAmount => 'amount',
717       DollarAmount      => 'amount',
718       CardAccountNum    => 'card_number',
719       ExpirationDate    => \( $month.$year ), # MM/YY from 'expiration'
720       CVV2              => 'cvv2',
721
722       RoutingNumber     => 'routing_code',
723       AccountNumber     => \( $type eq 'CC' ? $card_number : $account_number ),
724       CheckNumber       => 'check_number',
725
726       CardHolderName    => 'name',
727       CardHolderAddress => 'address',
728       CardHolderCity    => 'city',
729       CardHolderState   => 'state',
730       CardHolderZip     => \$zip,       # 'zip' with non-alphanumerics removed
731       CardHolderEmail   => 'email',
732       CardHolderPhone   => 'phone',
733       CardHolderCountry => 'country',
734
735       CustomerName      => 'name',
736       CustomerAddress   => 'address',
737       CustomerCity      => 'city',
738       CustomerState     => 'state',
739       CustomerZip       => \$zip,       # 'zip' with non-alphanumerics removed
740       CustomerEmail     => 'email',
741       CustomerPhone     => 'phone',
742
743       PaymentDescriptor => 'description',
744
745 =head1 Mapping TransFirst eLink transaction responses to object methods
746
747 The following methods provides access to the transaction response data
748 resulting from a Payflow Pro request (after submit()) is called:
749
750 =head2 order_number()
751
752 This order_number() method returns the ReferenceNum field for card transactions
753 and TransactionId for check transactions to uniquely identify the transaction.
754
755 =head2 result_code()
756
757 The result_code() method returns the Extended Transaction Status field for
758 card transactions and the Result Code field for check transactions.  It is the
759 numeric return code indicating the outcome of the attempted
760 transaction.
761
762 =head2 error_message()
763
764 The error_message() method returns the Errors field for check
765 transactions.  This provides more details about the transaction result.
766
767 =head2 authorization()
768
769 The authorization() method returns the Authorization Response Code field,
770 which is the approval code obtained from the card processing network.
771
772 =head2 avs_code()
773
774 The avs_code() method returns the AVS Response Code field from the
775 transaction result.
776
777 =head2 cvv2_response()
778
779 The cvv2_response() method returns the CVV2 Response Code field, which is a
780 response message returned with the transaction result.
781
782 =head2 expdate_mmyy()
783
784 The expdate_mmyy() method takes a single scalar argument (typically
785 the value in $content{expiration}) and attempts to parse and format
786 and put the date in MMYY format as required by PayflowPro
787 specification.  If unable to parse the expiration date simply leave it
788 as is and let the PayflowPro system attempt to handle it as-is.
789
790 =head2 debug()
791
792 Enable or disble debugging.  The value specified here will also set
793 $Business::OnlinePayment::HTTPS::DEBUG in submit() to aid in
794 troubleshooting problems.
795
796 =head1 COMPATIBILITY
797
798 This module implements an interface to the TransFirst eLink API version
799 3.4
800
801 =head1 AUTHORS
802
803 Jeff Finucane <transfirst@weasellips.com>
804
805 Based on Business::OnlinePayment::PayflowPro written by Ivan Kohler
806 and Phil Lobbes.
807
808 =head1 SEE ALSO
809
810 perl(1), L<Business::OnlinePayment>, L<Carp>, and the TransFirst
811 e Payment Services Card Not Present eLink User Guide.
812
813 =cut