File Coverage

blib/lib/Business/OnlinePayment.pm
Criterion Covered Total %
statement 191 248 77.0
branch 52 90 57.7
condition n/a
subroutine 45 56 80.3
pod 28 33 84.8
total 316 427 74.0


line stmt bran cond sub pod time code
1             package Business::OnlinePayment;
2              
3 6     6   104173 use strict;
  6         12  
  6         180  
4 6     6   32 use vars qw($VERSION %_info_handler);
  6         10  
  6         343  
5 6     6   31 use Carp;
  6         13  
  6         3895  
6              
7             require 5.005;
8              
9             $VERSION = '3.04';
10             $VERSION = eval $VERSION; # modperlstyle: convert the string into a number
11              
12             # Remember subclasses we have "wrapped" submit() with _pre_submit()
13             my %Presubmit_Added = ();
14              
15             my @methods = qw(
16             authorization
17             order_number
18             error_message
19             failure_status
20             fraud_detect
21             is_success
22             partial_auth_amount
23             maximum_risk
24             path
25             port
26             require_avs
27             result_code
28             server
29             server_response
30             test_transaction
31             transaction_type
32             fraud_score
33             fraud_transaction_id
34             response_code
35             response_header
36             response_page
37             avs_code
38             cvv2_response
39             );
40              
41             __PACKAGE__->build_subs(@methods);
42              
43             #fallback
44             sub _info {
45 2     2   3 my $class = shift;
46 2         16 ( my $gw = $class ) =~ s/^Business::OnlinePayment:://;
47             {
48 2         8 'info_compat' => '0.00',
49             'gateway_name' => $gw,
50             'module_notes' => "Module does not yet provide info.",
51             };
52             }
53              
54             #allow classes to declare info in a flexible way, but return normalized info
55             %_info_handler = (
56             'supported_types' => sub {
57             my( $class, $v ) = @_;
58             my $types = ref($v) ? $v : defined($v) ? [ $v ] : [];
59             $types = { map { $_=>1 } @$types } if ref($types) eq 'ARRAY';
60             $types;
61             },
62             'supported_actions' => sub {
63             my( $class, $v ) = @_;
64             return %$v if ref($v) eq 'HASH';
65             $v = [ $v ] unless ref($v);
66             my $types = $class->info('supported_types') || {};
67             ( map { $_ => $v } keys %$types );
68             },
69             );
70              
71             sub info {
72 7     7 0 2510 my $class = shift; #class or object
73 7         30 my $info = $class->_info;
74 7 50       71 if ( @_ ) {
75 7         11 my $key = shift;
76             exists($_info_handler{$key})
77 5         15 ? &{ $_info_handler{$key} }( $class, $info->{$key} )
78 7 100       32 : $info->{$key};
79             } else {
80 0 0       0 wantarray ? ( keys %$info ) : [ keys %$info ];
81             }
82             }
83              
84             sub new {
85 21     21 1 12637 my($class,$processor,%data) = @_;
86              
87 21 100       217 croak("unspecified processor") unless $processor;
88              
89 20         47 my $subclass = "${class}::$processor";
90 20     5   1446 eval "use $subclass";
  5     4   911  
  3     3   5  
  3     2   53  
  4     2   696  
  4     2   10  
  4     1   67  
  3     1   494  
  2     1   4  
  2     1   31  
  2     1   394  
  1     1   2  
  1     1   14  
  2     1   368  
  1         3  
  1         16  
  2         12  
  2         3  
  2         26  
  1         6  
  1         1  
  1         14  
  1         6  
  1         2  
  1         15  
  1         6  
  1         2  
  1         14  
  1         6  
  1         3  
  1         16  
  1         7  
  1         2  
  1         21  
  1         7  
  1         1  
  1         19  
  1         6  
  1         2  
  1         14  
  1         6  
  1         3  
  1         14  
91 20 100       194 croak("unknown processor $processor ($@)") if $@;
92              
93 19         68 my $self = bless {processor => $processor}, $subclass;
94              
95 19 50       148 if($self->can("set_defaults")) {
96 0         0 $self->set_defaults(%data);
97             }
98              
99 19         56 foreach(keys %data) {
100 5         9 my $key = lc($_);
101 5         10 my $value = $data{$_};
102 5         11 $key =~ s/^\-+//;
103 5         20 $self->build_subs($key);
104 5         159 $self->$key($value);
105             }
106              
107             # "wrap" submit with _pre_submit only once
108 19 50       57 unless ( $Presubmit_Added{$subclass} ) {
109 19         102 my $real_submit = $subclass->can('submit');
110              
111 6     6   33 no warnings 'redefine';
  6         12  
  6         243  
112 6     6   28 no strict 'refs';
  6         11  
  6         6829  
113              
114 19         98 *{"${subclass}::submit"} = sub {
115 15     15   2500 my $self = shift;
116 15 50       58 return unless $self->_pre_submit(@_);
117 12         31 return $real_submit->($self, @_);
118             }
119 19         86 }
120              
121 19         65 return $self;
122             }
123              
124             sub _risk_detect {
125 2     2   4 my ($self, $risk_transaction) = @_;
126              
127 2         9 my %parent_content = $self->content();
128 2         5 $parent_content{action} = 'Fraud Detect';
129 2         9 $risk_transaction->content( %parent_content );
130 2         8 $risk_transaction->submit();
131 0 0       0 if ($risk_transaction->is_success()) {
132 0         0 $self->fraud_score( $risk_transaction->fraud_score );
133 0         0 $self->fraud_transaction_id( $risk_transaction->fraud_transaction_id );
134 0 0       0 if ( $risk_transaction->fraud_score <= $self->maximum_fraud_score()) {
135 0         0 return 1;
136             } else {
137 0         0 $self->error_message('Excessive risk from risk management');
138             }
139             } else {
140 0         0 $self->error_message('Error in risk detection stage: ' . $risk_transaction->error_message);
141             }
142 0         0 $self->is_success(0);
143 0         0 return 0;
144             }
145              
146             my @Fraud_Class_Path = qw(Business::OnlinePayment Business::FraudDetect);
147              
148             sub _pre_submit {
149 15     15   25 my ($self) = @_;
150 15         475 my $fraud_detection = $self->fraud_detect();
151              
152             # early return if user does not want optional risk mgt
153 15 100       53 return 1 unless $fraud_detection;
154              
155             # Search for an appropriate FD module
156 3         8 foreach my $fraud_class ( @Fraud_Class_Path ) {
157 6         13 my $subclass = $fraud_class . "::" . $fraud_detection;
158 6         354 eval "use $subclass ()";
159 6 100       37 if ($@) {
160 4 50       24 croak("error loading fraud_detection module ($@)")
161             unless ( $@ =~ m/^Can\'t locate/ );
162             } else {
163 2         10 my $risk_tx = bless( { processor => $fraud_detection }, $subclass );
164 2 50       19 if ($risk_tx->can('set_defaults')) {
165 2         7 $risk_tx->set_defaults();
166             }
167 2         7 $risk_tx->_glean_parameters_from_parent($self);
168 2         10 return $self->_risk_detect($risk_tx);
169             }
170             }
171 1         118 croak("Unable to locate fraud_detection module $fraud_detection"
172             . " in \@INC under Fraud_Class_Path (\@Fraud_Class_Path"
173             . " contains: @Fraud_Class_Path) (\@INC contains: @INC)");
174             }
175              
176             sub content {
177 20     20 1 3121 my($self,%params) = @_;
178              
179 20 100       51 if(%params) {
180 7 100       19 if($params{'type'}) { $self->transaction_type($params{'type'}); }
  1         37  
181 7         14 %{$self->{'_content'}} = %params;
  7         43  
182             }
183 20 100       65 return exists $self->{'_content'} ? %{$self->{'_content'}} : ();
  15         68  
184             }
185              
186             sub required_fields {
187 4     4 1 1030 my($self,@fields) = @_;
188              
189 4         7 my @missing;
190 4         13 my %content = $self->content();
191 4         11 foreach(@fields) {
192 23 50       60 push(@missing, $_) unless exists $content{$_};
193             }
194              
195 4 100       535 croak("missing required field(s): " . join(", ", @missing) . "\n")
196             if(@missing);
197             }
198              
199             sub get_fields {
200 2     2 1 15 my($self, @fields) = @_;
201              
202 2         7 my %content = $self->content();
203              
204             #my %new = ();
205             #foreach(@fields) { $new{$_} = $content{$_}; }
206             #return %new;
207 2         8 map { $_ => $content{$_} } grep defined $content{$_}, @fields;
  4         17  
208             }
209              
210             sub remap_fields {
211 1     1 1 14 my($self,%map) = @_;
212              
213 1         7 my %content = $self->content();
214 1         5 foreach( keys %map ) {
215 2         6 $content{$map{$_}} = $content{$_};
216             }
217 1         5 $self->content(%content);
218             }
219              
220             sub submit {
221 1     1 1 3 my($self) = @_;
222              
223 1         170 croak("Processor subclass did not override submit function");
224             }
225              
226             sub dump_contents {
227 0     0 1 0 my($self) = @_;
228              
229 0         0 my %content = $self->content();
230 0         0 my $dump = "";
231 0         0 foreach(sort keys %content) {
232 0         0 $dump .= "$_ = $content{$_}\n";
233             }
234 0         0 return $dump;
235             }
236              
237             # didnt use AUTOLOAD because Net::SSLeay::AUTOLOAD passes right to
238             # AutoLoader::AUTOLOAD, instead of passing up the chain
239             sub build_subs {
240 14     14 1 1021 my $self = shift;
241              
242 14         38 foreach(@_) {
243 163 100       1140 next if($self->can($_));
244 152 100   2 1 8933 eval "sub $_ { my \$self = shift; if(\@_) { \$self->{$_} = shift; } return \$self->{$_}; }";
  2 0   0 1 1565  
  2 50   2 1 9  
  1 0   0 1 3  
  2 0   0 1 9  
  0 100   20 0 0  
  0 0   0 1 0  
  0 0   0 1 0  
  0 0   0 1 0  
  2 100   4 0 4  
  2 100   2 1 6  
  2 100   2 1 6  
  2 100   4 1 5  
  0 50   2 1 0  
  0 100   5 1 0  
  0 100   4 1 0  
  0 100   4 0 0  
  0 0   0 1 0  
  0 0   0 1 0  
  0 50   2 1 0  
  0 0   0 0 0  
  20 100   2 1 1005  
  20 100   3 1 58  
  3         13  
  20         75  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  4         2161  
  4         13  
  2         8  
  4         22  
  2         3  
  2         7  
  1         2  
  2         9  
  2         4  
  2         6  
  1         6  
  2         8  
  4         9  
  4         14  
  3         8  
  4         12  
  2         5  
  2         6  
  2         5  
  2         6  
  5         8  
  5         14  
  3         10  
  5         17  
  4         8  
  4         7  
  2         5  
  4         10  
  4         8  
  4         15  
  2         6  
  4         14  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  2         4  
  2         7  
  2         9  
  2         6  
  0         0  
  0         0  
  0         0  
  0         0  
  2         71  
  2         6  
  1         5  
  2         9  
  3         7  
  3         9  
  1         3  
  3         11  
245             }
246             }
247              
248             #helper method
249              
250             sub silly_bool {
251 0     0 1 0 my( $self, $value ) = @_;
252 0 0       0 return 1 if $value =~ /^[yt]/i;
253 0 0       0 return 0 if $value =~ /^[fn]/i;
254             #return 1 if $value == 1;
255             #return 0 if $value == 0;
256 0         0 $value; #die??
257             }
258              
259             1;
260              
261             __END__