Jump to content

Recommended Posts

Bonjour,

je suis en train de tester ma boutique avant ouverture pour faire le tour des problèmes et je constate que mes produits avec stock vide apparaissent quand même dans la liste des produits, mais que le bouton ajouter au panier est inactif.

ne peut-on pas empécher l'affichage de ces produits sans stock dans les préférences du back office ? Je n'ai pas trouvé dans Préférences > Produit > Stock produit

 

Autoriser la commande de produits hors stock : non

Activer la gestion des stocks : oui

Activer la gestion des stocks avancée : non

 

 

Merci d'avance

Share this post


Link to post
Share on other sites

Je viens de trouver comment faire pour que les produits hors-stock n'apparraisse pas. Il faut aller dans:

Onglet "catalogue" /

puis sélectione une page de tes produits /

va dans onglet "infos" puis tu vas voir les 3 options suivante dans "Si rupture de stock":

 

Refuser les commandes

Accepter les commandes

Par défaut : Refuser les commandes (voir dans Préférences)

 

Faut choisir "refuser les commandes"

 

L'image du produit reste en vue, mais le bouton "ajouter au panier" disparait et cest inscrit "en rupture de stock" donc les client peuvent plus en acheter. Jai aussi des déclinaisons de produits (tailles différentes) et quand par exemple, le medium nest plus dispo, la grandeur disparait du front office.

 

Je sais pas si ça t'aide, mais moi ça a fonctionné et je crois quil faut faire ça pour tout les produits

Edited by Isaberries (see edit history)

Share this post


Link to post
Share on other sites

Oui, j'étais déjà arrivé à cette solution, mais je trouve que c'est frustrant pour un client de voir un produit (dans une liste, un carousel...), être intéressé par celui ci et au moment où on arrive sur la page de commande, "Désolé en rupture de stock". C'est hyper frustrant. De plus, dans mon cas, les produits sont des pièces "uniques", donc le message ne sert à rien, dans 6 mois, 2 ans, il ne sera toujours pas remis en stock.

 

Par contre j'ai "vite fait" fait un override de la classe Category, ce qui me permet de n'afficher dans les listes via les catégories que les produits présents : a priori ça fonctionne dans les conditions de base, mais je n'ai pas affiné pour tester dans le cas d'un multiboutique ou autre.

à remplacer dans /override/classes/Categories.php

 

@PS core développeurs : il serait quand même bon d'avoir dans le core un levier pour gérer l'affichage ou non de produit selon le stock...

 

<?php
class Category extends CategoryCore
{
public $id;
/** @var integer category ID */
public $id_category;
/** @var string Name */
public $name;
/** @var boolean Status for display */
public $active = 1;
/** @var  integer category position */
public $position;
/** @var string Description */
public $description;
/** @var integer Parent category ID */
public $id_parent;
/** @var integer default Category id */
public $id_category_default;
/** @var integer Parents number */
public $level_depth;
/** @var integer Nested tree model "left" value */
public $nleft;
/** @var integer Nested tree model "right" value */
public $nright;
/** @var string string used in rewrited URL */
public $link_rewrite;
/** @var string Meta title */
public $meta_title;
/** @var string Meta keywords */
public $meta_keywords;
/** @var string Meta description */
public $meta_description;
/** @var string Object creation date */
public $date_add;
/** @var string Object last modification date */
public $date_upd;
/** @var boolean is Category Root */
public $is_root_category;
/** @var integer */
public $id_shop_default;
public $groupBox;
protected static $_links = array();
/**
 * @see ObjectModel::$definition
 */
public static $definition = array(
 'table' => 'category',
 'primary' => 'id_category',
 'multilang' => true,
 'multilang_shop' => true,
 'fields' => array(
  'nleft' =>	 array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
  'nright' =>    array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
  'level_depth' =>   array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
  'active' =>    array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => true),
  'id_parent' =>    array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
  'id_shop_default' =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
  'is_root_category' =>  array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
  'position' =>    array('type' => self::TYPE_INT),
  'date_add' =>    array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
  'date_upd' =>    array('type' => self::TYPE_DATE, 'validate' => 'isDate'),
  // Lang fields
  'name' =>	 array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isCatalogName', 'required' => true, 'size' => 64),
  'link_rewrite' =>   array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isLinkRewrite', 'required' => true, 'size' => 64),
  'description' =>   array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString'),
  'meta_title' =>   array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 128),
  'meta_description' =>  array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255),
  'meta_keywords' =>   array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255),
 ),
);
/** @var string id_image is the category ID when an image exists and 'default' otherwise */
public $id_image = 'default';
protected $webserviceParameters = array(
 'objectsNodeName' => 'categories',
 'hidden_fields' => array('nleft', 'nright', 'groupBox'),
 'fields' => array(
  'id_parent' => array('xlink_resource'=> 'categories'),
  'level_depth' => array('setter' => false),
  'nb_products_recursive' => array('getter' => 'getWsNbProductsRecursive', 'setter' => false),
 ),
 'associations' => array(
  'categories' => array('getter' => 'getChildrenWs', 'resource' => 'category', ),
  'products' => array('getter' => 'getProductsWs', 'resource' => 'product', ),
 ),
);
public function __construct($id_category = null, $id_lang = null, $id_shop = null)
{
 parent::__construct($id_category, $id_lang, $id_shop);
 $this->id_image = ($this->id && file_exists(_PS_CAT_IMG_DIR_.(int)$this->id.'.jpg')) ? (int)$this->id : false;
 $this->image_dir = _PS_CAT_IMG_DIR_;
}
/**
  * Return current category products
  *
  * @param integer $id_lang Language ID
  * @param integer $p Page number
  * @param integer $n Number of products per page
  * @param boolean $get_total return the number of results instead of the results themself
  * @param boolean $active return only active products
  * @param boolean $random active a random filter for returned products
  * @param int $random_number_products number of products to return if random is activated
  * @param boolean $check_access set to false to return all products (even if customer hasn't access)
  * @return mixed Products or number of products
  */
