You are here

simple_package_tracking.module in Simple Package Tracking 7

Same filename and directory in other branches
  1. 6 simple_package_tracking.module

File

simple_package_tracking.module
View source
<?php

/**
 * Implements hook_shipping_menu().
 */
function simple_package_tracking_menu() {
  $items = array();

  // Actually delete a tracking number using Ajax.
  $items['simple_package_tracking_number_delete_callback/%commerce_order/%simple_package_tracking_tracking_number'] = array(
    'page callback' => 'simple_package_tracking_number_delete_response',
    'access callback' => 'user_access',
    'page arguments' => array(
      1,
      2,
    ),
    'access arguments' => array(
      'access content',
    ),
    'theme callback' => 'ajax_base_page_theme',
    'type' => MENU_CALLBACK,
  );

  // Give a warning before deletion.
  $items['simple_package_tracking_number_delete_confirm_callback/%commerce_order/%simple_package_tracking_tracking_number'] = array(
    'page callback' => 'simple_package_tracking_number_delete_confirm_response',
    'access callback' => 'user_access',
    'page arguments' => array(
      1,
      2,
    ),
    'access arguments' => array(
      'access content',
    ),
    'theme callback' => 'ajax_base_page_theme',
    'type' => MENU_CALLBACK,
  );

  // Redo any actions for a tracking number.
  $items['simple_package_tracking_number_action_callback/%commerce_order/%simple_package_tracking_tracking_number'] = array(
    'page callback' => 'simple_package_tracking_number_action_response',
    'access callback' => 'user_access',
    'page arguments' => array(
      1,
      2,
    ),
    'access arguments' => array(
      'access content',
    ),
    'theme callback' => 'ajax_base_page_theme',
    'type' => MENU_CALLBACK,
  );

  // Give a warning before redoing actions.
  $items['simple_package_tracking_number_action_confirm_callback/%commerce_order/%simple_package_tracking_tracking_number'] = array(
    'page callback' => 'simple_package_tracking_number_action_confirm_response',
    'access callback' => 'user_access',
    'page arguments' => array(
      1,
      2,
    ),
    'access arguments' => array(
      'access content',
    ),
    'theme callback' => 'ajax_base_page_theme',
    'type' => MENU_CALLBACK,
  );

  // TODO: Figure out whether this is the best way to handle this
  if (module_exists('commerce_ui')) {
    $items['admin/commerce/config/tracking/carriers'] = array(
      'title' => 'Simple package tracking',
      'description' => 'Show and edit Shipping Carriers.',
      'page callback' => 'simple_package_tracking_carriers_view',
      'access callback' => 'user_access',
      'access arguments' => array(
        'configure store',
      ),
    );
    $items['admin/commerce/config/tracking/carriers/listing'] = array(
      'title' => 'Simple package tracking carriers list',
      'description' => 'Show sample Shipping Carrier URLs.',
      'page callback' => 'simple_package_tracking_carriers_url_view',
      'access callback' => 'user_access',
      'access arguments' => array(
        'configure store',
      ),
    );
    $items['admin/commerce/config/tracking/carriers/%simple_package_tracking_carrier/edit'] = array(
      'title' => 'Edit shipping carrier',
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'simple_package_tracking_carrier_edit_form',
        5,
      ),
      'access callback' => 'user_access',
      'access arguments' => array(
        'configure store',
      ),
      'type' => MENU_CALLBACK,
    );
    $items['admin/commerce/config/tracking/carriers/%simple_package_tracking_carrier/delete'] = array(
      'title' => 'Delete shipping carrier',
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'simple_package_tracking_carrier_delete_confirm',
        5,
      ),
      'access callback' => 'user_access',
      'access arguments' => array(
        'configure store',
      ),
      'type' => MENU_CALLBACK,
    );
  }
  return $items;
}

/**
 * Implements hook_field_extra_fields().
 */
function simple_package_tracking_field_extra_fields() {
  $extra = array();
  $extra['commerce_order']['commerce_order'] = array(
    'display' => array(
      'tracking' => array(
        'label' => t('Tracking'),
        'description' => t('Allows the user to view tracking info.'),
        'weight' => 0,
      ),
      'tracking_add' => array(
        'label' => t('Add Tracking'),
        'description' => t('Allows an admin to add tracking info.'),
        'weight' => 0,
      ),
    ),
  );
  return $extra;
}

/**
 * Implements hook_entity_view().
 */
