uc_product_minmax.module in Ubercart Product Minimum & Maximum 6
Same filename and directory in other branches
This module adds a textfield to product forms for you to enter a minimum and maximum quantity of the product that must be in the cart for it to be checked out.
The product min/max checkout pane must be the lowest weighted cart pane in order for the logic to properly intercept any invalid carts.
Product Min & Max modules originally coded by Ryan of Ubercart.org. Combined and converted to product feature by fred0.
Original development sponsored by Plum Drama - http://www.plumdrama.com
File
uc_product_minmax.moduleView source
<?php
/**
* @file
* This module adds a textfield to product forms for you to enter a minimum
* and maximum quantity of the product that must be in the cart for it to be checked out.
*
* The product min/max checkout pane must be the lowest weighted cart pane in
* order for the logic to properly intercept any invalid carts.
*
* Product Min & Max modules originally coded by Ryan of Ubercart.org.
* Combined and converted to product feature by fred0.
*
* Original development sponsored by Plum Drama - http://www.plumdrama.com
*/
/*******************************************************************************
* Product Feature API (Ubercart)
******************************************************************************/
/**
* Implementation of hook_product_feature().
*/
function uc_product_minmax_product_feature() {
$features[] = array(
'id' => 'minmax',
'title' => t('Product Minimum & Maximum'),
'callback' => 'uc_product_minmax_feature_form',
'delete' => 'uc_product_minmax_feature_delete',
'settings' => 'uc_product_minmax_feature_settings',
);
return $features;
}
/**
* This function gets called when an administrator browses to the product
* features settings form. It should return an array of form elements to add to
* this feature's fieldset in the form if necessary.
*/
function uc_product_minmax_feature_settings() {
$form['uc_product_minmax_position'] = array(
'#type' => 'radios',
'#title' => t('Display Position'),
'#description' => t('Set the default position of the minimum and maximum on the product page.<br />This can be overridden on individual products..'),
'#default_value' => variable_get('uc_product_minmax_position', 0),
'#options' => array(
t('As node item'),
t('As description below Quantity field'),
),
);
$form['uc_product_minmax_weight'] = array(
'#type' => 'weight',
'#title' => t('Node item page weight'),
'#description' => t('Only has an effect if the above setting is <b>As node item</b>.<br />Set the default position of the minimum and maximum on the product page.<br />This can be overridden on individual products.<br />Refer to the <a href="/admin/store/settings/products/edit/fields">Product Field settings</a> for other element weights.'),
'#default_value' => variable_get('uc_product_minmax_weight', 9),
'#delta' => 100,
);
return $form;
}
/**
* This form gets displayed when a product feature is added or edited for this
* product feature type.
*/
function uc_product_minmax_feature_form($form_state, $node, $feature) {
if (!empty($feature)) {
$minmax = uc_product_minmax_values_load($feature['pfid']);
}
$form['nid'] = array(
'#type' => 'hidden',
'#value' => $node->nid,
);
$form['min_fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Minimum'),
);
$form['min_fieldset']['product_min'] = array(
'#type' => 'textfield',
'#title' => t('Minimum quantity to checkout'),
'#description' => t('Enter the minimum quantity of this product needed to checkout.'),
'#default_value' => $minmax->product_min,
'#size' => 10,
);
$form['min_fieldset']['display_min'] = array(
'#type' => 'checkbox',
'#title' => t('Display the Minimum text on product page'),
'#default_value' => !is_null($minmax->display_min) ? $minmax->display_min : 1,
'#description' => t('Only has effect when Minimum is greater than 1 or multiples is checked.'),
);
$form['min_fieldset']['pmin_multiple'] = array(
'#type' => 'textfield',
'#title' => t('Products must be purchased in multiples of'),
'#default_value' => !empty($minmax->pmin_multiple) ? $minmax->pmin_multiple : 1,
'#size' => 10,
);
$form['min_fieldset']['display_multiple'] = array(
'#type' => 'checkbox',
'#title' => t('Display the Multiple text on product page'),
'#default_value' => !is_null($minmax->display_multiple) ? $minmax->display_multiple : 1,
'#description' => t('Only has effect when Multiple is greater than 1.'),
);
$form['max_fieldset'] = array(
'#type' => 'fieldset',
'#title' => t('Maxmimum'),
);
$form['max_fieldset']['product_max'] = array(
'#type' => 'textfield',
'#title' => t('Maximum quantity allowed to checkout'),
'#description' => t('Enter the maximum quantity of this product allowed to checkout. Set 0 for no limit.'),
'#default_value' => !empty($minmax->product_max) ? $minmax->product_max : 0,
'#size' => 10,
);
$form['max_fieldset']['display_max'] = array(
'#type' => 'checkbox',
'#title' => t('Display the Maximum text on product page'),
'#default_value' => !is_null($minmax->display_max) ? $minmax->display_max : 1,
'#description' => t('Only has effect when Maximum is greater than 0.'),
);
$form['display_weight'] = array(
'#type' => 'weight',
'#title' => t('Product Page weight'),
'#description' => t('Set the position of the minimum and maximum on the product page.<br ?> This overrides the default setting.<br />Refer to the <a href="/admin/store/settings/products/edit/fields">Product Field settings</a> for other element weights.'),
'#default_value' => !empty($minmax->display_weight) ? $minmax->display_weight : variable_get('uc_product_minmax_weight', 9),
'#delta' => 100,
);
return uc_product_feature_form($form);
}
function uc_product_minmax_feature_form_validate($form, &$form_state) {
$minmax = uc_product_minmax_feature_load($form_state['values']['nid']);
if ($minmax && $minmax->pfid != $form_state['values']['pfid']) {
form_set_error('minmax_exists', t('Product Minimum & Maximum feature already exists for this product.'));
}
if (!ctype_digit($form_state['values']['product_min'])) {
form_set_error('product_min', t('The value for Minimum must be zero or a positive integer.'));
}
if (empty($form_state['values']['pmin_multiple']) || !ctype_digit($form_state['values']['pmin_multiple'])) {
form_set_error('pmin_multiple', t('The value for Multiple must be an integer greater than zero'));
}
if (!ctype_digit($form_state['values']['product_max'])) {
form_set_error('product_max', t('The value for Maximum must be zero or a positive integer.'));
}
}
function uc_product_minmax_feature_form_submit($form, &$form_state) {
// Use the form specified pfid if available.
if (!empty($form_state['values']['pfid'])) {
$pfid = $form_state['values']['pfid'];
}
$minmax->pfid = $pfid;
$minmax->nid = $form_state['values']['nid'];
$minmax->product_min = intval($form_state['values']['product_min']);
$minmax->pmin_multiple = intval($form_state['values']['pmin_multiple']);
$minmax->product_max = intval($form_state['values']['product_max']);
$minmax->display_min = $form_state['values']['display_min'];
$minmax->display_multiple = $form_state['values']['display_multiple'];
$minmax->display_max = $form_state['values']['display_max'];
$minmax->display_weight = $form_state['values']['display_weight'];
$args = array(
'@min' => $minmax->pmin_multiple > 1 ? t('Requires item to be purchased in multiples of @multiple.', array(
'@multiple' => $minmax->pmin_multiple,
)) : t('Requires a minimum of @minimum to checkout.', array(
'@minimum' => $minmax->product_min,
)),
'@max' => $minmax->product_max >= 1 ? t('Limits checkout to a maximum of @maximum.', array(
'@maximum' => $minmax->product_max,
)) : '',
);
$data = array(
'pfid' => $form_state['values']['pfid'],
'nid' => $form_state['values']['nid'],
'fid' => 'minmax',
'description' => t('@min @max', $args),
);
// Save the product feature and store the returned URL as our redirect.
$form_state['redirect'] = uc_product_feature_save($data);
if (empty($pfid)) {
$minmax->pfid = db_last_insert_id('uc_product_features', 'pfid');
}
uc_product_minmax_values_save($minmax);
}
/**
* This function gets called when a feature of this type is deleted.
*/
function uc_product_minmax_feature_delete($pfid) {
db_query("DELETE FROM {uc_product_minmax} WHERE pfid = %d", $pfid);
}
/*******************************************************************************
* Hook Functions (Ubercart)
******************************************************************************/
/**
* Implementation of hook_add_to_cart().
*/
function uc_product_minmax_add_to_cart($nid, $qty, $data) {
$minmax = uc_product_minmax_feature_load($nid);
$cart_total = 0;
$items = uc_cart_get_contents();
foreach ($items as $item) {
if ($item->nid === $nid) {
if (module_exists('uc_product_kit') && in_array('uc_product_kit', $item->data)) {
continue;
}
// If item is part of a product kit, do not count cart items
$cart_total += $item->qty;
}
}
$node = node_load($nid);
$message = array();
if ($minmax->product_min && $qty < $minmax->product_min) {
$message[] = t('The minimum order quantity for <em>!item</em> is @qty.', array(
'@qty' => $minmax->product_min,
'!item' => $node->title,
));
}
if ($minmax->product_max && $qty + $cart_total > $minmax->product_max) {
$message[] = t('The maximum order quantity for <em>!item</em> is @qty and you already have @qty in your cart.', array(
'@qty' => $minmax->product_max,
'!item' => $node->title,
));
}
else {
if ($minmax->product_max && $qty > $minmax->product_max) {
$message[] = t('The maximum order quantity for <em>!item</em> is @qty.', array(
'@qty' => $minmax->product_max,
'!item' => $node->title,
));
}
}
if ($minmax->pmin_multiple && $qty % $minmax->pmin_multiple) {
$message[] = t('Orders for <em>!item</em> must be in multiples of @qty.', array(
'@qty' => $minmax->pmin_multiple,
'!item' => $node->title,
));
}
if (count($message)) {
$result[] = array(
'success' => FALSE,
'message' => theme_item_list($message, t('Please check your quantity and try again.'), 'ul'),
'silent' => FALSE,
);
}
if (module_exists('uc_product_kit') && isset($data['kit_id'])) {
return;
// If item is part of a product kit, do not apply minmax rules
}
else {
return $result;
}
}
/**
* Prevent illegal modifications of quantities in cart
*/
function uc_product_minmax_form_uc_cart_view_form_alter(&$form, &$form_state) {
foreach (element_children($form['items']) as $i) {
if (!$form['items'][$i]['nid']) {
continue;
}
// if removing all items or items with errors, skip validation
if (array_key_exists('post', $form_state)) {
if (array_key_exists('items', $form_state['post'])) {
if (array_key_exists($i, $form_state['post']['items'])) {
if (array_key_exists('remove', $form_state['post']['items'][$i])) {
continue;
}
}
}
}
// If item in cart is part of a product kit, do not apply minmax rules
if (module_exists('uc_product_kit')) {
if (in_array('uc_product_kit', (array) $form['items'][$i]['module'])) {
continue;
}
}
$nid = $form['items'][$i]['nid']['#value'];
$minmax = uc_product_minmax_feature_load($nid);
if (!$minmax) {
continue;
}
$form['items'][$i]['#element_validate'][] = 'uc_product_minmax_cart_validate';
}
}
function uc_product_minmax_cart_validate($element, &$form_state) {
$nid = $element['nid']['#value'];
$qty = $element['qty']['#value'];
$minmax = uc_product_minmax_feature_load($nid);
$message = array();
if ($minmax->pmin_multiple && $qty % $minmax->pmin_multiple) {
$message[] = t('!item must be ordered in multiples of !qty.', array(
'!item' => $element['title']['#value'],
'!qty' => $minmax->pmin_multiple,
));
}
if ($minmax->product_min && $qty < $minmax->product_min) {
$message[] = t('You must order !min or more of !item.', array(
'!item' => $element['title']['#value'],
'!min' => $minmax->product_min,
));
}
if ($minmax->product_max && $qty > $minmax->product_max) {
$message[] = t('You cannot order more than !max of !item.', array(
'!item' => $element['title']['#value'],
'!max' => $minmax->product_max,
));
}
if (count($message)) {
form_error($element['qty'], theme_item_list($message, t('Please check your quantity and try again.'), 'ul'));
}
}
/*******************************************************************************
* Theme and Node functions to display minmax restrictions as node item
* if selected in product feature general settings.
******************************************************************************/
/**
* Implementation of hook_theme()
* Themes the product minimum notice line on product view pages.
*/
function uc_product_minmax_theme() {
return array(
'uc_product_minmax' => array(
'arguments' => array(
'min' => NULL,
'multiple' => NULL,
'max' => NULL,
'display_min' => NULL,
'display_multiple' => NULL,
'display_max' => NULL,
'display_weight' => NULL,
),
),
);
}
function theme_uc_product_minmax($min, $multiple, $max, $display_min, $display_multiple, $display_max) {
if ($multiple > 1 && $display_multiple) {
$output = '<div class="uc_product_multiple">' . t('This product must be ordered in sets of !qty.', array(
'!qty' => $multiple,
)) . '</div>';
}
if ($min > 1 && $display_min) {
$output .= '<div class="uc_product_min">' . t('A minimum order of at least !qty is required.', array(
'!qty' => $min,
)) . '</div>';
}
if ($max >= 1 && $display_max) {
$output .= '<div class="uc_product_max">' . t('A maximum order of !qty is allowed.', array(
'!qty' => $max,
)) . '</div>';
}
return '<div class="product-minmax">' . $output . '</div>';
}
/**
* Implementation of hook_nodeapi().
*/
function uc_product_minmax_nodeapi(&$node, $op, $a3 = null, $a4 = null) {
switch ($op) {
case 'load':
if (variable_get('uc_product_minmax_position', 0) == 0) {
return (array) uc_product_minmax_feature_load($node->nid);
}
case 'view':
if (variable_get('uc_product_minmax_position', 0) == 0) {
if ($node->display_min || $node->display_max || $node->display_multiple) {
if ($node->product_min > 1 || $node->display_multiple > 1 || $node->product_max >= 1) {
drupal_add_css(drupal_get_path('module', 'uc_product_minmax') . '/uc_product_minmax.css', 'module', 'all', TRUE);
$node->content['product_minmax'] = array(
'#value' => theme('uc_product_minmax', $node->product_min, $node->pmin_multiple, $node->product_max, $node->display_min, $node->display_multiple, $node->display_max, $minmax->display_weight),
'#weight' => !empty($node->display_weight) ? $node->display_weight : variable_get('uc_product_minmax_weight', -9),
);
}
}
}
break;
case 'delete':
// Delete corresponding data from {uc_product_features} and {uc_product_minmax} tables
db_query("DELETE FROM {uc_product_features} WHERE nid = %d AND fid='minmax'", $node->nid);
db_query("DELETE FROM {uc_product_minmax} WHERE nid = %d", $node->nid);
break;
}
}
/*******************************************************************************
* Display minmax restrictions in add to cart form if selected in product
* feature general settings.
******************************************************************************/
/**
* Implementation of hook_form_alter().
*/
function uc_product_minmax_form_alter(&$form, &$form_state, $form_id) {
// Add text for "Add to cart" and "Buy it now" forms
if (variable_get('uc_product_minmax_position', 0) == 1) {
if (strpos($form_id, 'add_to_cart_form') > 0 || strpos($form_id, 'uc_catalog_buy_it_now_form_') === 0) {
$minmax = uc_product_minmax_feature_load($form['nid']['#value']);
if ($minmax->pmin_multiple > 1 && $minmax->display_multiple) {
$output = '<div class="uc_product_multiple">' . t('This product must be ordered in sets of !qty.', array(
'!qty' => $minmax->pmin_multiple,
)) . '</div>';
}
if ($minmax->product_min > 1 && $minmax->display_min) {
$output .= '<div class="uc_product_min">' . t('A minimum order of at least !qty is required.', array(
'!qty' => $minmax->product_min,
)) . '</div>';
}
if ($minmax->product_max >= 1 && $minmax->display_max) {
$output .= '<div class="uc_product_max">' . t('A maximum order of !qty is allowed.', array(
'!qty' => $minmax->product_max,
)) . '</div>';
}
$form['qty']['#description'] = $output;
}
}
}
/*******************************************************************************
* Misc and callbacks
******************************************************************************/
/**
* Restrict multiple minmax features from being added to a single product.
* Disable feature on product kits since it doesn't have any effect on them.
*/
function uc_product_minmax_form_uc_product_feature_add_form_alter(&$form, &$form_state) {
if (uc_product_minmax_feature_load(arg(1)) || uc_product_minmax_product_kit_load(arg(1))) {
unset($form['feature']['#options']['minmax']);
}
}
/**
* Load minmax product feature for the given node
*/
function uc_product_minmax_feature_load($nid) {
return db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE nid = %d", $nid));
}
/**
* Load product kit matches for the given node
*/
function uc_product_minmax_product_kit_load($nid) {
if (module_exists('uc_product_kit')) {
return db_fetch_object(db_query("SELECT * FROM {uc_product_kits} WHERE nid = %d", $nid));
}
}
/**
* Saves the min & max values.
*
* @param $minmax
* A min and max value object.
*/
function uc_product_minmax_values_save($minmax) {
// Allow other modules to change the saved data.
drupal_alter('product_minmax_values_save', $minmax);
db_query("DELETE FROM {uc_product_minmax} WHERE pfid = %d", $minmax->pfid);
drupal_write_record('uc_product_minmax', $minmax);
}
/**
* Loads min and max value based on pfid.
*
* @param $pfid
* The product feature ID to load.
* @return
* The min and max object.
*/
function uc_product_minmax_values_load($pfid) {
return db_fetch_object(db_query("SELECT * FROM {uc_product_minmax} WHERE pfid = %d", $pfid));
}
Functions
Name![]() |
Description |
---|---|
theme_uc_product_minmax | |
uc_product_minmax_add_to_cart | Implementation of hook_add_to_cart(). |
uc_product_minmax_cart_validate | |
uc_product_minmax_feature_delete | This function gets called when a feature of this type is deleted. |
uc_product_minmax_feature_form | This form gets displayed when a product feature is added or edited for this product feature type. |
uc_product_minmax_feature_form_submit | |
uc_product_minmax_feature_form_validate | |
uc_product_minmax_feature_load | Load minmax product feature for the given node |
uc_product_minmax_feature_settings | This function gets called when an administrator browses to the product features settings form. It should return an array of form elements to add to this feature's fieldset in the form if necessary. |
uc_product_minmax_form_alter | Implementation of hook_form_alter(). |
uc_product_minmax_form_uc_cart_view_form_alter | Prevent illegal modifications of quantities in cart |
uc_product_minmax_form_uc_product_feature_add_form_alter | Restrict multiple minmax features from being added to a single product. Disable feature on product kits since it doesn't have any effect on them. |
uc_product_minmax_nodeapi | Implementation of hook_nodeapi(). |
uc_product_minmax_product_feature | Implementation of hook_product_feature(). |
uc_product_minmax_product_kit_load | Load product kit matches for the given node |
uc_product_minmax_theme | Implementation of hook_theme() Themes the product minimum notice line on product view pages. |
uc_product_minmax_values_load | Loads min and max value based on pfid. |
uc_product_minmax_values_save | Saves the min & max values. |