NEW Can select several warehouses into the view stock at date in past

This commit is contained in:
Laurent Destailleur 2023-02-24 12:57:15 +01:00
parent 393b0e7c4c
commit 093099ea44
2 changed files with 67 additions and 35 deletions

View File

@ -5503,7 +5503,7 @@ class Product extends CommonObject
* This function need a lot of load. If you use it on list, use a cache to execute it once for each product id. * This function need a lot of load. If you use it on list, use a cache to execute it once for each product id.
* If ENTREPOT_EXTRA_STATUS is set, filtering on warehouse status is possible. * If ENTREPOT_EXTRA_STATUS is set, filtering on warehouse status is possible.
* *
* @param string $option '' = Load all stock info, also from closed and internal warehouses, 'nobatch', 'novirtual' * @param string $option '' = Load all stock info, also from closed and internal warehouses, 'nobatch' = do not load batch detail, 'novirtual' = do no load virtual detail
* You can also filter on 'warehouseclosed', 'warehouseopen', 'warehouseinternal' * You can also filter on 'warehouseclosed', 'warehouseopen', 'warehouseinternal'
* @param int $includedraftpoforvirtual Include draft status of PO for virtual stock calculation * @param int $includedraftpoforvirtual Include draft status of PO for virtual stock calculation
* @param int $dateofvirtualstock Date of virtual stock * @param int $dateofvirtualstock Date of virtual stock
@ -5568,7 +5568,7 @@ class Product extends CommonObject
$this->db->free($result); $this->db->free($result);
if (!preg_match('/novirtual/', $option)) { if (!preg_match('/novirtual/', $option)) {
$this->load_virtual_stock($includedraftpoforvirtual, $dateofvirtualstock); // This also load all arrays stats_xxx... $this->load_virtual_stock($includedraftpoforvirtual, $dateofvirtualstock); // This load stock_theorique and also load all arrays stats_xxx...
} }
return 1; return 1;

View File

