FINAL suepr merge step : added all modules to this super repos

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-19 16:46:59 +02:00
7585 changed files with 1723356 additions and 18 deletions

View File

@@ -0,0 +1,95 @@
<?php
/**
* @file
* Ubercart stock related tests
*/
class UbercartStockTestCase extends UbercartTestHelper {
public static function getInfo() {
return array(
'name' => 'Stock',
'description' => 'Ensure that stock control functions properly.',
'group' => 'Ubercart',
);
}
/**
* Overrides DrupalWebTestCase::setUp().
*/
public function setUp() {
parent::setUp(array('uc_stock'), array('administer product stock'));
$this->drupalLogin($this->adminUser);
}
public function testProductStock() {
$this->drupalGet('node/' . $this->product->nid . '/edit/stock');
$this->assertText($this->product->title);
$this->assertText($this->product->model, 'Product SKU found.');
$this->assertNoFieldChecked('edit-stock-0-active', 'Stock tracking is not active.');
$this->assertFieldByName('stock[0][stock]', '0', 'Default stock level found.');
$this->assertFieldByName('stock[0][threshold]', '0', 'Default stock threshold found.');
$stock = rand(1, 1000);
$edit = array(
'stock[0][active]' => 1,
'stock[0][stock]' => $stock,
'stock[0][threshold]' => rand(1, 100),
);
$this->drupalPost(NULL, $edit, t('Save changes'));
$this->assertText('Stock settings saved.');
$this->assertTrue(uc_stock_is_active($this->product->model));
$this->assertEqual($stock, uc_stock_level($this->product->model));
$stock = rand(1, 1000);
uc_stock_set($this->product->model, $stock);
$this->drupalGet('node/' . $this->product->nid . '/edit/stock');
$this->assertFieldByName('stock[0][stock]', (string)$stock, 'Set stock level found.');
}
public function testStockDecrement() {
$stock = rand(100, 1000);
$edit = array(
'stock[0][active]' => 1,
'stock[0][stock]' => $stock,
);
$this->drupalPost('node/' . $this->product->nid . '/edit/stock', $edit, t('Save changes'));
$this->assertText('Stock settings saved.');
// Enable product quantity field.
variable_set('uc_product_add_to_cart_qty', TRUE);
$qty = rand(1, 100);
$edit = array('qty' => $qty);
$this->drupalPost('node/' . $this->product->nid, $edit, t('Add to cart'));
$this->checkout();
$this->assertEqual($stock - $qty, uc_stock_level($this->product->model));
}
public function testStockThresholdMail() {
$edit = array('uc_stock_threshold_notification' => 1);
$this->drupalPost('admin/store/settings/stock', $edit, 'Save configuration');
$qty = rand(10, 100);
$edit = array(
'stock[0][active]' => 1,
'stock[0][stock]' => $qty + 1,
'stock[0][threshold]' => $qty,
);
$this->drupalPost('node/' . $this->product->nid . '/edit/stock', $edit, 'Save changes');
$this->drupalPost('node/' . $this->product->nid, array(), 'Add to cart');
$this->checkout();
$mail = $this->drupalGetMails(array('id' => 'uc_stock_threshold'));
$mail = array_pop($mail);
$this->assertTrue(strpos($mail['subject'], 'Stock threshold limit reached') !== FALSE, 'Threshold mail subject is correct.');
$this->assertTrue(strpos($mail['body'], $this->product->title) !== FALSE, 'Mail body contains product title.');
$this->assertTrue(strpos($mail['body'], $this->product->model) !== FALSE, 'Mail body contains SKU.');
$this->assertTrue(strpos($mail['body'], 'has reached ' . $qty) !== FALSE, 'Mail body contains quantity.');
}
}

View File

