[interchange-cvs] interchange - danb modified 2 files
interchange-core@icdevgroup.org
interchange-core@icdevgroup.org
Fri Aug 23 13:41:00 2002
User: danb
Date: 2002-08-23 17:40:00 GMT
Modified: . WHATSNEW
Added: lib/Vend/Payment ECHO.pm
Log:
* Support for ECHO added. Written, tested, and donated by
Michael Lehmkuhl <michael@electricpulp.com>. Ported from globalsub to
Vend::Payment by Dan Browning <db@kavod.com>. Thanks Michael!
Revision Changes Path
2.36 +3 -0 interchange/WHATSNEW
rev 2.36, prev_rev 2.35
Index: WHATSNEW
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /var/cvs/interchange/WHATSNEW,v
retrieving revision 2.35
retrieving revision 2.36
diff -u -r2.35 -r2.36
--- WHATSNEW 14 Aug 2002 19:58:00 -0000 2.35
+++ WHATSNEW 23 Aug 2002 17:39:59 -0000 2.36
@@ -169,6 +169,9 @@
Written, tested, and donated by Tom Friedel <tom@readyink.com>.
Thanks, Tom!
=20=20
+* Support for ECHO added. Written, tested, and donated by
+ Michael Lehmkuhl <michael@electricpulp.com>. Ported from globalsub to=
=20
+ Vend::Payment by Dan Browning <db@kavod.com>. Thanks Michael!
=20
UI
--
1.1 interchange/lib/Vend/Payment/ECHO.pm
rev 1.1, prev_rev 1.0
Index: ECHO.pm
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
# Vend::Payment::ECHO - Interchange ECHO support
#
# $Id: ECHO.pm,v 1.1 2002/08/23 17:40:00 danb Exp $
#
# Copyright (C) 2002=20
# Electric Pulp. <info@electricpulp.com>=20
# & Kavod Technologies <info@kavod.com>
#
# VERSION HISTORY
# + v1.1 08/06/2002 Fixed a problem with handling the return status from the
# OpenECHO module.
# + v1.2 08/17/2002 General clean up
# + v1.3 08/22/2002 Ported from globalsub to Vend::Payment
#
# http://www.openecho.com/
# http://www.echo-inc.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::ECHO;
=3Dhead1 Interchange ECHO Support
Vend::Payment::ECHO $Revision: 1.1 $
=3Dhead1 AUTHOR
Michael Lehmkuhl <michael@electricpulp.com>.
Ported to Vend::Payment by Dan Browning <db@kavod.com>. Code reused and=20
inspired by Mike Heins <mike@perusion.com>.
=3Dhead1 SPECIAL THANKS
Jim Darden <support@openecho.com>, Dan Browning <db@kavod.com>
=3Dhead1 SYNOPSIS
&charge=3Decho
=20
or
=20
[charge mode=3Decho param1=3Dvalue1 param2=3Dvalue2]
=3Dhead1 PREREQUISITES
If you have not done so already, you will need to sign up for an ECHO accou=
nt.
You will be provided an ID and a PIN (also known as 'secret'). You may also
sign up for a test account at the following URL:
http://www.echo-inc.com/echotestapp.php
This subroutine uses the OpenECHO module. Make sure OpenECHO.pm is in your=
@INC
array. For your convenience, version 1.2 has been included with Interchang=
e,=20
but you can get updated versions from:
=20=20
http://www.openecho.com/
http://www.echo-inc.com/
=20=20
The OpenECHO.pm module itself has some additional prerequisites:
Net::SSLeay
=20
or
=20=20
LWP::UserAgent and Crypt::SSLeay
Only one of these need be present and working. Net::SSLeay is preferred as=
some
have reported problems using LWP::UserAgent and Crypt::SSLeay.
URL::Escape
This module is used to write some of the URLs used by the OpenECHO module. =
It
is recommended that you read the documention for the OpenECHO module itself=
in
addition to this document.
=3Dhead1 DESCRIPTION
The Vend::Payment::ECHO module implements the echo() 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 CyberCash to ECHO with a few configuration=20
file changes.
To enable this module, place this directive in C<interchange.cfg>:
Require module Vend::Payment::ECHO
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<echo>. 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 echo
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:
Route echo id Your_ECHO_ID
or (with only ECHO as a payment provider)
=20=20=20=20
Variable MV_PAYMENT_ID Your_ECHO_ID
=09=20
or
Variable ECHO_PAYMENT_ID Your_ECHO_ID
or
=20
[charge mode=3Decho id=3DYour_ECHO_ID]
The active settings are:
=3Dover 4
=3Ditem id
Your account ID, supplied by ECHO when you sign up.
Global parameter is MV_PAYMENT_ID or ECHO_PAYMENT_ID.
=3Ditem secret
Your account password, selected by you or provided by ECHO when you sign up.
Global parameter is MV_PAYMENT_SECRET or ECHO_PAYMENT_SECRET.
=3Ditem others...
If planning to do AUTH_ONLY or other with special admin page
Variable MV_PAYMENT_REMAP order_id=3Dmv_order_id auth_code=3Dmv_auth_code
Variable ECHO_PAYMENT_ORDER_TYPE S
# S for "self-service" orders
# F for hosted or ISP orders
Variable ECHO_PAYMENT_ISP_ECHO_ID 123<4567890
Variable ECHO_PAYMENT_ISP_PIN 12345608
Variable ECHO_PAYMENT_MERCHANT_EMAIL merchant@merchant.com
Variable ECHO_PAYMENT_DEBUG F
# C causes ECHO to return a statement of conformity
# T or TRUE causes ECHO to return additional debug information
# Any other value turns off ECHO debugging
=3Dback=20
=3Dhead2 Example Configuration
This is an example configuration that one would add to catalog.cfg:=20
Variable MV_PAYMENT_ID Your_ECHO_ID
Variable MV_PAYMENT_SECRET Your_ECHO_secret
Variable MV_PAYMENT_MODE echo
=3Dhead2 Troubleshooting
Try a sale with the card number C<4111 1111 1111 1111> and a valid expirati=
on=20
date. The sale should be denied, and the reason should be in=20
[data session payment_error].
If nothing works:
=3Dover 4
=3Ditem *
Make sure you "Require"d the module in interchange.cfg:
Require module Vend::Payment::ECHO
=3Ditem *
Make sure the ECHO C<OpenECHO.pm> module is available either in your
path or in /path_to_interchange/lib.
=3Ditem *
Check the error logs, both catalog and global.
=3Ditem *
Make sure you set your account ID and secret properly.=20=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, Interchange consultants are available to help
with integration for a fee.
=3Dback
=3Dhead1 SECURITY CONSIDERATIONS
Because this library calls an executable, you should ensure that no
untrusted users have write permission on any of the system directories
or Interchange software directories.
=3Dhead1 NOTES
There is actually nothing *in* Vend::Payment::ECHO. It changes packages
to Vend::Payment and places things there.
=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__, $select=
ed)
unless $Vend::Quiet;
}
package Vend::Payment;
use OpenECHO;
sub echo {
my ($opt) =3D @_;
#::logDebug("echo called, args=3D" . ::uneval(\@_));
=09
my (%actual) =3D map_actual();
=09
my @errMsgs =3D ();
# Required for validation
if (! $user) {
$user =3D $opt->{id} ||=20
charge_param('id') ||=20=20
$::Variable->{ECHO_PAYMENT_ID} ||
$::Variable->{MV_PAYMENT_ID} ||
$::Variable->{CYBER_ID}
or push @errMsgs, "No payment ID found.";
}
=09
# Required for validation
if (! $secret) {
$secret =3D $opt->{secret} ||
charge_param('secret') ||
$::Variable->{ECHO_PAYMENT_SECRET} ||
$::Variable->{MV_PAYMENT_SECRET} ||
$::Variable->{CYBER_SECRET}
or push @errMsgs, "No payment secret found.";
}
if (scalar @errMsgs) {
for (@errMsgs) {
::logError($_);
}
return 0;
}
@errMsgs =3D ();
my $server =3D $opt->{server} ||
charge_param('server') ||
$::Variable->{ECHO_PAYMENT_SERVER} ||
$::Variable->{MV_PAYMENT_SERVER} ||
$::Variable->{CYBER_SERVER} ||
'https://wwws.echo-inc.com/scripts/INR200.EXE';
my $precision =3D $opt->{precision} ||
charge_param('precision') ||
$::Variable->{ECHO_PAYMENT_PRECISION} ||
$::Variable->{MV_PAYMENT_PRECISION} ||
$::Variable->{CYBER_PRECISION} ||
2;
##### ECHO SPECIFIC VARIABLES #####
my $order_type =3D $::Variable->{ECHO_PAYMENT_ORDER_TYPE} || 'S';
my $isp_echo_id =3D $::Variable->{ECHO_PAYMENT_ISP_ECHO_ID};
my $isp_pin =3D $::Variable->{ECHO_PAYMENT_ISP_PIN};
my $merchant_email =3D $::Variable->{ECHO_PAYMENT_MERCHANT_EMAIL};
# Set to 'C' for Certify mode to check compliance with the ECHO spec on a
# transaction-by-transaction basis. 'T' or 'TRUE' for full ECHO debugging.
my $debug =3D $::Variable->{ECHO_PAYMENT_DEBUG};
##########################
$actual{mv_credit_card_exp_month} =3D~ s/\D//g;
$actual{mv_credit_card_exp_month} =3D~ s/^0+//;
$actual{mv_credit_card_exp_year} =3D~ s/\D//g;
$actual{mv_credit_card_exp_year} =3D~ s/\d\d(\d\d)/$1/;
$actual{mv_credit_card_number} =3D~ s/\D//g;
my $exp =3D 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.
$actual{cyber_mode} =3D $actual{mv_payment_mode} || 'ES'
unless $actual{cyber_mode};
# Credit Card Transactions=20
# * AD (Address Verification)=20
# * AS (Authorization)=20
# * AV (Authorization with Address Verification)=20
# * CR (Credit)=20
# * DS (Deposit)=20
# * ES (Authorization and Deposit)=20
# * EV (Authorization and Deposit with Address Verification)=20
# * CK (System check)=20
# Credit Card Transactions Enhanced by CyberSource=20
# * CI (AV Transaction with CyberSource Internet Fraud Screen)=20
# * CE (AV Transaction with CyberSource Export Compliance)=20
# * CB (AV Transaction with CyberSource Internet Fraud Screen and Export C=
ompliance)=20
# Electronic Check Transactions=20
# * DV (Electronic Check Verification)=20
# * DD (Electronic Check Debit)=20
# * DC (Electronic Check Credit)
my %type_map =3D (
mauth_capture =3D> 'ES',
mauthonly =3D> 'AS',
CAPTURE_ONLY =3D> 'DS',
CREDIT =3D> 'CR',
AUTH_ONLY =3D> 'AS',
PRIOR_AUTH_CAPTURE =3D> 'DS',
);
=09
if (defined $type_map{$actual{cyber_mode}}) {
$actual{cyber_mode} =3D $type_map{$actual{cyber_mode}};
}
else {
$actual{cyber_mode} =3D 'ES';
}
if(! $amount) {
$amount =3D Vend::Interpolate::total_cost();
$amount =3D sprintf("%.${precision}f", $amount);
}
my($orderID);
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =3D gmtime(time=
());
### Make an order ID based on date, time, and Interchange session
# $mon is the month index where Jan=3D0 and Dec=3D11, so we use
# $mon+1 to get the more familiar Jan=3D1 and Dec=3D12
#$orderID =3D sprintf("%04d%02d%02d%02d%02d%05d%s",
# $year + 1900,$mon + 1,$mday,$hour,$min,$$,$Vend::SessionName);
$orderID =3D Vend::Payment::gen_order_id();
### Set up the OpenECHO instance
use OpenECHO;
my $openecho =3D new OpenECHO or push @errMsgs, "Couldn't make instance of=
OpenECHO.";
if (scalar @errMsgs) {
for (@errMsgs) {
::logError($_);
}
return 0;
}
@errMsgs =3D ();
### Connection info
$openecho->set_EchoServer("https://wwws.echo-inc.com/scripts/INR200.EXE");
$openecho->set_transaction_type($actual{cyber_mode});
$openecho->set_order_type($order_type);
### Merchant/ISP info
$openecho->set_merchant_echo_id($user);
$openecho->set_merchant_pin($secret);
$openecho->set_isp_echo_id($isp_echo_id);
$openecho->set_isp_pin($isp_pin);
$openecho->set_merchant_email($merchant_email);
### Billing info
my $billing_first_name =3D $actual{b_fname} || $actual{fname};
my $billing_last_name =3D $actual{b_lname} || $actual{lname};
my $billing_address1 =3D $actual{b_address1} || $actual{address1};
my $billing_address2 =3D $actual{b_address2} || $actual{address2};
my $billing_city =3D $actual{b_city} || $actual{city};
my $billing_state =3D $actual{b_state} || $actual{state};
my $billing_zip =3D $actual{b_zip} || $actual{zip};
my $billing_country =3D $actual{b_country} || $actual{country};
my $billing_phone =3D $actual{phone_day} || $actual{phone_night};
$openecho->set_billing_ip_address($Vend::Session->{ohost}); # aka [data s=
ession ohost] aka REMOTE_HOST
#$openecho->set_billing_prefix($actual{prefix});
$openecho->set_billing_first_name($billing_first_name);
$openecho->set_billing_last_name($billing_last_name);
#$openecho->set_billing_company_name($actual{company_name});
$openecho->set_billing_address1($billing_address1);
$openecho->set_billing_address2($billing_address2);
$openecho->set_billing_city($billing_city);
$openecho->set_billing_state($billing_state);
$openecho->set_billing_zip($billing_zip);
$openecho->set_billing_country($billing_country);
$openecho->set_billing_phone($billing_phone);
#$openecho->set_billing_fax($actual{fax});
$openecho->set_billing_email($actual{email});
### Electronic check payment info if supplied...
#$openecho->set_ec_bank_name($ec_bank_name);
#$openecho->set_ec_first_name($billing_first_name);
#$openecho->set_ec_last_name($billing_last_name);
#$openecho->set_ec_address1($billing_address1);
#$openecho->set_ec_address2($billing_address2);
#$openecho->set_ec_city($billing_city);
#$openecho->set_ec_state($billing_state);
#$openecho->set_ec_zip($billing_zip);
#$openecho->set_ec_rt($ec_rt);
#$openecho->set_ec_account($ec_account);
#$openecho->set_ec_serial_number($ec_serial_number);
#$openecho->set_ec_payee($ec_payee);
#$openecho->set_ec_id_state($ec_id_state);
#$openecho->set_ec_id_number($ec_id_number);
#$openecho->set_ec_id_type($ec_id_type);
### Debug on/off
$openecho->set_debug($debug);
=09
### Payment details
$openecho->set_cc_number($actual{mv_credit_card_number});
$openecho->set_grand_total($amount);
$openecho->set_ccexp_month($actual{mv_credit_card_exp_month});
$openecho->set_ccexp_year($actual{mv_credit_card_exp_year});
$openecho->set_counter($openecho->getRandomCounter());
$openecho->set_merchant_trace_nbr($orderID);
=09
### Send payment request
#print($openecho->get_version() . "<BR>");
#::logDebug("openecho submitting <urldata>%s</urldata>", $openecho->getURLD=
ata());
$openecho->Submit();
#::logDebug("The ECHO response is <echo_response>%s</echo_response>", $open=
echo->{'EchoResponse'});
#::logDebug("The ECHO type 2 response is <echotype2>%s</echotype2>", $opene=
cho->{'echotype2'});
#::logDebug("The avs_result field is <avs_result>%s</avs_result>", $openech=
o->{avs_result});
my %result;
if ($openecho->{EchoSuccess} !=3D 0) {
$result{'MStatus'} =3D 'success';
$result{'pop.status'} =3D 'success';
$result{'MErrMsg'} =3D $openecho->{'echotype2'};
$result{'pop.error-message'} =3D $openecho->{'echotype2'};
$result{'order-id'} =3D $openecho->{order_number} || 1;
$result{'pop.order-id'} =3D $openecho->{order_number} || 1;
$result{'auth_code'} =3D $openecho->{auth_code};
$result{'pop.auth_code'} =3D $openecho->{auth_code};
$result{'avs_code'} =3D $openecho->{avs_result};
$result{'pop.avs_code'} =3D $openecho->{avs_result};
}
else {
$result{MStatus} =3D 'failure';
$Vend::Session->{MStatus} =3D 'failure';
=09=09
# NOTE: A lot more AVS codes could be checked for here.
if ($result{avs_code} eq 'N') {
$result{MErrMsg} =3D "You must enter the correct billing address of your=
credit card. The bank returned the following error: " . $openecho->{'avs_r=
esult'};
}
else {
$result{MErrMsg} =3D $openecho->{'echotype2'};
}
$Vend::Session->{payment_error} =3D $result{MErrMsg};
#::logDebug("openecho oops: ".$Vend::Session->{payment_error});
}
return (%result);
}
package Vend::Payment::ECHO;
return 1;