diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index f2471d122af..a83cfae3000 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -4174,9 +4174,16 @@ abstract class CommonObject $sql = "UPDATE ".MAIN_DB_PREFIX.$elementTable; $sql .= " SET ".$fieldstatus." = ".((int) $status); // If status = 1 = validated, update also fk_user_valid - if ($status == 1 && $elementTable == 'expensereport') { + // TODO Replace the test on $elementTable by doing a test on existence of the field in $this->fields + if ($status == 1 && in_array($elementTable, array('expensereport', 'inventory'))) { $sql .= ", fk_user_valid = ".((int) $user->id); } + if ($status == 1 && in_array($elementTable, array('expensereport'))) { + $sql .= ", date_valid = '".$this->db->idate(dol_now())."'"; + } + if ($status == 1 && in_array($elementTable, array('inventory'))) { + $sql .= ", date_validation = '".$this->db->idate(dol_now())."'"; + } $sql .= " WHERE rowid=".((int) $elementId); dol_syslog(get_class($this)."::setStatut", LOG_DEBUG); diff --git a/htdocs/product/inventory/class/inventory.class.php b/htdocs/product/inventory/class/inventory.class.php index 092d98ea854..7a87f344e68 100644 --- a/htdocs/product/inventory/class/inventory.class.php +++ b/htdocs/product/inventory/class/inventory.class.php @@ -626,7 +626,7 @@ class Inventory extends CommonObject $statusType = 'status'.$status; if ($status == self::STATUS_RECORDED) { - $statusType = 'status5'; + $statusType = 'status6'; } return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', $statusType, $mode); diff --git a/htdocs/product/inventory/inventory.php b/htdocs/product/inventory/inventory.php index b6fa70ad551..c467b4367df 100644 --- a/htdocs/product/inventory/inventory.php +++ b/htdocs/product/inventory/inventory.php @@ -121,6 +121,8 @@ if (empty($reshook)) { $stockmovment = new MouvementStock($db); $stockmovment->setOrigin($object->element, $object->id); + $cacheOfProducts = array(); + $db->begin(); $sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,'; @@ -139,8 +141,30 @@ if (empty($reshook)) { $qty_stock = $line->qty_stock; $qty_view = $line->qty_view; // The quantity viewed by inventorier, the qty we target + + // Load real stock we have now. + if (isset($cacheOfProducts[$line->fk_product])) { + $product_static = $cacheOfProducts[$line->fk_product]; + } else { + $product_static = new Product($db); + $result = $product_static->fetch($line->fk_product, '', '', '', 1, 1, 1); + + //$option = 'nobatch'; + $option .= ',novirtual'; + $product_static->load_stock($option); // Load stock_reel + stock_warehouse. + + $cacheOfProducts[$product_static->id] = $product_static; + } + + // Get the real quantity in stock now, but before the stock move for inventory. + $realqtynow = $product_static->stock_warehouse[$line->fk_warehouse]->real; + if ($conf->productbatch->enabled && $product_static->hasbatch()) { + $realqtynow = $product_static->stock_warehouse[$line->fk_warehouse]->detail_batch[$line->batch]->qty; + } + + if (!is_null($qty_view)) { - $stock_movement_qty = price2num($qty_view - $qty_stock, 'MS'); + $stock_movement_qty = price2num($qty_view - $realqtynow, 'MS'); if ($stock_movement_qty != 0) { if ($stock_movement_qty < 0) { $movement_type = 1; @@ -152,15 +176,20 @@ if (empty($reshook)) { //$inventorycode = 'INV'.$object->id; $inventorycode = 'INV-'.$object->ref; - $idstockmove = $stockmovment->_create($user, $line->fk_product, $line->fk_warehouse, $stock_movement_qty, $movement_type, 0, $langs->trans('LabelOfInventoryMovemement', $object->id), $inventorycode, $datemovement, '', '', $line->batch); + $idstockmove = $stockmovment->_create($user, $line->fk_product, $line->fk_warehouse, $stock_movement_qty, $movement_type, 0, $langs->trans('LabelOfInventoryMovemement', $object->ref), $inventorycode, $datemovement, '', '', $line->batch); if ($idstockmove < 0) { $error++; setEventMessages($stockmovment->error, $stockmovment->errors, 'errors'); break; } - // Update line with id of stock movement - $sqlupdate = "UPDATE ".MAIN_DB_PREFIX."inventorydet SET fk_movement = ".((int) $idstockmove)." WHERE rowid = ".((int) $line->rowid); + // Update line with id of stock movement (and the start quantity if it has changed this last recording) + $sqlupdate = "UPDATE ".MAIN_DB_PREFIX."inventorydet"; + $sqlupdate .= " SET fk_movement = ".((int) $idstockmove); + if ($qty_stock != $realqtynow) { + $sqlupdate .= ", qty_stock = ".((float) $realqtynow); + } + $sqlupdate .= " WHERE rowid = ".((int) $line->rowid); $resqlupdate = $db->query($sqlupdate); if (! $resqlupdate) { $error++; @@ -215,7 +244,7 @@ if (empty($reshook)) { setEventMessages($langs->trans("FieldCannotBeNegative", $langs->transnoentitiesnoconv("RealQty")), null, 'errors'); } if ($result > 0) { - $inventoryline->qty_stock = price2num(GETPOST('stock_qty_'.$lineid, 'alpha'), 'MS'); // The new value we want + $inventoryline->qty_stock = price2num(GETPOST('stock_qty_'.$lineid, 'alpha'), 'MS'); // The new value that was set in as hidden field $inventoryline->qty_view = $qtytoupdate; // The new value we want $resultupdate = $inventoryline->update($user); } @@ -236,6 +265,18 @@ if (empty($reshook)) { } } + // Update line with id of stock movement (and the start quantity if it has changed this last recording) + if (! $error) { + $sqlupdate = "UPDATE ".MAIN_DB_PREFIX."inventory"; + $sqlupdate .= " SET fk_user_modif = ".((int) $user->id); + $sqlupdate .= " WHERE rowid = ".((int) $object->id); + $resqlupdate = $db->query($sqlupdate); + if (! $resqlupdate) { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + } + } + if (!$error) { $db->commit(); } else { @@ -766,9 +807,14 @@ if ($object->id > 0) { print $form->textwithpicto($langs->trans("RealQty"), $langs->trans("InventoryRealQtyHelp")); print ''; if ($object->status == $object::STATUS_DRAFT || $object->status == $object::STATUS_VALIDATED) { - // Actions + // Actions or link to stock movement print ''; print ''; + } else { + // Actions or link to stock movement + print ''; + //print $langs->trans("StockMovement"); + print ''; } print ''; @@ -799,7 +845,7 @@ if ($object->id > 0) { // Request to show lines of inventory (prefilled after start/validate step) $sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,'; - $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; + $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated, id.fk_movement'; $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); @@ -826,6 +872,7 @@ if ($object->id > 0) { $cacheOfWarehouses[$warehouse_static->id] = $warehouse_static; } + // Load real stock we have now if (isset($cacheOfProducts[$obj->fk_product])) { $product_static = $cacheOfProducts[$obj->fk_product]; } else { @@ -834,7 +881,7 @@ if ($object->id > 0) { //$option = 'nobatch'; $option .= ',novirtual'; - $product_static->load_stock($option); // Load stock_reel + stock_warehouse. This can also call load_virtual_stock() + $product_static->load_stock($option); // Load stock_reel + stock_warehouse. $cacheOfProducts[$product_static->id] = $product_static; } @@ -855,14 +902,14 @@ if ($object->id > 0) { // Expected quantity = Quantity in stock when we start inventory print ''; + $valuetoshow = $obj->qty_stock; + // For inventory not yet close, we overwrite with the real value in stock now if ($object->status == $object::STATUS_DRAFT || $object->status == $object::STATUS_VALIDATED) { if ($conf->productbatch->enabled && $product_static->hasbatch()) { $valuetoshow = $product_static->stock_warehouse[$obj->fk_warehouse]->detail_batch[$obj->batch]->qty; } else { $valuetoshow = $product_static->stock_warehouse[$obj->fk_warehouse]->real; } - } else { - $valuetoshow = $obj->qty_stock; } print price2num($valuetoshow, 'MS'); print ''; @@ -891,9 +938,16 @@ if ($object->id > 0) { print ''; print ''; } else { - print ''; + print ''; print $obj->qty_view; // qty found print ''; + print ''; + if ($obj->fk_movement > 0) { + $stockmovment = new MouvementStock($db); + $stockmovment->fetch($obj->fk_movement); + print $stockmovment->getNomUrl(1, 'movements'); + } + print ''; } print ''; diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index da06076fe97..a6bc6c2ec26 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -1071,7 +1071,7 @@ class MouvementStock extends CommonObject * Use this->id,this->lastname, this->firstname * * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) - * @param string $option On what the link point to + * @param string $option On what the link point to ('' = Tab of stock movement of warehouse, 'movements' = list of movements) * @param integer $notooltip 1=Disable tooltip * @param int $maxlen Max length of visible user name * @param string $morecss Add more css on link @@ -1082,16 +1082,21 @@ class MouvementStock extends CommonObject global $langs, $conf, $db; $result = ''; - $companylink = ''; - $label = ''.$langs->trans("Movement").' '.$this->id.''; + $label = img_picto('', 'stock', 'class="pictofixedwidth"').''.$langs->trans("Movement").' '.$this->id.''; $label .= '
'; $label .= ''.$langs->trans('Label').': '.$this->label; - $label .= '
'.$langs->trans('Qty').': '.$this->qty; + $label .= '
'.$langs->trans('Qty').': '.($this->qty > 0 ? '+' : '').$this->qty; $label .= '
'; - $link = 'id; + } else { + $url = DOL_URL_ROOT.'/product/stock/movement_list.php?id='.$this->warehouse_id.'&msid='.$this->id; + } + + $link = '