File Coverage

blib/lib/Business/OnlinePayment/PlugnPay.pm
Criterion Covered Total %
statement 29 126 23.0
branch 3 40 7.5
condition 1 33 3.0
subroutine 6 11 54.5
pod 5 5 100.0
total 44 215 20.4


line stmt bran cond sub pod time code
1             package Business::OnlinePayment::PlugnPay;
2              
3 2     2   42767 use strict;
  2         5  
  2         85  
4 2     2   11 use vars qw($VERSION $DEBUG);
  2         4  
  2         124  
5 2     2   10 use Carp qw(carp croak);
  2         9  
  2         144  
6              
7 2     2   10 use base qw(Business::OnlinePayment::HTTPS);
  2         5  
  2         2130  
8              
9             $VERSION = '0.03';
10             $VERSION = eval $VERSION;
11             $DEBUG = 0;
12              
13             sub debug {
14 0     0 1 0 my $self = shift;
15              
16 0 0       0 if (@_) {
17 0   0     0 my $level = shift || 0;
18 0 0       0 if ( ref($self) ) {
19 0         0 $self->{"__DEBUG"} = $level;
20             }
21             else {
22 0         0 $DEBUG = $level;
23             }
24 0         0 $Business::OnlinePayment::HTTPS::DEBUG = $level;
25             }
26 0 0 0     0 return ref($self) ? ( $self->{"__DEBUG"} || $DEBUG ) : $DEBUG;
27             }
28              
29             sub set_defaults {
30 2     2 1 3465 my $self = shift;
31 2         4 my %opts = @_;
32              
33             # standard B::OP methods/data
34 2         53 $self->server("pay1.plugnpay.com");
35 2         60 $self->port("443");
36 2         61 $self->path("/payment/pnpremote.cgi");
37              
38 2         25 $self->build_subs(qw(
39             order_number avs_code cvv2_response
40             response_page response_code response_headers
41             ));
42              
43             # module specific data
44 2 50       150 if ( $opts{debug} ) {
45 0         0 $self->debug( $opts{debug} );
46 0         0 delete $opts{debug};
47             }
48              
49 2         3 my %_defaults = ();
50 2         6 foreach my $key (keys %opts) {
51 0 0       0 $key =~ /^default_(\w*)$/ or next;
52 0         0 $_defaults{$1} = $opts{$key};
53 0         0 delete $opts{$key};
54             }
55 2         8 $self->{_defaults} = \%_defaults;
56              
57             }
58              
59             sub _map_fields {
60 0     0   0 my ($self) = @_;
61              
62 0         0 my %content = $self->content();
63              
64             #ACTION MAP
65 0         0 my %actions = (
66             'normal authorization' => 'auth', # Authorization/Settle transaction
67             'credit' => 'newreturn',# Credit (refund)
68             'void' => 'void', # Void
69             );
70              
71 0   0     0 $content{'mode'} = $actions{ lc( $content{'action'} ) }
72             || $content{'action'};
73              
74             # TYPE MAP
75 0         0 my %types = (
76             'visa' => 'CC',
77             'mastercard' => 'CC',
78             'american express' => 'CC',
79             'discover' => 'CC',
80             'cc' => 'CC',
81             'check' => 'ECHECK',
82             );
83              
84 0   0     0 $content{'type'} = $types{ lc( $content{'type'} ) } || $content{'type'};
85              
86             # PAYMETHOD MAP
87 0         0 my %paymethods = (
88             'CC' => 'credit',
89             'ECHECK' => 'onlinecheck',
90             );
91              
92 0         0 $content{'paymethod'} = $paymethods{ $content{'type'} };
93              
94 0         0 $self->transaction_type( $content{'type'} );
95              
96 0 0       0 $content{'transflags'} = 'recurring'
97             if lc( $content{'recurring_billing'} ) eq 'yes';
98              
99             # stuff it back into %content
100 0         0 $self->content(%content);
101             }
102              
103             sub _revmap_fields {
104 0     0   0 my ( $self, %map ) = @_;
105 0         0 my %content = $self->content();
106 0         0 foreach ( keys %map ) {
107 0         0 $content{$_} =
108             ref( $map{$_} )
109 0 0       0 ? ${ $map{$_} }
110             : $content{ $map{$_} };
111             }
112 0         0 $self->content(%content);
113             }
114              
115             sub expdate_mmyy {
116 4     4 1 1238 my $self = shift;
117 4         5 my $expiration = shift;
118 4         4 my $expdate_mmyy;
119 4 50 33     36 if ( defined($expiration) and $expiration =~ /^(\d+)\D+\d*(\d{2})$/ ) {
120 4         8 my ( $month, $year ) = ( $1, $2 );
121 4         13 $expdate_mmyy = sprintf( "%02d/", $month ) . $year;
122             }
123 4 50       13 return defined($expdate_mmyy) ? $expdate_mmyy : $expiration;
124             }
125              
126             sub required_fields {
127 0     0 1   my($self,@fields) = @_;
128              
129 0           my @missing;
130 0           my %content = $self->content();
131 0           foreach(@fields) {
132             next
133 0 0 0       if (exists $content{$_} && defined $content{$_} && $content{$_}=~/\S+/);
      0        
134 0           push(@missing, $_);
135             }
136              
137 0 0         Carp::croak("missing required field(s): " . join(", ", @missing) . "\n")
138             if(@missing);
139              
140             }
141              
142             sub submit {
143 0     0 1   my ($self) = @_;
144              
145 0 0         die "Processor does not support a test mode"
146             if $self->test_transaction;
147              
148 0           $self->_map_fields();
149              
150 0           my %content = $self->content;
151              
152 0           my %required;
153 0           $required{CC_auth} = [ qw( mode publisher-name card-amount card-name
154             card-number card-exp paymethod ) ];
155 0           $required{CC_newreturn} = [ @{$required{CC_auth}}, qw( publisher-password ) ];
  0            
156 0           $required{CC_void} = [ qw( mode publisher-name publisher-password orderID
157             card-amount ) ];
158             #$required{ECHECK_auth} = [ qw( mode publisher-name accttype routingnum
159             # accountnum checknum paymethod ) ];
160 0           my %optional;
161 0           $optional{CC_auth} = [ qw( publisher-email authtype required dontsndmail
162             easycard client convert cc-mail transflags
163             card-address1 card-address2 card-city card-state
164             card-prov card-zip card-country card-cvv
165             currency phone fax email shipinfo shipname
166             address1 address2 city state province zip
167             country ipaddress accttype orderID tax
168             shipping app-level order-id acct_code magstripe
169             marketdata carissuenum cardstartdate descrcodes
170             retailterms transflags ) ];
171 0           $optional{CC_newreturn} = [ qw( orderID card-address1 card-address2
172             card-city card-state card-zip card-country
173             notify-email
174             ) ];
175 0           $optional{CC_void} = [ qw( notify-email ) ];
176              
177             #$optional{ECHECK_auth} = $optional{CC_auth}; # ?
178             #$optional{ECHECK_newreturn} = $optional{CC_newreturn}; # ? legal combo?
179             #$optional{ECHECK_void} = $optional{CC_void}; # ? legal combo?
180              
181 0           my $type_action = $self->transaction_type(). '_'. $content{mode};
182 0 0         unless ( exists($required{$type_action}) ) {
183 0           $self->error_message("plugnpay can't handle transaction type: ".
184             "$content{action} on " . $self->transaction_type() );
185 0           $self->is_success(0);
186 0           return;
187             }
188              
189 0           my $expdate_mmyy = $self->expdate_mmyy( $content{"expiration"} );
190              
191 0           $self->_revmap_fields(
192              
193             'publisher-name' => 'login',
194             'publisher-password' => 'password',
195              
196             'card-amount' => 'amount',
197             'card-name' => 'name',
198             'card-address1' => 'address',
199             'card-city' => 'city',
200             'card-state' => 'state',
201             'card-zip' => 'zip',
202             'card-country' => 'country',
203             'card-number' => 'card_number',
204             'card-exp' => \$expdate_mmyy, # MMYY from 'expiration'
205             'card-cvv' => 'cvv2',
206             'order-id' => 'invoice_number',
207             'orderID' => 'order_number',
208              
209              
210             );
211              
212 0           my %shipping_params = ( shipname => (($content{ship_first_name} || '') .
213             ' '. ($content{ship_last_name} || '')),
214             address1 => $content{ship_address},
215 0   0       map { $_ => $content{ "ship_$_" } }
      0        
216             qw ( city state zip country )
217             );
218              
219              
220 0           foreach ( keys ( %shipping_params ) ) {
221 0 0 0       if ($shipping_params{$_} && $shipping_params{$_} =~ /^\s*$/) {
222 0           delete $shipping_params{$_};
223             }
224             }
225 0 0         $shipping_params{shipinfo} = 1 if scalar(keys(%shipping_params));
226              
227 0           my %params = ( $self->get_fields( @{$required{$type_action}},
  0            
228 0           @{$optional{$type_action}},
229             ),
230             (%shipping_params)
231             );
232              
233 0 0         $params{'txn-type'} = 'auth' if $params{mode} eq 'void';
234              
235 0           foreach ( keys ( %{($self->{_defaults})} ) ) {
  0            
236 0 0         $params{$_} = $self->{_defaults}->{$_} unless exists($params{$_});
237             }
238              
239            
240 0           $self->required_fields(@{$required{$type_action}});
  0            
241            
242 0 0         warn join("\n", map{ "$_ => $params{$_}" } keys(%params)) if $DEBUG > 1;
  0            
243 0           my ( $page, $resp, %resp_headers ) =
244             $self->https_post( %params );
245              
246 0           $self->response_code( $resp );
247 0           $self->response_page( $page );
248 0           $self->response_headers( \%resp_headers );
249              
250 0 0         warn "$page\n" if $DEBUG > 1;
251             # $page should contain key/value pairs
252              
253 0           my $status ='';
254 0           my %results = map { s/\s*$//;
  0            
255 0           my ($name, $value) = split '=', $_, 2;
256 0           $name =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0            
257 0           $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  0            
258 0           $name, $value;
259             } split '&', $page;
260              
261             # AVS and CVS values may be set on success or failure
262 0           $self->avs_code( $results{ 'avs-code' } );
263 0           $self->cvv2_response( $results{ cvvresp } );
264 0           $self->result_code( $results{ 'resp-code' } );
265 0           $self->order_number( $results{ orderID } );
266 0           $self->authorization( $results{ 'auth-code' } );
267 0           $self->error_message( $results{ MErrMsg } );
268              
269              
270 0 0 0       if ( $resp =~ /^(HTTP\S+ )?200/
      0        
271             &&($results{ FinalStatus } eq "success" ||
272             $results{ FinalStatus } eq "pending" && $results{ mode } eq 'newreturn'
273             )
274             ) {
275 0           $self->is_success(1);
276             } else {
277 0           $self->is_success(0);
278             }
279             }
280              
281             1;
282              
283             __END__