File Coverage

blib/lib/Business/OnlinePayment.pm
Criterion Covered Total %
statement 187 244 76.6
branch 51 88 57.9
condition n/a
subroutine 44 55 80.0
pod 27 32 84.3
total 309 419 73.7


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