[ic] Skip Skipjack?

Matthew Schick interchange-users@interchange.redhat.com
Sat Feb 9 22:37:01 2002


--=-yMvq6mbzEY2LWvhOoJu+
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

On Fri, 2002-02-08 at 11:22, Michael Stearne wrote:
    Kari Suomela wrote:
    > Has someone actually been able to get 4.8.3 working with Skipjack? 
    > We've now fiddled with it and investigated for a couple of weeks, and 
    > received nothing but contradicting instructions. We would pay someone, 
    > if they can get it working.
    
    Maybe buy the support license from RedHat and get them to get it to work 
    for you.  No one has seemed to have had any luck with 4.8.2/3.
<snip>

    
I've attached a working Skipjack.pm.  The one that ships with 8.2/3
doesn't work correctly.  It's been a while since I played with this, so
I don't remember the exact errors, but I believe it had to do with an
incorrect post url...  I hope to have some time this weekend to fix this
up and have a diff to post, but until then....

Matt
    
    

    
    



--=-yMvq6mbzEY2LWvhOoJu+
Content-Disposition: attachment; filename=Skipjack.pm
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1

# Vend::Payment::Skipjack - Interchange Skipjack support
#
# $Id: Skipjack.pm,v 2.0 2001/07/18 02:23:16 jon Exp $
#
# Copyright (C) 1999-2001 Red Hat, Inc. <interchange@redhat.com>
#
# Written by Cameron Prince <cprince@redhat.com> and
# Mark Johnson <markj@redhat.com>,
# based on code by Mike Heins <mheins@redhat.com>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA  02111-1307  USA.

package Vend::Payment::Skipjack;

=3Dhead1 Interchange Skipjack Support

Vend::Payment::Skipjack $Revision: 2.0 $

=3Dhead1 SYNOPSIS

    &charge=3Dskipjack

        or

    [charge mode=3Dskipjack param1=3Dvalue1 param2=3Dvalue2]

=3Dhead1 PREREQUISITES

  Net::SSLeay
=20
    or
 =20
  LWP::UserAgent and Crypt::SSLeay

Only one of these need be present and working.

=3Dhead1 DESCRIPTION

The Vend::Payment::Skipjack module implements the skipjack() routine for us=
ing
Skipjack IC payment services with Interchange. It is compatible on a call l=
evel
with the other Interchange payment modules -- in theory (and even usually i=
n
practice) you could switch from CyberCash to Skipjack with a few configurat=
ion
file changes.

To enable this module, place this directive in C<interchange.cfg>:

    Require module Vend::Payment::Skipjack

This I<must> be in interchange.cfg or a file included from it.

NOTE: Make sure CreditCardAuto is off (default in Interchange demos).

The mode can be named anything, but the C<gateway> parameter must be set
to C<skipjack>. To make it the default payment gateway for all credit
card transactions in a specific catalog, you can set in C<catalog.cfg>:

    Variable   MV_PAYMENT_MODE  skipjack

It uses several of the standard settings from Interchange payment. Any time
we speak of a setting, it is obtained either first from the tag/call option=
s,
then from an Interchange order Route named for the mode, then finally a
default global payment variable, For example, the C<id> parameter would
be specified by:

    [charge mode=3Dskipjack id=3DYourSkipjackID]

or

    Route skipjack id YourSkipjackID

or with only Skipjack as a payment provider

    Variable MV_PAYMENT_ID      YourskipjackID

A fully valid catalog.cfg entry to work with the standard demo would be:

    Variable MV_PAYMENT_MODE      skipjack
    Route skipjack id             YourSkipjackID
    Route skipjack vendor         YourSkipjackVendor

The active settings are:

=3Dover 4

=3Ditem id

Your account ID number, supplied by Skipjack when you sign up.
Global parameter is MV_PAYMENT_ID.

=3Ditem vendor

The developer ID of the system which interfaces with Skipjack.
Global parameter is MV_PAYMENT_VENDOR.

=3Ditem transaction

The type of transaction to be run. Valid values are:

    Interchange         Skipjack
    ----------------    -----------------
	sale                sale
	recurring           recurring

Default is C<sale>.

If you wish to do a recurring charge, you will have to ensure that the
following Interchange values are set properly:

	Interchange variable     Skipjack variable
	--------------------     -----------------
	recurring_item           rtItemNumber
	recurring_desc           rtItemDescription
	recurring_start_date     rtStartingDate
	recurring_frequency      rtFrequency
	recurring_transactions   rtTotalTransactions
	recurring_comment        rtComment