@ -67,7 +67,21 @@ $search_nom = GETPOST('search_nom', 'alphanohtml');
$now = dol_now(); $now = dol_now();
$productid = GETPOST('productid', 'int'); $productid = GETPOST('productid', 'int');
$fk_warehouse = GETPOST('fk_warehouse', 'int'); if (GETPOSTISARRAY('search_fk_warehouse')) {
$search_fk_warehouse = GETPOST('search_fk_warehouse', 'array:int');
} else {
$search_fk_warehouse = array(GETPOST('search_fk_warehouse', 'int'));
}
// For backward compatibility
if (GETPOST('fk_warehouse', 'int')) {
$search_fk_warehouse = array(GETPOST('fk_warehouse', 'int'));
}
// Clean value -1
foreach ($search_fk_warehouse as $key => $val) {
if ($val == -1 || empty($val)) {
unset($search_fk_warehouse[$key]);
}
}
$sortfield = GETPOST('sortfield', 'aZ09comma'); $sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma'); $sortorder = GETPOST('sortorder', 'aZ09comma');
@ -111,7 +125,7 @@ if ($mode == 'future') {
if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers
$date = ''; $date = '';
$productid = 0; $productid = 0;
$fk_warehouse = 0; $search_fk_warehouse = array();
$search_ref = ''; $search_ref = '';
$search_nom = ''; $search_nom = '';
} }
@ -139,8 +153,8 @@ if ($date && $dateIsValid) { // Avoid heavy sql if mandatory date is not defined
if ($productid > 0) { if ($productid > 0) {
$sql .= " AND ps.fk_product = ".((int) $productid); $sql .= " AND ps.fk_product = ".((int) $productid);
} }
if ($fk_warehouse > 0) { if (! empty($search_fk_warehouse)) {
$sql .= " AND ps.fk_entrepot = ".((int) $fk_warehouse); $sql .= " AND ps.fk_entrepot IN (".$db->sanitize(join(",", $search_fk_warehouse)).")";
} }
$sql .= " GROUP BY fk_product, fk_entrepot"; $sql .= " GROUP BY fk_product, fk_entrepot";
//print $sql; //print $sql;
@ -194,8 +208,8 @@ if ($date && $dateIsValid) {
if ($productid > 0) { if ($productid > 0) {
$sql .= " AND sm.fk_product = ".((int) $productid); $sql .= " AND sm.fk_product = ".((int) $productid);
} }
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
$sql .= " AND sm.fk_entrepot = ".((int) $fk_warehouse); $sql .= " AND sm.fk_entrepot IN (".$db->sanitize(join(",", $search_fk_warehouse)).")";
} }
$sql .= " GROUP BY sm.fk_product, sm.fk_entrepot"; $sql .= " GROUP BY sm.fk_product, sm.fk_entrepot";
$resql = $db->query($sql); $resql = $db->query($sql);
@ -246,7 +260,7 @@ $title = $langs->trans('StockAtDate');
$sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price, p.pmp,'; $sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price, p.pmp,';
$sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,'; $sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,';
$sql .= ' p.tms as datem, p.duration, p.tobuy, p.stock, '; $sql .= ' p.tms as datem, p.duration, p.tobuy, p.stock, ';
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
$sql .= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue"; $sql .= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue";
$sql .= ', SUM(ps.reel) as stock_reel'; $sql .= ', SUM(ps.reel) as stock_reel';
} else { } else {
@ -258,8 +272,8 @@ $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // N
$sql .= $hookmanager->resPrint; $sql .= $hookmanager->resPrint;
$sql .= ' FROM '.MAIN_DB_PREFIX.'product as p'; $sql .= ' FROM '.MAIN_DB_PREFIX.'product as p';
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as ps ON p.rowid = ps.fk_product AND ps.fk_entrepot = '.((int) $fk_warehouse); $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as ps ON p.rowid = ps.fk_product AND ps.fk_entrepot IN ('.$db->sanitize(join(",", $search_fk_warehouse)).")";
} }
// Add fields from hooks // Add fields from hooks
$parameters = array(); $parameters = array();
@ -275,7 +289,7 @@ if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
if (!empty($canvas)) { if (!empty($canvas)) {
$sql .= " AND p.canvas = '".$db->escape($canvas)."'"; $sql .= " AND p.canvas = '".$db->escape($canvas)."'";
} }
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
$sql .= ' GROUP BY p.rowid, p.ref, p.label, p.description, p.price, p.pmp, p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,'; $sql .= ' GROUP BY p.rowid, p.ref, p.label, p.description, p.price, p.pmp, p.price_ttc, p.price_base_type, p.fk_product_type, p.desiredstock, p.seuil_stock_alerte,';
$sql .= ' p.tms, p.duration, p.tobuy, p.stock'; $sql .= ' p.tms, p.duration, p.tobuy, p.stock';
} else { } else {
@ -287,10 +301,10 @@ $parameters = array();
$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
$sql .= $hookmanager->resPrint; $sql .= $hookmanager->resPrint;
if ($sortfield == 'stock_reel' && $fk_warehouse <= 0) { if ($sortfield == 'stock_reel' && empty($search_fk_warehouse)) {
$sortfield = 'stock'; $sortfield = 'stock';
} }
if ($sortfield == 'stock' && $fk_warehouse > 0) { if ($sortfield == 'stock' && !empty($search_fk_warehouse)) {
$sortfield = 'stock_reel'; $sortfield = 'stock_reel';
} }
$sql .= $db->order($sortfield, $sortorder); $sql .= $db->order($sortfield, $sortorder);
@ -319,7 +333,6 @@ if ($date && $dateIsValid) { // We avoid a heavy sql if mandatory parameter date
} }
$i = 0; $i = 0;
//print $sql;
$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|'; $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|';
$helpurl .= 'ES:M&oacute;dulo_Stocks'; $helpurl .= 'ES:M&oacute;dulo_Stocks';
@ -361,10 +374,15 @@ print img_picto('', 'product', 'class="pictofiwedwidth"').' ';
print '</span> '; print '</span> ';
print $form->select_produits($productid, 'productid', '', 0, 0, -1, 2, '', 0, array(), 0, $langs->trans('Product'), 0, 'maxwidth300', 0, '', null, 1); print $form->select_produits($productid, 'productid', '', 0, 0, -1, 2, '', 0, array(), 0, $langs->trans('Product'), 0, 'maxwidth300', 0, '', null, 1);
print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> '; if ($mode != 'future') {
print img_picto('', 'stock', 'class="pictofiwedwidth"'); // A virtual stock in future has no sense on a per warehouse view, so no filter on warehouse is available for stock at date in future
print '</span> '; print ' <span class="clearbothonsmartphone marginleftonly paddingleftonly marginrightonly paddingrightonly">&nbsp;</span> ';
print $formproduct->selectWarehouses((GETPOSTISSET('fk_warehouse') ? $fk_warehouse : 'ifonenodefault'), 'fk_warehouse', '', 1, 0, 0, $langs->trans('Warehouse'), 0, 0, null, '', null, 1, false, 'e.ref'); print img_picto('', 'stock', 'class="pictofixedwidth"').$langs->trans("Warehouse").' :';
print '</span> ';
$selected = ((GETPOSTISSET('search_fk_warehouse') || GETPOSTISSET('fk_warehouse')) ? $search_fk_warehouse : 'ifonenodefault');
print $formproduct->selectWarehouses($selected, 'search_fk_warehouse', '', 1, 0, 0, $langs->trans('Warehouse'), 0, 0, null, '', null, 1, false, 'e.ref', 1);
}
print '</div>'; print '</div>';
$parameters = array(); $parameters = array();
@ -387,8 +405,10 @@ if ($limit > 0 && $limit != $conf->liste_limit) {
$param .= '&limit='.urlencode($limit); $param .= '&limit='.urlencode($limit);
} }
$param .= '&mode='.$mode; $param .= '&mode='.$mode;
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
$param .= '&fk_warehouse='.$fk_warehouse; foreach ($search_fk_warehouse as $val) {
$param .= '&search_fk_warehouse[]='.$val;
}
} }
if ($productid > 0) { if ($productid > 0) {
$param .= '&productid='.$productid; $param .= '&productid='.$productid;
@ -414,7 +434,6 @@ if ($mode == 'future') {
$stocklabel = $langs->trans("VirtualStockAtDate"); $stocklabel = $langs->trans("VirtualStockAtDate");
} }
//print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">';
print '<input type="hidden" name="token" value="'.newToken().'">'; print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="sortfield" value="'.$sortfield.'">'; print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
print '<input type="hidden" name="sortorder" value="'.$sortorder.'">'; print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
@ -446,7 +465,7 @@ print '</td>';
print '</tr>'; print '</tr>';
$fieldtosortcurrentstock = 'stock'; $fieldtosortcurrentstock = 'stock';
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
$fieldtosortcurrentstock = 'stock_reel'; $fieldtosortcurrentstock = 'stock_reel';
} }
@ -506,9 +525,14 @@ while ($i < ($limit ? min($num, $limit) : $num)) {
}*/ }*/
$currentstock = ''; $currentstock = '';
if ($fk_warehouse > 0) { if (!empty($search_fk_warehouse)) {
//if ($productid > 0) { //if ($productid > 0) {
$currentstock = $stock_prod_warehouse[$objp->rowid][$fk_warehouse]; foreach ($search_fk_warehouse as $val) {
if (!is_numeric($currentstock)) {
$currentstock = 0;
}
$currentstock += $stock_prod_warehouse[$objp->rowid][$val];
}
//} else { //} else {
// $currentstock = $objp->stock_reel; // $currentstock = $objp->stock_reel;
//} //}
@ -521,17 +545,21 @@ while ($i < ($limit ? min($num, $limit) : $num)) {
} }
if ($mode == 'future') { if ($mode == 'future') {
$prod->load_stock('warehouseopen, warehouseinternal', 0, $dateendofday); $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0, $dateendofday);
$stock = $prod->stock_theorique; $stock = $prod->stock_theorique; // virtual stock at a date
$prod->load_stock('warehouseopen, warehouseinternal', 0); $prod->load_stock('warehouseopen,warehouseinternal,nobatch', 0);
$virtualstock = $prod->stock_theorique; $virtualstock = $prod->stock_theorique; // virtual stock in infinite future
} else { } else {
if ($fk_warehouse > 0) { $stock = $currentstock;
$stock = $currentstock - $movements_prod_warehouse[$objp->rowid][$fk_warehouse]; $nbofmovement = 0;
$nbofmovement = $movements_prod_warehouse_nb[$objp->rowid][$fk_warehouse]; if (!empty($search_fk_warehouse)) {
foreach ($search_fk_warehouse as $val) {
$stock -= $movements_prod_warehouse[$objp->rowid][$val];
$nbofmovement += $movements_prod_warehouse_nb[$objp->rowid][$val];
}
} else { } else {
$stock = $currentstock - $movements_prod[$objp->rowid]; $stock -= $movements_prod[$objp->rowid];
$nbofmovement = $movements_prod_nb[$objp->rowid]; $nbofmovement += $movements_prod_nb[$objp->rowid];
} }
} }
@ -585,7 +613,11 @@ while ($i < ($limit ? min($num, $limit) : $num)) {
print '<td class="right">'; print '<td class="right">';
if ($nbofmovement > 0) { if ($nbofmovement > 0) {
print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid.($fk_warehouse > 0 ? '&search_warehouse='.$fk_warehouse : '').'">'.$langs->trans("Movements").'</a>'; print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid;
foreach ($search_fk_warehouse as $val) {
print ($val > 0 ? '&search_warehouse='.$val : '');
}
print '">'.$langs->trans("Movements").'</a>';
print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>'; print ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
} }
print '</td>'; print '</td>';