1 package Business::OnlinePayment::viaKLIX;
4 use vars qw($VERSION $DEBUG);
5 use Carp qw(carp croak);
7 use base qw(Business::OnlinePayment::HTTPS);
10 $VERSION = eval $VERSION;
17 my $level = shift || 0;
19 $self->{"__DEBUG"} = $level;
24 $Business::OnlinePayment::HTTPS::DEBUG = $level;
26 return ref($self) ? ( $self->{"__DEBUG"} || $DEBUG ) : $DEBUG;
33 # standard B::OP methods/data
34 $self->server("www.viaKLIX.com");
36 $self->path("/process.asp");
39 order_number avs_code cvv2_response
40 response_page response_code response_headers
43 # module specific data
45 $self->debug( $opts{debug} );
50 foreach my $key (keys %opts) {
51 $key =~ /^default_(\w*)$/ or next;
52 $_defaults{$1} = $opts{$key};
55 $self->{_defaults} = \%_defaults;
62 my %content = $self->content();
66 'normal authorization' => 'SALE', # Authorization/Settle transaction
67 'credit' => 'CREDIT', # Credit (refund)
70 $content{'ssl_transaction_type'} = $actions{ lc( $content{'action'} ) }
71 || $content{'action'};
77 'american express' => 'CC',
82 $content{'type'} = $types{ lc( $content{'type'} ) } || $content{'type'};
84 $self->transaction_type( $content{'type'} );
86 # stuff it back into %content
87 $self->content(%content);
91 my ( $self, %map ) = @_;
92 my %content = $self->content();
93 foreach ( keys %map ) {
97 : $content{ $map{$_} };
99 $self->content(%content);
104 my $expiration = shift;
106 if ( defined($expiration) and $expiration =~ /^(\d+)\D+\d*(\d{2})$/ ) {
107 my ( $month, $year ) = ( $1, $2 );
108 $expdate_mmyy = sprintf( "%02d", $month ) . $year;
110 return defined($expdate_mmyy) ? $expdate_mmyy : $expiration;
113 sub required_fields {
114 my($self,@fields) = @_;
117 my %content = $self->content();
120 if (exists $content{$_} && defined $content{$_} && $content{$_}=~/\S+/);
124 Carp::croak("missing required field(s): " . join(", ", @missing) . "\n")
132 $self->_map_fields();
134 my %content = $self->content;
137 $required{CC_SALE} = [ qw( ssl_transaction_type ssl_merchant_id ssl_pin
138 ssl_amount ssl_card_number ssl_exp_date
140 $required{CC_CREDIT} = $required{CC_SALE};
142 $optional{CC_SALE} = [ qw( ssl_user_id ssl_salestax ssl_cvv2 ssl_cvv2cvc2
143 ssl_description ssl_invoice_number
144 ssl_customer_code ssl_company ssl_first_name
145 ssl_last_name ssl_avs_address ssl_address2
146 ssl_city ssl_state ssl_avs_zip ssl_country
147 ssl_phone ssl_email ssl_ship_to_company
148 ssl_ship_to_first_name ssl_ship_to_last_name
149 ssl_ship_to_address ssl_ship_to_city
150 ssl_ship_to_state ssl_ship_to_zip
153 $optional{CC_CREDIT} = $optional{CC_SALE};
155 my $type_action = $self->transaction_type(). '_'. $content{ssl_transaction_type};
156 unless ( exists($required{$type_action}) ) {
157 $self->error_message("viaKLIX can't handle transaction type: ".
158 "$content{action} on " . $self->transaction_type() );
159 $self->is_success(0);
163 my $expdate_mmyy = $self->expdate_mmyy( $content{"expiration"} );
164 my $zip = $content{'zip'};
165 $zip =~ s/[^[:alnum:]]//g;
167 my $cvv2indicator = 'present' if ( $content{"cvv2"} ); # visa only
169 $self->_revmap_fields(
171 ssl_merchant_id => 'login',
172 ssl_pin => 'password',
174 ssl_amount => 'amount',
175 ssl_card_number => 'card_number',
176 ssl_exp_date => \$expdate_mmyy, # MMYY from 'expiration'
177 ssl_cvv2 => \$cvv2indicator,
178 ssl_cvv2cvc2 => 'cvv2',
179 ssl_description => 'description',
180 ssl_invoice_number => 'invoice_number',
181 ssl_customer_code => 'customer_id',
183 ssl_first_name => 'first_name',
184 ssl_last_name => 'last_name',
185 ssl_avs_address => 'address',
187 ssl_state => 'state',
188 ssl_avs_zip => \$zip, # 'zip' with non-alnums removed
189 ssl_country => 'country',
190 ssl_phone => 'phone',
191 ssl_email => 'email',
195 my %params = $self->get_fields( @{$required{$type_action}},
196 @{$optional{$type_action}},
199 foreach ( keys ( %{($self->{_defaults})} ) ) {
200 $params{$_} = $self->{_defaults}->{$_} unless exists($params{$_});
203 $params{ssl_test_mode}='true' if $self->test_transaction;
205 $params{ssl_show_form}='false';
206 $params{ssl_result_format}='ASCII';
208 $self->required_fields(@{$required{$type_action}});
210 warn join("\n", map{ "$_ => $params{$_}" } keys(%params)) if $DEBUG > 1;
211 my ( $page, $resp, %resp_headers ) =
212 $self->https_post( %params );
214 $self->response_code( $resp );
215 $self->response_page( $page );
216 $self->response_headers( \%resp_headers );
218 warn "$page\n" if $DEBUG > 1;
219 # $page should contain key/value pairs
222 my %results = map { s/\s*$//; split '=', $_, 2 } split '^', $page;
224 # AVS and CVS values may be set on success or failure
225 $self->avs_code( $results{ssl_avs_response} );
226 $self->cvv2_response( $results{ ssl_cvv2_response } );
227 $self->result_code( $status = $results{ ssl_result } );
228 $self->order_number( $results{ ssl_txn_id } );
229 $self->authorization( $results{ ssl_approval_code } );
230 $self->error_message( $results{ ssl_result_message } );
233 if ( $resp =~ /^(HTTP\S+ )?200/ && $status eq "0" ) {
234 $self->is_success(1);
236 $self->is_success(0);
246 Business::OnlinePayment::viaKLIX - viaKLIX backend for Business::OnlinePayment
250 use Business::OnlinePayment;
252 my $tx = new Business::OnlinePayment(
253 'viaKLIX', 'default_ssl_user_id' => 'webuser',
256 # See the module documentation for details of content()
259 action => 'Normal Authorization',
260 description => 'Business::OnlinePayment::viaKLIX test',
262 invoice_number => '100100',
263 customer_id => 'jef',
264 name => 'Jeff Finucane',
265 address => '123 Anystreet',
269 email => 'viaklix@weasellips.com',
270 card_number => '4111111111111111',
271 expiration => '12/09',
273 order_number => 'string',
278 if ( $tx->is_success() ) {
280 "Card processed successfully: ", $tx->authorization, "\n",
281 "order number: ", $tx->order_number, "\n",
282 "CVV2 response: ", $tx->cvv2_response, "\n",
283 "AVS code: ", $tx->avs_code, "\n",
288 "Card was rejected: ", $tx->error_message, "\n",
289 "order number: ", $tx->order_number, "\n",
295 This module is a back end driver that implements the interface
296 specified by L<Business::OnlinePayment> to support payment handling
297 via viaKLIX's Internet payment solution.
299 See L<Business::OnlinePayment> for details on the interface this
302 =head1 Standard methods
308 This method sets the 'server' attribute to 'www.viaklix.com' and
309 the port attribute to '443'. This method also sets up the
310 L</Module specific methods> described below.
316 =head1 Unofficial methods
318 This module provides the following methods which are not officially part of the
319 standard Business::OnlinePayment interface (as of 3.00_06) but are nevertheless
320 supported by multiple gateways modules and expected to be standardized soon:
324 =item L<order_number()|/order_number()>
326 =item L<avs_code()|/avs_code()>
328 =item L<cvv2_response()|/cvv2_response()>
332 =head1 Module specific methods
334 This module provides the following methods which are not currently
335 part of the standard Business::OnlinePayment interface:
339 =item L<expdate_mmyy()|/expdate_mmyy()>
341 =item L<debug()|/debug()>
347 The following default settings exist:
365 =head1 Parameters passed to constructor
367 If any of the key/value pairs passed to the constructor have a key
368 beginning with "default_" then those values are passed to viaKLIX as
369 a the corresponding form field (without the "default_") whenever
370 content(%content) lacks that key.
372 =head1 Handling of content(%content)
374 The following rules apply to content(%content) data:
378 If 'type' matches one of the following keys it is replaced by the
379 right hand side value:
382 'mastercard' => 'CC',
383 'american express' => 'CC',
386 The value of 'type' is used to set transaction_type(). Currently this
387 module only supports the above values.
389 =head1 Setting viaKLIX parameters from content(%content)
391 The following rules are applied to map data to viaKLIX parameters
392 from content(%content):
394 # viaKLIX param => $content{<key>}
395 ssl_merchant_id => 'login',
396 ssl_pin => 'password',
398 ssl_amount => 'amount',
399 ssl_card_number => 'card_number',
400 ssl_exp_date => \( $month.$year ), # MM/YY from 'expiration'
401 ssl_cvv2 => 'present' whenever cvv2 data is provided
402 ssl_cvv2cvc2 => 'cvv2',
403 ssl_description => 'description',
404 ssl_invoice_number=> 'invoice_number',
405 ssl_customer_code => 'customer_id',
407 ssl_first_name => 'first_name',
408 ssl_last_name => 'last_name',
409 ssl_avs_address => 'address',
411 ssl_state => 'state',
412 ssl_zip => \$zip, # 'zip' with non-alphanumerics removed
413 ssl_country => 'country',
414 ssl_phone => 'phone',
415 ssl_email => 'email',
417 CardHolderName => 'name',
418 CustomerName => 'account_name',
421 =head1 Mapping viaKLIX transaction responses to object methods
423 The following methods provides access to the transaction response data
424 resulting from a viaKLIX request (after submit()) is called:
426 =head2 order_number()
428 This order_number() method returns the ssl_txn_id field for card transactions
429 to uniquely identify the transaction.
433 The result_code() method returns the ssl_result field for card transactions.
434 It is the numeric return code indicating the outcome of the attempted
437 =head2 error_message()
439 The error_message() method returns the ssl_result_message field for
440 transactions. This provides more details about the transaction result.
442 =head2 authorization()
444 The authorization() method returns the ssl_approval_code field,
445 which is the approval code obtained from the card processing network.
449 The avs_code() method returns the ssl_avs_response field from the
452 =head2 cvv2_response()
454 The cvv2_response() method returns the ssl_cvvw_response field, which is a
455 response message returned with the transaction result.
457 =head2 expdate_mmyy()
459 The expdate_mmyy() method takes a single scalar argument (typically
460 the value in $content{expiration}) and attempts to parse and format
461 and put the date in MMYY format as required by PayflowPro
462 specification. If unable to parse the expiration date simply leave it
463 as is and let the PayflowPro system attempt to handle it as-is.
467 Enable or disble debugging. The value specified here will also set
468 $Business::OnlinePayment::HTTPS::DEBUG in submit() to aid in
469 troubleshooting problems.
473 This module implements an interface to the viaKLIX API version 2.0
477 Jeff Finucane <viaklix@weasellips.com>
479 Based on Business::OnlinePayment::PayflowPro written by Ivan Kohler
484 perl(1), L<Business::OnlinePayment>, L<Carp>, and the Developer Guide to the
485 viaKLIX Virtual Terminal.