function simple_package_tracking_entity_view($entity, $entity_type, $view_mode, $langcode) {
  if ($entity_type == 'commerce_order') {

    // Optionally, integrate with views megarow, if available
    $megarow = module_exists('views_megarow');
    $click_message = FALSE;
    $table = simple_package_tracking_order_tracking_numbers_view($entity, $view_mode, -1, -1, $click_message);
    if ($view_mode == 'customer' && $table == NULL) {
      return;
    }
    $markup = '<div id="tracking-info-form-block-' . $entity->order_id . '">' . _simple_package_tracking_order_tracking_numbers_ajax_block($table, $view_mode, $entity->order_id, $click_message);
    if ($view_mode == 'customer') {
      $entity->content['tracking_lst'] = array(
        '#weight' => 5,
        '#markup' => $markup . '</div>',
        //ajax
        '#access' => commerce_order_access('view', $entity),
      );
      return;
    }
    $tracking_form = drupal_get_form('simple_package_tracking_add_tracking_form', $entity);

    // Bubble-up the signal for refreshing the parent row.
    if ($megarow && !empty($status_form['#megarow_refresh_parent'])) {
      $entity->content['#megarow_refresh_parent'] = TRUE;
    }
    $tracking_form = array(
      'tracking_list' => array(
        '#weight' => -11,
        '#markup' => $markup,
        '#access' => commerce_order_access('view', $entity),
      ),
      'add_new_header' => array(
        '#markup' => '<div class="field-label simple-package-tracking-label">' . t('Add a tracking number') . '</div>',
      ),
    ) + $tracking_form;
    $markup = '<div class="field simple-package-tracking-form">' . '<div id="tracking_messages"></div>';
    $markup .= drupal_render($tracking_form);
    $markup .= '</div>';
    $markup .= '</div>';
    $entity->content['tracking_add'] = array(
      '#weight' => 10,
      '#markup' => $markup,
      '#access' => commerce_order_access('update', $entity),
    );
  }
}
function simple_package_tracking_add_tracking_form($form, &$form_state, $order) {
  $form_state['order'] = $order;

  // Optionally, integrate with views megarow, if available
  $megarow = module_exists('views_megarow');
  if (!empty($form_state['order_tracking_saved'])) {

    // Show the status message on top of the form.
    drupal_set_message(t('A tracking number has been added to this order.'));
    if ($megarow) {

      // Send the signal to reload the parent row.
      $form['#megarow_refresh_parent'] = TRUE;
    }
  }
  $order_id = $order->order_id;
  $carriers = simple_package_tracking_get_carriers();
  $carriernames = array();
  $lastcarrier = '';
  foreach ($carriers as $key => $carrier) {
    $carriernames[$key] = $carrier['name'];
    $lastcarrier = $key;
  }
  $form['tracking_carrier'] = array(
    '#type' => 'select',
    '#title' => t('Carrier'),
    '#options' => $carriernames,
    '#attributes' => array(
      'style' => array(
        'clear:both;',
      ),
    ),
    '#default_value' => $lastcarrier,
    '#description' => t('To add, edit, or remove carriers, please visit the !link.', array(
      '!link' => l(t('setup page'), 'admin/commerce/config/tracking/carriers'),
    )),
  );
  $form['tracking_number'] = array(
    '#type' => 'textfield',
    '#title' => t('Tracking number'),
    '#size' => 30,
    '#attributes' => array(
      'onload' => array(
        'this.blur()',
      ),
    ),
  );
  $note_default_text = variable_get('simple_package_tracking_default_note_text', '');
  $form['tracking_note'] = array(
    '#type' => 'textfield',
    '#title' => t('Note to Customer'),
    '#size' => 50,
    '#default_value' => strftime($note_default_text),
    '#attributes' => array(
      'onload' => array(
        'this.blur()',
      ),
    ),
  );
  $form['do_tracking_actions'] = array(
    '#type' => 'checkbox',
    '#title' => t('Execute associated actions?'),
    '#default_value' => 1,
    '#description' => t('If checked, any events triggered by adding a tracking number (such as sending the customer an email) will be executed. If unchecked, the tracking number will be added silently.'),
  );
  $form['store']['carriers'] = array(
    '#type' => 'value',
    '#value' => $carriers,
  );
  $form['#validate'][] = 'simple_package_tracking_add_tracking_validate';
  $form['#submit'][] = 'simple_package_tracking_add_tracking_submit';
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
    '#ajax' => array(
      'callback' => 'simple_package_tracking_order_tracking_numbers_callback',
      'wrapper' => 'tracking-info-form-block-' . $order->order_id,
    ),
  );
  $form['#attached']['css'][] = drupal_get_path('module', 'simple_package_tracking') . '/css/simple-package-tracking.css';
  return $form;
}
function simple_package_tracking_add_tracking_validate($form, &$form_state) {

  // Duplicate tracking number
  // (Not an error since we added the note field - as the simplest way to fix an
  // incorrect note is to add it again then delete the old one. Add a warning instead.)

  /*if (
      simple_package_tracking_duplicate_check(
        $form_state['order']->order_id,
        $form_state['values']['tracking_number']
      )
    ) {
      form_set_error(
        'tracking_number',
        t('The tracking number you entered has already been entered for this order.')
      );
    }*/

  // For no-tracking carriers, number is disallowed, but
  // for tracking carriers, it is compulsory.
  $no_number = $form_state['values']['tracking_number'] == '' || $form_state['values']['tracking_number'] === NULL;
  $need_number = $form_state['values']['carriers'][$form_state['values']['tracking_carrier']]['url'] != '';
  if ($no_number == $need_number) {
    $message = $need_number ? t('Please enter a tracking number.') : t('The carrier you have selected does not have tracking numbers.');
    form_set_error('tracking_number', $message);
  }
}
function simple_package_tracking_add_tracking_submit($form, &$form_state) {
  global $user;
  $comment = '';
  $carriers = $form_state['values']['carriers'];
  $order = $form_state['order'];
  $order_id = $order->order_id;
  $number = $form_state['values']['tracking_number'];
  $note = $form_state['values']['tracking_note'];
  $do_tracking_actions = $form_state['values']['do_tracking_actions'];
  $carrier = $carriers[$form_state['values']['tracking_carrier']]['name'];
  $url = $carriers[$form_state['values']['tracking_carrier']]['url'];
  $optional = array();
  if (module_exists('commerce_shipping') && variable_get('simple_package_tracking_allow_all_shipping_fields', 0)) {
    $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
    $optional = $order_wrapper->commerce_customer_shipping->commerce_customer_address
      ->value();
  }
  $tracking_id = simple_package_tracking_save_tracking($order_id, $number, $url, $carrier, $note, NULL, $optional);
  if (!is_null($tracking_id)) {
    $comment = t('@carrier tracking number @number added by @name.', array(
      '@carrier' => $carrier,
      '@number' => $number,
      '@name' => $user->name,
    ));

    /*if ($form_state['values']['notify']) {
        $order = uc_order_load($order_id);
        $tracking = simple_package_tracking_tracking_number_load($tracking_id);
        ca_pull_trigger('simple_package_tracking_add_number', $order, $tracking);
        $comment .= t(' Notifcation sent to user');
      }*/
    if ($do_tracking_actions && module_exists('commerce_order')) {
      rules_invoke_event('simple_package_tracking_added', $order, $carrier, $number, $url, $note, $user);
    }
    if (module_exists('uc_order')) {
      uc_order_comment_save($form_state['values']['order_id'], $user->uid, $comment);
    }
  }
}
function simple_package_tracking_carrier_edit_form($form, &$form_state, $carrier = NULL) {
  $form_state['carrier'] = $carrier;
  $form['carrier_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Carrier name'),
    '#default_value' => isset($carrier) ? $carrier->carrier_name : '',
  );
  $form['tracking_number'] = array(
    '#type' => 'textfield',
    '#title' => t('Tracking number'),
    '#default_value' => '',
  );
  $form['carrier_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Carrier URL'),
    '#default_value' => isset($carrier) ? $carrier->carrier_url_default : '',
    '#maxlength' => 255,
  );
  $form['allow_no_tracking'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow no tracking'),
    '#checked' => 1,
    '#default_value' => $carrier->carrier_url_default != '' ? 0 : 1,
    '#description' => t('Check this box to add a carrier with an empty Carrier URL. You would want to do this if your Carrier has no tracking service.'),
  );
  $form['#validate'][] = 'simple_package_tracking_add_carrier_validate';
  $form['#submit'][] = 'simple_package_tracking_carrier_submit';
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  $form['cancel'] = array(
    '#markup' => l(t('Cancel'), 'admin/commerce/config/tracking/carriers'),
  );
  return $form;
}
function simple_package_tracking_carrier_submit($form, &$form_state) {
  global $user;
  $carrier = $form_state['carrier'];
  $id = isset($carrier) ? $carrier->carrier_id : NULL;
  $number = $form_state['values']['tracking_number'];
  $url = $form_state['values']['carrier_url'];
  $carrier_name = $form_state['values']['carrier_name'];
  $pattern = _simple_package_tracking_url_pattern_generate($url, $number);
  simple_package_tracking_save_carrier($carrier_name, $pattern, $id);
  $form_state['redirect'] = 'admin/commerce/config/tracking/carriers';
}

