Enhance Stock at date feature

This commit is contained in:
Laurent Destailleur 2020-07-10 20:33:06 +02:00
parent a155b20b2f
commit c91236244e
3 changed files with 54 additions and 16 deletions

View File

@ -136,7 +136,8 @@ ErrorNewValueCantMatchOldValue=New value can't be equal to old one
ErrorFailedToValidatePasswordReset=Failed to reinit password. May be the reinit was already done (this link can be used only one time). If not, try to restart the reinit process. ErrorFailedToValidatePasswordReset=Failed to reinit password. May be the reinit was already done (this link can be used only one time). If not, try to restart the reinit process.
ErrorToConnectToMysqlCheckInstance=Connect to database fails. Check database server is running (for example, with mysql/mariadb, you can launch it from command line with 'sudo service mysql start'). ErrorToConnectToMysqlCheckInstance=Connect to database fails. Check database server is running (for example, with mysql/mariadb, you can launch it from command line with 'sudo service mysql start').
ErrorFailedToAddContact=Failed to add contact ErrorFailedToAddContact=Failed to add contact
ErrorDateMustBeBeforeToday=The date cannot be greater than today ErrorDateMustBeBeforeToday=The date must be lower than today
ErrorDateMustBeInFuture=The date must be greater than today
ErrorPaymentModeDefinedToWithoutSetup=A payment mode was set to type %s but setup of module Invoice was not completed to define information to show for this payment mode. ErrorPaymentModeDefinedToWithoutSetup=A payment mode was set to type %s but setup of module Invoice was not completed to define information to show for this payment mode.
ErrorPHPNeedModule=Error, your PHP must have module <b>%s</b> installed to use this feature. ErrorPHPNeedModule=Error, your PHP must have module <b>%s</b> installed to use this feature.
ErrorOpenIDSetupNotComplete=You setup Dolibarr config file to allow OpenID authentication, but URL of OpenID service is not defined into constant %s ErrorOpenIDSetupNotComplete=You setup Dolibarr config file to allow OpenID authentication, but URL of OpenID service is not defined into constant %s

View File

@ -95,6 +95,8 @@ RealStock=Real Stock
RealStockDesc=Physical/real stock is the stock currently in the warehouses. RealStockDesc=Physical/real stock is the stock currently in the warehouses.
RealStockWillAutomaticallyWhen=The real stock will be modified according to this rule (as defined in the Stock module): RealStockWillAutomaticallyWhen=The real stock will be modified according to this rule (as defined in the Stock module):
VirtualStock=Virtual stock VirtualStock=Virtual stock
VirtualStockAtDate=Virtual stock at date
VirtualStockAtDateDesc=Virtual stock atonce all pending orders that are planned to be done before the date will be finished
VirtualStockDesc=Virtual stock is the calculated stock available once all open/pending actions (that affect stocks) are closed (purchase orders received, sales orders shipped, manufacturing orders produced, etc) VirtualStockDesc=Virtual stock is the calculated stock available once all open/pending actions (that affect stocks) are closed (purchase orders received, sales orders shipped, manufacturing orders produced, etc)
IdWarehouse=Id warehouse IdWarehouse=Id warehouse
DescWareHouse=Description warehouse DescWareHouse=Description warehouse

View File