public function getProducts($id_lang, $p, $n, $order_by = null, $order_way = null, $get_total = false, $active = true, $random = false, $random_number_products = 1, $check_access = true, Context $context = null)
{
 if (!$context)
  $context = Context::getContext();
 if ($check_access && !$this->checkAccess($context->customer->id))
  return false;

 $front = true;
 if (!in_array($context->controller->controller_type, array('front', 'modulefront')))
  $front = false;

 if ($p < 1) $p = 1;
 if (empty($order_by))
  $order_by = 'position';
 else
  /// Fix for all modules which are now using lowercase values for 'orderBy' parameter
  $order_by = strtolower($order_by);
 if (empty($order_way))
  $order_way = 'ASC';
 if ($order_by == 'id_product' || $order_by == 'date_add' || $order_by == 'date_upd')
  $order_by_prefix = 'p';
 elseif ($order_by == 'name')
  $order_by_prefix = 'pl';
 elseif ($order_by == 'manufacturer')
 {
  $order_by_prefix = 'm';
  $order_by = 'name';
 }
 elseif ($order_by == 'position')
  $order_by_prefix = 'cp';
 if ($order_by == 'price')
  $order_by = 'orderprice';
 if (!Validate::isBool($active) || !Validate::isOrderBy($order_by) || !Validate::isOrderWay($order_way))
  die (Tools::displayError());
 $id_supplier = (int)Tools::getValue('id_supplier');
 // Return only the number of products
 if ($get_total)
 {
  $sql = 'SELECT COUNT(cp.`id_product`) AS total
 FROM `'._DB_PREFIX_.'product` p
 '.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON sa.`id_product` = p.`id_product`
 LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON p.`id_product` = cp.`id_product`
 WHERE cp.`id_category` = '.(int)$this->id.
 ($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '').
($front ? ' AND sa.`quantity` >0' : '').
 ($active ? ' AND product_shop.`active` = 1' : '').
 ($id_supplier ? 'AND p.id_supplier = '.(int)$id_supplier : '');
  return (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
 }
 $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`id_product_attribute`, pl.`description`, pl.`description_short`, pl.`available_now`,
 pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, image_shop.`id_image`,
 il.`legend`, m.`name` AS manufacturer_name, tl.`name` AS tax_name, t.`rate`, cl.`name` AS category_default,
 DATEDIFF(product_shop.`date_add`, DATE_SUB(NOW(),
 INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).'
  DAY)) > 0 AS new,
 (product_shop.`price` * IF(t.`rate`,((100 + (t.`rate`))/100),1)) AS orderprice
   FROM `'._DB_PREFIX_.'category_product` cp
   LEFT JOIN `'._DB_PREFIX_.'product` p
 ON p.`id_product` = cp.`id_product`
   '.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON sa.`id_product` = p.`id_product`
   LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa
   ON (p.`id_product` = pa.`id_product`)
   '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').'
   '.Product::sqlStock('p', 'product_attribute_shop', false, $context->shop).'
   LEFT JOIN `'._DB_PREFIX_.'category_lang` cl
 ON (product_shop.`id_category_default` = cl.`id_category`
 AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').')
   LEFT JOIN `'._DB_PREFIX_.'product_lang` pl
 ON (p.`id_product` = pl.`id_product`
 AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').')
   LEFT JOIN `'._DB_PREFIX_.'image` i
 ON (i.`id_product` = p.`id_product`)'.
   Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').'
   LEFT JOIN `'._DB_PREFIX_.'image_lang` il
 ON (image_shop.`id_image` = il.`id_image`
 AND il.`id_lang` = '.(int)$id_lang.')
   LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr
 ON (product_shop.`id_tax_rules_group` = tr.`id_tax_rules_group`
 AND tr.`id_country` = '.(int)$context->country->id.'
 AND tr.`id_state` = 0
 AND tr.`zipcode_from` = 0)
   LEFT JOIN `'._DB_PREFIX_.'tax` t
 ON (t.`id_tax` = tr.`id_tax`)
   LEFT JOIN `'._DB_PREFIX_.'tax_lang` tl
 ON (t.`id_tax` = tl.`id_tax`
 AND tl.`id_lang` = '.(int)$id_lang.')
   LEFT JOIN `'._DB_PREFIX_.'manufacturer` m
 ON m.`id_manufacturer` = p.`id_manufacturer`
   WHERE product_shop.`id_shop` = '.(int)$context->shop->id.'
   AND (pa.id_product_attribute IS NULL OR product_attribute_shop.id_shop='.(int)$context->shop->id.')
   AND (i.id_image IS NULL OR image_shop.id_shop='.(int)$context->shop->id.')
 AND cp.`id_category` = '.(int)$this->id
 .($active ? ' AND product_shop.`active` = 1' : '')
 .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '')