/**
 * @param $order_id
 * @param $number
 * @param $url
 * @param $carrier
 * @param $note
 * @param null $id
 * @param $optional
 *    Optional array with replacement patterns
 * @return \DatabaseStatementInterface|int|null
 * @throws \Exception
 */
function simple_package_tracking_save_tracking($order_id, $number, &$url, $carrier, $note, $id = NULL, $optional = array()) {
  $url = preg_replace('/\\s+/', '', $url);
  $url = str_replace('@tracking_number', $number, $url);
  foreach ($optional as $token => $value) {
    $url = str_replace('@' . $token, $value, $url);
  }
  if (!$id) {
    $query = db_insert('tracking_numbers')
      ->fields(array(
      'order_id' => $order_id,
      'tracking_number' => $number,
      'tracking_url' => $url,
      'tracking_carrier' => $carrier,
      'tracking_note' => $note,
    ));
    if ($id = $query
      ->execute()) {
      drupal_set_message(t('Added tracking for order @oid', array(
        '@oid' => $order_id,
      )));
    }
  }
  else {
    $query = db_update('tracking_numbers')
      ->fields(array(
      'order_id' => $order_id,
      'tracking_number' => $number,
      'tracking_url' => $url,
      'tracking_carrier' => $carrier,
      'tracking_note' => $note,
    ))
      ->condition('tracking_id', $id, '=');
    if ($query
      ->execute()) {
      drupal_set_message(t('Updated tracking for order @oid', array(
        '@oid' => $order_id,
      )));
    }
  }
  return $id;
}
function simple_package_tracking_get_carriers() {
  $carriers = array();
  $query = db_select('tracking_carriers', 'c')
    ->fields('c', array(
    'carrier_id',
    'carrier_name',
    'carrier_url_default',
  ))
    ->execute();
  while ($carrier = $query
    ->fetchAssoc()) {
    $carriers[$carrier['carrier_id']] = array(
      'name' => $carrier['carrier_name'],
      'url' => $carrier['carrier_url_default'],
    );
  }
  return $carriers;
}

//*****************************************************************************
function simple_package_tracking_config_form($form, &$form_state) {
  $form['heading'] = array(
    '#markup' => '<h3 style="margin-top:1.5em; margin-bottom:0em;">' . t('Configuration:') . '</h3>',
  );
  $form['default_note_text'] = array(
    '#type' => 'textfield',
    '#title' => t('Default text for tracking notes'),
    '#default_value' => variable_get('simple_package_tracking_default_note_text', ''),
    '#size' => 50,
    '#description' => t('This value will be loaded as the default text for the note field when adding a tracking number. It may contain date and time components, which will be replaced by parts of today\'s date and time. For example, "Posted on !seq" will be shown similar to: "Posted on !repl". See !url for details.', array(
      '!seq' => '%e %b %Y, %l:%M%P',
      '!repl' => '23 Oct 2014, 11:56pm',
      '!url' => '<a href="http://php.net/manual/en/function.strftime.php" target="_blank">http://php.net/manual/en/function.strftime.php</a>',
    )),
  );

  // Only supports commerce shipping.
  if (module_exists('commerce_shipping')) {
    $form['allow_all_shipping_fields'] = array(
      '#type' => 'checkbox',
      '#title' => t('Allow all shipping replacement fields'),
      '#default_value' => variable_get('simple_package_tracking_allow_all_shipping_fields', ''),
      '#description' => t('This will enable all shipping fields to be used as replacement pattern. For example "@postal_code" or "@country". Which might be needed for some carries'),
    );
  }
  $form['#submit'][] = 'simple_package_tracking_config_submit';
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}
function simple_package_tracking_config_submit($form, &$form_state) {
  if (isset($form_state['values']['default_note_text'])) {
    variable_set('simple_package_tracking_default_note_text', $form_state['values']['default_note_text']);
    drupal_set_message(t('Set the default note text to: @dflt', array(
      '@dflt' => $form_state['values']['default_note_text'],
    )));
  }
  else {
    drupal_set_message(t('Could not set the default note text.'));
  }
  if (isset($form_state['values']['allow_all_shipping_fields'])) {
    variable_set('simple_package_tracking_allow_all_shipping_fields', $form_state['values']['allow_all_shipping_fields']);
  }
}
function simple_package_tracking_carriers_add_form($form, &$form_state) {
  $form['heading'] = array(
    '#markup' => '<h3 style="margin-top:1.5em; margin-bottom:0em;">' . t('Add a New Carrier:') . '</h3>',
  );
  $form['carrier_name'] = array(
    '#type' => 'textfield',
    '#title' => t('New carrier name'),
    '#default_value' => '',
    '#size' => 30,
    '#description' => t('The carrier name should be a human-readable name for your postal service (carrier) - it will be seen by your customers.'),
  );
  $form['help'] = array(
    '#markup' => '<div>' . t('In the two fields below, you can do either of these two things to set up your new carrier:') . '<ul><li>' . t('Enter an example tracking number, and the exact URL that will show tracking for that number; or') . '</li><li>' . t('Leave the example tracking number field blank, and in the Carrier URL field, use the special marker "@tracking_number" in the URL to show where tracking numbers should be inserted to get a valid tracking URL.') . '</li></ul>' . t('To fetch suitable URL patterns for world postal services, please !link.', array(
      '!link' => l(t('click here'), 'admin/commerce/config/tracking/carriers/listing'),
    )) . '</div>',
  );
  $form['tracking_number'] = array(
    '#type' => 'textfield',
    '#title' => t('Example tracking number'),
    '#default_value' => '',
    '#size' => 30,
  );
  $form['carrier_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Carrier URL to show tracking for the example tracking number'),
    '#default_value' => '',
    '#maxlength' => 255,
    '#size' => 90,
  );
  $form['allow_no_tracking'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow no tracking'),
    '#checked' => 1,
    '#default_value' => '',
    '#description' => t('If you check this box, you may add a carrier with an empty Carrier URL. You would want to do this if your Carrier has no tracking service. The purpose is that you can attach an action to the add tracking event that is conditional on when you post via such a carrier. For example you could have a different email from the standard one, which advised the customer that the parcel had been posted, but no tracking was available. When selecting such a carrier on the order page, an empty tracking number is both permitted and compulsory.'),
  );
  $form['#validate'][] = 'simple_package_tracking_add_carrier_validate';
  $form['#submit'][] = 'simple_package_tracking_add_carrier_submit';
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}
function simple_package_tracking_add_carrier_validate($form, &$form_state) {
  $name = $form_state['values']['carrier_name'];
  $number = $form_state['values']['tracking_number'];
  $pattern = $form_state['values']['carrier_url'];
  $no_tracking = $form_state['values']['allow_no_tracking'];
  if ($name == '') {
    form_set_error('carrier_name', t('You must provide a Carrier name.'));
  }
  if ($no_tracking) {
    if ($number != '') {
      form_set_error('tracking_number', t('If you select "Allow no tracking", then the example tracking number must be blank.'));
    }
    if ($pattern != '') {
      form_set_error('carrier_url', t('If you select "Allow no tracking", then the Carrier URL must be blank.'));
    }
    return;
  }
  if ($number != '') {
    if (strpos($pattern, $number) === FALSE) {
      form_set_error('carrier_url', t('If you provide a tracking number, it must occur somewhere in the Carrier URL.'));
    }
    else {
      $form_state['values']['carrier_url'] = str_replace($number, '@tracking_number', $pattern);
    }
  }
  else {
    if (strpos($pattern, '@tracking_number') === FALSE) {
      form_set_error('carrier_url', t('If you do not provide a tracking number, you must include "@tracking_number" somewhere in the Carrier URL.'));
    }
  }
}
function simple_package_tracking_add_carrier_submit($form, &$form_state) {
  $name = $form_state['values']['carrier_name'];
  $pattern = $form_state['values']['carrier_url'];
  $form_state['redirect'] = 'admin/commerce/config/tracking/carriers';
  simple_package_tracking_save_carrier($name, $pattern);
}

