From 387d2729d6025a3e0a5c0a760eb87476e69cc3ca Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 12 Oct 2023 13:53:31 +0200 Subject: [PATCH 01/20] Update as proposed --- htdocs/install/mysql/migration/18.0.0-19.0.0.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/install/mysql/migration/18.0.0-19.0.0.sql b/htdocs/install/mysql/migration/18.0.0-19.0.0.sql index 370e6f4595e4a..142d02481534e 100644 --- a/htdocs/install/mysql/migration/18.0.0-19.0.0.sql +++ b/htdocs/install/mysql/migration/18.0.0-19.0.0.sql @@ -208,3 +208,4 @@ INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle) VALUES (1,'66','Soci ALTER TABLE llx_prelevement_lignes ADD COLUMN tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; ALTER TABLE llx_bom_bomline ADD COLUMN tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; + From 7c03476819e93261c95d6786a0e82cc5b496d7eb Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 11 Jun 2023 05:00:30 +0200 Subject: [PATCH 02/20] Code part --- htdocs/core/lib/product.lib.php | 2 +- htdocs/product/class/product.class.php | 74 ++++++++++++++----- htdocs/product/list.php | 42 ++++++++++- .../stock/class/mouvementstock.class.php | 12 +-- 4 files changed, 102 insertions(+), 28 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index a631d7ff8269a..fc1442d659642 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -129,7 +129,7 @@ function product_prepare_head($object) $h++; } - if ($object->isProduct() || ($object->isService() && getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) { // If physical product we can stock (or service with option) + if (($object->isProduct() || ($object->isService() && && getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) && $object->stockable_product == Product::ENABLED_STOCK) { // If physical product we can stock (or service with option) if (isModEnabled('stock') && $user->hasRight('stock', 'lire')) { $head[$h][0] = DOL_URL_ROOT."/product/stock/product.php?id=".$object->id; $head[$h][1] = $langs->trans("Stock"); diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 3d10cc0143a10..88ab2e5fb8359 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -546,6 +546,12 @@ class Product extends CommonObject public $mandatory_period; + /** + * 0=This service or product is not managed in stock, 1=This service or product is managed in stock + * + * @var boolean + */ + public $stockable_product = 1; /** * 'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') @@ -599,6 +605,7 @@ class Product extends CommonObject //'tosell' =>array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Active', -1=>'Cancel')), //'tobuy' =>array('type'=>'integer', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Active', -1=>'Cancel')), 'mandatory_period' => array('type'=>'integer', 'label'=>'mandatoryperiod', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'default'=>0, 'index'=>1, 'position'=>1000), + 'stockable_product' =>array('type'=>'integer', 'label'=>'stockable_product', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>502), ); /** @@ -609,6 +616,21 @@ class Product extends CommonObject * Service */ const TYPE_SERVICE = 1; + /** + * Advanced feature: assembly kit + */ + const TYPE_ASSEMBLYKIT = 2; + /** + * Advanced feature: stock kit + */ + const TYPE_STOCKKIT = 3; + + /** + * Stockable product + */ + const NOT_MANAGED_IN_STOCK = 1; + const DISABLED_STOCK = 1; + const ENABLED_STOCK = 0; /** * Constructor @@ -710,6 +732,9 @@ public function create($user, $notrigger = 0) if (empty($this->status_buy)) { $this->status_buy = 0; } + if (empty($this->stockable_product)) { + $this->stockable_product = 0; + } $price_ht = 0; $price_ttc = 0; @@ -833,6 +858,7 @@ public function create($user, $notrigger = 0) $sql .= ", batch_mask"; $sql .= ", fk_unit"; $sql .= ", mandatory_period"; + $sql .= ", stockable_product"; $sql .= ") VALUES ("; $sql .= "'".$this->db->idate($now)."'"; $sql .= ", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity); @@ -863,6 +889,7 @@ public function create($user, $notrigger = 0) $sql .= ", '".$this->db->escape($this->batch_mask)."'"; $sql .= ", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) : 'NULL'); $sql .= ", '".$this->db->escape($this->mandatory_period)."'"; + $sql .= ", ".((int) $this->stockable_product); $sql .= ")"; dol_syslog(get_class($this)."::Create", LOG_DEBUG); @@ -1141,6 +1168,10 @@ public function update($id, $user, $notrigger = 0, $action = 'update', $updatety $this->state_id = 0; } + if (empty($this->stockable_product)) { + $this->stockable_product = 0; + } + // Barcode value $this->barcode = (empty($this->barcode) ? '' : trim($this->barcode)); @@ -1299,7 +1330,9 @@ public function update($id, $user, $notrigger = 0, $action = 'update', $updatety $sql .= ", price_autogen = ".(!$this->price_autogen ? 0 : 1); $sql .= ", fk_price_expression = ".($this->fk_price_expression != 0 ? (int) $this->fk_price_expression : 'NULL'); $sql .= ", fk_user_modif = ".($user->id > 0 ? $user->id : 'NULL'); - $sql .= ", mandatory_period = ".($this->mandatory_period); + $sql .= ", mandatory_period = ".($this->mandatory_period ); + $sql .= ", stockable_product = ".(int) $this->stockable_product; + // stock field is not here because it is a denormalized value from product_stock. $sql .= " WHERE rowid = ".((int) $id); @@ -2570,8 +2603,8 @@ public function fetch($id = 0, $ref = '', $ref_ext = '', $barcode = '', $ignore_ } else { $sql .= " p.pmp,"; } - $sql .= " p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.sell_or_eat_by_mandatory, p.batch_mask, p.fk_unit,"; - $sql .= " p.fk_price_expression, p.price_autogen, p.model_pdf,"; + $sql .= " p.datec, p.tms, p.import_key, p.entity, p.desiredstock, p.tobatch, p.batch_mask, p.fk_unit,"; + $sql .= " p.fk_price_expression, p.price_autogen, p.stockable_product,p.model_pdf,"; if ($separatedStock) { $sql .= " SUM(sp.reel) as stock"; } else { @@ -2684,12 +2717,12 @@ public function fetch($id = 0, $ref = '', $ref_ext = '', $barcode = '', $ignore_ $this->height = $obj->height; $this->height_units = $obj->height_units; - $this->surface = $obj->surface; - $this->surface_units = $obj->surface_units; - $this->volume = $obj->volume; - $this->volume_units = $obj->volume_units; - $this->barcode = $obj->barcode; - $this->barcode_type = $obj->fk_barcode_type; + $this->surface = $obj->surface; + $this->surface_units = $obj->surface_units; + $this->volume = $obj->volume; + $this->volume_units = $obj->volume_units; + $this->barcode = $obj->barcode; + $this->barcode_type = $obj->fk_barcode_type; $this->accountancy_code_buy = $obj->accountancy_code_buy; $this->accountancy_code_buy_intra = $obj->accountancy_code_buy_intra; @@ -2698,17 +2731,18 @@ public function fetch($id = 0, $ref = '', $ref_ext = '', $barcode = '', $ignore_ $this->accountancy_code_sell_intra = $obj->accountancy_code_sell_intra; $this->accountancy_code_sell_export = $obj->accountancy_code_sell_export; - $this->fk_default_warehouse = $obj->fk_default_warehouse; - $this->fk_default_workstation = $obj->fk_default_workstation; - $this->seuil_stock_alerte = $obj->seuil_stock_alerte; - $this->desiredstock = $obj->desiredstock; - $this->stock_reel = $obj->stock; - $this->pmp = $obj->pmp; - - $this->date_creation = $obj->datec; - $this->date_modification = $obj->tms; - $this->import_key = $obj->import_key; - $this->entity = $obj->entity; + $this->fk_default_warehouse = $obj->fk_default_warehouse; + $this->fk_default_workstation = $obj->fk_default_workstation; + $this->seuil_stock_alerte = $obj->seuil_stock_alerte; + $this->desiredstock = $obj->desiredstock; + $this->stock_reel = $obj->stock; + $this->stockable_product = $obj->stockable_product; + $this->pmp = $obj->pmp; + + $this->date_creation = $obj->datec; + $this->date_modification = $obj->tms; + $this->import_key = $obj->import_key; + $this->entity = $obj->entity; $this->ref_ext = $obj->ref_ext; $this->fk_price_expression = $obj->fk_price_expression; diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 3b137f8f88d55..9aad361755981 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -96,6 +96,7 @@ $search_state = GETPOST("state_id", 'int'); $fourn_id = GETPOST("fourn_id", 'int'); $search_tobatch = GETPOST("search_tobatch", 'int'); +$search_stockable_product = GETPOST('search_stockable_product', 'int'); $search_accountancy_code_sell = GETPOST("search_accountancy_code_sell", 'alpha'); $search_accountancy_code_sell_intra = GETPOST("search_accountancy_code_sell_intra", 'alpha'); $search_accountancy_code_sell_export = GETPOST("search_accountancy_code_sell_export", 'alpha'); @@ -272,6 +273,19 @@ 'p.tobuy'=>array('label'=>$langs->transnoentitiesnoconv("Status").' ('.$langs->transnoentitiesnoconv("Buy").')', 'checked'=>1, 'position'=>1000), 'p.import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'checked'=>-1, 'position'=>1100), ); + +if(! empty($conf->stock->enabled)) { + // service + if($type == 1) { + if(! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { + $arrayfields['p.stockable_product'] = array('label' => $langs->trans('StockableProduct'), 'checked' => 0, 'position' => 1001); + } + } + else { + //product + $arrayfields['p.stockable_product'] = array('label' => $langs->trans('StockableProduct'), 'checked' => 0, 'position' => 1001); + } +} /*foreach ($object->fields as $key => $val) { // If $val['visible']==0, then we never show the field if (!empty($val['visible'])) { @@ -364,6 +378,7 @@ //$search_type=''; // There is 2 types of list: a list of product and a list of services. No list with both. So when we clear search criteria, we must keep the filter on type. $show_childproducts = ''; + $search_stockable_product = ''; $search_accountancy_code_sell = ''; $search_accountancy_code_sell_intra = ''; $search_accountancy_code_sell_export = ''; @@ -449,7 +464,7 @@ } $sql .= ' p.datec as date_creation, p.tms as date_update, p.pmp, p.stock, p.cost_price,'; $sql .= ' p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units,'; -$sql .= ' p.fk_country, p.fk_state,'; +$sql .= ' p.fk_country, p.fk_state, p.stockable_product,'; $sql .= ' p.import_key,'; if (getDolGlobalString('PRODUCT_USE_UNITS')) { $sql .= ' p.fk_unit, cu.label as cu_label,'; @@ -548,6 +563,9 @@ if (isset($search_tobuy) && dol_strlen($search_tobuy) > 0 && $search_tobuy != -1) { $sql .= " AND p.tobuy = ".((int) $search_tobuy); } +if (isset($search_stockable_product) && dol_strlen($search_stockable_product) > 0 && $search_stockable_product != -1) { + $sql .= " AND p.stockable_product = '". $search_stockable_product . "'"; +} if (isset($search_tobatch) && dol_strlen($search_tobatch) > 0 && $search_tobatch != -1) { $sql .= " AND p.tobatch = ".((int) $search_tobatch); } @@ -633,7 +651,7 @@ $sql .= " ppe.accountancy_code_sell, ppe.accountancy_code_sell_intra, ppe.accountancy_code_sell_export, ppe.accountancy_code_buy, ppe.accountancy_code_buy_intra, ppe.accountancy_code_buy_export,"; } $sql .= ' p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units,'; -$sql .= ' p.fk_country, p.fk_state,'; +$sql .= ' p.fk_country, p.fk_state, p.stockable_product,'; $sql .= ' p.import_key'; if (getDolGlobalString('PRODUCT_USE_UNITS')) { $sql .= ', p.fk_unit, cu.label'; @@ -818,6 +836,9 @@ if ($search_finished) { $param .= "&search_finished=".urlencode($search_finished); } +if($search_stockable_product != '') { + $param .= "&search_stockable_product=".urlencode($search_stockable_product); +} // Add $param from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; @@ -1156,6 +1177,11 @@ print ' '; print ''; } +// Managed_in_stock +$array = array('-1'=>' ', '0'=>$langs->trans('No'), '1'=>$langs->trans('Yes')); +if (!empty($arrayfields['p.stockable_product']['checked'])){ + print ''.Form::selectarray('search_stockable_product', $array, $search_stockable_product).''; +} // Desired stock if (!empty($arrayfields['p.desiredstock']['checked'])) { print ''; @@ -1403,6 +1429,9 @@ print_liste_field_titre($arrayfields['p.seuil_stock_alerte']['label'], $_SERVER["PHP_SELF"], "p.seuil_stock_alerte", "", $param, '', $sortfield, $sortorder, 'right '); $totalarray['nbfield']++; } +if (!empty($arrayfields['p.stockable_product']['checked'])) { + print_liste_field_titre($arrayfields['p.stockable_product']['label'], $_SERVER['PHP_SELF'], 'p.stockable_product', '', $param, '', $sortfield, $sortorder, 'center '); +} if (!empty($arrayfields['p.desiredstock']['checked'])) { print_liste_field_titre($arrayfields['p.desiredstock']['label'], $_SERVER["PHP_SELF"], "p.desiredstock", "", $param, '', $sortfield, $sortorder, 'right '); $totalarray['nbfield']++; @@ -1552,6 +1581,7 @@ $product_static->volume_units = $obj->volume_units; $product_static->surface = $obj->surface; $product_static->surface_units = $obj->surface_units; + $product_static->stockable_product = $obj->stockable_product; if (getDolGlobalString('PRODUCT_USE_UNITS')) { $product_static->fk_unit = $obj->fk_unit; } @@ -2050,6 +2080,14 @@ $totalarray['nbfield']++; } } + + // not managed in stock + if(! empty($arrayfields['p.stockable_product']['checked'])) { + print ''; + print ($product_static->stockable_product == '1') ? $langs->trans('Yes') : $langs->trans('No'); + print ''; + } + // Desired stock if (!empty($arrayfields['p.desiredstock']['checked'])) { print ''; diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index 27a0cc5cf768e..cbbc8dd798a14 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -441,7 +441,7 @@ public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = return -8; } } else { - if (empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty)) { + if ((empty($product->stock_warehouse[$entrepot_id]->real) || $product->stock_warehouse[$entrepot_id]->real < abs($qty)) && $product->stockable_product == Product::ENABLED_STOCK) { $langs->load("stocks"); $this->error = $langs->trans('qtyToTranferIsNotEnough').' : '.$product->ref; $this->errors[] = $langs->trans('qtyToTranferIsNotEnough').' : '.$product->ref; @@ -451,7 +451,7 @@ public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = } } - if ($movestock) { // Change stock for current product, change for subproduct is done after + if ($movestock && $product->stockable_product == PRODUCT::ENABLED_STOCK) { // Change stock for current product, change for subproduct is done after // Set $origin_type, origin_id and fk_project $fk_project = $this->fk_project; if (!empty($this->origin_type)) { // This is set by caller for tracking reason @@ -627,9 +627,11 @@ public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = if ($movestock && !$error) { // Call trigger - $result = $this->call_trigger('STOCK_MOVEMENT', $user); - if ($result < 0) { - $error++; + if ($product->stockable_product != Product::NOT_MANAGED_IN_STOCK ) { + $result = $this->call_trigger('STOCK_MOVEMENT', $user); + if ($result < 0) { + $error++; + } } // End call triggers From 53645ff2d94313fbfde6fe16284f82342542ff7f Mon Sep 17 00:00:00 2001 From: tnegre Date: Thu, 12 Oct 2023 14:57:29 +0200 Subject: [PATCH 03/20] Code part 2 --- htdocs/expedition/card.php | 60 ++++++++++++++++---- htdocs/expedition/class/expedition.class.php | 2 +- htdocs/langs/en_US/products.lang | 5 +- htdocs/langs/fr_FR/products.lang | 4 ++ htdocs/product/card.php | 22 +++++++ 5 files changed, 81 insertions(+), 12 deletions(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 6826801e965bc..361625009014d 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -270,6 +270,7 @@ $subtotalqty = 0; $j = 0; + $batch = "batchl".$i."_0"; $stockLocation = "ent1".$i."_0"; $qty = "qtyl".$i; @@ -342,6 +343,31 @@ $qty = "qtyl".$i.'_'.$j; } } else { + $p = new Product($db); + $res = $p->fetch($objectsrc->lines[$i]->fk_product); + if($res > 0) { + if(GETPOST('entrepot_id', 'int') == -1) { + $qty .= '_'.$j; + } + + if($p->stockable_product == Product::DISABLED_STOCK) { + $w = new Entrepot($db); + $Tw = $w->list_array(); + if(count($Tw) > 0) { + $w_Id = array_keys($Tw); + $stockLine[$i][$j]['qty'] = GETPOST($qty, 'int'); + + // lorsque que l'on a le stock désactivé sur un produit/service + // on force l'entrepot pour passer le test d'ajout de ligne dans expedition.class.php + // + $stockLine[$i][$j]['warehouse_id'] = $w_Id[0]; + $stockLine[$i][$j]['ix_l'] = GETPOST($idl, 'int'); + } + else { + setEventMessage($langs->trans('NoWarehouseInBase')); + } + } + } //shipment line for product with no batch management and no multiple stock location if (GETPOST($qty, 'int') > 0) { $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS'); @@ -1234,7 +1260,7 @@ $text = $product_static->getNomUrl(1); $text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label); $description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc)); - + $description .= empty($product->stockable_product) ? $langs->trans('StockDisabled') : $langs->trans('StockEnabled') ; print $form->textwithtooltip($text, $description, 3, '', '', $i); // Show range @@ -1344,8 +1370,11 @@ if (!getDolGlobalInt('STOCK_ALLOW_NEGATIVE_TRANSFER')) { $stockMin = 0; } - print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'minwidth200', '', 1, $stockMin, 'stock DESC, e.ref'); - + if ($product->stockable_product == Product::ENABLED_STOCK){ + print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'minwidth200', '', 1, $stockMin, 'stock DESC, e.ref'); + } else { + print img_warning().' '.$langs->trans('StockDisabled') ; + } if ($tmpentrepot_id > 0 && $tmpentrepot_id == $warehouse_id) { //print $stock.' '.$quantityToBeDelivered; if ($stock < $quantityToBeDelivered) { @@ -1543,10 +1572,13 @@ if (isModEnabled('stock')) { print ''; if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) { - print $tmpwarehouseObject->getNomUrl(0).' '; - - print ''; - print '('.$stock.')'; + if ($product->stockable_product == Product::ENABLED_STOCK){ + print $tmpwarehouseObject->getNomUrl(0).' '; + print ''; + print '('.$stock.')'; + } else { + print img_warning().' '.$langs->trans('StockDisabled') ; + } } else { print '('.$langs->trans("Service").')'; } @@ -1706,6 +1738,10 @@ if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty. $disabled = 'disabled="disabled"'; } + // finally we overwrite the input with the product status stockable_product if it's disabled + if ($product->stockable_product == Product::DISABLED_STOCK){ + $disabled = ''; + } print ' '; } else { print $langs->trans("NA"); @@ -1720,8 +1756,11 @@ print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->label); } else { if ($line->fk_product) { - print img_warning().' '.$langs->trans("StockTooLow"); - } else { + if($product->stockable_product == Product::ENABLED_STOCK) { + print img_warning().' '.$langs->trans('StockTooLow'); + } else { + print img_warning().' '.$langs->trans('StockDisabled'); + } } else { print ''; } } @@ -2328,6 +2367,7 @@ $product_static->surface_units = $lines[$i]->surface_units; $product_static->volume = $lines[$i]->volume; $product_static->volume_units = $lines[$i]->volume_units; + $product_static->stockable_product = $lines[$i]->stockable_product; $text = $product_static->getNomUrl(1); $text .= ' - '.$label; @@ -2498,7 +2538,7 @@ print ''; if ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) { print '('.$langs->trans("Service").')'; - } elseif ($lines[$i]->entrepot_id > 0) { + } elseif ($lines[$i]->entrepot_id > 0 && $lines[$i]->product->stockable_product == Product::ENABLED_STOCK) { $entrepot = new Entrepot($db); $entrepot->fetch($lines[$i]->entrepot_id); print $entrepot->getNomUrl(1); diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 633291018e752..2d155d7a950fb 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -943,7 +943,7 @@ public function addline($entrepot_id, $id, $qty, $array_options = 0) $isavirtualproduct = ($product->hasFatherOrChild(1) > 0); // The product is qualified for a check of quantity (must be enough in stock to be added into shipment). if (!$isavirtualproduct || !getDolGlobalString('PRODUIT_SOUSPRODUITS') || ($isavirtualproduct && !getDolGlobalString('STOCK_EXCLUDE_VIRTUAL_PRODUCTS'))) { // If STOCK_EXCLUDE_VIRTUAL_PRODUCTS is set, we do not manage stock for kits/virtual products. - if ($product_stock < $qty) { + if ($product_stock < $qty && $product->stockable_product == Product::ENABLED_STOCK) { $langs->load("errors"); $this->error = $langs->trans('ErrorStockIsNotEnoughToAddProductOnShipment', $product->ref); $this->errorhidden = 'ErrorStockIsNotEnoughToAddProductOnShipment'; diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index 77355fce3858b..d50e4688ae39d 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -436,4 +436,7 @@ WarningConvertFromBatchToSerial=If you currently have a quantity higher or equal AllowStockMovementVariantParent=Also records stock movements on parent products of variant products AllowStockMovementVariantParentHelp=By default, a parent of a variant is a virtual product, so no stock is managed for it. By enabling this option, a stock will be managed for parent products and each time a stock quantity is modified for a variant product, the same quantity will be modified for the parent product. You should not need this option, except if you are using variant to manage the same product than parent (but with different descriptions, prices...) ConfirmSetToDraftInventory=Are you sure you want to go back to Draft status?
The quantities currently set in the inventory will be reset. - +StockableProduct=Stock management +StockableProductDescription=If this option is enabled, the stock modification for this element is retained. If disabled, the stock modification for this element is not retained. +StockDisabled=Stock disabled +StockEnabled=Stock enabled diff --git a/htdocs/langs/fr_FR/products.lang b/htdocs/langs/fr_FR/products.lang index 9ac8174656f83..89b1b6da9d2e9 100644 --- a/htdocs/langs/fr_FR/products.lang +++ b/htdocs/langs/fr_FR/products.lang @@ -438,3 +438,7 @@ OrProductsWithCategories=Ou des produits avec des tags/catégories WarningTransferBatchStockMouvToGlobal = Si vous souhaitez désérialiser ce produit, tout son stock sérialisé sera transformé en stock global WarningConvertFromBatchToSerial=Si vous disposez actuellement d'une quantité supérieure ou égale à 2 pour le produit, passer à ce choix signifie que vous aurez toujours un produit avec différents objets du même lot (alors que vous souhaitez un numéro de série unique). Le doublon restera jusqu'à ce qu'un inventaire ou un mouvement de stock manuel soit effectué pour résoudre ce problème. ConfirmSetToDraftInventory=Êtes-vous sûr de vouloir revenir à l'état de brouillon ?
Les quantités actuellement définies dans l'inventaire seront réinitialisées. +StockableProduct=Activer la gestion des stocks +StockableProductDescription=Si cette option est désactivée, la modification du stock pour cet élément n'est pas prise en compte. Les mouvements de stock ne seront pas pris en compte dans les commandes client, commande fournisseur, expédition, réception, ordre de fabrication.
Dans les faits, cette option se comporte comme une activation/désactivation du module stock mais à l'échelle du produit/service +StockDisabled=Stock désactivé +StockEnabled=Stock activé diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 5a4f56728f2e3..62ea709aedb59 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -629,6 +629,9 @@ $object->fk_unit = null; } + // managed_in_stock + $object->stockable_product = ($type == 0 || ($type == 1 && !empty($conf->global->STOCK_SUPPORTS_SERVICES))) ? 1 : 0; + $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha'); $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha'); $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha'); @@ -806,6 +809,9 @@ } else { $object->fk_default_bom = null; } + + // managed_in_stock + $object->stockable_product = GETPOSTISSET('stockable_product'); $units = GETPOST('units', 'int'); if ($units > 0) { @@ -2152,6 +2158,10 @@ print ''; print ''; */ + + print '' . $langs->trans("StockableProduct") . ''; + $checked = $object->stockable_product == 1 ? "checked" : ""; + print ''; } if ($object->isService() && $conf->workstation->enabled) { @@ -2184,6 +2194,12 @@ print ''; print ''; + + if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { + print '' . $langs->trans("StockableProduct") . ''; + $checked = $object->stockable_product == 1 ? "checked" : ""; + print ''; + } } else { if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) { // Nature @@ -2664,6 +2680,12 @@ print ''.$langs->trans("DefaultWorkstation").''; print(!empty($workstation->id) ? $workstation->getNomUrl(1) : ''); print ''; + } + + // View stockable_product + if (($object->isProduct() || ($object->isService() && !empty($conf->global->STOCK_SUPPORTS_SERVICES))) && !empty($conf->stock->enabled)) { + print '' . $form->textwithpicto($langs->trans("StockableProduct"), $langs->trans('StockableProductDescription')) . ''; + print 'stockable_product == 1 ? 'checked' : '').'>'; } // Parent product. From 29904fd2cd7b2c16af576d3211ecadd3466da418 Mon Sep 17 00:00:00 2001 From: tnegre Date: Thu, 12 Oct 2023 15:18:59 +0200 Subject: [PATCH 04/20] Fix : invert a const --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 88ab2e5fb8359..6cfab5c87ec91 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -628,7 +628,7 @@ class Product extends CommonObject /** * Stockable product */ - const NOT_MANAGED_IN_STOCK = 1; + const NOT_MANAGED_IN_STOCK = 0; const DISABLED_STOCK = 1; const ENABLED_STOCK = 0; From 8dd43c8cf83648ebf75647e0bf51461edf5e76d4 Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 17 Oct 2023 10:45:05 +0200 Subject: [PATCH 05/20] Fix : invert disable/enable stock values --- htdocs/product/class/product.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 6cfab5c87ec91..b5c062b3301a8 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -629,8 +629,8 @@ class Product extends CommonObject * Stockable product */ const NOT_MANAGED_IN_STOCK = 0; - const DISABLED_STOCK = 1; - const ENABLED_STOCK = 0; + const DISABLED_STOCK = 0; + const ENABLED_STOCK = 1; /** * Constructor From 1566d185578b296748e6fc618ba7ccd94fffc9b8 Mon Sep 17 00:00:00 2001 From: mrozniecki Date: Thu, 15 Feb 2024 15:00:59 +0100 Subject: [PATCH 06/20] Fix --- htdocs/core/lib/product.lib.php | 2 +- htdocs/expedition/class/expedition.class.php | 16 +++++++++++++--- htdocs/expedition/dispatch.php | 17 +++++++++++------ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/htdocs/core/lib/product.lib.php b/htdocs/core/lib/product.lib.php index fc1442d659642..8528b55695d0d 100644 --- a/htdocs/core/lib/product.lib.php +++ b/htdocs/core/lib/product.lib.php @@ -129,7 +129,7 @@ function product_prepare_head($object) $h++; } - if (($object->isProduct() || ($object->isService() && && getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) && $object->stockable_product == Product::ENABLED_STOCK) { // If physical product we can stock (or service with option) + if (($object->isProduct() || ($object->isService() && getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) && $object->stockable_product == Product::ENABLED_STOCK) { // If physical product we can stock (or service with option) if (isModEnabled('stock') && $user->hasRight('stock', 'lire')) { $head[$h][0] = DOL_URL_ROOT."/product/stock/product.php?id=".$object->id; $head[$h][1] = $langs->trans("Stock"); diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 2d155d7a950fb..045e9ba19eed6 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -1595,7 +1595,9 @@ public function fetch_lines() $sql .= ", cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc, cd.rang"; $sql .= ", ed.rowid as line_id, ed.qty as qty_shipped, ed.fk_origin_line, ed.fk_entrepot"; $sql .= ", p.ref as product_ref, p.label as product_label, p.fk_product_type, p.barcode as product_barcode"; - $sql .= ", p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch"; + $sql .= ", p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units"; + $sql .= ", p.surface, p.surface_units, p.volume, p.volume_units, p.tosell as product_tosell, p.tobuy as product_tobuy"; + $sql .= ", p.tobatch as product_tobatch, p.stockable_product"; $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed, ".MAIN_DB_PREFIX."commandedet as cd"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = cd.fk_product"; $sql .= " WHERE ed.fk_expedition = ".((int) $this->id); @@ -1679,8 +1681,9 @@ public function fetch_lines() $line->surface = $obj->surface; $line->surface_units = $obj->surface_units; $line->volume = $obj->volume; - $line->volume_units = $obj->volume_units; - $line->fk_unit = $obj->fk_unit; + $line->volume_units = $obj->volume_units; + $line->stockable_product = $obj->stockable_product; + $line->fk_unit = $obj->fk_unit; $line->pa_ht = $obj->pa_ht; @@ -2760,6 +2763,13 @@ class ExpeditionLigne extends CommonObjectLine public $volume; public $volume_units; + /** + * 0=This service or product is not managed in stock, 1=This service or product is managed in stock + * + * @var boolean + */ + public $stockable_product = 1; + // Invoicing public $remise_percent; public $tva_tx; diff --git a/htdocs/expedition/dispatch.php b/htdocs/expedition/dispatch.php index 72c74a3f35737..a7e13ba81ae09 100644 --- a/htdocs/expedition/dispatch.php +++ b/htdocs/expedition/dispatch.php @@ -905,13 +905,18 @@ // Warehouse print ''; - if (count($listwarehouses) > 1) { - print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix); - } elseif (count($listwarehouses) == 1) { - print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix); + if ($objp->stockable_product == Product::ENABLED_STOCK){ + if (count($listwarehouses) > 1) { + print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix); + } elseif (count($listwarehouses) == 1) { + print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix); + } else { + $langs->load("errors"); + print $langs->trans("ErrorNoWarehouseDefined"); + } } else { - $langs->load("errors"); - print $langs->trans("ErrorNoWarehouseDefined"); + print ''; + print img_warning().' '.$langs->trans('StockDisabled') ; } print "\n"; From 23623236eac0361576b585a3b3aefcc361474fea Mon Sep 17 00:00:00 2001 From: mrozniecki Date: Thu, 15 Feb 2024 16:34:09 +0100 Subject: [PATCH 07/20] phpcs --- htdocs/expedition/card.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index c947cd3a38539..65170732c6699 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -345,15 +345,15 @@ } else { $p = new Product($db); $res = $p->fetch($objectsrc->lines[$i]->fk_product); - if($res > 0) { - if(GETPOST('entrepot_id', 'int') == -1) { + if ($res > 0) { + if (GETPOST('entrepot_id', 'int') == -1) { $qty .= '_'.$j; } - if($p->stockable_product == Product::DISABLED_STOCK) { + if ($p->stockable_product == Product::DISABLED_STOCK) { $w = new Entrepot($db); $Tw = $w->list_array(); - if(count($Tw) > 0) { + if (count($Tw) > 0) { $w_Id = array_keys($Tw); $stockLine[$i][$j]['qty'] = GETPOST($qty, 'int'); @@ -362,8 +362,7 @@ // $stockLine[$i][$j]['warehouse_id'] = $w_Id[0]; $stockLine[$i][$j]['ix_l'] = GETPOST($idl, 'int'); - } - else { + } else { setEventMessage($langs->trans('NoWarehouseInBase')); } } From 4944282851c320544697e26fb5d652a0a8c325b0 Mon Sep 17 00:00:00 2001 From: mrozniecki Date: Thu, 15 Feb 2024 16:48:36 +0100 Subject: [PATCH 08/20] Fix missing column from select inside sql request --- htdocs/expedition/dispatch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expedition/dispatch.php b/htdocs/expedition/dispatch.php index a7e13ba81ae09..46c81fcefd457 100644 --- a/htdocs/expedition/dispatch.php +++ b/htdocs/expedition/dispatch.php @@ -572,7 +572,7 @@ //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,"; $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, '' AS sref, l.qty as qty,"; - $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse, p.barcode"; + $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse, p.barcode, p.stockable_product"; // Enable hooks to alter the SQL query (SELECT) $parameters = array(); $reshook = $hookmanager->executeHooks( From 1a6ad59bbf457bdfced909e02222a40bb07be933 Mon Sep 17 00:00:00 2001 From: mrozniecki Date: Thu, 15 Feb 2024 16:59:49 +0100 Subject: [PATCH 09/20] Fix input hidden missing name --- htdocs/expedition/dispatch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expedition/dispatch.php b/htdocs/expedition/dispatch.php index 46c81fcefd457..7322f097d5881 100644 --- a/htdocs/expedition/dispatch.php +++ b/htdocs/expedition/dispatch.php @@ -915,7 +915,7 @@ print $langs->trans("ErrorNoWarehouseDefined"); } } else { - print ''; + print ''; print img_warning().' '.$langs->trans('StockDisabled') ; } print "\n"; From ab529910f576ef55b3dda131271907a3ec53db18 Mon Sep 17 00:00:00 2001 From: mrozniecki Date: Fri, 16 Feb 2024 09:34:53 +0100 Subject: [PATCH 10/20] ajout d'un commentaire --- htdocs/expedition/dispatch.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/expedition/dispatch.php b/htdocs/expedition/dispatch.php index 7322f097d5881..c7af718a3631a 100644 --- a/htdocs/expedition/dispatch.php +++ b/htdocs/expedition/dispatch.php @@ -915,6 +915,7 @@ print $langs->trans("ErrorNoWarehouseDefined"); } } else { + // on force l'entrepot pour passer le test d'ajout de ligne dans expedition.class.php print ''; print img_warning().' '.$langs->trans('StockDisabled') ; } From cb731c189bc2ebda127b30f01f73ecbe034411a8 Mon Sep 17 00:00:00 2001 From: Ulysse Valdenaire Date: Wed, 13 Mar 2024 15:42:31 +0100 Subject: [PATCH 11/20] small fixes --- htdocs/expedition/card.php | 2 +- htdocs/expedition/class/expedition.class.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 4432939775f0a..6c64771d48fdb 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -2540,7 +2540,7 @@ print ''; if ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) { print '('.$langs->trans("Service").')'; - } elseif ($lines[$i]->entrepot_id > 0 && $lines[$i]->product->stockable_product == Product::ENABLED_STOCK) { + } elseif ($lines[$i]->entrepot_id > 0 && $lines[$i]->stockable_product == Product::ENABLED_STOCK) { $entrepot = new Entrepot($db); $entrepot->fetch($lines[$i]->entrepot_id); print $entrepot->getNomUrl(1); diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 80aabd31e92a1..03ff454f790ef 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -1662,6 +1662,7 @@ public function fetch_lines() $line->fk_expedition = $this->id; // id of parent + $line->stockable_product = $obj->stockable_product; $line->product_type = $obj->product_type; $line->fk_product = $obj->fk_product; $line->fk_product_type = $obj->fk_product_type; From ec71157e8bc19586d7578de13c56c7f6fc99f8db Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 16 Apr 2024 14:17:03 +0200 Subject: [PATCH 12/20] remove unrelated lines --- htdocs/product/class/product.class.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 38dab926cd1ba..74864cdea66ad 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -627,14 +627,6 @@ class Product extends CommonObject * Service */ const TYPE_SERVICE = 1; - /** - * Advanced feature: assembly kit - */ - const TYPE_ASSEMBLYKIT = 2; - /** - * Advanced feature: stock kit - */ - const TYPE_STOCKKIT = 3; /** * Stockable product From b1e6de6bb215a8007708b0d9f3c647f2badf043c Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 16 Apr 2024 14:24:48 +0200 Subject: [PATCH 13/20] stickler fix --- htdocs/product/class/product.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 74864cdea66ad..96ab761b3bae9 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -562,7 +562,7 @@ class Product extends CommonObject * * @var boolean */ - public $stockable_product = 1; + public $stockable_product = true; /** * 'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password') @@ -737,7 +737,7 @@ public function create($user, $notrigger = 0) $this->status_buy = 0; } if (empty($this->stockable_product)) { - $this->stockable_product = 0; + $this->stockable_product = false; } $price_ht = 0; @@ -1175,7 +1175,7 @@ public function update($id, $user, $notrigger = 0, $action = 'update', $updatety } if (empty($this->stockable_product)) { - $this->stockable_product = 0; + $this->stockable_product = false; } // Barcode value From 014b504c99e4ccc2b6240a8673f4caaf94c5e78c Mon Sep 17 00:00:00 2001 From: tnegre Date: Fri, 19 Apr 2024 13:37:37 +0200 Subject: [PATCH 14/20] pre-commit fixes --- htdocs/expedition/card.php | 15 ++++++++------- htdocs/product/card.php | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 6c64771d48fdb..bd4fed4883763 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -1259,7 +1259,7 @@ $text = $product_static->getNomUrl(1); $text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label); $description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc)); - $description .= empty($product->stockable_product) ? $langs->trans('StockDisabled') : $langs->trans('StockEnabled') ; + $description .= empty($product->stockable_product) ? $langs->trans('StockDisabled') : $langs->trans('StockEnabled'); print $form->textwithtooltip($text, $description, 3, '', '', $i); // Show range @@ -1369,10 +1369,10 @@ if (!getDolGlobalInt('STOCK_ALLOW_NEGATIVE_TRANSFER')) { $stockMin = 0; } - if ($product->stockable_product == Product::ENABLED_STOCK){ + if ($product->stockable_product == Product::ENABLED_STOCK) { print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'minwidth200', '', 1, $stockMin, 'stock DESC, e.ref'); } else { - print img_warning().' '.$langs->trans('StockDisabled') ; + print img_warning().' '.$langs->trans('StockDisabled'); } if ($tmpentrepot_id > 0 && $tmpentrepot_id == $warehouse_id) { //print $stock.' '.$quantityToBeDelivered; @@ -1571,12 +1571,12 @@ if (isModEnabled('stock')) { print ''; if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) { - if ($product->stockable_product == Product::ENABLED_STOCK){ + if ($product->stockable_product == Product::ENABLED_STOCK) { print $tmpwarehouseObject->getNomUrl(0).' '; print ''; print '('.$stock.')'; } else { - print img_warning().' '.$langs->trans('StockDisabled') ; + print img_warning().' '.$langs->trans('StockDisabled'); } } else { print '('.$langs->trans("Service").')'; @@ -1738,7 +1738,7 @@ $disabled = 'disabled="disabled"'; } // finally we overwrite the input with the product status stockable_product if it's disabled - if ($product->stockable_product == Product::DISABLED_STOCK){ + if ($product->stockable_product == Product::DISABLED_STOCK) { $disabled = ''; } print ' '; @@ -1762,7 +1762,8 @@ print img_warning().' '.$langs->trans('StockTooLow'); } else { print img_warning().' '.$langs->trans('StockDisabled'); - } } else { + } + } else { print ''; } } diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 5663d8186fe57..e6dfb69245cc8 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -812,7 +812,7 @@ } else { $object->fk_default_bom = 0; } - + // managed_in_stock $object->stockable_product = GETPOSTISSET('stockable_product'); @@ -2193,7 +2193,7 @@ print ''; print ''; - + if (!empty($conf->stock->enabled) && !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { print '' . $langs->trans("StockableProduct") . ''; $checked = $object->stockable_product == 1 ? "checked" : ""; @@ -2679,7 +2679,7 @@ print ''.$langs->trans("DefaultWorkstation").''; print(!empty($workstation->id) ? $workstation->getNomUrl(1) : ''); print ''; - } + } // View stockable_product if (($object->isProduct() || ($object->isService() && !empty($conf->global->STOCK_SUPPORTS_SERVICES))) && !empty($conf->stock->enabled)) { From 7ed6877a2076a09a8edca953cb1c608f1e3e3a3e Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 14 May 2024 13:49:00 +0200 Subject: [PATCH 15/20] pre-commit fixes --- htdocs/expedition/card.php | 2 +- htdocs/expedition/dispatch.php | 60 +++++++++++++++++----------------- htdocs/product/card.php | 6 ++-- htdocs/product/list.php | 12 +++---- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index bd4fed4883763..85b095a9a222d 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -1758,7 +1758,7 @@ print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->label); } else { if ($line->fk_product) { - if($product->stockable_product == Product::ENABLED_STOCK) { + if ($product->stockable_product == Product::ENABLED_STOCK) { print img_warning().' '.$langs->trans('StockTooLow'); } else { print img_warning().' '.$langs->trans('StockDisabled'); diff --git a/htdocs/expedition/dispatch.php b/htdocs/expedition/dispatch.php index 63565b6443656..c8cb5047a4755 100644 --- a/htdocs/expedition/dispatch.php +++ b/htdocs/expedition/dispatch.php @@ -901,7 +901,7 @@ // Warehouse print ''; - if ($objp->stockable_product == Product::ENABLED_STOCK){ + if ($objp->stockable_product == Product::ENABLED_STOCK) { if (count($listwarehouses) > 1) { print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix); } elseif (count($listwarehouses) == 1) { @@ -913,7 +913,7 @@ } else { // on force l'entrepot pour passer le test d'ajout de ligne dans expedition.class.php print ''; - print img_warning().' '.$langs->trans('StockDisabled') ; + print img_warning().' '.$langs->trans('StockDisabled'); } print "\n"; @@ -1166,7 +1166,7 @@ var errortab3 = []; var errortab4 = []; - function barcodescannerjs(){ + function barcodescannerjs() { console.log("We catch inputs in scanner box"); jQuery("#scantoolmessage").text(); @@ -1183,11 +1183,11 @@ function barcodescannerjs(){ errortab3 = []; errortab4 = []; - textarray = textarray.filter(function(value){ + textarray = textarray.filter(function(value) { return value != ""; }); - if(textarray.some((element) => element != "")){ - $(".qtydispatchinput").each(function(){ + if (textarray.some((element) => element != "")) { + $(".qtydispatchinput").each(function() { id = $(this).attr(\'id\'); idarray = id.split(\'_\'); idproduct = idarray[2]; @@ -1198,7 +1198,7 @@ function barcodescannerjs(){ productbarcode = $("#product_"+idproduct).attr(\'data-barcode\'); console.log(productbarcode); productbatchcode = $("#lot_number_"+id).val(); - if(productbatchcode == undefined){ + if (productbatchcode == undefined) { productbatchcode = ""; } console.log(productbatchcode); @@ -1206,25 +1206,25 @@ function barcodescannerjs(){ if (barcodemode != "barcodeforproduct") { tabproduct.forEach(product=>{ console.log("product.Batch="+product.Batch+" productbatchcode="+productbatchcode); - if(product.Batch != "" && product.Batch == productbatchcode){ + if (product.Batch != "" && product.Batch == productbatchcode) { console.log("duplicate batch code found for batch code "+productbatchcode); duplicatedbatchcode.push(productbatchcode); } }) } productinput = $("#qty_"+id).val(); - if(productinput == ""){ + if (productinput == "") { productinput = 0 } tabproduct.push({\'Id\':id,\'Warehouse\':warehouse,\'Barcode\':productbarcode,\'Batch\':productbatchcode,\'Qty\':productinput,\'fetched\':false}); }); console.log("Loop on each record entered in the textarea"); - textarray.forEach(function(element,index){ + textarray.forEach(function(element,index) { console.log("Process record element="+element+" id="+id); var verify_batch = false; var verify_barcode = false; - switch(barcodemode){ + switch(barcodemode) { case "barcodeforautodetect": verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode",true); verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial",true); @@ -1255,12 +1255,12 @@ function barcodescannerjs(){ if (Object.keys(errortab1).length < 1 && Object.keys(errortab2).length < 1 && Object.keys(errortab3).length < 1) { tabproduct.forEach(product => { - if(product.Qty!=0){ - if(product.hasOwnProperty("reelqty")){ + if (product.Qty!=0) { + if (product.hasOwnProperty("reelqty")) { idprod = $("td[data-idproduct=\'"+product.fk_product+"\']").attr("id"); idproduct = idprod.split("_")[1]; console.log("We create a new line for product_"+idproduct); - if(product.Barcode != null){ + if (product.Barcode != null) { modedispatch = "dispatch"; } else { modedispatch = "batch"; @@ -1272,7 +1272,7 @@ function barcodescannerjs(){ $("#qty_"+(nbrTrs-1)+"_"+idproduct).val(product.Qty); $("#entrepot_"+(nbrTrs-1)+"_"+idproduct).val(product.Warehouse); - if(modedispatch == "batch"){ + if (modedispatch == "batch") { $("#lot_number_"+(nbrTrs-1)+"_"+idproduct).val(product.Batch); } @@ -1323,7 +1323,7 @@ function barcodescannerjs(){ } /* This methode is called by parent barcodescannerjs() */ - function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=false){ + function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=false) { BarcodeIsInProduct=0; newproductrow=0 result=false; @@ -1333,13 +1333,13 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,ware type: \'POST\', async: false, success: function(response) { - if (response.status == "success"){ + if (response.status == "success") { console.log(response.message); - if(!newproductrow){ + if (!newproductrow) { newproductrow = response.object; } }else{ - if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)){ + if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)) { errortab4.push(element); console.error(response.message); } @@ -1350,18 +1350,18 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,ware }, }); console.log("Product "+(index+=1)+": "+element); - if(mode == "barcode"){ + if (mode == "barcode") { testonproduct = product.Barcode - }else if (mode == "lotserial"){ + }else if (mode == "lotserial") { testonproduct = product.Batch } testonwarehouse = product.Warehouse; - if(testonproduct == element && testonwarehouse == warehousetouse){ - if(selectaddorreplace == "add"){ + if (testonproduct == element && testonwarehouse == warehousetouse) { + if (selectaddorreplace == "add") { productqty = parseInt(product.Qty,10); product.Qty = productqty + parseInt(barcodeproductqty,10); - }else if(selectaddorreplace == "replace"){ - if(product.fetched == false){ + }else if (selectaddorreplace == "replace") { + if (product.fetched == false) { product.Qty = barcodeproductqty product.fetched=true }else{ @@ -1372,11 +1372,11 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,ware BarcodeIsInProduct+=1; } }) - if(BarcodeIsInProduct==0 && newproductrow!=0){ + if (BarcodeIsInProduct==0 && newproductrow!=0) { tabproduct.push({\'Id\':tabproduct.length-1,\'Warehouse\':newproductrow.fk_warehouse,\'Barcode\':mode=="barcode"?element:null,\'Batch\':mode=="lotserial"?element:null,\'Qty\':barcodeproductqty,\'fetched\':true,\'reelqty\':newproductrow.reelqty,\'fk_product\':newproductrow.fk_product,\'mode\':mode}); result = true; } - if(BarcodeIsInProduct > 0){ + if (BarcodeIsInProduct > 0) { result = true; } return result; @@ -1400,7 +1400,7 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,ware $("#autoreset").click(function() { console.log("we click on autoreset"); - $(".autoresettr").each(function(){ + $(".autoresettr").each(function() { id = $(this).attr("name"); idtab = id.split("_"); console.log("we process line "+id+" "+idtab); @@ -1423,8 +1423,8 @@ function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,ware return false; }); - $("#resetalltoexpected").click(function(){ - $(".qtydispatchinput").each(function(){ + $("#resetalltoexpected").click(function() { + $(".qtydispatchinput").each(function() { console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch"); $(this).val($(this).data("expected")); }); diff --git a/htdocs/product/card.php b/htdocs/product/card.php index e6dfb69245cc8..b7d9c8ff06c9f 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -812,7 +812,7 @@ } else { $object->fk_default_bom = 0; } - + // managed_in_stock $object->stockable_product = GETPOSTISSET('stockable_product'); @@ -1989,7 +1989,7 @@ $(document).ready(function() { console.log($("#statusBatchWarning")) $("#status_batch").on("change", function() { - if ($("#status_batch")[0].value == 0){ + if ($("#status_batch")[0].value == 0) { $("#statusBatchMouvToGlobal").show() } else { $("#statusBatchMouvToGlobal").hide() @@ -2003,7 +2003,7 @@ $(document).ready(function() { console.log($("#statusBatchWarning")) $("#status_batch").on("change", function() { - if ($("#status_batch")[0].value == 2){ + if ($("#status_batch")[0].value == 2) { $("#statusBatchWarning").show() } else { $("#statusBatchWarning").hide() diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 2a5ea70139670..7f0c558f7bb64 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -277,10 +277,10 @@ 'p.import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'notnull' => -1, 'index' => 0, 'checked' => -1, 'position' => 1100), ); -if(! empty($conf->stock->enabled)) { +if (! empty($conf->stock->enabled)) { // service - if($type == 1) { - if(! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { + if ($type == 1) { + if (! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { $arrayfields['p.stockable_product'] = array('label' => $langs->trans('StockableProduct'), 'checked' => 0, 'position' => 1001); } } @@ -845,7 +845,7 @@ if ($search_finished) { $param .= "&search_finished=".urlencode($search_finished); } -if($search_stockable_product != '') { +if ($search_stockable_product != '') { $param .= "&search_stockable_product=".urlencode($search_stockable_product); } // Add $param from extra fields @@ -1188,7 +1188,7 @@ } // Managed_in_stock $array = array('-1'=>' ', '0'=>$langs->trans('No'), '1'=>$langs->trans('Yes')); -if (!empty($arrayfields['p.stockable_product']['checked'])){ +if (!empty($arrayfields['p.stockable_product']['checked'])) { print ''.Form::selectarray('search_stockable_product', $array, $search_stockable_product).''; } // Desired stock @@ -2091,7 +2091,7 @@ } // not managed in stock - if(! empty($arrayfields['p.stockable_product']['checked'])) { + if (! empty($arrayfields['p.stockable_product']['checked'])) { print ''; print ($product_static->stockable_product == '1') ? $langs->trans('Yes') : $langs->trans('No'); print ''; From c34c7e90ca8d1bef4056c80b99e7c32d6b4dc0ea Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 14 May 2024 14:08:44 +0200 Subject: [PATCH 16/20] pre-commit fix --- htdocs/product/list.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 7f0c558f7bb64..549d6b933df6f 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -283,8 +283,7 @@ if (! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { $arrayfields['p.stockable_product'] = array('label' => $langs->trans('StockableProduct'), 'checked' => 0, 'position' => 1001); } - } - else { + } else { //product $arrayfields['p.stockable_product'] = array('label' => $langs->trans('StockableProduct'), 'checked' => 0, 'position' => 1001); } From ede7e03c7c580bef92dbf720c0b0e3be8bff8c89 Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 14 May 2024 14:11:58 +0200 Subject: [PATCH 17/20] phan fix --- 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 03ff454f790ef..9012cfb4cc328 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -2780,7 +2780,7 @@ class ExpeditionLigne extends CommonObjectLine * * @var boolean */ - public $stockable_product = 1; + public $stockable_product = true; // Invoicing public $remise_percent; From 810d4a3f489044d1b721b9240fee3c94f337d147 Mon Sep 17 00:00:00 2001 From: tnegre Date: Tue, 28 May 2024 17:07:00 +0200 Subject: [PATCH 18/20] fix missing translation --- htdocs/langs/en_US/sendings.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/langs/en_US/sendings.lang b/htdocs/langs/en_US/sendings.lang index 71d4214c8a5fc..f47172723a6dd 100644 --- a/htdocs/langs/en_US/sendings.lang +++ b/htdocs/langs/en_US/sendings.lang @@ -66,6 +66,7 @@ NoLineGoOnTabToAddSome=No line, go on tab "%s" to add CreateInvoiceForThisCustomerFromSendings=Bill sendings IfValidateInvoiceIsNoSendingStayUnbilled=If invoice validation is 'No', the sending will remain to status 'Unbilled' until the invoice is validated. OptionToSetSendingBilledNotEnabled=Option from module Workflow, to set sending to 'Billed' automatically when invoice is validated, is not enabled, so you will have to set the status of sendings to 'Billed' manually after the invoice has been generated. +NoWarehouseInBase=No warehouse in base # Sending methods # ModelDocument From dd45b3857ece7a81afe2d364b286b712daa224b4 Mon Sep 17 00:00:00 2001 From: tnegre Date: Mon, 10 Jun 2024 14:36:43 +0200 Subject: [PATCH 19/20] Fix phpstan --- htdocs/product/stock/class/mouvementstock.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index d8a5a3ced83b7..5ab474c885535 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -456,7 +456,7 @@ public function _create($user, $fk_product, $entrepot_id, $qty, $type, $price = } } - if ($movestock && $product->stockable_product == PRODUCT::ENABLED_STOCK) { // Change stock for current product, change for subproduct is done after + if ($movestock && $product->stockable_product == Product::ENABLED_STOCK) { // Change stock for current product, change for subproduct is done after // Set $origin_type, origin_id and fk_project $fk_project = $this->fk_project; if (!empty($this->origin_type)) { // This is set by caller for tracking reason From 28517af01698d6ade69c0c6b21f5539e04711f98 Mon Sep 17 00:00:00 2001 From: tnegre Date: Mon, 10 Jun 2024 15:18:16 +0200 Subject: [PATCH 20/20] fix winCI --- htdocs/product/list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 83de05dc4b5f8..f52b74b78962d 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -579,7 +579,7 @@ $sql .= " AND p.tobuy = ".((int) $search_tobuy); } if (isset($search_stockable_product) && dol_strlen($search_stockable_product) > 0 && $search_stockable_product != -1) { - $sql .= " AND p.stockable_product = '". $search_stockable_product . "'"; + $sql .= " AND p.stockable_product = '". ((int) $search_stockable_product) . "'"; } if (isset($search_tobatch) && dol_strlen($search_tobatch) > 0 && $search_tobatch != -1) { $sql .= " AND p.tobatch = ".((int) $search_tobatch);