=3Ditem test

If you set the C<test> parameter, Interchange will remap some values and
the URL for the transaction to point to the Skipjack test server.
It will return a valid transaction if all is working.

=3Ditem generate_error

To generate errors in test mode only, set the parameter C<generate_error>
to one of the following values (error it generates in parenthesese):

	number   (invalid credit card number)
	avs      (will succeed, but generate AVS message)
	exp      (expired card)
	id       (invalid Skipjack account?)
	vendor   (invalid vendor?)

=3Dback

The following should rarely be used, as the supplied defaults are
usually correct.

=3Dover 4

=3Ditem remap

This remaps the form variable names to the ones needed by Skipjack. See
the C<Payment Settings> heading in the Interchange documentation for use.

=3Ditem submit_url

The Skipjack URL to submit to. Default is:

	https://www.skipjackic.com/scripts/evolvcc.dll?Authorize

=3Dback

=3Dhead2 Troubleshooting

Try the instructions above, then enable test mode:

	Route skipjack  test           1

A test order should complete.

Then set a generate error

	Route skipjack  test           1
	Route skipjack  generate_error number

and try a sale. The sale should be denied, and the reason should
be in [data session payment_error].

If nothing works:

=3Dover 4

=3Ditem *

Make sure you "Require"d the module in interchange.cfg:

    Require module Vend::Payment::iTransact

=3Ditem *

Make sure either Net::SSLeay or Crypt::SSLeay and LWP::UserAgent are instal=
led
and working. You can test to see whether your Perl thinks they are:

    perl -MNet::SSLeay -e 'print "It works\n"'

or

    perl -MLWP::UserAgent -MCrypt::SSLeay -e 'print "It works\n"'

If either one prints "It works." and returns to the prompt you should be OK
(presuming they are in working order otherwise).

=3Ditem *

Check the error logs, both catalog and global.

=3Ditem *

Make sure you set your account ID properly. =20

=3Ditem *

