initial import
[Business-OnlinePayment-PayflowPro.git] / LinkPoint.pm
1 package Business::OnlinePayment::PayflowPro;
2
3 use strict;
4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
5 use Carp qw(croak);
6 use AutoLoader;
7 use Business::OnlinePayment;
8
9 use PFProAPI; #Payflow PRO SDK from Verisign
10
11 require Exporter;
12
13 @ISA = qw(Exporter AutoLoader Business::OnlinePayment);
14 @EXPORT = qw();
15 @EXPORT_OK = qw();
16 $VERSION = '0.02';
17
18 sub set_defaults {
19     my $self = shift;
20
21     #$self->server('staging.linkpt.net');
22     $self->server('secure.linkpt.net');
23     $self->port('1139');
24
25 }
26
27 sub map_fields {
28     my($self) = @_;
29
30     my %content = $self->content();
31
32     #ACTION MAP
33     my %actions = ('normal authorization' => 'ApproveSale',
34                    'authorization only'   => 'CapturePayment',
35                    'credit'               => 'ReturnOrder',
36                    'post authorization'   => 'BillOrders',
37                   );
38     $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
39
40     # stuff it back into %content
41     $self->content(%content);
42 }
43
44 sub build_subs {
45     my $self = shift;
46     foreach(@_) {
47         #no warnings; #not 5.005
48         local($^W)=0;
49         eval "sub $_ { my \$self = shift; if(\@_) { \$self->{$_} = shift; } return \$self->{$_}; }";
50     }
51 }
52
53 sub remap_fields {
54     my($self,%map) = @_;
55
56     my %content = $self->content();
57     foreach(keys %map) {
58         $content{$map{$_}} = $content{$_};
59     }
60     $self->content(%content);
61 }
62
63 sub revmap_fields {
64     my($self, %map) = @_;
65     my %content = $self->content();
66     foreach(keys %map) {
67 #    warn "$_ = ". ( ref($map{$_})
68 #                         ? ${ $map{$_} }
69 #                         : $content{$map{$_}} ). "\n";
70         $content{$_} = ref($map{$_})
71                          ? ${ $map{$_} }
72                          : $content{$map{$_}};
73     }
74     $self->content(%content);
75 }
76
77 sub get_fields {
78     my($self,@fields) = @_;
79
80     my %content = $self->content();
81     my %new = ();
82     foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
83     return %new;
84 }
85
86 sub submit {
87     my($self) = @_;
88
89
90     $self->map_fields();
91
92     my %content = $self->content;
93
94     my($month, $year);
95     unless ( $content{action} eq 'BillOrders' ) {
96
97         if (  $self->transaction_type() =~
98                 /^(cc|visa|mastercard|american express|discover)$/i
99            ) {
100         } else {
101             Carp::croak("PayflowPro can't handle transaction type: ".
102                         $self->transaction_type());
103         }
104
105       $content{'expiration'} =~ /^(\d+)\D+\d*(\d{2})$/
106         or croak "unparsable expiration $content{expiration}";
107
108       ( $month, $year ) = ( $1, $2 );
109       $month = '0'. $month if $month =~ /^\d$/;
110       $year += 2000 if $year < 2000; #not y4k safe, oh shit
111     }
112
113     $content{'address'} =~ /^(\S+)\s/;
114     my $addrnum = $1;
115
116     $self->server('staging.linkpt.net') if $self->test_transaction;
117
118     $self->revmap_fields(
119       hostname     => \( $self->server ),
120       port         => \( $self->port ),
121       storename    => \( $self->storename ),
122       keyfile      => \( $self->keyfile ),
123       addrnum      => \$addrnum,
124
125       cardNumber   => 'card_number',
126       cardExpMonth => \$month,
127       cardExpYear  => \$year,
128     );
129
130     my $lperl = new LPERL
131       $self->lbin,
132       'FILE',
133       $self->can('tmp')
134         ? $self->tmp
135         : '/tmp';
136     my $action = $content{action};
137
138     $self->required_fields(qw/
139       hostname port storename keyfile amount cardNumber cardExpMonth cardExpYear
140     /);
141
142     my %post_data = $self->get_fields(qw/
143       hostname port storename keyfile
144       result
145       amount cardNumber cardExpMonth cardExpYear
146       name email phone address city state zip country
147     /);
148
149     #print "$_ => $post_data{$_}\n" foreach keys %post_data;
150
151     my %response;
152     {
153       local($^W)=0;
154       %response = $lperl->$action(\%post_data);
155     }
156
157     if ( $response{'statusCode'} == 0 ) {
158       $self->is_success(0);
159       $self->result_code('');
160       $self->error_message($response{'statusMessage'});
161     } else {
162       $self->is_success(1);
163       $self->result_code($response{'AVCCode'});
164       $self->authorization($response{'trackingID'});
165 #      $self->order_number($response{'neworderID'});
166     }
167
168 }
169
170 1;
171 __END__
172
173 =head1 NAME
174
175 Business::OnlinePayment::PayflowPro - Verisign PayflowPro backend for Business::OnlinePayment
176
177 =head1 SYNOPSIS
178
179   use Business::OnlinePayment;
180
181   my $tx = new Business::OnlinePayment( 'PayflowPro',
182     'storename' => 'your_store_number',
183     'keyfile'   => '/path/to/keyfile.pem',
184     'lbin'      => '/path/to/binary/lbin',
185     'tmp'       => '/secure/tmp',          # a secure tmp directory
186   );
187
188   $tx->content(
189       type           => 'VISA',
190       action         => 'Normal Authorization',
191       description    => 'Business::OnlinePayment test',
192       amount         => '49.95',
193       invoice_number => '100100',
194       customer_id    => 'jsk',
195       name           => 'Jason Kohles',
196       address        => '123 Anystreet',
197       city           => 'Anywhere',
198       state          => 'UT',
199       zip            => '84058',
200       email          => 'ivan-payflowpro@420.am',
201       card_number    => '4007000000027',
202       expiration     => '09/99',
203   );
204   $tx->submit();
205
206   if($tx->is_success()) {
207       print "Card processed successfully: ".$tx->authorization."\n";
208   } else {
209       print "Card was rejected: ".$tx->error_message."\n";
210   }
211
212 =head1 SUPPORTED TRANSACTION TYPES
213
214 =head2 Visa, MasterCard, American Express, JCB, Discover/Novus, Carte blanche/Diners Club
215
216 =head1 DESCRIPTION
217
218 For detailed information see L<Business::OnlinePayment>.
219
220 =head1 COMPATIBILITY
221
222 This module implements an interface to the PayflowPro Perl API, which can
223 be downloaded at https://manager.verisign.com/ with a valid login.
224
225 =head1 BUGS
226
227 =head1 AUTHOR
228
229 Ivan Kohler <ivan-payflowpro@420.am>
230
231 Based on Busienss::OnlinePayment::AuthorizeNet written by Jason Kohles.
232
233 =head1 SEE ALSO
234
235 perl(1), L<Business::OnlinePayment>.
236
237 =cut
238