Recently I had to implement a donation form in Commerce but the Commerce Express Checkout module doesn't handle custom line items. Since it was a donation and all (who is trying to screw the house?), I felt it appropriate to pass the donation amount as a 3rd parameter in URL the Express Checkout module provides. Here is how I went about hacking the module:
I added a new entry to the router:
$items['commerce-express-checkout/%/%/%'] = array(
'title' => 'Express Checkout w/ extra argument',
// 'page callback' => 'commerce_express_checkout_create_order',
'page callback' => 'commerce_express_checkout_create_order_extra',
'page arguments' => array(1, 2, 3),
'access arguments' => array('access checkout'),
'type' => MENU_CALLBACK,
);
I duplicated and tweaked the default callback and tacked '_extra' to it. Note that the "data" property seems to be a static variable store for occasions just such as this and persists the life of the line item.
function commerce_express_checkout_create_order_extra($product_id, $token, $amount) {
if (drupal_hmac_base64($product_id, drupal_get_private_key().drupal_get_hash_salt()) == $token && is_numeric($amount)) {
global $user;
$product = commerce_product_load($product_id);
$product->commerce_price['und'][0]['amount'] = (int)$amount;
$order = ($user->uid) ? commerce_order_new($user->uid, 'checkout_checkout') : commerce_cart_order_new();
commerce_order_save($order);
$price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $amount), 'currency_code' => commerce_default_currency());
$line_item = commerce_product_line_item_new($product, 1, $order->order_id);
$line_item->data = array('und' => array('0' => $price));
commerce_line_item_save($line_item);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$order_wrapper->commerce_line_items[] = $line_item;
$order->data['type'] = 'commerce_express_checkout_order';
commerce_order_save($order);
drupal_goto('checkout/' . $order->order_id);
return "";
}
return "";
}
Here is the part that ended up being most tricky simply due to the learning curve and not knowing what the heck function to use:
/**
* Implements hook_commerce_cart_line_item_refresh().
*/
function commerce_express_checkout_commerce_cart_line_item_refresh($line_item, $order_wrapper) {
if ($line_item->commerce_product['und'][0]['line_item_label'] == 'DONATE' || $line_item->commerce_product['und'][0]['product_id'] == '11') {
$price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $line_item->data['und'][0]['amount']), 'currency_code' => commerce_default_currency());
$line_item->commerce_unit_price = array('und' => array('0' => $price));
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
$line_item_wrapper->commerce_unit_price->value(), 'base_price', $price, TRUE
);
}
}
Every single time the cart is modified, it refreshes and attempts to set the products in the cart to their in-code prototype. It seems pretty inefficient to me too, but I could be missing something.