Fix: Several bugs int replenishment feature.

This commit is contained in:
Laurent Destailleur 2015-03-01 16:04:34 +01:00
parent 5f29942257
commit 8a00109baf
8 changed files with 120 additions and 101 deletions

View File

@ -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'];

View File

@ -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
{

View File

@ -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;

View File

@ -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)

View File

@ -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'];

View File

@ -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))
{
while($res = $db->fetch_object($resql))
$dispatched[] = $res;
}
$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';
# 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))
$ordered[] = $res;
if ($resql && $db->num_rows($resql))
{
while ($obj = $db->fetch_object($resql))
$dispatched[$obj->fk_product] = $obj;
}
return $dispatched == $ordered;
# 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;
$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 ($obj = $db->fetch_object($resql))
$ordered[$obj->fk_product] = $obj;
}
$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)';

View File

@ -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">

View File

@ -45,6 +45,8 @@ $result=restrictedArea($user,'produit|service');
* View
*/
$form = new Form($db);
$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;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] . '>'.