MiniVend Akopia Services

[Date Prev][Date Next][Thread Prev][Thread Next][Minivend by date ][Minivend by thread ]

re: Payment Net (signio) Pains!! but IT WORKS!



Well after getting nowhere I finally decided to rewrite CCLib.pm to use the most 
recect auth program from signio (pfpro).  

Attached is my new updated CCLib.pm with some hacks in it based on signio's test.cgi 
script.

You need the signio exe from their website.  Download and tuck this away in the minivend
directory or anywhere.

Besides the documented parameters you should define 
Variable CYBER_EXECUTABLE /path/to/pfpro

CYBER_EXECUTABLE is refernced in CCLib.pm, but appears NO WHERE in the documentation

The signio client returns different parameters so the status checks were all balled up.
Hope this helps someone out there!

Cordially,

                                          George
____________________________________________________________________________
Customer Service              		            Software Workshop Inc.
glaw@thebook.com 315.635-1968 (x213)             "software that fits!" (TM)
http://www.thebook.com


#!/usr/bin/perl

=head1 NAME

CCLib.pm -- Compatibility module for PAYMENTNET.COM and CyberCash version 2

=cut

package CCLib;

use Carp;
use Exporter;
@EXPORT = qw/ SetServer sendmserver /;

use POSIX qw/tmpnam/;
$VERSION = '0.01';

use vars qw/$VERSION/;

my $Port   = 1605;
my $Server = 'connect.seguesystems.com';
my $Password;
my $VendorID;
my $Executable;

=head1 VERSION

0.01

=head1 SYNOPSIS

use CCLib;

SetServer( 
            host     => 'connect.sequesystems.com',
            port     => '1605',                    
            secret   => 'analyze',                 
            vendor   => 'sltest',                  
            );

my $mode = 'mauthonly' || 'mauthcapture';

%result = sendmserver (
        $mode,
        # may be anything
        'Order-ID'     => $orderID,
        # can be the Cybercash 'usd 33.44'
        'Amount'       => $amount,
        # spaces OK
        'Card-Number'  => $ccnum,
        'Card-Name'    => $name,
        'Card-Address' => $address,
        'Card-City'    => $city,
        'Card-State'   => $state,
        'Card-Zip'     => $zip,
        'Card-Country' => $country,
        # Can be cybercash style, must be
        # one of MM/YY, M/YY, MYY, or MMYY
        'Card-Exp'     => $exp,
        );

    if($result{MStatus} !~ /^success/) {
        $error = $result{MErrMsg};
        return undef;
    }
    else {
        return 1;
    }

=head1 DESCRIPTION

This module interfaces PaymentNet.com servers to software
designed for CyberCash 2. It is also quite suitable for standalone use
with Perl.

This module was designed to work with MiniVend, so if you see
references to $Vend::Cfg that is the reason. You may ignore
those references; they should not cause problems.

If you want to set your Vendor ID in the environment, use 
$ENV{PAYMENTNET_VENDORID}.

The C<socklink> executable can either reside in the Perl @INC
libary include path, or can be in your $ENV{PATH}. They are used
in that order.

=head2 Example of use with MiniVend

Set the following variables in catalog.cfg:

    # the paymentnet.com host
    Variable CYBER_HOST   connect.sequesystems.com

    # the paymentnet.com port, defaults to 1605
    #Variable CYBER_PORT   1605

    # your password
    Variable CYBER_SECRET analyze

    # your password
    Variable CYBER_VENDOR sltest

You can set your mv_cyber_mode variable to any valid PaymentNet
transaction type, or to the CyberCash:

    CyberCash       PaymentNet
    ------------------------------
    mauthonly           C1
    mauthcapture        C6

=head1 AUTHOR

Mike Heins, Internet Robotics, <mikeh@minivend.com>.

=head1 BUGS

Doesn't capture and log approval, AVS, and verify. That would be
easy to add.

=cut


