80cc4c25631c911544193112b505602873398cef
[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.02';
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     }
381
382     my $expdate_mmyy = $self->expdate_mmyy( $content{"expiration"} );
383     my $zip          = $content{'zip'};
384     $zip =~ s/[^[:alnum:]]//g;
385
386     my $merchantcustservnum = $self->merchantcustservnum;
387     my $account_number = $self->transaction_type() eq 'CC'
388                            ? $content{card_number}
389                            : $content{account_number} ;
390
391     my $invoice_number = $content{invoice_number} || "PAYMENT";  # make one up
392     my $check_number = $content{check_number} || "100";  # make one up
393
394     $self->_revmap_fields(
395
396         ePayAccountNum      => 'login',
397         Password            => 'password',
398         OrderNum            => \$invoice_number,
399         OrderNumber         => \$invoice_number,
400         MerchantCustServNum => \$merchantcustservnum,
401
402         TransactionAmount   => 'amount',
403         DollarAmount        => 'amount',
404         CardAccountNum      => 'card_number',
405         ExpirationDate      => \$expdate_mmyy,    # MMYY from 'expiration'
406         CVV2                => 'cvv2',
407
408         RoutingNumber       => 'routing_code',
409         AccountNumber       => \$account_number,
410         AccountNum          => \$account_number,
411         CheckNumber         => \$check_number,
412
413         CardHolderName      => 'name',
414         CustomerName        => 'account_name',
415         CardHolderAddress   => 'address',
416         CustomerAddress     => 'address',
417         CardHolderCity      => 'city',
418         CustomerCity        => 'city',
419         CardHolderState     => 'state',
420         CustomerState       => 'state',
421         CardHolderZip       => \$zip,          # 'zip' with non-alnums removed
422         CustomerZip         => \$zip,          # 'zip' with non-alnums removed
423         CardHolderEmail     => 'email',
424         CustomerEmail       => 'email',
425         CardHolderPhone     => 'phone',
426         CustomerPhone       => 'phone',
427         CustomerNum         => 'customer_id',
428         CustomerNumber      => 'customer_id',
429         CardHolderCountry   => 'country',
430
431         PaymentDescriptor   => 'description',
432
433         ReferenceNum        => 'order_number'
434     );
435
436     tie my %params, 'Tie::IxHash',
437       $self->get_fields( @{$required{$type_action}},
438                          @{$optional{$type_action}},
439                        );
440
441     $params{TestTransaction}='Y' if $self->test_transaction;
442
443     $params{InstallmentNum} = $params{InstallmentOf} = '01'
444       unless ($params{InstallmentNum} && $params{InstallmentOf}); 
445
446     if ($self->transaction_type() eq 'ECHECK') {
447       delete $params{InstallmentNum};
448       delete $params{InstallmentOf};
449     }
450
451     if ( $type_action eq "CC_30" || $type_action eq "CC_32" ) {
452       $self->path($self->path."elink/authpd.asp");
453     } elsif ( $type_action eq "CC_61" ) {
454       $self->path($self->path."eLink/voidpd.asp");
455     } elsif ( $type_action eq "CC_20" ) {
456       $self->path($self->path."eLink/creditpd.asp");
457     } elsif ( $type_action eq "ECHECK_32" ) {
458       $self->path($self->path."eLink/checkPD.asp");
459     } elsif ( $type_action eq "ECHECK_20" ) {
460       $self->path($self->path."eLink/checkcreditPD.asp");
461     } else {
462       croak "don't know path for unexpected type and action $type_action";
463     }
464
465     warn join("\n", map{ "$_ => $params{$_}" } keys(%params)) if $DEBUG > 1;
466     my ( $page, $resp, %resp_headers ) =
467       $self->https_post( %params );
468
469     $self->response_code( $resp );
470     $self->response_page( $page );
471     $self->response_headers( \%resp_headers );
472
473     warn "$page\n" if $DEBUG > 1;
474     # $page should contain | separated values
475
476     $self->required_fields(@{$required{$type_action}});
477
478     my $status ='';
479     my @rarray = ();
480
481     if ( $type_action eq "CC_30" || $type_action eq "CC_32" ) {
482       my ($format,$account,$tcode,$seq,$moi,$cardnum,$exp,$authamt,$authdate,
483           $authtime,$tstat,$custnum,$ordernum,$refnum,$rcode,$authsrc,$achar,
484           $transid,$vcode,$sic,$country,$avscode,$storenum,$cvv2resp,$cavvcode,
485           $crossrefnum,$etstat,$cavvresponse,$xid,$eci,@junk)
486         = split '\|', $page;
487
488       # AVS and CVS values may be set on success or failure
489       $self->avs_code($avscode);
490       $self->cvv2_response( $cvv2resp );
491       $self->result_code( $status = $etstat );
492       $self->order_number( $refnum );
493       $self->authorization( $rcode );
494       $self->junk( \@junk );
495       $self->error_message($error_messages{$status});
496
497
498     } elsif ( $type_action eq "CC_61" ) {
499       $self->avs_code('');
500       $self->cvv2_response('');
501       my ($format,$account,$tcode,$seq,$voiddate,$voidtime,$tstat, # flaky docs
502           $refnum,$filler1,$filler2,$filler3,$etstat,@junk)
503          = split '\|', $page;
504       $self->result_code( $status = $etstat );
505       $self->order_number( $refnum );
506       $self->authorization('');
507       $self->junk( \@junk );
508       $self->error_message($error_messages{$status});
509
510     } elsif ( $type_action eq "CC_20" ) {
511       $self->avs_code('');
512       $self->cvv2_response('');
513       my ($format,$account,$tcode,$seq,$moi,$authamt,$authdate,$authtime,
514           $tstat,$refnum,$crossrefnum,$custnum,$ordernum,$etstat,@junk)
515          = split '\|', $page;
516       $self->result_code( $status = $etstat );
517       $self->order_number( $refnum );
518       $self->authorization('');
519       $self->junk( \@junk );
520       $self->error_message($error_messages{$status});
521
522     } elsif ( $type_action eq "ECHECK_32" ) {
523       my ($responsecode,$response,$transactionid,$note,$errors,@junk)
524          = split '\|', $page;
525       $self->avs_code('');
526       $self->cvv2_response('');
527       $self->result_code( $status = $responsecode );
528       $self->order_number( $transactionid );
529       $self->authorization('');
530       $errors = $errors ? $errors : '';
531       $self->error_message("$response $errors");
532       $self->junk( \@junk );
533
534     } elsif ( $type_action eq "ECHECK_20" ) {
535       my ($response,$transactionid,$note,$errors,@junk) # very flaky docs
536          = split '\|', $page;
537       $self->avs_code('');
538       $self->cvv2_response('');
539       $self->result_code( $status = $response );
540       $self->order_number( $transactionid );
541       $self->authorization('');
542       $errors = $errors ? $errors : '';
543       $self->error_message("$response $errors");
544       $self->junk( \@junk );
545
546     } else {
547       croak "can't interpret response for unexpected type and action $type_action";
548     }
549
550     if ( $resp eq "200" && ($status eq "000" || $status eq "011" || $status eq "085" || $status eq "0P0" || $status eq "P00" || $status eq 'ACCEPTED') ) {
551         $self->is_success(1);
552     }
553     else {
554         $self->is_success(0);
555     }
556 }
557
558 1;
559
560 __END__
561
562 =head1 NAME
563
564 Business::OnlinePayment::TransFirsteLink - Transfirst eLink backend for Business::OnlinePayment
565
566 =head1 SYNOPSIS
567
568   use Business::OnlinePayment;
569   
570   my $tx = new Business::OnlinePayment(
571       'TransFirsteLink',
572       'merchantcustservnum' => "8005551212",
573   );
574   
575   # See the module documentation for details of content()
576   $tx->content(
577       type           => 'CC',
578       action         => 'Normal Authorization',
579       description    => 'Business::OnlinePayment::TransFirsteLink test',
580       amount         => '49.95',
581       invoice_number => '100100',
582       customer_id    => 'jef',
583       name           => 'Jeff Finucane',
584       address        => '123 Anystreet',
585       city           => 'Anywhere',
586       state          => 'GA',
587       zip            => '30004',
588       email          => 'transfirst@weasellips.com',
589       card_number    => '4111111111111111',
590       expiration     => '12/09',
591       cvv2           => '123',
592       order_number   => 'string',
593   );
594   
595   $tx->submit();
596   
597   if ( $tx->is_success() ) {
598       print(
599           "Card processed successfully: ", $tx->authorization, "\n",
600           "order number: ",                $tx->order_number,  "\n",
601           "CVV2 response: ",               $tx->cvv2_response, "\n",
602           "AVS code: ",                    $tx->avs_code,      "\n",
603       );
604   }
605   else {
606       my $info = "";
607       $info = " (CVV2 mismatch)" if ( $tx->result_code == 114 );
608       
609       print(
610           "Card was rejected: ", $tx->error_message, $info, "\n",
611           "order number: ",      $tx->order_number,         "\n",
612       );
613   }
614
615 =head1 DESCRIPTION
616
617 This module is a back end driver that implements the interface
618 specified by L<Business::OnlinePayment> to support payment handling
619 via TransFirst's eLink Internet payment solution.
620
621 See L<Business::OnlinePayment> for details on the interface this
622 modules supports.
623
624 =head1 Standard methods
625
626 =over 4
627
628 =item set_defaults()
629
630 This method sets the 'server' attribute to 'epaysecure1.transfirst.com' and
631 the port attribute to '443'.  This method also sets up the
632 L</Module specific methods> described below.
633
634 =item submit()
635
636 =back
637
638 =head1 Unofficial methods
639
640 This module provides the following methods which are not officially part of the
641 standard Business::OnlinePayment interface (as of 3.00_06) but are nevertheless
642 supported by multiple gateways modules and expected to be standardized soon:
643
644 =over 4
645
646 =item L<order_number()|/order_number()>
647
648 =item L<avs_code()|/avs_code()>
649
650 =item L<cvv2_response()|/cvv2_response()>
651
652 =back
653
654 =head1 Module specific methods
655
656 This module provides the following methods which are not currently
657 part of the standard Business::OnlinePayment interface:
658
659 =over 4
660
661 =item L<expdate_mmyy()|/expdate_mmyy()>
662
663 =item L<debug()|/debug()>
664
665 =back
666
667 =head1 Settings
668
669 The following default settings exist:
670
671 =over 4
672
673 =item server
674
675 epaysecure1.transfirst.com
676
677 =item port
678
679 443
680
681 =back
682
683 =head1 Handling of content(%content)
684
685 The following rules apply to content(%content) data:
686
687 =head2 type
688
689 If 'type' matches one of the following keys it is replaced by the
690 right hand side value:
691
692   'visa'               => 'CC',
693   'mastercard'         => 'CC',
694   'american express'   => 'CC',
695   'discover'           => 'CC',
696   'check'              => 'ECHECK',
697
698 The value of 'type' is used to set transaction_type().  Currently this
699 module only supports the above values.
700
701 =head1 Setting TransFirst eLink parameters from content(%content)
702
703 The following rules are applied to map data to TransFirst eLink parameters
704 from content(%content):
705
706     # eLink param       => $content{<key>}
707       ePayAccountNum    => 'login',
708       Password          => 'password',
709       OrderNum          => 'invoice_number',
710       OrderNumber       => 'invoice_number',
711
712       TransactionAmount => 'amount',
713       DollarAmount      => 'amount',
714       CardAccountNum    => 'card_number',
715       ExpirationDate    => \( $month.$year ), # MM/YY from 'expiration'
716       CVV2              => 'cvv2',
717
718       RoutingNumber     => 'routing_code',
719       AccountNumber     => \( $type eq 'CC' ? $card_number : $account_number ),
720       CheckNumber       => 'check_number',
721
722       CardHolderName    => 'name',
723       CardHolderAddress => 'address',
724       CardHolderCity    => 'city',
725       CardHolderState   => 'state',
726       CardHolderZip     => \$zip,       # 'zip' with non-alphanumerics removed
727       CardHolderEmail   => 'email',
728       CardHolderPhone   => 'phone',
729       CardHolderCountry => 'country',
730
731       CustomerName      => 'name',
732       CustomerAddress   => 'address',
733       CustomerCity      => 'city',
734       CustomerState     => 'state',
735       CustomerZip       => \$zip,       # 'zip' with non-alphanumerics removed
736       CustomerEmail     => 'email',
737       CustomerPhone     => 'phone',
738
739       PaymentDescriptor => 'description',
740
741 =head1 Mapping TransFirst eLink transaction responses to object methods
742
743 The following methods provides access to the transaction response data
744 resulting from a Payflow Pro request (after submit()) is called:
745
746 =head2 order_number()
747
748 This order_number() method returns the ReferenceNum field for card transactions
749 and TransactionId for check transactions to uniquely identify the transaction.
750
751 =head2 result_code()
752
753 The result_code() method returns the Extended Transaction Status field for
754 card transactions and the Result Code field for check transactions.  It is the
755 numeric return code indicating the outcome of the attempted
756 transaction.
757
758 =head2 error_message()
759
760 The error_message() method returns the Errors field for check
761 transactions.  This provides more details about the transaction result.
762
763 =head2 authorization()
764
765 The authorization() method returns the Authorization Response Code field,
766 which is the approval code obtained from the card processing network.
767
768 =head2 avs_code()
769
770 The avs_code() method returns the AVS Response Code field from the
771 transaction result.
772
773 =head2 cvv2_response()
774
775 The cvv2_response() method returns the CVV2 Response Code field, which is a
776 response message returned with the transaction result.
777
778 =head2 expdate_mmyy()
779
780 The expdate_mmyy() method takes a single scalar argument (typically
781 the value in $content{expiration}) and attempts to parse and format
782 and put the date in MMYY format as required by PayflowPro
783 specification.  If unable to parse the expiration date simply leave it
784 as is and let the PayflowPro system attempt to handle it as-is.
785
786 =head2 debug()
787
788 Enable or disble debugging.  The value specified here will also set
789 $Business::OnlinePayment::HTTPS::DEBUG in submit() to aid in
790 troubleshooting problems.
791
792 =head1 COMPATIBILITY
793
794 This module implements an interface to the TransFirst eLink API version
795 3.4
796
797 =head1 AUTHORS
798
799 Jeff Finucane <transfirst@weasellips.com>
800
801 Based on Business::OnlinePayment::PayflowPro written by Ivan Kohler
802 and Phil Lobbes.
803
804 =head1 SEE ALSO
805
806 perl(1), L<Business::OnlinePayment>, L<Carp>, and the TransFirst
807 e Payment Services Card Not Present eLink User Guide.
808
809 =cut