//*****************************************************************************
function simple_package_tracking_save_carrier($name, $pattern, $id = NULL) {
  $pattern = preg_replace('/\\s+/', '', $pattern);
  if (!$id) {
    $query = db_insert('tracking_carriers')
      ->fields(array(
      'carrier_name' => $name,
      'carrier_url_default' => $pattern,
    ));
    if ($query
      ->execute()) {
      drupal_set_message(t('Added new carrier @carrier.', array(
        '@carrier' => $name,
      )));
    }
  }
  else {
    $query = db_update('tracking_carriers')
      ->fields(array(
      'carrier_name' => $name,
      'carrier_url_default' => $pattern,
    ))
      ->condition('carrier_id', $id, '=');
    if ($query
      ->execute()) {
      drupal_set_message(t('Updated carrier @carrier', array(
        '@carrier' => $name,
      )));
    }
  }
}
function simple_package_tracking_carrier_load($carrier_id) {
  $query = db_select('tracking_carriers', 'c')
    ->fields('c')
    ->condition('carrier_id', $carrier_id, '=')
    ->execute();
  $carrier = $query
    ->fetchObject();
  return $carrier;
}
function simple_package_tracking_tracking_number_load($tracking_id) {
  $query = db_select('tracking_numbers', 't')
    ->fields('t')
    ->condition('tracking_id', $tracking_id, '=')
    ->execute();
  $tracking = $query
    ->fetchObject();
  return $tracking;
}
function simple_package_tracking_tracking_number_load_multiple_by_order($order) {
  $query = db_select('tracking_numbers', 'n')
    ->fields('n', array(
    'tracking_id',
    'tracking_number',
    'tracking_carrier',
    'tracking_url',
  ))
    ->condition('order_id', $order->order_id, '=')
    ->execute();
  $numbers = $query
    ->fetchAllKeyed();
}

/**
 * Delete a tracking number.
 */
function simple_package_tracking_tracking_number_delete($tracking_id) {
  $delete = db_delete('tracking_numbers')
    ->condition('tracking_id', $tracking_id, '=');
  if ($delete
    ->execute()) {
    drupal_set_message(t('Tracking number has been deleted.'));
  }
  else {
    watchdog('simple_package_tracking', 'Error deleting tracking number with id @id', array(
      '@id' => $tracking_id,
    ));
  }
}

/**
 * Insert the real tracking number delete URL, with a "confirm" message.
 */
function simple_package_tracking_number_delete_confirm_response($order, $tracking, $type = 'ajax') {
  _simple_package_tracking_number_action_feedback($order, $tracking->tracking_id, -1, $type);
}

/**
 * Delete the tracking number.
 */
function simple_package_tracking_number_delete_response($order, $tracking, $type = 'ajax') {
  simple_package_tracking_tracking_number_delete($tracking->tracking_id);
  _simple_package_tracking_number_action_feedback($order, -1, -1, $type);
}
function _simple_package_tracking_number_action_feedback($order, $tracking_delete_id, $tracking_action_id, $type = 'ajax') {
  if ($type == 'ajax') {
    $table = simple_package_tracking_order_tracking_numbers_view($order, 'not-customer', $tracking_delete_id, $tracking_action_id);
    $output = _simple_package_tracking_order_tracking_numbers_ajax_block($table, 'not-customer', $order->order_id);
    $commands = array();
    $commands[] = ajax_command_replace('#tracking-information-block-' . $order->order_id, $output);

    // Remove the old messages div, clearing existing messages.
    $commands[] = ajax_command_remove('#tracking_messages');
    $commands[] = ajax_command_remove('.messages');

    // Append a new messages div with our latest errors and messages.
    $commands[] = ajax_command_prepend('#tracking-info-form-block-' . $order->order_id, '<div id="tracking_messages">' . theme('status_messages') . '</div>');
    $page = array(
      '#type' => 'ajax',
      '#commands' => $commands,
    );
    ajax_deliver($page);
  }
  else {
    $output = '';
    return $output;
  }
}

