You are here

commerce_flat_rate.module in Commerce Flat Rate 7

Allows you to define any number of flat rate shipping services for customers to choose during checkout.

File

commerce_flat_rate.module
View source
<?php

/**
 * @file
 * Allows you to define any number of flat rate shipping services for customers
 * to choose during checkout.
 */

/**
 * Implements hook_menu().
 */
function commerce_flat_rate_menu() {
  $items = array();
  $items['admin/commerce/config/shipping/methods/flat-rate/add'] = array(
    'title' => 'Add a flat rate service',
    'description' => 'Create a new flat rate shipping service, including a title and base shipping rate.',
    'page callback' => 'drupal_goto',
    'page arguments' => array(
      'admin/commerce/config/shipping/services/flat-rate/add',
    ),
    'access callback' => 'commerce_flat_rate_service_access',
    'access arguments' => array(
      'create',
    ),
    'type' => MENU_LOCAL_TASK,
    'context' => MENU_CONTEXT_INLINE,
    'weight' => 8,
  );
  $items['admin/commerce/config/shipping/services/flat-rate/add'] = array(
    'title' => 'Add a flat rate service',
    'description' => 'Create a new flat rate shipping service, including a title and base shipping rate.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'commerce_flat_rate_service_form',
      commerce_flat_rate_service_new(),
    ),
    'access callback' => 'commerce_flat_rate_service_access',
    'access arguments' => array(
      'create',
    ),
    'type' => MENU_LOCAL_ACTION,
    'context' => MENU_CONTEXT_PAGE,
    'file' => 'includes/commerce_flat_rate.admin.inc',
  );

  // Get the default flat rate service.
  $default_service_name = commerce_flat_rate_get_default_service();
  foreach (commerce_shipping_services('flat_rate') as $name => $shipping_service) {

    // Convert underscores to hyphens for the menu item argument.
    $service_name_arg = 'flat-rate-' . strtr($name, '_', '-');
    $items['admin/commerce/config/shipping/services/' . $service_name_arg . '/edit'] = array(
      'title' => 'Edit',
      'description' => 'Edit the flat rate service.',
      'page callback' => 'commerce_flat_rate_service_edit_page',
      'page arguments' => array(
        $name,
      ),
      'access callback' => 'commerce_flat_rate_service_access',
      'access arguments' => array(
        'update',
      ),
      'type' => MENU_LOCAL_TASK,
      'context' => MENU_CONTEXT_INLINE,
      'weight' => 0,
      'file' => 'includes/commerce_flat_rate.admin.inc',
    );
    $items['admin/commerce/config/shipping/services/' . $service_name_arg . '/delete'] = array(
      'title' => 'Delete',
      'description' => 'Delete the flat rate service.',
      'page callback' => 'commerce_flat_rate_service_delete_page',
      'page arguments' => array(
        $name,
      ),
      'access callback' => 'commerce_flat_rate_service_access',
      'access arguments' => array(
        'delete',
      ),
      'type' => MENU_LOCAL_TASK,
      'context' => MENU_CONTEXT_INLINE,
      'weight' => 10,
      'file' => 'includes/commerce_flat_rate.admin.inc',
    );

    // If this is not the default service, define a form menu item to set it.
    if ($name != $default_service_name) {
      $items['admin/commerce/config/shipping/services/' . $service_name_arg . '/make-default'] = array(
        'title' => 'Make default',
        'page callback' => 'drupal_get_form',
        'page arguments' => array(
          'commerce_flat_rate_service_make_default_form',
          $name,
        ),
        'access callback' => 'commerce_flat_rate_service_access',
        'access arguments' => array(
          'update',
        ),
        'type' => MENU_LOCAL_TASK,
        'context' => MENU_CONTEXT_INLINE,
        'weight' => 20,
        'file' => 'includes/commerce_flat_rate.admin.inc',
      );
    }
    else {
      $items['admin/commerce/config/shipping/services/' . $service_name_arg . '/unset-default'] = array(
        'title' => 'Unset default',
        'page callback' => 'drupal_get_form',
        'page arguments' => array(
          'commerce_flat_rate_service_unset_default_form',
        ),
        'access callback' => 'commerce_flat_rate_service_access',
        'access arguments' => array(
          'update',
        ),
        'type' => MENU_LOCAL_TASK,
        'context' => MENU_CONTEXT_INLINE,
        'weight' => 20,
        'file' => 'includes/commerce_flat_rate.admin.inc',
      );
    }
  }
  return $items;
}

