[interchange] Update Worldpay payment module to version 1.0.2.

Stefan Hornburg interchange-cvs at icdevgroup.org
Thu Feb 23 08:26:06 UTC 2012


commit 533b96c0555a812f316eab2a99022c22d13e9b29
Author: Lyn St George <lyn at zolotek.net>
Date:   Thu Feb 23 09:24:01 2012 +0100

    Update Worldpay payment module to version 1.0.2.

 lib/Vend/Payment/Worldpay.pm |  400 ++++++++++++++++++++++++------------------
 1 files changed, 233 insertions(+), 167 deletions(-)
---
diff --git a/lib/Vend/Payment/Worldpay.pm b/lib/Vend/Payment/Worldpay.pm
index f0be487..05534cd 100644
--- a/lib/Vend/Payment/Worldpay.pm
+++ b/lib/Vend/Payment/Worldpay.pm
@@ -1,9 +1,9 @@
 # Vend::Payment::Worldpay - Interchange Worldpay support
 #
-# worldpay.pm, v 1.0.0, June 2009
+# worldpay.pm, v 1.0.2, October 2010
 #
 # Copyright (C) 2009 Nimbus Designs Ltd T/A TVCables and 
-# Zolotek Ltd All rights reserved.
+# Zolotek Resources Ltd All rights reserved.
 #
 # Authors: Andy Smith <andy at tvcables.co.uk>, http://www.tvcables.co.uk
 # Lyn St George <info at zolotek.net, http://www.zolotek.net>
@@ -29,7 +29,7 @@ package Vend::Payment::Worldpay;
 
 =head1 Interchange Worldpay Support
 
-Vend::Payment::Worldpay $Revision: 1.0.0 $
+Vend::Payment::Worldpay $Revision: 1.0.2 $
 
 http://kiwi.zolotek.net is the home page with the latest version.
 
@@ -38,13 +38,13 @@ http://kiwi.zolotek.net is the home page with the latest version.
 
 =head1 Quick Start Summary
 
-1 Place this module in <IC_root>/lib/Vend/Payment/worldpay.pm
+1 Place this module in <IC_root>/lib/Vend/Payment/Worldpay.pm
 
 2 Call it in interchange.cfg with:
     Require module Vend::Payment::Worldpay.
     
 3 Add a new route into catalog.cfg (options for the last entry in parentheses):
-  Route worldpay host https://select.wp3.rbsworldpay.com/wcc/purchase (Live Payment URL)
+  Route worldpay host https://secure.wp3.rbsworldpay.com/wcc/purchase (Live Payment URL)
   Route worldpay testhost https://secure-test.wp3.rbsworldpay.com/wcc/dispatcher (Test payment URL)
   Route worldpay instid 12345 (Your Worldpay instID)
   Route worldpay currency GBP (defaults to GBP)
@@ -56,6 +56,12 @@ http://kiwi.zolotek.net is the home page with the latest version.
   Route worldpay reporttitle 1 (If set to 1 will modifty order report title to include transaction ID)
   Route worldpay update_status processing (Text to set order status on success eg processing, default pending)
   Route worldpay wpcounter (Defines the counter for temporary order number, defaults to etc/username)
+  Route worldpay md5pw yourmd5secret (required in this version, will die without it)
+
+## md5 code ##
+  Enter the following into the worldpay control panel:-
+  Your MD5 secret as set in catalog.cfg
+  In the signature fields box enter amount:instId:MC_affsubtotal:currency
 
 4 Create a new locale setting for en_GB as noted in "item currency" below, and copy the
 public space interchange/en_US/ directory to a new interchange/en_GB/ one. Ensure that any
@@ -98,24 +104,36 @@ ADD `wp_risk` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `wp_authentication` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `wp_authamount` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `wp_order_number` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci,
+ADD `wp_transtime` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `lead_source` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `referring_url` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `txtype` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci,
+ADD `email_copy` CHAR(1) CHARACTER SET utf8 COLLATE utf8_general_ci,
+ADD `mail_list` varCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci,
+ADD `cartid` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci,
 ADD `cart` BLOB;
 
+
 And run these to allow for temporary order numbers of greater than the default 14 character field type
 ALTER TABLE `transactions` MODIFY `order_number` varchar(32);
 ALTER TABLE `orderline` MODIFY `order_number` varchar(32);
 
+Also add 'cartid' to the orderline table.
+
 7. Add the following to etc/log_transaction just BEFORE [/import][/try]
 
 lead_source: [data session source]
 referring_url: [data session referer]
 cart: [calc]uneval($Items)[/calc]
+cartid: [value mv_order_number]
+email_copy: [value email_copy]
+mail_list: [value mail_list]
 
 8. Still in etc/log_transaction, find the section that starts "Set order number in values: " and insert
 this just before it:
 
+NB/ this only applies if your IC is greater than v 5.2, otherwise skip sections 8 & 9
+
 [if value mv_order_profile =~ /worldpay/]
 [value name=mv_order_number set="[scratch purchaseID]" scratch=1]
 [else]
@@ -125,7 +143,7 @@ line. The order number is generated by the module and passed to Worldpay at an e
 passed back to Interchange with a callback. This prevents Interchange generating another order number.
 The module will not currently work with IC versions lower than 5.2 that use a tid counter defined in
 catalog.cfg. The initial order number uses the username.counter number prefixed with 'WPtmp', and a normal
