'Stock settings', 'description' => 'View the stock settings.', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_stock_settings_form'), 'access arguments' => array('administer product stock'), 'type' => MENU_NORMAL_ITEM, 'file' => 'uc_stock.admin.inc', ); $items['admin/store/reports/stock'] = array( 'title' => 'Stock reports', 'description' => 'View reports for product stock.', 'page callback' => 'uc_stock_report', 'access arguments' => array('view reports'), 'type' => MENU_NORMAL_ITEM, 'file' => 'uc_stock.admin.inc', ); $items['node/%node/edit/stock'] = array( 'title' => 'Stock', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_stock_edit_form', 1), 'access callback' => 'uc_stock_product_access', 'access arguments' => array(1), 'weight' => 10, 'type' => MENU_LOCAL_TASK, 'file' => 'uc_stock.admin.inc', ); return $items; } /** * Access callback for node/%node/edit/stock. */ function uc_stock_product_access($node) { if ($node->type == 'product_kit') { return FALSE; } return uc_product_is_product($node) && node_access('update', $node) && user_access('administer product stock'); } /** * Implementation of hook_perm(). */ function uc_stock_perm() { return array('administer product stock'); } /** * Implementation of hook_theme(). */ function uc_stock_theme() { return array( 'uc_stock_edit_form' => array( 'arguments' => array('content' => NULL), 'file' => 'uc_stock.admin.inc', ), ); } /** * Implementation of hook_init(). */ function uc_stock_init() { global $conf; $conf['i18n_variables'][] = 'uc_stock_threshold_notification_message'; $conf['i18n_variables'][] = 'uc_stock_threshold_notification_subject'; } /** * Implementation of hook_mail(). */ function uc_stock_mail($key, &$message, $params) { switch ($key) { case 'threshold': $message['subject'] = $params['subject']; $message['body'] = $params['body']; break; } } /****************************************************************************** * Ubercart Hooks * ******************************************************************************/ /** * Implementation of hook_token_list(). */ function uc_stock_token_list($type = 'all') { $tokens = array(); if ($type == 'stock' || $type == 'ubercart' || $type == 'all') { $tokens['stock']['stock-level'] = t('The current stock level'); $tokens['stock']['stock-model'] = t('The model or SKU of the stock level'); $tokens['stock']['stock-threshold'] = t('The threshold or warning limit of the stock level'); } return $tokens; } /** * Implementation of hook_token_values(). */ function uc_stock_token_values($type, $object = NULL) { $values = array(); switch ($type) { case 'stock': $values['stock-level'] = $object->stock; $values['stock-model'] = $object->sku; $values['stock-threshold'] = $object->threshold; break; } return $values; } /** * Implementation of hook_uc_message(). */ function uc_stock_uc_message() { $messages['uc_stock_threshold_notification_subject'] = t('[store-name]: Stock threshold limit reached'); $messages['uc_stock_threshold_notification_message'] = t("This message has been sent to let you know that the stock level for the model [stock-model] has reached [stock-level]. There may not be enough units in stock to fulfill order #[order-link]."); return $messages; } /****************************************************************************** * Module and Helper Functions * ******************************************************************************/ /** * Adjust the product stock level by a set amount. * * @param $sku * The product SKU of the stock level to adjust. * @param $qty * The amount to add to or subtract from the stock level. */ function uc_stock_adjust($sku, $qty, $check_active = TRUE) { $stock = db_fetch_object(db_query("SELECT active, stock FROM {uc_product_stock} WHERE sku = '%s'", $sku)); if ($check_active) { if (!$stock->active) { return; } } db_query("UPDATE {uc_product_stock} SET stock = stock + %d WHERE sku = '%s'", $qty, $sku); module_invoke_all('uc_stock_adjusted', $sku, $stock->stock, $qty); } /** * Set the product stock level. * * @param $sku * The product SKU of the stock level to set. * @param $qty * The number of items in stock. */ function uc_stock_set($sku, $qty) { db_query("UPDATE {uc_product_stock} SET stock = %d WHERE sku = '%s'", $qty, $sku); } /** * Get the stock level of a particular product SKU. * * @param $sku * The Ubercart product SKU of the stock level to return. * @return: * The SKU's stock level, or FALSE if not active. */ function uc_stock_level($sku) { $stock = db_fetch_object(db_query("SELECT active, stock FROM {uc_product_stock} WHERE sku = '%s'", $sku)); if ($stock && $stock->active) { return $stock->stock; } return FALSE; } /** * Check if a sku has an active stock record. * * @param $sku * The Ubercart product SKU to check * @return (bool) * Whether or not the sku has an active stock record. */ function uc_stock_is_active($sku) { return (bool) db_result(db_query("SELECT active FROM {uc_product_stock} WHERE sku = '%s'", $sku)); } /** * Emails administrator regarding any stock level thresholds hit. * * @param $order * The order object that tripped the threshold limit. * @param $product * The product object that is associated with the SKU. * @param $stock * The stock level object that contains the stock level and SKU. * @return * The result of drupal_mail(). */ function _uc_stock_send_mail($order, $stock) { $token_filters = array('global' => NULL, 'order' => $order, 'stock' => $stock); $account = user_load(array('uid' => $order)); $to = variable_get('uc_stock_threshold_notification_recipients', variable_get('uc_store_email', ini_get('sendmail_from'))); $to = explode(',', $to); $from = uc_store_email_from(); $subject = variable_get('uc_stock_threshold_notification_subject', uc_get_message('uc_stock_threshold_notification_subject')); $subject = token_replace_multiple($subject, $token_filters); $body = variable_get('uc_stock_threshold_notification_message', uc_get_message('uc_stock_threshold_notification_message')); $body = token_replace_multiple($body, $token_filters); // Send to each recipient. foreach ($to as $email) { $sent = drupal_mail('uc_stock', 'threshold', $email, uc_store_mail_recipient_language($email), array('body' => $body, 'subject' => $subject), $from); if (!$sent['result']) { watchdog('uc_stock', 'Attempt to e-mail @email concerning stock level on sku @sku failed.', array('@email' => $email, '@sku' => $stock->sku), WATCHDOG_ERROR); } } } /** * Implementation of hook_views_api(). */ function uc_stock_views_api() { return array( 'api' => '2.0', 'path' => drupal_get_path('module', 'uc_stock') .'/views', ); } /** * Deprecated. Wrapper function for uc_stock_adjust_product_stock(). * * Keeps backwards compatibility with contributed modules. */ function uc_stock_decrement_product_stock($product, $key, $order) { return uc_stock_adjust_product_stock($product, $key, $order); } /** * Adjust a product's stock. * * @param $product * The product whose stock is being adjusted. * @param $key * Internal, so this function can be used as a callback of array_walk(). * @param $order * Order object. */ function uc_stock_adjust_product_stock($product, $key, $order) { // Product has an active stock? if (!uc_stock_is_active($product->model)) { return; } // Do nothing if decrement quantity is 0 if ($product->qty == 0) { return; } // Adjust the product's stock. uc_stock_adjust($product->model, -$product->qty); // Load the new stock record $stock = db_fetch_object(db_query("SELECT * FROM {uc_product_stock} WHERE sku = '%s'", $product->model)); // Should we notify? if (variable_get('uc_stock_threshold_notification', FALSE) && $stock->stock <= $stock->threshold) { _uc_stock_send_mail($order, $stock); } // Save a comment about the stock level. uc_order_comment_save($order->order_id, 0, t('The stock level for %model_name has been !action to !qty.', array('%model_name' => $product->model, '!qty' => $stock->stock, '!action' => (-$product->qty <= 0) ? t('decreased') : t('increased') ))); }