@@ -0,0 +1,321 @@
<?php
/**
* @file
* Stock administration menu items.
*/
/**
* Form builder for stock settings form.
*
* @ingroup forms
*/
function uc_stock_settings_form($form, &$form_state) {
$form['uc_stock_threshold_notification'] = array(
'#type' => 'checkbox',
'#title' => t('Send email notification when stock level reaches its threshold value'),
'#default_value' => variable_get('uc_stock_threshold_notification', FALSE),
);
$form['uc_stock_threshold_notification_recipients'] = array(
'#type' => 'textfield',
'#title' => t('Notification recipients'),
'#default_value' => variable_get('uc_stock_threshold_notification_recipients', uc_store_email()),
'#description' => t('The list of comma-separated email addresses that will receive the notification.'),
);
$form['uc_stock_threshold_notification_subject'] = array(
'#type' => 'textfield',
'#title' => t('Message subject'),
'#default_value' => variable_get('uc_stock_threshold_notification_subject', uc_get_message('uc_stock_threshold_notification_subject')),
);
$form['uc_stock_threshold_notification_message'] = array(
'#type' => 'textarea',
'#title' => t('Message text'),
'#default_value' => variable_get('uc_stock_threshold_notification_message', uc_get_message('uc_stock_threshold_notification_message')),
'#description' => t('The message the user receives when the stock level reaches its threshold value.'),
'#rows' => 10,
);
if (module_exists('token')) {
$form['token_tree'] = array(
'#markup' => theme('token_tree', array('token_types' => array('uc_order', 'uc_stock', 'node', 'site', 'store'))),
);
}
return system_settings_form($form);
}
/**
* Displays a stock report for products with stock tracking enabled.
*/
function uc_stock_report() {
$page_size = (isset($_GET['nopage'])) ? UC_REPORTS_MAX_RECORDS : variable_get('uc_reports_table_size', 30);
$csv_rows = array();
$rows = array();
$header = array(
array('data' => t('SKU'), 'field' => 'sku', 'sort' => 'asc'),
array('data' => t('Product'), 'field' => 'title'),
array('data' => t('Stock'), 'field' => 'stock'),
array('data' => t('Threshold'), 'field' => 'threshold'),
array('data' => t('Operations')),
);
$csv_rows[] = array(t('SKU'), t('Product'), t('Stock'), t('Threshold'));
$query = db_select('uc_product_stock', 's')->extend('PagerDefault')->extend('TableSort')
->orderByHeader($header)
->limit($page_size)
->fields('s', array(
'nid',
'sku',
'stock',
'threshold',
));
$query->leftJoin('node', 'n', 's.nid = n.nid');
$query->addField('n', 'title');
$query->condition('active', 1)
->condition('title', '', '<>');
if (arg(4) == 'threshold') {
$query->where('threshold >= stock');
}
$result = $query->execute();
foreach ($result as $stock) {
$op = array();
if (user_access('administer product stock')) {
$op[] = l(t('edit'), 'node/' . $stock->nid . '/edit/stock', $options = array('query' => array('destination' => 'admin/store/reports/stock')));
}
// Add the data to a table row for display.
$rows[] = array(
'data' => array(
array('data' => $stock->sku),
array('data' => l($stock->title, 'node/' . $stock->nid)),
array('data' => $stock->stock),
array('data' => $stock->threshold),
array('data' => implode(' ', $op)),
),
'class' => array(($stock->threshold >= $stock->stock) ? 'uc-stock-below-threshold' : 'uc-stock-above-threshold'),
);
// Add the data to the CSV contents for export.
$csv_rows[] = array($stock->sku, $stock->title, $stock->stock, $stock->threshold);
}
module_load_include('inc', 'uc_reports', 'uc_reports.admin');
$csv_data = uc_reports_store_csv('uc_stock', $csv_rows);
$build['form'] = drupal_get_form('uc_stock_report_form');
$build['report'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
'#attributes' => array('width' => '100%', 'class' => array('uc-stock-table')),
);
$build['pager'] = array(
'#theme' => 'pager',
);
$build['links'] = array(
'#prefix' => '<div class="uc-reports-links">',
'#suffix' => '</div>',
);
$build['links']['export_csv'] = array(
'#markup' => l(t('Export to CSV file'), 'admin/store/reports/getcsv/' . $csv_data['report'] . '/' . $csv_data['user']),
'#suffix' => '&nbsp;&nbsp;&nbsp;',
);
if (isset($_GET['nopage'])) {
$build['links']['toggle_pager'] = array(
'#markup' => l(t('Show paged records'), 'admin/store/reports/stock'),
);
}
else {
$build['links']['toggle_pager'] = array(
'#markup' => l(t('Show all records'), 'admin/store/reports/stock', array('query' => array('nopage' => '1'))),
);
}
return $build;
}
/**
* Form builder for stock report threshold filter.
*
* @see uc_stock_report_form_submit()
* @ingroup forms
*/
function uc_stock_report_form($form, &$form_state) {
$form['threshold'] = array(
'#type' => 'checkbox',
'#title' => t('Only show SKUs that are below their threshold.'),
'#default_value' => arg(4) == 'threshold' ? TRUE : FALSE,
'#attributes' => array('onchange' => 'this.form.submit();'),
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#attributes' => array('style' => "display:none;"),
);
return $form;
}
/**
* Form submission handler for uc_stock_report_form().
*
* @see uc_stock_report_form()
*/
function uc_stock_report_form_submit($form, &$form_state) {
if ($form_state['values']['threshold']) {
drupal_goto('admin/store/reports/stock/threshold');
}
else {
drupal_goto('admin/store/reports/stock');
}
}
/**
* Form builder for product stock edit form.
*
* @see uc_stock_edit_form_submit()
* @see theme_uc_stock_edit_form()
* @ingroup forms
*/
function uc_stock_edit_form($form, &$form_state, $node) {
drupal_set_title($node->title);
$form['stock'] = array('#tree' => TRUE);
$skus = uc_product_get_models($node->nid);
// Remove 'Any'.
unset($skus[NULL]);
if (!$skus) {
drupal_set_message(t('No SKU found.'), 'error');
}
else {
foreach (array_values($skus) as $id => $sku) {
$stock = db_query("SELECT * FROM {uc_product_stock} WHERE sku = :sku", array(':sku' => $sku))->fetchAssoc();
$form['stock'][$id]['sku'] = array(
'#type' => 'value',
'#value' => $sku,
);
// Checkbox to mark this as active.
$form['stock'][$id]['active'] = array(
'#type' => 'checkbox',
'#default_value' => !empty($stock['active']) ? $stock['active'] : 0,
);
// Sanitized version of the SKU for display.
$form['stock'][$id]['display_sku'] = array(
'#markup' => check_plain($sku),
);
// Textfield for entering the stock level.
$form['stock'][$id]['stock'] = array(
'#type' => 'textfield',
'#default_value' => !empty($stock['stock']) ? $stock['stock'] : 0,
'#maxlength' => 9,
'#size' => 9,
);
// Textfield for entering the threshold level.
$form['stock'][$id]['threshold'] = array(
'#type' => 'textfield',
'#default_value' => !empty($stock['threshold']) ? $stock['threshold'] : 0,
'#maxlength' => 9,
'#size' => 9,
);
}
}
$form['nid'] = array(
'#type' => 'value',
'#value' => $node->nid,
);
$form['actions'] = array('#type' => 'actions');
$form['actions']['save'] = array(
'#type' => 'submit',
'#value' => t('Save changes'),
);
return $form;
}
/**
* Form submission handler for uc_stock_edit_form().
*
* @see uc_stock_edit_form()
* @see theme_uc_stock_edit_form()
*/
function uc_stock_edit_form_submit($form, &$form_state) {
foreach (element_children($form_state['values']['stock']) as $id) {
$stock = $form_state['values']['stock'][$id];
db_merge('uc_product_stock')
->key(array('sku' => $stock['sku']))
->updateFields(array(
'active' => $stock['active'],
'stock' => $stock['stock'],
'threshold' => $stock['threshold'],
))
->insertFields(array(
'sku' => $stock['sku'],
'active' => $stock['active'],
'stock' => $stock['stock'],
'threshold' => $stock['threshold'],
'nid' => $form_state['values']['nid'],
))
->execute();
}
drupal_set_message(t('Stock settings saved.'));
}
/**
* Returns HTML for uc_stock_edit_form().
*
* @param $variables
* An associative array containing:
* - form: A render element representing the form.
*
* @see uc_stock_edit_form()
* @see uc_stock_edit_form_submit()
* @ingroup themeable
*/
function theme_uc_stock_edit_form($variables) {
$form = $variables['form'];
drupal_add_js('misc/tableselect.js');
$header = array(
array('data' => '&nbsp;&nbsp;' . t('Active'), 'class' => array('select-all')),
array('data' => t('SKU')),
array('data' => t('Stock')),
array('data' => t('Threshold')),
);
$rows = array();
foreach (element_children($form['stock']) as $id) {
$rows[] = array(
array('data' => drupal_render($form['stock'][$id]['active'])),
array('data' => drupal_render($form['stock'][$id]['display_sku'])),
array('data' => drupal_render($form['stock'][$id]['stock'])),
array('data' => drupal_render($form['stock'][$id]['threshold'])),
);
}
return theme('table', array('header' => $header, 'rows' => $rows)) . drupal_render_children($form);
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* @file
* Hooks provided by the Stock module.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Allows modules to take action when a stock level is changed.
*
* @param $sku
* The SKU whose stock level is being changed.
* @param $stock
* The stock level before the adjustment.
* @param $qty
* The amount by which the stock level was changed.
*/
function hook_uc_stock_adjusted($sku, $stock, $qty) {
$params = array(
'sku' => $sku,
'stock' => $stock,
'qty' => $qty,
);
drupal_mail('uc_stock_notify', 'stock-adjusted', uc_store_email_from(), language_default(), $params);
}
/**
* @} End of "addtogroup hooks".
*/

View File

@@ -0,0 +1,20 @@
name = Stock
description = Manages stock levels of your products.
dependencies[] = uc_product
package = Ubercart - extra
core = 7.x
; Test cases
files[] = tests/uc_stock.test
; Views handlers
files[] = views/uc_stock_handler_filter_below_threshold.inc
configure = admin/store/settings/stock
; Information added by Drupal.org packaging script on 2013-12-17
version = "7.x-3.6"
core = "7.x"
project = "ubercart"
datestamp = "1387304010"

View File

@@ -0,0 +1,102 @@
<?php
/**
* @file
* Install, update and uninstall functions for the uc_stock module.
*/
/**
* Implements hook_schema().
*/
function uc_stock_schema() {
$schema = array();
$schema['uc_product_stock'] = array(
'description' => 'Stock levels for Ubercart products.',
'fields' => array(
'sku' => array(
'description' => 'SKU (Stock Keeping Unit) of a product.',
'type' => 'varchar',
'length' => '255',
'not null' => TRUE,
'default' => '',
),
'nid' => array(
'description' => 'Node ID of a product.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'active' => array(
'description' => 'Boolean flag indicating whether stock is being tracked for this product. 1 => Yes. 0 => No.',
'type' => 'int',
'size' => 'tiny',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'stock' => array(
'description' => 'Quantity in stock.',
'type' => 'int',
'size' => 'medium',
'not null' => TRUE,
'default' => 0,
),
'threshold' => array(
'description' => 'Minimum quantity threshold level.',
'type' => 'int',
'size' => 'medium',
'not null' => TRUE,
'default' => 0,
),
),
'indexes' => array(
'nid' => array('nid'),
),
'primary key' => array('sku'),
'foreign keys' => array(
'uc_products' => array(
'table' => 'uc_products',
'columns' => array('nid' => 'nid'),
),
),
);
return $schema;
}
/**
* Implements hook_uninstall().
*/
function uc_stock_uninstall() {
db_delete('variable')
->condition('name', 'uc_stock_%', 'LIKE')
->execute();
variable_del('uc_stock_threshold_notification');
variable_del('uc_stock_threshold_notification_recipients');
variable_del('uc_stock_threshold_notification_subject');
variable_del('uc_stock_threshold_notification_message');
}
/**
* Implements hook_update_last_removed().
*/
function uc_stock_update_last_removed() {
return 6000;
}
/**
* Remove unused message format variable.
*/
function uc_stock_update_7000() {
variable_del('uc_stock_threshold_notification_format');
}
/**
* Remove unused message format variable.
*/
function uc_stock_update_7001() {
variable_del('uc_stock_threshold_notification_message_format');
}

View File

@@ -0,0 +1,297 @@
<?php
/**
* @file
* Allow ubercart products to have stock levels associated with their SKU
*
* uc_stock enables ubercart to manage stock for products. Store admins can set
* the stock levels on a product edit page and a threshold for each SKU value
* When that threshold is reached admins can be optionally notified about the
* current stock level. Store admins can view all stock levels in the reports
* section of Ubercart.
*
* Development sponsored by the Ubercart project. http://www.ubercart.org
*/
/**
* Implements hook_help().
*/
function uc_stock_help($path, $arg) {
switch ($path) {
case 'node/%/edit/stock':
return '<p>' . t('To keep track of stock for a particular product SKU, make sure it is marked as active and enter a stock value. When the stock level drops below the threshold value, you can be notified based on your stock settings.') . '</p>';
case 'admin/store/reports/stock':
case 'admin/store/reports/stock/threshold':
return '<p>' . t('This is the list of product SKUs that are currently active. Stock levels below their threshold have highlighted rows. Toggle the checkbox below to alter which stock levels are shown.') . '</p>';
}
}
/**
* Implements hook_menu().
*/
function uc_stock_menu() {
$items = array();
$items['admin/store/settings/stock'] = array(
'title' => 'Stock notifications',
'description' => 'Enable or disable stock level notifications.',
'page callback' => 'drupal_get_form',
'page arguments' => array('uc_stock_settings_form'),
'access arguments' => array('administer product stock'),
'file' => 'uc_stock.admin.inc',
);
if (module_exists('uc_reports')) {
$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'),
'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;
}
/**
* Implements hook_admin_paths().
*/
function uc_stock_admin_paths() {
$paths = array(
'node/*/edit/stock' => TRUE,
);
return $paths;
}
/**
* 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');
}
/**
* Implements hook_permission().
*/
function uc_stock_permission() {
return array(
'administer product stock' => array(
'title' => t('Administer product stock'),
)
);
}
/**
* Implements hook_theme().
*/
function uc_stock_theme() {
return array(
'uc_stock_edit_form' => array(
'render element' => 'form',
'file' => 'uc_stock.admin.inc',
),
);
}
/**
* Implements hook_mail().
*/
function uc_stock_mail($key, &$message, $params) {
switch ($key) {
case 'threshold':
$message['subject'] = $params['subject'];
$message['body'][] = $params['body'];
break;
}
}
/**
* Implements 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 "[node:title]" with SKU [uc_stock:model] has reached [uc_stock:level]. There may not be enough units in stock to fulfill order #[uc_order:link].');
return $messages;
}
/**
* Adjusts 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.
* @param $check_active
* If FALSE, don't check if stock tracking is active for this SKU.
*/
function uc_stock_adjust($sku, $qty, $check_active = TRUE) {
$stock = db_query("SELECT active, stock FROM {uc_product_stock} WHERE sku = :sku", array(':sku' => $sku))->fetchObject();
if ($check_active) {
if (!$stock || !$stock->active) {
return;
}
}
db_update('uc_product_stock')
->expression('stock', 'stock + :qty', array(':qty' => $qty))
->condition('sku', $sku)
->execute();
module_invoke_all('uc_stock_adjusted', $sku, $stock->stock, $qty);
}
/**
* Sets 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_update('uc_product_stock')
->fields(array('stock' => $qty))
->condition('sku', $sku)
->execute();
}
/**
* Gets 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_query("SELECT active, stock FROM {uc_product_stock} WHERE sku = :sku", array(':sku' => $sku))->fetchObject();
if ($stock && $stock->active) {
return $stock->stock;
}
return FALSE;
}
/**
* Checks if a SKU has an active stock record.
*
* @param $sku
* The Ubercart product SKU to check
*
* @return
* Boolean indicating whether or not the sku has an active stock record.
*/
function uc_stock_is_active($sku) {
return (bool) db_query("SELECT active FROM {uc_product_stock} WHERE sku = :sku", array(':sku' => $sku))->fetchField();
}
/**
* Emails administrator regarding any stock level thresholds hit.
*
* @param $order
* The order object that tripped the threshold limit.
* @param $node
* The node object that is associated with the SKU/model.
* @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, $node, $stock) {
$account = user_load($order->uid);
$token_filters = array('uc_order' => $order, 'user' => $account, 'uc_stock' => $stock, 'node' => $node);
$to = variable_get('uc_stock_threshold_notification_recipients', uc_store_email());
$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($subject, $token_filters);
$body = variable_get('uc_stock_threshold_notification_message', uc_get_message('uc_stock_threshold_notification_message'));
$body = token_replace($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, 'order' => $order, 'stock' => $stock), $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);
}
}
}
/**
* Implements hook_views_api().
*/
function uc_stock_views_api() {
return array(
'api' => '2.0',
'path' => drupal_get_path('module', 'uc_stock') . '/views',
);
}
/**
* Decrement 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_query("SELECT * FROM {uc_product_stock} WHERE sku = :sku", array(':sku' => $product->model))->fetchObject();
// Should we notify?
if (variable_get('uc_stock_threshold_notification', FALSE) && $stock->stock <= $stock->threshold) {
$node = node_load($product->nid);
_uc_stock_send_mail($order, $node, $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') )));
}
/**
* Increment a product's stock.
*/
function uc_stock_increment_product_stock($product, $key, $order) {
$product->qty = -$product->qty;
return uc_stock_adjust_product_stock($product, $key, $order);
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* @file
* Rules hooks for uc_stock.module.
*/
/**
* Implements hook_rules_action_info().
*/
function uc_stock_rules_action_info() {
$actions['uc_stock_action_decrement_stock'] = array(
'label' => t('Decrement stock of products on the order with tracking activated.'),
'group' => t('Stock'),
'base' => 'uc_stock_action_decrement_stock',
'parameter' => array(
'order' => array(
'type' => 'uc_order',
'label' => t('Order'),
),
),
);
$actions['uc_stock_action_increment_stock'] = array(
'label' => t('Increment stock of products on the order with tracking activated.'),
'group' => t('Stock'),
'base' => 'uc_stock_action_increment_stock',
'parameter' => array(
'order' => array(
'type' => 'uc_order',
'label' => t('Order'),
),
),
);
return $actions;
}
/**
* Decreases the stock of ordered products.
*/
function uc_stock_action_decrement_stock($order) {
if (is_array($order->products)) {
array_walk($order->products, 'uc_stock_adjust_product_stock', $order);
}
}
/**
* Increase the stock of ordered products.
*/
function uc_stock_action_increment_stock($order, $settings) {
if (is_array($order->products)) {
array_walk($order->products, 'uc_stock_increment_product_stock', $order);
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* @file
* Rules default configurations for uc_stock.module.
*/
/**
* Implements hook_default_rules_configuration().
*/
function uc_stock_default_rules_configuration() {
$configs = array();
$rule = rules_reaction_rule();
$rule->label = t('Decrement stock upon order submission');
$rule->active = TRUE;
$rule->event('uc_checkout_complete')
->action('uc_stock_action_decrement_stock', array('order:select' => 'order'));
$configs['uc_stock_decrement_on_order'] = $rule;
$rule = rules_reaction_rule();
$rule->label = t('Increment stock on cancelling order');
$rule->active = FALSE;
$rule->event('uc_order_status_update')
->condition(rules_condition('data_is', array('data:select' => 'updated_order:order-status', 'value' => 'canceled')))
->condition(rules_condition('data_is', array('data:select' => 'order:order-status', 'value' => 'canceled'))->negate())
->condition(rules_condition('data_is', array('data:select' => 'order:order-status', 'value' => 'in_checkout'))->negate())
->action('uc_stock_action_increment_stock', array('order:select' => 'order'));
$configs['uc_stock_increment_on_cancel'] = $rule;
$rule = rules_reaction_rule();
$rule->label = t('Increment stock on deleting an order');
$rule->active = FALSE;
$rule->event('uc_order_delete')
->condition(rules_condition('data_is', array('data:select' => 'order:order-status', 'value' => 'canceled'))->negate())
->condition(rules_condition('data_is', array('data:select' => 'order:order-status', 'value' => 'in_checkout'))->negate())
->action('uc_stock_action_increment_stock', array('order:select' => 'order'));
$configs['uc_stock_increment_on_delete'] = $rule;
$rule = rules_reaction_rule();
$rule->label = t('Decrement stock when order cancellation is being undone');
$rule->active = FALSE;
$rule->event('uc_order_status_update')
->condition(rules_condition('data_is', array('data:select' => 'order:order-status', 'value' => 'canceled')))
->condition(rules_condition('data_is', array('data:select' => 'updated_order:order-status', 'value' => 'canceled'))->negate())
->condition(rules_condition('data_is', array('data:select' => 'updated_order:order-status', 'value' => 'in_checkout'))->negate())
->action('uc_stock_action_decrement_stock', array('order:select' => 'order'));
$configs['uc_stock_decrement_on_uncancel'] = $rule;
return $configs;
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* @file
* Token hooks for the uc_stock module.
*/
/**
* Implements hook_token_info().
*/
function uc_stock_token_info() {
$type = array(
'name' => t('Stock level'),
'description' => t('Tokens for the stock levels of products.'),
'needs-data' => 'uc_stock',
);
$tokens['level'] = array(
'name' => t('Level'),
'description' => t('The current stock level.'),
);
$tokens['model'] = array(
'name' => t('Model'),
'description' => t('The model or SKU of the stock level.'),
);
$tokens['threshold'] = array(
'name' => t('Threshold'),
'description' => t('The threshold or warning limit of the stock level.'),
);
return array(
'types' => array('uc_stock' => $type),
'tokens' => array('uc_stock' => $tokens),
);
}
/**
* Implements hook_tokens().
*/
function uc_stock_tokens($type, $tokens, $data = array(), $options = array()) {
$sanitize = !empty($options['sanitize']);
$replacements = array();
if ($type == 'uc_stock' && !empty($data['uc_stock'])) {
$object = $data['uc_stock'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'level':
$replacements[$original] = $object->stock;
break;
case 'model':
$replacements[$original] = $sanitize ? check_plain($object->sku) : $object->sku;
break;
case 'threshold':
$replacements[$original] = $object->threshold;
break;
}
}
}
return $replacements;
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* @file
* Variable module hook implementations.
*/
/**
* Implements hook_variable_group_info().
*/
function uc_stock_variable_group_info() {
$groups['uc_stock'] = array(
'title' => t('Ubercart stock settings'),
'access' => 'administer store',
'path' => array('admin/store/settings/stock'),
);
return $groups;
}
/**
* Implements hook_variable_info().
*/
function uc_stock_variable_info($options) {
$variables['uc_stock_threshold_notification_message'] = array(
'type' => 'text',
'title' => t('Message text', array(), $options),
'description' => t('The message the user receives when the stock level reaches its threshold value.', array(), $options),
'group' => 'uc_stock',
'default' => t('[store:name]: Stock threshold limit reached', array(), $options),
);
$variables['uc_stock_threshold_notification_subject'] = array(
'type' => 'text',
'title' => t('Message subject', array(), $options),
'description' => t('The subject line of the message the user receives when the stock level reaches its threshold value.', array(), $options),
'group' => 'uc_stock',
'default' => t('This message has been sent to let you know that the stock level for "[node:title]" with SKU [uc_stock:model] has reached [uc_stock:level]. There may not be enough units in stock to fulfill order #[uc_order:link].', array(), $options),
);
return $variables;
}

View File

@@ -0,0 +1,95 @@
<?php
/**
* @file
* Views hooks and callback registries.
*/
/**
* Implements hook_views_data().
*/
function uc_stock_views_data() {
$data['uc_product_stock']['table']['group'] = t('Stock');
// Attach stock data to nodes.
$data['uc_product_stock']['table']['join']['node'] = array(
'left_field' => 'nid',
'field' => 'nid',
);
$data['uc_product_stock']['sku'] = array(
'title' => t('SKU'),
'help' => t('The model or SKU of the stock level.'),
'field' => array(
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
);
$data['uc_product_stock']['active'] = array(
'title' => t('Active'),
'help' => t('Whether or not stock is currently being tracked.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean_operator',
'label' => t('Active'),
'type' => 'yes-no',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['uc_product_stock']['stock'] = array(
'title' => t('Level'),
'help' => t('The current stock level.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['uc_product_stock']['threshold'] = array(
'title' => t('Threshold'),
'help' => t('The level at which a stock warning can be sent.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['uc_product_stock']['below_threshold'] = array(
'title' => t('Is below threshold'),
'help' => t('Filter the node based on whether its stock level is below the threshold for the SKU.'),
'filter' => array(
'handler' => 'uc_stock_handler_filter_below_threshold',
'label' => t('Is below threshold'),
'type' => 'yes-no',
),
);
return $data;
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* @file
* Views handler: Filter on comparison of stock level to threshold.
*/
/**
* Filters nodes based on comparison of stock value to stock threshold.
*/
class uc_stock_handler_filter_below_threshold extends views_handler_filter_boolean_operator {
/**
* Overrides views_handler_field::query().
*/
function query() {
$this->ensure_my_table();
$this->query->add_where_expression($this->options['group'], "$this->table_alias.stock " . (empty($this->value) ? '>=' : '<') . " $this->table_alias.threshold");
}
}