-order number is created and the initial order number replaced only when Worldpay callsback that the card
+order number is created and the initial order number replaced only when Worldpay calls back that the card
 has been charged. This is to avoid gaps in the order number sequence caused by customers abandoning the 
 transaction.
 
@@ -142,7 +160,7 @@ Then in the [calc] block immediately below insert this line:
 Within the same section change the following two instances of
 [var MV_PAYMENT_MODE] to [value mv_payment_route]
 
-10. Creat a callback page in /pages called wpcallback.html or any name you prefer, set this page in
+10. Create a callback page in /pages called wpcallback.html or any name you prefer, set this page in
 the Worldpay admin panel, the module also supports dynamic callback pages where different catalogs can
 have different callback pages, if using this the callpage URL must be set in the route in catalog.cfg as
 described above.
@@ -183,7 +201,20 @@ On your checkout page include a button that sets the route and submits the check
     form=checkout
    ]
    mv_order_profile=worldpay
-   mv_order_route=worldpay
+   mv_order_route=log
+   mv_todo=submit
+[/button]
+
+NB/ for IC versions 5.2 and older, make the button so as to call the 'wprequest.html' page:
+
+[button
+    mv_click=worldpay
+    text="Place Order"
+    hidetext=1
+    form=checkout
+   ]
+   mv_nextpage=ord/wprequest
+   mv_order_route=log
    mv_todo=submit
 [/button]
 
@@ -282,9 +313,10 @@ and all successfull transactions will have status processing, defaults to pendin
 
 =item dec_inventory
 
-Set to 1 for module to decrement the inventory on a sucessfull transaction, if used disable decrement via
+Set to 1 for module to decrement the inventory on a sucessful transaction, if used disable decrement via
 log_transaction.
 
+
 =back
 
 =head2 Testing
@@ -343,10 +375,15 @@ Visa Purchasing
 4484070000000000
 
 
+=head1 changelog
+ - v1.0.2 November 2011, added encryption from Andy to main request as defence against tampering
+ - v1.0.1 not released: October 2010, made work with IC v4.8.7 - needs to have 'use strict' commented out, and a redirection page
+  
+
 =head1 AUTHORS
 
 Andy Smith <andy at tvcables.co.uk> with help from and based on code by
-Lyn St George <info at zolotek.net>, which in turn was based on original
+Lyn St George <lyn at zolotek.net>, which in turn was based on original
 code by Mike Heins <mike at perusion.com> and others.
 
 =cut
@@ -371,6 +408,7 @@ BEGIN {
             require HTTP::Request::Common;
             require Crypt::SSLeay;
             require CGI;
+            use Digest::MD5 qw(md5_hex);
             require Encode;
              import Encode qw(encode decode);
              import HTTP::Request::Common qw(POST);
@@ -381,162 +419,176 @@ BEGIN {
     }
 
     unless ($Vend::Payment::Have_Net_SSLeay or $Vend::Payment::Have_LWP) {
-        die __PACKAGE__ . " requires Net::SSLeay or Crypt::SSLeay";
+        die __PACKAGE__ . " requires Net::SSLeay or Crypt::SSLeay, " . $@;
     }
 
-::logGlobal("%s 1.0.0 payment module initialised, using %s", __PACKAGE__, $selected)
+::logGlobal("%s 1.0.2 payment module initialised, using %s", __PACKAGE__, $selected)
         unless $Vend::Quiet;
 
 }
 
 package Vend::Payment;
