| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Business::OnlinePayment::Ogone; |
|
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:ESSELENS'; |
|
3
|
6
|
|
|
6
|
|
31900
|
use parent 'Business::OnlinePayment::HTTPS'; |
|
|
6
|
|
|
|
|
2302
|
|
|
|
6
|
|
|
|
|
37
|
|
|
4
|
6
|
|
|
6
|
|
163998
|
use strict; # keep Perl::Critic happy over common::sense; |
|
|
6
|
|
|
|
|
17
|
|
|
|
6
|
|
|
|
|
262
|
|
|
5
|
6
|
|
|
6
|
|
12502
|
use common::sense; |
|
|
6
|
|
|
|
|
80
|
|
|
|
6
|
|
|
|
|
52
|
|
|
6
|
6
|
|
|
6
|
|
483
|
use Carp; |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
514
|
|
|
7
|
6
|
|
|
6
|
|
1612
|
use XML::Simple qw/:strict/; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
use Digest::SHA qw/sha1_hex sha256_hex sha512_hex/; |
|
9
|
|
|
|
|
|
|
use MIME::Base64; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# ABSTRACT: Online payment processing via Ogone |
|
12
|
|
|
|
|
|
|
our $VERSION = 0.2; |
|
13
|
|
|
|
|
|
|
our $API_VERSION = 4.9; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# Ogone config defaults and info ###################################################################################### |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our %defaults = ( |
|
18
|
|
|
|
|
|
|
server => 'secure.ogone.com', |
|
19
|
|
|
|
|
|
|
port => 443, |
|
20
|
|
|
|
|
|
|
); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our %info = ( |
|
23
|
|
|
|
|
|
|
'info_compat' => '0.01', # always 0.01 for now, |
|
24
|
|
|
|
|
|
|
'gateway_name' => 'Ogone', |
|
25
|
|
|
|
|
|
|
'gateway_url' => 'http://www.ogone.com/', |
|
26
|
|
|
|
|
|
|
'module_version' => $VERSION, |
|
27
|
|
|
|
|
|
|
'supported_types' => [ qw( CC ) ], |
|
28
|
|
|
|
|
|
|
'token_support' => 0, #card storage/tokenization support |
|
29
|
|
|
|
|
|
|
'test_transaction' => 1, #set true if ->test_transaction(1) works |
|
30
|
|
|
|
|
|
|
'supported_actions' => [ |
|
31
|
|
|
|
|
|
|
'Authorization Only', |
|
32
|
|
|
|
|
|
|
'Post Authorization', |
|
33
|
|
|
|
|
|
|
'Query', |
|
34
|
|
|
|
|
|
|
'Credit', |
|
35
|
|
|
|
|
|
|
] |
|
36
|
|
|
|
|
|
|
); |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Methods ############################################################################################################# |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub _info { |
|
41
|
|
|
|
|
|
|
return \%info; |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub set_defaults { |
|
45
|
|
|
|
|
|
|
my $self = shift; |
|
46
|
|
|
|
|
|
|
my %data = @_; |
|
47
|
|
|
|
|
|
|
$self->{$_} = $defaults{$_} for keys %defaults; |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
$self->build_subs(qw/http_args result_xml/); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub submit { |
|
54
|
|
|
|
|
|
|
my $self = shift; |
|
55
|
|
|
|
|
|
|
my %data = $self->content(); |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# do not allow submitting same object twice |
|
58
|
|
|
|
|
|
|
croak 'submitting same object twice is not allowed' if $self->{_dirty}; $self->{_dirty} = 1; |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Turn the data into a format usable by the online processor |
|
61
|
|
|
|
|
|
|
croak 'no action parameter defined in content' unless exists $self->{_content}->{action}; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# Default currency to Euro |
|
64
|
|
|
|
|
|
|
$self->{_content}->{currency} ||= 'EUR'; |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
# Table to translate from Business::OnlinePayment::Ogone args to Ogone API args |
|
67
|
|
|
|
|
|
|
# The values of this hash are also used as a list of allowed args for the HTTP POST request, thus preventing information leakage |
|
68
|
|
|
|
|
|
|
my %ogone_api_args = ( |
|
69
|
|
|
|
|
|
|
# credentials |
|
70
|
|
|
|
|
|
|
login => 'USERID', |
|
71
|
|
|
|
|
|
|
password => 'PSWD', |
|
72
|
|
|
|
|
|
|
PSPID => 'PSPID', |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# primary identifier |
|
75
|
|
|
|
|
|
|
invoice_number => 'orderID', |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# transaction identifiers (action = query) |
|
78
|
|
|
|
|
|
|
payid => 'PAYID', |
|
79
|
|
|
|
|
|
|
payidsub => 'PAYIDSUB', |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# credit card data |
|
82
|
|
|
|
|
|
|
card_number => 'CARDNO', |
|
83
|
|
|
|
|
|
|
cvc => 'CVC', |
|
84
|
|
|
|
|
|
|
expiration => 'ED', |
|
85
|
|
|
|
|
|
|
alias => 'ALIAS', |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# financial data |
|
88
|
|
|
|
|
|
|
currency => 'Currency', |
|
89
|
|
|
|
|
|
|
amount => 'amount', |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Ogone specific arguments |
|
92
|
|
|
|
|
|
|
operation => 'Operation', # REN, DEL, DES, SAL, SAS, RFD, RFS |
|
93
|
|
|
|
|
|
|
eci => 'ECI', # defaults 7: e-commerce with ssl (9: recurring e-commerce) |
|
94
|
|
|
|
|
|
|
accepturl => 'accepturl', |
|
95
|
|
|
|
|
|
|
declineurl => 'declineurl', |
|
96
|
|
|
|
|
|
|
exceptionurl => 'exceptionurl', |
|
97
|
|
|
|
|
|
|
paramplus => 'paramplus', |
|
98
|
|
|
|
|
|
|
complus => 'complus', |
|
99
|
|
|
|
|
|
|
language => 'LANGUAGE', |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Business::OnlinePayment common |
|
102
|
|
|
|
|
|
|
description => 'COM', |
|
103
|
|
|
|
|
|
|
name => 'CN', |
|
104
|
|
|
|
|
|
|
email => 'EMAIL', |
|
105
|
|
|
|
|
|
|
address => 'Owneraddress', |
|
106
|
|
|
|
|
|
|
zip => 'OwnerZip', |
|
107
|
|
|
|
|
|
|
city => 'ownertown', |
|
108
|
|
|
|
|
|
|
country => 'ownercty', |
|
109
|
|
|
|
|
|
|
phone => 'ownertelno', |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# client authentication (not used directly, only here as valid HTTP POST arg) |
|
112
|
|
|
|
|
|
|
SHASign => 'SHASign', # see sha_key, sha_type |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# 3d secure arguments |
|
115
|
|
|
|
|
|
|
flag3d => 'FLAG3D', |
|
116
|
|
|
|
|
|
|
win3ds => 'win3ds', |
|
117
|
|
|
|
|
|
|
http_accept => 'HTTP_ACCEPT', |
|
118
|
|
|
|
|
|
|
http_user_agent => 'HTTP_USER_AGENT', |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# recurrent fields |
|
121
|
|
|
|
|
|
|
subscription_id => 'SUBSCRIPTION_ID', |
|
122
|
|
|
|
|
|
|
subscription_orderid => 'SUB_ORDERID', |
|
123
|
|
|
|
|
|
|
subscription_status => 'SUBSCRIPTION_STATUS', |
|
124
|
|
|
|
|
|
|
startdate => 'SUB_STARTDATE', |
|
125
|
|
|
|
|
|
|
enddate => 'SUB_ENDDATE', |
|
126
|
|
|
|
|
|
|
status => 'SUB_STATUS', |
|
127
|
|
|
|
|
|
|
period_unit => 'SUB_PERIOD_UNIT', # 'd', 'ww', 'm' (yes two 'w's) for resp daily weekly monthly |
|
128
|
|
|
|
|
|
|
period_moment => 'SUB_PERIOD_MOMENT', # Integer, the moment in time on which the payment is (0-7 when period_unit is ww, 1-31 for d, 1-12 for m?) |
|
129
|
|
|
|
|
|
|
period_number => 'SUB_PERIOD_NUMBER', |
|
130
|
|
|
|
|
|
|
); |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
# Only allow max of 2 digits after comma as we need to int ( $amount * 100 ) for Ogone |
|
133
|
|
|
|
|
|
|
croak 'max 2 digits after comma (or dot) allowed' if $self->{_content}->{amount} =~ m/[\,\.]\d{3}/; |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Ogone has multiple users per login, defaults to login |
|
136
|
|
|
|
|
|
|
$self->{_content}->{PSPID} ||= $self->{pspid} || $self->{PSPID} || $self->{login} || $self->{_content}->{login}; |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Login information, default to constructor values |
|
139
|
|
|
|
|
|
|
$self->{_content}->{login} ||= $self->{login}; |
|
140
|
|
|
|
|
|
|
$self->{_content}->{password} ||= $self->{password}; |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Default Operation request for authorization (RES) for authorization only, (capture full and close) SAS for post authorization |
|
143
|
|
|
|
|
|
|
$self->{_content}->{operation} ||= 'RES' if $self->{_content}->{action} =~ m/authorization only/; |
|
144
|
|
|
|
|
|
|
$self->{_content}->{operation} ||= 'SAL' if $self->{_content}->{action} =~ m/normal authorization/; |
|
145
|
|
|
|
|
|
|
$self->{_content}->{operation} ||= 'SAS' if $self->{_content}->{action} =~ m/post authorization/; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Default ECI is SSL e-commerce (7) or Recurring with e-commerce (9) if subscription_id exists |
|
148
|
|
|
|
|
|
|
$self->{_content}->{eci} ||= $self->{_content}->{subscription_id} ? 9 : 7; |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Remap the fields to their Ogone-API counterparts ie: cvc => CVC |
|
151
|
|
|
|
|
|
|
$self->remap_fields(%ogone_api_args); |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
croak "no sha_key provided" if $self->{_content}->{sha_type} && ! $self->{_content}->{sha_key}; |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# These fields are required by Businiess::OnlinePayment::Ogone |
|
156
|
|
|
|
|
|
|
my @args_basic = (qw/login password PSPID action/); |
|
157
|
|
|
|
|
|
|
my @args_ccard = (qw/card_number expiration cvc/); |
|
158
|
|
|
|
|
|
|
my @args_alias = (qw/alias cvc/); |
|
159
|
|
|
|
|
|
|
my @args_recur = (@args_basic, qw/name subscription_id subscription_orderid invoice_number amount currency startdate enddate period_unit period_moment period_number/, $self->{_content}->{card_numer} ? @args_ccard : @args_alias ), |
|
160
|
|
|
|
|
|
|
my @args_new = (@args_basic, qw/invoice_number amount currency/, $self->{_content}->{card_number} ? @args_ccard : @args_alias); |
|
161
|
|
|
|
|
|
|
my @args_post = (@args_basic, qw/invoice_number/); |
|
162
|
|
|
|
|
|
|
my @query = (@args_basic, qw/invoice_number/); |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Poor man's given/when |
|
165
|
|
|
|
|
|
|
my %action_arguments = ( |
|
166
|
|
|
|
|
|
|
qr/normal authorization/i => \@args_new, |
|
167
|
|
|
|
|
|
|
qr/authorization only/i => \@args_new, |
|
168
|
|
|
|
|
|
|
qr/post authorization/i => \@args_post, |
|
169
|
|
|
|
|
|
|
qr/query/i => \@query, |
|
170
|
|
|
|
|
|
|
qr/recurrent authorization/i => \@args_recur |
|
171
|
|
|
|
|
|
|
); |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Compile a list of required arguments |
|
174
|
|
|
|
|
|
|
my @args = map { @{$action_arguments{$_}} } # lookup value using regex, return dereffed arrayref |
|
175
|
|
|
|
|
|
|
grep { $self->{_content}->{action} =~ $_ } # compare action input against regex key |
|
176
|
|
|
|
|
|
|
keys %action_arguments; # extract regular expressions |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
croak 'unable to determine HTTP POST @args, is the action parameter one of ( authorization only | normal authorization | post authorization | query | recurrent authorization )' unless @args; |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# Enforce the field requirements by calling parent |
|
181
|
|
|
|
|
|
|
my @undefs = grep { ! defined $self->{_content}->{$_} } @args; |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
croak "missing required args: ". join(',',@undefs) if scalar @undefs; |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Your module should check to see if the require_avs() function returns true, and turn on AVS checking if it does. |
|
186
|
|
|
|
|
|
|
if ( $self->require_avs() ) { |
|
187
|
|
|
|
|
|
|
$self->{_content}->{CHECK_AAV} = 1; |
|
188
|
|
|
|
|
|
|
$self->{_content}->{CAVV_3D} = 1; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# Define all possible arguments for http request |
|
192
|
|
|
|
|
|
|
my @all_http_args = (values %ogone_api_args); |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# Construct the HTTP POST parameters by selecting the ones which are defined from all_http_args |
|
195
|
|
|
|
|
|
|
my %http_req_args = map { $_ => $self->{_content}{$_} } |
|
196
|
|
|
|
|
|
|
grep { defined $self->{_content}{$_} } |
|
197
|
|
|
|
|
|
|
map { $ogone_api_args{$_} || $_ } @all_http_args; |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Ogone accepts the amount as 100 fold in integer form. |
|
200
|
|
|
|
|
|
|
# # Adding 0.5 to amount to prevent "rounding" errors, see http://stackoverflow.com/a/1274692 or perldoc -q round |
|
201
|
|
|
|
|
|
|
$http_req_args{amount} = int(100 * $http_req_args{amount} + 0.5) if exists $http_req_args{amount}; |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Map normal fields to their SUB_ counterparts when recurrent authorization is used |
|
204
|
|
|
|
|
|
|
if($self->{_content}->{action} =~ m/recurrent authorization/) { |
|
205
|
|
|
|
|
|
|
$http_req_args{SUB_COMMENT} = $http_req_args{COM} if exists $http_req_args{COM}; |
|
206
|
|
|
|
|
|
|
$http_req_args{SUB_AMOUNT} = $http_req_args{amount}; |
|
207
|
|
|
|
|
|
|
$http_req_args{SUB_ORDERID} = $http_req_args{orderID}; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# PSPID might be entered in lowercase (as per old documentation) |
|
211
|
|
|
|
|
|
|
$http_req_args{PSPID} = $self->{_content}{pspid} if defined $self->{_content}{pspid}; |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
# Calculate sha1 by default, but has to be enabled in the Ogone backend to have any effect |
|
214
|
|
|
|
|
|
|
my ($sha_type) = ($self->{_content}->{sha_type} =~ m/^(1|256|512)$/); |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# Create a reference to the correct sha${sha_type}_hex function, default to SHA-1 |
|
217
|
|
|
|
|
|
|
my $sha_hex = sub { my $type = shift; no strict; &{"sha".($type || 1)."_hex"}(@_); use strict; }; |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# Algo: make a list of "KEY=value$passphrase" sort alphabetically |
|
220
|
|
|
|
|
|
|
my $signature = join('', |
|
221
|
|
|
|
|
|
|
sort map { uc($_) . "=" . $http_req_args{$_} . ($self->{_content}{sha_key} || '') } |
|
222
|
|
|
|
|
|
|
keys %http_req_args); |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
$http_req_args{SHASign} = $sha_hex->($sha_type,$signature); |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Construct the URL to query, taking into account the action and test_transaction values |
|
227
|
|
|
|
|
|
|
my %action_file = ( |
|
228
|
|
|
|
|
|
|
qr/normal authorization/i => 'orderdirect.asp', |
|
229
|
|
|
|
|
|
|
qr/authorization only/i => 'orderdirect.asp', |
|
230
|
|
|
|
|
|
|
qr/recurrent authorization/i => 'orderdirect.asp', |
|
231
|
|
|
|
|
|
|
qr/post authorization/i => 'maintenancedirect.asp', |
|
232
|
|
|
|
|
|
|
qr/query/i => 'querydirect.asp', |
|
233
|
|
|
|
|
|
|
); |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
my $uri_dir = $self->test_transaction() ? 'test' : 'prod'; |
|
236
|
|
|
|
|
|
|
my ($uri_file) = map { $action_file{$_} } |
|
237
|
|
|
|
|
|
|
grep { $self->{_content}->{action} =~ $_ } |
|
238
|
|
|
|
|
|
|
keys %action_file; |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
croak 'unable to determine URI path, is the action parameter one of ( authorization only | normal authorization | post authorization | query | recueent authorization)' unless $uri_file; |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# Construct the path to be used in https_post |
|
243
|
|
|
|
|
|
|
$self->{path} = '/ncol/'.$uri_dir.'/'.$uri_file; |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Save the http args for later inspection |
|
246
|
|
|
|
|
|
|
$self->http_args(\%http_req_args); |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# Submit the transaction to the processor and collect a response. |
|
249
|
|
|
|
|
|
|
my ($page, $response_code, %reply_headers) = $self->https_post(%http_req_args); |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
# Call server_response() with a copy of the entire unprocessed response |
|
252
|
|
|
|
|
|
|
$self->server_response([$response_code, \%reply_headers, $page]); |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
my $xml = XMLin($page, ForceArray => [], KeyAttr => [] ); |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Store the result xml for later inspection |
|
257
|
|
|
|
|
|
|
$self->result_xml($xml); |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
croak 'Ogone refused SHA digest' if $xml->{NCERRORPLUS} =~ m#^unknown order/1/s#; |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# Call is_success() with either a true or false value, indicating if the transaction was successful or not. |
|
262
|
|
|
|
|
|
|
if ( $response_code =~ m/^200/ ) { |
|
263
|
|
|
|
|
|
|
$self->is_success(0); # defaults to fail |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# croak 'incorrect credentials. WARNING: continuing with bad credentials will block your account s: '.$xml->{STATUS}.'{}'.$xml->{NCERROR} if $xml->{NCERROR} eq '50001119'; |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 46 ) { $self->is_success(1) } # identification required |
|
269
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 5 ) { $self->is_success(1) } # authorization accepted |
|
270
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 9 ) { $self->is_success(1) } # payment accepted |
|
271
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 91 ) { $self->is_success(1) } # partial payment accepted |
|
272
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 61 ) { $self->is_success(1) } # Author. deletion waiting |
|
273
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 2 ) { $self->failure_status('refused') } # authorization refused |
|
274
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 0 && $xml->{NCERROR} eq '50001134' ) { $self->failure_status('declined') } # 3d secure wrong identification |
|
275
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 0 && $xml->{NCERRORPLUS} =~ m/status \(91\)/ ) { |
|
276
|
|
|
|
|
|
|
$self->failure_status('declined'); |
|
277
|
|
|
|
|
|
|
$self->error_message('Operation only allowed on fully completed transactions (status may not be 91)'); } |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
} else { |
|
280
|
|
|
|
|
|
|
warn "remote server did not respond with HTTP 200 status code"; |
|
281
|
|
|
|
|
|
|
$self->is_success(0) |
|
282
|
|
|
|
|
|
|
} |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# Extract the base64 encoded HTML part |
|
285
|
|
|
|
|
|
|
if ( $xml->{STATUS} == 46 ) { |
|
286
|
|
|
|
|
|
|
my $html = decode_base64($xml->{HTML_ANSWER}); |
|
287
|
|
|
|
|
|
|
# remove sillyness |
|
288
|
|
|
|
|
|
|
$html =~ s/ |
|
289
|
|
|
|
|
|
|
//g; |
|
290
|
|
|
|
|
|
|
$html =~ s/ //g; |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# TODO: parse |
|
293
|
|
|
|
|
|
|
#open my $fh, '>', '/tmp/ogone_'.$self->{_content}->{win3ds}.'.html'; |
|
294
|
|
|
|
|
|
|
#print $fh $html; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# Call result_code() with the servers result code |
|
298
|
|
|
|
|
|
|
$self->result_code($xml->{NCERROR}); |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# If the transaction was successful, call authorization() with the authorization code the processor provided. |
|
301
|
|
|
|
|
|
|
if ( $self->is_success() ) { |
|
302
|
|
|
|
|
|
|
$self->authorization($xml->{PAYID}); |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# If the transaction was not successful, call error_message() with either the processor provided error message, or some error message to indicate why it failed. |
|
306
|
|
|
|
|
|
|
if ( not $self->is_success() and $xml->{NCERRORPLUS} ne '!' ) { # '!' == no errorplus |
|
307
|
|
|
|
|
|
|
$self->error_message($xml->{NCERRORPLUS}); |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
42; |
|
312
|
|
|
|
|
|
|
__END__ |