From 8a00109baf27c38243ee776a411a24f616d3dd15 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur <eldy@destailleur.fr> Date: Sun, 1 Mar 2015 16:04:34 +0100 Subject: [PATCH] Fix: Several bugs int replenishment feature. --- htdocs/commande/list.php | 13 ++-- htdocs/fourn/commande/dispatch.php | 4 +- htdocs/install/mysql/migration/repair.sql | 1 + htdocs/langs/en_US/stocks.lang | 2 +- htdocs/product/class/product.class.php | 15 ++-- .../product/stock/lib/replenishment.lib.php | 74 ++++++++++++------- htdocs/product/stock/replenish.php | 74 ++++++++----------- htdocs/product/stock/replenishorders.php | 32 ++++---- 8 files changed, 117 insertions(+), 98 deletions(-) diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index 0de3c54e1ba..59df993b686 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -361,19 +361,22 @@ if ($resql) // stock order and stock order_supplier $stock_order=0; $stock_order_supplier=0; - if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) { - if (! empty($conf->commande->enabled)) { + if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) + { + if (! empty($conf->commande->enabled)) + { if (empty($productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_customer'])) { - $generic_product->load_stats_commande(0,'1,2',true); + $generic_product->load_stats_commande(0,'1,2'); $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_customer'] = $generic_product->stats_commande['qty']; } else { $generic_product->stats_commande['qty'] = $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_customer']; } $stock_order=$generic_product->stats_commande['qty']; } - if (! empty($conf->fournisseur->enabled)) { + if (! empty($conf->fournisseur->enabled)) + { if (empty($productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_supplier'])) { - $generic_product->load_stats_commande_fournisseur(0,'3',true); + $generic_product->load_stats_commande_fournisseur(0,'3'); $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_supplier'] = $generic_product->stats_commande_fournisseur['qty']; } else { $generic_product->stats_commande_fournisseur['qty'] = $productstat_cache[$generic_commande->lines[$lig]->fk_product]['stats_order_supplier']; diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index c88886de649..9874f809673 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -387,11 +387,11 @@ if ($id > 0 || ! empty($ref)) print '<td align="right">'; if (count($listwarehouses)>1) { - print $form->selectarray("entrepot".$suffix, $listwarehouses, '', 1, 0, 0, '', 0, 0, $disabled); + print $form->selectarray("entrepot".$suffix, $listwarehouses, GETPOST("entrepot".$suffix), 1, 0, 0, '', 0, 0, $disabled); } elseif (count($listwarehouses)==1) { - print $form->selectarray("entrepot".$suffix, $listwarehouses, '', 0, 0, 0, '', 0, 0, $disabled); + print $form->selectarray("entrepot".$suffix, $listwarehouses, GETPOST("entrepot".$suffix), 0, 0, 0, '', 0, 0, $disabled); } else { diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 9e1ca7bb6f9..c0aeda5b671 100755 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -212,5 +212,6 @@ update llx_facturedet set product_type = 1 where product_type = 2; --update llx_commandedet as d set d.product_type = 1 where d.fk_product = 22 and d.product_type = 0; --update llx_facturedet as d set d.product_type = 1 where d.fk_product = 22 and d.product_type = 0; +delete from llx_commande_fournisseur_dispatch where fk_commandefourndet = 0 or fk_commandefourndet IS NULL; diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index 0e3e7dd6c27..fdd6408accb 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -108,7 +108,7 @@ WarehouseForStockDecrease=The warehouse <b>%s</b> will be used for stock decreas WarehouseForStockIncrease=The warehouse <b>%s</b> will be used for stock increase ForThisWarehouse=For this warehouse ReplenishmentStatusDesc=This is list of all product with a stock lower than desired stock (or lower than alert value if checkbox "alert only" is checked), and suggest you to create supplier orders to fill the difference. -ReplenishmentOrdersDesc=This is list of all opened supplier orders +ReplenishmentOrdersDesc=This is list of all opened supplier orders including predefined products. Only opened orders with predefined products, so that may affect stocks, are visible here. Replenishments=Replenishments NbOfProductBeforePeriod=Quantity of product %s in stock before selected period (< %s) NbOfProductAfterPeriod=Quantity of product %s in stock after selected period (> %s) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 0778046c431..e26f9102544 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -3024,7 +3024,9 @@ class Product extends CommonObject } } $this->db->free($result); - $this->load_virtual_stock(); + + $this->load_virtual_stock(); // This also load stats_commande_fournisseur, ... + return 1; } else @@ -3048,18 +3050,21 @@ class Product extends CommonObject $stock_sending_client=0; $stock_reception_fournisseur=0; - if (! empty($conf->commande->enabled)) { + if (! empty($conf->commande->enabled)) + { $result=$this->load_stats_commande(0,'1,2'); if ($result < 0) dol_print_error($db,$this->error); $stock_commande_client=$this->stats_commande['qty']; } - if (! empty($conf->expedition->enabled)) { + if (! empty($conf->expedition->enabled)) + { $result=$this->load_stats_sending(0,'1,2'); if ($result < 0) dol_print_error($db,$this->error); $stock_sending_client=$this->stats_expedition['qty']; } - if (! empty($conf->fournisseur->enabled)) { - $result=$this->load_stats_commande_fournisseur(0,'3,4'); + if (! empty($conf->fournisseur->enabled)) + { + $result=$this->load_stats_commande_fournisseur(0,'1,2,3,4'); if ($result < 0) dol_print_error($db,$this->error); $stock_commande_fournisseur=$this->stats_commande_fournisseur['qty']; diff --git a/htdocs/product/stock/lib/replenishment.lib.php b/htdocs/product/stock/lib/replenishment.lib.php index 50a0d85e25c..1ef993c479d 100644 --- a/htdocs/product/stock/lib/replenishment.lib.php +++ b/htdocs/product/stock/lib/replenishment.lib.php @@ -25,56 +25,80 @@ require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php'; /** - * dispatched + * Check if there is still some dispatching of stock to do. * - * @param int $order_id Id of order - * @return boolean + * @param int $order_id Id of order to check + * @return boolean True = There is some dispatching to do, False = All dispatching is done (may be we receive more) or is not required */ -function dispatched($order_id) +function dolDispatchToDo($order_id) { global $db; - $sql = 'SELECT fk_product, SUM(qty) FROM ' . MAIN_DB_PREFIX . 'commande_fournisseur_dispatch'; - $sql .= ' WHERE fk_commande = ' . $order_id . ' GROUP BY fk_product'; - $sql .= ' ORDER by fk_product'; - $resql = $db->query($sql); + $dispatched = array(); $ordered = array(); - if($resql && $db->num_rows($resql)) + + # Count nb of quantity dispatched per product + $sql = 'SELECT fk_product, SUM(qty) FROM ' . MAIN_DB_PREFIX . 'commande_fournisseur_dispatch'; + $sql.= ' WHERE fk_commande = ' . $order_id; + $sql.= ' GROUP BY fk_product'; + $sql.= ' ORDER by fk_product'; + $resql = $db->query($sql); + if ($resql && $db->num_rows($resql)) { - while($res = $db->fetch_object($resql)) - $dispatched[] = $res; + while ($obj = $db->fetch_object($resql)) + $dispatched[$obj->fk_product] = $obj; } + + # Count nb of quantity to dispatch per product $sql = 'SELECT fk_product, SUM(qty) FROM ' . MAIN_DB_PREFIX . 'commande_fournisseurdet'; - $sql .= ' WHERE fk_commande = ' . $order_id . ' GROUP BY fk_product'; - $sql .= ' ORDER by fk_product'; + $sql.= ' WHERE fk_commande = ' . $order_id; + $sql.= ' AND fk_product > 0'; + if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) $sql.= ' AND product_type = 0'; + $sql.= ' GROUP BY fk_product'; + $sql.= ' ORDER by fk_product'; $resql = $db->query($sql); - if($resql && $db->num_rows($resql)) { - while($res = $db->fetch_object($resql)) - $ordered[] = $res; + if ($resql && $db->num_rows($resql)) + { + while ($obj = $db->fetch_object($resql)) + $ordered[$obj->fk_product] = $obj; } - return $dispatched == $ordered; + + $todispatch=0; + foreach ($ordered as $key => $val) + { + if ($ordered[$key] > $dispatched[$key]) $todispatch++; + } + + return ($todispatch ? true : false); + //return true; } /** * dispatchedOrders * - * @return Ambigous <string, multitype:NULL > + * @return string Array of id of orders wit all dispathing already done or not required */ function dispatchedOrders() { global $db; + $sql = 'SELECT rowid FROM ' . MAIN_DB_PREFIX . 'commande_fournisseur'; $resql = $db->query($sql); - $res = array(); - if ($resql && $db->num_rows($resql) > 0) { - while ($obj = $db->fetch_object($resql)) { - if (dispatched($obj->rowid)) { - $res[] = $obj->rowid; + $resarray = array(); + if ($resql && $db->num_rows($resql) > 0) + { + while ($obj = $db->fetch_object($resql)) + { + if (! dolDispatchToDo($obj->rowid)) + { + $resarray[] = $obj->rowid; } } } - if ($res) { - $res = '(' . implode(',', $res) . ')'; + + if (count($resarray)) + { + $res = '(' . implode(',', $resarray) . ')'; } else { //hack to make sure ordered SQL request won't syntax error $res = '(0)'; diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 35835709ab8..efb008df4ff 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -336,6 +336,17 @@ $head[1][0] = DOL_URL_ROOT.'/product/stock/replenishorders.php'; $head[1][1] = $langs->trans("ReplenishmentOrders"); $head[1][2] = 'replenishorders'; + + +print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">'. + '<input type="hidden" name="token" value="' .$_SESSION['newtoken'] . '">'. + '<input type="hidden" name="sortfield" value="' . $sortfield . '">'. + '<input type="hidden" name="sortorder" value="' . $sortorder . '">'. + '<input type="hidden" name="type" value="' . $type . '">'. + '<input type="hidden" name="linecount" value="' . $num . '">'. + '<input type="hidden" name="action" value="order">'. + '<input type="hidden" name="mode" value="' . $mode . '">'; + dol_fiche_head($head, 'replenish', $langs->trans('Replenishment'), 0, 'stock'); print $langs->trans("ReplenishmentStatusDesc").'<br>'."\n"; @@ -386,16 +397,7 @@ if ($sref || $snom || $sall || $salert || GETPOST('search', 'alpha')) { ); } -print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">'. - '<input type="hidden" name="token" value="' .$_SESSION['newtoken'] . '">'. - '<input type="hidden" name="sortfield" value="' . $sortfield . '">'. - '<input type="hidden" name="sortorder" value="' . $sortorder . '">'. - '<input type="hidden" name="type" value="' . $type . '">'. - '<input type="hidden" name="linecount" value="' . $num . '">'. - '<input type="hidden" name="action" value="order">'. - '<input type="hidden" name="mode" value="' . $mode . '">'. - - '<table class="liste" width="100%">'; +print '<table class="liste" width="100%">'; $param = (isset($type)? '&type=' . $type : ''); $param .= '&fourn_id=' . $fourn_id . '&snom='. $snom . '&salert=' . $salert; @@ -467,7 +469,6 @@ while ($i < ($limit ? min($num, $limit) : $num)) if (!empty($objtp->label)) $objp->label = $objtp->label; } } - $form = new Form($db); $var =! $var; if ($usevirtualstock) @@ -480,7 +481,13 @@ while ($i < ($limit ? min($num, $limit) : $num)) $stock = $prod->stock_reel; } - $ordered = $prod->stats_commande_fournisseur['qty']-$prod->stats_reception['qty']; + // Force call prod->load_stats_xxx to choose status to count (otherwise it is loaded by load_stock function) + $result=$prod->load_stats_commande_fournisseur(0,'1,2,3,4'); + $result=$prod->load_stats_reception(0,'4'); + + //print $prod->stats_commande_fournisseur['qty'].'<br>'."\n"; + //print $prod->stats_reception['qty']; + $ordered = $prod->stats_commande_fournisseur['qty'] - $prod->stats_reception['qty']; $warning=''; if ($objp->alertstock && ($stock < $objp->alertstock)) @@ -555,12 +562,6 @@ while ($i < ($limit ? min($num, $limit) : $num)) print '</table>'; -$value=$langs->trans("CreateOrders"); -print '<div class="center"><input class="button" type="submit" name="valid" value="'.$value.'"></div>'; - - -print '</form>'; - if ($num > $conf->liste_limit) { if ($sref || $snom || $sall || $salert || GETPOST('search', 'alpha')) @@ -569,36 +570,16 @@ if ($num > $conf->liste_limit) $filters .= '&sall=' . $sall; $filters .= '&salert=' . $salert; $filters .= '&mode=' . $mode; - print_barre_liste( - '', - $page, - 'replenish.php', - $filters, - $sortfield, - $sortorder, - '', - $num, - 0, - '' - ); - } else { + 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; $filters .= '&mode=' . $mode; - print_barre_liste( - '', - $page, - 'replenish.php', - $filters, - $sortfield, - $sortorder, - '', - $num, - 0, - '' - ); + print_barre_liste('', $page, 'replenish.php', $filters, $sortfield, $sortorder, '', $num, 0, ''); } } @@ -607,6 +588,13 @@ $db->free($resql); dol_fiche_end(); +$value=$langs->trans("CreateOrders"); +print '<div class="center"><input class="button" type="submit" name="valid" value="'.$value.'"></div>'; + + +print '</form>'; + + // TODO Replace this with jquery print ' <script type="text/javascript"> diff --git a/htdocs/product/stock/replenishorders.php b/htdocs/product/stock/replenishorders.php index 71fe1407a2d..db450a09f6e 100644 --- a/htdocs/product/stock/replenishorders.php +++ b/htdocs/product/stock/replenishorders.php @@ -45,6 +45,8 @@ $result=restrictedArea($user,'produit|service'); * View */ +$form = new Form($db); + $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks'; $texte = $langs->trans('ReplenishmentOrders'); @@ -90,7 +92,7 @@ $sql.= ' AND cf.entity = ' . $conf->entity; if ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) { $sql .= ' AND cf.fk_statut < 3'; } elseif ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) { - $sql .= ' AND cf.fk_statut < 6'; + $sql .= ' AND cf.fk_statut < 6'; // We want alos status 5, we will keep them visible if dispatching is not yet finished (tested with function dolDispatchToDo). } else { $sql .= ' AND cf.fk_statut < 5'; } @@ -143,6 +145,8 @@ $sql .= ' GROUP BY cf.rowid, cf.ref, cf.date_creation, cf.fk_statut'; $sql .= ', cf.total_ttc, cf.fk_user_author, u.login, s.rowid, s.nom'; $sql .= $db->order($sortfield, $sortorder); $sql .= $db->plimit($conf->liste_limit+1, $offset); +//print $sql; + $resql = $db->query($sql); if ($resql) { @@ -151,20 +155,11 @@ if ($resql) print $langs->trans("ReplenishmentOrdersDesc").'<br><br>'; - print_barre_liste( - '', - $page, - $_SERVER["PHP_SELF"], - '', - $sortfield, - $sortorder, - '', - $num, - 0, - '' - ); - print '<form action="'.$_SERVER["PHP_SELF"].'" method="GET">'. - '<table class="noborder" width="100%">'. + print_barre_liste('', $page, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', $num, 0, ''); + + print '<form action="'.$_SERVER["PHP_SELF"].'" method="GET">'; + + print '<table class="noborder" width="100%">'. '<tr class="liste_titre">'; print_liste_field_titre( $langs->trans('Ref'), @@ -226,8 +221,8 @@ if ($resql) $sortfield, $sortorder ); - $form = new Form($db); print '</tr>'. + '<tr class="liste_titre">'. '<td class="liste_titre">'. '<input type="text" class="flat" name="search_ref" value="' . $sref . '">'. @@ -258,7 +253,10 @@ if ($resql) { $obj = $db->fetch_object($resql); $var = !$var; - if (!dispatched($obj->rowid) && (!$sproduct || in_array($sproduct, getProducts($obj->rowid)))) + + $showline = dolDispatchToDo($obj->rowid) && (!$sproduct || in_array($sproduct, getProducts($obj->rowid))); + + if ($showline) { $href = DOL_URL_ROOT . '/fourn/commande/card.php?id=' . $obj->rowid; print '<tr ' . $bc[$var] . '>'. -- GitLab