-use strict;
-
-#use Data::Dumper;
+use strict; 
 
 sub worldpay {
-	my ($amount, $actual, $opt, $worldpayrequest, $cart, $orderID, $purchaseID, %result);
-	
+	my ($amount, $actual, $opt, $worldpayrequest, $cart, $orderID, $purchaseID, %result, $dbh, $sql, $sth, $stho);
+
+#::logDebug("WP".__LINE__.": amnt=$amount, req=$worldpayrequest, pID=$purchaseID");	
 	# Amount to send with 2 decimals and no symbol
 	   $amount =  $::Values->{amount} || charge_param('amount') || Vend::Interpolate::total_cost();
 	   $amount =~ s/^\D*//g;
 	   $amount =~ s/\,//g;
 	   $amount =  sprintf '%.2f', $amount;
 	   
-	   
+	my $oldic  = charge_param('oldic');   
+ 
 	# Transaction variables to send to worldpay.
-	my $host = charge_param('host') || 'https://select.wp3.rbsworldpay.com/wcc/purchase'; #Live 
-	my $testhost = charge_param('testhost') || 'https://secure-test.wp3.rbsworldpay.com/wcc/dispatcher';#Test 
-	my $instId = charge_param('instid') || '00000';
+	my $host = charge_param('host') || 'https://secure.wp3.rbsworldpay.com/wcc/purchase'; #Live 
+	my $testhost = charge_param('testhost') || 'https://secure-test.wp3.rbsworldpay.com/wcc/purchase';#Test 
+	my $instId = charge_param('instid');
+	my $accId1 = charge_param('accid1');
 	my $currency = charge_param('currency') || 'GBP';
+    my $charged = charge_param('authtype') ||  'WP PreAuthed';
 	my $testMode = charge_param('testmode') || '0';
-	my $callbackurl	= charge_param('callbackurl') || '';	#URL on your server WP will callback
-	my $callpw = charge_param('callpw') || 'password'; #Must be same as Worldpay admin panel callback password
-	my $desc = charge_param('desc') || '';	#Transaction description
+	my $authMode = $::Values->{'authmode'} || charge_param('authmode') || 'E';
+	my $callbackurl	= charge_param('callbackurl');	#URL on your server WP will callback, including .html extension
+	my $callpw = charge_param('callpw'); #Must be same as Worldpay admin panel callback password
+	my $desc;	#Transaction description, set to CartID for easier reference
+	my $tmpPrefix = charge_param('tmporderprefix') || 'Cart';
 	my $fixcontact = charge_param('fixcontact') || '0';    #0=details editable at WP 1=details fixed as sent 
-	my $affsubtotal = $Tag->subtotal({noformat => 1,});# This is used to send subtotal as as MC_ parameter to read back for affilate sales calculations
+	my $affsubtotal = Vend::Interpolate::subtotal(); # This is used to send subtotal as as MC_ parameter to read back for affilate sales calculations
 	   $affsubtotal =~ s/^\D*//g;
 	   $affsubtotal =~ s/\,//g;
 	   $affsubtotal =  sprintf '%.2f', $affsubtotal;
 	
-::logDebug("WP:".__LINE__.": Session = $::Session->{id} Host = $host instid = $instId currency = $currency testmode = $testMode callbackurl = $callbackurl pw = $callpw desc = $desc fix = $fixcontact  affsubtotal=$affsubtotal");
+#::logDebug("WP:".__LINE__.": Session = $Vend::Session->{id} Host = $host instid = $instId currency = $currency testmode = $testMode callbackurl = $callbackurl pw = $callpw desc = $desc fix = $fixcontact  affsubtotal=$affsubtotal");
 
-	if ($testMode > '0') {	# send to test url not live
-		$host = $testhost;
-	}
+	   $host = $testhost if ($testMode > '0');# send to test url not live
 
 	my $ordernumber  = charge_param('ordernumber') || 'etc/order.number';
 	my $wpcounter   = charge_param('wpcounter') || 'etc/username.counter'; 
+	my $username    = $Vend::Session->{'username'};
+	my $allowbilling = charge_param('allow_billing') || '';
+	my $md5pw = charge_param('md5pw') or die "No MD5 password set in route";
 
-	$worldpayrequest  = charge_param('worldpayrequest')  || $::Values->{worldpayrequest} || 'post';
-	$opt     = {};
-	
-::logDebug("WP:".__LINE__.": Request = $worldpayrequest");
+	   $worldpayrequest  = charge_param('worldpayrequest')  || $::Values->{worldpayrequest} || 'post';
+	   $opt     = {};
 
+  
+#::logDebug("WP:".__LINE__.": Request = $worldpayrequest; un=$username, $::Values->{mv_username},");
+	   $::Values->{'mv_order_number'} = '';
+	
 ##-----------Post Information and send customer to Worldpay------------##
 if ($worldpayrequest eq 'post') {	
-::logDebug("WP:".__LINE__.": Sending customer to Worldpay");
-::logDebug("WP:".__LINE__.": TestMode = $testMode : Host = $host");
-
-  my $separator = '
';
-  my $name = "$::Values->{b_fname} $::Values->{b_lname}";
-  my $address = "$::Values->{b_address1}%0A$::Values->{b_address2}%0A$::Values->{b_city}%0A$::Values->{b_state}"; #%0A is the line feed separator between address lines
-  my $postcode = "$::Values->{b_zip}";
-  my $country = "$::Values->{b_country}";
-  my $email = "$::Values->{email}";
-  my $tel = "$::Values->{phone_night}"; #some may wish to use phone_day
-
-	 $orderID = gen_order_id($opt);
-	 $::Scratch->{orderID} = $orderID;
-
-# Disable order number creation in log_transaction and create it here instead
-if ($::Values->{inv_no}) {
-   $purchaseID = $::Values->{inv_no};
-      }
-elsif ($::Values->{mv_order_number}){
-  # IC 5.2 and earlier set order number prior to log_transaction
-   $purchaseID = $::Values->{mv_order_number};
-      }
-else{
+#::logDebug("WP:".__LINE__.": Sending customer to Worldpay");
+#::logDebug("WP:".__LINE__.": TestMode = $testMode : Host = $host");
+
+	my $separator = '
';
+	my $name = "$::Values->{fname} $::Values->{lname}" || "$::Values->{b_fname} $::Values->{b_lname}";
+	my $address = "$::Values->{address1}%0A$::Values->{address2}%0A$::Values->{city}%0A$::Values->{state}" || "$::Values->{b_address1}%0A$::Values->{b_address2}%0A$::Values->{b_city}%0A$::Values->{b_state}"; #%0A is the line feed separator between address lines
+	my $postcode = "$::Values->{zip}" || $::Values->{b_zip};
+	my $country = "$::Values->{country}" || "$::Values->{b_country}";
+	my $email = "$::Values->{email}";
+	my $tel = "$::Values->{phone_night}" || "$::Values->{phone_day}"; #some may wish to use phone_day
+
+	   $orderID = gen_order_id($opt);
+	   $::Scratch->{orderID} = $orderID;
+
+# Disable order number creation in log_transaction and create it here instead, unless IC is old
+	if ($::Values->{inv_no}) {
+	  $purchaseID = $::Values->{inv_no};
+		  }
+	else{
 # Use temporary number as the initial order number, and only replace upon successful order completion
-    $purchaseID = 'WPtmp'.Vend::Interpolate::tag_counter("$wpcounter");
-#::logDebug(":WP:".__LINE__.": purchaseID=$purchaseID;");
-}
+		$purchaseID = "$tmpPrefix".Vend::Interpolate::tag_counter("$wpcounter");
+		$Vend::Session->{mv_order_number} = $::Values->{mv_order_number} = $purchaseID if ($oldic == 1);# prevents early ICs setting order number prior to log_transaction
+	::logDebug("WP:".__LINE__.": purchaseID=$purchaseID; $Vend::Session->{mv_order_number}");
+	}
     
-    $::Scratch->{purchaseID} = $purchaseID;
-
-  my $cartId = $::Scratch->{purchaseID};
-
+    my $cartId = $desc = $::Scratch->{purchaseID} = $purchaseID;
 
+	my $md5data = $md5pw . ":" . $amount . ":" . $instId . ":" . $affsubtotal . ":" . $currency;
+	my $signature = md5_hex($md5data);  
+#::logDebug("WP:".__LINE__.": md5pw = $md5pw md5data = $md5data signature =$signature");
 
 #go to worldpay
-  my $redirecturl = "$host?instId=$instId&currency=$currency&testMode=$testMode&amount=$amount&cartId=$cartId&desc=$desc&name=$name&address=$address";
-	 $redirecturl .= "&postcode=$postcode&country=$country&email=$email&tel=$tel&MC_mv_order_number=$cartId&MC_callback=$callbackurl&MC_affsubtotal=$affsubtotal";
-	
+  my $redirecturl = "$host?signature=$signature&instId=$instId&currency=$currency&testMode=$testMode&authMode=$authMode&amount=$amount&cartId=$cartId&desc=$desc&name=$name&address=$address";
+	 $redirecturl .= "&postcode=$postcode&country=$country&email=$email&tel=$tel&MC_mv_order_number=$cartId&MC_callback=$callbackurl";
 	 $redirecturl .= "&fixContact" if ($fixcontact == 1);
-	 $redirecturl = Vend::Util::header_data_scrub($redirecturl);
+	 $redirecturl .= "&accId1=$accId1" if $accId1;
+	 $redirecturl =~ s/(?:%0[da]|[\r\n]+)+//ig; ## "HTTP Response Splitting" Exploit Fix
+
+	 $::Scratch->{'redirecturl'} = $redirecturl; # for old versions of IC needing a redirection page
+#::logDebug("WP:".__LINE__.": redirectURL = $redirecturl");
+
+# Fake the result so that IC can log the transaction
+	$result{Status}     = 'success';
+	$result{MStatus}    = 'success';
+	$result{'order-id'} = $orderID;
+#::logDebug("WP".__LINE__.": resSt=$result{'Status'}; resMSt=$result{'MStatus'},resoid=$result{'order-id'}");
+
+# Delete any stale baskets, ie with tmpID but without proper order numbers; only works if user is forced
+# to login prior to ordering and uses same username
+    $dbh = dbconnectwp() or warn "###dbh failed\n";
+	$sql = "DELETE FROM transactions WHERE order_number LIKE '$tmpPrefix%' AND username='$username'";
+	$sth = $dbh->prepare("$sql") or warn "###sth failed\n";
+	$sth->execute() or die errmsg("###Transactions tbl failed") if $username;
+	$sql = "DELETE FROM orderline WHERE order_number LIKE '$tmpPrefix%' AND username='$username'";
+	$sth = $dbh->prepare("$sql") or warn "###sth failed\n";
+	$sth->execute() or die errmsg("###Transactions tbl failed") if $username;
 
-::logDebug("WP:".__LINE__.": URL = $redirecturl");
- 
 $::Tag->tag({ op => 'header', body => <<EOB });
 Status: 302 moved
 Location: $redirecturl
 EOB
-
-# Fake the result so that IC can log the transaction
-   $result{Status}     = 'success';
-   $result{MStatus}    = 'success';
-   $result{'order-id'} = $orderID;
-   
-   return %result;
-
-
-
+	   return %result;
 }
 
 ####----------------Handle the callback from Worldpay--------------####
 elsif ($worldpayrequest eq 'callback'){
 
-	my $newsess = $::Session->{id};	
-::logDebug("WP:".__LINE__.": Processing Callback Session = $newsess");
+	my $newsess = $Vend::Session->{id};	
+#::logDebug("WP:".__LINE__.": Processing Callback Session = $newsess");
 
-	my $reporttitle = charge_param('reporttitle') || '0';
+	my $reporttitle   = charge_param('reporttitle') || '';
 	my $update_status = charge_param('update_status') || 'pending';
-	my $dec_inventory = charge_param('dec_inventory') || '0';
-
-#Capture all callback fields from CGI
-	my $transid		= $::CGI->{transId}; 		#transaction ID
-	my $check_testmode	= $::CGI->{testMode};		#returns testmode value 0 live anything higher test mode
-	my $transstatus		= $::CGI->{transStatus}; 	#Y=Sucess C=Cancelled
-	my $authamount		= $::CGI->{authAmount};		#Authorised amount
-	my $transtime		= $::CGI->{transTime};		#Time of transaction
-	my $authcurrency	= $::CGI->{authCurrency};	#Currency of authorisation
-	my $rawauthmessage	= $::CGI->{rawAuthMessade};	#Raw auth message
-	my $callbackpw		= $::CGI->{callbackPW};		#Callback password as set in admin panel
-	my $cardtype		= $::CGI->{cardType};		#Card type used
-	my $countrymatch	= $::CGI->{countryMatch};	#Y=Match N=No match B=Not available I=Country not supplied S=Country issue not available
-	my $avs			= $::CGI->{AVS};		#AVS Results
-	my $wafmerchmessage	= $::CGI->{wafMerchMessage};	#Risk result
-	my $authentication	= $::CGI->{authentication};	#VbyV or Mastercard Securecode authentication type
-	my $ipaddress		= $::CGI->{ipAdress};		#Shopper IP address
-
-::logDebug("WP:".__LINE__.": transid=$transid testmode=$check_testmode transstatus=$transstatus authamount=$authamount transtime=$transtime authcurrency=$authcurrency rawauthmessage=$rawauthmessage");
-::logDebug("WP:".__LINE__.": callbackpw=$callbackpw cardtype=$cardtype countrymatch=$countrymatch avs=$avs wafmerchmessage=$wafmerchmessage authentication=$authentication ipaddress=$ipaddress");
-
-	my $wp_order_number	= $::CGI->{MC_mv_order_number};
-
-	my $db  = dbref('transactions') or die errmsg("cannot open transactions table");
-	my $dbh = $db->dbh() or die errmsg("cannot get handle for tbl 'transactions'");
-	my $sth;
-	my $stho;
-
-::logDebug("WP:".__LINE__.": Callback order number = $wp_order_number");
-
+	my $dec_inventory = charge_param('dec_inventory') || '';
+
+#Capture all callback fields 
+ 	my ($transid, $check_testmode, $transstatus, $authamount, $transtime, $authcurrency, $rawauthcode, $rawauthmessage, $callbackpw,	$cardtype, $countrymatch, $avs, $wafmerchmessage, $authentication, $ipaddress, $wp_order_number);
+	my $page = ::http()->{'entity'};
+#::logDebug("WP".__LINE__.": page=\n$$page\n----------------------------------\n");
+	foreach my $line (split /\&/, $$page) {
+	  $transid		    = $1 if ($line =~ /transId=(.*)/i);			#transaction ID
+	  $wp_order_number  = $1 if ($line =~ /MC_mv_order_number=(.*)/);# temp CartID sent
+	  $check_testmode	= $1 if ($line =~ /testMode=(.*)/);			#returns testmode value 0 live anything higher test mode
+	  $transstatus		= $1 if ($line =~ /transStatus=(.*)/); 		#Y=Sucess C=Cancelled
+	  $authamount		= $1 if ($line =~ /authAmount=(.*)/);		#Authorised amount
+	  $transtime		= $1 if ($line =~ /transTime=(.*)/);		#Time of transaction
+	  $authcurrency		= $1 if ($line =~ /authCurrency=(.*)/);		#Currency of authorisation
+	  $callbackpw		= $1 if ($line =~ /callbackPW=(.*)/);		#Callback password as set in admin panel
+	  $rawauthmessage	= $::Values->{'rawauthmessage'}  = $1 if ($line =~ /rawAuthMessage=(.*)/);	#Raw auth message
+	  $rawauthcode		= $::Values->{'rawauthcode'}     = $1 if ($line =~ /rawAuthCode=(.*)/);	#Raw auth message
+	  $cardtype			= $::Values->{'cardtype'}        = $1 if ($line =~ /cardType=(.*)/);	#Card type used
+	  $countrymatch		= $::Values->{'countrymatch'}    = $1 if ($line =~ /countryMatch=(.*)/); #Y=Match N=No match B=Not available I=Country not supplied S=Country issue not available
+	  $avs			    = $::Values->{'avs'}             = $1 if ($line =~ /AVS=(.*)/);			#AVS Results
+	  $wafmerchmessage	= $::Values->{'wafmerchmessage'} = $1 if ($line =~ /wafMerchMessage=(.*)/);	#Risk result
+	  $authentication	= $::Values->{'authentication'}  = $1 if ($line =~ /authentication=(.*)/);	#VbyV or Mastercard Securecode authentication type
+	  $ipaddress		= $::Values->{'ipaddress'}       = $1 if ($line =~ /ipAddress=(.*)/);		#Shopper IP address
+   }
+	  $::Values->{'cardtype'} = $cardtype =~ s/\+/ /g;
+	  
+#::logDebug("WP:".__LINE__.": transid=$transid testmode=$check_testmode transstatus=$transstatus authamount=$authamount transtime=$transtime authcurrency=$authcurrency rawauthmessage=$rawauthmessage");
+#::logDebug("WP:".__LINE__.": callbackpw=$callbackpw cardtype=$cardtype countrymatch=$countrymatch avs=$avs wafmerchmessage=$wafmerchmessage authentication=$authentication ipaddress=$ipaddress");
+ 	
+ 	my $db  = Vend::Data::dbref('transactions') or die errmsg("cannot open transactions table");
+	   $dbh = $db->dbh() or die errmsg("cannot get handle for tbl 'transactions'");
 
+#::logDebug("WP:".__LINE__.": Callback order number = $wp_order_number");
 
 #if success
-if (($transstatus eq 'Y') and ($callbackpw eq $callpw)) { 
-::logDebug("WP:".__LINE__.": Transaction Suucessful");
+  if (($transstatus eq 'Y') and ($callbackpw eq $callpw)) { 
+#::logDebug("WP:".__LINE__.": Transaction Successful");
 
 	   $sth = $dbh->prepare("SELECT total_cost,email,txtype,order_number FROM transactions WHERE order_number='$wp_order_number'") or die errmsg("Cannot select from transactions tbl for $wp_order_number");
 	   $sth->execute() or die errmsg("Cannot get data from transactions tbl");
@@ -545,32 +597,31 @@ if (($transstatus eq 'Y') and ($callbackpw eq $callpw)) {
     my $email       = $d[1];
     my $txtype      = $d[2];
     my $old_tid     = $d[3];
-    my $new_order_no  = $::Values->{mv_order_number} = Vend::Interpolate::tag_counter("$ordernumber") ; #generate the IC Order Number
-    my $charged = 'WP Charged';
-
+#generate the IC Order Number, and put in session to block old ICs from generating a second number
+	my $new_order_no = $::Values->{mv_order_number} = $Vend::Session->{mv_order_number} = Vend::Interpolate::tag_counter("$ordernumber"); 
 #Check if transaction was in test mode
     if ($check_testmode > '0') { # Transaction was in test mode
 		$update_status = $update_status .'-TEST'; #Append Test to end of order status to show order was made in test mode
 		$charged = $charged .'-TEST'; #Variable we write to txtype
 		}    
-::logDebug("WP:".__LINE__.": Check testmode = $check_testmode Update Status = $update_status Set txtype = $charged");
+#::logDebug("WP:".__LINE__.": new on = $new_order_no;  Check testmode = $check_testmode Update Status = $update_status Set txtype = $charged");
 		
 #Replace temporary order number with IC order number
-::logDebug("WP:".__LINE__.": Replacing order number: Old TID = $old_tid with New Order No = $new_order_no");
-	  $sth = $dbh->prepare("UPDATE transactions SET code='$new_order_no', order_number='$new_order_no', txtype='$charged' WHERE order_number='$wp_order_number'");
-	  $stho = $dbh->prepare("UPDATE orderline SET code=replace(code, '$old_tid', '$new_order_no'), order_number='$new_order_no' WHERE order_number='$old_tid'");
-	  $stho->execute() or die errmsg("Cannot update transactions tbl for WP '$wp_order_number'");
-	  $sth->execute() or die errmsg("Cannot update transactions tbl for WP '$wp_order_number'");
+#::logDebug("WP:".__LINE__.": Replacing order number: Old TID = $old_tid with New Order No = $new_order_no");
+	   $sth = $dbh->prepare("UPDATE transactions SET code='$new_order_no', order_number='$new_order_no', txtype='$charged', payment_method='Worldpay ($cardtype)', cartid='$wp_order_number'  WHERE order_number='$wp_order_number'");
+	   $sth->execute() or die errmsg("Cannot update transactions tbl for WP '$wp_order_number'");
+	   $stho = $dbh->prepare("UPDATE orderline SET code=replace(code, '$old_tid', '$new_order_no'), order_number='$new_order_no' WHERE order_number='$old_tid'");
+	   $stho->execute() or die errmsg("Cannot update transactions tbl for WP '$wp_order_number'");
 	   
 #Log transaction information & change order status
-::logDebug("WP:".__LINE__.": Logging transaction details to tbl for order $new_order_no");
-	  $sth = $dbh->prepare("UPDATE transactions SET status='$update_status', order_id='$transid', wp_transtime='$transtime', wp_cardtype='$cardtype', wp_countrymatch='$countrymatch', wp_avs='$avs', wp_risk='$wafmerchmessage', wp_authentication='$authentication', wp_authamount='$authamount' WHERE order_number='$new_order_no'");
-	  $stho = $dbh->prepare("UPDATE orderline SET status='$update_status' WHERE order_number='$new_order_no'");
-	  $stho->execute() or die errmsg("Cannot update orderline tbl for worldpay order '$new_order_no'");
-	  $sth->execute() or die errmsg("Cannot update transactions tbl for worldpay order '$new_order_no'");
+#::logDebug("WP:".__LINE__.": Logging transaction details to tbl for order $new_order_no");
+	   $sth = $dbh->prepare("UPDATE transactions SET status='$update_status', order_id='$transid', wp_transtime='$transtime', wp_cardtype='$cardtype', wp_countrymatch='$countrymatch', wp_avs='$avs', wp_risk='$wafmerchmessage', wp_authentication='$authentication', wp_authamount='$authamount' WHERE order_number='$new_order_no'");
+	   $sth->execute() or die errmsg("Cannot update transactions tbl for worldpay order '$new_order_no'");
+	   $stho = $dbh->prepare("UPDATE orderline SET status='$update_status' WHERE order_number='$new_order_no'");
+	   $stho->execute() or die errmsg("Cannot update orderline tbl for worldpay order '$new_order_no'");
 	
 #Read the order details and cart from the database
-       $sth = $dbh->prepare("SELECT total_cost,email,order_number,fname,lname,company,address1,address2,city,state,zip,country,phone_day,fax,b_fname,b_lname,b_company,b_address1,b_address2,b_city,b_state,b_zip,b_country,shipmode,handling,order_date,lead_source,referring_url,txtype,locale,currency_locale,cart,session,salestax,shipping,b_phone FROM transactions WHERE order_number='$new_order_no'") or die errmsg("Cannot select from transactions tbl for $wp_order_number");
+       $sth = $dbh->prepare("SELECT total_cost,email,order_number,fname,lname,company,address1,address2,city,state,zip,country,phone_day,fax,b_fname,b_lname,b_company,b_address1,b_address2,b_city,b_state,b_zip,b_country,shipmode,handling,order_date,lead_source,referring_url,txtype,locale,currency_locale,cart,session,salestax,shipping,b_phone,subtotal,cartid,email_copy,mail_list,free_sample FROM transactions WHERE order_number='$new_order_no'") or die errmsg("Cannot select from transactions tbl for $wp_order_number");
        $sth->execute() or die errmsg("Cannot get data from transactions tbl");
     my @d = $sth->fetchrow_array;
     my $order_total = $::Values->{order_total} = $d[0];
@@ -596,103 +647,118 @@ if (($transstatus eq 'Y') and ($callbackpw eq $callpw)) {
     my $b_state = $::Values->{b_state} = $d[20];
     my $b_zip = $::Values->{b_zip} = $d[21];
     my $b_country = $::Values->{b_country} = $d[22];
-    my $shipmode = $::Values->{shipmode} = $d[23];
-    my $handling = $::Values->{handling} = $d[24];
+    my $shipmode = $::Values->{mv_shipmode} = $d[23];
+    my $handling = $::Values->{mv_handling} = $d[24];
     my $order_date = $::Values->{order_date} = $d[25];
-    my $lead_source = $::Session->{lead_source} = $d[26];
-    my $referring_url = $::Session->{referer} = $d[27];
+    my $lead_source = $::Values->{lead_source} = $d[26];
+    my $referring_url = $::Values->{referring_url} = $d[27];
     my $txtype = $::Values->{txtype} = $d[28];
     my $mv_locale = $d[29];
-    my $mv_currency = $d[30];
+    my $mv_currency = $d[30] || 'GBP';
     my $cart = $d[31];
     my $session = $d[32];
-    my $salestax = $d[33];
-    my $shipping = $d[34];
+    my $salestax = $d[33] || '0';
+    my $shipping = $d[34] || '0';
     my $phone_night = $::Values->{phone_night} = $d[35];
+	my $subtotal = $d[36] || '0';
+	my $cartID = $::Values->{'cartid'} = $d[37];
+    my $email_copy = $::Values->{'email_copy'} = $d[38];
+    my $mail_list = $::Values->{'mail_list'} = $d[39];
+	my $free_sample = $::Values->{'free_sample'} = $d[40];
     
     #todo add evening phone
-    
-	   $Tag->assign(  { shipping => $shipping, }  );
-	   $Tag->assign(  { salestax => $salestax, }  );
-	  
-	   $::Values->{mv_handling} = 1;
-	   $Tag->assign(  { handling => $handling, }  );
+	   $::Values->{'mv_shipmode'} ||= 'Standard';
+	   $::Values->{mv_handling} = 1 if ($handling > '0');
+	   $cartID = $wp_order_number unless defined $cartID;
+	   Vend::Interpolate::tag_assign({ subtotal => "$subtotal", shipping => "$shipping", salestax => "$salestax" });
+	   Vend::Interpolate::tag_assign({ handling => "$handling" }) if ($handling > '0');
     
 	my (@cart, $acart);
        $cart =~ s/\"/\'/g;
        $cart =~ s/\\//;
 	   @cart = eval($cart); 
 	   $acart = eval ($cart);
-	   ::logDebug("WP:".__LINE__.": cart=$cart Email=$email");	
+#::logDebug("WP:".__LINE__.": cart=$cart Email=$email");	
 	   
-	   $::Values->{mv_payment} = 'Worldpay';
+	   $::Values->{mv_payment} = 'Worldpay'." $::Values->{'cardtype'}";
 	   $::Values->{wp_order_number} = $wp_order_number;
 	   $::Session->{values}->{iso_currency_code} = $currency;
 	   $::Session->{scratch}->{mv_locale} = $mv_locale;
 	   $::Session->{scratch}->{mv_currency} = $mv_currency;
+	   $::CGI::values{'mv_todo'} = 'submit';
+	   $result{'MStatus'} = $result{'pop.status'} = 'success';
+	   $result{'order-id'} = $orderID;
+	   $result{'Status'} = 'OK';
+	   $result{'WPStatus'} = 'success';
+	   $Vend::Session->{'payment_result'} = \%result;
+
  
-::logDebug("WP:".__LINE__.": Shipmode = $shipmode Shipping = $shipping Tax = $salestax Handling = $handling");
+#::logDebug("WP:".__LINE__.": Shipmode = $shipmode Shipping = $shipping Tax = $salestax Handling = $handling");
 
 
 #Set new report title with final order number and WP transaction ID
 	if ($reporttitle == '1') {
 		my $amt = sprintf '%.2f', $order_total;
-		$::Values->{mv_order_subject} = 'Order '.$new_order_no.' : WPID:'.$transid.' : '.$mv_currency.''.$amt.' : '.$charged;
+		$::Values->{mv_order_subject} = 'Order '.$new_order_no.' : CartID '.$cartID.' : WPID:'.$transid.' : '.$mv_currency.''.$amt.' : '.$charged;
 	}       
 
 
 	if ($dec_inventory == '1') {
 #Decrement item quantities in inventory table
-	my $dbi  = dbref('inventory') or die errmsg("cannot open inventory table");
-	my $dbhi = $dbi->dbh() or die errmsg("cannot get handle for tbl 'inventory'");
+	my $dbi  = Vend::Data::database_exists_ref('inventory') or die errmsg("cannot open inventory table");
+	my $dbhi = dbconnectwp() or die errmsg("cannot get handle for tbl 'inventory'");
 	my ($sthi, $itm, $qty);
 	
-	foreach my $items (@{$acart})
-	{ 
+	foreach my $items (@{$acart})	{ 
 		$itm = $items->{'code'};
 		$qty = $items->{'quantity'};
 		$sthi = $dbh->prepare("UPDATE inventory SET quantity = quantity -'$qty' WHERE sku = '$itm'");
 		$sthi->execute() or die errmsg("Cannot update table inventory");
-::logDebug("WP:".__LINE__.": Decremented inventory for $itm by $qty");
+#::logDebug("WP:".__LINE__.": Decremented inventory for $itm by $qty");
 	}
 }
 
-
 # run custom final route which cascades 'copy_user' and 'main_entry', ie no receipt page.
     	Vend::Order::route_order("wp_final", @cart) if @cart; 
 
+		undef $Vend::Session->{mv_order_number};
 
-::logDebug("WP:".__LINE__.": End worldpay transaction success");
+#::logDebug("WP:".__LINE__.": sid=$::Session->{'id'};  End worldpay transaction success");
 }
 
 elsif ($callbackpw ne $callpw) { 
 #This should never happen unless someone tries to simulate transactions without knowing the callback password or the password is entered incorrectly in catalog.cfg or the WP admin panel
 #Transaction logged as txtype WP Pass Error and status passerror
-::logDebug("WP:".__LINE__.": Callback password was incorrect");
-::logDebug("WP:".__LINE__.": Logging transaction with callback password failure to tbl for order $wp_order_number");
-	$sth = $dbh->prepare("UPDATE transactions SET status='passerror', txtype='WP Pass Error', order_id='$transid', wp_transtime='$transtime', wp_cardtype='$cardtype', wp_countrymatch='$countrymatch', wp_avs='$avs', wp_risk='$wafmerchmessage', wp_authentication='$authentication', wp_authamount='$authamount' WHERE order_number='$wp_order_number'");
-	$stho = $dbh->prepare("UPDATE orderline SET status='passerror' WHERE order_number='$wp_order_number'");
-	$stho->execute() or die errmsg("Cannot update orderline tbl for worldpay order '$wp_order_number'");
-	$sth->execute() or die errmsg("Cannot update transactions tbl for worldpay order '$wp_order_number'");
+#::logDebug("WP:".__LINE__.": Callback password was incorrect");
+#::logDebug("WP:".__LINE__.": Logging transaction with callback password failure to tbl for order $wp_order_number");
+	$sql = "DELETE FROM transactions WHERE order_number='$wp_order_number'";
+	$sth = $dbh->prepare("$sql") or warn "sth failed\n";
+	$sth->execute() or die errmsg("Transactions tbl failed");
+	$sql = "DELETE FROM orderline WHERE order_number='$wp_order_number'";
+	$stho = $dbh->prepare("$sql") or warn "sth failed\n";
+	$stho->execute() or die errmsg("Orderline tbl failed");
 }
 
 else {
 #transaction has been cancelled
-::logDebug("WP:".__LINE__.": Transaction for order $wp_order_number was cancelled");
+#::logDebug("WP:".__LINE__.": Transaction for order $wp_order_number was cancelled");
 
 #log details of cancelled transaction & set archived to 1 so it won't show in admin panel
-::logDebug("WP:".__LINE__.": Logging cancelled transaction details to tbl for order $wp_order_number");
-	$sth = $dbh->prepare("UPDATE transactions SET status='cancelled', archived='1', txtype='WP Cancelled', order_id='$transid', wp_transtime='$transtime', wp_cardtype='$cardtype', wp_countrymatch='$countrymatch', wp_avs='$avs', wp_risk='$wafmerchmessage', wp_authentication='$authentication', wp_authamount='$authamount' WHERE order_number='$wp_order_number'");
-	$stho = $dbh->prepare("UPDATE orderline SET status='cancelled' WHERE order_number='$wp_order_number'");
-	$stho->execute() or die errmsg("Cannot update orderline tbl for worldpay order '$wp_order_number'");
-	$sth->execute() or die errmsg("Cannot update transactions tbl for worldpay order '$wp_order_number'");
-
+#::logDebug("WP:".__LINE__.": Deleting cancelled transaction details from tbl for order $wp_order_number");
+#    $dbh = dbconnectwp() or warn "dbh failed\n";
+	$sql = "DELETE FROM transactions WHERE order_number='$wp_order_number'";
+	$sth = $dbh->prepare("$sql") or warn "sth failed\n";
+	$sth->execute() or die errmsg("Transactions tbl failed");
+	$sql = "DELETE FROM orderline WHERE order_number='$wp_order_number'";
+	$sth = $dbh->prepare("$sql") or warn "sth failed\n";
+	$sth->execute() or die errmsg("Orderline tbl failed");
+	
+#	$Vend::Session->{'payment_result'}{'MStatus'} = 'cancelled';
 	}
 
   }
 	
 }
- 
 
 package Vend::Payment::Worldpay;
 



More information about the interchange-cvs mailing list