[ic] RE: Payment module failure

Boyer, Jim boyerj at wsu.edu
Tue Nov 29 16:40:05 EST 2005


Here is a little more info on the payment module failure I am getting

IC version 5.2.0
Perl 5.8.5
OS RHEL  2.4.21-37.ELsmp


Here is the module I am running
=============================
# Vend::Payment::WSU - Interchange WSU support
#
# $Id: WSU.pm,v 2.7 2002/12/17 02:39:04 kwalsh Exp $
#
# Copyright (C) 1999-2003 Perusion, Inc. <info at perusion.net>
#
# 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.

# Connection routine for WSU custom payment server

package Vend::Payment::WSU;

use Vend::Util;

=head1 Interchange WSU Custom Payment Server Support

Vend::Payment::WSU $Revision: 1.0 $

=head1 SYNOPSIS

    &charge=wsu

        or

    [charge mode=wsu param1=value1 param2=value2]

=head1 PREREQUISITES

This module is required:

  Frontier::Client

It implements the RPC calls via HTTP.

One of these:

  Net::SSLeay OR LWP::UserAgent and Crypt::SSLeay

Only one of these need be present and working.

=head1 DESCRIPTION

The Vend::Payment::WSU module implements the wsu() routine
for use with Interchange. It is compatible on a call level with the
other
Interchange payment modules -- in theory (and even usually in practice)
you
could switch from WSU to Authorize.net with a few configuration
file changes.

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

    Require module Vend::Payment::WSU

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

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<wsu>. 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  wsu

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
options,
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=wsu id=YourWSUID]

or

    Route wsu id YourWSUID

or

    Variable MV_PAYMENT_ID      YourWSUID

The active settings are:

=over 4

=item id

Your WSU account ID, supplied by WSU IT.  Global parameter is
MV_PAYMENT_ID.

Example:

     Route wsu id CAHE

=item

=item payment_opt

The WSU payment option. Default is 201.

    Route    wsu  payment_opt  201

=item remap

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

=item transaction

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

    Interchange         WSU
    ----------------    -----------------
        auth            AUTH
        reverse         REVERSAL
        sale            AUTHCAP
        settle          CAPTURE

You can set the default in catalog.cfg:

    Route    wsu  transaction  AUTH

To change the type for one particular charge operation, you would
pass it in the [charge ...] or $Tag->charge():

  [charge transaction=AUTHCAP mode=wsu]

     or

  $Tag->charge({ transaction => 'AUTHCAP', mode => 'wsu' });

The Interchange UI can be used for CAPTURE and REVERSAL operations.
REVERSAL
only will reverse the entire amount of the order in the UI, but using
the
amount flag can cause partial reversal (if the gateway supports it).

=back

=head2 Troubleshooting

Try the instructions above, then enable test mode. A test order should
complete.

Disable test mode, then test in various WSU error modes by
using the credit card number 4222 2222 2222 2222.

Then try a sale with the card number C<4111 1111 1111 1111>
and a valid expiration date. The sale should be denied, and the reason
should
be in [data session payment_error].

If nothing works:

=over 4

=item *

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

    Require module Vend::Payment::WSU

=item *

Make sure either Net::SSLeay or Crypt::SSLeay and LWP::UserAgent are
installed
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).

=item *

Check the error logs, both catalog and global.

=item *

Make sure you set your payment parameters properly.

=item *

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

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

That should show what happened.

=item *

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

=back

=head1 BUGS

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

=head1 AUTHORS

Mike Heins, <mikeh at perusion.net>.

=cut

BEGIN {

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

     $Vend::Payment::Have_Net_SSLeay = 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 = "LWP and Crypt::SSLeay";
          };

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

     }

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

     eval {
          package Vend::Payment;
          require Frontier::Client;
          import Frontier::Client;
     };

     if($@) {
          die __PACKAGE__ . "requires Frontier::Client\n";
     }

     logGlobal("%s payment module initialized, using %s\n", __PACKAGE__,
$selected)
          unless $Vend::Quiet or ! $Global::VendRoot;
}

package Vend::Payment;