#
#   socklink <host> <port> <URL> <vendorID> <password> <transType> <ccNum> <ZIP> <expDate> <amount> <comment1> <comment2>
#   
#   <host>      host name                         'www2.onanalysis.com'
#   <port>      port number                       '443'
#   <URL>       local path on host to cgi         '/socketlink/cc.cgi'
#   <vendorID>  user name for SocketLink account  'XYZcorp'
#   <password>  password for SocketLink account   'foobar'
#   <transType> credit card transaction type      'C6'
#   <ccNum>     credit card number                '1234234534564567'
#   <ZIP>       ZIP code for card (AVS)           '94612'
#   <expDate>   credit card expiration date       '0698'
#   <amount>    amount of transaction             '49.95'
#   <comment1>  Comment #1                        'SuperWidget (green)'
#   <comment2>  Comment #2                        'Sales Agent: 4432'
#   

sub SetServer {

#::logGlobal("Setserver called", @_);
        my (%hash) = @_;
        $Server = $hash{'host'}
                    if  $hash{'host'} and
                        $hash{'host'} ne 'localhost';
        $Port   = $hash{'port'}
                    if  $hash{'port'} and
                    $hash{'port'} ne '8000';
        $Password = $hash{'secret'}
                    if $hash{'secret'};

        if ($hash{'vendor'}) {
            $VendorID = $hash{'vendor'};
#::logGlobal("vendor id assigned from hash");
        }
        elsif($ENV{PAYMENTNET_VENDORID}) {
#::logGlobal("vendor id assigned from PAYMENTNET env");
            $VendorID = $ENV{PAYMENTNET_VENDORID};
        }
        elsif(  defined $Vend::Cfg and
                ref     $Vend::Cfg->{Variable} and 
                $Vend::Cfg->{Variable}{CYBER_VENDOR}
                )
        {
#::logGlobal("vendor id assigned from CYBER_VENDOR");
            $VendorID = $Vend::Cfg->{Variable}{CYBER_VENDOR};
        }
        else {
            carp "No vendor id assigned.\n";
            $VendorID = 'sltest';
        }

        my $ext = '';
        my $joiner = "/";

        if($^O =~ /win32/) {
            $joiner = "\\";
            $ext = '.exe';
        }

        $Executable =  $Vend::Cfg->{Variable}{CYBER_EXECUTABLE};
        $Executable = 'socklink' unless $Executable;
#::logGlobal("Vendor=$VendorID exec=$Executable pass=$Password\n");
        return 1;
}

my %status_translate = (

                        -99 => 'Internal (unknown) error',
                        -8 => 'X509 cerification verification error',
                        -7 => 'SSL verify location error',
                        -6 => 'SSL verification policy error',
                        -5 => 'SSL context initialization failed',
                        -4 => 'Socket initialization error',
                        -2 => 'Hostname lookup failed',
                        -1 => 'Server socket unavailable',
                        0  => 'success',
                        1  => 'Invalid Vendor ID',
                        2  => 'Invalid password',
                        3  => 'Invalid transaction type',
                        4  => 'Invalid amount',
                        5  => 'Processor host connection error',
                        11  => 'Transaction timeout error',
                        12  => 'Transaction declined',
                        19  => 'Invalid authorization transaction ID',
                        21  => 'Recapture not allowed',
                        23  => 'Credit card number is invalid',
                        24  => 'Credit card expiration date is invalid',
                        

                        );


my %mode_translate = ( qw/

                        C0 C0
                        C1 C1
                        C3 C3
                        C6 C6
                        C7 C7
                        mauthonly       C1
                        mauthcapture    C6
                        authonly        C1
                        authcapture     C6

                        / );

