From de847250b11287ca812ffe30702468a7bd97af7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20David?= Date: Thu, 1 Jul 2021 17:55:54 +0200 Subject: [PATCH 01/39] NEW #18046 Add ticket categories data model --- .../mysql/tables/llx_categorie_ticket.key.sql | 21 +++++++++++++++++++ .../mysql/tables/llx_categorie_ticket.sql | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 htdocs/install/mysql/tables/llx_categorie_ticket.key.sql create mode 100644 htdocs/install/mysql/tables/llx_categorie_ticket.sql diff --git a/htdocs/install/mysql/tables/llx_categorie_ticket.key.sql b/htdocs/install/mysql/tables/llx_categorie_ticket.key.sql new file mode 100644 index 00000000000..012b9a9eadc --- /dev/null +++ b/htdocs/install/mysql/tables/llx_categorie_ticket.key.sql @@ -0,0 +1,21 @@ +-- Copyright (C) 2021 EOXIA +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see https://www.gnu.org/licenses/. + +ALTER TABLE llx_categorie_ticket ADD PRIMARY KEY pk_categorie_ticket (fk_categorie, fk_ticket); +ALTER TABLE llx_categorie_ticket ADD INDEX idx_categorie_ticket_fk_categorie (fk_categorie); +ALTER TABLE llx_categorie_ticket ADD INDEX idx_categorie_ticket_fk_ticket (fk_ticket); + +ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid); +ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_ticket_rowid FOREIGN KEY (fk_ticket) REFERENCES llx_ticket (rowid); diff --git a/htdocs/install/mysql/tables/llx_categorie_ticket.sql b/htdocs/install/mysql/tables/llx_categorie_ticket.sql new file mode 100644 index 00000000000..16ab92522c6 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_categorie_ticket.sql @@ -0,0 +1,21 @@ +-- Copyright (C) 2021 EOXIA +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see https://www.gnu.org/licenses/. + +create table llx_categorie_ticket +( + fk_categorie integer NOT NULL, + fk_ticket integer NOT NULL, + import_key varchar(14) +)ENGINE=innodb; From ec6fadf196a73ac8b5313a97a81437e3e71781f1 Mon Sep 17 00:00:00 2001 From: kamel Date: Fri, 9 Jul 2021 15:29:39 +0200 Subject: [PATCH 02/39] Fix hook constructCategory when several new categories is added by several modules --- htdocs/categories/class/categorie.class.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index b98cff5b3a5..3144f1f98c3 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -263,15 +263,16 @@ class Categorie extends CommonObject $parameters = array(); $reshook = $hookmanager->executeHooks('constructCategory', $parameters, $this); // Note that $action and $object may have been modified by some hooks if ($reshook >= 0 && !empty($hookmanager->resArray)) { - $mapList = $hookmanager->resArray; - $mapId = $mapList['id']; - $mapCode = $mapList['code']; - self::$MAP_ID_TO_CODE[$mapId] = $mapCode; - $this->MAP_ID[$mapCode] = $mapId; - $this->MAP_CAT_FK[$mapCode] = $mapList['cat_fk']; - $this->MAP_CAT_TABLE[$mapCode] = $mapList['cat_table']; - $this->MAP_OBJ_CLASS[$mapCode] = $mapList['obj_class']; - $this->MAP_OBJ_TABLE[$mapCode] = $mapList['obj_table']; + foreach ($hookmanager->resArray as $mapList) { + $mapId = $mapList['id']; + $mapCode = $mapList['code']; + self::$MAP_ID_TO_CODE[$mapId] = $mapCode; + $this->MAP_ID[$mapCode] = $mapId; + $this->MAP_CAT_FK[$mapCode] = $mapList['cat_fk']; + $this->MAP_CAT_TABLE[$mapCode] = $mapList['cat_table']; + $this->MAP_OBJ_CLASS[$mapCode] = $mapList['obj_class']; + $this->MAP_OBJ_TABLE[$mapCode] = $mapList['obj_table']; + } } } } From 073ace3a9e48c60d90b25717819d4b1ac3636a41 Mon Sep 17 00:00:00 2001 From: kamel Date: Fri, 9 Jul 2021 16:23:46 +0200 Subject: [PATCH 03/39] FIX get categories linked to another object type --- htdocs/categories/class/categorie.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index b98cff5b3a5..5bcfa903f75 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -1497,7 +1497,7 @@ class Categorie extends CommonObject } else { $sql = "SELECT ct.fk_categorie, c.label, c.rowid"; $sql .= " FROM ".MAIN_DB_PREFIX."categorie_".(empty($this->MAP_CAT_TABLE[$type]) ? $type : $this->MAP_CAT_TABLE[$type])." as ct, ".MAIN_DB_PREFIX."categorie as c"; - $sql .= " WHERE ct.fk_categorie = c.rowid AND ct.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".(int) $id." AND c.type = ".$this->MAP_ID[$type]; + $sql .= " WHERE ct.fk_categorie = c.rowid AND ct.fk_".(empty($this->MAP_CAT_FK[$type]) ? $type : $this->MAP_CAT_FK[$type])." = ".(int) $id; $sql .= " AND c.entity IN (".getEntity('category').")"; $res = $this->db->query($sql); From 97ac547fe230d4773f295ff9d68c91f272c11e86 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 11 Jul 2021 00:44:36 +0200 Subject: [PATCH 04/39] Fix/debug the numbering module to autocalculate a new lot. --- htdocs/core/modules/modProductBatch.class.php | 4 +- .../product_batch/mod_lot_advanced.php | 10 +- .../product_batch/mod_lot_standard.php | 27 +- .../modules/product_batch/mod_sn_advanced.php | 6 +- .../modules/product_batch/mod_sn_standard.php | 31 +- htdocs/langs/en_US/productbatch.lang | 8 +- htdocs/product/admin/product_lot.php | 287 +++++++++--------- .../product/stock/class/productlot.class.php | 2 +- 8 files changed, 198 insertions(+), 177 deletions(-) diff --git a/htdocs/core/modules/modProductBatch.class.php b/htdocs/core/modules/modProductBatch.class.php index 79529898bb0..4b508d79d7c 100644 --- a/htdocs/core/modules/modProductBatch.class.php +++ b/htdocs/core/modules/modProductBatch.class.php @@ -84,14 +84,14 @@ class modProductBatch extends DolibarrModules $this->const[$r][0] = "PRODUCTBATCH_LOT_ADDON"; $this->const[$r][1] = "chaine"; $this->const[$r][2] = "mod_lot_free"; - $this->const[$r][3] = 'Module to control product codes'; + $this->const[$r][3] = 'Module to control lot number'; $this->const[$r][4] = 0; $r++; $this->const[$r][0] = "PRODUCTBATCH_SN_ADDON"; $this->const[$r][1] = "chaine"; $this->const[$r][2] = "mod_sn_free"; - $this->const[$r][3] = 'Module to control product codes'; + $this->const[$r][3] = 'Module to control serial number'; $this->const[$r][4] = 0; $r++; diff --git a/htdocs/core/modules/product_batch/mod_lot_advanced.php b/htdocs/core/modules/product_batch/mod_lot_advanced.php index 0bbb124d14b..8ee857bfbea 100644 --- a/htdocs/core/modules/product_batch/mod_lot_advanced.php +++ b/htdocs/core/modules/product_batch/mod_lot_advanced.php @@ -128,27 +128,27 @@ class mod_lot_advanced extends ModeleNumRefBatch /** * Return next free value * - * @param Product $objprod Object product + * @param Societe $objsoc Object Societe * @param Object $object Object we need next value for * @return string Value if KO, <0 if KO */ - public function getNextValue($objprod, $object) + public function getNextValue($objsoc, $object) { global $db, $conf; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; // We get cursor rule - $mask = $conf->global->BATCH_ADVANCED_MASK; + $mask = $conf->global->LOT_ADVANCED_MASK; if (!$mask) { $this->error = 'NotConfigured'; return 0; } - $date = $object->date; + $date = dol_now(); - $numFinal = get_next_value($db, $mask, 'product_lot', 'ref', '', null, $date); + $numFinal = get_next_value($db, $mask, 'product_lot', 'batch', '', null, $date); return $numFinal; } diff --git a/htdocs/core/modules/product_batch/mod_lot_standard.php b/htdocs/core/modules/product_batch/mod_lot_standard.php index 0d2b5a55139..59de1965a6e 100644 --- a/htdocs/core/modules/product_batch/mod_lot_standard.php +++ b/htdocs/core/modules/product_batch/mod_lot_standard.php @@ -85,17 +85,21 @@ class mod_lot_standard extends ModeleNumRefBatch $coyymm = ''; $max = ''; $posindice = strlen($this->prefix) + 6; - $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql = "SELECT MAX(CAST(SUBSTRING(batch FROM ".$posindice.") AS SIGNED)) as max"; $sql .= " FROM ".MAIN_DB_PREFIX."product_lot"; - $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + $sql .= " WHERE batch LIKE '".$db->escape($this->prefix)."____-%'"; $sql .= " AND entity = ".$conf->entity; $resql = $db->query($sql); if ($resql) { - $row = $db->fetch_row($resql); - if ($row) { $coyymm = substr($row[0], 0, 6); $max = $row[0]; } + $obj = $db->fetch_object($resql); + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } } - if ($coyymm && !preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i', $coyymm)) { + if ($max && !preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i', $max)) { $langs->load("errors"); $this->error = $langs->trans('ErrorNumRefModel', $max); return false; @@ -117,23 +121,26 @@ class mod_lot_standard extends ModeleNumRefBatch // First, we get the max value $posindice = strlen($this->prefix) + 6; - $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql = "SELECT MAX(CAST(SUBSTRING(batch FROM ".$posindice.") AS SIGNED)) as max"; $sql .= " FROM ".MAIN_DB_PREFIX."product_lot"; - $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + $sql .= " WHERE batch LIKE '".$db->escape($this->prefix)."____-%'"; $sql .= " AND entity = ".$conf->entity; $resql = $db->query($sql); if ($resql) { $obj = $db->fetch_object($resql); - if ($obj) $max = intval($obj->max); - else $max = 0; + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } } else { dol_syslog("mod_lot_standard::getNextValue", LOG_DEBUG); return -1; } //$date=time(); - $date = $object->date_creation; + $date = dol_now(); $yymm = strftime("%y%m", $date); if ($max >= (pow(10, 4) - 1)) $num = $max + 1; // If counter > 9999, we do not format on 4 chars, we take number as it is diff --git a/htdocs/core/modules/product_batch/mod_sn_advanced.php b/htdocs/core/modules/product_batch/mod_sn_advanced.php index 8117b9e6c6e..54c67291d9a 100644 --- a/htdocs/core/modules/product_batch/mod_sn_advanced.php +++ b/htdocs/core/modules/product_batch/mod_sn_advanced.php @@ -139,16 +139,16 @@ class mod_sn_advanced extends ModeleNumRefBatch require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; // We get cursor rule - $mask = $conf->global->BATCH_ADVANCED_MASK; + $mask = $conf->global->SN_ADVANCED_MASK; if (!$mask) { $this->error = 'NotConfigured'; return 0; } - $date = $object->date; + $date = dol_now(); - $numFinal = get_next_value($db, $mask, 'product_sn', 'ref', '', null, $date); + $numFinal = get_next_value($db, $mask, 'product_lot', 'batch', '', null, $date); return $numFinal; } diff --git a/htdocs/core/modules/product_batch/mod_sn_standard.php b/htdocs/core/modules/product_batch/mod_sn_standard.php index bef5efcd9f8..845044c39f3 100644 --- a/htdocs/core/modules/product_batch/mod_sn_standard.php +++ b/htdocs/core/modules/product_batch/mod_sn_standard.php @@ -85,17 +85,21 @@ class mod_sn_standard extends ModeleNumRefBatch $coyymm = ''; $max = ''; $posindice = strlen($this->prefix) + 6; - $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql = "SELECT MAX(CAST(SUBSTRING(batch FROM ".$posindice.") AS SIGNED)) as max"; $sql .= " FROM ".MAIN_DB_PREFIX."product_lot"; - $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + $sql .= " WHERE batch LIKE '".$db->escape($this->prefix)."____-%'"; $sql .= " AND entity = ".$conf->entity; $resql = $db->query($sql); if ($resql) { - $row = $db->fetch_row($resql); - if ($row) { $coyymm = substr($row[0], 0, 6); $max = $row[0]; } + $obj = $db->fetch_object($resql); + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } } - if ($coyymm && !preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i', $coyymm)) { + if ($max && !preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i', $max)) { $langs->load("errors"); $this->error = $langs->trans('ErrorNumRefModel', $max); return false; @@ -107,33 +111,36 @@ class mod_sn_standard extends ModeleNumRefBatch /** * Return next free value * - * @param Product $objprod Object product + * @param Societe $objsoc Object product * @param Object $object Object we need next value for * @return string Value if KO, <0 if KO */ - public function getNextValue($objprod, $object) + public function getNextValue($objsoc, $object) { global $db, $conf; // First, we get the max value $posindice = strlen($this->prefix) + 6; - $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql = "SELECT MAX(CAST(SUBSTRING(batch FROM ".$posindice.") AS SIGNED)) as max"; $sql .= " FROM ".MAIN_DB_PREFIX."product_lot"; - $sql .= " WHERE ref LIKE '".$db->escape($this->prefix)."____-%'"; + $sql .= " WHERE batch LIKE '".$db->escape($this->prefix)."____-%'"; $sql .= " AND entity = ".$conf->entity; $resql = $db->query($sql); if ($resql) { $obj = $db->fetch_object($resql); - if ($obj) $max = intval($obj->max); - else $max = 0; + if ($obj) { + $max = intval($obj->max); + } else { + $max = 0; + } } else { dol_syslog("mod_sn_standard::getNextValue", LOG_DEBUG); return -1; } //$date=time(); - $date = $object->date_creation; + $date = dol_now(); $yymm = strftime("%y%m", $date); if ($max >= (pow(10, 4) - 1)) $num = $max + 1; // If counter > 9999, we do not format on 4 chars, we take number as it is diff --git a/htdocs/langs/en_US/productbatch.lang b/htdocs/langs/en_US/productbatch.lang index 450d0285819..763af20c6b4 100644 --- a/htdocs/langs/en_US/productbatch.lang +++ b/htdocs/langs/en_US/productbatch.lang @@ -26,12 +26,10 @@ ShowLogOfMovementIfLot=Show log of movements for couple product/lot StockDetailPerBatch=Stock detail per lot SerialNumberAlreadyInUse=Serial number %s is already used for product %s TooManyQtyForSerialNumber=You can only have one product %s for serial number %s -BatchLotNumberingModules=Options for automatic generation of batch products managed by lots -BatchSerialNumberingModules=Options for automatic generation of batch products managed by serial numbers ManageLotMask=Custom mask -CustomMasks=Adds an option to define mask in the product card -LotProductTooltip=Adds an option in the product card to define a dedicated batch number mask -SNProductTooltip=Adds an option in the product card to define a dedicated serial number mask +CustomMasks=Option to define a different numbering mask for each product +BatchLotNumberingModules=Numbering rule for automatic generation of lot number +BatchSerialNumberingModules=Numbering rule for automatic generation of serial number (for products with property 1 unique lot/serial for each product) QtyToAddAfterBarcodeScan=Qty to add for each barcode/lot/serial scanned LifeTime=Life span (in days) EndOfLife=End of life diff --git a/htdocs/product/admin/product_lot.php b/htdocs/product/admin/product_lot.php index 8cafa97e077..3f4fd636de4 100644 --- a/htdocs/product/admin/product_lot.php +++ b/htdocs/product/admin/product_lot.php @@ -101,188 +101,197 @@ $head = product_lot_admin_prepare_head(); print dol_get_fiche_head($head, 'settings', $langs->trans("Batch"), -1, 'lot'); -/* - * Lot Numbering models - */ -print load_fiche_titre($langs->trans("BatchLotNumberingModules"), '', ''); +if ($conf->global->MAIN_FEATURES_LEVEL < 2) { + // The feature to define the numbering module of lot or serial is no enabled bcause it is not used anywhere in Dolibarr code: You can set it + // but the numbering module is not used. + // TODO Use it on lot creation page, when you create a lot and when the lot number is kept empty to define the lot according + // to the selected product. + print $langs->trans("NothingToSetup"); +} else { + /* + * Lot Numbering models + */ -print ''; -print ''; -print ''; -print ''; -print ''; -print ''; -print ''; -print ''."\n"; + print load_fiche_titre($langs->trans("BatchLotNumberingModules"), '', ''); -clearstatcache(); + print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''."\n"; -foreach ($dirmodels as $reldir) { - $dir = dol_buildpath($reldir."core/modules/product_batch/"); + clearstatcache(); - if (is_dir($dir)) { - $handle = opendir($dir); - if (is_resource($handle)) { - while (($file = readdir($handle)) !== false) { - if (substr($file, 0, 8) == 'mod_lot_' && substr($file, dol_strlen($file) - 3, 3) == 'php') { - $file = substr($file, 0, dol_strlen($file) - 4); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/product_batch/"); - require_once $dir.$file.'.php'; + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + if (substr($file, 0, 8) == 'mod_lot_' && substr($file, dol_strlen($file) - 3, 3) == 'php') { + $file = substr($file, 0, dol_strlen($file) - 4); - $module = new $file($db); + require_once $dir.$file.'.php'; - // Show modules according to features level - if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue; - if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue; + $module = new $file($db); - if ($module->isEnabled()) { - print ''; + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue; - // Show example of numbering model - print ''."\n"; + if ($module->isEnabled()) { + print ''; - print ''; + // Show example of numbering model + print ''."\n"; - $batch = new Productlot($db); - $batch->initAsSpecimen(); - - // Info - $htmltooltip = ''; - $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; - $nextval = $module->getNextValue($mysoc, $batch); - if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval - $htmltooltip .= ''.$langs->trans("NextValue").': '; - if ($nextval) { - if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') - $nextval = $langs->trans($nextval); - $htmltooltip .= $nextval.'
'; + print ''; + + $batch = new Productlot($db); + $batch->initAsSpecimen(); + + // Info + $htmltooltip = ''; + $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; + $nextval = $module->getNextValue($mysoc, $batch); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip .= ''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') + $nextval = $langs->trans($nextval); + $htmltooltip .= $nextval.'
'; + } else { + $htmltooltip .= $langs->trans($module->error).'
'; + } + } + + print ''; + + print "\n"; } - - print ''; - - print "\n"; } } + closedir($handle); } - closedir($handle); } } -} -print "
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'.$module->name."\n"; - print $module->info(); - print ''; - $tmp = $module->getExample(); - if (preg_match('/^Error/', $tmp)) print '
'.$langs->trans($tmp).'
'; - elseif ($tmp == 'NotConfigured') print $langs->trans($tmp); - else print $tmp; - print '
'.$module->name."\n"; + print $module->info(); + print ''; - if ($conf->global->PRODUCTBATCH_LOT_ADDON == $file) { - print img_picto($langs->trans("Activated"), 'switch_on'); - } else { - print ''; - print img_picto($langs->trans("Disabled"), 'switch_off'); - print ''; - } - print ''; + $tmp = $module->getExample(); + if (preg_match('/^Error/', $tmp)) print '
'.$langs->trans($tmp).'
'; + elseif ($tmp == 'NotConfigured') print $langs->trans($tmp); + else print $tmp; + print '
'; + if ($conf->global->PRODUCTBATCH_LOT_ADDON == $file) { + print img_picto($langs->trans("Activated"), 'switch_on'); } else { - $htmltooltip .= $langs->trans($module->error).'
'; + print ''; + print img_picto($langs->trans("Disabled"), 'switch_off'); + print ''; } + print '
'; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print '
'; - print $form->textwithpicto('', $htmltooltip, 1, 0); - print '