.($front ? ' AND sa.`quantity` >0' : '')
 .($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '');
 if ($random === true)
 {
  $sql .= ' ORDER BY RAND()';
  $sql .= ' LIMIT 0, '.(int)$random_number_products;
 }
 else
  $sql .= ' ORDER BY '.(isset($order_by_prefix) ? $order_by_prefix.'.' : '').'`'.pSQL($order_by).'` '.pSQL($order_way).'
  LIMIT '.(((int)$p - 1) * (int)$n).','.(int)$n;
 $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
 if ($order_by == 'orderprice')
  Tools::orderbyPrice($result, $order_way);
 if (!$result)
  return false;
 // Modify SQL result
 return Product::getProductsProperties($id_lang, $result);
}
}

Share this post


Link to post
Share on other sites

Bonjour,

 

J'avais trouvé une solution avec la condition p.quantity>0 qui fonctionnait bien mais qui hélas ne peut plus être appliquée sur prestashop 1.5.3...

Du coup en cherchant sur le forum, j'ai trouvé ta solution (et te remercie de l'avoir publiée) qui marche bien avec la nouvelle variable (stock available).

Par contre j'ai un petit bug gênant que je n'arrive pas à solutionner:

En utilisant cette solution, les déclinaisons sont prises en compte et cela créer des problèmes notamment pour le module "dans la même catégorie" qui affiches plusieurs fois le même produit.

C'est le cas aussi du module productlinks qui fait appel à la fonction getProducts et et qui du coup ne peut pas afficher les produits ssuivants mais seulement les précédents (seul la décroissance de l'id est prise en compte).

Aurais tu une astuce pour solutionner ce petit bug?

Share this post


Link to post
Share on other sites

Un petit up!

 

J'ai beau chercher et tourner le pb dans tous les sens, je n'y arrive pas!

 

Le soucis est que dans la table stock_available lorsqu'on applique la condition >0 le produit qui a des attributs est pris en compte plusieurs fois (.

Ce n'était pas le cas avec la variable p.quantity des versions précédentes de prestashop qui concidérait le stock global pour un produit.

 

A priori il faudrait regarder si stock_available est >0 pour id-product_attribute=0 qui semble être le stock global du produit; Mais je ne sais pas le faire!!

 

Alors merci d'avance à celui ou celle qui résoudra ce problème.

Share this post


Link to post
Share on other sites

C'est en formulant la question qu'à priori j'ai trouvé la réponse:

il suffit de modifier la ligne

LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON sa.`id_product` = p.`id_product`

dans le post #4 de CREACOM par

LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON (sa.`id_product` = p.`id_product` AND sa.`id_product_attribute` =0)

Share this post


Link to post
Share on other sites

Ce serait bien que creacom édite le post en résolu pour faciliter les recherches sur le forum...

Share this post


Link to post
Share on other sites

Merci pour le code, il faut donc seulement rajouter dans la query sql :

 

LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON sa.`id_product` = p.`id_product`

 

AND sa.`quantity` >0

 

Par contre pour ceux qui comme moi utilisent le module de navigation à facettes, il faut faire ces modifications dans :

/modules/blocklayered/blocklayered.php

 

Etant donné qu'il surcharge le getProducts du fichier /classes/Category.php

 

Pour appliquer la même modification aux nouveaux produits (block + page) il faut faire de même dans la fonction getNewProducts en surchargeant avec /override/classes/Product.php

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More