/**
 * Insert the real tracking number redo actions URL, with a "confirm" message.
 */
function simple_package_tracking_number_action_confirm_response($order, $tracking, $type = 'ajax') {
  _simple_package_tracking_number_action_feedback($order, -1, $tracking->tracking_id, $type);
}

/**
 * Redo actions for the tracking number.
 */
function simple_package_tracking_number_action_response($order, $tracking, $type = 'ajax') {
  global $user;
  rules_invoke_event('simple_package_tracking_added', $order, $tracking->tracking_carrier, $tracking->tracking_number, $tracking->tracking_url, $tracking->tracking_note, $user);
  _simple_package_tracking_number_action_feedback($order, -1, -1, $type);
}
function _simple_package_tracking_order_tracking_numbers_ajax_block($contents, $view_mode, $order_id, $click_message = FALSE) {
  $markup = '<div class="field simple-package-tracking-numbers" id="tracking-information-block-' . $order_id . '">';
  if ($contents != NULL) {
    $markup .= '<div class="field-label simple-package-tracking-numbers-label">' . t('Tracking information') . '</div>';
    $markup .= $contents;
    if ($view_mode == 'customer' && $click_message) {
      $markup .= '<div class="field">' . t('(Click the number to track parcel.)') . '</div>';
    }
  }
  $markup .= '</div>';
  return $markup;
}
function simple_package_tracking_order_tracking_numbers_callback($form, $form_state) {
  $form['tracking_number']['#value'] = '';
  $form['do_tracking_actions']['#checked'] = 1;
  $form['do_tracking_actions']['#value'] = 1;
  return '<div id="tracking-info-form-block-' . $form_state['order']->order_id . '">' . _simple_package_tracking_order_tracking_numbers_ajax_block(simple_package_tracking_order_tracking_numbers_view($form_state['order'], 'not-customer'), 'not-customer', $form_state['order']->order_id) . drupal_render($form) . '</div>';
}
function simple_package_tracking_order_tracking_numbers_view($order, $view_mode, $confirmed_delete_id = -1, $confirmed_action_id = -1, &$click = NULL) {
  $query = db_select('tracking_numbers', 'n')
    ->fields('n', array(
    'tracking_id',
    'tracking_number',
    'tracking_carrier',
    'tracking_url',
    'tracking_note',
  ))
    ->condition('order_id', $order->order_id, '=')
    ->execute();
  $rows = array();
  $nums = array();

  // for duplicate test
  $unique = 1;

  // for duplicate test
  $click_message = FALSE;
  while ($tracking = $query
    ->fetchObject()) {
    $row = array();
    $row[] = $tracking->tracking_carrier != NULL ? $tracking->tracking_carrier : t('Other');
    if ($tracking->tracking_number != '') {
      $row[] = l($tracking->tracking_number, $tracking->tracking_url, array(
        'attributes' => array(
          'target' => '_blank',
        ),
      ));
      $nums[] = $tracking->tracking_number;
      $click_message = TRUE;
    }
    else {
      $row[] = t('No tracking available');
      $nums[] = 'ignore' . $unique++;
    }
    $row[] = $tracking->tracking_note;
    if (user_access('administer commerce_order entities')) {
      drupal_add_library('system', 'drupal.ajax');
      if ($tracking->tracking_id == $confirmed_delete_id) {

        // This item has been clicked once for deletion on a second click
        $row[] = '<div>' . t('Do you really want to delete this number?') . '<br />' . l(t('Yes, delete for real!'), 'simple_package_tracking_number_delete_callback/' . $order->order_id . '/' . $tracking->tracking_id . '/nojs/', array(
          'attributes' => array(
            'class' => array(
              'use-ajax',
              'tracking-delete-confirm',
            ),
          ),
        )) . '<br />' . t('(If not, simply ignore this question.)') . '</div>';
      }
      else {

        // This item has NOT been clicked once for deletion, so go to a confirmation message
        $row[] = '<div>' . l(t('Delete'), 'simple_package_tracking_number_delete_confirm_callback/' . $order->order_id . '/' . $tracking->tracking_id . '/nojs/', array(
          'attributes' => array(
            'class' => array(
              'use-ajax',
              'tracking-delete-confirm',
            ),
          ),
        )) . '</div>';
      }
      if ($tracking->tracking_id == $confirmed_action_id) {

        // This item has been clicked once to redo actions on a second click
        $row[] = '<div>' . t('Do you really want to repeat the actions for this number?') . '<br />' . l(t('Yes, redo the actions.'), 'simple_package_tracking_number_action_callback/' . $order->order_id . '/' . $tracking->tracking_id . '/nojs/', array(
          'attributes' => array(
            'class' => array(
              'use-ajax',
              'tracking-delete-confirm',
            ),
          ),
        )) . '<br />' . t('(If not, simply ignore this question.)') . '</div>';
      }
      else {

        // This item has NOT been clicked once for redo actions, so go to a confirmation message
        $row[] = '<div>' . l(t('Redo actions'), 'simple_package_tracking_number_action_confirm_callback/' . $order->order_id . '/' . $tracking->tracking_id . '/nojs/', array(
          'attributes' => array(
            'class' => array(
              'use-ajax',
              'tracking-delete-confirm',
            ),
          ),
        )) . '</div>';
      }
    }
    $rows[] = $row;
  }
  $n = count($rows);
  if ($n === 0) {

    // If you want a message when no tracking is available, comment out
    // the following 'return NULL;' line and un-comment the next two lines.
    return NULL;

    //$row = array('No tracking information is available yet');

    //$rows = array($row);
  }
  if ($view_mode != 'customer') {

    // Mark duplicates
    $dups = array();
    for ($i = 0; $i < $n; ++$i) {
      for ($j = 0; $j < $n; ++$j) {
        if ($i == $j) {
          continue;
        }

        //if (strcmp($rows[$i][1], $rows[$j][1]) == 0) {
        if (strcmp($nums[$i], $nums[$j]) == 0) {
          $dups[] = $i;
          break;
        }
      }
    }
    foreach ($dups as $d) {
      $rows[$d][1] .= ' <b>(' . t('duplicate') . ')</b>';
    }
  }
  $headers = array();
  $output = theme('table', array(
    'header' => $headers,
    'rows' => $rows,
  ));
  if (!is_null($click)) {
    $click = $click_message;
  }
  return $output;
}
function simple_package_tracking_carriers_url_view() {
  $output = '';
  $header = array(
    t('Postal Service ID'),
    t('Tracking URL Pattern'),
    t('Select'),
  );
  $rows = array();
  $urlFile = DRUPAL_ROOT . '/' . drupal_get_path('module', 'simple_package_tracking') . '/tracking-urls.txt';
  $fh = fopen($urlFile, 'rb');
  if (!$fh) {
    return '<div>' . t('The tracking data file could not be opened.') . '</div>';
  }
  while ($theData = fgets($fh)) {
    $row = explode(' - ', $theData);
    if (count($row) == 2) {
      $row[0] = rtrim($row[0]);
      $row[1] = rtrim($row[1]);
      $row[2] = l(t('Select'), 'admin/commerce/config/tracking/carriers', array(
        'query' => array(
          'carrierid' => $row[0],
          'pattern' => $row[1],
        ),
      ));
      $rows[] = $row;
    }
  }
  fclose($fh);
  if (count($rows) === 0) {
    $rows = array(
      array(
        'data' => array(
          array(
            'data' => t('The URL file contained no valid data'),
            'colspan' => 3,
          ),
        ),
      ),
    );
  }
  $output = array(
    'title_part' => array(
      '#markup' => '<h2>' . t('List of Postal Services (Carriers) tracking URL patterns') . '</h2>',
    ),
    'instructions' => array(
      '#markup' => '<h3>' . t('Instructions:') . '</h3><div style="margin-bottom: 1em;">' . t('Locate your postal service in the following table, then click the corresponding "Select" link in the rightmost column. You will be returned to the configuration screen, and the tracking URL pattern for your chosen carrier will be pre-filled for you. Then follow the instructions on that screen to give your carrier a customer-friendly name.') . '</div><div style="margin-bottom: 1em;">' . l(t('Go back.'), 'admin/commerce/config/tracking/carriers') . '</div>',
    ),
    'listing_part' => array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'simple-package-tracking-carrier-listing',
        ),
      ),
      'list_table' => array(
        '#theme' => 'table',
        '#header' => $header,
        '#rows' => $rows,
        '#attributes' => array(),
      ),
    ),
  );
  $output = drupal_render($output);
  return $output;
}
function simple_package_tracking_carriers_view() {
  $parameters = drupal_get_query_parameters();
  $carrier_id = '';
  if (isset($parameters['carrierid'])) {
    $carrier_id = $parameters['carrierid'];
  }
  $pattern = '';
  if (isset($parameters['pattern'])) {
    $pattern = $parameters['pattern'];
  }

  //drupal_set_message("'$carrier_id' -- '$pattern'");
  $output = '';
  $carriers = simple_package_tracking_get_carriers();
  $header = array(
    t('ID'),
    t('Name'),
    t('Tracking URL'),
    t('Operations'),
  );
  $rows = array();
  $attributes = array();
  $base_path = base_path();
  foreach ($carriers as $id => $carrier) {
    $row = array();
    $row[] = $id;
    $row[] = $carrier['name'];
    $row[] = $carrier['url'];
    $row[] = t('<a href="@editlink" title="Edit this carrier">Edit</a>', array(
      '@editlink' => $base_path . 'admin/commerce/config/tracking/carriers/' . $id . '/edit',
    )) . ' &nbsp;&nbsp; ' . t('<a href="@deletelink" title="Delete this carrier">Delete</a>', array(
      '@deletelink' => $base_path . 'admin/commerce/config/tracking/carriers/' . $id . '/delete',
    ));
    $rows[] = $row;
  }
  if (count($rows) === 0) {
    $rows = array(
      array(
        'data' => array(
          array(
            'data' => t('No carriers have been added yet'),
            'colspan' => 3,
          ),
        ),
      ),
    );
  }
  $output = array(
    'title_part' => array(
      '#markup' => '<h3>' . t('Existing Carriers:') . '</h3>',
    ),
    'listing_part' => array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'simple-package-tracking-carrier-listing',
        ),
      ),
      'list_table' => array(
        '#theme' => 'table',
        '#header' => $header,
        '#rows' => $rows,
        '#attributes' => array(),
      ),
    ),
    'form_part' => array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'tracking-carrier-add-link',
        ),
      ),
      drupal_get_form('simple_package_tracking_carriers_add_form'),
    ),
    'config_part' => array(
      '#type' => 'container',
      '#attributes' => array(
        'class' => array(
          'tracking-carrier-add-link',
        ),
      ),
      drupal_get_form('simple_package_tracking_config_form'),
    ),
  );
  if ($pattern != '') {
    $output['form_part'][0]['carrier_url']['#value'] = $pattern;
    $output['form_part'][0]['help']['#markup'] = '<div>' . t('The "Carrier URL" field below has been pre-filled for your selected carrier. To use this carrier, enter a human-readable name in the "New carrier name" box above, leave the "Example tracking number" box empty, and Save.') . '</div><div>' . l(t('Get another carrier.'), 'admin/commerce/config/tracking/carriers/listing') . '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' . l(t('Reset form.'), 'admin/commerce/config/tracking/carriers');
  }
  if ($carrier_id != '') {
    $output['form_part'][0]['help']['#markup'] = '<div>' . t('You have selected carrier !id.', array(
      '!id' => "<b>{$carrier_id}</b>",
    )) . '</div>' . $output['form_part'][0]['help']['#markup'];
  }
  $output = drupal_render($output);
  return $output;
}

