[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/default/files/hooks/ -> ubercart.hooks.php (source)

   1  <?php
   2  
   3  /**
   4   * @file
   5   * These are the hooks that are invoked by the Ubercart core.
   6   *
   7   * Core hooks are typically called in all modules at once using
   8   * module_invoke_all().
   9   */
  10  
  11  /**
  12   * @addtogroup hooks
  13   * @{
  14   */
  15  
  16  /**
  17   * Do extra processing when an item is added to the shopping cart.
  18   *
  19   * Some modules need to be able to hook into the process of adding items to a
  20   * cart. For example, an inventory system may need to check stock levels and
  21   * prevent an out of stock item from being added to a customer's cart. This hook
  22   * lets developers squeeze right in at the end of the process after the product
  23   * information is all loaded and the product is about to be added to the cart.
  24   * In the event that a product should not be added to the cart, you simply have
  25   * to return a failure message described below. This hook may also be used simply
  26   * to perform some routine action when products are added to the cart.
  27   *
  28   * @param $nid
  29   *   The node ID of the product
  30   * @param $qty
  31   *   The quantity being added
  32   * @param $data
  33   *   The data array, including attributes and model number adjustments
  34   * @return
  35   *   The function can use this data to whatever purpose to see if the item can
  36   *   be added to the cart or not. The function should return an array containing
  37   *   the result array. (This is due to the nature of Drupal's module_invoke_all()
  38   *   function. You must return an array within an array or other module data will
  39   *   end up getting ignored.) At this moment, there are only three keys:
  40   *   - "success": TRUE or FALSE for whether the specified quantity of the item
  41   *       may be added to the cart or not; defaults to TRUE.
  42   *   - "message": the fail message to display in the event of a failure; if
  43   *       omitted, Ubercart will display a default fail message.
  44   *   - "silent": return TRUE to suppress the display of any messages; useful
  45   *       when a module simply needs to do some other processing during an add to
  46   *       cart or fail silently.
  47   */
  48  function hook_add_to_cart($nid, $qty, $data) {
  49    if ($qty > 1) {
  50      $result[] = array(
  51        'success' => FALSE,
  52        'message' => t('Sorry, you can only add one of those at a time.'),
  53      );
  54    }
  55    return $result;
  56  }
  57  
  58  /**
  59   * Add extra information to a cart item's "data" array.
  60   *
  61   * This is effectively the submit handler of any alterations to the Add to Cart
  62   * form. It provides a standard way to store the extra information so that it
  63   * can be used by hook_add_to_cart().
  64   *
  65   * @param $form_values
  66   *   The values submitted to the Add to Cart form.
  67   * @return
  68   *   An array of data to be merged into the item added to the cart.
  69   */
  70  function hook_add_to_cart_data($form_values) {
  71    $node = node_load($form_values['nid']);
  72    return array('module' => 'uc_product', 'shippable' => $node->shippable);
  73  }
  74  
  75  /**
  76   * Calculate tax line items for an order.
  77   *
  78   * @param $order
  79   *   An order object or an order id.
  80   * @return
  81   *   An array of tax line item objects keyed by a module-specific id.
  82   */
  83  function hook_calculate_tax($order) {
  84    global $user;
  85    if (is_numeric($order)) {
  86      $order = uc_order_load($order);
  87      $account = user_load(array('uid' => $order->uid));
  88    }
  89    elseif ((int)$order->uid) {
  90      $account = user_load(array('uid' => intval($order->uid)));
  91    }
  92    else {
  93      $account = $user;
  94    }
  95    if (!is_object($order)) {
  96      return array();
  97    }
  98    if (empty($order->delivery_postal_code)) {
  99      $order->delivery_postal_code = $order->billing_postal_code;
 100    }
 101    if (empty($order->delivery_zone)) {
 102      $order->delivery_zone = $order->billing_zone;
 103    }
 104    if (empty($order->delivery_country)) {
 105      $order->delivery_country = $order->billing_country;
 106    }
 107  
 108    $order->taxes = array();
 109  
 110    if (isset($order->order_status)) {
 111      $state = uc_order_status_data($order->order_status, 'state');
 112      $use_same_rates = in_array($state, array('payment_received', 'completed'));
 113    }
 114    else {
 115      $use_same_rates = FALSE;
 116    }
 117  
 118    $arguments = array(
 119      'order' => array(
 120        '#entity' => 'uc_order',
 121        '#title' => t('Order'),
 122        '#data' => $order,
 123      ),
 124      'tax' => array(
 125        '#entity' => 'tax',
 126        '#title' => t('Tax rule'),
 127        // #data => each $tax in the following foreach() loop;
 128      ),
 129      'account' => array(
 130        '#entity' => 'user',
 131        '#title' => t('User'),
 132        '#data' => $account,
 133      ),
 134    );
 135  
 136    $predicates = ca_load_trigger_predicates('calculate_taxes');
 137    foreach (uc_taxes_rate_load() as $tax) {
 138      if ($use_same_rates) {
 139        foreach ((array)$order->line_items as $old_line) {
 140          if ($old_line['type'] == 'tax' && $old_line['data']['tax_id'] == $tax->id) {
 141            $tax->rate = $old_line['data']['tax_rate'];
 142            break;
 143          }
 144        }
 145      }
 146  
 147      $arguments['tax']['#data'] = $tax;
 148      if (ca_evaluate_conditions($predicates['uc_taxes_'. $tax->id], $arguments)) {
 149        $line_item = uc_taxes_action_apply_tax($order, $tax);
 150        if ($line_item) {
 151          $order->taxes[$line_item->id] = $line_item;
 152        }
 153      }
 154    }
 155  
 156    return $order->taxes;
 157  }
 158  
 159  /**
 160   * Control the display of an item in the cart.
 161   *
 162   * Product type modules allow the creation of nodes that can be added to the
 163   * cart. The cart determines how they are displayed through this hook. This is
 164   * especially important for product kits, because it may be displayed as a single
 165   * unit in the cart even though it is represented as several items.
 166   *
 167   * @param $item
 168   *   The item in the cart to display.
 169   * @return
 170   *   A form array containing the following elements:
 171   *   - "nid"
 172   *     - #type: value
 173   *     - #value: The node id of the $item.
 174   *   - "module"
 175   *     - #type: value
 176   *     - #value: The module implementing this hook and the node represented by
 177   *       $item.
 178   *   - "remove"
 179   *     - #type: checkbox
 180   *     - #value: If selected, removes the $item from the cart.
 181   *   - "description"
 182   *     - #type: markup
 183   *     - #value: Themed markup (usually an unordered list) displaying extra information.
 184   *   - "title"
 185   *     - #type: markup
 186   *     - #value: The displayed title of the $item.
 187   *   - "#total"
 188   *     - "type": float
 189   *     - "value": Numeric price of $item. Notice the '#' signifying that this is
 190   *       not a form element but just a value stored in the form array.
 191   *   - "data"
 192   *     - #type: hidden
 193   *     - #value: The serialized $item->data.
 194   *   - "qty"
 195   *     - #type: textfield
 196   *     - #value: The quantity of $item in the cart. When "Update cart" is clicked,
 197   *         the customer's input is saved to the cart.
 198   */
 199  function hook_cart_display($item) {
 200    $node = node_load($item->nid);
 201    $element = array();
 202    $element['nid'] = array('#type' => 'value', '#value' => $node->nid);
 203    $element['module'] = array('#type' => 'value', '#value' => 'uc_product');
 204    $element['remove'] = array('#type' => 'checkbox');
 205  
 206    $element['title'] = array(
 207      '#value' => node_access('view', $node) ? l($item->title, 'node/'. $node->nid) : check_plain($item->title),
 208    );
 209  
 210    $context = array(
 211      'revision' => 'altered',
 212      'type' => 'cart_item',
 213      'subject' => array(
 214        'cart_item' => $item,
 215        'node' => $node,
 216      ),
 217    );
 218    $price_info = array(
 219      'price' => $item->price,
 220      'qty' => $item->qty,
 221    );
 222  
 223    $element['#total'] = uc_price($price_info, $context);
 224    $element['data'] = array('#type' => 'hidden', '#value' => serialize($item->data));
 225    $element['qty'] = array(
 226      '#type' => 'textfield',
 227      '#default_value' => $item->qty,
 228      '#size' => 5,
 229      '#maxlength' => 6
 230    );
 231  
 232    if ($description = uc_product_get_description($item)) {
 233      $element['description'] = array('#value' => $description);
 234    }
 235  
 236    return $element;
 237  }
 238  
 239  /**
 240   * Add extra data about an item in the cart.
 241   *
 242   * Products that are added to a customer's cart are referred as items until the
 243   * sale is completed. Just think of a grocery store having a bunch of products
 244   * on the shelves but putting a sign over the express lane saying "15 Items or
 245   * Less." hook_cart_item() is in charge of acting on items at various times like
 246   * when they are being added to a cart, saved, loaded, and checked out.
 247   *
 248   * Here's the rationale for this hook: Products may change on a live site during
 249   * a price increase or change to attribute adjustments. If a user has previously
 250   * added an item to their cart, when they go to checkout or view their cart
 251   * screen we want the latest pricing and model numbers to show. So, the essential
 252   * product information is stored in the cart, but when the items in a cart are
 253   * loaded, modules are given a chance to adjust the data against the latest settings.
 254   *
 255   * @param $op
 256   *   The action that is occurring. Possible values:
 257   *   - "load" - Passed for each item when a cart is being loaded in the function
 258   *       uc_cart_get_contents(). This gives modules the chance to tweak information
 259   *       for items when the cart is being loaded prior to being view or added to
 260   *       an order. No return value is expected.
 261   *   - "can_ship" - Passed when a cart is being scanned for items that are not
 262   *       shippable items. Übercart will bypass cart and checkout operations
 263   *       specifically related to tangible products if nothing in the cart is
 264   *       shippable. hook_cart_item functions that check for this op are expected
 265   *       to return TRUE or FALSE based on whether a product is shippable or not.
 266   *   - "remove" - Passed when an item is removed from the cart.
 267   *   - "checkout" - Passed for each item when the cart is being emptied for checkout.
 268   * @return
 269   *   No return value for load.
 270   *   TRUE or FALSE for can_ship.
 271   */
 272  function hook_cart_item($op, &$item) {
 273    switch ($op) {
 274      case 'load':
 275        $term = array_shift(taxonomy_node_get_terms_by_vocabulary($item->nid, variable_get('uc_manufacturer_vid', 0)));
 276        $arg1->manufacturer = $term->name;
 277        break;
 278    }
 279  }
 280  
 281  /**
 282   * Register callbacks for a cart pane.
 283   *
 284   * The default cart view page displays a table of the cart contents and a few
 285   * simple form features to manage the cart contents. For a module to add
 286   * information to this page, it must use hook_cart_pane to define extra panes
 287   * that may be ordered to appear above or below the default information.
 288   *
 289   * @param $items
 290   *   The current contents of the shopping cart.
 291   * @return
 292   *   The function is expected to return an array of pane arrays with the following
 293   *   keys:
 294   *   - "id"
 295   *     - type: string
 296   *     - value: The internal ID of the pane, using a-z, 0-9, and - or _.
 297   *   - "title"
 298   *     - type: string
 299   *     - value: The name of the cart pane displayed to the user.  Use t().
 300   *   - "enabled"
 301   *     - type: boolean
 302   *     - value: Whether the pane is enabled by default or not. (Defaults to TRUE.)
 303   *   - "weight"
 304   *     - type: integer
 305   *     - value: The weight of the pane to determine its display order. (Defaults
 306   *         to 0.)
 307   *   - "body"
 308   *     - type: string
 309   *     - value: The body of the pane when rendered on the cart view screen.
 310   *
 311   * The body gets printed to the screen if it is on the cart view page.  For the
 312   * settings page, the body field is ignored.  You may want your function to check
 313   * for a NULL argument before processing any queries or foreach() loops.
 314   */
 315  function hook_cart_pane($items) {
 316    $panes[] = array(
 317      'id' => 'cart_form',
 318      'title' => t('Default cart form'),
 319      'enabled' => TRUE,
 320      'weight' => 0,
 321      'body' => !is_null($items) ? drupal_get_form('uc_cart_view_form', $items) : '',
 322    );
 323  
 324    return $panes;
 325  }
 326  
 327  /**
 328   * Alter cart pane definitions.
 329   *
 330   * @param $panes
 331   *   The array of pane information in the format defined in hook_cart_pane(), passed
 332   *   by reference.
 333   *
 334   * @param $items
 335   *   The array of item information.
 336   */
 337  function hook_cart_pane_alter(&$panes, $items) {
 338    foreach ($panes as &$pane) {
 339      if ($pane['id'] == 'cart') {
 340        $pane['body'] = drupal_get_form('my_custom_pane_form_builder', $items);
 341      }
 342    }
 343  }
 344  
 345  /**
 346   * Register callbacks for a checkout pane.
 347   *
 348   * The checkout screen for Ubercart is a compilation of enabled checkout panes.
 349   * A checkout pane can be used to display order information, collect data from
 350   * the customer, or interact with other panes. Panes are defined in enabled modules
 351   * with hook_checkout_pane() and displayed and processed through specified callback
 352   * functions. Some of the settings for each pane are configurable from the checkout
 353   * settings page with defaults being specified in the hooks.
 354   *
 355   * The default panes are defined in uc_cart.module in the function
 356   * uc_cart_checkout_pane(). These include panes to display the contents of the
 357   * shopping cart and to collect essential site user information, a shipping address,
 358   * a payment address, and order comments. Other included modules offer panes for
 359   * shipping and payment purposes as well.
 360   *
 361   * @return
 362   *   An array of checkout pane arrays using the following keys:
 363   *   - "id"
 364   *     - type: string
 365   *     - value: The internal ID of the checkout pane, using a-z, 0-9, and - or _.
 366   *   - "title"
 367   *     - type: string
 368   *     - value:The name of the pane as it appears on the checkout form.
 369   *   - "desc"
 370   *     - type: string
 371   *     - value: A short description of the pane for the admin pages.
 372   *   - "callback"
 373   *     - type: string
 374   *     - value: The name of the callback function for this pane.  View
 375   *         @link http://www.ubercart.org/docs/developer/245/checkout this page @endlink
 376   *         for more documentation and examples of checkout pane callbacks.
 377   *   - "weight"
 378   *     - type: integer
 379   *     - value: Default weight of the pane, defining its order on the checkout form.
 380   *   - "enabled"
 381   *     - type: boolean
 382   *     - value: Optional. Whether or not the pane is enabled by default. Defaults
 383   *         to TRUE.
 384   *   - "process"
 385   *     - type: boolean
 386   *     - value: Optional. Whether or not this pane needs to be processed when the
 387   *         checkout form is submitted. Defaults to TRUE.
 388   *   - "collapsible"
 389   *     - type: boolean
 390   *     - value: Optional. Whether or not this pane is displayed as a collapsible
 391   *         fieldset. Defaults to TRUE.
 392   */
 393  function hook_checkout_pane() {
 394    $panes[] = array(
 395      'id' => 'cart',
 396      'callback' => 'uc_checkout_pane_cart',
 397      'title' => t('Cart Contents'),
 398      'desc' => t("Display the contents of a customer's shopping cart."),
 399      'weight' => 1,
 400      'process' => FALSE,
 401      'collapsible' => FALSE,
 402    );
 403    return $panes;
 404  }
 405  
 406  /**
 407   * Alter checkout pane definitions.
 408   *
 409   * @param $panes
 410   *   Array with the panes information as defined in hook_checkout_pane(), passed
 411   *   by reference.
 412   */
 413  function hook_checkout_pane_alter(&$panes) {
 414    foreach ($panes as &$pane) {
 415      if ($pane['id'] == 'cart') {
 416        $pane['callback'] = 'my_custom_module_callback';
 417      }
 418    }
 419  }
 420  
 421  /**
 422   * Give clearance to a user to download a file.
 423   *
 424   * By default the uc_file module can implement 3 restrictions on downloads: by
 425   * number of IP addresses downloaded from, by number of downloads, and by a set
 426   * expiration date. Developers wishing to add further restrictions can do so by
 427   * implementing this hook. After the 3 aforementioned restrictions are checked,
 428   * the uc_file module will check for implementations of this hook.
 429   *
 430   * @param $user
 431   *   The drupal user object that has requested the download
 432   * @param $file_download
 433   *   The file download object as defined as a row from the uc_file_users table
 434   *   that grants the user the download
 435   * @return
 436   *   TRUE or FALSE depending on whether the user is to be permitted download of
 437   *   the requested files. When a implementation returns FALSE it should set an
 438   *   error message in Drupal using drupal_set_message() to inform customers of
 439   *   what is going on.
 440   */
 441  function hook_download_authorize($user, $file_download) {
 442    if (!$user->status) {
 443      drupal_set_message(t("This account has been banned and can't download files anymore. "),'error');
 444      return FALSE;
 445    }
 446    else {
 447      return TRUE;
 448    }
 449  }
 450  
 451  /**
 452   * Perform actions on file products.
 453   *
 454   * The uc_file module comes with a file manager (found at Administer » Store
 455   * administration » Products » View file downloads) that provides some basic
 456   * functionality: deletion of multiple files and directories, and upload of single
 457   * files (those looking to upload multiple files should just directly upload them
 458   * to their file download directory then visit the file manager which automatically
 459   * updates new files found in its directory). Developers that need to create more
 460   * advanced actions with this file manager can do so by using this hook.
 461   *
 462   * @param $op
 463   *   The operation being taken by the hook, possible ops defined below.
 464   *   - 'info': Called before the uc_file module builds its list of possible file
 465   *       actions. This op is used to define new actions that will be placed in
 466   *       the file action select box.
 467   *   - 'insert': Called after uc_file discovers a new file in the file download
 468   *       directory.
 469   *   - 'form': When any defined file action is selected and submitted to the form
 470   *       this function is called to render the next form. Because this is called
 471   *       whenever a module-defined file action is selected, the variable
 472   *       $args['action'] can be used to define a new form or append to an existing
 473   *       form.
 474   *   - 'upload': After a file has been uploaded, via the file manager's built in
 475   *       file upload function, and moved to the file download directory this op
 476   *       can perform any remaining operations it needs to perform on the file
 477   *       before its placed into the uc_files table.
 478   *   - 'upload_validate': This op is called to validate the uploaded file that
 479   *       was uploaded via the file manager's built in file upload function. At
 480   *       this point, the file has been uploaded to PHP's temporary directory.
 481   *       Files passing this upload validate function will be moved into the file
 482   *       downloads directory.
 483   *   - 'validate': This op is called to validate the file action form.
 484   *   - 'submit': This op is called to submit the file action form.
 485   * @param $args
 486   *   A keyed array of values that varies depending on the op being performed,
 487   *   possible values defined below.
 488   *   - 'info': None
 489   *   - 'insert':
 490   *     - 'file_object': The file object of the newly discovered file
 491   *   - 'form':
 492   *     - 'action': The file action being performed as defined by the key in the
 493   *         array sent by hook_file_action($op = 'info')
 494   *     - 'file_ids' - The file ids (as defined in the uc_files table) of the
 495   *          selected files to perform the action on
 496   *   - 'upload':
 497   *     - 'file_object': The file object of the file moved into file downloads
 498   *         directory
 499   *     - 'form_id': The form_id variable of the form_submit function
 500   *     - 'form_values': The form_values variable of the form_submit function
 501   *   - 'upload_validate':
 502   *     - 'file_object': The file object of the file that has been uploaded into
 503   *         PHP's temporary upload directory
 504   *     - 'form_id': The form_id variable of the form_validate function
 505   *     - 'form_values': The form_values variable of the form_validate function
 506   *   - 'validate':
 507   *     - 'form_id': The form_id variable of the form_validate function
 508   *     - 'form_values': The form_values variable of the form_validate function
 509   *   - 'submit':
 510   *     - 'form_id': The form_id variable of the form_submit function
 511   *     - 'form_values': The form_values variable of the form_submit function
 512   * @return
 513   *   The return value of hook depends on the op being performed, possible return
 514   *   values defined below.
 515   *   - 'info': The associative array of possible actions to perform. The keys are
 516   *       unique strings that defines the actions to perform. The values are the
 517   *       text to be displayed in the file action select box.
 518   *   - 'insert': None
 519   *   - 'form': This op should return an array of drupal form elements as defined
 520   *       by the drupal form API.
 521   *   - 'upload': None
 522   *   - 'upload_validate': None
 523   *   - 'validate': None
 524   *   - 'submit': None
 525   */
 526  function hook_file_action($op, $args) {
 527    switch ($op) {
 528      case 'info':
 529        return array('uc_image_watermark_add_mark' => 'Add Watermark');
 530      case 'insert':
 531        //automatically adds watermarks to any new files that are uploaded to the file download directory
 532        _add_watermark($args['file_object']->filepath);
 533      break;
 534      case 'form':
 535        if ($args['action'] == 'uc_image_watermark_add_mark') {
 536          $form['watermark_text'] = array(
 537            '#type' => 'textfield',
 538            '#title' => t('Watermark Text'),
 539          );
 540          $form['submit_watermark'] = array(
 541            '#type' => 'submit',
 542            '#value' => t('Add Watermark'),
 543          );
 544        }
 545      return $form;
 546      case 'upload':
 547        _add_watermark($args['file_object']->filepath);
 548        break;
 549      case 'upload_validate':
 550        //Given a file path, function checks if file is valid JPEG
 551        if(!_check_image($args['file_object']->filepath)) {
 552          form_set_error('upload',t('Uploaded file is not a valid JPEG'));
 553        }
 554      break;
 555      case 'validate':
 556        if ($args['form_values']['action'] == 'uc_image_watermark_add_mark') {
 557          if (empty($args['form_values']['watermark_text'])) {
 558            form_set_error('watermar_text',t('Must fill in text'));
 559          }
 560        }
 561      break;
 562      case 'submit':
 563        if ($args['form_values']['action'] == 'uc_image_watermark_add_mark') {
 564          foreach ($args['form_values']['file_ids'] as $file_id) {
 565            $filename = db_result(db_query("SELECT filename FROM {uc_files} WHERE fid = %d",$file_id));
 566            //Function adds watermark to image
 567            _add_watermark($filename);
 568          }
 569        }
 570      break;
 571    }
 572  }
 573  
 574  /**
 575   * Make changes to a file before it is downloaded by the customer.
 576   *
 577   * Stores, either for customization, copy protection or other reasons, might want
 578   * to send customized downloads to customers. This hook will allow this to happen.
 579   * Before a file is opened to be transfered to a customer, this hook will be called
 580   * to make any altercations to the file that will be used to transfer the download
 581   * to the customer. This, in effect, will allow a developer to create a new,
 582   * personalized, file that will get transfered to a customer.
 583   *
 584   * @param $file_user
 585   *   The file_user object (i.e. an object containing a row from the uc_file_users
 586   *   table) that corresponds with the user download being accessed.
 587   * @param $ip
 588   *   The IP address from which the customer is downloading the file
 589   * @param $fid
 590   *   The file id of the file being transfered
 591   * @param $file
 592   *   The file path of the file to be transfered
 593   * @return
 594   *   The path of the new file to transfer to customer.
 595   */
 596  function hook_file_transfer_alter($file_user, $ip, $fid, $file) {
 597    $file_data = file_get_contents($file)." [insert personalized data]"; //for large files this might be too memory intensive
 598    $new_file = tempnam(file_directory_temp(),'tmp');
 599    file_put_contents($new_file,$file_data);
 600    return $new_file;
 601  }
 602  
 603  /**
 604   * Used to define line items that are attached to orders.
 605   *
 606   * A line item is a representation of charges, fees, and totals for an order.
 607   * Default line items include the subtotal and total line items, the tax line
 608   * item, and the shipping line item. There is also a generic line item that store
 609   * admins can use to add extra fees and discounts to manually created orders.
 610   * Module developers will use this hook to define new types of line items for
 611   * their stores. An example use would be for a module that allows customers to
 612   * use coupons and wants to represent an entered coupon as a line item.
 613   *
 614   * Once a line item has been defined in hook_line_item, Übercart will begin
 615   * interacting with it in various parts of the code. One of the primary ways this
 616   * is done is through the callback function you specify for the line item.
 617   *
 618   * @return
 619   *   Your hook should return an array of associative arrays. Each item in the
 620   *   array represents a single line item and should use the following keys:
 621   *   - "id"
 622   *     - type: string
 623   *     - value: The internal ID of the line item.
 624   *   - "title"
 625   *     - type: string
 626   *     - value: The title of the line item shown to the user in various interfaces.
 627   *         Use t().
 628   *   - "callback"
 629   *     - type: string
 630   *     - value: Name of the line item's callback function, called for various
 631   *         operations.
 632   *   - "weight"
 633   *     - type: integer
 634   *     - value: Display order of the line item in lists; "lighter" items are
 635   *         displayed first.
 636   *   - "stored"
 637   *     - type: boolean
 638   *     - value: Whether or not the line item will be stored in the database.
 639   *         Should be TRUE for any line item that is modifiable from the order
 640   *         edit screen.
 641   *   - "add_list"
 642   *     - type: boolean
 643   *     - value: Whether or not a line item should be included in the "Add a Line
 644   *         Item" select box on the order edit screen.
 645   *   - "calculated"
 646   *     - type: boolean
 647   *     - value: Whether or not the value of this line item should be added to the
 648   *         order total. (Ex: would be TRUE for a shipping charge line item but
 649   *         FALSE for the subtotal line item since the product prices are already
 650   *         taken into account.)
 651   *   - "display_only"
 652   *     - type: boolean
 653   *     - value: Whether or not this line item is simply a display of information
 654   *         but not calculated anywhere. (Ex: the total line item uses display to
 655   *         simply show the total of the order at the bottom of the list of line
 656   *         items.)
 657   */
 658  function hook_line_item() {
 659    $items[] = array(
 660      'id' => 'generic',
 661      'title' => t('Empty Line'),
 662      'weight' => 2,
 663      'default' => FALSE,
 664      'stored' => TRUE,
 665      'add_list' => TRUE,
 666      'calculated' => TRUE,
 667      'callback' => 'uc_line_item_generic',
 668    );
 669  
 670    return $items;
 671  }
 672  
 673  /**
 674   * Alter a line item on an order when the order is loaded.
 675   *
 676   * @param &$item
 677   *   The line item array.
 678   * @param $order
 679   *   The order object containing the line item.
 680   */
 681  function hook_line_item_alter(&$item, $order) {
 682    $account = user_load($order->uid);
 683    ca_pull_trigger('calculate_line_item_discounts', $item, $account);
 684  }
 685  
 686  /**
 687   * Alter the line item definitions declared in hook_line_item().
 688   *
 689   * @param &$items
 690   *   The combined return value of hook_line_item().
 691   */
 692  function hook_line_item_data_alter(&$items) {
 693    foreach ($items as &$item) {
 694      // Tax amounts are added in to other line items, so the actual tax line
 695      // items should not be added to the order total.
 696      if ($item['id'] == 'tax') {
 697        $item['calculated'] = FALSE;
 698      }
 699      // Taxes are included already, so the subtotal without taxes doesn't
 700      // make sense.
 701      elseif ($item['id'] == 'tax_subtotal') {
 702        $item['callback'] = NULL;
 703      }
 704    }
 705  }
 706  
 707  
 708  /**
 709   * Perform actions on orders.
 710   *
 711   * An order in Übercart represents a single transaction. Orders are created
 712   * during the checkout process where they sit in the database with a status of In
 713   * Checkout. When a customer completes checkout, the order's status gets updated
 714   * to show that the sale has gone through. Once an order is created, and even
 715   * during its creation, it may be acted on by any module to connect extra
 716   * information to an order. Every time an action occurs to an order, hook_order()
 717   * gets invoked to let your modules know what's happening and make stuff happen.
 718   *
 719   * @param $op
 720   *   The action being performed.
 721   * @param &$arg1
 722   *   This is the order object.
 723   * @param $arg2
 724   *   This is variable and is based on the value of $op:
 725   *   - new: Called when an order is created. $arg1 is a reference to the new
 726   *       order object, so modules may add to or modify the order at creation.
 727   *   - presave: Before an order object is saved, the hook gets invoked with this
 728   *       op to let other modules alter order data before it is written to the
 729   *       database. $order is a reference to the order object.
 730   *   - save: When an order object is being saved, the hook gets invoked with this
 731   *       op to let other modules do any necessary saving. $arg1 is a reference to
 732   *       the order object.
 733   *   - load: Called when an order is loaded after the order and product data has
 734   *       been loaded from the database. Passes $arg1 as the reference to the
 735   *       order object, so modules may add to or modify the order object when it's
 736   *       loaded.
 737   *   - submit: When a sale is being completed and the customer has clicked the
 738   *       Submit order button from the checkout screen, the hook is invoked with
 739   *       this op. This gives modules a chance to determine whether or not the
 740   *       order should be allowed. An example use of this is the credit module
 741   *       attempting to process payments when an order is submitted and returning
 742   *       a failure message if the payment failed.
 743   *
 744   *       To prevent an order from passing through, you must return an array
 745   *       resembling the following one with the failure message:
 746   *       @code
 747   *         return array(array('pass' => FALSE, 'message' => t('We were unable to process your credit card.')));
 748   *       @endcode
 749   *   - can_update: Called before an order's status is changed to make sure the
 750   *       order can be updated. $arg1 is the order object with the old order
 751   *       status ID ($arg1->order_status), and $arg2 is simply the new order
 752   *       status ID. Return FALSE to stop the update for some reason.
 753   *   - update: Called when an order's status is changed. $arg1 is the order
 754   *       object with the old order status ID ($arg1->order_status), and $arg2 is
 755   *       the new order status ID.
 756   *   - can_delete: Called before an order is deleted to verify that the order may
 757   *       be deleted. Returning FALSE will prevent a delete from happening. (For
 758   *       example, the payment module returns FALSE by default when an order has
 759   *       already received payments.)
 760   *   - delete: Called when an order is deleted and before the rest of the order
 761   *       information is removed from the database. Passes $arg1 as the order
 762   *       object to let your module clean up it's tables.
 763   *   - total: Called when the total for an order is being calculated after the
 764   *       total of the products has been added. Passes $arg1 as the order object.
 765   *       Expects in return a value (positive or negative) by which to modify the
 766   *       order total.
 767   */
 768  function hook_order($op, $arg1, $arg2) {
 769    switch ($op) {
 770      case 'save':
 771        // Do something to save payment info!
 772        break;
 773    }
 774  }
 775  
 776  /**
 777   * Add links to local tasks for orders on the admin's list of orders.
 778   *
 779   * @param $order
 780   *   An order object.
 781   * @return
 782   *   An array of specialized link arrays. Each link has the following keys:
 783   *   - "name": The title of page being linked.
 784   *   - "url": The link path. Do not use url(), but do use the $order's order_id.
 785   *   - "icon": HTML of an image.
 786   *   - "title": Title attribute text (mouseover tool-tip).
 787   */
 788  function hook_order_actions($order) {
 789    $actions = array();
 790    $module_path = base_path() . drupal_get_path('module', 'uc_shipping');
 791    if (user_access('fulfill orders')) {
 792      $result = db_query("SELECT nid FROM {uc_order_products} WHERE order_id = %d AND data LIKE '%%s:9:\"shippable\";s:1:\"1\";%%'", $order->order_id);
 793      if (db_num_rows($result)) {
 794        $title = t('Package order !order_id products.', array('!order_id' => $order->order_id));
 795        $actions[] = array(
 796          'name' => t('Package'),
 797          'url' => 'admin/store/orders/'. $order->order_id .'/packages',
 798          'icon' => '<img src="'. $module_path .'/images/package.gif" alt="'. $title .'" />',
 799          'title' => $title,
 800        );
 801        $result = db_query("SELECT package_id FROM {uc_packages} WHERE order_id = %d", $order->order_id);
 802        if (db_num_rows($result)) {
 803          $title = t('Ship order !order_id packages.', array('!order_id' => $order->order_id));
 804          $actions[] = array(
 805            'name' => t('Ship'),
 806            'url' => 'admin/store/orders/'. $order->order_id .'/shipments',
 807            'icon' => '<img src="'. $module_path .'/images/ship.gif" alt="'. $title .'" />',
 808            'title' => $title,
 809          );
 810        }
 811      }
 812    }
 813    return $actions;
 814  }
 815  
 816  /**
 817   * Register callbacks for an order pane.
 818   *
 819   * This hook is used to add panes to the order viewing and administration screens.
 820   * The default panes include areas to display and edit addresses, products,
 821   * comments, etc. Developers should use this hook when they need to display or
 822   * modify any custom data pertaining to an order. For example, a store that uses
 823   * a custom checkout pane to find out a customer's desired delivery date would
 824   * then create a corresponding order pane to show the data on the order screens.
 825   *
 826   * hook_order_pane() works by defining new order panes and providing a little bit
 827   * of information about them. View the return value section below for information
 828   * about what parts of an order pane are defined by the hook.
 829   *
 830   * The real meat of an order pane is its callback function (which is specified in
 831   * the hook). The callback function handles what gets displayed on which screen
 832   * and what data can be manipulated. That is all somewhat out of the scope of
 833   * this API page, so you'll have to click here to read more about what a callback
 834   * function should contain.
 835  */
 836  function hook_order_pane() {
 837    $panes[] = array(
 838      'id' => 'payment',
 839      'callback' => 'uc_order_pane_payment',
 840      'title' => t('Payment'),
 841      'desc' => t('Specify and collect payment for an order.'),
 842      'class' => 'pos-left',
 843      'weight' => 4,
 844      'show' => array('view', 'edit', 'customer'),
 845    );
 846    return $panes;
 847  }
 848  
 849  /**
 850   * Alter order pane definitions.
 851   *
 852   * @param $panes
 853   *   Array with the panes information as defined in hook_order_pane(), passed
 854   *   by reference.
 855   */
 856  function hook_order_pane_alter(&$panes) {
 857    foreach ($panes as &$pane) {
 858      if ($pane['id'] == 'payment') {
 859        $pane['callback'] = 'my_custom_module_callback';
 860      }
 861    }
 862  }
 863  
 864  /**
 865   * Allows modules to alter ordered products when they're loaded with an order.
 866   *
 867   * @param &$product
 868   *   The product object as found in the $order object.
 869   * @param $order
 870   *   The order object to which the product belongs.
 871   * @return
 872   *   Nothing should be returned. Hook implementations should receive the
 873   *     $product object by reference and alter it directly.
 874   */
 875  function hook_order_product_alter(&$product, $order) {
 876    drupal_set_message('hook_order_product_alter(&$product, $order):');
 877    drupal_set_message('&$product: <pre>'. print_r($product, TRUE) .'</pre>');
 878    drupal_set_message('$order: <pre>'. print_r($order, TRUE) .'</pre>');
 879  }
 880  
 881  /**
 882   * Register static order states.
 883   *
 884   * Order states are module-defined categories for order statuses. Each state
 885   * will have a default status that is used when modules need to move orders to
 886   * new state, but don't know which status to use.
 887   *
 888   * @return
 889   *   An array of order state definitions. Each definition is an array with the
 890   *   following keys:
 891   *   - id: The machine-readable name of the order state.
 892   *   - title: The human-readable, translated name.
 893   *   - weight: The list position of the state.
 894   *   - scope: Either "specific" or "general".
 895   */
 896  function hook_order_state() {
 897    $states[] = array(
 898      'id' => 'canceled',
 899      'title' => t('Canceled'),
 900      'weight' => -20,
 901      'scope' => 'specific',
 902    );
 903    $states[] = array(
 904      'id' => 'in_checkout',
 905      'title' => t('In checkout'),
 906      'weight' => -10,
 907      'scope' => 'specific',
 908    );
 909    $states[] = array(
 910      'id' => 'post_checkout',
 911      'title' => t('Post checkout'),
 912      'weight' => 0,
 913      'scope' => 'general',
 914    );
 915    $states[] = array(
 916      'id' => 'completed',
 917      'title' => t('Completed'),
 918      'weight' => 20,
 919      'scope' => 'general',
 920    );
 921  
 922    return $states;
 923  }
 924  
 925  /**
 926   * Register payment gateway callbacks.
 927   *
 928   * @see @link http://www.ubercart.org/docs/api/hook_payment_gateway @endlink
 929   *
 930   * @return
 931   *   Returns an array of payment gateways, which are arrays with the following keys:
 932   *   - "id"
 933   *     - type: string
 934   *     - value: The internal ID of the payment gateway, using a-z, 0-9, and - or
 935   *         _.
 936   *   - "title"
 937   *     - type: string
 938   *     - value: The name of the payment gateway displayed to the user. Use t().
 939   *   - "description"
 940   *     - type: string
 941   *     - value: A short description of the payment gateway.
 942   *   - "settings"
 943   *     - type: string
 944   *     - value: The name of a function that returns an array of settings form
 945   *         elements for the gateway.
 946   */
 947  function hook_payment_gateway() {
 948    $gateways[] = array(
 949      'id' => 'test_gateway',
 950      'title' => t('Test Gateway'),
 951      'description' => t('Process credit card payments through the Test Gateway.'),
 952      'credit' => 'test_gateway_charge',
 953    );
 954    return $gateways;
 955  }
 956  
 957  /**
 958   * Alter payment gateways.
 959   *
 960   * @param $gateways
 961   *   Payment gateways passed by reference.
 962   */
 963  function hook_payment_gateway_alter(&$gateways) {
 964    // Change the title of all gateways.
 965    foreach ($gateways as &$gateway) {
 966      // $gateway was passed by reference.
 967      $gateway['title'] = t('Altered gateway @original', array('@original' => $gateway['title']));
 968    }
 969  }
 970  
 971  /**
 972   * Register callbacks for payment methods.
 973   *
 974   * Payment methods are different ways to collect payment. By default, Übercart
 975   * comes with support for check, credit card, and generic payments. Payment
 976   * methods show up at checkout or on the order administration screens, and they
 977   * collect different sorts of information from the user that is used to process
 978   * or track the payment.
 979   *
 980   * @return
 981   *   An array of payment methods.
 982   */
 983  function hook_payment_method() {
 984    $methods[] = array(
 985      'id' => 'check',
 986      'name' => t('Check'),
 987      'title' => t('Check or Money Order'),
 988      'desc' => t('Pay by mailing a check or money order.'),
 989      'callback' => 'uc_payment_method_check',
 990      'weight' => 1,
 991      'checkout' => TRUE,
 992    );
 993    return $methods;
 994  }
 995  
 996  /**
 997   * Perform actions on product classes.
 998   *
 999   * @param $type
1000   *   The node type of the product class.
1001   * @param $op
1002   *   The action being performed on the product class:
1003   *   - "insert": A new node type is created, or an existing node type is being
1004   *       converted into a product type.
1005   *   - "update": A product class has been updated.
1006   *   - "delete": A product class has been deleted. Modules that have attached
1007   *       additional information to the node type because it is a product type
1008   *       should delete this information.
1009   */
1010  function hook_product_class($type, $op) {
1011    switch ($op) {
1012      case 'delete':
1013        db_query("DELETE FROM {uc_class_attributes} WHERE pcid = '%s'", $type);
1014        db_query("DELETE FROM {uc_class_attribute_options} WHERE pcid = '%s'", $type);
1015      break;
1016    }
1017  }
1018  
1019  /**
1020   * Return a structured array representing the given product's description.
1021   *
1022   * Modules that add data to cart items when they are selected should display it
1023   * with this hook. The return values from each implementation will be
1024   * sent through to hook_product_description_alter() implementations and then
1025   * all descriptions are rendered using drupal_render().
1026   *
1027   * @param $product
1028   *   Product. Usually one of the values of the array returned by
1029   *   uc_cart_get_contents().
1030   * @return
1031   *   A structured array that can be fed into drupal_render().
1032   */
1033  function hook_product_description($product) {
1034    $description = array(
1035      'attributes' => array(
1036        '#product' => array(
1037          '#type' => 'value',
1038          '#value' => $product,
1039        ),
1040        '#theme' => 'uc_product_attributes',
1041        '#weight' => 1,
1042      ),
1043    );
1044  
1045    $desc =& $description['attributes'];
1046  
1047    // Cart version of the product has numeric attribute => option values so we
1048    // need to retrieve the right ones
1049    $weight = 0;
1050    if (empty($product->order_id)) {
1051      foreach (_uc_cart_product_get_options($product) as $option) {
1052        if (!isset($desc[$option['aid']])) {
1053          $desc[$option['aid']]['#attribute_name'] = $option['attribute'];
1054          $desc[$option['aid']]['#options'] = array($option['name']);
1055        }
1056        else {
1057          $desc[$option['aid']]['#options'][] = $option['name'];
1058        }
1059        $desc[$option['aid']]['#weight'] = $weight++;
1060      }
1061    }
1062    else {
1063      foreach ((array)$product->data['attributes'] as $attribute => $option) {
1064        $desc[] = array(
1065          '#attribute_name' => $attribute,
1066          '#options' => $option,
1067          '#weight' => $weight++,
1068        );
1069      }
1070    }
1071  
1072    return $description;
1073  }
1074  
1075  /**
1076   * Alters the given product description.
1077   *
1078   * @param $description
1079   *   Description array reference.
1080   * @param $product
1081   *   The product being described.
1082   */
1083  function hook_product_description_alter(&$description, $product) {
1084    $description['attributes']['#weight'] = 2;
1085  }
1086  
1087  /**
1088   * List node types which should be considered products.
1089   *
1090   * Trusts the duck philosophy of object identification: if it walks like a duck,
1091   * quacks like a duck, and has feathers like a duck, it's probably a duck.
1092   * Products are nodes with prices, SKUs, and everything else Übercart expects
1093   * them to have.
1094   *
1095   * @return
1096   *   Array of node type ids.
1097   */
1098  function hook_product_types() {
1099    return array('product_kit');
1100  }
1101  
1102  /**
1103   * Handle additional data for shipments.
1104   *
1105   * @param $op
1106   *   The action being taken on the shipment. One of the following values:
1107   *   - "load": The shipment and its packages are loaded from the database.
1108   *   - "save": Changes to the shipment have been written.
1109   *   - "delete": The shipment has been deleted and the packages are available
1110   *     for reshipment.
1111   * @param &$shipment
1112   *   The shipment object.
1113   * @return
1114   *   Only given when $op is "load". An array of extra data to be added to the
1115   *   shipment object.
1116   */
1117  function hook_shipment($op, &$shipment) {
1118    switch ($op) {
1119      case 'save':
1120        $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
1121        if ($google_order_number && $shipment->is_new) {
1122          $xml_data = '';
1123          foreach ($shipment->packages as $package) {
1124            if ($package->tracking_number) {
1125              $tracking_number = $package->tracking_number;
1126            }
1127            else if ($shipment->tracking_number) {
1128              $tracking_number = $shipment->tracking_number;
1129            }
1130            if ($tracking_number) {
1131              foreach ($package->products as $product) {
1132                $xml_data .= '<item-shipping-information>';
1133                $xml_data .= '<item-id>';
1134                $xml_data .= '<merchant-item-id>'. check_plain($product->nid .'|'. $product->model) .'</merchant-item-id>';
1135                $xml_data .= '</item-id>';
1136                $xml_data .= '<tracking-data-list>';
1137                $xml_data .= '<tracking-data>';
1138                $xml_data .= '<carrier>'. check_plain($shipment->carrier) .'</carrier>';
1139                $xml_data .= '<tracking-number>'. check_plain($tracking_number) .'</tracking-number>';
1140                $xml_data .= '</tracking-data>';
1141                $xml_data .= '</tracking-data-list>';
1142                $xml_data .= '</item-shipping-information>';
1143              }
1144            }
1145          }
1146          if ($xml_data) {
1147            $request = '<?xml version="1.0" encoding="UTF-8"?>'. "\n";
1148            $request .= '<ship-items xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
1149            $request .= '<item-shipping-information-list>';
1150            $request .= $xml_data;
1151            $request .= '</item-shipping-information-list>';
1152            $request .= '<send-email>true</send-email>';
1153            $request .= '</ship-items>';
1154            $response = uc_google_checkout_send_request('request', $request);
1155          }
1156        }
1157      break;
1158      case 'delete':
1159        $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
1160        if ($google_order_number) {
1161          foreach ($shipment->packages as $package) {
1162            foreach ($package->products as $product) {
1163              $reset_ids[] = check_plain($product->nid .'|'. $product->model);
1164            }
1165          }
1166          $request = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
1167          $request .= '<reset-items-shipping-information xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
1168          $request .= '<item-ids>';
1169          foreach (array_unique($reset_ids) as $item_id) {
1170            $request .= '<item-id>';
1171            $request .= '<merchant-item-id>'. $item_id .'</merchant-item-id>';
1172            $request .= '</item-id>';
1173          }
1174          $request .= '</item-ids>';
1175          $request .= '<send-email>false</send-email>';
1176          $request .= '</reset-items-shipping-information>';
1177        }
1178        $response = uc_google_checkout_send_request('request', $request);
1179      break;
1180    }
1181  }
1182  
1183  /**
1184   * Define callbacks and service options for shipping methods.
1185   *
1186   * The shipping quote controller module, uc_quote, expects a very specific
1187   * structured array of methods from the implementations of this hook.
1188   *
1189   * The weights and enabled flags for shipping methods and types are set at the
1190   * Shipping Quote Settings page under Store Configuration. They keys of the
1191   * variables are the ids of the shipping methods. The "quote" and "ship" arrays of
1192   * the method are both optional.
1193   *
1194   * @return
1195   *   An array of shipping methods which have the following keys.
1196   *   - "type": The quote and shipping types are ids of the product shipping type
1197   *       that these methods apply to. type may also be 'order' which indicates
1198   *       that the quote applies to the entire order, regardless of the shipping
1199   *       types of its products. This is used by quote methods that are base on
1200   *       the location of the customer rather than their purchase.
1201   *   - "callback": The function that is called by uc_quote when a shipping quote
1202   *       is requested. Its arguments are the array of products and an array of
1203   *       order details (the shipping address). The return value is an array
1204   *       representing the rates quoted and errors returned (if any) for each
1205   *       option in the accessorials array.
1206   *   - "accessorials": This array represents the different options the customer
1207   *       may choose for their shipment. The callback function should generate a
1208   *       quote for each option in accessorials and return them via an array.
1209   *       drupal_to_js() is very useful for this.
1210   *       @code
1211   *         return array(
1212   *           '03' => array('rate' => 15.75, 'format' => uc_price(15.75, $context) 'option_label' => t('UPS Ground'),
1213   *                         'error' => 'Additional handling charge automatically applied.'),
1214   *           '14' => array('error' => 'Invalid package type.'),
1215   *           '59' => array('rate' => 26.03, 'format' => uc_price(26.03, $context), 'option_label' => t('UPS 2nd Day Air A.M.'))
1216   *         );
1217   *       @endcode
1218   *   - "pkg_types": The list of package types that the shipping method can handle.
1219   *       This should be an associative array that can be used as the #options of
1220   *       a select form element. It is recommended that a function be written to
1221   *       output this array so the method doesn't need to be found just for the
1222   *       package types.
1223   */
1224  function hook_shipping_method() {
1225    $methods = array();
1226  
1227    $enabled = variable_get('uc_quote_enabled', array('ups' => TRUE));
1228    $weight = variable_get('uc_quote_method_weight', array('ups' => 0));
1229    $methods['ups'] = array(
1230      'id' => 'ups',
1231      'title' => t('UPS'),
1232      'enabled' => $enabled['ups'],
1233      'weight' => $weight['ups'],
1234      'quote' => array(
1235        'type' => 'small package',
1236        'callback' => 'uc_ups_quote',
1237        'accessorials' => array(
1238          '03' => t('UPS Ground'),
1239          '11' => t('UPS Standard'),
1240          '01' => t('UPS Next Day Air'),
1241          '13' => t('UPS Next Day Air Saver'),
1242          '14' => t('UPS Next Day Early A.M.'),
1243          '02' => t('UPS 2nd Day Air'),
1244          '59' => t('UPS 2nd Day Air A.M.'),
1245          '12' => t('UPS 3-Day Select'),
1246        ),
1247      ),
1248      'ship' => array(
1249        'type' => 'small package',
1250        'callback' => 'uc_ups_fulfill_order',
1251        'pkg_types' => array(
1252          '01' => t('UPS Letter'),
1253          '02' => t('Customer Supplied Package'),
1254          '03' => t('Tube'),
1255          '04' => t('PAK'),
1256          '21' => t('UPS Express Box'),
1257          '24' => t('UPS 25KG Box'),
1258          '25' => t('UPS 10KG Box'),
1259          '30' => t('Pallet'),
1260        ),
1261      ),
1262    );
1263  
1264    return $methods;
1265  }
1266  
1267  /**
1268   * Define shipping types for shipping methods.
1269   *
1270   * This hook defines a shipping type that this module is designed to handle.
1271   * These types are specified by a machine- and human-readable name called 'id',
1272   * and 'title' respectively. Shipping types may be set for individual products,
1273   * manufacturers, and for the entire store catalog. Shipping modules should be
1274   * careful to use the same shipping type ids as other similar shipping modules
1275   * (i.e., FedEx and UPS both operate on "small package" shipments). Modules that
1276   * do not fulfill orders may not need to implement this hook.
1277   *
1278   * @return
1279   *   An array of shipping types keyed by a machine-readable name.
1280   */
1281  function hook_shipping_type() {
1282    $weight = variable_get('uc_quote_type_weight', array('small_package' => 0));
1283  
1284    $types = array();
1285    $types['small_package'] = array(
1286      'id' => 'small_package',
1287      'title' => t('Small Packages'),
1288      'weight' => $weight['small_package'],
1289    );
1290  
1291    return $types;
1292  }
1293  
1294  /**
1295   * Add status messages to the "Store administration" page.
1296   *
1297   * This hook is used to add items to the store status table on the main store
1298   * administration screen. Each item gets a row in the table that consists of a
1299   * status icon, title, and description. These items should be used to give
1300   * special instructions, notifications, or indicators for components of the cart
1301   * enabled by the modules. At a glance, a store owner should be able to look here
1302   * and see if a critical component of your module is not functioning properly.
1303   *
1304   * For example, if the catalog module is installed and it cannot find the catalog
1305   * taxonomy vocabulary, it will show an error message here to alert the store
1306   * administrator.
1307   *
1308   * @return
1309   *   An array of tore status items which are arrays with the following keys:
1310   *   - "status": "ok", "warning", or "error" depending on the message.
1311   *   - "title" The title of the status message or module that defines it.
1312   *   - "desc": The description; can be any message, including links to pages and
1313   *       forms that deal with the issue being reported.
1314   */
1315  function hook_store_status() {
1316    if ($key = uc_credit_encryption_key()) {
1317      $statuses[] = array(
1318        'status' => 'ok',
1319        'title' => t('Credit card encryption'),
1320        'desc' => t('Credit card data in the database is currently being encrypted.'),
1321      );
1322    }
1323    return $statuses;
1324  }
1325  
1326  /**
1327   * Allow modules to alter the TAPIr table after the rows are populated.
1328   *
1329   * The example below adds a value for the custom 'designer' column to the table
1330   * rows. Each table row has a numeric key in $table and these keys can be
1331   * accessed using element_children() from the Form API.
1332   *
1333   * @param $table Table declaration containing header and populated rows.
1334   * @param $table_id Table ID. Also the function called to build the table
1335   *   declaration.
1336   */
1337  function hook_tapir_table_alter(&$table, $table_id) {
1338    if ($table_id == 'uc_product_table') {
1339      foreach (element_children($table) as $key) {
1340        $node = node_load($table['#parameters'][1][$key]);
1341  
1342        $table[$key]['designer'] = array(
1343          '#value' => l($node->designer, 'collections/'.$node->designer_tid),
1344          '#cell_attributes' => array(
1345            'nowrap' => 'nowrap',
1346          ),
1347        );
1348      }
1349    }
1350  }
1351  
1352  /**
1353   * Allow modules to alter TAPIr table headers.
1354   *
1355   * This is most often done when a developer wants to add a sortable field to
1356   * the table. A sortable field is one where the header can be clicked to sort
1357   * the table results. This cannot be done using hook_tapir_table_alter() as
1358   * once that is called the query has already executed.
1359   *
1360   * The example below adds a 'designer' column to the catalog product table. The
1361   * example module would also have added joins to the query using
1362   * hook_db_rewrite_sql() in order for table 'td2' to be valid. The 'name' field
1363   * is displayed in the table and the header has the title 'Designer'.
1364   *
1365   * Also shown are changes made to the header titles for list_price and
1366   * price fields.
1367   *
1368   * @see hook_db_rewrite_sql()
1369   *
1370   * @param $header Reference to the array header declaration
1371   *   (i.e $table['#header']).
1372   * @param $table_id Table ID. Also the function called to build the table
1373   *   declaration.
1374   */
1375  function hook_tapir_table_header_alter(&$header, $table_id) {
1376    if ($table_id == 'uc_product_table') {
1377      $header['designer'] = array(
1378        'weight' => 2,
1379        'cell' => array(
1380          'data' => t('Designer'),
1381          'field' => 'td2.name',
1382        ),
1383      );
1384  
1385      $header['list_price']['cell']['data'] = t('RRP');
1386      $header['price']['cell']['data'] = t('Sale');
1387      $header['add_to_cart']['cell']['data'] = '';
1388    }
1389  }
1390  
1391  /**
1392   * Take action when checkout is completed.
1393   *
1394   * @param $order
1395   *   The resulting order object from the completed checkout.
1396   * @param $account
1397   *   The customer that completed checkout, either the current user, or the
1398   *   account created for an anonymous customer.
1399   */
1400  function hook_uc_checkout_complete($order, $account) {
1401    // Get previous records of customer purchases.
1402    $nids = array();
1403    $result = db_query("SELECT uid, nid, qty FROM {uc_customer_purchases} WHERE uid = %d", $account->uid);
1404    while ($record = db_fetch_object($result)) {
1405      $nids[$record->nid] = $record->qty;
1406    }
1407  
1408    // Update records with new data.
1409    $record = array('uid' => $account->uid);
1410    foreach ($order->products as $product) {
1411      $record['nid'] = $product->nid;
1412      if (isset($nids[$product->nid])) {
1413        $record['qty'] = $nids[$product->nid] + $product->qty;
1414        db_write_record($record, 'uc_customer_purchases', array('uid', 'nid'));
1415      }
1416      else {
1417        $record['qty'] = $product->qty;
1418        db_write_record($record, 'uc_customer_purchases');
1419      }
1420    }
1421  }
1422  
1423  /**
1424   * Allow modules to modify forms before Drupal invokes hook_form_alter().
1425   *
1426   * This hook will normally be used by core modules so any form modifications
1427   * they make can be further modified by contrib modules using a normal
1428   * hook_form_alter(). At this point, drupal_prepare_form() has not been called,
1429   * so none of the automatic form data (e.g.: #parameters, #build_id, etc.) has
1430   * been added yet.
1431   *
1432   * For a description of the hook parameters:
1433   * @see hook_form_alter()
1434   */
1435  function hook_uc_form_alter(&$form, &$form_state, $form_id) {
1436    // If the node has a product list, add attributes to them
1437    if (isset($form['products']) && count(element_children($form['products']))) {
1438      foreach (element_children($form['products']) as $key) {
1439        $form['products'][$key]['attributes'] = _uc_attribute_alter_form(node_load($key));
1440        if (is_array($form['products'][$key]['attributes'])) {
1441          $form['products'][$key]['attributes']['#tree'] = TRUE;
1442          $form['products'][$key]['#type'] = 'fieldset';
1443        }
1444      }
1445    }
1446    // If not, add attributes to the node.
1447    else {
1448      $form['attributes'] = _uc_attribute_alter_form($node);
1449  
1450      if (is_array($form['attributes'])) {
1451        $form['attributes']['#tree'] = TRUE;
1452        $form['attributes']['#weight'] = -1;
1453      }
1454    }
1455  }
1456  
1457  /**
1458   * Add invoice templates to the list of suggested template files.
1459   *
1460   * Allows modules to declare new "types" of invoice templates (other than the
1461   * default 'admin' and 'customer').
1462   *
1463   * @return
1464   *   Array of template names that are available choices when mailing an
1465   *   invoice.
1466   */
1467  function hook_uc_invoice_templates() {
1468    return array('admin', 'customer');
1469  }
1470  
1471  /**
1472   * Convenience function to display large blocks of text in several places.
1473   *
1474   * There are many instances where Ubercart modules have configurable blocks of
1475   * text. These usually come with default messages, like e-mail templates for new
1476   * orders. Because of the way default values are normally set, you're then stuck
1477   * having to copy and paste a large chunk of text in at least two different
1478   * places in the module (when you're wanting to use the variable or to display
1479   * the settings form with the default value). To cut down code clutter, this hook
1480   * was introduced. It lets you put your messages in one place and use the
1481   * function uc_get_message() to retrieve the default value at any time (and from
1482   * any module).
1483   *
1484   * The function is very simple, expecting no arguments and returning a basic
1485   * associative array with keys being message IDs and their values being the
1486   * default message. When you call uc_get_message(), use the message ID you set
1487   * here to refer to the message you want.
1488   *
1489   * Note: When using t(), you must not pass it a concatenated string! So our
1490   * example has no line breaks in the message even though it is much wider than 80
1491   * characters. Using concatenation breaks translation.
1492   *
1493   * @return
1494   *   An array of messages.
1495   */
1496  function hook_uc_message() {
1497    $messages['configurable_message_example'] = t('This block of text represents a configurable message such as a set of instructions or an e-mail template.  Using hook_uc_message to handle the default values for these is so easy even your grandma can do it!');
1498  
1499    return $messages;
1500  }
1501  
1502  /**
1503   * Take action when a payment is entered for an order.
1504   *
1505   * @param $order
1506   *   The order object.
1507   * @param $method
1508   *   The name of the payment method used.
1509   * @param $amount
1510   *   The value of the payment.
1511   * @param $account
1512   *   The user account that entered the order. When the payment is entered
1513   *   during checkout, this is probably the order's user. Otherwise, it is
1514   *   likely a store administrator.
1515   * @param $data
1516   *   Extra data associated with the transaction.
1517   * @param $comment
1518   *   Any comments from the user about the transaction.
1519   */
1520  function hook_uc_payment_entered($order, $method, $amount, $account, $data, $comment) {
1521    drupal_set_message(t('User @uid entered a @method payment of @amount for order @order_id.',
1522      array(
1523        '@uid' => $account->uid,
1524        '@method' => $method,
1525        '@amount' => uc_price($amount, array('location' => 'hook-payment', 'revision' => 'formatted-original')),
1526        '@order_id' => $order->order_id,
1527      ))
1528    );
1529  }
1530  
1531  /**
1532   * Use this hook to define price handlers for your module. You may define one
1533   * price alterer and one price formatter. You may also define options that are
1534   * merged into the options array in order of each price alterer's weight.
1535   */
1536  function hook_uc_price_handler() {
1537    return array(
1538      'alter' => array(
1539        'title' => t('My price handler'),
1540        'description' => t('Handles my price alteration needs.'),
1541        'callback' => 'my_price_handler_alter',
1542      ),
1543      'format' => array(
1544        'title' => t('My price handler'),
1545        'description' => t('Handles my price formatting needs.'),
1546        'callback' => 'my_price_handler_format',
1547      ),
1548      'options' => array(
1549        'sign' => variable_get('uc_currency_sign', '*'),
1550        'sign_after' => TRUE,
1551        'prec' => 4,
1552        'dec' => ',',
1553        'thou' => '.',
1554        'label' => FALSE,
1555        'my_option_that_my_formatter_recognizes' => 1337,
1556      )
1557    );
1558  }
1559  
1560  /**
1561   * Define default product classes.
1562   *
1563   * The results of this hook are eventually passed through hook_node_info(),
1564   * so you may include any keys that hook_node_info() uses. Defaults will
1565   * be provided where keys are not set. This hook can also be used to
1566   * override the default "product" product class name and description.
1567   */
1568  function hook_uc_product_default_classes() {
1569    return array(
1570      'my_class' => array(
1571        'name' => t('My product class'),
1572        'description' => t('Content type description for my product class.'),
1573      ),
1574    );
1575  }
1576  
1577  /**
1578   * Notify core of any SKUs your module adds to a given node.
1579   *
1580   * NOTE: DO NOT map the array keys, as the possibility for numeric SKUs exists, and
1581   * this will conflict with the behavior of module_invoke_all(), specifically
1582   * array_merge_recursive().
1583   *
1584   * Code lifted from uc_attribute.module.
1585   */
1586  function hook_uc_product_models($node) {
1587    $models = array();
1588  
1589    // Get all the SKUs for all the attributes on this node.
1590    $adjustments = db_query("SELECT model FROM {uc_product_adjustments} WHERE nid = %d", $node->nid);
1591    while ($adjustment = db_fetch_object($adjustments)) {
1592      if (!in_array($adjustment->model, $models)) {
1593        $models[] = $adjustment->model;
1594      }
1595    }
1596  
1597    return $models;
1598  }
1599  
1600  /**
1601   * Allow modules to take action when a stock level is changed.
1602   *
1603   * @param $sku
1604   *   The SKU whose stock level is being changed.
1605   * @param $stock
1606   *   The stock level before the adjustment.
1607   * @param $qty
1608   *   The amount by which the stock level was changed.
1609   */
1610  function hook_uc_stock_adjusted($sku, $stock, $qty) {
1611    $params = array(
1612      'sku' => $sku,
1613      'stock' => $stock,
1614      'qty' => $qty,
1615    );
1616  
1617    drupal_mail('uc_stock_notify', 'stock-adjusted', uc_store_email_from(), language_default(), $params);
1618  }
1619  
1620  /**
1621   * Used to determine whether or not UC Google Analytics should add e-commerce
1622   *   tracking code to the bottom of the page.
1623   *
1624   * The Google Analytics module takes care of adding the necessary .js file from
1625   * Google for tracking general statistics.  The UC Google Analytics module works
1626   * in conjunction with this code to add e-commerce specific code.  However, the
1627   * e-commerce code should only be added on appropriate pages.  Generally, the
1628   * correct page will be the checkout completion page at cart/checkout/complete.
1629   * However, because modules can change the checkout flow as necessary, it must
1630   * be possible for alternate pages to be used.
1631   *
1632   * This hook allows other modules to tell the UC Google Analytics module that
1633   * it should go ahead and add the e-commerce tracking code to the current page.
1634   * A module simply needs to implement this hook and return TRUE on the proper
1635   * order completion page to let UC Google Analytics know it should add the
1636   * e-commerce tracking code to the current page.
1637   *
1638   * The implementation below comes from the 2Checkout.com module which uses an
1639   * alternate checkout completion page.
1640   *
1641   * @return
1642   *   TRUE if e-commerce tracking code should be added to the current page.
1643   */
1644  function hook_ucga_display() {
1645    // Tell UC Google Analytics to display the e-commerce JS on the custom
1646    // order completion page for this module.
1647    if (arg(0) == 'cart' && arg(1) == '2checkout' && arg(2) == 'complete') {
1648      return TRUE;
1649    }
1650  }
1651  
1652  /**
1653   * Allows modules to alter items before they're added to the UC Google Analytics
1654   *   e-commerce tracking code.
1655   *
1656   * The UC Google Analytics module constructs function calls that work through
1657   * the Google Analytics JS API to report purchased items for e-commerce tracking
1658   * purposes.  The module builds the argument list for each product on an order
1659   * and uses this hook to give other modules a chance to alter what gets reported
1660   * to Google Analytics.  Additional arguments passed to implementations of this
1661   * hook are provided for context.
1662   *
1663   * @param $item
1664   *   An array of arguments being passed to Google Analytics representing an item
1665   *   on the order, including order_id, sku, name, category, price, and qty.
1666   * @param $product
1667   *   The product object as found in the $order object.
1668   * @param $trans
1669   *   The array of arguments that were passed to Google Analytics to represent
1670   *     the transaction.
1671   * @param $order
1672   *   The order object being reported to Google Analytics.
1673   * @return
1674   *   Nothing should be returned. Hook implementations should receive the $item
1675   *     array by reference and alter it directly.
1676   */
1677  function hook_ucga_item_alter(&$item, $product, $trans, $order) {
1678    // Example implementation: always set the category to "UBERCART".
1679    $item['category'] = 'UBERCART';
1680  }
1681  
1682  /**
1683   * Allows modules to alter transaction info before it's added to the UC Google
1684   *   Analytics e-commerce tracking code.
1685   *
1686   * The UC Google Analytics module constructs function calls that work through
1687   * the Google Analytics JS API to report order information for e-commerce
1688   * tracking purposes.  The module builds the argument list for the transaction
1689   * and uses this hook to give other modules a chance to alter what gets reported
1690   * to Google Analytics.
1691   *
1692   * @param $trans
1693   *   An array of arguments being passed to Google Analytics representing the
1694   *     transaction, including order_id, store, total, tax, shipping, city,
1695   *     state, and country.
1696   * @param $order
1697   *   The order object being reported to Google Analytics.
1698   * @return
1699   *   Nothing should be returned. Hook implementations should receive the $trans
1700   *     array by reference and alter it directly.
1701   */
1702  function hook_ucga_trans_alter(&$trans, $order) {
1703    // Example implementation: prefix all orders with "UC-".
1704    $trans['order_id'] = 'UC-'. $trans['order_id'];
1705  }
1706  
1707  /**
1708   * Handle requests to update a cart item.
1709   *
1710   * @param $nid
1711   *   Node id of the cart item.
1712   * @param $data
1713   *   Array of extra information about the item.
1714   * @param $qty
1715   *   The quantity of this item in the cart.
1716   * @param $cid
1717   *   The cart id. Defaults to NULL, which indicates that the current user's cart
1718   *   should be retrieved with uc_cart_get_id().
1719   */
1720  function hook_update_cart_item($nid, $data = array(), $qty, $cid = NULL) {
1721    if (!$nid) return NULL;
1722    $cid = !(is_null($cid) || empty($cid)) ? $cid : uc_cart_get_id();
1723    if ($qty < 1) {
1724      uc_cart_remove_item($nid, $cid, $data);
1725    }
1726    else {
1727      db_query("UPDATE {uc_cart_products} SET qty = %d, changed = %d WHERE nid = %d AND cart_id = '%s' AND data = '%s'", $qty, time(), $nid, $cid, serialize($data));
1728    }
1729  
1730    // Rebuild the items hash
1731    uc_cart_get_contents(NULL, 'rebuild');
1732    if (!strpos(request_uri(), 'cart', -4)) {
1733      drupal_set_message(t('Your item(s) have been updated.'));
1734    }
1735  }
1736  
1737  /**
1738   * @} End of "addtogroup hooks".
1739   */


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7