sub sendmserver {
        my $mode = shift;
        my %opt = @_;

my $debug = "mode=$mode\n";
for(keys %opt) {
    $debug .= "$_=$opt{$_}\n";
}
#::logGlobal("sendmserver called:\n$debug");
        
        my (@err_parms);
        unless( $Server && $Password && $VendorID && $Port ) {
            @err_parms = ( 'MStatus' , 'error_before_connect', 'MErrMsg' );
            my $err = '';
            $err .= "No server set.\n" unless $Server;
            $err .= "No password given.\n" unless $Password;
            $err .= "No port set.\n" unless $Port;
            $err .= "No Vendor ID given.\n" unless $VendorID;
            push @err_parms, $err;
#::logGlobal("error", @err_parms);
            return(@err_parms);
        }

        $opt{'Card-Number'} =~ tr/0-9//cd;
        $opt{'Card-Exp'} =~ tr/0-9//cd;
        $opt{'Card-Exp'} = "0" .  $opt{'Card-Exp'}
            if length   $opt{'Card-Exp'} < 4;
        $opt{'Amount'} =~ tr/.0-9//cd;
        unless ( $mode_translate{$mode}) {
            @err_parms = ('MStatus', 'error_before_connect',
                            'MErrMsg', 'No mode set.');
#::logGlobal("error", @err_parms);
            return(@err_parms);
        }

        # The order of these params is documented in PaymentNet 
        # literature (and above from the socklink usage message).
        # We use Order ID and customer name as the last two
        # user-definable ones.
        my (@param);
        @param = (
                $Server,
                $Port,
                $opt{'Card-Address'},
                $VendorID,
                $Password,
                $mode_translate{$mode},
                $opt{'Card-Number'},
                $opt{'Card-Zip'},
                $opt{'Card-Exp'},
                $opt{'Amount'},
                $opt{'Order-ID'},
                $opt{'Card-Name'},
            );
        for(@param) {
            next if /^[-\w.]+$/;
            s/\s/ /g;
            s/"/\\"/g;
            $_ = qq{"$_"};
        }

#$debug = "parms:\n" . join "\n", @param;
#::logGlobal($debug);
    
        @err_parms = ( 'MStatus' , 'error_on_execution', 'MErrMsg' );
        my $rfile = POSIX::tmpnam();
        my $status_msg;
        my $paramstring;
        $paramstring = "TRXTYPE=S&TENDER=C&PWD=$Password&USER=$VendorID&ACCT=$opt{'Card-Number'}&EXPDATE=$opt{'Card-Exp'}&AMT=$opt{'Amount'}";

        # do the authorization, results saved in the $rfile
        open (TRANS, "| $Executable $Server $Port \"$paramstring\" 30 > $rfile");      
        close TRANS;

        if($?) {  # check the system status
            my $status = $? >> 8;
            @err_parms = ( 'MStatus', 'error_on_execution', 'MErrMsg' );
            push @err_parms, "Status $status: $status_translate{$status}";
#::logGlobal("error", @err_parms);
            return @err_parms if $status != 1;
        }


        open(RESULT, $rfile)                    or croak "read $rfile: $!\n";
        my $status = <RESULT>;  #signio file only has 1 line 0 see the format below
        chomp $status;
        my $result = <RESULT>;
        chomp $result;
        # Not using this at the moment
        # my $process = <RESULT>;
        # chomp $process;
        close RESULT;
        # payment net returns a string like :
        #RESULT=1&PNREF=P789321897561RESPMSG=Approved&AUTHCODE=821PNI&AVSADDR=X&AVSZIP=X
        # split this up, create a assoc array $results with keys 
        my @resultfields = split("&",$status);
        my $resultline;
        my $results;
        my $key;
        my $value;
        foreach $resultline (@resultfields) {
            ($key,$value) = split ("=",$resultline);
            $results{$key} = $value;
        } 
        my $status1 = $results{'RESULT'}; 

        if($?) {
            my $code = $? >> 8;
            @err_parms = ( 'MStatus', 'error_during_execution', 'MErrMsg' );
            carp("Error running $Executable, error $code: $!\n");
            push @err_parms, $status_translate{$status};
#::logGlobal("error", @err_parms);
            unlink($rfile);
            return @err_parms;
        }

        $result = $status_translate{$status1} unless $result;

        my $success = ($status1 eq '0');

        #if($status eq '0') {
        #   $status_msg = 'success';
        #}
        #elsif ($status < 0) {
        #   $status_msg = 'connection error';
        #}
        #else {
        #   $status_msg = 'transaction error';
        #}

        my %result;
        if ($success) {
            $result{MStatus} = 'success';
            $result{'order-id'} = $result;
        }
        else {
            $result{MStatus} = $status_translate{$status};
            $result{MErrMsg} = $result;
        }
        unlink($rfile);
        return (%result);

}

1;


Search for: Match: Format: Sort by: