Drupal 7 Ubercart - Programmatically Capture Pre-Authorized Payments from Authorize.net

I'm working with Drupal 7, Ubercart, and the Authorize.net payment gateway.

The goal here is to pre-authorize the payment at check-out, and capture the payment once the items have been shipped. I'm using order status to trigger when that happens, but I wanted to just show an example of how to capture that pre-authorized transaction.

    Important notes:
  • I'm using the authorize.net gateway with 'Authorize Only' selected. I do not know if other gateways which offer authorize only transactions will work with this code. (I'd love to hear which ones do though!)
  • Authorize.net CIM Settings must be set to create a CIM profile
  • Authorize.net must be set to Live. The transaction will be authorized in test mode, but you won't be able to capture it. Please comment or send me an email if you know of a way to test this without live.

This example would be called from a module named uc_preauth_capture. You would call the following function when I'm ready to capture payment.

If the payment is successfully captures, it will return the order object. Otherwise, it will return NULL.

It is important to note that I've only done limited testing on this and it is not running in a production environment yet. I am not sure if checking strictly for 'payment_recieved' as a success flag is proper, but it works. Use with caution.

/**
* Process payment for an order which has been authorized but not captured yet.
*
* @param $order_id int The order id.
*
* @return mixed The order object if it has been processed successfully. NULL for failure.
*/
function uc_preauth_capture_process_payment($order_id) {
  $order = uc_order_load($order_id);
  // make sure there's authorizations available
  if (!isset($order->data['cc_txns']) && !isset($order->data['cc_txns']['authorizations'])) {
    return NULL;
  }
  // run through authorizations array and process first that isn't captured
  foreach ($order->data['cc_txns']['authorizations'] as $auth_id => $authorization) {
    if (!isset($authorization['captured'])) {
      $data = array(
        'auth_id' => $auth_id,
        'txn_type' => UC_CREDIT_PRIOR_AUTH_CAPTURE
      );
      uc_payment_process_payment('credit', $order->order_id, $order->order_total, $data, TRUE, NULL, FALSE);
      $order = uc_order_load(14, TRUE);
      // return the order if we've received a payment successfully
      if ($order->order_status == 'payment_received') {
        return $order;
      }
    }
  }
  return NULL;
}