File Coverage

blib/lib/Business/OnlinePayment.pm
Criterion Covered Total %
statement 191 252 75.7
branch 52 92 56.5
condition n/a
subroutine 45 57 78.9
pod 29 34 85.2
total 317 435 72.8


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