How do i create a payment method+gateway with a custom function called by the gateway to determine whether payment is successful? We're looking to use a payment gateway - SecurePay in this case - that allows merchants to save credit card details in their system and then trigger payments against that credit card again for future checkouts by sending a token representing that credit card, without the user re-entering the details, and we don't need to store credit card numbers in our database.

The native handling of credit cards by UberCart, along with the uc_securepayxml module was great for the initial transaction, and storage of credit card number + token with SecurePay but the validation step on the checkout screen meant that it looks like I'll have to set up an alternative payment method + gateway to manage the sending of tokens for payment.

The problem that I'm having is getting Ubercart to fire the function that is supposed to either return success or failure when the order is finally submitted when I don't use the 'credit' payment method.

To be clear, the issue isn't (so far :P) sending the data off to SecurePay, it is convincing UberCart to use the return value of my custom function to determine whether a payment is successful or not, without using the supplied Credit Card module.

Here is all the relevant code (I think) that I'm currently using, so some advice on what needs to change or even just a working example would probably be enough to answer my question!

Using Drupal 6 and UberCart 2, and I cleared the Drupal cache a few times, btw.

&lt;?php
/* This function creates a new payment method */
function uc_securepaytoken_payment_method() {

  $methods[] = array(
    'id' =&gt; 'sptoken',
    'name' =&gt; t('SecurePay Token'),
    'title' =&gt; t('SecurePay Token'),
    'desc' =&gt; t('Pay by triggering a tokenised payment through Secure Pay.'),
    'callback' =&gt; 'uc_payment_method_sp_token', /* I believe this callback function just sets some strings for display in various places and the validation when submitting on the checkout page, is that right? */
    'weight' =&gt; 1,
    'checkout' =&gt; TRUE,
  );

return $methods;
}

/* 
* This function sets up the payment gateway, 
* I believe that if the 'sptoken' key in the $gateways array matches the ID of the payment method, 
* the function named in the value should be fired when I want to process a payment 
* (NB - This doesn't actually seem to be happening)
*/
function uc_securepaytoken_payment_gateway() {

  $gateways[] = array(
  'id' =&gt; 'securepay_token',
  'title' =&gt; t('SecurePay Tokens'),
  'description' =&gt; t('Process credit card payments using SecurePay Tokens.'),
  'settings' =&gt; 'uc_securepaytoken_settings_form',
  'sptoken' =&gt; 'uc_securepaytoken_charge',
);

return $gateways;
}

function uc_securepaytoken_charge($order_id, $amount, $data) {

  /* 
  * This is the function that I want to use to process a payment
  * and return success or failed, at the moment it doesn't seem to be working
  * and dpm() doesn't display anything, Ubercart simply always completes checkout without doing this
  */

  }

?&gt;
The answer, is that uc_payment_process() needs to be called in hook_order() when the $op variable is 'submit' with the payment method ID as the first argument.

The missing link to bring payment methods, gateways and actual payments together is as follows:

&lt;?php

/**
 * Implements hook_order
 * This is the bit that actually gets the method/gateway-combo into gear
 * when an order is submitted in the checkout process.
 */

  function uc_securepaytoken_order( $op, $arg1, $arg2 ) {

    switch( $op ) {
        case 'submit':

          if($arg1-&gt;payment_method == 'sptoken') {


            // Attempt to process the payment
            $pass = uc_payment_process( 'sptoken', $arg1-&gt;order_id, $arg1-&gt;order_total, $data, TRUE, NULL, FALSE);

            // If the payment failed, store the data back in the session and
            // halt the checkout process.

            if(!$pass) {
            $message = 'We were unable to process this payment. Please verify your details and try again. If the problem persists, contact us to complete your order';
            return array(array('pass' =&gt; FALSE, 'message' =&gt; $message ));
            }

          }

        break;
    }
}

?&gt;


The next "gotcha" is that the return value from uc_payment_process() is only TRUE if your callback function defined by the gateway returns an array that looks something like this (but with success = TRUE). Check out the uc_credit module for more clues.

&lt;?php
$result = array(
    'success' =&gt; FALSE,
    'comment' =&gt; 'Invalid transaction type',
    'message' =&gt; 'Invalid transaction type',
    'data' =&gt; array(
        'module' =&gt; 'uc_securepaytoken', 
        'transaction_id' =&gt; 0,
    ),
    'uid' =&gt; $user-&gt;uid,
    'log_payment' =&gt; 0,
);
?&gt;


For further reading check:


http://api.lullabot.com/uc_payment_process - API Reference
http://www.commerceguys.com/resources/articles/122 - Post explains uc_payment_process() and a few other UC API concepts but no explicit reference to hook_order() unfortunately :(