From 0c0923fbfc335c9f945092386382855cb288077c Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 14 Oct 2022 11:28:49 +0200 Subject: [PATCH 1/6] new: add information of line detail orgin and source into stock mouvement --- htdocs/expedition/class/expedition.class.php | 224 +++++++----------- .../stock/class/mouvementstock.class.php | 9 +- 2 files changed, 99 insertions(+), 134 deletions(-) diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 0790b54daa3..8fbfcc96234 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -708,76 +708,8 @@ class Expedition extends CommonObject // If stock increment is done on sending (recommanded choice) if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - - $langs->load("agenda"); - - // Loop on each product line to add a stock movement - $sql = "SELECT cd.fk_product, cd.subprice,"; - $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; - $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; - $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; - $sql .= " ".MAIN_DB_PREFIX."expeditiondet as ed"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; - $sql .= " WHERE ed.fk_expedition = ".((int) $this->id); - $sql .= " AND cd.rowid = ed.fk_origin_line"; - - dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) { - $cpt = $this->db->num_rows($resql); - for ($i = 0; $i < $cpt; $i++) { - $obj = $this->db->fetch_object($resql); - if (empty($obj->edbrowid)) { - $qty = $obj->qty; - } else { - $qty = $obj->edbqty; - } - if ($qty <= 0) { - continue; - } - dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); - - //var_dump($this->lines[$i]); - $mouvS = new MouvementStock($this->db); - - $mouvS->setOrigin($this->element, $this->id); - - if (empty($obj->edbrowid)) { - // line without batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr", $numref), '', '', '', '', 0, '', 1); - - if ($result < 0) { - $error++; - $this->error = $mouvS->error; - $this->errors = array_merge($this->errors, $mouvS->errors); - break; - } - } else { - // line with batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. - // Note: ->fk_origin_stock = id into table llx_product_batch (may be renamed into llx_product_stock_batch in another version) - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentValidatedInDolibarr", $numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock, '', 1); - if ($result < 0) { - $error++; - $this->error = $mouvS->error; - $this->errors = array_merge($this->errors, $mouvS->errors); - break; - } - } - } - - // If some stock lines are now 0, we can remove entry into llx_product_stock, but only if there is no child lines into llx_product_batch (detail of batch, because we can imagine - // having a lot1/qty=X and lot2/qty=-X, so 0 but we must not loose repartition of different lot. - $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".MAIN_DB_PREFIX."product_batch as pb)"; - $resql = $this->db->query($sql); - // We do not test error, it can fails if there is child in batch details - } else { - $this->db->rollback(); - $this->error = $this->db->error(); + $result = $this->manageStockMvtOnEvt($user); + if ($result < 0) { return -2; } } @@ -2151,69 +2083,8 @@ class Expedition extends CommonObject // If stock increment is done on closing if (!$error && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { - require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; - - $langs->load("agenda"); - - // Loop on each product line to add a stock movement - // TODO possibilite d'expedier a partir d'une propale ou autre origine ? - $sql = "SELECT cd.fk_product, cd.subprice,"; - $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; - $sql .= " e.ref,"; - $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; - $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; - $sql .= " ".MAIN_DB_PREFIX."expeditiondet as ed"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; - $sql .= " INNER JOIN ".MAIN_DB_PREFIX."expedition as e ON ed.fk_expedition = e.rowid"; - $sql .= " WHERE ed.fk_expedition = ".((int) $this->id); - $sql .= " AND cd.rowid = ed.fk_origin_line"; - - dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) { - $cpt = $this->db->num_rows($resql); - for ($i = 0; $i < $cpt; $i++) { - $obj = $this->db->fetch_object($resql); - if (empty($obj->edbrowid)) { - $qty = $obj->qty; - } else { - $qty = $obj->edbqty; - } - if ($qty <= 0) { - continue; - } - dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); - - $mouvS = new MouvementStock($this->db); - $mouvS->origin = &$this; - $mouvS->setOrigin($this->element, $this->id); - - if (empty($obj->edbrowid)) { - // line without batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref)); - if ($result < 0) { - $this->error = $mouvS->error; - $this->errors = $mouvS->errors; - $error++; - break; - } - } else { - // line with batch detail - - // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record - $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); - if ($result < 0) { - $this->error = $mouvS->error; - $this->errors = $mouvS->errors; - $error++; - break; - } - } - } - } else { - $this->error = $this->db->lasterror(); + $result = $this->manageStockMvtOnEvt($user); + if ($result<0) { $error++; } } @@ -2242,6 +2113,93 @@ class Expedition extends CommonObject } } + /** + * Manage Stock MVt onb Close or valid Shipment + * @param User $user Object user that modify + * @return int <0 if ko, >0 if ok + * @throws Exception + * + */ + private function manageStockMvtOnEvt($user) + { + $error=0; + + require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql .= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql .= " e.ref,"; + $sql .= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql .= " ,cd.rowid as cdid, ed.rowid as edid"; + $sql .= " FROM " . MAIN_DB_PREFIX . "commandedet as cd,"; + $sql .= " " . MAIN_DB_PREFIX . "expeditiondet as ed"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; + $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "expedition as e ON ed.fk_expedition = e.rowid"; + $sql .= " WHERE ed.fk_expedition = " . ((int) $this->id); + $sql .= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this) . "::valid select details", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) { + $qty = $obj->qty; + } else { + $qty = $obj->edbqty; + } + if ($qty <= 0) { + continue; + } + dol_syslog(get_class($this) . "::valid movement index " . $i . " ed.rowid=" . $obj->rowid . " edb.rowid=" . $obj->edbrowid); + + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + $mouvS->setOrigin($this->element, $this->id, $obj->cdid, $obj->edid); + + if (empty($obj->edbrowid)) { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; + break; + } + } else { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ShipmentClassifyClosedInDolibarr", $obj->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; + break; + } + } + + // If some stock lines are now 0, we can remove entry into llx_product_stock, but only if there is no child lines into llx_product_batch (detail of batch, because we can imagine + // having a lot1/qty=X and lot2/qty=-X, so 0 but we must not loose repartition of different lot. + $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_stock WHERE reel = 0 AND rowid NOT IN (SELECT fk_product_stock FROM ".MAIN_DB_PREFIX."product_batch as pb)"; + $resql = $this->db->query($sql); + // We do not test error, it can fails if there is child in batch details + } + } else { + $this->error = $this->db->lasterror(); + $this->errors[] = $this->db->lasterror(); + $error ++; + } + + return $error; + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Classify the shipping as invoiced (used when WORKFLOW_BILL_ON_SHIPMENT is on) diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index 31e66796a48..26f35a1a94e 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -104,6 +104,9 @@ class MouvementStock extends CommonObject public $inventorycode; public $batch; + public $lineIdObjectSrc; + public $lineIdObjectOrigin; + public $fields = array( 'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10, 'showoncombobox'=>1), @@ -1003,13 +1006,17 @@ class MouvementStock extends CommonObject * * @param string $origin_element Type of element * @param int $origin_id Id of element + * @param int $lineIdObjectSrc Id line of element Source + * @param int $lineIdObjectOrigin Id line of element Origin * * @return void */ - public function setOrigin($origin_element, $origin_id) + public function setOrigin($origin_element, $origin_id, $lineIdObjectSrc = 0, $lineIdObjectOrigin = 0) { $this->origin_type = $origin_element; $this->origin_id = $origin_id; + $this->lineIdObjectSrc = $lineIdObjectSrc; + $this->lineIdObjectOrigin = $lineIdObjectOrigin; // For backward compatibility $this->origintype = $origin_element; $this->fk_origin = $origin_id; From 7bb334fb5fc31c2cf69879e8ce29a55f5db52148 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 14 Oct 2022 11:35:44 +0200 Subject: [PATCH 2/6] fix --- htdocs/expedition/class/expedition.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 8fbfcc96234..6e42357a545 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -2122,6 +2122,8 @@ class Expedition extends CommonObject */ private function manageStockMvtOnEvt($user) { + global $langs; + $error=0; require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; From b5dac0e5f57157889618aae554d3a80c025afebc Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Wed, 23 Nov 2022 08:26:12 +0100 Subject: [PATCH 3/6] merge --- htdocs/expedition/class/expedition.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index f258423108c..04849a72dd9 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -2162,7 +2162,7 @@ class Expedition extends CommonObject } else { $qty = $obj->edbqty; } - if ($qty <= 0) { + if ($qty <= 0 || ($qty < 0 && !getDolGlobalInt('SHIPMENT_ALLOW_NEGATIVE_QTY'))) { continue; } dol_syslog(get_class($this) . "::valid movement index " . $i . " ed.rowid=" . $obj->rowid . " edb.rowid=" . $obj->edbrowid); From 1b5dcee03bf9ef1ba329ea81d8e73937e8c8e112 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Tue, 29 Nov 2022 22:34:24 +0100 Subject: [PATCH 4/6] revert camel case to old style --- .../product/stock/class/mouvementstock.class.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index ff88a93dca9..ce2a4213250 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -104,8 +104,8 @@ class MouvementStock extends CommonObject public $inventorycode; public $batch; - public $lineIdObjectSrc; - public $lineIdObjectOrigin; + public $line_id_oject_src; + public $line_id_oject_origin; public $fields = array( @@ -1005,17 +1005,17 @@ class MouvementStock extends CommonObject * * @param string $origin_element Type of element * @param int $origin_id Id of element - * @param int $lineIdObjectSrc Id line of element Source - * @param int $lineIdObjectOrigin Id line of element Origin + * @param int $line_id_oject_src Id line of element Source + * @param int $line_id_oject_origin Id line of element Origin * * @return void */ - public function setOrigin($origin_element, $origin_id, $lineIdObjectSrc = 0, $lineIdObjectOrigin = 0) + public function setOrigin($origin_element, $origin_id, $line_id_oject_src = 0, $line_id_oject_origin = 0) { $this->origin_type = $origin_element; $this->origin_id = $origin_id; - $this->lineIdObjectSrc = $lineIdObjectSrc; - $this->lineIdObjectOrigin = $lineIdObjectOrigin; + $this->line_id_oject_src = $line_id_oject_src; + $this->line_id_oject_origin = $line_id_oject_origin; // For backward compatibility $this->origintype = $origin_element; $this->fk_origin = $origin_id; From 35e75f335a6905761dc089cdf2e74b3f4812a8fc Mon Sep 17 00:00:00 2001 From: kkhelifa Date: Fri, 17 Mar 2023 09:58:49 +0100 Subject: [PATCH 5/6] FIX : Fix case when the value of a extrafields of the type 'boolean', 'select' or other have an option with a value equal to '0'. It's not reselected when the filter is set. --- htdocs/core/tpl/extrafields_list_search_input.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/tpl/extrafields_list_search_input.tpl.php b/htdocs/core/tpl/extrafields_list_search_input.tpl.php index f57101b81e6..3f90715cbea 100644 --- a/htdocs/core/tpl/extrafields_list_search_input.tpl.php +++ b/htdocs/core/tpl/extrafields_list_search_input.tpl.php @@ -47,7 +47,7 @@ if (!empty($extrafieldsobjectkey)) { // $extrafieldsobject is the $object->table if (in_array($typeofextrafield, array('link', 'sellist', 'text', 'html'))) { $morecss = 'maxwidth200'; } - echo $extrafields->showInputField($key, (empty($search_array_options[$search_options_pattern.$tmpkey]) ? '' : $search_array_options[$search_options_pattern.$tmpkey]), '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); + echo $extrafields->showInputField($key, (!isset($search_array_options[$search_options_pattern.$tmpkey]) ? '' : $search_array_options[$search_options_pattern.$tmpkey]), '', '', $search_options_pattern, $morecss, 0, $extrafieldsobjectkey, 1); } print ''; } From 8b095fdec0e22aaa89edfd2b8a085750121ac0f8 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Sun, 2 Apr 2023 12:57:38 +0200 Subject: [PATCH 6/6] review variable name --- .../product/stock/class/mouvementstock.class.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index 77f0f0cf60e..8ab5ff77da4 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -112,8 +112,8 @@ class MouvementStock extends CommonObject public $inventorycode; public $batch; - public $line_id_oject_src; - public $line_id_oject_origin; + public $line_id_object_src; + public $line_id_object_origin; public $fields = array( @@ -1015,17 +1015,17 @@ class MouvementStock extends CommonObject * * @param string $origin_element Type of element * @param int $origin_id Id of element - * @param int $line_id_oject_src Id line of element Source - * @param int $line_id_oject_origin Id line of element Origin + * @param int $line_id_object_src Id line of element Source + * @param int $line_id_object_origin Id line of element Origin * * @return void */ - public function setOrigin($origin_element, $origin_id, $line_id_oject_src = 0, $line_id_oject_origin = 0) + public function setOrigin($origin_element, $origin_id, $line_id_object_src = 0, $line_id_object_origin = 0) { $this->origin_type = $origin_element; $this->origin_id = $origin_id; - $this->line_id_oject_src = $line_id_oject_src; - $this->line_id_oject_origin = $line_id_oject_origin; + $this->line_id_oject_src = $line_id_object_src; + $this->line_id_oject_origin = $line_id_object_origin; // For backward compatibility $this->origintype = $origin_element; $this->fk_origin = $origin_id;