@ -1,6 +1,6 @@
<?php <?php
/* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr> /* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
* Copyright (C) 2013-2018 Laurent Destaileur <ely@users.sourceforge.net> * Copyright (C) 2013-2020 Laurent Destaileur <ely@users.sourceforge.net>
* Copyright (C) 2014 Regis Houssin <regis.houssin@inodbox.com> * Copyright (C) 2014 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2016 ATM Consulting <support@atm-consulting.fr> * Copyright (C) 2016 ATM Consulting <support@atm-consulting.fr>
@ -59,9 +59,10 @@ if (GETPOSTISSET('dateday') && GETPOSTISSET('datemonth') && GETPOSTISSET('dateye
$dateendofday = dol_mktime(23, 59, 59, GETPOST('datemonth', 'int'), GETPOST('dateday', 'int'), GETPOST('dateyear', 'int')); $dateendofday = dol_mktime(23, 59, 59, GETPOST('datemonth', 'int'), GETPOST('dateday', 'int'), GETPOST('dateyear', 'int'));
} }
$now = dol_now();
$productid = GETPOST('productid', 'int'); $productid = GETPOST('productid', 'int');
$fk_warehouse = GETPOST('fk_warehouse', 'int'); $fk_warehouse = GETPOST('fk_warehouse', 'int');
$texte = '';
$sortfield = GETPOST('sortfield', 'alpha'); $sortfield = GETPOST('sortfield', 'alpha');
$sortorder = GETPOST('sortorder', 'alpha'); $sortorder = GETPOST('sortorder', 'alpha');
@ -80,6 +81,19 @@ $parameters = array();
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
$dateIsValid= true;
if ($mode == 'future') {
if ($date && $date < $now) {
setEventMessages($langs->trans("ErrorDateMustBeInFuture"), null, 'errors');
$dateIsValid= false;
}
} else {
if ($date && $date > $now) {
setEventMessages($langs->trans("ErrorDateMustBeBeforeToday"), null, 'errors');
$dateIsValid= false;
}
}
/* /*
* Actions * Actions
@ -99,11 +113,10 @@ if ($conf->global->ENTREPOT_EXTRA_STATUS) {
$warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL; $warehouseStatus[] = Entrepot::STATUS_OPEN_INTERNAL;
} }
// Get array with current stock per product, warehouse // Get array with current stock per product, warehouse
$stock_prod_warehouse = array(); $stock_prod_warehouse = array();
$stock_prod = array(); $stock_prod = array();
if ($date) { // Avoid heavy sql if mandatory date is not defined if ($date && $dateIsValid) { // Avoid heavy sql if mandatory date is not defined
$sql = "SELECT ps.fk_product, ps.fk_entrepot as fk_warehouse,"; $sql = "SELECT ps.fk_product, ps.fk_entrepot as fk_warehouse,";
$sql .= " SUM(ps.reel) AS stock"; $sql .= " SUM(ps.reel) AS stock";
$sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps"; $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps";
@ -146,13 +159,17 @@ if ($date) { // Avoid heavy sql if mandatory date is not defined
dol_print_error($db); dol_print_error($db);
} }
//var_dump($stock_prod_warehouse); //var_dump($stock_prod_warehouse);
} elseif ($action == 'filter') {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
} }
// Get array with list of stock movements between date and now (for product/warehouse= // Get array with list of stock movements between date and now (for product/warehouse=
$movements_prod_warehouse = array(); $movements_prod_warehouse = array();
$movements_prod = array(); $movements_prod = array();
if ($date) { $movements_prod_warehouse_nb = array();
$sql = "SELECT sm.fk_product, sm.fk_entrepot, SUM(sm.value) AS stock"; $movements_prod_nb = array();
if ($date && $dateIsValid) {
$sql = "SELECT sm.fk_product, sm.fk_entrepot, SUM(sm.value) AS stock, COUNT(sm.rowid) AS nbofmovement";
$sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as sm"; $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as sm";
$sql .= ", ".MAIN_DB_PREFIX."entrepot as w"; $sql .= ", ".MAIN_DB_PREFIX."entrepot as w";
$sql .= " WHERE w.entity IN (".getEntity('stock').")"; $sql .= " WHERE w.entity IN (".getEntity('stock').")";
@ -184,12 +201,15 @@ if ($date) {
$fk_product = $obj->fk_product; $fk_product = $obj->fk_product;
$fk_entrepot = $obj->fk_entrepot; $fk_entrepot = $obj->fk_entrepot;
$stock = $obj->stock; $stock = $obj->stock;
$nbofmovement = $obj->nbofmovement;
// Pour llx_product_stock.reel // Pour llx_product_stock.reel
$movements_prod_warehouse[$fk_product][$fk_entrepot] = $stock; $movements_prod_warehouse[$fk_product][$fk_entrepot] = $stock;
$movements_prod_warehouse_nb[$fk_product][$fk_entrepot] = $nbofmovement;
// Pour llx_product.stock // Pour llx_product.stock
$movements_prod[$fk_product] += $stock; $movements_prod[$fk_product] += $stock;
$movements_prod_nb[$fk_product] += $nbofmovement;
$i++; $i++;
} }
@ -259,7 +279,7 @@ if ($sortfield == 'stock' && $fk_warehouse > 0) {
} }
$sql .= $db->order($sortfield, $sortorder); $sql .= $db->order($sortfield, $sortorder);
if ($date) { // We avoid a heavy sql if mandatory parameter date not yet defined if ($date && $dateIsValid) { // We avoid a heavy sql if mandatory parameter date not yet defined
$nbtotalofrecords = ''; $nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
{ {
@ -355,7 +375,7 @@ print '<div class="div-table-responsive">'; // You can use div-table-responsive-
print '<table class="liste centpercent">'; print '<table class="liste centpercent">';
$stocklabel = $langs->trans('StockAtDate'); $stocklabel = $langs->trans('StockAtDate');
if ($mode == 'future') $stocklabel = $langs->trans("VirtualStock"); if ($mode == 'future') $stocklabel = $langs->trans("VirtualStockAtDate");
//print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formulaire">'; //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().'">';
@ -371,6 +391,9 @@ print '<td class="liste_titre"><input class="flat" type="text" name="search_nom"
print '<td class="liste_titre"></td>'; print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>'; print '<td class="liste_titre"></td>';
print '<td class="liste_titre"></td>'; print '<td class="liste_titre"></td>';
if ($mode == 'future') {
print '<td class="liste_titre"></td>';
}
// Fields from hook // Fields from hook
$parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); $parameters = array('param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
@ -394,7 +417,8 @@ print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', ''
if ($mode == 'future') { if ($mode == 'future') {
print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right '); print_liste_field_titre('CurrentStock', $_SERVER["PHP_SELF"], $fieldtosortcurrentstock, $param, '', '', $sortfield, $sortorder, 'right ');
print_liste_field_titre('', $_SERVER["PHP_SELF"]); print_liste_field_titre('', $_SERVER["PHP_SELF"]);
print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockDesc'); print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockAtDateDesc');
print_liste_field_titre('VirtualStock', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ', 'VirtualStockDesc');
} else { } else {
print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right '); print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
print_liste_field_titre('', $_SERVER["PHP_SELF"]); print_liste_field_titre('', $_SERVER["PHP_SELF"]);
@ -453,18 +477,21 @@ while ($i < ($limit ? min($num, $limit) : $num))
} }
if ($mode == 'future') { if ($mode == 'future') {
$prod->load_stock('warehouseopen, warehouseinternal', 0); $prod->load_stock('warehouseopen, warehouseinternal', 0); // This call also ->load_virtual_stock()
//$result = $prod->load_stats_reception(0, '4'); //$result = $prod->load_stats_reception(0, '4');
//print $prod->stats_commande_fournisseur['qty'].'<br>'."\n"; //print $prod->stats_commande_fournisseur['qty'].'<br>'."\n";
//print $prod->stats_reception['qty']; //print $prod->stats_reception['qty'];
$stock = 123; $stock = '<span class="opacitymedium">'.$langs->trans("FeatureNotYetAvailable").'</span>';
$virtualstock = $prod->stock_theorique;
} else { } else {
if ($fk_warehouse > 0) { if ($fk_warehouse > 0) {
$stock = $currentstock - $movements_prod_warehouse[$objp->rowid][$fk_warehouse]; $stock = $currentstock - $movements_prod_warehouse[$objp->rowid][$fk_warehouse];
$nbofmovement = $movements_prod_warehouse_nb[$objp->rowid][$fk_warehouse];
} else { } else {
$stock = $currentstock - $movements_prod[$objp->rowid]; $stock = $currentstock - $movements_prod[$objp->rowid];
$nbofmovement = $movements_prod_nb[$objp->rowid];
} }
} }
@ -485,16 +512,24 @@ while ($i < ($limit ? min($num, $limit) : $num))
print '<td class="right"></td>'; print '<td class="right"></td>';
// Stock at date // Virtual stock at date
print '<td class="right">'.$stock.'</td>'; print '<td class="right">'.$stock.'</td>';
// Final virtual stock
print '<td class="right">'.$virtualstock.'</td>';
} else { } else {
// Stock at date // Stock at date
print '<td class="right">'.$stock.'</td>'; print '<td class="right">'.($stock ? $stock : '<span class="opacitymedium">'.$stock.'</span>').'</td>';
print '<td class="right"><a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$objp->rowid.($fk_warehouse > 0 ? '&search_warehouse='.$fk_warehouse : '').'">'.$langs->trans("Movements").'</a></td>'; print '<td class="right">';
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 ' <span class="tabs"><span class="badge">'.$nbofmovement.'</span></span>';
}
print '</td>';
// Current stock // Current stock
print '<td class="right">'.$currentstock.'</td>'; print '<td class="right">'.($currentstock ? $currentstock : '<span class="opacitymedium">0</span>').'</td>';
} }
// Action // Action