\n"; + print "
\n"; -/* - * Serials Numbering models - */ + /* + * Serials Numbering models + */ -print load_fiche_titre($langs->trans("BatchSerialNumberingModules"), '', ''); + print load_fiche_titre($langs->trans("BatchSerialNumberingModules"), '', ''); -print ''; -print ''; -print ''; -print ''; -print ''; -print ''; -print ''; -print ''."\n"; + print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''."\n"; -clearstatcache(); + clearstatcache(); -foreach ($dirmodels as $reldir) { - $dir = dol_buildpath($reldir."core/modules/product_batch/"); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/product_batch/"); - if (is_dir($dir)) { - $handle = opendir($dir); - if (is_resource($handle)) { - while (($file = readdir($handle)) !== false) { - if (substr($file, 0, 7) == 'mod_sn_' && substr($file, dol_strlen($file) - 3, 3) == 'php') { - $file = substr($file, 0, dol_strlen($file) - 4); + if (is_dir($dir)) { + $handle = opendir($dir); + if (is_resource($handle)) { + while (($file = readdir($handle)) !== false) { + if (substr($file, 0, 7) == 'mod_sn_' && substr($file, dol_strlen($file) - 3, 3) == 'php') { + $file = substr($file, 0, dol_strlen($file) - 4); - require_once $dir.$file.'.php'; + require_once $dir.$file.'.php'; - $module = new $file($db); + $module = new $file($db); - // Show modules according to features level - if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue; - if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue; + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue; - if ($module->isEnabled()) { - print ''; + if ($module->isEnabled()) { + print ''; - // Show example of numbering model - print ''."\n"; + // Show example of numbering model + print ''."\n"; - print ''; - - $batch = new Productlot($db); - $batch->initAsSpecimen(); - - // Info - $htmltooltip = ''; - $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; - $nextval = $module->getNextValue($mysoc, $batch); - if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval - $htmltooltip .= ''.$langs->trans("NextValue").': '; - if ($nextval) { - if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') - $nextval = $langs->trans($nextval); - $htmltooltip .= $nextval.'
'; + print ''; + + $batch = new Productlot($db); + $batch->initAsSpecimen(); + + // Info + $htmltooltip = ''; + $htmltooltip .= ''.$langs->trans("Version").': '.$module->getVersion().'
'; + $nextval = $module->getNextValue($mysoc, $batch); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip .= ''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') + $nextval = $langs->trans($nextval); + $htmltooltip .= $nextval.'
'; + } else { + $htmltooltip .= $langs->trans($module->error).'
'; + } + } + + print ''; + + print "\n"; } - - print ''; - - print "\n"; } } + closedir($handle); } - closedir($handle); } } -} -print "
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'.$module->name."\n"; - print $module->info(); - print '
'.$module->name."\n"; + print $module->info(); + print ''; - $tmp = $module->getExample(); - if (preg_match('/^Error/', $tmp)) print '
'.$langs->trans($tmp).'
'; - elseif ($tmp == 'NotConfigured') print $langs->trans($tmp); - else print $tmp; - print '
'; + $tmp = $module->getExample(); + if (preg_match('/^Error/', $tmp)) print '
'.$langs->trans($tmp).'
'; + elseif ($tmp == 'NotConfigured') print $langs->trans($tmp); + else print $tmp; + print '
'; - if ($conf->global->PRODUCTBATCH_SN_ADDON == $file) { - print img_picto($langs->trans("Activated"), 'switch_on'); - } else { - print ''; - print img_picto($langs->trans("Disabled"), 'switch_off'); - print ''; - } - print ''; + if ($conf->global->PRODUCTBATCH_SN_ADDON == $file) { + print img_picto($langs->trans("Activated"), 'switch_on'); } else { - $htmltooltip .= $langs->trans($module->error).'
'; + print ''; + print img_picto($langs->trans("Disabled"), 'switch_off'); + print ''; } + print '
'; + print $form->textwithpicto('', $htmltooltip, 1, 0); + print '
'; - print $form->textwithpicto('', $htmltooltip, 1, 0); - print '

\n"; + print "
\n"; +} // End of page llxFooter(); diff --git a/htdocs/product/stock/class/productlot.class.php b/htdocs/product/stock/class/productlot.class.php index 2a3b3cf2e20..52322cf4697 100644 --- a/htdocs/product/stock/class/productlot.class.php +++ b/htdocs/product/stock/class/productlot.class.php @@ -87,7 +87,7 @@ class Productlot extends CommonObject */ public $fields = array( 'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'noteditable'=>1, 'notnull'=> 1, 'index'=>1, 'position'=>1, 'comment'=>'Id', 'css'=>'left'), - 'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>15, 'notnull'=>1, 'index'=>1, 'searchall'=>1), + 'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>5, 'notnull'=>1, 'index'=>1, 'searchall'=>1), 'batch' => array('type'=>'varchar(30)', 'label'=>'Batch', 'enabled'=>1, 'visible'=>1, 'notnull'=>0, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'comment'=>'Batch', 'searchall'=>1), 'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'default'=>1, 'notnull'=>1, 'index'=>1, 'position'=>20), 'sellby' => array('type'=>'date', 'label'=>'SellByDate', 'enabled'=>'empty($conf->global->PRODUCT_DISABLE_SELLBY)?1:0', 'visible'=>5, 'position'=>60), From 2091120d77232de12b42c2482e9cf56f590b2e47 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 11 Jul 2021 00:50:57 +0200 Subject: [PATCH 05/39] FIX #18122 --- htdocs/product/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/card.php b/htdocs/product/card.php index b1e892ae2da..9e1cf6af40c 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1628,7 +1628,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial")); print $form->selectarray('status_batch', $statutarray, $object->status_batch); print ''; - if ($object->status_batch !== '0') { + if (!empty($object->status_batch) || !empty($conf->use_javascript_ajax)) { $langs->load("admin"); $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch")); $tooltip .= '
'.$langs->trans("GenericMaskCodes2"); From e7b3280c172e9c3cb439ae39da27950d1de0b6b1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 11 Jul 2021 01:12:52 +0200 Subject: [PATCH 06/39] Debug v14 with nojs --- htdocs/admin/accountant.php | 8 +- htdocs/admin/company.php | 8 +- htdocs/core/class/extrafields.class.php | 48 ++--- htdocs/core/class/html.form.class.php | 248 ++++++++++++----------- htdocs/core/tpl/extrafields_view.tpl.php | 1 - htdocs/product/card.php | 88 ++++---- htdocs/societe/card.php | 2 +- 7 files changed, 210 insertions(+), 193 deletions(-) diff --git a/htdocs/admin/accountant.php b/htdocs/admin/accountant.php index 7c82775abad..24df7e0cb68 100644 --- a/htdocs/admin/accountant.php +++ b/htdocs/admin/accountant.php @@ -99,14 +99,16 @@ print "
\n"; /** * Edit parameters */ -print "\n".''."\n"; + print ''."\n"; +} print '
'; print ''; diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index d2dac38b500..b33c0adde29 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -384,14 +384,16 @@ print "
\n"; /** * Edit parameters */ -print "\n".''."\n"; + print ''."\n"; +} print ''; print ''; diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 54d812aeafb..f6a5ba93d61 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -2006,30 +2006,32 @@ class ExtraFields $collapse_display = ((isset($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key]) || GETPOST('ignorecollapsesetup', 'int')) ? ($_COOKIE['DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key] ? true : false) : ($extrafield_collapse_display_value == 2 ? false : true)); $extrafields_collapse_num = $this->attributes[$object->table_element]['pos'][$key].(!empty($object->id)?'_'.$object->id:''); - $out .= ''."\n"; - $out .= ''."\n"; } - $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').'").click(function(){'."\n"; - $out .= ' console.log("We click on collapse/uncollapse .trextrafields_collapse'.$extrafields_collapse_num.'");'."\n"; - $out .= ' jQuery(".trextrafields_collapse'.$extrafields_collapse_num.'").toggle(300, function(){'."\n"; - $out .= ' if (jQuery(".trextrafields_collapse'.$extrafields_collapse_num.'").is(":hidden")) {'."\n"; - $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-plus-square").removeClass("fa-minus-square");'."\n"; - $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=0; path='.$_SERVER["PHP_SELF"].'"'."\n"; - $out .= ' } else {'."\n"; - $out .= ' jQuery("#trextrafieldseparator'.$key.(!empty($object->id)?'_'.$object->id:'').' '.$tagtype_dyn.' span").addClass("fa-minus-square").removeClass("fa-plus-square");'."\n"; - $out .= ' document.cookie = "DOLCOLLAPSE_'.$object->table_element.'_extrafields_'.$key.'=1; path='.$_SERVER["PHP_SELF"].'"'."\n"; - $out .= ' }'."\n"; - $out .= ' });'."\n"; - $out .= ' });'."\n"; - $out .= '});'."\n"; - $out .= ''."\n"; } } } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 048fbb0cad3..816e0a79225 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -7067,7 +7067,7 @@ class Form public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0) { global $conf, $langs; - global $delayedhtmlcontent; + global $delayedhtmlcontent; // Will be used later outside of this function // TODO Use an internal dolibarr component instead of select2 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) { @@ -7076,68 +7076,71 @@ class Form $out = ''; - $tmpplugin = 'select2'; - $outdelayed = "\n".' - '; + }); + '; + } if ($acceptdelayedhtml) { $delayedhtmlcontent .= $outdelayed; @@ -7168,7 +7171,7 @@ class Form public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0) { global $conf, $langs; - global $delayedhtmlcontent; + global $delayedhtmlcontent; // Will be used later outside of this function // TODO Use an internal dolibarr component instead of select2 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) { @@ -7187,74 +7190,77 @@ class Form $formattedarrayresult[] = $o; } - $tmpplugin = 'select2'; - $outdelayed = "\n".' - '; + '.($callurlonselect ? ' + /* Code to execute a GET when we select a value */ + $(".'.$htmlname.'").change(function() { + var selected = $(".'.$htmlname.'").val(); + console.log("We select "+selected) + + $(".'.$htmlname.'").val(""); /* reset visible combo value */ + $.each( saveRemoteData, function( key, value ) { + if (key == selected) + { + console.log("selectArrayFilter - Do a redirect to "+value.url) + location.assign(value.url); + } + }); + });' : '').' + + }); + '; + } if ($acceptdelayedhtml) { $delayedhtmlcontent .= $outdelayed; @@ -7297,7 +7303,7 @@ class Form } // Add code for jquery to use multiselect - if (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) { + if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) { $out .= "\n".''; $out .= "\n".''."\n"; + print ''."\n"; + } // Load object modCodeProduct $module = (!empty($conf->global->PRODUCT_CODEPRODUCT_ADDON) ? $conf->global->PRODUCT_CODEPRODUCT_ADDON : 'mod_codeproduct_leopard'); @@ -1551,14 +1553,16 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { //WYSIWYG Editor require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - print ''."\n"; + } // We set country_id, country_code and country for the selected country $object->country_id = GETPOST('country_id') ? GETPOST('country_id') : $object->country_id; @@ -1646,46 +1650,48 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK'); print ''; print $form->textwithpicto('', $tooltip, 1, 1); - - print ''; + '; + } print ''; } } diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 76ae78fdb51..b62c277cdf2 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1859,7 +1859,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { $sub2 = 1; } - if ($conf->use_javascript_ajax) { + if (!empty($conf->use_javascript_ajax)) { print "\n".''; } - + $stringtoprint .=''; $stringtoprint .= ajax_combobox($htmlname); return $stringtoprint; From 5b1525e77c1941dc6e282ecc26bb6ab3ea576d51 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Mon, 12 Jul 2021 14:15:28 +0000 Subject: [PATCH 29/39] Fixing style errors. --- htdocs/core/class/html.formticket.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 4724c57e885..48c861fdd95 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -697,7 +697,7 @@ class FormTicket } if ($num_rows_level0 == 1) { return ''; - }else{ + } else { $stringtoprint .= ''; $stringtoprint .= ''; } From d3f324c2d4267ab27c7cc127d238f8b563891889 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Jul 2021 16:55:16 +0200 Subject: [PATCH 30/39] Try a better fix for #18105 --- htdocs/core/class/hookmanager.class.php | 23 ++++++++++++++++++----- htdocs/core/lib/functions.lib.php | 7 ++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index d610203b3ad..8384886e50c 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -254,16 +254,29 @@ class HookManager // Hooks that must return int (hooks with type 'addreplace') if ($hooktype == 'addreplace') { - $resaction += $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) - if ($resaction < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) - { + $resactiontmp = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) + $resaction += $resactiontmp; + + if ($resactiontmp < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) { $error++; $this->error = $actionclassinstance->error; $this->errors = array_merge($this->errors, (array) $actionclassinstance->errors); dol_syslog("Error on hook module=".$module.", method ".$method.", class ".get_class($actionclassinstance).", hooktype=".$hooktype.(empty($this->error) ? '' : " ".$this->error).(empty($this->errors) ? '' : " ".join(",", $this->errors)), LOG_ERR); } - if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) $this->resArray = array_merge($this->resArray, $actionclassinstance->results); - if (!empty($actionclassinstance->resprints)) $this->resPrint .= $actionclassinstance->resprints; + if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) { + if ($resactiontmp > 0) { + $this->resArray = $actionclassinstance->results; + } else { + $this->resArray = array_merge($this->resArray, $actionclassinstance->results); + } + } + if (!empty($actionclassinstance->resprints)) { + if ($resactiontmp > 0) { + $this->resPrint = $actionclassinstance->resprints; + } else { + $this->resPrint .= $actionclassinstance->resprints; + } + } } // Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) else { diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 884b5ece6f7..54ef73f19d6 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -7754,11 +7754,12 @@ function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, { $parameters = array('object' => $object, 'mode' => $mode, 'head' => $head); $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters); - if ($reshook > 0) - { + if ($reshook > 0) { // Hook ask to replace completely the array $head = $hookmanager->resArray; - $h = count($head); + } else { // Hook + $head = array_merge($head, $hookmanager->resArray); } + $h = count($head); } } From a15d895b4ba16fe8c86b52f54b0eecf8d8dedd64 Mon Sep 17 00:00:00 2001 From: Christophe Battarel Date: Mon, 12 Jul 2021 14:09:16 +0200 Subject: [PATCH 31/39] fix badge status bgcolor --- htdocs/theme/eldy/badges.inc.php | 8 ++++---- htdocs/theme/md/badges.inc.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/htdocs/theme/eldy/badges.inc.php b/htdocs/theme/eldy/badges.inc.php index dcb61499b63..58317deba15 100644 --- a/htdocs/theme/eldy/badges.inc.php +++ b/htdocs/theme/eldy/badges.inc.php @@ -258,9 +258,9 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL print $cssPrefix.".badge-status".$statusName." {\n"; print " color: ".$thisBadgeTextColor." !important;\n"; if (in_array((string) $statusName, $TBadgeBorderOnly)) { - print " border-color: ".$thisBadgeBorderColor.";\n"; + print " border-color: ".$thisBadgeBorderColor." !important;\n"; } - print " background-color: ".$thisBadgeBackgroundColor.";\n"; + print " background-color: ".$thisBadgeBackgroundColor." !important;\n"; print "}\n"; print $cssPrefix.".font-status".$statusName." {\n"; @@ -269,14 +269,14 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL print $cssPrefix.".badge-status".$statusName.".focus, ".$cssPrefix.".badge-status".$statusName.":focus {\n"; print " outline: 0;\n"; - print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5).";\n"; + print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5)." !important;\n"; print "}\n"; print $cssPrefix.".badge-status".$statusName.":focus, ".$cssPrefix.".badge-status".$statusName.":hover {\n"; print " color: ".$thisBadgeTextColor." !important;\n"; //print " background-color: " . colorDarker($thisBadgeBackgroundColor, 10) . ";\n"; if (in_array((string) $statusName, $TBadgeBorderOnly)) { - print " border-color: ".colorDarker($thisBadgeBorderColor, 10).";\n"; + print " border-color: ".colorDarker($thisBadgeBorderColor, 10)." !important;\n"; } print "}\n"; } diff --git a/htdocs/theme/md/badges.inc.php b/htdocs/theme/md/badges.inc.php index fd1b1122a17..4a36177e852 100644 --- a/htdocs/theme/md/badges.inc.php +++ b/htdocs/theme/md/badges.inc.php @@ -261,9 +261,9 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL print $cssPrefix.".badge-status".$statusName." {\n"; print " color: ".$thisBadgeTextColor." !important;\n"; if (in_array((string) $statusName, $TBadgeBorderOnly)) { - print " border-color: ".$thisBadgeBorderColor.";\n"; + print " border-color: ".$thisBadgeBorderColor." !important;\n"; } - print " background-color: ".$thisBadgeBackgroundColor.";\n"; + print " background-color: ".$thisBadgeBackgroundColor." !important;\n"; print "}\n"; print $cssPrefix.".font-status".$statusName." {\n"; @@ -272,14 +272,14 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL print $cssPrefix.".badge-status".$statusName.".focus, ".$cssPrefix.".badge-status".$statusName.":focus {\n"; print " outline: 0;\n"; - print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5).";\n"; + print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5)." !important;\n"; print "}\n"; print $cssPrefix.".badge-status".$statusName.":focus, ".$cssPrefix.".badge-status".$statusName.":hover {\n"; print " color: ".$thisBadgeTextColor." !important;\n"; //print " background-color: ".colorDarker($thisBadgeBackgroundColor, 10).";\n"; if (in_array((string) $statusName, $TBadgeBorderOnly)) { - print " border-color: ".colorDarker($thisBadgeBorderColor, 10).";\n"; + print " border-color: ".colorDarker($thisBadgeBorderColor, 10)." !important;\n"; } print "}\n"; } From 202ee8340a4dafd6a17a066781bffdff729f0d7b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Jul 2021 23:01:34 +0200 Subject: [PATCH 32/39] FIX #18091 --- htdocs/langs/en_US/errors.lang | 1 + htdocs/product/card.php | 2 +- .../product/class/html.formproduct.class.php | 4 +- htdocs/projet/class/task.class.php | 24 +++++- htdocs/projet/tasks/time.php | 75 ++++++++++++++----- 5 files changed, 81 insertions(+), 25 deletions(-) diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index 3ed7441afa5..cb97af5c183 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -264,6 +264,7 @@ ErrorAnAmountWithoutTaxIsRequired=Error, amount is mandatory ErrorAPercentIsRequired=Error, please fill in the percentage correctly ErrorYouMustFirstSetupYourChartOfAccount=You must first setup your chart of account ErrorFailedToFindEmailTemplate=Failed to find template with code name %s +ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice=Duration not defined on service. No way to calculate the hourly price. # Warnings WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup. diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 01a2d9acfdd..2472c764d7e 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1234,7 +1234,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) { if ($type == 1) { print ''.$langs->trans("Duration").''; print ''; - print $formproduct->selectMeasuringUnits("duration_unit", "time", GETPOST('duration_value', 'alpha'), 0, 1); + print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_value') ? GETPOSTISSET('duration_value', 'alpha') : 'h'), 0, 1); print ''; } diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php index 5be93a9b9d1..555bc08d03e 100644 --- a/htdocs/product/class/html.formproduct.class.php +++ b/htdocs/product/class/html.formproduct.class.php @@ -414,7 +414,7 @@ class FormProduct dol_print_error($db); return -1; } else { - $return .= ''; if ($adddefault || $adddefault === '') { $return .= ''; } @@ -447,6 +447,8 @@ class FormProduct $return .= ''; } + $return .= ajax_combobox($name); + return $return; } diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 5e17c92c562..02c045e2ce1 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -116,6 +116,7 @@ class Task extends CommonObject public $timespent_datehour; // More accurate start date (same than timespent_date but includes hours, minutes and seconds) public $timespent_withhour; // 1 = we entered also start hours for timesheet line public $timespent_fk_user; + public $timespent_thm; public $timespent_note; public $comments = array(); @@ -1212,6 +1213,7 @@ class Task extends CommonObject $ret = -2; } + // Update hourly rate of this time spent entry $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time"; $sql .= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".((int) $this->timespent_fk_user).")"; // set average hour rate of user $sql .= " WHERE rowid = ".((int) $tasktime_id); @@ -1425,6 +1427,7 @@ class Task extends CommonObject $sql .= " ptt.task_duration,"; $sql .= " ptt.fk_user,"; $sql .= " ptt.note,"; + $sql .= " ptt.thm,"; $sql .= " pt.rowid as task_id,"; $sql .= " pt.ref as task_ref,"; $sql .= " pt.label as task_label,"; @@ -1435,7 +1438,7 @@ class Task extends CommonObject $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid"; $sql .= " WHERE ptt.fk_task = pt.rowid AND pt.fk_projet = p.rowid"; - $sql .= " AND ptt.fk_user = ".$userobj->id; + $sql .= " AND ptt.fk_user = ".((int) $userobj->id); $sql .= " AND pt.entity IN (".getEntity('project').")"; if ($morewherefilter) { $sql .= $morewherefilter; @@ -1471,6 +1474,7 @@ class Task extends CommonObject $newobj->timespent_withhour = $obj->task_date_withhour; $newobj->timespent_duration = $obj->task_duration; $newobj->timespent_fk_user = $obj->fk_user; + $newobj->timespent_thm = $obj->thm; // hourly rate $newobj->timespent_note = $obj->note; $arrayres[] = $newobj; @@ -1552,10 +1556,12 @@ class Task extends CommonObject } if ($ret == 1 && ($this->timespent_old_duration != $this->timespent_duration)) { - $newDuration = $this->timespent_duration - $this->timespent_old_duration; - + // Recalculate amount of time spent for task and update denormalized field $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task"; $sql .= " SET duration_effective = (SELECT SUM(task_duration) FROM ".MAIN_DB_PREFIX."projet_task_time as ptt where ptt.fk_task = ".((int) $this->id).")"; + if (isset($this->progress)) { + $sql .= ", progress = ".((float) $this->progress); // Do not overwrite value if not provided + } $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG); @@ -1564,6 +1570,18 @@ class Task extends CommonObject $this->db->rollback(); $ret = -2; } + + // Update hourly rate of this time spent entry, but only if it was not set initialy + $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time"; + $sql .= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".((int) $this->timespent_fk_user).")"; // set average hour rate of user + $sql .= " WHERE (thm IS NULL OR thm = 0) AND rowid = ".((int) $this->timespent_id); + + dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG); + if (!$this->db->query($sql)) { + $this->error = $this->db->lasterror(); + $ret = -2; + } + } if ($ret >= 0) { diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index bbe9671faf3..f04b53c3d1e 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -261,10 +261,10 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us $object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds $object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0) { // If hour was entered - $object->timespent_date = dol_mktime(GETPOST("timelinehour"), GETPOST("timelinemin"), 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear")); + $object->timespent_date = dol_mktime(GETPOST("timelinehour", 'int'), GETPOST("timelinemin", 'int'), 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int')); $object->timespent_withhour = 1; } else { - $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear")); + $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int')); } $object->timespent_fk_user = GETPOST("userid_line", 'int'); @@ -353,6 +353,13 @@ if ($action == 'confirm_generateinvoice') { $prodDurationHours = 1.0; if ($idprod > 0) { $tmpproduct->fetch($idprod); + + if (empty($tmpproduct->duration_value)) { + $error++; + $langs->load("errors"); + setEventMessages($langs->trans("ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice"), null, 'errors'); + } + if ($tmpproduct->duration_unit == 'i') { $prodDurationHours = 1. / 60; } @@ -380,6 +387,8 @@ if ($action == 'confirm_generateinvoice') { $localtax1 = $dataforprice['localtax1']; $localtax2 = $dataforprice['localtax2']; } else { + $prodDurationHours = 1; + $pu_ht = 0; $txtva = get_default_tva($mysoc, $projectstatic->thirdparty); $localtax1 = get_default_localtax($mysoc, $projectstatic->thirdparty, 1); @@ -482,14 +491,14 @@ if ($action == 'confirm_generateinvoice') { break; } } - } elseif ($generateinvoicemode == 'onelinepertask') { + } elseif ($generateinvoicemode == 'onelinepertask') { // One line for each different task $arrayoftasks = array(); foreach ($toselect as $key => $value) { // Get userid, timepent - $object->fetchTimeSpent($value); - // $object->id is the task id + $object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utiliy method found into Task object) + // $object->id is now the task id $arrayoftasks[$object->id]['timespent'] += $object->timespent_duration; - $arrayoftasks[$object->id]['totalvaluetodivideby3600'] += $object->timespent_duration * $object->timespent_thm; + $arrayoftasks[$object->id]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm); } foreach ($arrayoftasks as $task_id => $value) { @@ -499,24 +508,46 @@ if ($action == 'confirm_generateinvoice') { $qtyhour = $value['timespent'] / 3600; $qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY); - // If no unit price known - if (empty($pu_ht)) { - $pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU'); + if ($idprod > 0) { + // If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously). + $pu_ht_for_task = $pu_ht; + // If we want to reuse the value of timespent (so use same price than cost price) + if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) { + $pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours; + } + $pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours; + } else { + // If not product used, we use the hour unit for duration and unit price. + $pu_ht_for_task = 0; + // If we want to reuse the value of timespent (so use same price than cost price) + if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) { + $pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU'); + } + $pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU'); } // Add lines + $date_start = ''; + $date_end = ''; $lineName = $ftask->ref.' - '.$ftask->label; - $lineid = $tmpinvoice->addline($lineName, $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0)); - - // Update lineid into line of timespent - $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id); - $sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')'; - $result = $db->query($sql); - if (!$result) { + $lineid = $tmpinvoice->addline($lineName, $pu_ht_for_task, price2num($qtyhour / $prodDurationHours, 'MS'), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0), 0, $date_start, $date_end, 0, 0, '', 'HT', 0, 1, -1, 0, '', 0, 0, null, $pa_ht); + if ($lineid < 0) { $error++; - setEventMessages($db->lasterror(), null, 'errors'); + setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors'); break; } + + if (!$error) { + // Update lineid into line of timespent + $sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id); + $sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')'; + $result = $db->query($sql); + if (!$result) { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + break; + } + } } } } @@ -960,7 +991,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { print ''; if ($projectstatic->thirdparty->id > 0) { - print ''; + print '
'; print ''; print ''; - $date1 = $db->jdate($task_time->task_date); $date2 = $db->jdate($task_time->task_datehour); + print ''; + // Date if (!empty($arrayfields['t.task_date']['checked'])) { print ''; if (!$i) { $totalarray['nbfield']++; From f9d60b15d956cac3e4bd14eacf1b0f1a30f4a159 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 12 Jul 2021 23:56:42 +0200 Subject: [PATCH 33/39] Fix phpcs --- htdocs/projet/class/task.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 02c045e2ce1..574fb534b2c 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -1581,7 +1581,6 @@ class Task extends CommonObject $this->error = $this->db->lasterror(); $ret = -2; } - } if ($ret >= 0) { From 35b29481c786f2ea091160ad4d8550d8f9f26e74 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Tue, 13 Jul 2021 10:05:38 +0200 Subject: [PATCH 34/39] Close #18131 : new massaction for thirdparty --- htdocs/core/actions_massactions.inc.php | 74 +++++++++++++++++++++++++ htdocs/core/tpl/massactions_pre.tpl.php | 8 +++ htdocs/langs/en_US/main.lang | 10 ++++ htdocs/langs/fr_FR/main.lang | 10 ++++ htdocs/societe/list.php | 8 ++- 5 files changed, 109 insertions(+), 1 deletion(-) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index cd8a3817602..30433004f95 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1470,6 +1470,80 @@ if (!$error && ($action == 'affecttag' && $confirm == 'yes') && $permissiontoadd } } +if (!$error && ($massaction == 'enable' || ($action == 'enable' && $confirm == 'yes')) && $permissiontoadd) { + $db->begin(); + + $objecttmp = new $objectclass($db); + $nbok = 0; + foreach ($toselect as $toselectid) { + $result = $objecttmp->fetch($toselectid); + if($result>0){ + if (in_array($objecttmp->element,array('societe'))) { + $result =$objecttmp->setStatut(1); + } + if ($result <= 0) { + setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); + $error++; + break; + } else { + $nbok++; + } + }else { + setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); + $error++; + break; + } + } + + if (!$error) { + if ($nbok > 1) { + setEventMessages($langs->trans("RecordsEnabled", $nbok), null, 'mesgs'); + } else { + setEventMessages($langs->trans("RecordEnabled"), null, 'mesgs'); + } + $db->commit(); + } else { + $db->rollback(); + } +} + +if (!$error && ($massaction == 'disable' || ($action == 'disable' && $confirm == 'yes')) && $permissiontoadd) { + $db->begin(); + + $objecttmp = new $objectclass($db); + $nbok = 0; + foreach ($toselect as $toselectid) { + $result = $objecttmp->fetch($toselectid); + if($result>0){ + if (in_array($objecttmp->element,array('societe'))) { + $result =$objecttmp->setStatut(0); + } + if ($result <= 0) { + setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); + $error++; + break; + } else { + $nbok++; + } + }else { + setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); + $error++; + break; + } + } + + if (!$error) { + if ($nbok > 1) { + setEventMessages($langs->trans("RecordsDisabled", $nbok), null, 'mesgs'); + } else { + setEventMessages($langs->trans("RecordDisabled"), null, 'mesgs'); + } + $db->commit(); + } else { + $db->rollback(); + } +} + $parameters['toselect'] = $toselect; $parameters['uploaddir'] = $uploaddir; $parameters['massaction'] = $massaction; diff --git a/htdocs/core/tpl/massactions_pre.tpl.php b/htdocs/core/tpl/massactions_pre.tpl.php index 4b8680e11bb..c40f896e702 100644 --- a/htdocs/core/tpl/massactions_pre.tpl.php +++ b/htdocs/core/tpl/massactions_pre.tpl.php @@ -194,6 +194,14 @@ if ($massaction == 'presend') { print dol_get_fiche_end(); } + +if ($massaction == 'preenable') { + print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassEnabling"), $langs->trans("ConfirmMassEnablingQuestion", count($toselect)), "enable", null, '', 0, 200, 500, 1); +} +if ($massaction == 'predisable') { + print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassDisabling"), $langs->trans("ConfirmMassDisablingQuestion", count($toselect)), "disable", null, '', 0, 200, 500, 1); +} + // Allow Pre-Mass-Action hook (eg for confirmation dialog) $parameters = array( 'toselect' => $toselect, diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 863b94af564..44cdafdda09 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -1137,3 +1137,13 @@ CopiedToClipboard=Copied to clipboard InformationOnLinkToContract=This amount is only the total of all the lines of the contract. No notion of time is taken into consideration. ConfirmCancel=Are you sure you want to cancel EmailMsgID=Email MsgID +SetToEnabled=Set to enabled +SetToDisabled=Set to disabled +ConfirmMassEnabling=mass enabling confirmation +ConfirmMassEnablingQuestion=Are you sure you want to enable the %s selected record(s)? +ConfirmMassDisabling=mass disabling confirmation +ConfirmMassDisablingQuestion=Are you sure you want to disable the %s selected record(s)? +RecordsEnabled=%s record(s) enabled +RecordsDisabled=%s record(s) disabled +RecordEnabled=Record enabled +RecordDisabled=Record disabled diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang index bf49ccccf54..2453fab1e16 100644 --- a/htdocs/langs/fr_FR/main.lang +++ b/htdocs/langs/fr_FR/main.lang @@ -1137,3 +1137,13 @@ CopiedToClipboard=Copié dans le presse-papier InformationOnLinkToContract=Ce montant n’est que le total de toutes les lignes du contrat. Aucune notion de temps n’est prise en considération. ConfirmCancel=Êtes-vous sûr de vous annuler EmailMsgID=E-mail MsgID +SetToEnabled=Activer +SetToDisabled=Désactiver +ConfirmMassEnabling=Confirmation d'activation en masse +ConfirmMassEnablingQuestion=Êtes-vous sur de vouloir activer les %s enregistrement(s) sélectionné(s) ? +ConfirmMassDisabling=Confirmation de desactivation en masse +ConfirmMassDisablingQuestion=Êtes-vous sur de vouloir desactiver les %s enregistrement(s) sélectionné(s) ? +RecordsEnabled=%s enregistrement(s) activé(s) +RecordsDisabled=%s enregistrement(s) désactivé(s) +RecordEnabled=Enregistrement activé +RecordDisabled=Enregistrement désactivé diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php index 5935ac43b70..6835794e916 100644 --- a/htdocs/societe/list.php +++ b/htdocs/societe/list.php @@ -865,7 +865,13 @@ if ($user->rights->societe->supprimer) { if ($user->rights->societe->creer) { $arrayofmassactions['preaffecttag'] = img_picto('', 'category', 'class="pictofixedwidth"').$langs->trans("AffectTag"); } -if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete', 'preaffecttag'))) { +if ($user->rights->societe->creer) { + $arrayofmassactions['preenable'] = img_picto('', '', 'class="pictofixedwidth"').$langs->trans("SetToEnabled"); +} +if ($user->rights->societe->creer) { + $arrayofmassactions['predisable'] = img_picto('', '', 'class="pictofixedwidth"').$langs->trans("SetToDisabled"); +} +if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete', 'preaffecttag', 'preenable', 'preclose'))) { $arrayofmassactions = array(); } $massactionbutton = $form->selectMassAction('', $arrayofmassactions); From 85adefe721b9f5c49e357942602cd852f4512279 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Tue, 13 Jul 2021 08:08:01 +0000 Subject: [PATCH 35/39] Fixing style errors. --- htdocs/core/actions_massactions.inc.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 30433004f95..e5d4de26278 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1477,8 +1477,8 @@ if (!$error && ($massaction == 'enable' || ($action == 'enable' && $confirm == ' $nbok = 0; foreach ($toselect as $toselectid) { $result = $objecttmp->fetch($toselectid); - if($result>0){ - if (in_array($objecttmp->element,array('societe'))) { + if ($result>0) { + if (in_array($objecttmp->element, array('societe'))) { $result =$objecttmp->setStatut(1); } if ($result <= 0) { @@ -1488,7 +1488,7 @@ if (!$error && ($massaction == 'enable' || ($action == 'enable' && $confirm == ' } else { $nbok++; } - }else { + } else { setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); $error++; break; @@ -1514,8 +1514,8 @@ if (!$error && ($massaction == 'disable' || ($action == 'disable' && $confirm == $nbok = 0; foreach ($toselect as $toselectid) { $result = $objecttmp->fetch($toselectid); - if($result>0){ - if (in_array($objecttmp->element,array('societe'))) { + if ($result>0) { + if (in_array($objecttmp->element, array('societe'))) { $result =$objecttmp->setStatut(0); } if ($result <= 0) { @@ -1525,7 +1525,7 @@ if (!$error && ($massaction == 'disable' || ($action == 'disable' && $confirm == } else { $nbok++; } - }else { + } else { setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); $error++; break; From df3d88570c4527f7da70d526a77154f86c567324 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Jul 2021 11:39:08 +0200 Subject: [PATCH 36/39] Fix missing column in migration --- htdocs/install/mysql/migration/12.0.0-13.0.0.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index da4d0fd0a42..cb466f94b10 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -368,7 +368,7 @@ ALTER TABLE llx_actioncomm_reminder ADD UNIQUE uk_actioncomm_reminder_unique (fk ALTER TABLE llx_actioncomm_reminder ADD INDEX idx_actioncomm_reminder_status (status); - +ALTER TABLE llx_inventorydet ADD COLUMN fk_warehouse integer DEFAULT 0; ALTER TABLE llx_inventorydet ADD UNIQUE uk_inventorydet(fk_inventory, fk_warehouse, fk_product, batch); ALTER TABLE llx_commandedet ADD COLUMN ref_ext varchar(255) AFTER label; From 4c29a3ad994b9d9f43fbebdf33ccb1fe08ca7803 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Jul 2021 13:06:28 +0200 Subject: [PATCH 37/39] Fix migration --- htdocs/install/mysql/migration/12.0.0-13.0.0.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql index 1ebb8e380a7..29c2aad9bd4 100644 --- a/htdocs/install/mysql/migration/12.0.0-13.0.0.sql +++ b/htdocs/install/mysql/migration/12.0.0-13.0.0.sql @@ -367,7 +367,7 @@ ALTER TABLE llx_actioncomm_reminder ADD UNIQUE uk_actioncomm_reminder_unique (fk ALTER TABLE llx_actioncomm_reminder ADD INDEX idx_actioncomm_reminder_status (status); - +ALTER TABLE llx_inventorydet ADD COLUMN fk_warehouse integer DEFAULT 0; ALTER TABLE llx_inventorydet ADD UNIQUE uk_inventorydet(fk_inventory, fk_warehouse, fk_product, batch); ALTER TABLE llx_commandedet ADD COLUMN ref_ext varchar(255) AFTER label; From 7a589921fe3d6cd902bff136b5047d8811bd80ec Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Jul 2021 13:10:19 +0200 Subject: [PATCH 38/39] Fix #18142 --- htdocs/install/mysql/tables/llx_facture.sql | 2 +- htdocs/install/mysql/tables/llx_facture_fourn.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/install/mysql/tables/llx_facture.sql b/htdocs/install/mysql/tables/llx_facture.sql index 010cf1c1573..ee98752e5f3 100644 --- a/htdocs/install/mysql/tables/llx_facture.sql +++ b/htdocs/install/mysql/tables/llx_facture.sql @@ -86,7 +86,7 @@ create table llx_facture fk_incoterms integer, -- for incoterms location_incoterms varchar(255), -- for incoterms - fk_mode_transport integer, -- for intracomm report + fk_transport_mode integer, -- for intracomm report situation_cycle_ref smallint, -- situation cycle reference situation_counter smallint, -- situation counter diff --git a/htdocs/install/mysql/tables/llx_facture_fourn.sql b/htdocs/install/mysql/tables/llx_facture_fourn.sql index ef7e980b8aa..906125d0679 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn.sql @@ -71,7 +71,7 @@ create table llx_facture_fourn fk_incoterms integer, -- for incoterms location_incoterms varchar(255), -- for incoterms - fk_mode_transport integer, -- for intracomm report + fk_transport_mode integer, -- for intracomm report model_pdf varchar(255), last_main_doc varchar(255), -- relative filepath+filename of last main generated document From e755d68b068dd1008b90ab62156fa7e606570969 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Jul 2021 13:22:20 +0200 Subject: [PATCH 39/39] Merge branch '14.0' of git@github.com:Dolibarr/dolibarr.git into develop --- htdocs/core/class/hookmanager.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index b22caf17f04..5e24ee03fa4 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -296,9 +296,9 @@ class HookManager $this->resPrint .= $actionclassinstance->resprints; } } - } - // Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) - else { + } else { + // Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) + // TODO. this test should be done into the method of hook by returning nothing if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) { continue;
'; print $langs->trans('DateInvoice'); @@ -1352,11 +1383,11 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { break; } - print '
'; @@ -1480,9 +1511,13 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { // Value spent if (!empty($arrayfields['value']['checked'])) { + $langs->load("salaries"); + print ''; $value = price2num($task_time->thm * $task_time->task_duration / 3600, 'MT', 1); + print 'thm).'">'; print price($value, 1, $langs, 1, -1, -1, $conf->currency); + print ''; print '