sub wsu {
     my ($user, $amount) = @_;

     my $opt;
     if(ref $user) {
          $opt = $user;
          $user = $opt->{id} || undef;
          $secret = $opt->{secret} || undef;
     }
     else {
          $opt = {};
     }

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

#::logDebug("actual map result: " . ::uneval($actual));
     if (! $user ) {
          $user    =  charge_param('id')
                              or return (
                                   MStatus => 'failure-hard',
                                   MErrMsg => errmsg('No account id'),
                                   );
     }

     $secret    =  charge_param('secret') if ! $secret;

    $opt->{host}   ||= 'https://itnt104.it.wsu.edu';

    $opt->{script} ||= '/xml-rpc/epay.asp';

    $opt->{function} ||= 'epay_cc';

    $opt->{port}   ||= '';
     $opt->{port} =~ s/^:*/:/ if $opt->{port};

    $opt->{payment_opt}   ||= charge_param('payment_opt') || '201';

     my $precision = $opt->{precision}
                    || 2;

     my $referer   =  $opt->{referer}
                         || charge_param('referer');

     my @override = qw/
                              order_id
                              auth_code
                              mv_credit_card_exp_month
                              mv_credit_card_exp_year
                              mv_credit_card_number
                         /;
     for(@override) {
          next unless defined $opt->{$_};
          $actual->{$_} = $opt->{$_};
     }

     ## Format month
     $actual->{mv_credit_card_exp_month} =~ s/\D//g;
    $actual->{mv_credit_card_exp_month} =~ s/^0+//;
    $actual->{mv_credit_card_exp_year} =~ s/\D//g;
    $actual->{mv_credit_card_exp_year} =~ s/\d\d(\d\d)/$1/;

    $actual->{mv_credit_card_number} =~ s/\D//g;

    my $exp = sprintf '%02d%02d',
                        $actual->{mv_credit_card_exp_month},
                        $actual->{mv_credit_card_exp_year};

     # Using mv_payment_mode for compatibility with older versions,
probably not
     # necessary.
     $opt->{transaction} ||= 'sale';
     my $transtype = $opt->{transaction};

     my %type_map = (
          AUTH                =>   'AUTH',
          REVERSAL            =>  'REVERSAL',
          AUTHCAP                  =>   'AUTHCAP',
          CAPTURE                  =>   'CAPTURE',
          authorize           =>   'AUTH',
          auth                =>   'AUTH',
          mauthonly           =>   'AUTH',
          return                   =>   'REVERSAL',
          sale                =>   'AUTHCAP',
          settle              =>  'CAPTURE',
          settle_prior             =>  'CAPTURE',
          void                =>   'REVERSAL',
     );

     if (defined $type_map{$transtype}) {
        $transtype = $type_map{$transtype};
    }

     $amount = $opt->{total_cost} if $opt->{total_cost};

    if(! $amount) {
        $amount = Vend::Interpolate::total_cost();
        $amount = Vend::Util::round_to_frac_digits($amount,$precision);
    }
     $amount = int( $amount * 100 );

     $order_id = gen_order_id($opt);

#::logDebug("auth_code=$actual->{auth_code} order_id=$opt->{order_id}");

     my $cc = $actual->{mv_credit_card_number};
     $cc =~ s/\D+//g;

     my %ctype = (
          visa     => '001',
          mc           => '002',
          mastercard     => '002',
     );

     my $card_type = $ctype{$actual->{mv_credit_card_type}};
#::logDebug("card type=$actual->{mv_credit_card_type}
card_type=$card_type");

     if(! $card_type) {
          $actual->{mv_credit_card_number} =~ /^4/ and $card_type =
'001';
          $actual->{mv_credit_card_number} =~ /^5/ and $card_type =
'002';
     }
#::logDebug("card type=$actual->{mv_credit_card_type}
card_type=$card_type");

     $card_type ||= '001';
     if(! $card_type) {
     $result{MStatus} = 'failure';
          return (
                         MStatus => 'failure',
                         MErrMsg => "WSU doesn't accept
$actual->{mv_credit_card_type}",
                    );

     }

     my $name_and_phone = '';
     if($actual->{b_name}) {
          $name_and_phone .= $actual->{b_name};
     }
     elsif($actual->{name}) {
          $name_and_phone .= $actual->{name};
     }
     else {
          $name_and_phone .= "NO NAME";
     }

     if($actual->{phone_day}) {
          $name_and_phone .= ", " . $actual->{phone_day};
     }
     elsif($actual->{phone_night}) {
          $name_and_phone .= ", " . $actual->{phone_night};
     }
     else {
          $name_and_phone .= " (NO PHONE)";
     }

     my $server_url = $opt->{host} . $opt->{port} . $opt->{script};

     ## Get Frontier object
     my $server = Frontier::Client->new(url => $server_url)
          or die "Unable to reach Frontier::Client\n";

     ## Stack parameters, formatted for Frontier
    my %query = (
          merchant            => $server->string($user),
          tran_type           => $server->string($transtype),
          card_num            => $server->string($cc),
          exp_date            => $server->string($exp),
          amount                   => $server->int($amount),
          card_type           => $server->string($card_type),
          payment_opt              =>
$server->string($opt->{payment_opt}),
          t_type_id           => $server->string($opt->{t_type_id}),
          trans_id            => $server->string($order_id),
          sequence_num_in          => $server->string($order_id),
          ip_address               =>
$server->string($Session->{ohost}),
          additional_info          => $server->string($name_and_phone),
          cvv                      => $server->string($actual->{cvv2} ||
''),
     );

#::logDebug(qq{\nwsu array to send: } . ::uneval(\%query));

    my $return   = $server->call($opt->{function}, \%query);

    # Interchange names are on the  left, WSU on the right
    my %result_map = ( qw/
            pop.status            return_code
            pop.error-message     return_message
            order-id              sequence_num
            pop.order-id          sequence_num
            pop.auth-code         approval_code
            pop.cvv_code          cvv_result
    /
    );


::logDebug(qq{\nwsu hash result: } . ::uneval($return));

    my %result = %{$return->[0]};

    for (keys %result_map) {
        $result{$_} = $result{$result_map{$_}}
            if defined $result{$result_map{$_}};
    }
::logDebug(qq{\nwsu hash result translated: } . ::uneval(\%result));

     my $status = $result{return_code};
     my $gwmsg  = $result{return_message};

     if(! defined $status or $status eq '') {
          $result{MStatus} = 'failure-hard';
          $result{MErrMsg} = $gwmsg || 'Gateway failure';
     }
     elsif($status == 0) {
          $result{MStatus} = 'success';
     }
     elsif($status == 1) {
          $result{MStatus} = 'failure';
          $result{MErrMsg} = errmsg($gwmsg || 'Card declined.');
     }
     elsif($status == 2) {
          $result{MStatus} = 'failure-hard';
          $result{MErrMsg} = errmsg($gwmsg || 'Gateway processing
error.');
     }
     elsif($status == 3) {
          $result{MStatus} = 'failure';
          $result{MErrMsg} = errmsg("Bad input parameter: %s", $gwmsg ||
'unknown');
     }

::logDebug(qq{\nwsu hash result: } . ::uneval(\%result));

    return (%result);
}

package Vend::Payment::WSU;

1;
===============================================

And the error again:

I have a payment module written for us that uses XML to talk to our
credit card server.  It has recently been receiving the following error
on a random basis:

==============================================================
- [28/November/2005:09:15:00 -0800] pestrecert
/cgi-bin/pestrecert/process Safe:
 Real-time charge failed.
 Reason: payment routine 'wsu' returned error: 500 read failed:
>
>
>
>               die errmsg(
>                               "Real-time charge failed. Reason: %s\n",
>                               errmsg($Session->{cybercash_error}),
>                       );
>
>
==============================================================
                             
I looked in the archives for LWP and I could not find anything about my
problem, maybe I am blind...   

Any help would be greatly appreciated.

Thanks,


-------------------------------
Jim Boyer
Systems Programmer
College of Agriculture, Human, and Natural Resource Sciences 
Washington State University
509.335.2838
 




More information about the interchange-users mailing list