diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql index f59aa43a6af..140fc3480ea 100644 --- a/htdocs/core/menus/init_menu_auguria.sql +++ b/htdocs/core/menus/init_menu_auguria.sql @@ -102,6 +102,8 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3102__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/liste.php', 'List', 1, 'stocks', '$user->rights->stock->lire', '', 2, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3103__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/valo.php', 'EnhancedValue', 1, 'stocks', '$user->rights->stock->lire', '', 2, 2, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3104__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/mouvement.php', 'Movements', 1, 'stocks', '$user->rights->stock->mouvement->lire', '', 2, 3, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled && $conf->fournisseur->enabled', __HANDLER__, 'left', 3105__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/replenish.php', 'Replenishments', 1, 'stocks', '$user->rights->stock->mouvement->lire && $user->rights->fournisseur->lire', '', 2, 4, __ENTITY__); + -- Product - Categories insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->categorie->enabled', __HANDLER__, 'left', 3200__+MAX_llx_menu__, 'products', 'cat', 3__+MAX_llx_menu__, '/categories/index.php?leftmenu=cat&type=0', 'Categories', 0, 'categories', '$user->rights->categorie->lire', '', 2, 4, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->categorie->enabled', __HANDLER__, 'left', 3201__+MAX_llx_menu__, 'products', '', 3200__+MAX_llx_menu__, '/categories/fiche.php?action=create&type=0', 'NewCategory', 1, 'categories', '$user->rights->categorie->creer', '', 2, 0, __ENTITY__); diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index f6604ff0253..98021186e34 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1007,7 +1007,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu if (empty($leftmenu) || $leftmenu=="stock") $newmenu->add("/product/stock/liste.php", $langs->trans("List"), 1, $user->rights->stock->lire); if (empty($leftmenu) || $leftmenu=="stock") $newmenu->add("/product/stock/valo.php", $langs->trans("EnhancedValue"), 1, $user->rights->stock->lire); if (empty($leftmenu) || $leftmenu=="stock") $newmenu->add("/product/stock/mouvement.php", $langs->trans("Movements"), 1, $user->rights->stock->mouvement->lire); - if (empty($leftmenu) || $leftmenu=="stock") $newmenu->add("/product/stock/replenish.php", $langs->trans("Replenishment"), 1, $user->rights->stock->mouvement->lire); + if ($conf->fournisseur->enabled) if (empty($leftmenu) || $leftmenu=="stock") $newmenu->add("/product/stock/replenish.php", $langs->trans("Replenishment"), 1, $user->rights->stock->mouvement->lire && $user->rights->fournisseur->lire); } // Expeditions diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index fde34aa52a0..27108adef18 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -143,11 +143,11 @@ NoStockForThisProduct=No stock for this product NoStock=No Stock Restock=Restock ProductSpecial=Special -QtyMin=Min. Order Qty. +QtyMin=Minimum Qty PriceQty=Price for this quantity -PriceQtyMin=MOQ Price (w/o discount) +PriceQtyMin=Price for this min. qty (w/o discount) VATRateForSupplierProduct=VAT Rate (for this supplier/product) -DiscountQtyMin=MOQ Discount (by default) +DiscountQtyMin=Default discount for qty NoPriceDefinedForThisSupplier=No price/qty defined for this supplier/product NoSupplierPriceDefinedForThisProduct=No supplier price/qty defined for this product RecordedProducts=Products recorded diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index 80b8fb352ac..b26970e110d 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -95,8 +95,10 @@ Replenishment=Replenishment ReplenishmentOrders=Replenishment orders UseVirtualStock=Use virtual stock instead of physical stock RuleForStockReplenishment=Rule for stocks replenishment -SelectProduct=Select at least one product +SelectProductWithNotNullQty=Select at least one product with a qty not null and a supplier AlertOnly= Alerts only WarehouseForStockDecrease=The warehouse %s will be used for stock decrease WarehouseForStockIncrease=The warehouse %s will be used for stock increase -ForThisWarehouse=For this warehouse \ No newline at end of file +ForThisWarehouse=For this warehouse +ReplenishmentStatusDesc=This is list of all product with a physical stock lower than desired stock and suggest you to create supplier orders to fill the difference. +ReplenishmentOrdersDesc=This is list of all opened supplier orders \ No newline at end of file diff --git a/htdocs/langs/fr_FR/stocks.lang b/htdocs/langs/fr_FR/stocks.lang index 934e0b59b99..d1ce8931a1a 100644 --- a/htdocs/langs/fr_FR/stocks.lang +++ b/htdocs/langs/fr_FR/stocks.lang @@ -95,8 +95,10 @@ Replenishment=Réapprovisionnement ReplenishmentOrders=Commandes de réapprovisionnement UseVirtualStock=Utiliser le stock théorique à la place du stock physique RuleForStockReplenishment=Règle de gestion du réapprovisionnement des stocks -SelectProduct=Sélectionnez au moins un produit +SelectProductWithNotNullQty=Sélectionnez au moins un produit avec une quantité non nulle et un fournisseur AlertOnly = Alertes seulement WarehouseForStockDecrease=L'entrepôt %s sera utilisé pour la décrémentation du stock WarehouseForStockIncrease=L'entrepôt %s sera utilisé pour l'incrémentation du stock -ForThisWarehouse=Pour cet entrepôt \ No newline at end of file +ForThisWarehouse=Pour cet entrepôt +ReplenishmentStatusDesc=Cet écran permet de voir les produits avec un stock physique inférieure à la quantité minimale désirée et propose de créer des commandes fournisseurs pour compléter la différence +ReplenishmentOrdersDesc=Voici la liste des commandes fournisseurs en cours \ No newline at end of file diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 30941ec0cc2..650891bb6bd 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -67,7 +67,8 @@ $offset = $limit * $page ; * Actions */ -if (isset($_POST['button_removefilter']) || isset($_POST['valid'])) { +if (isset($_POST['button_removefilter']) || isset($_POST['valid'])) +{ $sref = ''; $snom = ''; $sal = ''; @@ -75,16 +76,19 @@ if (isset($_POST['button_removefilter']) || isset($_POST['valid'])) { } //orders creation -//FIXME: could go in the lib -if ($action == 'order' && isset($_POST['valid'])) { +//TODO: could go in the lib +if ($action == 'order' && isset($_POST['valid'])) +{ $linecount = GETPOST('linecount', 'int'); $box = 0; unset($_POST['linecount']); if ($linecount > 0) { $suppliers = array(); - for ($i = 0; $i < $linecount; $i++) { - if(GETPOST($i, 'alpha') === 'on' - && GETPOST('fourn' . $i, 'int') > 0) { //one line + for ($i = 0; $i < $linecount; $i++) + { + if (GETPOST($i, 'alpha') === 'on' && GETPOST('fourn' . $i, 'int') > 0) + { + //one line $box = $i; $supplierpriceid = GETPOST('fourn'.$i, 'int'); //get all the parameters needed to create a line @@ -95,22 +99,28 @@ if ($action == 'order' && isset($_POST['valid'])) { $sql .= MAIN_DB_PREFIX . 'product_fournisseur_price'; $sql .= ' WHERE rowid = ' . $supplierpriceid; $resql = $db->query($sql); - if ($resql && $db->num_rows($resql) > 0) { - //might need some value checks - $obj = $db->fetch_object($resql); - $line = new CommandeFournisseurLigne($db); - $line->qty = $qty; - $line->desc = $desc; - $line->fk_product = $obj->fk_product; - $line->tva_tx = $obj->tva_tx; - $line->subprice = $obj->unitprice; - $line->total_ht = $obj->unitprice * $qty; - $tva = $line->tva_tx / 100; - $line->total_tva = $line->total_ht * $tva; - $line->total_ttc = $line->total_ht + $line->total_tva; - $line->ref_fourn = $obj->ref_fourn; - $suppliers[$obj->fk_soc]['lines'][] = $line; - } else { + if ($resql && $db->num_rows($resql) > 0) + { + if ($qty) + { + //might need some value checks + $obj = $db->fetch_object($resql); + $line = new CommandeFournisseurLigne($db); + $line->qty = $qty; + $line->desc = $desc; + $line->fk_product = $obj->fk_product; + $line->tva_tx = $obj->tva_tx; + $line->subprice = $obj->unitprice; + $line->total_ht = $obj->unitprice * $qty; + $tva = $line->tva_tx / 100; + $line->total_tva = $line->total_ht * $tva; + $line->total_ttc = $line->total_ht + $line->total_tva; + $line->ref_fourn = $obj->ref_fourn; + $suppliers[$obj->fk_soc]['lines'][] = $line; + } + } + else + { $error=$db->lasterror(); dol_print_error($db); dol_syslog('replenish.php: '.$error, LOG_ERR); @@ -120,11 +130,13 @@ if ($action == 'order' && isset($_POST['valid'])) { } unset($_POST[$i]); } + //we now know how many orders we need and what lines they have $i = 0; $orders = array(); $suppliersid = array_keys($suppliers); - foreach ($suppliers as $supplier) { + foreach ($suppliers as $supplier) + { $order = new CommandeFournisseur($db); $order->socid = $suppliersid[$i]; //trick to know which orders have been generated this way @@ -150,13 +162,15 @@ if ($action == 'order' && isset($_POST['valid'])) { } } if ($box == 0) { - setEventMessage($langs->trans('SelectProduct'), 'warnings'); + setEventMessage($langs->trans('SelectProductWithNotNullQty'), 'warnings'); } } + /* * View */ + $title = $langs->trans('Status'); $sql = 'SELECT p.rowid, p.ref, p.label, p.price'; @@ -196,385 +210,399 @@ if ($snom) { $sql .= ' AND p.label LIKE "%' . $db->escape($crit) . '%"'; } } - $sql .= ' AND p.tobuy = 1'; - -if (!empty($canvas)) { - $sql .= ' AND p.canvas = "' . $db->escape($canvas) . '"'; -} +if (!empty($canvas)) $sql .= ' AND p.canvas = "' . $db->escape($canvas) . '"'; $sql .= ' GROUP BY p.rowid, p.ref, p.label, p.price'; $sql .= ', p.price_ttc, p.price_base_type,p.fk_product_type, p.tms'; $sql .= ', p.duration, p.tobuy, p.seuil_stock_alerte'; $sql .= ', p.desiredstock, s.fk_product'; $sql .= ' HAVING p.desiredstock > SUM(COALESCE(s.reel, 0))'; $sql .= ' AND p.desiredstock > 0'; -if ($salert == 'on') { +if ($salert == 'on') +{ $sql .= ' AND SUM(COALESCE(s.reel, 0)) < p.seuil_stock_alerte AND p.seuil_stock_alerte is not NULL'; $alertchecked = 'checked="checked"'; } $sql .= $db->order($sortfield,$sortorder); $sql .= $db->plimit($limit + 1, $offset); $resql = $db->query($sql); - -if ($resql) { - $num = $db->num_rows($resql); - $i = 0; - - $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|'; - $helpurl .= 'ES:Módulo_Stocks'; - llxHeader('', $title, $helpurl, $title); - $head = array(); - $head[0][0] = DOL_URL_ROOT.'/product/stock/replenish.php'; - $head[0][1] = $title; - $head[0][2] = 'replenish'; - $head[1][0] = DOL_URL_ROOT.'/product/stock/replenishorders.php'; - $head[1][1] = $langs->trans("ReplenishmentOrders"); - $head[1][2] = 'replenishorders'; - dol_fiche_head($head, 'replenish', $langs->trans('Replenishment'), 0, 'stock'); - if ($sref || $snom || $sall || $salert || GETPOST('search', 'alpha')) { - $filters = '&sref=' . $sref . '&snom=' . $snom; - $filters .= '&sall=' . $sall; - $filters .= '&salert=' . $salert; - print_barre_liste( - $texte, - $page, - 'replenish.php', - $filters, - $sortfield, - $sortorder, - '', - $num - ); - } else { - $filters = '&sref=' . $sref . '&snom=' . $snom; - $filters .= '&fourn_id=' . $fourn_id; - $filters .= (isset($type)?'&type=' . $type:''); - $filters .= '&salert=' . $salert; - print_barre_liste( - $texte, - $page, - 'replenish.php', - $filters, - $sortfield, - $sortorder, - '', - $num - ); - } - - print '
'; - - if ($num > $conf->liste_limit) - { - if ($sref || $snom || $sall || $salert || GETPOST('search', 'alpha')) - { - $filters = '&sref=' . $sref . '&snom=' . $snom; - $filters .= '&sall=' . $sall; - $filters .= '&salert=' . $salert; - print_barre_liste( - '', - $page, - 'replenish.php', - $filters, - $sortfield, - $sortorder, - '', - $num, - 0, - '' - ); - } else { - $filters = '&sref=' . $sref . '&snom=' . $snom; - $filters .= '&fourn_id=' . $fourn_id; - $filters .= (isset($type)? '&type=' . $type : ''); - $filters .= '&salert=' . $salert; - print_barre_liste( - '', - $page, - 'replenish.php', - $filters, - $sortfield, - $sortorder, - '', - $num, - 0, - '' - ); - } - } - - $db->free($resql); -print ' '; -} else { +if (empty($resql)) +{ dol_print_error($db); + exit; } +$num = $db->num_rows($resql); +$i = 0; + +$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|'; +$helpurl .= 'ES:Módulo_Stocks'; + +llxHeader('', $title, $helpurl, $title); + +$head = array(); +$head[0][0] = DOL_URL_ROOT.'/product/stock/replenish.php'; +$head[0][1] = $title; +$head[0][2] = 'replenish'; +$head[1][0] = DOL_URL_ROOT.'/product/stock/replenishorders.php'; +$head[1][1] = $langs->trans("ReplenishmentOrders"); +$head[1][2] = 'replenishorders'; + +dol_fiche_head($head, 'replenish', $langs->trans('Replenishment'), 0, 'stock'); + +print $langs->trans("ReplenishmentStatusDesc").'