/******************************************************************************
 * Helper functions                                                           *
 ******************************************************************************/
function simple_package_tracking_duplicate_check($order_id, $number) {
  if ($number == '') {

    // We have to allow duplicate 'no tracking' entries because an order might be
    // split into multiple parcels, each of which is sent without tracking.
    return FALSE;
  }
  $query = db_select('tracking_numbers', 'n');
  $result = $query
    ->fields('n', array(
    'tracking_number',
  ))
    ->condition('order_id', $order_id, '=')
    ->execute();
  $numbers = array();
  while ($num = $result
    ->fetchAssoc()) {
    $numbers[] = $num['tracking_number'];
  }
  if (in_array($number, $numbers)) {
    return TRUE;
  }
  return FALSE;
}
function _simple_package_tracking_url_pattern_generate($url, $number) {
  if ($number == '') {
    return $url;
  }
  $tnpos = strpos($url, $number);
  $tnlen = strlen($number);
  $patstart = substr($url, 0, $tnpos);
  $patend = substr($url, $tnpos + $tnlen, strlen($url));
  $pattern = $patstart . '@tracking_number' . $patend;
  return $pattern;
}

/******************************************************************************
 * Ubercart hooks                                                             *
 ******************************************************************************/

/**
 * Implements hook_order_pane().
 */
