From d45dfe8ee7a9ccacaa4ffa583095c05715dc092a Mon Sep 17 00:00:00 2001 From: lainwir3d Date: Wed, 20 Oct 2021 18:17:26 +0400 Subject: [PATCH 1/2] Add stock availability reading. --- htdocs/core/modules/modStock.class.php | 23 ++++++++++++++------- htdocs/langs/en_US/stocks.lang | 3 ++- htdocs/langs/fr_FR/stocks.lang | 1 + htdocs/product/class/api_products.class.php | 23 +++++++++++++++++---- htdocs/product/class/product.class.php | 22 ++++++++++++++++++++ 5 files changed, 59 insertions(+), 13 deletions(-) diff --git a/htdocs/core/modules/modStock.class.php b/htdocs/core/modules/modStock.class.php index 3494cb684dc..89bc7c35423 100644 --- a/htdocs/core/modules/modStock.class.php +++ b/htdocs/core/modules/modStock.class.php @@ -149,18 +149,25 @@ class modStock extends DolibarrModules $this->rights[4][4] = 'mouvement'; $this->rights[4][5] = 'creer'; - $this->rights[5][0] = 1011; - $this->rights[5][1] = 'inventoryReadPermission'; // Permission label - $this->rights[5][3] = 0; // Permission by default for new user (0/1) - $this->rights[5][4] = 'inventory_advance'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) - $this->rights[5][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + $this->rights[5][0] = 1006; + $this->rights[5][1] = 'stockAvailabilityReadPermission'; + $this->rights[5][3] = 0; + $this->rights[5][4] = 'availability'; + $this->rights[5][5] = 'read'; - $this->rights[6][0] = 1012; - $this->rights[6][1] = 'inventoryCreatePermission'; // Permission label + $this->rights[6][0] = 1011; + $this->rights[6][1] = 'inventoryReadPermission'; // Permission label $this->rights[6][3] = 0; // Permission by default for new user (0/1) $this->rights[6][4] = 'inventory_advance'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) - $this->rights[6][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + $this->rights[6][5] = 'read'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + $this->rights[7][0] = 1012; + $this->rights[7][1] = 'inventoryCreatePermission'; // Permission label + $this->rights[7][3] = 0; // Permission by default for new user (0/1) + $this->rights[7][4] = 'inventory_advance'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + $this->rights[7][5] = 'write'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2) + + if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { $this->rights[8][0] = 1014; $this->rights[8][1] = 'inventoryValidatePermission'; // Permission label diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index f1bfe186bdf..d07a86f7354 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -256,4 +256,5 @@ MakeMovementsAndClose=Generate movements and close AutofillWithExpected=Fill real quantity with expected quantity ShowAllBatchByDefault=By default, show batch details on product "stock" tab CollapseBatchDetailHelp=You can set batch detail default display in stocks module configuration -FieldCannotBeNegative=Field "%s" cannot be negative \ No newline at end of file +FieldCannotBeNegative=Field "%s" cannot be negative +stockAvailabilityReadPermission=See stock availability diff --git a/htdocs/langs/fr_FR/stocks.lang b/htdocs/langs/fr_FR/stocks.lang index 68003ebe864..f91b24ad1db 100644 --- a/htdocs/langs/fr_FR/stocks.lang +++ b/htdocs/langs/fr_FR/stocks.lang @@ -257,3 +257,4 @@ AutofillWithExpected=Remplir la quantité réelle avec la quantité prévue ShowAllBatchByDefault=Par défaut, afficher les détails des lots sur l'onglet "stock" du produit CollapseBatchDetailHelp=You can set batch detail default display in stocks module configuration FieldCannotBeNegative=Le champ "%s" ne peut pas être négatif +stockAvailabilityReadPermission=Voir la disponibilité des stocks diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index 2e0d21b0456..c66bb7b43ed 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -1617,11 +1617,14 @@ class Products extends DolibarrApi $combinations[$key]->attributes = $prodc2vp->fetchByFkCombination((int) $combination->id); $combinations[$key] = $this->_cleanObjectDatas($combinations[$key]); - if ($includestock==1) { + if ($includestock==1 && (DolibarrApiAccess::$user->rights->stock->lire || DolibarrApiAccess::$user->rights->stock->availability->read)) { $productModel = new Product($this->db); $productModel->fetch((int) $combination->fk_product_child); $productModel->load_stock(); - $combinations[$key]->stock_warehouse = $this->_cleanObjectDatas($productModel)->stock_warehouse; + + if(DolibarrApiAccess::$user->rights->stock->lire){ // full warehouse info needs full stock reading perms + $combinations[$key]->stock_warehouse = $this->_cleanObjectDatas($productModel)->stock_warehouse; + } } } @@ -1859,7 +1862,7 @@ class Products extends DolibarrApi public function getStock($id, $selected_warehouse_id = null) { - if (!DolibarrApiAccess::$user->rights->produit->lire) { + if (!DolibarrApiAccess::$user->rights->produit->lire || !DolibarrApiAccess::$user->rights->stock->lire) { // full product and stock access required for detailed stock info throw new RestException(401); } @@ -1945,6 +1948,18 @@ class Products extends DolibarrApi unset($object->supplierprices); // Mut use another API to get them + // remove stock info if no stock read rights + if(!DolibarrApiAccess::$user->rights->stock->lire){ + unset($object->stock_reel); + unset($object->stock_theorique); + unset($object->stock_warehouse); + } + + // remove stock availability info if no stock read rights or availability read rights + if((!DolibarrApiAccess::$user->rights->stock->availability->read) && (!DolibarrApiAccess::$user->rights->stock->lire)){ + unset($object->stock_real_available); + unset($object->stock_virtual_available); + } return $object; } @@ -2008,7 +2023,7 @@ class Products extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - if ($includestockdata) { + if ($includestockdata && (DolibarrApiAccess::$user->rights->stock->lire || DolibarrApiAccess::$user->rights->stock->availability->read)) { $this->product->load_stock(); if (is_array($this->product->stock_warehouse)) { diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index bcdf5a6d033..ca4e3ecf58b 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -208,6 +208,22 @@ class Product extends CommonObject */ public $stock_theorique; + /** + * Stock real available + * + * @var bool + */ + public $stock_real_available = false; + + /** + * Stock virtual available + * + * @var bool + */ + public $stock_virtual_available = false; + + + /** * Cost price * @@ -5172,6 +5188,8 @@ class Product extends CommonObject $this->stock_reel = 0; $this->stock_warehouse = array(); $this->stock_theorique = 0; + $this->stock_real_available = false; + $this->stock_virtual_available = false; // Set filter on warehouse status $warehouseStatus = array(); @@ -5221,6 +5239,8 @@ class Product extends CommonObject } $this->db->free($result); + $this->stock_real_available = ($this->stock_reel > 0) ? true : false; + if (!preg_match('/novirtual/', $option)) { $this->load_virtual_stock($includedraftpoforvirtual); // This also load all arrays stats_xxx... } @@ -5344,6 +5364,8 @@ class Product extends CommonObject $this->stock_theorique = $hookmanager->resArray['stock_theorique']; } + $this->stock_virtual_available = ($this->stock_theorique > 0) ? true : false; + return 1; } From f2c1d9d63791cd5b18510628ee7549bc26c6e2f1 Mon Sep 17 00:00:00 2001 From: lainwir3d Date: Tue, 2 Nov 2021 19:28:06 +0400 Subject: [PATCH 2/2] Stock availability: show stock availability in web ui product combo list. --- htdocs/core/class/html.form.class.php | 74 ++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 7137d843ba7..3dbf689d562 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -2807,7 +2807,7 @@ class Form $opt .= ' pbq="'.$objp->price_by_qty_rowid.'" data-pbq="'.$objp->price_by_qty_rowid.'" data-pbqup="'.$objp->price_by_qty_unitprice.'" data-pbqbase="'.$objp->price_by_qty_price_base_type.'" data-pbqqty="'.$objp->price_by_qty_quantity.'" data-pbqpercent="'.$objp->price_by_qty_remise_percent.'"'; } if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) { - if (!empty($user->rights->stock->lire)) { + if ((!empty($user->rights->stock->lire)) || (!empty($user->rights->stock->availability->read))) { if ($objp->stock > 0) { $opt .= ' class="product_line_stock_ok"'; } elseif ($objp->stock <= 0) { @@ -2973,9 +2973,9 @@ class Form $tmpproduct->load_virtual_stock(); $virtualstock = $tmpproduct->stock_theorique; - $opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock; + $opt .= ' - '.$langs->trans("VirtualStock").': '.$virtualstock; - $outval .= ' - '.$langs->transnoentities("VirtualStock").':'; + $outval .= ' - '.$langs->transnoentities("VirtualStock").': '; if ($virtualstock > 0) { $outval .= ''; } elseif ($virtualstock <= 0) { @@ -2984,9 +2984,40 @@ class Form $outval .= $virtualstock; $outval .= ''; + unset($tmpproduct); + } + }else if (!empty($user->rights->stock->availability->read)) { + if ($objp->stock > 0) { + $opt .= ' - '.$langs->trans("Stock").': '.$langs->trans("Available"); + $outval .= ' - '.$langs->transnoentities("Stock").': '.$langs->trans("Available"); + } elseif ($objp->stock <= 0) { + $opt .= ' - '.$langs->trans("Stock").': '.$langs->trans("NotAvailable"); + $outval .= ' - '.$langs->transnoentities("Stock").': '.$langs->trans("NotAvailable"); + } + $outval .= ''; + if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation + $langs->load("stocks"); + + $tmpproduct = new Product($this->db); + $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after) + $tmpproduct->load_virtual_stock(); + $virtualstock = $tmpproduct->stock_virtual_available ? $langs->trans("Available") : $langs->trans("NotAvailable"); + + $opt .= ' - '.$langs->trans("VirtualStock").': '.$virtualstock; + + $outval .= ' - '.$langs->transnoentities("VirtualStock").': '; + if ($tmpproduct->stock_virtual_available) { + $outval .= ''; + } else { + $outval .= ''; + } + $outval .= $virtualstock; + $outval .= ''; + unset($tmpproduct); } } + } $opt .= "\n"; @@ -3344,7 +3375,7 @@ class Form } elseif ($objp->stock <= 0) { $optlabel .= ' - '; } - $optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS')); + $optlabel .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS')); $optlabel .= ''; if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation $langs->load("stocks"); @@ -3354,20 +3385,51 @@ class Form $tmpproduct->load_virtual_stock(); $virtualstock = $tmpproduct->stock_theorique; - $outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock; + $outvallabel .= ' - '.$langs->trans("VirtualStock").': '.$virtualstock; - $optlabel .= ' - '.$langs->transnoentities("VirtualStock").':'; if ($virtualstock > 0) { $optlabel .= ''; } elseif ($virtualstock <= 0) { $optlabel .= ''; } + $optlabel .= ' - '.$langs->transnoentities("VirtualStock").': '; + $optlabel .= $virtualstock; + $optlabel .= ''; + + unset($tmpproduct); + } + }else if (!empty($user->rights->stock->availability->read)) { + if ($objp->stock > 0) { + $outvallabel .= ' - '.$langs->trans("Stock").': '.$langs->trans("Available"); + $optlabel .= ' - '.$langs->transnoentities("Stock").': '.$langs->trans("Available"); + } elseif ($objp->stock <= 0) { + $outvallabel .= ' - '.$langs->trans("Stock").': '.$langs->trans("NotAvailable"); + $optlabel .= ' - '.$langs->transnoentities("Stock").': '.$langs->trans("NotAvailable"); + } + $optlabel .= ''; + if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation + $langs->load("stocks"); + + $tmpproduct = new Product($this->db); + $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after) + $tmpproduct->load_virtual_stock(); + $virtualstock = $tmpproduct->stock_virtual_available ? $langs->trans("Available") : $langs->trans("NotAvailable"); + + $outvallabel .= ' - '.$langs->trans("VirtualStock").': '.$virtualstock; + + if ($tmpproduct->stock_virtual_available) { + $optlabel .= ''; + } else { + $optlabel .= ''; + } + $optlabel .= ' - '.$langs->transnoentities("VirtualStock").': '; $optlabel .= $virtualstock; $optlabel .= ''; unset($tmpproduct); } } + } $opt = '