Try an order, then put this code in a page:

    <XMP>
    [calc]
        my $string =3D $Tag->uneval( { ref =3D> $Session->{payment_result} =
});
        $string =3D~ s/{/{\n/;
        $string =3D~ s/,/,\n/g;
        return $string;
    [/calc]
    </XMP>

That should show what happened.

=3Ditem *

If all else fails, Red Hat and other consultants are available to help
with integration for a fee.

=3Dback

=3Dhead1 BUGS

There is actually nothing *in* Vend::Payment::Skipjack. It changes packages
to Vend::Payment and places things there.

=3Dhead1 AUTHORS

Originally developed by New York Connect Net (http://nyct.net)
Michael Bacarella <mbac@nyct.net>

Modified for GetCareer.com by Slipstream.com by Troy Davis <troy@slipstream=
.com>

LWP/Crypt::SSLeay interface code by Matthew Schick,
<mschick@brightredproductions.com>.

Interchange implementation by Mike Heins, <mheins@redhat.com>.

=3Dcut

BEGIN {

	my $selected;
	eval {
		package Vend::Payment;
		require Net::SSLeay;
		import Net::SSLeay qw(post_https make_form make_headers);
		$selected =3D "Net::SSLeay";
	};

	$Vend::Payment::Have_Net_SSLeay =3D 1 unless $@;

	unless ($Vend::Payment::Have_Net_SSLeay) {

		eval {
			package Vend::Payment;
			require LWP::UserAgent;
			require HTTP::Request::Common;
			require Crypt::SSLeay;
			import HTTP::Request::Common qw(POST);
			$selected =3D "LWP and Crypt::SSLeay";
		};

		$Vend::Payment::Have_LWP =3D 1 unless $@;

	}

	unless ($Vend::Payment::Have_Net_SSLeay or $Vend::Payment::Have_LWP) {
		die __PACKAGE__ . " requires Net::SSLeay or Crypt::SSLeay";
	}

	::logGlobal("%s payment module initialized, using %s", __PACKAGE__, $selec=
ted)
		unless $Vend::Quiet;

}

package Vend::Payment;

use vars qw/%SJ_ERRORS %SJ_AVS_CODES %SJ_RT_FREQ %SJ_RC_ERRORS/;
use vars qw/$Have_LWP $Have_Net_SSLeay/;

%SJ_ERRORS =3D (
        '1'    =3D>      'Authorization failed, card declined (1)',
        '-1'    =3D>      'Invalid length (-1)',
        '-35'   =3D>      'Invalid credit card number (-35)',
        '-37'   =3D>      'Failed communication (-37)',
        '-39'   =3D>      'Serial number is too short (-39)',
        '-51'   =3D>      'The zip code is invalid',
        '-52'   =3D>      'The shipto zip code is invalid',
        '-53'   =3D>      'Length of expiration date (-53)',
        '-54'   =3D>      'Length of account number date (-54)',
        '-55'   =3D>      'Length of street address (-55)',
        '-56'   =3D>      'Length of shipto street address (-56)',
        '-57'   =3D>      'Length of transaction amount (-57)',
        '-58'   =3D>      'Length of name (-58)',
        '-59'   =3D>      'Length of location (-59)',
        '-60'   =3D>      'Length of state (-60)',
        '-61'   =3D>      'Length of shipto state (-61)',
        '-62'   =3D>      'Length of order string (-62)',
        '-64'   =3D>      'Invalid phone number (-64)',
        '-65'	=3D>		'Empty name (-65)',
        '-66'   =3D>      'Empty email (-66)',
        '-67'   =3D>      'Empty street address (-66)',
        '-68'   =3D>      'Empty city (-68)',
        '-69'   =3D>      'Empty state (-69)',
        '-70'   =3D>      'Empty zip code (-70)',
        '-71'   =3D>      'Empty order number (-71)',
        '-72'   =3D>      'Empty account number (-72)',
        '-73'   =3D>      'Empty expiration month (-73)',
        '-74'   =3D>      'Empty expiration year (-74)',
        '-75'   =3D>      'Empty serial number (-75)',
        '-76'   =3D>      'Empty transaction amount (-76)',
        '-79'   =3D>      'Length of customer name (-79)',
        '-80'   =3D>      'Length of shipto customer name (-80)',
        '-81'   =3D>      'Length of customer location (-81)',
        '-82'   =3D>      'Length of customer state (-82)',
        '-83'   =3D>      'Length of shipto phone (-83)',
        '-84'   =3D>      'Pos Error duplicate ordernumber (-84)',
        '-91'   =3D>      'Pos Error CVV2 (-91)',
        '-92'   =3D>      'Pos Error Approval Code (-92)',
        '-93'   =3D>      'Pos Error Blind Credits Not Allowed (-93)',
        '-94'   =3D>      'Pos Error Blind Credits Failed (-94)',
        '-95'   =3D>      'Pos Error Voice Authorizations Not Allowed (-95)=
',
);

%SJ_AVS_CODES =3D (
	'X' =3D> 'Exact match, 9 digit zip',
	'Y' =3D> 'Exact match, 5 digit zip',
	'A' =3D> 'Address match only',
	'W' =3D> '9 digit match only',
	'Z' =3D> '5 digit match only',
	'N' =3D> 'No address or zip match',
	'U' =3D> 'Address unavailable',
	'R' =3D> 'Issuer system unavailable',
	'E' =3D> 'Not a mail/phone order',
	'S' =3D> 'Service not supported'
);

%SJ_RT_FREQ =3D (		# Logic used for the frequency of recurring transactions
		'Weekly' =3D> '0',			# Starting Date + 7 Days
		'Biweekly' =3D> '1',			# Starting Date + 14 Days
		'Twice Monthly' =3D> '2',		# Starting Date + 15 Days
		'Monthly' =3D> '3',			# Every month
		'Every Four Weeks' =3D> '4',	# Every fourth week
		'Bimonthly' =3D> '5',			# Every other month
		'Quarterly' =3D> '6',			# Every third month
		'Biannually' =3D> '7',		# Semiannually / Twice per year
		'Annually' =3D> '8', 			# Once a year
		'0' =3D>	'0',
		'1'	=3D>	'1',
		'2'	=3D>	'2',
		'3'	=3D>	'3',
		'4'	=3D>	'4',
		'5'	=3D>	'5',
		'6'	=3D>	'6',
		'7'	=3D>	'7',
		'8'	=3D>	'8'
);

%SJ_RC_ERRORS =3D (
		'1'		=3D>	'CALL FAILED (1)',
		'-1'	=3D>	'INVALID COMMAND (-1)',
		'-2'	=3D>	'PARAMETER MISSING (-2)',
		'-3'	=3D>	'FAILED RETRIEVING RESPONSE (-3)',
		'-4'	=3D>	'INVALID STATUS (-4)',
		'-5'	=3D>	'FAILED READING SECURITY FLAGS (-5)',
		'-6'	=3D>	'DEVELOPER SERIAL NUMBER NOT FOUND (-6)',
		'-7'	=3D>	'INVALID SERIAL NUMBER (-7)',
		'-8'	=3D>	'EXPIRATION YEAR IS NOT FOUR CHARECTERS (-8)',
		'-9'	=3D>	'CREDIT CARD EXPIRED (-9)',
		'-10'	=3D>	'INVALID STARTING DATE (-10)',
		'-11'	=3D>	'FAILED ADDING RECURRING PAYMENT (-11)',
		'-12'	=3D>	'INVALID FREQUENCY (-12)'
);

sub sj_test_values {
	my ($inopt, $inval) =3D @_;
	my $opt =3D {
		id         =3D> '000658076426',
		submit_url =3D>
			'https://developer.skipjackic.com/scripts/evolvcc.dll?Authorize',
		vendor     =3D> '111222333444',
	};
	my $val =3D {
		mv_credit_card_number     =3D> '4445999922225',
		mv_credit_card_cvv2       =3D> '999',
		mv_credit_card_exp_month  =3D> '09',
		mv_credit_card_exp_year   =3D> '02',
		b_address                 =3D> '8320 Rocky Road',
		b_zip                     =3D> '85284',
	};

	my $gen;
	if($inopt and $gen =3D $inopt->{generate_error}) {
		$opt->{id} =3D '1111000011111' if $gen eq /\bid\b/i;
		$opt->{vendor} =3D '1111000011111' if $gen =3D~ /vendor/i;
		$val->{mv_credit_card_number} =3D '4111111111111112' if $gen =3D~ /number=
/i;
		$val->{b_zip} =3D '45056' if $gen =3D~ /avs/i;
		$val->{mv_credit_card_exp_year} =3D '00' if $gen =3D~ /exp/i;
	}

	if($inopt) {
		for (keys %$opt) {
			$inopt->{$_} =3D $opt->{$_};
		}
	}
	if($inval) {
		for (keys %$val) {
			$inval->{$_} =3D $val->{$_};
		}
	}
	return ($opt, $val);
}

sub skipjack {
	my ($opt, $amount) =3D @_;

	my $user =3D $opt->{id} || charge_param('id');

	my %actual;
	if($opt->{actual}) {
		%actual =3D %{$opt->{actual}};
	}
	else {
		%actual =3D map_actual();
	}

	if($opt->{test} || charge_param('test')) {
		sj_test_values($opt, \%actual);
	}

	my $ccem =3D $actual{mv_credit_card_exp_month};
	$ccem =3D~ s/\D//g;
	$ccem =3D~ s/^0+//;
	$ccem =3D sprintf('%02d', $ccem);

	my $ccey =3D $actual{mv_credit_card_exp_year};
	$ccey +=3D 2000 unless $ccem =3D~ /\d{4}/;

	$actual{mv_credit_card_number} =3D~ s/\D//g;
	$actual{phone_day} =3D~ s/\D//g;

	my $precision =3D $opt->{precision} || charge_param('precision') || 2;

	$amount =3D $opt->{total_cost} || undef;

	$opt->{transaction} =3D charge_param('transaction') || 'sale';
	my $transtype =3D $opt->{transaction};

	# Skipjack doesn't do transaction types?
	my %type_map =3D (
	);
=09
	if (defined $type_map{$transtype}) {
        $transtype =3D $type_map{$transtype};
    }

    if(! $amount) {
			$amount =3D Vend::Interpolate::total_cost();
			$amount =3D Vend::Util::round_to_frac_digits($amount,$precision);
    }

	my %values;
	if($transtype eq 'sale') {
		%values =3D (
		 	Sjname =3D> $actual{b_name},
			Email =3D> $actual{email},
			Streetaddress =3D> $actual{b_address},
			City =3D> $actual{b_city},
			State =3D> $actual{b_state},
			Zipcode =3D> $actual{b_zip},
			Ordernumber =3D> $opt->{order_id},
			Accountnumber =3D> $actual{mv_credit_card_number},
			Month =3D> $ccem,
			Year =3D> $ccey,
			Serialnumber =3D> $user,
			Transactionamount =3D> $amount,
			Orderstring =3D> "0001~Generic Order String~$amount~1~N~||",
			Shiptophone =3D> $actual{phone_day}
			);
	}
	elsif($transtype eq 'recurring') {
		%values =3D (
		 	szSerialNumber =3D> $user,
			szDeveloperSerialNumber =3D> $opt->{vendor},
			rtName =3D> $actual{b_name},
			rtEmail =3D> $actual{b_email},
			rtAddress1 =3D> $actual{b_address},
			rtCity =3D> $actual{b_city},
			rtState =3D> $actual{b_state},
			rtPostalCode =3D> $actual{b_zip},
			rtCountry =3D> $actual{b_country},
			rtPhone =3D> $actual{phone_day},
			rtAccountnumber =3D> $actual{mv_credit_card_number},
			rtExpMonth =3D>  $ccem,
			rtExpYear =3D> $ccey,
			rtItemNumber =3D> $opt->{item_code},
			rtItemDescription =3D> $opt->{item_description},
			rtAmount =3D> $amount,
			rtStartingDate =3D> $opt->{start_date},
			rtFrequency =3D> $SJ_RT_FREQ{$opt->{frequency}},
			rtTotalTransactions =3D> $opt->{total_transactions},
			rtOrderNumber =3D> $opt->{order_id},
			rtComment =3D> $actual{gift_note},
		);
	}

	#my $submit_url =3D $opt->{submit_url} || 'https://www.skipjackic.com/scri=
pts/evolvcc.dll?Authorize';
	$opt->{submit_url} =3D 'https://www.skipjackic.com/scripts/evolvcc.dll?Aut=
horize';

#::logDebug("URL: $submit_url");

	my $thing =3D post_data($opt, \%values);
#::logDebug("Sending: " . ::uneval(\%values) . ::uneval($opt) );

	## check for errors
	my $error;

#::logDebug("request returned: $thing->{result_page}");

	my %result;

	if($transtype eq 'sale') {
		my @lines =3D split /</, $thing->{result_page};
		@lines =3D grep /\!-+/, @lines;
		for (@lines) {
#::logDebug("found response line=3D$_");
			s/-->.*//s;
			if (/^!--(.*)/) {
				my ($name, $val) =3D split(/=3D/,$1);
#::logDebug("name=3D$name value=3D$val");
				$result{$name} =3D $val;
			}
		}
		if ($result{szAuthorizationResponseCode} ne "") {
			$result{MStatus} =3D $result{'pop.status'} =3D 'success';
			$result{'order-id'} =3D $opt->{order_id};
		}
		else {
			$result{MStatus} =3D 'failed';
			$result{MErrMsg} =3D  $SJ_ERRORS{$result{szReturnCode}}
		}
	}
	elsif ($transtype eq 'recurring') {
		$thing->{result_page} =3D~ s/\"//g;
		my ($ron,$rc,$rn) =3D split(/\,/, $thing->{result_page});
		$result{szAuthorizationResponseCode} =3D $ron || '';
		if($rc =3D=3D 0) {
			$result{MStatus} =3D 'success';
			$result{'order-id'} =3D $ron;
		}
		else {
			$result{MStatus} =3D 'failed';
			$result{MErrMsg} =3D  $SJ_RC_ERRORS{$rc}
		}
	}
	else {
		return (
			MStatus =3D> 'failure-hard',
			MErrMsg =3D> ::errmsg('unknown transction type: %s',$transtype),
		);
	}

    # Interchange names are on the  left, Skipjack on the right
    my %result_map =3D ( qw/
            pop.ref-code          szSerialNumber
            pop.auth-code         szAuthorizationResponseCode
            pop.avs_code          szAVSResponseCode
            pop.avs_reason        szAVSResponseMessage
			pop.txn-id            szOrderNumber
			pop.price             szTransactionAmount
			pop.error-message     szAuthorizationResponseCode
			pop.cvv2_code         szCVV2ResponseCode
			pop.cvv2_reason       szCVV2ResponseMessage
            icp_ref_code          szSerialNumber
            icp_auth_code         szAuthorizationResponseCode
            icp_avs_code          szAVSResponseCode
            icp_avs_reason        szAVSResponseMessage
			icp_txn_id            szOrderNumber
			icp_price             szTransactionAmount
			icp_error_message     szAuthorizationResponseCode
			icp_cvv2_code         szCVV2ResponseCode
			icp_cvv2_reason       szCVV2ResponseMessage
    /
    );

    for (keys %result_map) {
        $result{$_} =3D $result{$result_map{$_}}
            if defined $result{$result_map{$_}};
    }

#::logDebug("Skipjack request result: " . ::uneval(\%result) );

	return %result;
}

package Vend::Payment::Skipjack;

1;

--=-yMvq6mbzEY2LWvhOoJu+--