You are here

function commerce_order_calculate_total in Commerce Core 7

Calculates the order total, updating the commerce_order_total field data in the order object this function receives.

Parameters

$order: The order object whose order total should be calculated.

See also

commerce_line_items_total()

1 call to commerce_order_calculate_total()
CommerceOrderEntityController::save in modules/order/includes/commerce_order.controller.inc
Saves an order.

File

modules/order/commerce_order.module, line 1295
Defines the core Commerce order entity and API functions to manage orders and interact with them.

Code

function commerce_order_calculate_total($order) {
  $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

  // First determine the currency to use for the order total.
  $default_currency_code = $currency_code = commerce_default_currency();
  $currencies = array();

  // Populate an array of how many line items on the order use each currency.
  foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {

    // If the current line item actually no longer exists...
    if (!$line_item_wrapper
      ->value()) {

      // Remove the reference from the order and continue to the next value.
      $order_wrapper->commerce_line_items
        ->offsetUnset($delta);
      continue;
    }
    $line_item_currency_code = $line_item_wrapper->commerce_total->currency_code
      ->value();
    if (!isset($currencies[$line_item_currency_code])) {
      $currencies[$line_item_currency_code] = 1;
    }
    else {
      $currencies[$line_item_currency_code]++;
    }
  }
  reset($currencies);

  // If only one currency is present on the order, use that to calculate the
  // order total.
  if (count($currencies) == 1) {
    $currency_code = key($currencies);
  }
  elseif (isset($currencies[$default_currency_code])) {

    // Otherwise use the site default currency if it's in the order.
    $currency_code = $default_currency_code;
  }
  elseif (count($currencies) > 1) {

    // Otherwise use the first currency on the order. We do this instead of
    // trying to determine the most dominant currency for now because using the
    // first currency leaves the option open for a UI based module to let
    // customers reorder the items in the cart by currency to get the order
    // total in a different currency. The currencies array still contains useful
    // data, though, should we decide to expand on the count by currency approach.
    $currency_code = key($currencies);
  }

  // Initialize the order total with the selected currency.
  $order_wrapper->commerce_order_total->amount = 0;
  $order_wrapper->commerce_order_total->currency_code = $currency_code;

  // Reset the data array of the order total field to only include a
  // base price component, set the currency code from any line item.
  $base_price = array(
    'amount' => 0,
    'currency_code' => $currency_code,
    'data' => array(),
  );
  $order_wrapper->commerce_order_total->data = commerce_price_component_add($base_price, 'base_price', $base_price, TRUE);
  $order_total = $order_wrapper->commerce_order_total
    ->value();

  // Then loop over each line item and add its total to the order total.
  $amount = 0;
  foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {

    // Convert the line item's total to the order's currency for totalling.
    $line_item_total = $line_item_wrapper->commerce_total
      ->value();
    $component_total = commerce_price_component_total($line_item_total);

    // Add the totals.
    $amount += commerce_currency_convert($component_total['amount'], $component_total['currency_code'], $currency_code);

    // Combine the line item total's component prices into the order total.
    $order_total['data'] = commerce_price_components_combine($order_total, $line_item_total);
  }

  // Update the order total price field with the final total amount and data.
  $order_wrapper->commerce_order_total->amount = round($amount);
  $order_wrapper->commerce_order_total->data = $order_total['data'];
}