/**
 * Access callback: grants users access to flat rate service operations if they
 * have the specific flat rate permission or generic shipping permission.
 *
 * @param $op
 *   The operation string: of create, update, or delete.
 *
 * @return
 *   Boolean indicating the user's access.
 */
function commerce_flat_rate_service_access($op) {
  return user_access('administer shipping') || user_access('administer flat rate services');
}

/**
 * Implements hook_permission().
 */
function commerce_flat_rate_permission() {
  return array(
    'administer flat rate services' => array(
      'title' => t('Administer flat rate shipping services.'),
      'description' => t('Allows users to create, edit and delete flat rate shipping services.'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Implements hook_commerce_shipping_method_info().
 */
function commerce_flat_rate_commerce_shipping_method_info() {
  return array(
    'flat_rate' => array(
      'title' => t('Flat rate'),
      'description' => t('Lets you create flat rate services, specifying their base rates and using Rules to apply additional rate calculation logic.'),
    ),
  );
}

/**
 * Implements hook_commerce_shipping_service_info().
 */
function commerce_flat_rate_commerce_shipping_service_info() {
  $services = array();

  // Get the default service name directly to avoid a recursive loop. It's ok in
  // this function if the service no longer exists.
  $default_service_name = variable_get('commerce_flat_rate_default_service', '');

  // Look for flat rate services currently defined in the database.
  $result = db_query('SELECT * FROM {commerce_flat_rate_service}')
    ->fetchAllAssoc('name', PDO::FETCH_ASSOC);
  if (!empty($result)) {
    foreach ($result as $name => $service) {

      // Create a base rate price array for the service
      $base_rate = array(
        'amount' => $service['amount'],
        'currency_code' => $service['currency_code'],
        'data' => array(),
      );

      // Unserialize the data array for the service.
      $data = !empty($service['data']) ? unserialize($service['data']) : array();
      $price_component_type = 'flat_rate_' . $name;

      // If the data array specifies an included tax, include it now.
      if (module_exists('commerce_tax') && !empty($data['include_tax']) && ($tax_rate = commerce_tax_rate_load($data['include_tax']))) {

        // Reverse apply the tax.
        $tax_amount = $base_rate['amount'] - $base_rate['amount'] / (1 + $tax_rate['rate']);
        $tax_amount = commerce_tax_rate_round_amount($tax_rate, $tax_amount);

        // Add a base price to the data array.
        $component = array(
          'amount' => $base_rate['amount'] - $tax_amount,
          'currency_code' => $base_rate['currency_code'],
          'data' => array(),
        );
        $base_rate['data'] = commerce_price_component_add($base_rate, $price_component_type, $component, TRUE, FALSE);

        // Add the tax to the data array.
        $component['amount'] = $tax_amount;
        $component['data']['tax_rate'] = $tax_rate;
        $base_rate['data'] = commerce_price_component_add($base_rate, $tax_rate['price_component'], $component, TRUE);
      }

      // Add the full service array to our return value.
      $services[$name] = array(
        'title' => $service['title'],
        'display_title' => !empty($service['display_title']) ? $service['display_title'] : $service['title'],
        'description' => $service['description'],
        'shipping_method' => 'flat_rate',
        'rules_component' => !empty($service['rules_component']),
        'price_component' => $price_component_type,
        'callbacks' => array(
          'rate' => 'commerce_flat_rate_service_rate_order',
        ),
        'base_rate' => $base_rate,
        'weight' => $service['weight'],
        'data' => $data,
      );

      // Add the base rate, sort order, and default status to the service's
      // description on the admin overview page.
      if (strpos(current_path(), 'admin/commerce/config/shipping') === 0 && arg(6) == '') {
        $extra_description = t('Base rate: @rate', array(
          '@rate' => commerce_currency_format($services[$name]['base_rate']['amount'], $services[$name]['base_rate']['currency_code']),
        ));
        $extra_description .= ', ' . t('Sort order: @weight', array(
          '@weight' => $service['weight'],
        ));
        if ($name == $default_service_name) {
          $extra_description .= ' ' . t('(default service)');
        }
        $services[$name]['description'] .= '<div class="sort-order-default-status">' . $extra_description . '</div>';
      }
    }
  }
  return $services;
}

/**
 * Shipping service callback: returns the base rate for a flat rate service.
 */
function commerce_flat_rate_service_rate_order($shipping_service, $order) {

  // The base rate is simply defined in the service, so we return it directly.
  return $shipping_service['base_rate'];
}

/**
 * Returns an initialized flat rate shipping service array for forms.
 */
function commerce_flat_rate_service_new() {
  return array(
    'name' => '',
    'title' => '',
    'display_title' => '',
    'description' => '',
    'rules_component' => TRUE,
    'base_rate' => array(
      'amount' => 0,
      'currency_code' => commerce_default_currency(),
      'data' => array(),
    ),
    'weight' => 1,
    'data' => array(),
    'is_new' => TRUE,
  );
}

/**
 * Saves a flat rate service to the database.
 *
 * @param $shipping_service
 *   The flat rate shipping service to save. If the service array includes the
 *   base_rate array, its amount and currency_code values will be moved up a
 *   level to be saved to the database via drupal_write_record().
 * @param $skip_reset
 *   Boolean indicating whether or not this save should result in shipping
 *   services being reset and the menu being rebuilt; defaults to FALSE. This is
 *   useful when you intend to perform many saves at once, as menu rebuilding is
 *   very costly in terms of performance.
 *
 * @return
 *   The return value of the call to drupal_write_record() to save the flat rate
 *   service; either FALSE on failure or SAVED_NEW or SAVED_UPDATED indicating
 *   the type of query performed to save the flat rate service.
 */
function commerce_flat_rate_service_save($shipping_service, $skip_reset = FALSE) {

  // Move the amount and currency code up a level in the service array.
  if (!empty($shipping_service['base_rate'])) {
    $shipping_service['amount'] = $shipping_service['base_rate']['amount'];
    $shipping_service['currency_code'] = $shipping_service['base_rate']['currency_code'];
  }
  $op = drupal_write_record('commerce_flat_rate_service', $shipping_service, empty($shipping_service['is_new']) ? 'name' : array());

  // If this is a new flat rate service and the insert did not fail...
  if (!empty($shipping_service['is_new']) && $op !== FALSE) {

    // Notify other modules that a new tax flat rate service has been created.
    module_invoke_all('commerce_flat_rate_service_insert', $shipping_service, $skip_reset);
  }
  elseif ($op !== FALSE) {

    // Notify other modules that an existing flat rate service has been updated.
    module_invoke_all('commerce_flat_rate_service_update', $shipping_service, $skip_reset);
  }

  // Clear the necessary caches and rebuild the menu items.
  if (!$skip_reset) {
    commerce_shipping_services_reset();
    entity_defaults_rebuild();
    rules_clear_cache(TRUE);
    menu_rebuild();
  }
  return $op;
}

/**
 * Deletes a flat rate service.
 *
 * @param $name
 *   The machine-name of the flat rate service.
 * @param $skip_reset
 *   Boolean indicating whether or not this delete should result in shipping
 *   services being reset and the menu being rebuilt; defaults to FALSE. This is
 *   useful when you intend to perform many deletions at once, as menu
 *   rebuilding is very costly in terms of performance.
 */
function commerce_flat_rate_service_delete($name, $skip_reset = FALSE) {
  $shipping_service = commerce_shipping_service_load($name);
  db_delete('commerce_flat_rate_service')
    ->condition('name', $name)
    ->execute();
  rules_config_delete(array(
    'commerce_shipping_service_' . $name,
  ));

  // Clear the necessary caches and rebuild the menu items.
  if (!$skip_reset) {
    commerce_shipping_services_reset();
    entity_defaults_rebuild();
    rules_clear_cache(TRUE);
    menu_rebuild();
  }

  // Notify other modules that this flat rate service has been deleted.
  module_invoke_all('commerce_flat_rate_service_delete', $shipping_service, $skip_reset);
}

/**
 * Returns the name of the default flat rate service.
 *
 * @return string
 *   The name of the default flat rate service or an empty string if it hasn't
 *   been set yet or references a service that no longer exists.
 */
function commerce_flat_rate_get_default_service() {
  $name = variable_get('commerce_flat_rate_default_service', '');
  if (!in_array($name, array_keys(commerce_shipping_services('flat_rate')))) {
    $name = '';
  }
  return $name;
}

/**
 * Sets the name of the default flat rate service.
 */
function commerce_flat_rate_set_default_service($name) {
  variable_set('commerce_flat_rate_default_service', $name);
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * - Alters the checkout form to set a default flat rate service if no other
 *   default is selected.
 */
function commerce_flat_rate_form_commerce_checkout_form_alter(&$form, &$form_state) {
  $default_service_name = commerce_flat_rate_get_default_service();

  // If there is a default flat rate service and the shipping service radios
  // element is on the current page...
  if (!empty($default_service_name) && !empty($form['commerce_shipping']['shipping_service'])) {
    $element =& $form['commerce_shipping']['shipping_service'];

    // Look for submitted shipping pane values.
    $pane_values = !empty($form_state['values']['commerce_shipping']) ? $form_state['values']['commerce_shipping'] : array();

    // First check for a shipping service selection in the pane values.
    if (!empty($pane_values['shipping_service']) && !empty($element['#options'][$pane_values['shipping_service']])) {
      $default_value = $pane_values['shipping_service'];
    }
    else {

      // Then look for one in a line item on the order already.
      $order_wrapper = entity_metadata_wrapper('commerce_order', $form_state['order']);
      foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
        if ($line_item_wrapper
          ->value() && $line_item_wrapper->type
          ->value() == 'shipping' && !empty($element['#options'][$line_item_wrapper->commerce_shipping_service
          ->value()])) {
          $default_value = $line_item_wrapper->commerce_shipping_service
            ->value();
          break;
        }
      }
    }

    // If the form didn't have a default value, it ordinarily gets set to the
    // first available shipping service. If the default flat rate service is on
    // the form, switch to that one instead.
    if (empty($default_value) || empty($element['#options'][$default_value])) {
      $default_value = $default_service_name;
      if (!empty($element['#options'][$default_value])) {
        $element['#default_value'] = $default_value;
      }
    }
  }
}

Functions

Namesort descending Description
commerce_flat_rate_commerce_shipping_method_info Implements hook_commerce_shipping_method_info().
commerce_flat_rate_commerce_shipping_service_info Implements hook_commerce_shipping_service_info().
commerce_flat_rate_form_commerce_checkout_form_alter Implements hook_form_FORM_ID_alter().
commerce_flat_rate_get_default_service Returns the name of the default flat rate service.
commerce_flat_rate_menu Implements hook_menu().
commerce_flat_rate_permission Implements hook_permission().
commerce_flat_rate_service_access Access callback: grants users access to flat rate service operations if they have the specific flat rate permission or generic shipping permission.
commerce_flat_rate_service_delete Deletes a flat rate service.
commerce_flat_rate_service_new Returns an initialized flat rate shipping service array for forms.
commerce_flat_rate_service_rate_order Shipping service callback: returns the base rate for a flat rate service.
commerce_flat_rate_service_save Saves a flat rate service to the database.
commerce_flat_rate_set_default_service Sets the name of the default flat rate service.