X-Git-Url: http://git.freeside.biz/gitweb/?p=Business-OnlinePayment-vSecureProcessing.git;a=blobdiff_plain;f=lib%2FBusiness%2FOnlinePayment%2FvSecureProcessing.pm;h=0ae9adc5782c1cac0e996e8b6311fd08d2542b3c;hp=872e4cacf8d01041cb697f65276858dc63ea8129;hb=1dfeb8c498824e8a4164edac87546bcecdeb40ff;hpb=59dc9c0128f8c9258c9ec80f11754dd1e7ecf26e diff --git a/lib/Business/OnlinePayment/vSecureProcessing.pm b/lib/Business/OnlinePayment/vSecureProcessing.pm index 872e4ca..0ae9adc 100644 --- a/lib/Business/OnlinePayment/vSecureProcessing.pm +++ b/lib/Business/OnlinePayment/vSecureProcessing.pm @@ -1,20 +1,17 @@ package Business::OnlinePayment::vSecureProcessing; use strict; +use vars qw($VERSION $DEBUG @ISA); use Carp; use XML::Writer; use XML::Simple; use Data::Dumper; - use Business::OnlinePayment; use Business::OnlinePayment::HTTPS; -#use Net::SSLeay qw(post_http post_https make_headers make_form); -use vars qw($VERSION $DEBUG @ISA $me); @ISA = qw(Business::OnlinePayment::HTTPS); -$DEBUG = 3; -$VERSION = '0.01'; -$me = 'Business::OnlinePayment::vSecureProcessing'; +$DEBUG = 0; +$VERSION = '0.05'; # mapping out all possible endpoints # but this version will only be building out "charge", "void", & "credit" @@ -22,17 +19,27 @@ my %payment_actions = ( 'charge' => { path => '/vsg2/processpayment', process => 'ProcessPayment', - fields => [qw/ Amount Trk1 Trk2 TypeOfSale Cf1 Cf2 Cf AccountNumber ExpirationMonth ExpirationYear Cvv CardHolderFirstName CardHolderLastName AvsZip AvsStreet IndustryType ApplicationId Recurring /] + fields => [qw/ + Amount Trk1 Trk2 TypeOfSale Cf1 Cf2 Cf AccountNumber + ExpirationMonth ExpirationYear Cvv + CardHolderFirstName CardHolderLastName AvsZip AvsStreet + IndustryType ApplicationId Recurring + /], }, 'void' => { path => '/vsg2/processvoid', process => 'ProcessVoid', - fields => [qw( Amount AccountNumber ExpirationMonth ExpirationYear ReferenceNumber TransactionDate IndustryType ApplicationId )] + fields => [qw( + Amount AccountNumber ExpirationMonth ExpirationYear ReferenceNumber + TransactionDate IndustryType ApplicationId + )], }, 'refund' => { path => '/vsg2/processrefund', process => 'ProcessRefund', - fields => [qw( Amount AccountNumber ExpirationMonth ExpirationYear ApplicationId )] + fields => [qw( + Amount AccountNumber ExpirationMonth ExpirationYear ApplicationId + )], }, 'authorize' => { path => '/vsg2/processauth', @@ -80,27 +87,23 @@ sub set_defaults { result_code error_message server - port path server_response/; # B::OP creates the following accessors: - # server, port, path, test_transaction, transaction_type, + # server, path, test_transaction, transaction_type, # server_response, is_success, authorization, # result_code, error_message, $self->build_subs(qw/ - env platform userid gid tid appid action reference_number cvv_response - avs_response risk_score txn_amount txn_date response_code + platform tid appid + action reference_number cvv2_response avs_code response_code + risk_score txn_amount txn_date /); $DEBUG = exists($options{debug}) ? $options{debug} : $DEBUG; - - - $self->server($options{'server'}); - - $self->gid($options{'gid'}); + $self->server('svr1.vsecureprocessing.com'); $self->tid($options{'tid'}); @@ -108,13 +111,10 @@ sub set_defaults { $self->appid($options{'appid'}); - $self->env((defined($options{'env'})) ? $options{'env'} : 'live'); # 'live'/'test' - $self->port(443); + } - - sub clean_content { my ($self,$content) = @_; my %content = $self->content(); @@ -134,13 +134,19 @@ sub clean_content { # separate month and year values for expiry_date if ( $content{expiration} ) { - ($content{exp_month}, $content{exp_year}) = split /\//, $content{expiration}; + ($content{exp_month}, $content{exp_year}) = + split /\//, $content{expiration}; $content{exp_month} = sprintf "%02d", $content{exp_month}; - $content{exp_year} = substr($content{exp_year},0,2) if ($content{exp_year} > 99); + $content{exp_year} = substr($content{exp_year},0,2) + if ($content{exp_year} > 99); } - if (!$content{'first_name'} || !$content{'last_name'} && $content{'name'}) { - ($content{'first_name'}, $content{'last_name'}) = split(' ', $content{'name'}, 2); + if ( !$content{'first_name'} + || !$content{'last_name'} && $content{'name'} + ) + { + ($content{'first_name'}, $content{'last_name'}) = + split(' ', $content{'name'}, 2); } if ($content{'address'} =~ m/[\D ]*(\d+)\D/) { @@ -155,7 +161,10 @@ sub process_content { my $self = shift; $self->clean_content(); my %content = $self->content(); - $self->action(($action_mapping{lc $content{'action'}}) ? $action_mapping{lc $content{'action'}} : lc $content{'action'}); + $self->action( ($action_mapping{lc $content{'action'}}) + ? $action_mapping{lc $content{'action'}} + : lc $content{'action'} + ); $self->path($payment_actions{ $self->action }{path}) unless length($self->path); $self->appid($content{appid}) if (!$self->appid && $content{appid}); @@ -175,6 +184,10 @@ sub submit { $self->process_content(); my %content = $self->content; my $action = $self->action(); + + if ( $self->test_transaction ) { + $self->server('dvrotsos2.kattare.com'); + } my @acceptable_actions = ('charge', 'refund', 'void'); @@ -186,9 +199,9 @@ sub submit { my $xml_vars = { auth => { Platform => $self->platform, - UserId => $self->userid, - GID => $self->gid, - Tid => $self->tid + UserId => $content{'login'}, + GID => $content{'password'}, + Tid => $self->tid || '01', }, payment => { @@ -224,11 +237,14 @@ sub submit { # create the list of required fields based on the action my @required_fields = qw/ Amount /; if ($action eq 'charge') { - push(@required_fields, $_) foreach (qw/ AccountNumber Cvv ExpirationMonth ExpirationYear /); + push @required_fields, $_ + foreach (qw/ AccountNumber ExpirationMonth ExpirationYear /); }elsif ($action eq 'void') { - push(@required_fields, $_) foreach (qw/ ReferenceNumber /); + push @required_fields, $_ + foreach (qw/ ReferenceNumber /); }elsif ($action eq 'refund') { - push(@required_fields, $_) foreach (qw/ Amount AccountNumber ExpirationMonth ExpirationYear /); + push @required_fields, $_ + foreach (qw/ Amount AccountNumber ExpirationMonth ExpirationYear /); } # check the requirements are met. @@ -245,10 +261,10 @@ sub submit { $process_action = 'Process'.$process_action; my $xml_data; my $writer = new XML::Writer( OUTPUT => \$xml_data, - DATA_MODE => 0, - DATA_INDENT => 0, - ENCODING => 'utf-8', - ); + DATA_MODE => 0, + DATA_INDENT => 0, + ENCODING => 'utf-8', + ); $writer->xmlDecl(); $writer->startTag('Request'); $writer->startTag('MerchantData'); @@ -264,7 +280,7 @@ sub submit { }else { $writer->startTag($key); foreach my $key2 (keys %{$xml_vars->{payment}{$key}}) { - $writer->dataElement( $key2, $xml_vars->{payment}{$key}{$key2} ); + $writer->dataElement( $key2, $xml_vars->{payment}{$key}{$key2} ); } $writer->endTag($key); } @@ -291,7 +307,8 @@ sub submit { # conform to RFC standards $content =~ s/\n/\r\n/gs; - my ( $page, $server_response, %headers ) = $self->https_post( $opts, $content ); + my ( $page, $server_response, %headers ) = + $self->https_post( $opts, $content ); # store the server response. $self->server_response($server_response); @@ -300,9 +317,7 @@ sub submit { if (!$self->is_success() && !$self->error_message() ) { if ( $DEBUG ) { - #additional logging information, possibly too sensitive for an error msg - # (vSecureProcessing seems to have a failure mode where they return the full - # original request including card number) + #additional logging information, possibly too sensitive for an error $self->error_message( "(HTTPS response: ".$server_response.") ". "(HTTPS headers: ". @@ -331,8 +346,14 @@ sub parse_response { warn "Response:\n".Dumper($response)."\n" if $DEBUG > 2; $self->result_code($response->{Status}); # 0 /1 $self->response_code($response->{ResponseCode}); # see documentation for translation - $self->avs_response($response->{AvsResponse}); # Y / N - $self->cvv_response($response->{CvvResponse}); # P / F + $self->avs_code($response->{AvsResponse}); # Y / N + + #weird (missing?) gateway responses turn into a hashref screwing up Card Fortress + $self->cvv2_response( $response->{CvvResponse} =~ /^\w$/ + ? $response->{CvvResponse} + : '' + ); + $self->txn_date($response->{TransactionDate}); # MMDDhhmmss $self->txn_amount($response->{TransactionAmount} / 100); # 00000003500 / 100 $self->reference_number($response->{ReferenceNumber}); @@ -348,9 +369,8 @@ sub parse_response { $self->error_message('Error '.$response->{ResponseCode}.': '.(exists($response->{Receipt})) ? $response->{Receipt} : ''); } - }else { - $self->is_success(0); - $self->error_message('Error communicating with vSecureProcessing server'); + } else { + die 'Error communicating with vSecureProcessing server'; return; } @@ -368,17 +388,17 @@ Business::OnlinePayment::vSecureProcessing - vSecureProcessing backend for Busin use Business::OnlinePayment; my %processor_info = ( - platform => '####', - gid => 12345678901234567890, - tid => 01, - user_id => '####', - url => 'www.####.com' + platform => 'vsecure_platform', + appid => 'vsecure_appid', + tid => '54', #optional, defaults to 01 ); my $tx = new Business::OnlinePayment( "vSecureProcessing", %processor_info); $tx->content( - appid => '######', - type => 'VISA', + login => 'vsecure@user.id', + password => '12345678901234567890', #vsecure gid + + type => 'CC', action => 'Normal Authorization', description => 'Business::OnlinePayment test', amount => '49.95', @@ -455,7 +475,8 @@ from content(%content): =head1 COMPATIBILITY -Business::OnlinePayment::vSecureProcessing uses vSecureProcessing XML Document Version: 140901 (September 1, 2014). +Business::OnlinePayment::vSecureProcessing uses vSecureProcessing XML Document +Version: 140901 (September 1, 2014). See http://www.vsecureprocessing.com/ for more information. @@ -463,7 +484,7 @@ See http://www.vsecureprocessing.com/ for more information. Original author: Alex Brelsfoard -Current maintainer: Alex Brelsfoard +Current maintainer: Ivan Kohler =head1 COPYRIGHT @@ -489,4 +510,3 @@ perl(1). L. =cut -