function simple_package_tracking_order_pane() {
  $panes[] = array(
    'id' => 'tracking_simple',
    'callback' => 'simple_package_tracking_order_pane_tracking_numbers',
    'title' => t('Tracking numbers'),
    'desc' => t('Display tracking numbers of shipped packages.'),
    'class' => 'pos-left',
    'weight' => 7,
    'show' => array(
      'view',
      'invoice',
      'customer',
    ),
  );
  return $panes;
}

/**
 * Shipping order pane callback.
 *
 * @see uc_shipping_order_pane()
 */
function simple_package_tracking_order_pane_tracking_numbers($op, $order) {
  switch ($op) {
    case 'view':
    case 'customer':
      $rows = array();
      $result = db_query("SELECT tracking_id, tracking_number, tracking_carrier, tracking_url FROM {tracking_numbers} WHERE order_id = %d", $order->order_id);
      while ($tracking = db_fetch_object($result)) {
        $row = array();
        $row[] = $tracking->tracking_carrier != NULL ? $tracking->tracking_carrier : t('Other');
        $row[] = l($tracking->tracking_number, $tracking->tracking_url, array(
          'attributes' => array(
            'target' => '_blank',
          ),
        ));
        if (user_access('administer commerce_order entities')) {
          $row[] = l(t('Delete'), 'admin/store/orders/' . $order->order_id . '/tracking/' . $tracking->tracking_id . '/delete');
        }
        $rows[] = $row;
      }
      if (count($rows)) {
        $headers = array();
        $output = theme('table', $header, $rows);
        return $output;
      }
      break;
  }
}

/******************************************************************************
 * Tokens - old D6 code. Email notification is working in D7 without this code.
 * To be removed if nothing is found to need it later.
 ******************************************************************************/

/**
 * Implements hook_token_values(). (token.module)
 */

/*function simple_package_tracking_token_values($type, $object = NULL) {
  $values = array();

  switch ($type) {
    case 'tracking':
      $tracking = $object;
      $values['tracking-carrier'] = $tracking->tracking_carrier;
      $values['tracking-number'] = $tracking->tracking_number;
      $values['tracking-number-link'] = l($tracking->tracking_number, $tracking->tracking_url);
      break;
  }

  return $values;
}*/

/**
 * Implements hook_token_list(). (token.module)
 */

/*function simple_package_tracking_token_list($type = 'all') {
  $tokens = array();

  if ($type == 'tracking') {
    $tokens['tracking']['tracking-carrier'] = t('The carrier associated with a tracking number.');
    $tokens['tracking']['tracking-number'] = t('A tracking number for an order.');
    $tokens['tracking']['tracking-number-link'] = t('The link to track a shipment.');
  }

  return $tokens;
}*/

//******************************************************************************

/**
 * Implements hook_uc_message().
 */
function simple_package_tracking_uc_message() {
  $messages['simple_package_tracking_tracking_notification_subject'] = t('Shipment for order [order-id] at [store-name]');
  $messages['simple_package_tracking_tracking_notification_message'] = t("Hello,\n\nWe just wanted to let you know that a shipment is on it's way for order [order-link] via [tracking-carrier]. For your convenience, here is the tracking number [tracking-number-link]. You can use this to track your shipment on the [tracking-carrier] website.\n\nAs always, if you have any questions, please give us a call at [store-phone] if you have any questions. Thanks!\n\n-- The [store-name] team");
  return $messages;
}
function simple_package_tracking_ca_entity() {
  $entities['tracking_number'] = array(
    '#title' => t('Ubercart tracking number'),
    '#type' => 'object',
  );
  return $entities;
}

/**
 * Implements hook_ca_predicate().
 */
function simple_package_tracking_ca_predicate() {
  $predicates = array();

  // Notify the user when a role is granted.
  $predicates['simple_package_tracking_add_number'] = array(
    '#title' => t('A tracking number is added'),
    '#description' => t('A tracking number is added.'),
    '#class' => 'notification',
    '#trigger' => 'simple_package_tracking_add_number',
    '#status' => 1,
    '#actions' => array(
      array(
        '#name' => 'simple_package_tracking_tracking_email',
        '#title' => t('Send an e-mail to the customer'),
        '#argument_map' => array(
          'order' => 'order',
          'tracking_number' => 'tracking_number',
        ),
        '#settings' => array(
          'from' => uc_store_email_from(),
          'addresses' => '[order-email]',
          'subject' => uc_get_message('simple_package_tracking_tracking_notification_subject'),
          'message' => uc_get_message('simple_package_tracking_tracking_notification_message'),
          'format' => 1,
        ),
      ),
    ),
  );
  return $predicates;
}
function simple_package_tracking_ca_action() {
  $actions['simple_package_tracking_tracking_email'] = array(
    '#title' => t('Send a tracking number notification to a user.'),
    '#category' => t('Notification'),
    '#callback' => 'simple_package_tracking_action_tracking_email',
    '#arguments' => array(
      'order' => array(
        '#entity' => 'uc_order',
        '#title' => t('Order'),
      ),
      'tracking_number' => array(
        '#entity' => 'uc_tracking_number',
        '#title' => t('Tracking Number'),
      ),
    ),
  );
  return $actions;
}
function simple_package_tracking_ca_trigger() {
  $triggers['simple_package_tracking_add_number'] = array(
    '#title' => t('A tracking number is added'),
    '#category' => t('Fulfillment'),
    '#arguments' => array(
      'order' => array(
        '#entity' => 'uc_order',
        '#title' => t('Order'),
      ),
      'tracking_number' => array(
        '#entity' => 'uc_tracking_number',
        '#title' => t('Tracking Number'),
      ),
    ),
  );
  return $triggers;
}
function simple_package_tracking_action_tracking_email($order, $tracking, $settings) {
  $account = uc_order_user_load($order);

  // Token replacements for the subject and body
  $settings['replacements'] = array(
    'global' => NULL,
    'order' => $order,
    'user' => $account,
    'tracking' => $tracking,
  );
  $recipients = array();
  $addresses = token_replace_multiple($settings['addresses'], $settings['replacements']);
  foreach (explode("\n", $addresses) as $address) {
    $recipients[] = trim($address);
  }

  // Send to each recipient
  foreach ($recipients as $email) {
    $sent = drupal_mail('uc_order', 'action-mail', $email, uc_store_mail_recipient_language($email), $settings, $settings['from']);
    if (!$sent['result']) {
      watchdog('ca', 'Attempt to e-mail @email concerning order @order_id failed.', array(
        '@email' => $email,
        '@order_id' => $order->order_id,
      ), WATCHDOG_ERROR);
    }
  }
}
function simple_package_tracking_action_tracking_email_form($form_state, $settings = array()) {
  return ca_build_email_form($form_state, $settings, array(
    'global',
    'tracking',
    'user',
    'order',
  ));
}

