## Business::OnlinePayment::Skipjack ## ## Original Skipjack.pm developed by New York Connect Net (http://nyct.net) ## Michael Bacarella ## ## Modified for GetCareer.com by Slipstream.com ## Troy Davis ## ## 'Adapted' (completely rewritten) for Business::OnlinePayment ## by Fire2Wire Internet Services (http://www.fire2wire.com) ## Mark Wells ## Kristian Hoffmann ## James Switzer ## Required packages: ## Net::SSLeay ## Text::CSV ## Business::OnlinePayment package Business::OnlinePayment::Skipjack; use strict; use Business::OnlinePayment; use Net::SSLeay qw(post_https make_form); use Text::CSV; use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION); $VERSION="0.1.1"; require Exporter; @ISA = qw(Exporter AutoLoader Business::OnlinePayment); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT = qw(); @EXPORT_OK = qw(); my %CC_ERRORS = ( '-1' => 'Invalid length (-1)', '-35' => 'Invalid credit card number (-35)', '-37' => 'Failed communication (-37)', '-39' => 'Serial number is too short (-39)', '-51' => 'The zip code is invalid', '-52' => 'The shipto zip code is invalid', '-53' => 'Length of expiration date (-53)', '-54' => 'Length of account number date (-54)', '-55' => 'Length of street address (-55)', '-56' => 'Length of shipto street address (-56)', '-57' => 'Length of transaction amount (-57)', '-58' => 'Length of name (-58)', '-59' => 'Length of location (-59)', '-60' => 'Length of state (-60)', '-61' => 'Length of shipto state (-61)', '-62' => 'Length of order string (-62)', '-64' => 'Invalid phone number (-64)', '-65' => 'Empty name (-65)', '-66' => 'Empty email (-66)', '-67' => 'Empty street address (-66)', '-68' => 'Empty city (-68)', '-69' => 'Empty state (-69)', '-70' => 'Empty zip code (-70)', '-71' => 'Empty order number (-71)', '-72' => 'Empty account number (-72)', '-73' => 'Empty expiration month (-73)', '-74' => 'Empty expiration year (-74)', '-75' => 'Empty serial number (-75)', '-76' => 'Empty transaction amount (-76)', '-79' => 'Length of customer name (-79)', '-80' => 'Length of shipto customer name (-80)', '-81' => 'Length of customer location (-81)', '-82' => 'Length of customer state (-82)', '-83' => 'Length of shipto phone (-83)', '-84' => 'Pos Error duplicate ordernumber (-84)', '-91' => 'Pos Error CVV2 (-91)', '-92' => 'Pos Error Approval Code (-92)', '-93' => 'Pos Error Blind Credits Not Allowed (-93)', '-94' => 'Pos Error Blind Credits Failed (-94)', '-95' => 'Pos Error Voice Authorizations Not Allowed (-95)', ); my %AVS_CODES = ( 'X' => 'Exact match, 9 digit zip', 'Y' => 'Exact match, 5 digit zip', 'A' => 'Address match only', 'W' => '9 digit match only', 'Z' => '5 digit match only', 'N' => 'No address or zip match', 'U' => 'Address unavailable', 'R' => 'Issuer system unavailable', 'E' => 'Not a mail/phone order', 'S' => 'Service not supported' ); my %FIELDS = ( name => 'sjname', email => 'Email', address => 'Streetaddress', city => 'City', state => 'State', zip => 'Zipcode', invoice_number => 'Ordernumber', card_number => 'Accountnumber', exp_month => 'Month', exp_year => 'Year', amount => 'Transactionamount', orderstring => 'Orderstring', phone => 'Shiptophone', login => 'Serialnumber', ); sub _gen_ordernum { return int(rand(4000000000)); } sub set_defaults { my $self = shift; # For production $self->server('www.skipjackic.com'); $self->path('/scripts/evolvcc.dll?AuthorizeAPI'); # For auth testing #$self->server('developer.skipjackic.com'); # test mode #$self->path('/scripts/evolvcc.dll?AuthorizeAPI'); # For comms testing #$self->server('www.skipjackic.com'); #$self->path('/secure/echo.asp'); $self->port(443); return; } sub submit { my $self = shift; my %c = $self->content; my (%input, %output); my ($page, $response, %reply_headers); # if($c{type} and $c{type} ne 'normal authorization') { if($c{type} eq 'credit') { warn 'Business::OnlinePayment::Skipjack does not support "' . $c{type}. '"transactions'; return; } # FIXME! # This should be set from %processor_info. # Or, if we want, from $c{login}. $c{expiration} =~ /(\d\d?)\D*(\d\d?)/; # Slightly less crude way to extract the exp date. $c{exp_month} = sprintf('%02d',$1); $c{exp_year} = sprintf('%02d',$2); $c{invoice_number} = _gen_ordernum unless $c{invoice_number}; $c{orderstring} = '0~'.$c{description}.'~'.$c{amount}.'~1~N~||' unless $c{orderstring}; %input = map { ($FIELDS{$_} || $_), $c{$_} } keys(%c); ($page, $response, %reply_headers) = post_https($self->server, $self->port, $self->path, '', make_form(%input)); %output = parse_Authorize_API($page); $self->{_result} = \%output; $self->authorization($output{'AUTHCODE'}); return; } sub is_success { my $self = shift; return ($self->{_result}->{'szIsApproved'} == 1); } sub error_message { my $self = shift; my $r; if($self->is_success) { return ''; } if(($r = $self->{_result}->{'szReturnCode'}) < 0) { return $CC_ERRORS{$r}; } if($r = $self->{_result}->{'szAVSResponseMessage'}) { return $r; } if($r = $self->{_result}->{'szAuthorizationDeclinedMessage'}) { return $r; } } sub parse_Authorize_API { my $page = shift; my %output; my $csv_keys = new Text::CSV; my $csv_values = new Text::CSV; my ($keystring, $valuestring) = split(/\r\n/, $page); $csv_keys->parse($keystring); $csv_values->parse($valuestring); @output{$csv_keys->fields()} = $csv_values->fields(); return %output; } __END__ 1;