1 package Business::OnlinePayment::PayflowPro;
6 use base qw(Business::OnlinePayment);
8 # PayflowPRO SDK from PayPal/Verisign
9 use PFProAPI qw( pfpro );
12 $VERSION = eval $VERSION;
17 $self->server('payflow.verisign.com');
21 vendor partner order_number cert_path avs_code cvv2_code
28 my %content = $self->content();
31 my %actions = ('normal authorization' => 'S', #Sale
32 'authorization only' => 'A', #Authorization
33 'credit' => 'C', #Credit (refund)
34 'post authorization' => 'D', #Delayed Capture
37 $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
40 my %types = ('visa' => 'C',
42 'american express' => 'C',
47 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
48 $self->transaction_type($content{'type'});
50 # stuff it back into %content
51 $self->content(%content);
57 my %content = $self->content();
59 $content{$map{$_}} = $content{$_};
61 $self->content(%content);
66 my %content = $self->content();
68 # warn "$_ = ". ( ref($map{$_})
70 # : $content{$map{$_}} ). "\n";
71 $content{$_} = ref($map{$_})
75 $self->content(%content);
83 my %content = $self->content;
85 my($month, $year, $zip);
87 if ( $self->transaction_type() ne 'C' ) {
88 croak("PayflowPro can't (yet?) handle transaction type: " .
89 $self->transaction_type());
92 if ( defined($content{'expiration'}) && length($content{'expiration'}) ) {
93 $content{'expiration'} =~ /^(\d+)\D+\d*(\d{2})$/
94 or croak "unparsable expiration $content{expiration}";
96 ( $month, $year ) = ( $1, $2 );
97 $month = '0'. $month if $month =~ /^\d$/;
100 ( $zip = $content{'zip'} ) =~ s/\D//g;
102 $self->server('test-payflow.verisign.com') if $self->test_transaction;
104 $self->revmap_fields(
105 ACCT => 'card_number',
106 EXPDATE => \( $month.$year ),
109 # (BUG?) VENDOR B::OP:PayflowPro < 0.05 backward compatibility. If
110 # vendor not set use login (although test indicate undef vendor is ok)
111 VENDOR => $self->vendor ? \( $self->vendor ) : 'login',
112 PARTNER => \( $self->partner ),
121 COMMENT1 => 'description',
122 COMMENT2 => 'invoice_number',
123 COMPANYNAME => 'company',
124 COUNTRY => 'country',
125 FIRSTNAME => 'first_name',
126 LASTNAME => 'last_name',
132 ORIGID => 'order_number'
136 my @required = qw( TRXTYPE TENDER PARTNER VENDOR USER PWD );
137 if ( $self->transaction_type() eq 'C' ) { #credit card
138 if ( $content{'action'} =~ /^[CDV]$/
139 && defined($content{'ORIGID'})
140 && length($content{'ORIGID'})
143 push @required, qw(ORIGID);
145 push @required, qw(AMT ACCT EXPDATE);
148 $self->required_fields(@required);
150 my %params = $self->get_fields(qw(
151 ACCT EXPDATE AMT USER VENDOR PARTNER PWD TRXTYPE TENDER
152 STREET ZIP CITY COMMENT1 COMMENT2 COMPANYNAME COUNTRY
153 FIRSTNAME LASTNAME NAME EMAIL STATE
157 $ENV{'PFPRO_CERT_PATH'} = $self->cert_path;
158 my( $response, $resultstr ) = pfpro( \%params, $self->server, $self->port );
159 # PNREF (aka transaction id) is set on success and failure
160 $self->order_number( $response->{'PNREF'} );
162 if ( $response->{'RESULT'} eq '0' ) { #want an explicit zero, not just
164 $self->is_success(1);
165 $self->result_code( $response->{'RESULT'} );
166 $self->error_message( $response->{'RESPMSG'} );
167 $self->authorization( $response->{'AUTHCODE'} );
169 if ( exists $response->{AVSADDR} || exists $response->{AVSZIP} ) {
170 if ( $response->{AVSADDR} eq 'Y' && $response->{AVSZIP} eq 'Y' ) {
172 } elsif ( $response->{AVSADDR} eq 'Y' ) {
174 } elsif ( $response->{AVSZIP} eq 'Y' ) {
176 } elsif ( $response->{AVSADDR} eq 'N' || $response->{AVSZIP} eq 'N' ) {
180 $self->avs_code( $avs_code );
181 $self->cvv2_code( $response->{'CVV2MATCH'});
183 $self->is_success(0);
184 $self->result_code( $response->{'RESULT'} );
185 $self->error_message( $response->{'RESPMSG'} );
196 Business::OnlinePayment::PayflowPro - Verisign PayflowPro backend for Business::OnlinePayment
200 use Business::OnlinePayment;
202 my $tx = new Business::OnlinePayment( 'PayflowPro',
203 'vendor' => 'your_vendor',
204 'partner' => 'your_partner',
205 'cert_path' => '/path/to/your/certificate/file/', #just the dir
210 action => 'Normal Authorization',
211 description => 'Business::OnlinePayment test',
213 invoice_number => '100100',
214 customer_id => 'jsk',
215 name => 'Jason Kohles',
216 address => '123 Anystreet',
220 email => 'ivan-payflowpro@420.am',
221 card_number => '4007000000027',
222 expiration => '09/04',
226 order_number => 'string', # returned by $tx->order_number() from an
227 # "authorization only" or
228 # "normal authorization" action, used by a
229 # "credit", "void", or "post authorization"
233 if($tx->is_success()) {
234 print "Card processed successfully: ", $tx->authorization, "\n";
235 print "order number: ", $tx->order_number, "\n";
236 print "AVS code: ", $tx->avs_code, "\n"; # Y - Address and ZIP match
237 # A - Address matches but not ZIP
238 # Z - ZIP matches bu tnot address
240 # E - AVS error or unsupported
242 print "CVV2 code: ", $tx->cvv2_code, "\n";
245 print "Card was rejected: ", $tx->error_message;
246 print " (CVV2 mismatch)" if $tx->result_code == 114;
250 =head1 SUPPORTED TRANSACTION TYPES
252 =head2 Visa, MasterCard, American Express, JCB, Discover/Novus, Carte blanche/Diners Club, CC
254 =head1 SUPPORTED ACTIONS
256 =head2 Normal Authorization, Authorization Only, Post Authorization, Credit, Void
260 For detailed information see L<Business::OnlinePayment>.
264 This module implements an interface to the PayflowPro Perl API, which
265 can be downloaded at https://manager.verisign.com/ with a valid login.
271 Ivan Kohler <ivan-payflowpro@420.am>
273 Based on Busienss::OnlinePayment::AuthorizeNet written by Jason Kohles.
277 perl(1), L<Business::OnlinePayment>.