/**
 * Implements hook_rules_event_info().
 */
function simple_package_tracking_rules_event_info() {
  $items = array(
    'simple_package_tracking_added' => array(
      'label' => t('A tracking number is added to order'),
      'group' => t('Commerce Order'),
      'variables' => array(
        'commerce_order' => array(
          'type' => 'commerce_order',
          'label' => t('Commerce order'),
        ),
        'tracking_carrier' => array(
          'type' => 'text',
          'label' => t('Carrier name.'),
        ),
        'tracking_number' => array(
          'type' => 'text',
          'label' => t('Tracking number.'),
        ),
        'tracking_url' => array(
          'type' => 'text',
          'label' => t('URL to Carrier site with tracking number.'),
        ),
        'tracking_note' => array(
          'type' => 'text',
          'label' => t('Note to customer for this shipment.'),
        ),
        'account' => array(
          'type' => 'user',
          'label' => t('Customer.'),
        ),
      ),
    ),
  );
  return $items;
}

/**
 * Delete a carrier.
 */
function simple_package_tracking_carrier_delete($carrier_id) {
  $delete = db_delete('tracking_carriers')
    ->condition('carrier_id', $carrier_id, '=');
  if ($delete
    ->execute()) {
    drupal_set_message(t('Tracking number has been deleted.'));
  }
  else {
    watchdog('simple_package_tracking', 'Error deleting carrier with id @id', array(
      '@id' => $carrier_id,
    ));
  }
}
function simple_package_tracking_carrier_delete_confirm($form, &$form_state, $carrier) {
  $form = array();
  $form['carrier_id'] = array(
    '#type' => 'value',
    '#value' => $carrier->carrier_id,
  );
  $output = confirm_form($form, t('Are you sure you want to delete carrier @c, "@n"?', array(
    '@c' => $carrier->carrier_id,
    '@n' => $carrier->carrier_name,
  )), 'admin/commerce/config/tracking/carriers', t('Only the carrier settings are deleted; existing tracking data remains in place.'), t('Delete'), t('Cancel'));
  return $output;
}
function simple_package_tracking_carrier_delete_confirm_submit($form, &$form_state) {
  simple_package_tracking_carrier_delete($form_state['values']['carrier_id']);
  $form_state['redirect'] = 'admin/commerce/config/tracking/carriers';
}

Functions

Namesort descending Description
simple_package_tracking_action_tracking_email
simple_package_tracking_action_tracking_email_form
simple_package_tracking_add_carrier_submit
simple_package_tracking_add_carrier_validate
simple_package_tracking_add_tracking_form
simple_package_tracking_add_tracking_submit
simple_package_tracking_add_tracking_validate
simple_package_tracking_carriers_add_form
simple_package_tracking_carriers_url_view
simple_package_tracking_carriers_view
simple_package_tracking_carrier_delete Delete a carrier.
simple_package_tracking_carrier_delete_confirm
simple_package_tracking_carrier_delete_confirm_submit
simple_package_tracking_carrier_edit_form
simple_package_tracking_carrier_load
simple_package_tracking_carrier_submit
simple_package_tracking_ca_action
simple_package_tracking_ca_entity
simple_package_tracking_ca_predicate Implements hook_ca_predicate().
simple_package_tracking_ca_trigger
simple_package_tracking_config_form
simple_package_tracking_config_submit
simple_package_tracking_duplicate_check
simple_package_tracking_entity_view Implements hook_entity_view().
simple_package_tracking_field_extra_fields Implements hook_field_extra_fields().
simple_package_tracking_get_carriers
simple_package_tracking_menu Implements hook_shipping_menu().
simple_package_tracking_number_action_confirm_response Insert the real tracking number redo actions URL, with a "confirm" message.
simple_package_tracking_number_action_response Redo actions for the tracking number.
simple_package_tracking_number_delete_confirm_response Insert the real tracking number delete URL, with a "confirm" message.
simple_package_tracking_number_delete_response Delete the tracking number.
simple_package_tracking_order_pane Implements hook_order_pane().
simple_package_tracking_order_pane_tracking_numbers Shipping order pane callback.
simple_package_tracking_order_tracking_numbers_callback
simple_package_tracking_order_tracking_numbers_view
simple_package_tracking_rules_event_info Implements hook_rules_event_info().
simple_package_tracking_save_carrier
simple_package_tracking_save_tracking
simple_package_tracking_tracking_number_delete Delete a tracking number.
simple_package_tracking_tracking_number_load
simple_package_tracking_tracking_number_load_multiple_by_order
simple_package_tracking_uc_message Implements hook_uc_message().
_simple_package_tracking_number_action_feedback
_simple_package_tracking_order_tracking_numbers_ajax_block
_simple_package_tracking_url_pattern_generate