- Add patch from William McKee <william@knowmad.com> to support
[Business-OnlinePayment-LinkPoint.git] / LinkPoint.pm
1 package Business::OnlinePayment::LinkPoint;
2
3 # $Id: LinkPoint.pm,v 1.23 2005-01-07 02:53:50 ivan Exp $
4
5 use strict;
6 use vars qw($VERSION @ISA $DEBUG @EXPORT @EXPORT_OK);
7 use Carp qw(croak);
8 use AutoLoader;
9 use Business::OnlinePayment;
10
11 require Exporter;
12
13 @ISA = qw(Exporter AutoLoader Business::OnlinePayment);
14 @EXPORT = qw();
15 @EXPORT_OK = qw();
16 $VERSION = '0.05';
17 $DEBUG = 0;
18
19 use lpperl; #3;  #lpperl.pm from LinkPoint
20 $LPPERL::VERSION =~ /^(\d+\.\d+)/
21   or die "can't parse lpperl.pm version: $LPPERL::VERSION";
22 die "lpperl.pm minimum version 3 required\n" unless $1 >= 3;
23
24 sub set_defaults {
25     my $self = shift;
26
27     #$self->server('staging.linkpt.net');
28     $self->server('secure.linkpt.net');
29     $self->port('1129');
30
31     $self->build_subs(qw(order_number avs_code));
32
33 }
34
35 sub map_fields {
36     my($self) = @_;
37
38     my %content = $self->content();
39
40     #ACTION MAP
41     my %actions = ('normal authorization' => 'SALE',
42                    'authorization only'   => 'PREAUTH',
43                    'credit'               => 'CREDIT',
44                    'post authorization'   => 'POSTAUTH',
45                    'void'                 => 'VOID',
46                   );
47     $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
48
49     # stuff it back into %content
50     $self->content(%content);
51 }
52
53 sub build_subs {
54     my $self = shift;
55     foreach(@_) {
56         #no warnings; #not 5.005
57         local($^W)=0;
58         eval "sub $_ { my \$self = shift; if(\@_) { \$self->{$_} = shift; } return \$self->{$_}; }";
59     }
60 }
61
62 sub remap_fields {
63     my($self,%map) = @_;
64
65     my %content = $self->content();
66     foreach(keys %map) {
67         $content{$map{$_}} = $content{$_};
68     }
69     $self->content(%content);
70 }
71
72 sub revmap_fields {
73     my($self, %map) = @_;
74     my %content = $self->content();
75     foreach(keys %map) {
76 #    warn "$_ = ". ( ref($map{$_})
77 #                         ? ${ $map{$_} }
78 #                         : $content{$map{$_}} ). "\n";
79         $content{$_} = ref($map{$_})
80                          ? ${ $map{$_} }
81                          : $content{$map{$_}};
82     }
83     $self->content(%content);
84 }
85
86 sub get_fields {
87     my($self,@fields) = @_;
88
89     my %content = $self->content();
90     my %new = ();
91     foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
92     return %new;
93 }
94
95 sub submit {
96     my($self) = @_;
97
98     $self->map_fields();
99
100     my %content = $self->content;
101
102     my($month, $year);
103     unless ( $content{action} eq 'POSTAUTH'
104              || ( $content{'action'} =~ /^(CREDIT|VOID)$/
105                   && exists $content{'order_number'} )
106            ) {
107
108         if (  $self->transaction_type() =~
109                 /^(cc|visa|mastercard|american express|discover)$/i
110            ) {
111         } else {
112             Carp::croak("LinkPoint can't handle transaction type: ".
113                         $self->transaction_type());
114         }
115
116       $content{'expiration'} =~ /^(\d+)\D+\d*(\d{2})$/
117         or croak "unparsable expiration $content{expiration}";
118
119       ( $month, $year ) = ( $1, $2 );
120       $month = '0'. $month if $month =~ /^\d$/;
121     }
122
123     $content{'address'} =~ /^(\S+)\s/;
124     my $addrnum = $1;
125
126     my $result = $content{'result'};
127     if ( $self->test_transaction) {
128       $result ||= 'GOOD';
129       #$self->server('staging.linkpt.net');
130     } else {
131       $result ||= 'LIVE';
132     }
133
134     $self->revmap_fields(
135       host         => \( $self->server ),
136       port         => \( $self->port ),
137       #storename    => \( $self->storename ),
138       configfile   => \( $self->storename ),
139       keyfile      => \( $self->keyfile ),
140       addrnum      => \$addrnum,
141       result       => \$result,
142       cardnumber   => 'card_number',
143       cardexpmonth => \$month,
144       cardexpyear  => \$year,
145       chargetotal  => 'amount',
146       oid          => 'order_number',
147     );
148
149     my $lperl = new LPPERL;
150
151     $self->required_fields(qw/
152       host port configfile keyfile amount cardnumber cardexpmonth cardexpyear
153     /);
154
155     my %post_data = $self->get_fields(qw/
156       host port configfile keyfile
157       result
158       chargetotal cardnumber cardexpmonth cardexpyear
159       name email phone addrnum city state zip country
160       oid
161     /);
162
163     $post_data{'ordertype'} = $content{action};
164
165     if ( $content{'cvv2'} ) { 
166       $post_data{cvmindicator} = 'provided';
167       $post_data{cvmvalue} = $content{'cvv2'};
168     }
169
170     if ( $DEBUG ) {
171       warn "$_ => $post_data{$_}\n" foreach keys %post_data;
172     }
173
174     my %response;
175     #{
176     #  local($^W)=0;
177     #  %response = $lperl->$action(\%post_data);
178     #}
179     %response = $lperl->curl_process(\%post_data);
180
181     if ( $DEBUG ) {
182       warn "$_ => $response{$_}\n" for keys %response;
183     }
184
185     if ( $response{'r_approved'} eq 'APPROVED' ) {
186       $self->is_success(1);
187       $self->result_code($response{'r_code'});
188       $self->authorization($response{'r_ref'});
189       $self->order_number($response{'r_ordernum'});
190       $self->avs_code($response{'r_avs'});
191     } else {
192       $self->is_success(0);
193       $self->result_code('');
194       $self->error_message($response{'r_error'});
195     }
196
197 }
198
199 1;
200 __END__
201
202 =head1 NAME
203
204 Business::OnlinePayment::LinkPoint - LinkPoint (Cardservice) backend for Business::OnlinePayment
205
206 =head1 SYNOPSIS
207
208   use Business::OnlinePayment;
209
210   my $tx = new Business::OnlinePayment( 'LinkPoint',
211     'storename' => 'your_store_number',
212     'keyfile'   => '/path/to/keyfile.pem',
213   );
214
215   $tx->content(
216       type           => 'VISA',
217       action         => 'Normal Authorization',
218       description    => 'Business::OnlinePayment test',
219       amount         => '49.95',
220       invoice_number => '100100',
221       customer_id    => 'jsk',
222       name           => 'Jason Kohles',
223       address        => '123 Anystreet',
224       city           => 'Anywhere',
225       state          => 'UT',
226       zip            => '84058',
227       email          => 'ivan-linkpoint@420.am',
228       card_number    => '4007000000027',
229       expiration     => '09/99',
230   );
231   $tx->submit();
232
233   if($tx->is_success()) {
234       print "Card processed successfully: ".$tx->authorization."\n";
235   } else {
236       print "Card was rejected: ".$tx->error_message."\n";
237   }
238
239 =head1 SUPPORTED TRANSACTION TYPES
240
241 =head2 Visa, MasterCard, American Express, JCB, Discover/Novus, Carte blanche/Diners Club
242
243 =head1 DESCRIPTION
244
245 For detailed information see L<Business::OnlinePayment>.
246
247 =head1 COMPATIBILITY
248
249 This module implements an interface to the LinkPoint Perl Wrapper
250 http://www.linkpoint.com/product_solutions/internet/lperl/lperl_main.html
251
252 Versions 0.4 and on of this module support the LinkPoint Perl Wrapper version
253 3.5.
254
255 =head1 BUGS
256
257 =head1 AUTHOR
258
259 Ivan Kohler <ivan-linkpoint@420.am>
260
261 Based on Busienss::OnlinePayment::AuthorizeNet written by Jason Kohles.
262
263 =head1 SEE ALSO
264
265 perl(1), L<Business::OnlinePayment>.
266
267 =cut
268