Jump to content
seanmccabe

SwipeHQ Process Incorrect

Recommended Posts

Hi all,

 

In the process of setting up the store to use SwipeHQs payment gateway (http://addons.oscommerce.com/info/8684), Have managed to install it correctly, but have run into a couple of issues whilst using it during a test run.

 

When I press "confirm order" an email is sent to the admin advising of the payment. This email should only occur if the payment is successful correct?

Upon returning to the store the shopping cart is not emptied.

 

I have done testing with other payment options, and the cart is emptied upon order confirmation.

 

Any help with this is appreciated. If you need images of the process please let me know. I have not modified the code of the add-on.

Share this post


Link to post
Share on other sites

Hi there

 

I've had a quick squint at the Swipe module you've linked to and it works by doing all the work in the after_process() function - if you look at the file checkout_process.php from around line 285 you'll see this (and by the time you get there the order is created and the emails have been sent)

 

// load the after_process function from the payment modules
 $payment_modules->after_process();
 $cart->reset(true);

 

The second line is what empties the cart and the first line calls in the code from the Swipe payment file. So if it sends you off to Swipe then the cart is going to stay filled - that's not very useful - it's also going to ignore the session resets that occur later in checkout_process.

 

I don't think it's well coded but it's their own presentation so you could moan at them - a quick and dirty fix would be to swap the two lines above around so that the cart is emptied before after_process() but that could impact on other payment modules.

 

Ideally all the payment stuff should take place in before_process so you do not have emails flying about before payment (also ideally osCommerce should have a during_process() payment function like Zencart but it hasn't so you're stuck with either having to steal code from core files (like checkout_process) and bung it into your payment modules (examples being the PayPal module that ships with osC 2.3.3) .

 

I've made a little edit to the swipe file that lives in catalog/includes/modules/payment/ folder. What you will get should be a customer goes through the checkout and his order is saved with a Pending status.

Email gets sent.

Cart gets emptied & sessions reset <--- new bit

Curl data is send to Swipe and if a valid response is achieved then the customer gets sent there.

Depending on what happens there Swipe should send a call back to the callback files to update the order status.

Customer gets returned to store

 

If any orders get left at 'Pending' then you'll have to go look at youe Swipe records and see if any payment was made, failed etc etc - you then have to manually update your pending order depending on what you find.

 

If no valid response to the CURL is achieved then, as far as I can see, you customer is going to be left with an order mail telling him that his order is pending and he's going to be mighty confused ('Duh - I never managed to pay, how come I have this email? I want my stuff now...rant rant')

 

OK moan/rant/ramble over here's a quick fix for the cart problem but it's still going to leave you with a crap orders system that you'll need to monitor

 

<?php
/*
 $Id$
 osCommerce, Open Source E-Commerce Solutions
 http://www.oscommerce.com
 Copyright (c) 2008 osCommerce
 Released under the GNU General Public License
*/
require_once DIR_FS_CATALOG . 'ext/modules/payment/swipehq/functions.php';
class swipehq {
   var $code, $title, $description, $enabled;

   /**
 * List of available currency codes
 * @var array
 */
   var $currencies = array (
    'NZD', 'USD', 'KRW', 'SGD', 'EUR', 'GBP', 'JPY', 'AUD', 'ZAR', 'HKD', 'CNY', 'CAD'
   );
// class constructor
   function swipehq() {
  global $order;
  $this->code = 'swipehq';
  $this->title = MODULE_PAYMENT_SWIPEHQ_TEXT_TITLE;
  $this->public_title = MODULE_PAYMENT_SWIPEHQ_TEXT_PUBLIC_TITLE;
  $this->description = MODULE_PAYMENT_SWIPEHQ_TEXT_DESCRIPTION;
  $this->sort_order = MODULE_PAYMENT_SWIPEHQ_SORT_ORDER;
  $this->enabled = ((MODULE_PAYMENT_SWIPEHQ_STATUS == 'True') ? true : false);
  if ((int)MODULE_PAYMENT_SWIPEHQ_PREPARE_ORDER_STATUS_ID > 0) {
    $this->order_status = MODULE_PAYMENT_SWIPEHQ_PREPARE_ORDER_STATUS_ID;
  }
  if (is_object($order)) $this->update_status();
   }
// class methods
   function update_status() {
  global $order;
  if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_SWIPEHQ_ZONE > 0) ) {
    $check_flag = false;
    $check_query = tep_db_query("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_SWIPEHQ_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id");
    while ($check = tep_db_fetch_array($check_query)) {
	  if ($check['zone_id'] < 1) {
	    $check_flag = true;
	    break;
	  } elseif ($check['zone_id'] == $order->billing['zone_id']) {
	    $check_flag = true;
	    break;
	  }
    }
    if ($check_flag == false) {
	  $this->enabled = false;
    }
  }
   }
   function javascript_validation() {
  return false;
   }
   /**
 * Displays payment method name along with Credit Card Information Submission Fields (if any) on the Checkout Payment Page
 *
 * @[member='Return'] array
  */
   function selection() {
  return array('id' => $this->code,
			   'module' => MODULE_PAYMENT_SWIPEHQ_TEXT_CATALOG_LOGO,
			   'icon' => MODULE_PAYMENT_SWIPEHQ_TEXT_CATALOG_LOGO
			   );
   }
   function pre_confirmation_check() {
  global $cartID, $cart;
  if (empty($cart->cartID)) {
    $cartID = $cart->cartID = $cart->generate_cart_id();
  }
  if (!tep_session_is_registered('cartID')) {
    tep_session_register('cartID');
  }
   }
   function confirmation() {
    return false;
   }
   function process_button() {
    return '';
   }
   function before_process() {
    return false;
   }
   /**
 * Post-processing activities
 * When the order returns from the processor, if PDT was successful, this stores the results in order-status-history and logs data for subsequent reference
 *
 * @[member='Return'] boolean
  */
   function after_process() {
    global $insert_id, $order;
    $order_id = $insert_id;

    if (!empty($order_id)) {
	    $currency = !empty($order->info['currency']) ? $order->info['currency'] : false;

	    if (in_array($currency, $this->currencies)) {

		    $price = round($order->info['total']*$order->info['currency_value'], 2);

		    //get list of ordered products
		    $products = '';
		    $products_list = $order->products;
		    foreach ($products_list as $product) {
			    $products .= $product['qty'] . ' x ' . $product['name'] . ($product != end($products_list) ? '<br />' : '');
		    }
		    //get product ID using TransactionIdentifier API
		    $params = array (
			    'merchant_id'		   => MODULE_PAYMENT_SWIPEHQ_MERCHANT_ID,
			    'api_key'			   => MODULE_PAYMENT_SWIPEHQ_API_KEY,
			    'td_item'			   => 'Order ID' . $order_id,
			    'td_description'	    => $products,
			    'td_amount'			 => $price,
			    'td_currency'		   => $currency,
			    'td_default_quantity'   => 1,
			    'td_user_data'		  => $order_id
		    );
		    //BT the next line sends CURL to Swipe
		    $response = shq_post_to_url('https://api.swipehq.com/createTransactionIdentifier.php', $params);
		    $response_data = json_decode($response);
		    //BT if it likes what it gets back it'll send you to Swipe
		    if ($response_data->response_code == 200 && !empty($response_data->data->identifier)) {
		    //BT NEW CODE
		    //OK so before you go - kill the cart:
			    $cart->reset(true);
   //and also kill all those pesky sessions using the code from checkout_process.php
   // unregister session variables used during checkout
   tep_session_unregister('sendto');
   tep_session_unregister('billto');
   tep_session_unregister('shipping');
   tep_session_unregister('payment');
   tep_session_unregister('comments');
   //BT end new code
			    header('Location: https://payment.swipehq.com?checkout=true&identifier_id=' . $response_data->data->identifier);
			    exit;
		    }
	    }
    }
//BT line below should really be a redirect to a payment error page/order cancellation
    echo MODULE_PAYMENT_SWIPEHQ_TEXT_ERROR_MESSAGE;
    exit;
   }
   function output_error() {
  return false;
   }
   function check() {
  if (!isset($this->_check)) {
    $check_query = tep_db_query("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_SWIPEHQ_STATUS'");
    $this->_check = tep_db_num_rows($check_query);
  }
  return $this->_check;
   }
   function install() {
  $check_query = tep_db_query("select orders_status_id from " . TABLE_ORDERS_STATUS . " where orders_status_name = 'Preparing [swipeHQ]' limit 1");
  if (tep_db_num_rows($check_query) < 1) {
    $status_query = tep_db_query("select max(orders_status_id) as status_id from " . TABLE_ORDERS_STATUS);
    $status = tep_db_fetch_array($status_query);
    $status_id = $status['status_id']+1;
    $languages = tep_get_languages();
    for ($i=0, $n=sizeof($languages); $i<$n; $i++) {
	  tep_db_query("insert into " . TABLE_ORDERS_STATUS . " (orders_status_id, language_id, orders_status_name) values ('" . $status_id . "', '" . $languages[$i]['id'] . "', 'Preparing [swipeHQ]')");
    }
    $flags_query = tep_db_query("describe " . TABLE_ORDERS_STATUS . " public_flag");
    if (tep_db_num_rows($flags_query) == 1) {
	  tep_db_query("update " . TABLE_ORDERS_STATUS . " set public_flag = 0 and downloads_flag = 0 where orders_status_id = '" . $status_id . "'");
    }
  } else {
    $check = tep_db_fetch_array($check_query);
    $status_id = $check['orders_status_id'];
  }


  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable SwipeHQ Checkout Payment Module', 'MODULE_PAYMENT_SWIPEHQ_STATUS', 'True', 'Do you want to accept SwipeHQ Checkout payments?', '6', '0', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Merchant ID', 'MODULE_PAYMENT_SWIPEHQ_MERCHANT_ID', '', 'The ID of your merchant account on merchant.swipehq.com (Settings -> API Credentials)', '6', '0', now())");
  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('API Key', 'MODULE_PAYMENT_SWIPEHQ_API_KEY', '', 'API Key is available in your merchant account (Settings -> API Credentials)', '6', '0', now())");

  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Test Mode', 'MODULE_PAYMENT_SWIPEHQ_TEST_MODE', 'Off', 'Use test mode for processing orders', '6', '0', 'tep_cfg_select_option(array(\'On\', \'Off\'), ', now())");

  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_SWIPEHQ_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '0', 'tep_get_zone_class_title', 'tep_cfg_pull_down_order_statuses(', now())");
  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_SWIPEHQ_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '0', now())");
  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Unpaid Order Status', 'MODULE_PAYMENT_SWIPEHQ_ORDER_STATUS_ID', '1', 'Set the status of unpaid orders made with this payment module to this value (recommended: Pending [1]).', '6', '0', 'tep_cfg_pull_down_order_statuses(', 'tep_get_order_status_name', now())");
  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Paid Order Status', 'MODULE_PAYMENT_SWIPEHQ_PROCESSING_STATUS_ID', '2', 'Set the status of orders made with this payment module to this value (recommended: Processing [2])', '6', '0', 'tep_cfg_pull_down_order_statuses(', 'tep_get_order_status_name', now())");
  tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Test Order Status', 'MODULE_PAYMENT_SWIPEHQ_TEST_STATUS_ID', '1', 'Set the status of orders made with test mode turning on (recommended: Pending [1])', '6', '0', 'tep_cfg_pull_down_order_statuses(', 'tep_get_order_status_name', now())");
   }

   /**
 * Remove the module and all its settings
 *
 */
   function remove() {
  tep_db_query("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
   }
   /**
 * Internal list of configuration keys used for configuration of the module
 *
 * @[member='Return'] array
 */
   function keys() {
  return array(
	  'MODULE_PAYMENT_SWIPEHQ_STATUS',
	  'MODULE_PAYMENT_SWIPEHQ_API_KEY',
	  'MODULE_PAYMENT_SWIPEHQ_MERCHANT_ID',
	  'MODULE_PAYMENT_SWIPEHQ_TEST_MODE',
	  'MODULE_PAYMENT_SWIPEHQ_ZONE',
	  'MODULE_PAYMENT_SWIPEHQ_ORDER_STATUS_ID',
	  'MODULE_PAYMENT_SWIPEHQ_PROCESSING_STATUS_ID',
	  'MODULE_PAYMENT_SWIPEHQ_TEST_STATUS_ID',
	  'MODULE_PAYMENT_SWIPEHQ_SORT_ORDER');
   }
 }
?>

Share this post


Link to post
Share on other sites

@@Bob Terveuren thank you very much for having a look at this, I really appreciate it. I have been waiting to hear something back from SwipeHQ for a couple of days and even pointed them to this post but yet to hear anything.

 

Your fix is great, should really help, I will give it a go and let you know how I get on with it. I understand about the issue with pending orders, but I think I can make that manageable by running a CRON job, that can just check the database for orders still pending every hour or more and have it email me, coupled with just checking the Swipe Mobile App, at least I will hopefully avoid any issues.

 

Will post up also if I hear anything from SwipeHQ. If not will get hold of them and certainly mention your points to them and with any luck they will be able to do a complete fix.

 

Thanks again.

Share this post


Link to post
Share on other sites

Hi there

 

To process payment via SwipeHQ we need to pass order identifier, but In Oscommerce $insert_id (order ID) is available only in the after_process() method, when email already has been sent.

We are working on this problem at the moment and a new version of add-on will be available soon (1-3 days).

 

Thank you for reporting the problem.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×