Thanks @bob!
Just a bit of background: I'm dealing with a 3rd party order fulfillment company who provides me with an API to generate orders in their Magento system after orders are created in my Drupal Commerce system. The 3rd party passes back the order number from the Magento API, which I store as $order->field_vendor_order_number
in Drupal Commerce. Later I actually replace the Drupal Commerce $order->order_number
with the custom field I created to temporarily hold the 3rd party's order number. I do this after successfully processing the customer's payment, so unfortunately all the checkout pages leading up to the "thank you" page still have the internal commerce order_id
in the url because the order hasn't been created in the 3rd party's system yet, and therefore I don't have the proper order number that I want to show the customer yet.
Here are the rules, actions, and callbacks that send an order to the 3rd party and save the order number they respond with as the new Drupal Commerce order_number
:
/**
* Implements hook_default_rules_configuration().
*/
function example_store_default_rules_configuration() {
$rules = array();
/**
* Add a reaction rule to send the order to 3rd party for fulfillment upon checkout completion.
*/
$rule = rules_reaction_rule();
$rule->label = t('Send Order for Fulfillment');
$rule->tags = array('Example Store');
$rule->active = TRUE;
$rule
->event('commerce_checkout_complete')
->action('example_store_send_order_for_fulfillment', array(
'commerce_order:select' => 'commerce-order',
));
$rule->weight = 1;
$rules['example_store_send_order_for_fulfillment_rule'] = $rule;
/**
* Add a reaction rule to update the order number to the one assigned by 3rd party fulfillment upon checkout completion.
*/
$rule = rules_reaction_rule();
$rule->label = t('Assign Fulfillment Order Number');
$rule->tags = array('Example Store');
$rule->active = TRUE;
$rule
->event('commerce_checkout_complete')
->action('example_store_assign_fulfillment_order_number', array(
'commerce_order:select' => 'commerce-order',
));
$rule->weight = 2;
$rules['example_store_assign_fulfillment_order_number_rule'] = $rule;
return $rules;
}
/**
* Implements hook_rules_action_info().
*/
function example_store_rules_action_info() {
$actions = array();
$actions['example_store_send_order_for_fulfillment'] = array(
'label' => t('Send Order for Fulfillment'),
'parameter' => array(
'commerce_order' => array(
'type' => 'commerce_order',
'label' => t('Order to send for fulfillment'),
),
),
'group' => t('Example Store'),
'callbacks' => array(
'execute' => 'example_store_send_order_for_fulfillment_callback',
),
);
$actions['example_store_assign_fulfillment_order_number'] = array(
'label' => t('Assign Fulfillment Order Number'),
'parameter' => array(
'commerce_order' => array(
'type' => 'commerce_order',
'label' => t('Order to assign a new fulfillment order number'),
),
),
'group' => t('Example Store'),
'callbacks' => array(
'execute' => 'example_store_assign_fulfillment_order_number_callback',
),
);
return $actions;
}
/**
* Callback for rules action to send the order for fulfillment to 3rd party API and process the response
* Save the 3rd party order number into a custom field on the order entity
*/
function example_store_send_order_for_fulfillment_callback($order) {
include_once DRUPAL_ROOT . '/services/ExampleStoreService.php';
$objExampleStoreService = new ExampleStoreService();
$arrResponse = $objExampleStoreService->SendOrder($order);
if ($arrResponse['status'] === 'success') {
$order->field_vendor_order_number['und'][0]['value'] = $arrResponse['order_number'];
$order->log = 'Order Number from 3rd party is: '.$order->field_vendor_order_number['und'][0]['value'];
$order->revision = TRUE;
commerce_order_save($order);
}
}
/**
* Callback for rules action to assign the new order number received from 3rd party fulfillment
* Take the order number stored in the custom field and actually save it as the order entity's order_number
*/
function example_store_assign_fulfillment_order_number_callback($order) {
if (isset($order->field_vendor_order_number['und'][0]['value']) && !empty($order->field_vendor_order_number['und'][0]['value'])) {
$order->order_number = $order->field_vendor_order_number['und'][0]['value'];
$order->log = 'Order Number '.$order->order_number.' saved.';
$order->revision = TRUE;
commerce_order_save($order);
}
}
However instead of going to the default "Checkout Complete" page, I created a rule that reacts to the checkout_complete event by redirecting to "store/order/[commerce-order:order-number]". Notice it has a weight of 10, to ensure it's the last thing I want to do when reacting to the checkout_complete
event.
{ "rules_redirect_to_custom_checkout_complete_page" : {
"LABEL" : "Redirect to custom checkout complete page",
"PLUGIN" : "reaction rule",
"WEIGHT" : "10",
"TAGS" : [ "Commerce Checkout", "Example Store" ],
"REQUIRES" : [ "php", "rules", "commerce_checkout" ],
"ON" : [ "commerce_checkout_complete" ],
"DO" : [
{ "redirect" : { "url" : "store\/order\/[commerce-order:order-number]\/" } }
]
}
}
I added a hook_menu
entry for this, which accepts the order_number instead of the internal commerce order_id as an url argument:
/**
* Implements hook_menu().
*/
function example_store_menu() {
$items['store/order/%'] = array(
'page callback' => '_example_store_order_view',
'page arguments' => array(2),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Custom page callback for store/order/%
* @param string $order_number - order number from 3rd party fulfillment api
* @return array - order as renderable array
*/
function _example_store_order_view($order_number) {
if (!empty($order_number)) {
$order = commerce_order_load_by_number($order_number);
}
if (!empty($order)) {
$entity_view = entity_view('commerce_order', array($order->order_id => $order), 'customer', NULL, TRUE);
return theme('example_store_order_complete_thank_you', array('entity_view' => $entity_view));
}
else {
drupal_set_message(t("No order was found for order number ". $order_number . ". Please check your order number to make sure it is correct."), 'error');
drupal_goto('store');
}
}
And a custom hook_theme
entry to handle the template for this custom "Order Complete Thank You" page, which mainly just displays the rendered order entity. If you have any Google Analytics e-commerce tracking code, this is the template in which you'd want to place those scripts. I'm not displaying it in this stripped down example, but I rigged mine up to only render those scripts on the first visit of this page, that was if the customer refreshes the thank you page, Google Analytics won't see duplicate tracking.
/**
* Implements hook_theme().
*/
function example_store_theme($existing, $type, $theme, $path) {
$module_path = drupal_get_path('module', 'example_store');
return array(
'example_store_order_complete_thank_you' => array(
'variables' => array(
'entity_view' => NULL,
),
'template' => 'example-store-order-complete-thank-you',
'path' => $module_path.'/templates',
),
);
}
Contents of example-store-order-complete-thank-you.tpl.php
:
//Render the order entity
print render($entity_view);