From 2ee7b4be95510acf127a5d8cf3f4da98972e1673 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 26 Nov 2025 22:36:23 +0100 Subject: [PATCH 01/53] UX Accountancy - Ledger - Add icon for more comprehension --- htdocs/accountancy/bookkeeping/card.php | 4 ++-- htdocs/accountancy/bookkeeping/list.php | 6 ++++++ htdocs/accountancy/bookkeeping/listbyaccount.php | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index d7fb7d2a3fd..2832520875f 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -851,7 +851,7 @@ if ($action == 'create') { print ''; print '' . $langs->trans("DateExport") . ''; print ''; - print $object->date_export ? img_picto($langs->trans("TransactionExportDesc"), 'fa-file-export', 'class="pictofixedwidth"').dol_print_date($object->date_export, 'dayhour') : ' '; + print $object->date_export ? img_picto($langs->trans("TransactionExportDesc"), 'fa-file-export', 'class="pictofixedwidth opacitymedium"').dol_print_date($object->date_export, 'dayhour') : ' '; print ''; print ''; @@ -859,7 +859,7 @@ if ($action == 'create') { print ''; print '' . $langs->trans("DateValidation") . ''; print ''; - print $object->date_validation ? img_picto($langs->trans("TransactionBlockedLockedDesc"), 'fa-lock', 'class="pictofixedwidth"').dol_print_date($object->date_validation, 'dayhour') : ' '; + print $object->date_validation ? img_picto($langs->trans("TransactionBlockedLockedDesc"), 'fa-lock', 'class="pictofixedwidth opacitymedium"').dol_print_date($object->date_validation, 'dayhour') : ' '; print ''; print ''; diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index 93e89ca5abf..1eb4791d61d 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -1272,6 +1272,12 @@ while ($i < min($num, $limit)) { $object->piece_num = $line->piece_num; $object->ref = $line->ref; print $object->getNomUrl(1, '', 0, '', 1); + if (!empty($line->date_export)) { + print img_picto($langs->trans("DateExport").": ".dol_print_date($line->date_export, 'dayhour')." (".$langs->trans("TransactionExportDesc").")", 'fa-file-export', 'class="paddingleft pictofixedwidth opacitymedium"'); + } + if (!empty($line->date_validation)) { + print img_picto($langs->trans("DateValidation").": ".dol_print_date($line->date_validation, 'dayhour')." (".$langs->trans("TransactionBlockedLockedDesc").")", 'fa-lock', 'class="paddingleft pictofixedwidth opacitymedium"'); + } print ''; if (!$i) { $totalarray['nbfield']++; diff --git a/htdocs/accountancy/bookkeeping/listbyaccount.php b/htdocs/accountancy/bookkeeping/listbyaccount.php index 9de49b6aa8c..c55f773781d 100644 --- a/htdocs/accountancy/bookkeeping/listbyaccount.php +++ b/htdocs/accountancy/bookkeeping/listbyaccount.php @@ -1421,10 +1421,10 @@ while ($i < min($num, $limit)) { $object->ref = $line->ref; print $object->getNomUrl(1, '', 0, '', 1); if (!empty($line->date_export)) { - print img_picto($langs->trans("DateExport").": ".dol_print_date($line->date_export, 'dayhour')." (".$langs->trans("TransactionExportDesc").")", 'fa-file-export', 'class="paddingleft pictofixedwidth"'); + print img_picto($langs->trans("DateExport").": ".dol_print_date($line->date_export, 'dayhour')." (".$langs->trans("TransactionExportDesc").")", 'fa-file-export', 'class="paddingleft pictofixedwidth opacitymedium"'); } if (!empty($line->date_validation)) { - print img_picto($langs->trans("DateValidation").": ".dol_print_date($line->date_validation, 'dayhour')." (".$langs->trans("TransactionBlockedLockedDesc").")", 'fa-lock', 'class="paddingleft pictofixedwidth"'); + print img_picto($langs->trans("DateValidation").": ".dol_print_date($line->date_validation, 'dayhour')." (".$langs->trans("TransactionBlockedLockedDesc").")", 'fa-lock', 'class="paddingleft pictofixedwidth opacitymedium"'); } print ''; if (!$i) { From 0333daa8a8484226f6121eae581dd9892252cdef Mon Sep 17 00:00:00 2001 From: MDW Date: Wed, 26 Nov 2025 15:48:36 +0100 Subject: [PATCH 02/53] Qual: Update PHP-CS-Fixer configuration and DolibarrModules class - Update PHP-CS-Fixer configuration to replace deprecated 'visibility_required' rule with 'modifier_keywords' - Update DolibarrModules class to use const instead of public const for PHP 7.0 compatibility (revert recent change) --- dev/tools/php-cs-fixer/.php-cs-fixer.dist.php | 38 ++++++++++--------- htdocs/core/modules/DolibarrModules.class.php | 18 ++++----- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/dev/tools/php-cs-fixer/.php-cs-fixer.dist.php b/dev/tools/php-cs-fixer/.php-cs-fixer.dist.php index 5b97cfb88be..e5345d9d723 100644 --- a/dev/tools/php-cs-fixer/.php-cs-fixer.dist.php +++ b/dev/tools/php-cs-fixer/.php-cs-fixer.dist.php @@ -1,20 +1,22 @@ + */ /* PHP 7.0 */ $finder = (new PhpCsFixer\Finder()) -->in(__DIR__) -->exclude([ - 'core/includes', - 'custom', - 'documents', - 'doctemplates', - 'vendor', - 'install/doctemplates', - 'htdocs/custom', - 'htdocs/includes', - 'htdocs/install/doctemplates', -]) -->notPath('vendor'); + ->in(__DIR__) + ->exclude([ + 'core/includes', + 'custom', + 'documents', + 'doctemplates', + 'vendor', + 'install/doctemplates', + 'htdocs/custom', + 'htdocs/includes', + 'htdocs/install/doctemplates', + ]) + ->notPath('vendor'); /* PHP 7.4+ */ @@ -43,8 +45,11 @@ return (new PhpCsFixer\Config()) // So we use target PHP70 for the moment. '@PHP70Migration' => true, //'@PHP71Migration' => true, - // Avoid adding public to const (incompatible with PHP 7.0): - 'visibility_required' => ['elements'=>['property', 'method']], + // Avoid adding public to const (incompatible with PHP 7.0): + 'visibility_required' => ['elements' => ['property', 'method']], + // Replace deprecated 'visibility_required' + 'modifier_keywords' => ['elements' => ['property', 'method']], + //'strict_param' => true, //'array_syntax' => ['syntax' => 'short'], @@ -59,5 +64,4 @@ return (new PhpCsFixer\Config()) ->setIndent("\t") // All files MUST use the Unix LF line ending only // https://www.php-fig.org/psr/psr-12/#22-files - ->setLineEnding("\n") -; + ->setLineEnding("\n"); diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index b425ea09617..e5ad6f19dba 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -139,16 +139,16 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it */ public $rights_class; - public const URL_FOR_BLACKLISTED_MODULES = 'https://ping.dolibarr.org/modules-blacklist.txt'; + const URL_FOR_BLACKLISTED_MODULES = 'https://ping.dolibarr.org/modules-blacklist.txt'; - public const KEY_ID = 0; - public const KEY_LABEL = 1; - public const KEY_TYPE = 2; // deprecated - public const KEY_DEFAULT = 3; - public const KEY_FIRST_LEVEL = 4; - public const KEY_SECOND_LEVEL = 5; - public const KEY_MODULE = 6; - public const KEY_ENABLED = 7; + const KEY_ID = 0; + const KEY_LABEL = 1; + const KEY_TYPE = 2; // deprecated + const KEY_DEFAULT = 3; + const KEY_FIRST_LEVEL = 4; + const KEY_SECOND_LEVEL = 5; + const KEY_MODULE = 6; + const KEY_ENABLED = 7; /** * @var array|int<1,1> Module menu entries (1 means the menu entries are not declared into module descriptor but are hardcoded into menu manager) From 57431464f55832626c3d733cbc1eede55a3ea824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Thu, 27 Nov 2025 09:30:31 +0100 Subject: [PATCH 03/53] fix warning in upgrade2.php --- htdocs/install/upgrade2.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index 8f32f43092a..c49f7c706ce 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -4568,7 +4568,7 @@ function migrate_productlot_path() if ($dir) { $lot->id = $obj->rowid; - $lot->ref = $obj->id; // No ref for the moment + $lot->ref = $obj->rowid; // No ref for the moment $lot->batch = $obj->batch; $lot->entity = $obj->entity; $lot->fk_product = $obj->fk_product; From b17f37bc93117835cef4928187b95138af622a36 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 27 Nov 2025 10:47:50 +0100 Subject: [PATCH 04/53] Debug v23 --- htdocs/install/upgrade2.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index 8f32f43092a..7bb79a5572d 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -683,6 +683,7 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ 'MAIN_MODULE_BLOCKEDLOG' => 'noboxes', 'MAIN_MODULE_DON' => 'newboxdefonly', 'MAIN_MODULE_ECM' => 'newboxdefonly', + 'MAIN_MODULE_EVENTORGANIZATION' => 'newboxdefonly', 'MAIN_MODULE_EXPENSEREPORT' => 'newboxdefonly', 'MAIN_MODULE_FACTURE' => 'newboxdefonly', 'MAIN_MODULE_FOURNISSEUR' => 'newboxdefonly', From 889a716aeee9e78732427d0259be30ea9ece6194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Thu, 27 Nov 2025 12:49:00 +0100 Subject: [PATCH 05/53] add modulepart for direct print capabilities --- htdocs/core/class/html.formfile.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 6ab8eaca887..d0d59dcdeaa 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -508,7 +508,7 @@ class FormFile $printer = 0; // The direct print feature is implemented only for such elements - if (in_array($modulepart, array('contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket'))) { + if (in_array($modulepart, array('contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo'))) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); } From f757b08f97ef293a4f09978f5fc6b1f9ea9d7fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Thu, 27 Nov 2025 14:50:14 +0100 Subject: [PATCH 06/53] add project --- htdocs/core/class/html.formfile.class.php | 3 ++- htdocs/projet/card.php | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index d0d59dcdeaa..1a6d66e60c7 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -507,8 +507,9 @@ class FormFile } $printer = 0; + $modulepartssupported = ['project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; // The direct print feature is implemented only for such elements - if (in_array($modulepart, array('contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo'))) { + if (in_array($modulepart, $modulepartssupported)) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); } diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index e97160987bf..b53a8ee9954 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -614,6 +614,9 @@ if (empty($reshook)) { } } + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + // Actions to send emails $triggersendname = 'PROJECT_SENTBYMAIL'; $paramname = 'id'; From 9ffc224897d1890886db36a6597d9733665b489a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Thu, 27 Nov 2025 14:53:18 +0100 Subject: [PATCH 07/53] add project --- htdocs/core/class/html.formfile.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 1a6d66e60c7..fd410086b9a 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -507,9 +507,9 @@ class FormFile } $printer = 0; - $modulepartssupported = ['project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; + $supportedmoduleparts = ['project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; // The direct print feature is implemented only for such elements - if (in_array($modulepart, $modulepartssupported)) { + if (in_array($modulepart, $supportedmoduleparts)) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); } From dc85a6756b79d9d4576f02c5687d05b8b4b1d8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Thu, 27 Nov 2025 20:55:45 +0100 Subject: [PATCH 08/53] add more --- htdocs/core/class/html.formfile.class.php | 2 +- htdocs/ticket/card.php | 2 ++ htdocs/user/card.php | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index fd410086b9a..2ecbef23f41 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -507,7 +507,7 @@ class FormFile } $printer = 0; - $supportedmoduleparts = ['project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; + $supportedmoduleparts = ['user', 'project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; // The direct print feature is implemented only for such elements if (in_array($modulepart, $supportedmoduleparts)) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); diff --git a/htdocs/ticket/card.php b/htdocs/ticket/card.php index 4b9c98d7bf0..cf4c724e88f 100644 --- a/htdocs/ticket/card.php +++ b/htdocs/ticket/card.php @@ -688,6 +688,8 @@ if (empty($reshook)) { $action = 'view'; } + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; $permissiondellink = $user->hasRight('ticket', 'write'); include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once' diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 241f56d47ef..a3c307bc880 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -879,6 +879,9 @@ if (empty($reshook)) { // Actions to build doc $upload_dir = $conf->user->dir_output; include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; } From 4f3e23516fd2175d71090f9404d268079c57c410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Thu, 27 Nov 2025 21:27:59 +0100 Subject: [PATCH 09/53] add ficheuinter --- htdocs/core/class/html.formfile.class.php | 2 +- htdocs/fichinter/card.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 2ecbef23f41..36b0d175849 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -507,7 +507,7 @@ class FormFile } $printer = 0; - $supportedmoduleparts = ['user', 'project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; + $supportedmoduleparts = ['ficheinter', 'user', 'project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; // The direct print feature is implemented only for such elements if (in_array($modulepart, $supportedmoduleparts)) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index 089374b8b6e..280329b3f0b 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -66,14 +66,14 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; // Load translation files required by the page $langs->loadLangs(array('bills', 'companies', 'interventions', 'stocks')); -$id = GETPOSTINT('id'); -$ref = GETPOST('ref', 'alpha'); +$id = GETPOSTINT('id'); +$ref = GETPOST('ref', 'alpha'); $ref_client = GETPOST('ref_client', 'alpha'); $socid = GETPOSTINT('socid'); $contratid = GETPOSTINT('contratid'); -$action = GETPOST('action', 'alpha'); -$cancel = GETPOST('cancel', 'alpha'); -$confirm = GETPOST('confirm', 'alpha'); +$action = GETPOST('action', 'alpha'); +$cancel = GETPOST('cancel', 'alpha'); +$confirm = GETPOST('confirm', 'alpha'); $backtopage = GETPOST('backtopage', 'alpha'); $mesg = GETPOST('msg', 'alpha'); From b33386ba0dbe4e076a5bfd4da20bd9ca56055240 Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 22:06:51 +0100 Subject: [PATCH 10/53] qual: Update phpstan-baseline.neon to remove unresolvable type issues Removed multiple entries related to unresolvable types in dol_sort_array function calls and property assignments. --- dev/build/phpstan/phpstan-baseline.neon | 72 ------------------------- 1 file changed, 72 deletions(-) diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index 8b5d79a5e40..678d591e9ee 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -1038,18 +1038,6 @@ parameters: count: 1 path: ../../../htdocs/admin/website.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 1 - path: ../../../htdocs/admin/workflow.php - - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 1 - path: ../../../htdocs/admin/workflow.php - - message: '#^Loose comparison using \=\= between ''edit'' and ''edit'' will always evaluate to true\.$#' identifier: equal.alwaysTrue @@ -1596,24 +1584,12 @@ parameters: count: 1 path: ../../../htdocs/categories/class/categorie.class.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 1 - path: ../../../htdocs/categories/class/categorie.class.php - - message: '#^Property Categorie\:\:\$cats \(array\\) does not accept array\\.$#' identifier: assign.propertyType count: 2 path: ../../../htdocs/categories/class/categorie.class.php - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 1 - path: ../../../htdocs/categories/class/categorie.class.php - - message: '#^If condition is always true\.$#' identifier: if.alwaysTrue @@ -5646,12 +5622,6 @@ parameters: count: 2 path: ../../../htdocs/core/class/html.form.class.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 3 - path: ../../../htdocs/core/class/html.form.class.php - - message: '#^Parameter \#15 \$excludeids of method Form\:\:select_company\(\) expects array\, array\ given\.$#' identifier: argument.type @@ -5718,12 +5688,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/html.form.class.php - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 3 - path: ../../../htdocs/core/class/html.form.class.php - - message: '#^Right side of && is always true\.$#' identifier: booleanAnd.rightAlwaysTrue @@ -5760,24 +5724,12 @@ parameters: count: 1 path: ../../../htdocs/core/class/html.formcompany.class.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 1 - path: ../../../htdocs/core/class/html.formcompany.class.php - - message: '#^Parameter \#3 \$selected of method Form\:\:multiselectarray\(\) expects array\, array\\|int\> given\.$#' identifier: argument.type count: 1 path: ../../../htdocs/core/class/html.formcompany.class.php - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 1 - path: ../../../htdocs/core/class/html.formcompany.class.php - - message: '#^Variable \$idprof might not be defined\.$#' identifier: variable.undefined @@ -10794,18 +10746,6 @@ parameters: count: 1 path: ../../../htdocs/main.inc.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 1 - path: ../../../htdocs/margin/agentMargins.php - - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 1 - path: ../../../htdocs/margin/agentMargins.php - - message: '#^Ternary operator condition is always false\.$#' identifier: ternary.alwaysFalse @@ -15666,12 +15606,6 @@ parameters: count: 3 path: ../../../htdocs/user/class/user.class.php - - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' - identifier: argument.unresolvableType - count: 1 - path: ../../../htdocs/user/class/user.class.php - - message: '#^Property User\:\:\$rights \(stdClass\) in empty\(\) is not falsy\.$#' identifier: empty.property @@ -15726,12 +15660,6 @@ parameters: count: 4 path: ../../../htdocs/user/class/user.class.php - - - message: '#^Return type of call to function dol_sort_array contains unresolvable type\.$#' - identifier: function.unresolvableReturnType - count: 1 - path: ../../../htdocs/user/class/user.class.php - - message: '#^Variable \$whereforadd in empty\(\) always exists and is not falsy\.$#' identifier: empty.variable From 04bc3ee058624ff33377e704dd1e439976261e56 Mon Sep 17 00:00:00 2001 From: Steph501 Date: Thu, 27 Nov 2025 23:05:21 +0100 Subject: [PATCH 11/53] FIX #36447 Email Collector subject/body exclusion filters not working The '!' prefix was removed at line 1369-1373 before being tested at lines 1398 and 1406, causing exclusion filters to never work. This fix uses the $not variable (already set correctly) instead of re-testing for '!' on the modified rulevalue. --- htdocs/emailcollector/class/emailcollector.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index 9c4368b286a..28154fa95c6 100644 --- a/htdocs/emailcollector/class/emailcollector.class.php +++ b/htdocs/emailcollector/class/emailcollector.class.php @@ -1395,17 +1395,17 @@ class EmailCollector extends CommonObject array_push($criteria, array($not."CC" => $rule['rulevalue'])); } if ($rule['type'] == 'subject') { - if (strpos($rule['rulevalue'], '!') === 0) { + if ($not) { //array_push($criteria, array("NOT SUBJECT" => $rule['rulevalue'])); - $searchfilterexcludesubjectarray[] = preg_replace('/^!/', '', $rule['rulevalue']); + $searchfilterexcludesubjectarray[] = $rule['rulevalue']; } else { array_push($criteria, array("SUBJECT" => $rule['rulevalue'])); } } if ($rule['type'] == 'body') { - if (strpos($rule['rulevalue'], '!') === 0) { + if ($not) { //array_push($criteria, array("NOT BODY" => $rule['rulevalue'])); - $searchfilterexcludebodyarray[] = preg_replace('/^!/', '', $rule['rulevalue']); + $searchfilterexcludebodyarray[] = $rule['rulevalue']; } else { array_push($criteria, array("BODY" => $rule['rulevalue'])); } From 53baeeaf67b32734fb605f7d27f2b31e7d6d20dc Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 22:03:46 +0100 Subject: [PATCH 12/53] Qual: Improve type hinting for phpstan in dol_sort_array() #Qual: Improve type hinting for phpstan in dol_sort_array() - Improve phpdoc for phpstan in dol_sort_array() --- htdocs/core/lib/functions.lib.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index a2136039999..a44357ecd92 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -5691,7 +5691,7 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srco 'accounting_account' => 'infobox-bank_account', 'accountline' => 'infobox-bank_account', 'accountancy' => 'infobox-bank_account', - 'admin'=> 'opacitymedium', + 'admin' => 'opacitymedium', 'asset' => 'infobox-bank_account', 'bank_account' => 'infobox-bank_account', 'bill' => 'infobox-commande', @@ -8445,7 +8445,8 @@ function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, } // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule. - if (empty($vatrule) && (($seller_country_code == $buyer_country_code) + if (empty($vatrule) && ( + ($seller_country_code == $buyer_country_code) || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC'))) || (in_array($seller_country_code, array('MQ', 'GP')) && in_array($buyer_country_code, array('MQ', 'GP'))) // We should be able to manage the case of MQ, GP, ... with a deicated vat rate at previous step. )) { // Warning ->country_code not always defined @@ -8517,7 +8518,8 @@ function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, // Allow an external module to bypass the calculation of prices $parameters = array('vatvalue' => $vatvalue, 'vatrule' => $vatrule); - $tmpobject = null; $tmpaction = ''; + $tmpobject = null; + $tmpaction = ''; // @phan-suppress-next-line PhanPluginConstantVariableNull $reshook = $hookmanager->executeHooks('get_default_tva', $parameters, $tmpobject, $tmpaction); // @phan-suppress-current-line PhanPluginConstantVariableNull if ($reshook > 0 && !empty($hookmanager->resArray['vatvalue'])) { From bacfd43079f1771b2100425bc5dab2160e7bddae Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 22:58:26 +0100 Subject: [PATCH 13/53] qual: Add type hint for $arraydata in select_juridicalstatus method This change adds a type hint for the $arraydata variable in the select_juridicalstatus method for phpstan --- htdocs/core/class/html.formcompany.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/class/html.formcompany.class.php b/htdocs/core/class/html.formcompany.class.php index 4018933ed7e..4a754e6a1a8 100644 --- a/htdocs/core/class/html.formcompany.class.php +++ b/htdocs/core/class/html.formcompany.class.php @@ -582,6 +582,7 @@ class FormCompany extends Form if ($num) { $i = 0; $country = ''; + /** @var array $arraydata */ $arraydata = array(); while ($i < $num) { $obj = $this->db->fetch_object($resql); From e68b0f23d4a51362814a08f9bcf9bf669a3fcbd6 Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 23:14:48 +0100 Subject: [PATCH 14/53] Qual: Change array assignment for phpstan type deduction --- htdocs/core/class/html.form.class.php | 36 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 52e1f42ed13..69a61b22055 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1000,6 +1000,7 @@ class Form $langs->load("dict"); $out = ''; + /** @var array $countryArray */ $countryArray = array(); $favorite = array(); $label = array(); @@ -1020,12 +1021,15 @@ class Form while ($i < $num) { $obj = $this->db->fetch_object($resql); - $countryArray[$i]['rowid'] = $obj->rowid; - $countryArray[$i]['code_iso'] = $obj->code_iso; - $countryArray[$i]['code_iso3'] = $obj->code_iso3; - $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : '')); - $countryArray[$i]['favorite'] = $obj->favorite; - $countryArray[$i]['eec'] = $obj->eec; + $countryArray[$i] + = array( + 'rowid' => (int) $obj->rowid, + 'code_iso' => $obj->code_iso, + 'code_iso3' => $obj->code_iso3, + 'label' => ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : '')), + 'favorite' => $obj->favorite, + 'eec' => $obj->eec, + ); $favorite[$i] = $obj->favorite; $label[$i] = dol_string_unaccent($countryArray[$i]['label']); $i++; @@ -4762,9 +4766,12 @@ class Form $label = $langs->trans($obj->code); // So translation key SRC_XXX will work } - $tmparray[$obj->rowid]['id'] = (int) $obj->rowid; - $tmparray[$obj->rowid]['code'] = $obj->code; - $tmparray[$obj->rowid]['label'] = $label; + $tmparray[(int) $obj->rowid] + = array( + 'id' => (int) $obj->rowid, + 'code' => $obj->code, + 'label' => $label, + ); $i++; } @@ -5226,10 +5233,13 @@ class Form // If traduction exist, we use it else we take the default label $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : '')); - $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid; - $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code; - $this->cache_transport_mode[$obj->rowid]['label'] = $label; - $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active; + $this->cache_transport_mode[(int) $obj->rowid] + = array( + 'rowid' => (int) $obj->rowid, + 'code' => $obj->code, + 'label' => $label, + 'active' => (int) $obj->active, + ); $i++; } From 55b6364bf6d94a516722fe1579b9ebc5477ce4ca Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 23:15:00 +0100 Subject: [PATCH 15/53] Qual: Change array assignment for phpstan type deduction --- htdocs/categories/class/categorie.class.php | 30 ++++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index b84bacaaed0..cc37c3c2bcd 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -1342,19 +1342,23 @@ class Categorie extends CommonObject $nbcateg = $this->db->num_rows($resql); while ($obj = $this->db->fetch_object($resql)) { - $this->cats[$obj->rowid]['rowid'] = $obj->rowid; - $this->cats[$obj->rowid]['id'] = $obj->rowid; - $this->cats[$obj->rowid]['fk_parent'] = $obj->fk_parent; - $this->cats[$obj->rowid]['label'] = !empty($obj->label_trans) ? $obj->label_trans : $obj->label; - $this->cats[$obj->rowid]['description'] = !empty($obj->description_trans) ? $obj->description_trans : $obj->description; - $this->cats[$obj->rowid]['color'] = $obj->color; - $this->cats[$obj->rowid]['position'] = $obj->position; - $this->cats[$obj->rowid]['visible'] = $obj->visible; - $this->cats[$obj->rowid]['ref_ext'] = $obj->ref_ext; - $this->cats[$obj->rowid]['picto'] = 'category'; - // fields are filled with buildPathFromId later - $this->cats[$obj->rowid]['fullpath'] = ''; - $this->cats[$obj->rowid]['fulllabel'] = ''; + $this->cats[(int) $obj->rowid] + = array( + 'rowid' => (int) $obj->rowid, + 'id' => (int) $obj->rowid, + 'fk_parent' => (int) $obj->fk_parent, + 'label' => !empty($obj->label_trans) ? $obj->label_trans : $obj->label, + 'description' => !empty($obj->description_trans) ? $obj->description_trans : $obj->description, + 'color' => $obj->color, + 'position' => $obj->position, + 'visible' => (int) $obj->visible, + 'ref_ext' => $obj->ref_ext, + 'picto' => 'category', + // fields are filled with buildPathFromId later + 'fullpath' => '', + 'fulllabel' => '', + // 'level' => null, + ); $i++; } } else { From 5117e0995977587750842ca6a482679b4bcf3f58 Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 23:26:02 +0100 Subject: [PATCH 16/53] Qual: Cast properties to string in get_full_arbo method --- htdocs/categories/class/categorie.class.php | 12 ++++++------ htdocs/core/class/html.form.class.php | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index cc37c3c2bcd..96d846ffb62 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -1347,17 +1347,17 @@ class Categorie extends CommonObject 'rowid' => (int) $obj->rowid, 'id' => (int) $obj->rowid, 'fk_parent' => (int) $obj->fk_parent, - 'label' => !empty($obj->label_trans) ? $obj->label_trans : $obj->label, - 'description' => !empty($obj->description_trans) ? $obj->description_trans : $obj->description, - 'color' => $obj->color, - 'position' => $obj->position, + 'label' => !empty($obj->label_trans) ? (string) $obj->label_trans : (string) $obj->label, + 'description' => !empty($obj->description_trans) ? (string) $obj->description_trans : (string) $obj->description, + 'color' => (string) $obj->color, + 'position' => (string) $obj->position, 'visible' => (int) $obj->visible, - 'ref_ext' => $obj->ref_ext, + 'ref_ext' => (string) $obj->ref_ext, 'picto' => 'category', // fields are filled with buildPathFromId later 'fullpath' => '', 'fulllabel' => '', - // 'level' => null, + 'level' => null, ); $i++; } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 69a61b22055..034dfb2e420 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -6854,10 +6854,10 @@ class Form * Show form with transport mode * * @param string $page Page - * @param string $selected Id mode pre-select + * @param int|'' $selected Id mode pre-select * @param string $htmlname Name of select html field - * @param int $active Active or not, -1 = all - * @param int $addempty 1=Add empty entry + * @param int<-1,1> $active Active or not, -1 = all + * @param int<0,1> $addempty 1=Add empty entry * @return void */ public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0) From b37aa3d1c6cf420b113629d15d8df223c29ba03a Mon Sep 17 00:00:00 2001 From: MDW Date: Thu, 27 Nov 2025 23:31:28 +0100 Subject: [PATCH 17/53] Qual: Type casting in select_country and loadCacheInputReason methods --- htdocs/core/class/html.form.class.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 034dfb2e420..be72f9f6b8f 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1024,11 +1024,11 @@ class Form $countryArray[$i] = array( 'rowid' => (int) $obj->rowid, - 'code_iso' => $obj->code_iso, - 'code_iso3' => $obj->code_iso3, - 'label' => ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : '')), - 'favorite' => $obj->favorite, - 'eec' => $obj->eec, + 'code_iso' => (string) $obj->code_iso, + 'code_iso3' => (string) $obj->code_iso3, + 'label' => (string) ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : '')), + 'favorite' => (string) $obj->favorite, + 'eec' => (string) $obj->eec, ); $favorite[$i] = $obj->favorite; $label[$i] = dol_string_unaccent($countryArray[$i]['label']); @@ -4753,6 +4753,7 @@ class Form if ($resql) { $num = $this->db->num_rows($resql); $i = 0; + /** @var array */ $tmparray = array(); while ($i < $num) { $obj = $this->db->fetch_object($resql); @@ -4769,7 +4770,7 @@ class Form $tmparray[(int) $obj->rowid] = array( 'id' => (int) $obj->rowid, - 'code' => $obj->code, + 'code' => (string) $obj->code, 'label' => $label, ); $i++; @@ -5236,8 +5237,8 @@ class Form $this->cache_transport_mode[(int) $obj->rowid] = array( 'rowid' => (int) $obj->rowid, - 'code' => $obj->code, - 'label' => $label, + 'code' => (string) $obj->code, + 'label' => (string) $label, 'active' => (int) $obj->active, ); $i++; From 04ec188cb64f51a42e07e653682824ae22c1e07b Mon Sep 17 00:00:00 2001 From: MDW Date: Fri, 28 Nov 2025 01:46:37 +0100 Subject: [PATCH 18/53] fix: Improve type casting and array initialization in user.class.php - Added explicit type casting for array values - Improved array initialization syntax for better readability and maintainability --- htdocs/user/class/user.class.php | 39 +++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php index 9be513889f6..9b47ff3731b 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -372,7 +372,7 @@ class User extends CommonObject public $lastsearch_values; // To store last saved search criteria for user /** - * @var array|array,admin:int<0,1>,photo:string,fullpath:string,fullname:string,level:int}> Array of User (filled from fetchAll) or Array with hierarchy of user information (filled with get_full_tree() + * @var array|array,admin:int<0,1>,photo:string,fullpath:string,fullname:string,level:int}> Array of User (filled from fetchAll) or Array with hierarchy of user information (filled with get_full_tree()) */ public $users = array(); /** @@ -3923,23 +3923,26 @@ class User extends CommonObject if ($resql) { $i = 0; while ($obj = $this->db->fetch_object($resql)) { - $this->users[$obj->rowid]['rowid'] = $obj->rowid; - $this->users[$obj->rowid]['id'] = $obj->rowid; - $this->users[$obj->rowid]['fk_user'] = $obj->fk_user; - $this->users[$obj->rowid]['fk_soc'] = $obj->fk_soc; - $this->users[$obj->rowid]['firstname'] = $obj->firstname; - $this->users[$obj->rowid]['lastname'] = $obj->lastname; - $this->users[$obj->rowid]['login'] = $obj->login; - $this->users[$obj->rowid]['statut'] = $obj->statut; - $this->users[$obj->rowid]['entity'] = $obj->entity; - $this->users[$obj->rowid]['email'] = $obj->email; - $this->users[$obj->rowid]['gender'] = $obj->gender; - $this->users[$obj->rowid]['admin'] = $obj->admin; - $this->users[$obj->rowid]['photo'] = $obj->photo; - // fields are filled with build_path_from_id_user - $this->users[$obj->rowid]['fullpath'] = ''; - $this->users[$obj->rowid]['fullname'] = ''; - $this->users[$obj->rowid]['level'] = 0; + $this->users[(int) $obj->rowid] + = array( + 'rowid' => (int) $obj->rowid, + 'id' => (int) $obj->rowid, + 'fk_user' => (int) $obj->fk_user, + 'fk_soc' => (int) $obj->fk_soc, + 'firstname' => (string) $obj->firstname, + 'lastname' => (string) $obj->lastname, + 'login' => (string) $obj->login, + 'statut' => (int) $obj->statut, + 'entity' => (int) $obj->entity, + 'email' => (string) $obj->email, + 'gender' => (string) $obj->gender, + 'admin' => (int) $obj->admin, + 'photo' => (string) $obj->photo, + // fields are filled with build_path_from_id_user + 'fullpath' => '', + 'fullname' => '', + 'level' => 0, + ); $i++; } } else { From 44acb8eb4700abb19e6dff374d2d6dbadad46514 Mon Sep 17 00:00:00 2001 From: MDW Date: Fri, 28 Nov 2025 01:49:42 +0100 Subject: [PATCH 19/53] qual: Add type hint for group_list array Add a type hint for the $group_list array for phpstan. --- htdocs/margin/agentMargins.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/htdocs/margin/agentMargins.php b/htdocs/margin/agentMargins.php index 43496922547..7c9fcc45315 100644 --- a/htdocs/margin/agentMargins.php +++ b/htdocs/margin/agentMargins.php @@ -280,23 +280,24 @@ if ($result) { print "\n"; if ($num > 0) { + /** @var array $group_list */ $group_list = array(); while ($objp = $db->fetch_object($result)) { if ($agentid > 0) { - $group_id = $objp->socid; + $group_id = (int) $objp->socid; } else { - $group_id = $objp->agent; + $group_id = (int) $objp->agent; } if (!isset($group_list[$group_id])) { if ($agentid > 0) { - $group_name = $objp->name; + $group_name = (string) $objp->name; $companystatic->id = $objp->socid; $companystatic->name = $objp->name; $companystatic->client = $objp->client; $group_htmlname = $companystatic->getNomUrl(1, 'customer'); } else { - $group_name = $objp->lastname; + $group_name = (string) $objp->lastname; $userstatic->fetch($objp->agent); $group_htmlname = $userstatic->getFullName($langs, 0, 0, 0); } @@ -317,15 +318,15 @@ if ($result) { } else { if ($obj_seller = $db->fetch_object($resql_seller)) { if ($obj_seller->nb > 0) { - $seller_nb = $obj_seller->nb; + $seller_nb = (int) $obj_seller->nb; } } } } - $group_list[$group_id]['selling_price'] += $objp->selling_price / $seller_nb; - $group_list[$group_id]['buying_price'] += $objp->buying_price / $seller_nb; - $group_list[$group_id]['marge'] += $objp->marge / $seller_nb; + $group_list[$group_id]['selling_price'] += (float) $objp->selling_price / $seller_nb; + $group_list[$group_id]['buying_price'] += (float) $objp->buying_price / $seller_nb; + $group_list[$group_id]['marge'] += (float) $objp->marge / $seller_nb; } // sort group array by sortfield From 19637c1996908dc45bf5abc5725138b2b102b9ed Mon Sep 17 00:00:00 2001 From: MDW Date: Fri, 28 Nov 2025 01:55:07 +0100 Subject: [PATCH 20/53] qual: Update type hints and casting in select_juridicalstatus method - Changed type hint for $arraydata - Added explicit casting for `code` and `country_code` in the array assignment --- htdocs/core/class/html.formcompany.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.formcompany.class.php b/htdocs/core/class/html.formcompany.class.php index 4a754e6a1a8..3131b264e5d 100644 --- a/htdocs/core/class/html.formcompany.class.php +++ b/htdocs/core/class/html.formcompany.class.php @@ -582,7 +582,7 @@ class FormCompany extends Form if ($num) { $i = 0; $country = ''; - /** @var array $arraydata */ + /** @var array $arraydata */ $arraydata = array(); while ($i < $num) { $obj = $this->db->fetch_object($resql); @@ -590,7 +590,7 @@ class FormCompany extends Form if ($obj->code) { // We exclude empty line, we will add it later $labelcountry = (($langs->trans("Country" . $obj->country_code) != "Country" . $obj->country_code) ? $langs->trans("Country" . $obj->country_code) : $obj->country); $labeljs = (($langs->trans("JuridicalStatus" . $obj->code) != "JuridicalStatus" . $obj->code) ? $langs->trans("JuridicalStatus" . $obj->code) : ($obj->label != '-' ? $obj->label : '')); // $obj->label is already in output charset (converted by database driver) - $arraydata[$obj->code] = array('code' => $obj->code, 'label' => $labeljs, 'label_sort' => $labelcountry . '_' . $labeljs, 'country_code' => $obj->country_code, 'country' => $labelcountry); + $arraydata[(int) $obj->code] = array('code' => (int) $obj->code, 'label' => $labeljs, 'label_sort' => $labelcountry . '_' . $labeljs, 'country_code' => (string) $obj->country_code, 'country' => $labelcountry); } $i++; } From 05c32bb12d58112e711e5c180ad231782ff99523 Mon Sep 17 00:00:00 2001 From: MDW Date: Fri, 28 Nov 2025 01:57:26 +0100 Subject: [PATCH 21/53] Qual: Cast label to string to ensure type consistency (phpstan) --- htdocs/core/class/html.form.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index be72f9f6b8f..1527041ae58 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -4759,7 +4759,7 @@ class Form $obj = $this->db->fetch_object($resql); // Si traduction existe, on l'utilise, sinon on prend le libelle par default - $label = ($obj->label != '-' ? $obj->label : ''); + $label = ($obj->label != '-' ? (string) $obj->label : ''); if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) { $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work } From b362b6d395b22caa4e963d7b82f766eb7e5f483c Mon Sep 17 00:00:00 2001 From: MDW Date: Fri, 28 Nov 2025 02:51:58 +0100 Subject: [PATCH 22/53] Qual: Add types for $workflow and $workflowcodes. --- htdocs/admin/workflow.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/htdocs/admin/workflow.php b/htdocs/admin/workflow.php index 0c568e70c99..76c38f94ff4 100644 --- a/htdocs/admin/workflow.php +++ b/htdocs/admin/workflow.php @@ -3,7 +3,7 @@ * Copyright (C) 2004 Eric Seigne * Copyright (C) 2005-2021 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -65,9 +65,11 @@ if (preg_match('/del(.*)/', $action, $reg)) { } } + // List of workflow we can enable clearstatcache(); +/** @var array,reloadpage?:int<0,1>}> $workflowcodes */ $workflowcodes = array( // Automatic creation 'WORKFLOW_PROPAL_AUTOCREATE_ORDER' => array( @@ -227,6 +229,7 @@ $workflowcodes = array( if (!empty($conf->modules_parts['workflow']) && is_array($conf->modules_parts['workflow'])) { foreach ($conf->modules_parts['workflow'] as $workflow) { + /** @var array,reloadpage?:int<0,1>}> $workflow */ $workflowcodes = array_merge($workflowcodes, $workflow); } } From 87fbbce618d07781fc42a822d8b9d2acbb7647a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 28 Nov 2025 07:59:10 +0100 Subject: [PATCH 23/53] Update upgrade2.php --- htdocs/install/upgrade2.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index c49f7c706ce..08055c71d49 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -4567,8 +4567,8 @@ function migrate_productlot_path() } if ($dir) { - $lot->id = $obj->rowid; - $lot->ref = $obj->rowid; // No ref for the moment + $lot->id = (int) $obj->rowid; + $lot->ref = (string) $obj->rowid; // No ref for the moment $lot->batch = $obj->batch; $lot->entity = $obj->entity; $lot->fk_product = $obj->fk_product; From 09aca511e8cdd9d5fb77567bffa6e0308d2dc149 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 28 Nov 2025 08:55:11 +0100 Subject: [PATCH 24/53] Debug v23 --- htdocs/compta/facture/card.php | 17 +++++------------ htdocs/langs/en_US/bills.lang | 2 +- htdocs/theme/eldy/global.inc.php | 7 +++++++ htdocs/theme/md/style.css.php | 15 +++++++++++++-- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 8c928751d46..fbd76efd115 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -100,11 +100,6 @@ $cancel = GETPOST('cancel', 'alpha'); $backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used $backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used $lineid = GETPOSTINT('lineid'); -$userid = GETPOSTINT('userid'); -$search_ref = GETPOST('sf_ref', 'alpha') ? GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha'); -$search_societe = GETPOST('search_societe', 'alpha'); -$search_montant_ht = GETPOST('search_montant_ht', 'alpha'); -$search_montant_ttc = GETPOST('search_montant_ttc', 'alpha'); $origin = GETPOST('origin', 'alpha'); $originid = (GETPOSTINT('originid') ? GETPOSTINT('originid') : GETPOSTINT('origin_id')); // For backward compatibility $fac_rec = GETPOSTINT('fac_rec'); @@ -123,8 +118,6 @@ $hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString( // Number of lines for predefined product/service choices $NBLINES = 4; -$usehm = getDolGlobalInt('MAIN_USE_HOURMIN_IN_DATE_RANGE'); - $object = new Facture($db); $extrafields = new ExtraFields($db); @@ -1274,7 +1267,7 @@ if (empty($reshook)) { $sourceinvoice = GETPOSTINT('fac_avoir'); if (!($sourceinvoice > 0) && !getDolGlobalString('INVOICE_CREDIT_NOTE_STANDALONE')) { $error++; - setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CorrectInvoice")), null, 'errors'); + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceAvoirAskCombo")), null, 'errors'); $action = 'create'; } @@ -4309,7 +4302,7 @@ if ($action == 'create') { }); '; $text = ' '; - $text .= ' 0 ? 'checked' : '').' /> "; - //print '
'; - print '
0 ? 'checked' : '').' />
"; + print '
0 ? 'checked' : '').' />
"; + print '
0 ? 'checked' : '').' />
"; + // TODO Add a checkbox: "Automatically consume the credit note to close the corrected invoice" print ''; print ''."\n"; diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index ef03e65b1aa..cd6131ffa1a 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -30,7 +30,7 @@ InvoiceReplacementShort=Replacement InvoiceReplacementAsk=Replacement invoice for invoice InvoiceReplacementDesc=Replacement invoice is used to completely replace an invoice with no payment already received.

Note: Only invoices with no payment on it can be replaced. If the invoice you replace is not yet closed, it will be automatically closed to 'abandoned'. InvoiceAvoir=Credit note -InvoiceAvoirAsk=Credit note +InvoiceAvoirAsk=Credit note from InvoiceAvoirAskCombo=Invoice to correct InvoiceAvoirDesc=The credit note is a negative invoice used to correct the fact that an invoice shows an amount that differs from the amount actually paid (eg the customer paid too much by mistake, or will not pay the complete amount since some products were returned). invoiceAvoirWithLines=Create Credit Note with lines from the origin invoice diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index b010c0555f1..fe005609ee9 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1241,6 +1241,9 @@ td.wordbreak img, td.wordbreakimp img { .marginleftlarge { margin-: 20px !important; } +.marginleftlargeondesktop { + margin-: 20px; +} .paddinglarge { padding: 6px !important; } @@ -2280,6 +2283,10 @@ datalist { font-size: !important; } + .marginleftlargeondesktop { + margin-: 0; + } + div#login_left, div#login_right { min-width: 150px !important; max-width: 240px !important; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 0369cb6fadb..3e2657d6a1b 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1397,6 +1397,9 @@ td.wordbreak img, td.wordbreakimp img { .marginleftlarge { margin-: 20px !important; } +.marginleftlargeondesktop { + margin-: 20px; +} .paddinglarge { padding: 6px !important; } @@ -1587,8 +1590,12 @@ span.fa.fa-plus-circle.paddingleft { margin-left: 1px; } .listofinvoicetype { - height: 28px; + min-height: 1.8em; vertical-align: middle; + padding-top: 7px; + padding-bottom: 1px; + display: flex; + align-items: center; } .divsocialnetwork:not(:last-child) { padding-: 20px; @@ -2395,6 +2402,10 @@ select.widthcentpercentminusxx, span.widthcentpercentminusxx:not(.select2-select font-size: !important; } + .marginleftlargeondesktop { + margin-: 0; + } + .login_vertical_align { padding-left: 0; } @@ -2436,7 +2447,7 @@ select.widthcentpercentminusxx, span.widthcentpercentminusxx:not(.select2-select height: 40px !important; } div.tabBar .listofinvoicetype table tr, div.tabBar .listofinvoicetype table tr td { - height: 28px !important; + height: 2.2em !important; } div.tabs div.tab a.tab { From cd5e0b7e9dc237bf44ab4ebc1347a969db46a3e5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 28 Nov 2025 09:05:14 +0100 Subject: [PATCH 25/53] Doc --- htdocs/compta/facture/card.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index fbd76efd115..79b22a73e64 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -4320,7 +4320,8 @@ if ($action == 'create') { print '
'; print '
0 ? 'checked' : '').' />
"; print '
0 ? 'checked' : '').' />
"; - // TODO Add a checkbox: "Automatically consume the credit note to close the corrected invoice" + // Adding a checkbox: "Automatically consume the credit note to close the corrected invoice" is better to be into + // the confirm popup when we validate the credit note print '
'; print ''."\n"; From 6c54e4792ba0b903c246259852933827d9811ea8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 28 Nov 2025 09:17:34 +0100 Subject: [PATCH 26/53] CSS --- htdocs/core/class/html.form.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 52e1f42ed13..8852e4804e2 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -2107,7 +2107,7 @@ class Form dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG); $resql = $this->db->query($sql); if ($resql) { - print ''; $num = $this->db->num_rows($resql); $qualifiedlines = $num; From 66d79d69afb11e0c8c4ba90be173bc32d4477550 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 28 Nov 2025 10:28:25 +0100 Subject: [PATCH 27/53] Doc --- .../blockedlog/admin/blockedlog_archives.php | 18 +++++++++++------- htdocs/langs/en_US/blockedlog.lang | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/htdocs/blockedlog/admin/blockedlog_archives.php b/htdocs/blockedlog/admin/blockedlog_archives.php index 7dc47a0fbfc..885d5cd5c4a 100644 --- a/htdocs/blockedlog/admin/blockedlog_archives.php +++ b/htdocs/blockedlog/admin/blockedlog_archives.php @@ -169,7 +169,7 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x' include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; -if (GETPOST('action') == 'upload' && $user->hasRight('blockedlog', 'read')) { // read is read/upload for blockedlog +if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { // read is read/export for blockedlog $error = 0; $previoushash = ''; @@ -184,16 +184,20 @@ if (GETPOST('action') == 'upload' && $user->hasRight('blockedlog', 'read')) { / $error++; } + $dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 1); + $datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 12); + + if ($datee >= dol_now()) { + setEventMessages($langs->trans("ErrorPeriodMustBePastToAllowExport"), null, "errors"); + $error++; + } + if (!$error) { // Get the ID of the first line qualified $sql = "SELECT rowid,date_creation,tms,user_fullname,action,amounts,element,fk_object,date_object,ref_object,signature,fk_user,object_data"; $sql .= " FROM ".MAIN_DB_PREFIX."blockedlog"; $sql .= " WHERE entity = ".((int) $conf->entity); - if (GETPOSTINT('monthtoexport') > 0 || GETPOSTINT('yeartoexport') > 0) { - $dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 1); - $datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 12); - $sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'"; - } + $sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'"; $sql .= " ORDER BY rowid ASC"; // Required so we get the first one $sql .= $db->plimit(1); @@ -518,7 +522,7 @@ if ($action == 'deletefile') { print '
'; print ''; -print ''; +print ''; print '
'; diff --git a/htdocs/langs/en_US/blockedlog.lang b/htdocs/langs/en_US/blockedlog.lang index f2ba1d3788c..9d83eab7b98 100644 --- a/htdocs/langs/en_US/blockedlog.lang +++ b/htdocs/langs/en_US/blockedlog.lang @@ -49,6 +49,7 @@ TotalTTCIfInvoiceSeeCompleteDataForDetail=Amount of event. Total including tax i TypeOfEvent=Type of event TotalForAction=Total for event %s SecretKey=Secret key +ErrorPeriodMustBePastToAllowExport=Export into archives is allowed only if period is completely past ## logTypes logBILL_DELETE=Customer invoice logically deleted From 621da6eb0d5f248cd677e39afc6437e1109bb789 Mon Sep 17 00:00:00 2001 From: Lucas Marcouiller Date: Fri, 28 Nov 2025 11:19:16 +0100 Subject: [PATCH 28/53] Fix prevent use of TRACE method in waf --- htdocs/waf.inc.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/htdocs/waf.inc.php b/htdocs/waf.inc.php index f514b46af26..60fc4e9c453 100644 --- a/htdocs/waf.inc.php +++ b/htdocs/waf.inc.php @@ -309,6 +309,13 @@ function analyseVarsForSqlAndScriptsInjection(&$var, $type, $stopcode = 1) } } +// Prevent the use of method TRACE +if ($_SERVER["REQUEST_METHOD"] == "TRACE") { + print 'Access refused with request method TRACE'; + http_response_code(405); + exit(); +} + // Sanity check on URL if (!defined('NOSCANPHPSELFFORINJECTION') && !empty($_SERVER["PHP_SELF"])) { $morevaltochecklikepost = array($_SERVER["PHP_SELF"]); From 206e6367564ff10af226d406a9be247928bb6f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20JOUM?= Date: Thu, 27 Nov 2025 18:08:31 +0100 Subject: [PATCH 29/53] FIX: reinstate shipment with origin --- htdocs/expedition/card.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index f00273f3599..a1018a8f10e 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -294,7 +294,16 @@ if (empty($reshook)) { if ($action == 'add' && $permissiontoadd) { $db->begin(); - if (GETPOSTINT('socid') < 1) { + if ($origin && $origin_id > 0) { + // We will loop on each line of the original document to complete the shipping object with various info and quantity to deliver + $classname = ucfirst($origin); + $objectsrc = new $classname($db); + '@phan-var-force Facture|Commande $objectsrc'; + $objectsrc->fetch($origin_id); + $object->socid = $objectsrc->socid; + } + + if (GETPOSTINT('socid') < 1 && $object->socid < 1) { $error++; setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors'); $action = 'create'; @@ -1418,7 +1427,7 @@ $product_static = new Product($db); $shipment_static = new Expedition($db); $warehousestatic = new Entrepot($db); -if ($action == 'create' && !getDolGlobalString('SHIPMENT_STANDALONE')) { +if (!$origin && $action == 'create' && !getDolGlobalString('SHIPMENT_STANDALONE')) { print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly'); print '
' .$langs->trans("ShipmentCreationIsDoneFromOrder"); @@ -2257,7 +2266,7 @@ if ($action == 'create' && $usercancreate) { } } else { // ship from multiple locations - if (isModEnabled('productbatch') || !$product->hasbatch()) { + if (!isModEnabled('productbatch') || !$product->hasbatch()) { print ''; print ''; if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) { @@ -2464,6 +2473,7 @@ if ($action == 'create' && $usercancreate) { print ''; print ''; + print ''; //print '|'.$line->fk_product.'|'.$dbatch->batch.'|
'; print $langs->trans("Batch") . ': '; From 180726920242293fe86b4650c52bc0305f8459bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 28 Nov 2025 15:05:13 +0100 Subject: [PATCH 30/53] add another --- htdocs/core/class/html.formfile.class.php | 2 +- htdocs/product/stock/card.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index fd410086b9a..db1a28daa51 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -507,7 +507,7 @@ class FormFile } $printer = 0; - $supportedmoduleparts = ['project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; + $supportedmoduleparts = ['stock', 'project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; // The direct print feature is implemented only for such elements if (in_array($modulepart, $supportedmoduleparts)) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); diff --git a/htdocs/product/stock/card.php b/htdocs/product/stock/card.php index 6d37679a266..363f39b3968 100644 --- a/htdocs/product/stock/card.php +++ b/htdocs/product/stock/card.php @@ -284,6 +284,8 @@ if (empty($reshook)) { $action = ''; } + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; // Actions to build doc $upload_dir = $conf->stock->dir_output; From d43e697a10bfe542fbc3b56fe45d2b6af7b20c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Champlon?= Date: Fri, 28 Nov 2025 15:14:29 +0100 Subject: [PATCH 31/53] implem --- .../societe/class/api_thirdparties.class.php | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 4e83728ff7d..1f516b98798 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -1094,6 +1094,7 @@ class Thirdparties extends DolibarrApi * @since 7.0.0 Initial implementation * * @param int $id ID of the third party + * @param string $mode 'customer' or 'supplier' * @param string $filter Filter exceptional discount. "none" will return every discount, "available" returns unapplied discounts, "used" returns applied discounts {@choice none,available,used} * @param string $sortfield Sort field * @param string $sortorder Sort order @@ -1109,7 +1110,7 @@ class Thirdparties extends DolibarrApi * @throws RestException 404 * @throws RestException 503 */ - public function getFixedAmountDiscounts($id, $filter = "none", $sortfield = "f.type", $sortorder = 'ASC') + public function getFixedAmountDiscounts($id, $mode = 'customer', $filter = "none", $sortfield = "f.type", $sortorder = 'ASC') { $obj_ret = array(); @@ -1130,15 +1131,27 @@ class Thirdparties extends DolibarrApi throw new RestException(404, 'Thirdparty not found'); } - - $sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line"; - $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f"; - $sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id); - if ($filter == "available") { - $sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL"; - } - if ($filter == "used") { - $sql .= " AND (re.fk_facture IS NOT NULL OR re.fk_facture_line IS NOT NULL)"; + $sql = ''; + if ($mode === 'customer') { + $sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line"; + $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f"; + $sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id); + if ($filter == "available") { + $sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL"; + } + if ($filter == "used") { + $sql .= " AND (re.fk_facture IS NOT NULL OR re.fk_facture_line IS NOT NULL)"; + } + }elseif ($mode === 'supplier') { + $sql = "SELECT f.ref, f.type as factype, re.fk_invoice_supplier_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_invoice_supplier, re.fk_invoice_supplier_line"; + $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture_fourn as f"; + $sql .= " WHERE f.rowid = re.fk_invoice_supplier_source AND re.fk_soc = ".((int) $id); + if ($filter == "available") { + $sql .= " AND re.fk_invoice_supplier IS NULL AND re.fk_invoice_supplier_line IS NULL"; + } + if ($filter == "used") { + $sql .= " AND (re.fk_invoice_supplier IS NOT NULL OR re.fk_invoice_supplier_line IS NOT NULL)"; + } } $sql .= $this->db->order($sortfield, $sortorder); From 7ffb16abef16f3b37776ce7119f482314c53e508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Champlon?= Date: Fri, 28 Nov 2025 15:25:15 +0100 Subject: [PATCH 32/53] fix space --- htdocs/societe/class/api_thirdparties.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 1f516b98798..35f9a619546 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -1110,7 +1110,7 @@ class Thirdparties extends DolibarrApi * @throws RestException 404 * @throws RestException 503 */ - public function getFixedAmountDiscounts($id, $mode = 'customer', $filter = "none", $sortfield = "f.type", $sortorder = 'ASC') + public function getFixedAmountDiscounts($id, $mode = 'customer', $filter = "none", $sortfield = "f.type", $sortorder = 'ASC') { $obj_ret = array(); From 991b8670477aba67745d873aece6fc0955718d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 28 Nov 2025 15:26:10 +0100 Subject: [PATCH 33/53] add another --- htdocs/core/class/html.formfile.class.php | 22 +++++++++++++++++++++- htdocs/product/card.php | 3 +++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 5fd8b4e34f0..d052e20793e 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -507,7 +507,27 @@ class FormFile } $printer = 0; - $supportedmoduleparts = ['stock', 'ficheinter', 'user', 'project', 'contract', 'facture', 'supplier_proposal', 'propal', 'proposal', 'order', 'commande', 'expedition', 'commande_fournisseur', 'expensereport', 'delivery', 'ticket', 'bom', 'mrp:mo']; + $supportedmoduleparts = [ + 'product', + 'stock', + 'ficheinter', + 'user', + 'project', + 'contract', + 'facture', + 'supplier_proposal', + 'propal', + 'proposal', + 'order', + 'commande', + 'expedition', + 'commande_fournisseur', + 'expensereport', + 'delivery', + 'ticket', + 'bom', + 'mrp:mo', + ]; // The direct print feature is implemented only for such elements if (in_array($modulepart, $supportedmoduleparts)) { $printer = ($user->hasRight('printing', 'read') && isModEnabled('printing')); diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 05868f72fb0..a46d4ca06b9 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1342,6 +1342,9 @@ if (empty($reshook)) { } } + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + // Actions to send emails $triggersendname = 'PRODUCT_SENTBYMAIL'; $paramname = 'id'; From e3fbe0943e6af271269d7bf879760ed588d8a069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Champlon?= Date: Fri, 28 Nov 2025 15:40:57 +0100 Subject: [PATCH 34/53] fix space --- htdocs/societe/class/api_thirdparties.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index 35f9a619546..136add22e74 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -1142,7 +1142,7 @@ class Thirdparties extends DolibarrApi if ($filter == "used") { $sql .= " AND (re.fk_facture IS NOT NULL OR re.fk_facture_line IS NOT NULL)"; } - }elseif ($mode === 'supplier') { + } elseif ($mode === 'supplier') { $sql = "SELECT f.ref, f.type as factype, re.fk_invoice_supplier_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_invoice_supplier, re.fk_invoice_supplier_line"; $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture_fourn as f"; $sql .= " WHERE f.rowid = re.fk_invoice_supplier_source AND re.fk_soc = ".((int) $id); From 3616b229bb052f91715b024fabd4c750e98b7a79 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 28 Nov 2025 16:00:36 +0100 Subject: [PATCH 35/53] CSS --- htdocs/admin/syslog.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/htdocs/admin/syslog.php b/htdocs/admin/syslog.php index 7e8d7da76d4..24ec3b36b15 100644 --- a/htdocs/admin/syslog.php +++ b/htdocs/admin/syslog.php @@ -28,8 +28,6 @@ // Load Dolibarr environment require '../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; - /** * @var Conf $conf * @var DoliDB $db @@ -37,6 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; * @var Translate $langs * @var User $user */ +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; if (!$user->admin) { accessforbidden(); @@ -332,7 +331,7 @@ print ''; if (!empty($conf->loghandlers['mod_syslog_file']) && isModEnabled('cron')) { print ''.$langs->trans("SyslogFileNumberOfSaves").''; print ''; - print '   ('.$langs->trans('ConfigureCleaningCronjobToSetFrequencyOfSaves').')'; + print '   '.$langs->trans('ConfigureCleaningCronjobToSetFrequencyOfSaves').''; } print ''; From 165d047bf628448c1f4964a0395b927680e410f3 Mon Sep 17 00:00:00 2001 From: Lucas Marcouiller Date: Fri, 28 Nov 2025 16:02:55 +0100 Subject: [PATCH 36/53] Fix webhook history record save on error --- .../interface_95_modWebhook_WebhookTriggers.class.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php index e2cfbcd2df3..0b7154d52f4 100644 --- a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php +++ b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php @@ -69,6 +69,7 @@ class InterfaceWebhookTriggers extends DolibarrTriggers */ public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf) { + global $dolibarr_main_db_pass; if (!isModEnabled('webhook')) { return 0; // If module is not enabled, we do nothing } @@ -93,6 +94,9 @@ class InterfaceWebhookTriggers extends DolibarrTriggers return 0; } + // Create new instance of db for webhook history save + $dbhistory = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $dolibarr_main_db_pass, $conf->db->name, (int) $conf->db->port); + $sendmanualtriggers = (!empty($object->context['sendmanualtriggers']) ? $object->context['sendmanualtriggers'] : ""); foreach ($target_url as $key => $tmpobject) { // Set list of all triggers for this targetinto $actionarray @@ -146,7 +150,8 @@ class InterfaceWebhookTriggers extends DolibarrTriggers }*/ } - $triggerhistory = new TriggerHistory($this->db); + $dbhistory->begin(); + $triggerhistory = new TriggerHistory($dbhistory); $triggerhistory->trigger_code = $action; $triggerhistory->trigger_data = $jsonstr; $triggerhistory->fk_target = $tmpobject->id; @@ -157,10 +162,14 @@ class InterfaceWebhookTriggers extends DolibarrTriggers if (!$resql) { $errors++; $this->errors = array_merge($this->errors, $triggerhistory->errors); + $dbhistory->rollback(); + } else { + $dbhistory->commit(); } } } + $dbhistory->close(); dol_syslog("Trigger '" . $this->name . "' for action '$action' launched by " . __FILE__ . ". id=" . $object->id." -> nbPost=".$nbPosts); if (!empty($errors)) { From 0ce80ab5e6353beb1e3f32268f1362548d5b5278 Mon Sep 17 00:00:00 2001 From: Lucas Marcouiller Date: Fri, 28 Nov 2025 16:20:55 +0100 Subject: [PATCH 37/53] fix CI --- .../triggers/interface_95_modWebhook_WebhookTriggers.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php index 0b7154d52f4..f260ec47dd6 100644 --- a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php +++ b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php @@ -95,7 +95,7 @@ class InterfaceWebhookTriggers extends DolibarrTriggers } // Create new instance of db for webhook history save - $dbhistory = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $dolibarr_main_db_pass, $conf->db->name, (int) $conf->db->port); + $dbhistory = getDoliDBInstance($conf->db->type, $conf->db->host, (string) $conf->db->user, $dolibarr_main_db_pass, $conf->db->name, (int) $conf->db->port); $sendmanualtriggers = (!empty($object->context['sendmanualtriggers']) ? $object->context['sendmanualtriggers'] : ""); foreach ($target_url as $key => $tmpobject) { From c8cffbc3b5ef56723362d355ad27bd378c1d3f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 18:53:03 +0100 Subject: [PATCH 38/53] fix missing migration --- htdocs/install/mysql/migration/22.0.0-23.0.0.sql | 2 ++ htdocs/install/mysql/tables/llx_fichinterdet.sql | 1 + 2 files changed, 3 insertions(+) diff --git a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql index f8a2cce8326..3ebdeecf0d1 100644 --- a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql +++ b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql @@ -394,4 +394,6 @@ CREATE TABLE llx_expensereport_det_extrafields ALTER TABLE llx_blockedlog ADD INDEX idx_ref_object (ref_object); ALTER TABLE llx_blockedlog ADD CONSTRAINT fk_linktoref FOREIGN KEY (linktoref) REFERENCES llx_blockedlog(ref_object); +ALTER TABLE llx_fichinterdet ADD COLUMN special_code integer DEFAULT 0 AFTER fk_parent_line + -- end of migration diff --git a/htdocs/install/mysql/tables/llx_fichinterdet.sql b/htdocs/install/mysql/tables/llx_fichinterdet.sql index f25c14f14d8..043c55d6cc3 100644 --- a/htdocs/install/mysql/tables/llx_fichinterdet.sql +++ b/htdocs/install/mysql/tables/llx_fichinterdet.sql @@ -22,6 +22,7 @@ create table llx_fichinterdet rowid integer AUTO_INCREMENT PRIMARY KEY, fk_fichinter integer, fk_parent_line integer NULL, + special_code integer DEFAULT 0, -- code for special lines (may be 1=transport, 2=ecotax, 3=option, moduleid=...) date datetime, -- date de la ligne d'intervention description text, -- description de la ligne d'intervention duree integer, -- duree de la ligne d'intervention From 8ba7fca18a2430631fb379c45140086a0e040f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 18:55:29 +0100 Subject: [PATCH 39/53] fix missing migration --- htdocs/install/mysql/migration/22.0.0-23.0.0.sql | 3 ++- htdocs/install/mysql/tables/llx_fichinterdet.sql | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql index 3ebdeecf0d1..90a6f131b39 100644 --- a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql +++ b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql @@ -394,6 +394,7 @@ CREATE TABLE llx_expensereport_det_extrafields ALTER TABLE llx_blockedlog ADD INDEX idx_ref_object (ref_object); ALTER TABLE llx_blockedlog ADD CONSTRAINT fk_linktoref FOREIGN KEY (linktoref) REFERENCES llx_blockedlog(ref_object); -ALTER TABLE llx_fichinterdet ADD COLUMN special_code integer DEFAULT 0 AFTER fk_parent_line +ALTER TABLE llx_fichinterdet ADD COLUMN special_code integer DEFAULT 0 AFTER fk_parent_line; +ALTER TABLE llx_fichinterdet ADD COLUMN product_type integer DEFAULT 0 AFTER special_code; -- end of migration diff --git a/htdocs/install/mysql/tables/llx_fichinterdet.sql b/htdocs/install/mysql/tables/llx_fichinterdet.sql index 043c55d6cc3..0ee2ec41b51 100644 --- a/htdocs/install/mysql/tables/llx_fichinterdet.sql +++ b/htdocs/install/mysql/tables/llx_fichinterdet.sql @@ -23,6 +23,7 @@ create table llx_fichinterdet fk_fichinter integer, fk_parent_line integer NULL, special_code integer DEFAULT 0, -- code for special lines (may be 1=transport, 2=ecotax, 3=option, moduleid=...) + product_type integer DEFAULT 0, date datetime, -- date de la ligne d'intervention description text, -- description de la ligne d'intervention duree integer, -- duree de la ligne d'intervention From 123af6513977047bc89f1039588e9dbd7ac64821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 19:42:56 +0100 Subject: [PATCH 40/53] add more --- htdocs/core/class/html.formfile.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index d052e20793e..26f0f5eb399 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -508,6 +508,7 @@ class FormFile $printer = 0; $supportedmoduleparts = [ + 'member', 'product', 'stock', 'ficheinter', From 4a42d5d8bcad45f8958509325a1eadf060ba0a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 19:52:10 +0100 Subject: [PATCH 41/53] add more --- htdocs/core/class/html.formfile.class.php | 1 + htdocs/societe/card.php | 47 ++++++++++++----------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 26f0f5eb399..406fef7c6b3 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -508,6 +508,7 @@ class FormFile $printer = 0; $supportedmoduleparts = [ + 'company', 'member', 'product', 'stock', diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index b9ca8e591da..7d1ff903a2f 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -945,6 +945,9 @@ if (empty($reshook)) { $upload_dir = !empty($conf->societe->multidir_output[$object->entity ?? $conf->entity]) ? $conf->societe->multidir_output[$object->entity ?? $conf->entity] : $conf->societe->dir_output; $permissiontoadd = $user->hasRight('societe', 'creer'); include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; + + // Actions when printing a doc from card + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; } @@ -1094,12 +1097,12 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio } } - $object->phone = GETPOST('phone', 'alpha'); - $object->phone_mobile = (string) GETPOST("phone_mobile", 'alpha'); - $object->fax = GETPOST('fax', 'alpha'); - $object->email = GETPOST('email', 'email'); - $object->url = GETPOST('url', 'url'); - $object->capital = GETPOST('capital'); // can be null or 0 or a float value + $object->phone = GETPOST('phone', 'alpha'); + $object->phone_mobile = (string) GETPOST("phone_mobile", 'alpha'); + $object->fax = GETPOST('fax', 'alpha'); + $object->email = GETPOST('email', 'email'); + $object->url = GETPOST('url', 'url'); + $object->capital = GETPOST('capital'); // can be null or 0 or a float value $paymentTermId = GETPOSTINT('cond_reglement_id'); // can be set by default values on create page and not already in get or post variables if (empty($paymentTermId) && !GETPOSTISSET('cond_reglement_id')) { $paymentTermId = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID'); @@ -1109,28 +1112,28 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio if (empty($paymentTypeId) && !GETPOSTISSET('mode_reglement_id')) { $paymentTypeId = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID'); } - $object->mode_reglement_id = $paymentTypeId; - $object->barcode = GETPOST('barcode', 'alphanohtml'); - $object->idprof1 = GETPOST('idprof1', 'alphanohtml'); - $object->idprof2 = GETPOST('idprof2', 'alphanohtml'); - $object->idprof3 = GETPOST('idprof3', 'alphanohtml'); - $object->idprof4 = GETPOST('idprof4', 'alphanohtml'); - $object->idprof5 = GETPOST('idprof5', 'alphanohtml'); - $object->idprof6 = GETPOST('idprof6', 'alphanohtml'); + $object->mode_reglement_id = $paymentTypeId; + $object->barcode = GETPOST('barcode', 'alphanohtml'); + $object->idprof1 = GETPOST('idprof1', 'alphanohtml'); + $object->idprof2 = GETPOST('idprof2', 'alphanohtml'); + $object->idprof3 = GETPOST('idprof3', 'alphanohtml'); + $object->idprof4 = GETPOST('idprof4', 'alphanohtml'); + $object->idprof5 = GETPOST('idprof5', 'alphanohtml'); + $object->idprof6 = GETPOST('idprof6', 'alphanohtml'); $object->typent_id = GETPOSTINT('typent_id'); - $object->effectif_id = GETPOSTINT('effectif_id'); - $object->civility_id = GETPOST('civility_id', 'alpha'); + $object->effectif_id = GETPOSTINT('effectif_id'); + $object->civility_id = GETPOST('civility_id', 'alpha'); $object->tva_assuj = GETPOSTINT('assujtva_value'); $object->vat_reverse_charge = GETPOST('vat_reverse_charge') == 'on' ? 1 : 0; $object->status = GETPOSTINT('status'); //Local Taxes - $object->localtax1_assuj = GETPOSTINT('localtax1assuj_value'); - $object->localtax2_assuj = GETPOSTINT('localtax2assuj_value'); + $object->localtax1_assuj = GETPOSTINT('localtax1assuj_value'); + $object->localtax2_assuj = GETPOSTINT('localtax2assuj_value'); - $object->localtax1_value = GETPOST('lt1', 'alpha'); - $object->localtax2_value = GETPOST('lt2', 'alpha'); + $object->localtax1_value = GETPOST('lt1', 'alpha'); + $object->localtax2_value = GETPOST('lt2', 'alpha'); $object->tva_intra = GETPOST('tva_intra', 'alphanohtml'); @@ -1147,7 +1150,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio } } if (GETPOSTISSET('accountancy_code_buy')) { - $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha'); + $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha'); if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') { $object->accountancy_code_buy = ''; @@ -1159,7 +1162,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio $object->logo = (isset($_FILES['photo']) ? dol_sanitizeFileName($_FILES['photo']['name']) : ''); // Company logo management - $dir = $conf->societe->multidir_output[$conf->entity]."/".$object->id."/logos"; + $dir = $conf->societe->multidir_output[$conf->entity]."/".$object->id."/logos"; $file_OK = (isset($_FILES['photo']) ? is_uploaded_file($_FILES['photo']['tmp_name']) : false); if ($file_OK) { if (image_format_supported($_FILES['photo']['name'])) { From 2afb048dfbae6b59ca1b99d8e79d5c44fe407dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 19:57:10 +0100 Subject: [PATCH 42/53] add more --- htdocs/core/class/html.formfile.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 406fef7c6b3..92f10d73c0c 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -524,6 +524,7 @@ class FormFile 'commande', 'expedition', 'commande_fournisseur', + 'facture_fournisseur', 'expensereport', 'delivery', 'ticket', From 15124c1bf3f354175153fedd0eb5694f4f776244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 20:10:00 +0100 Subject: [PATCH 43/53] add more --- htdocs/core/actions_printing.inc.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/core/actions_printing.inc.php b/htdocs/core/actions_printing.inc.php index 52fc3fa27d9..8c204e99039 100644 --- a/htdocs/core/actions_printing.inc.php +++ b/htdocs/core/actions_printing.inc.php @@ -1,6 +1,6 @@ - * Copyright (C) 2014-2024 Frédéric France + * Copyright (C) 2014-2025 Frédéric France * Copyright (C) 2024 MDW * * This program is free software; you can redistribute it and/or modify @@ -65,6 +65,7 @@ if ($action == 'print_file' && $user->hasRight('printing', 'read')) { $subdir = ''; $module = GETPOST('printer', 'alpha'); + // TODO make conversion in printing module switch ($module) { case 'livraison': $subdir = 'receipt'; @@ -74,7 +75,7 @@ if ($action == 'print_file' && $user->hasRight('printing', 'read')) { $subdir = 'sending'; break; case 'commande_fournisseur': - $module = 'fournisseur'; + $module = 'commande_fournisseur'; $subdir = 'commande'; break; } From d7597d72d26a15e0a5306ebcff277297294f4440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 20:39:32 +0100 Subject: [PATCH 44/53] add more --- .../modules/printing/modules_printing.php | 3 +-- .../modules/printing/printipp.modules.php | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/htdocs/core/modules/printing/modules_printing.php b/htdocs/core/modules/printing/modules_printing.php index e1df70fa5f7..d9aabb51d9a 100644 --- a/htdocs/core/modules/printing/modules_printing.php +++ b/htdocs/core/modules/printing/modules_printing.php @@ -1,6 +1,6 @@ + * Copyright (C) 2014-2025 Frédéric France * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -47,7 +47,6 @@ class PrintingDriver */ public $errors = array(); - /** * @var string Name */ diff --git a/htdocs/core/modules/printing/printipp.modules.php b/htdocs/core/modules/printing/printipp.modules.php index f51d105f650..a5df9e35744 100644 --- a/htdocs/core/modules/printing/printipp.modules.php +++ b/htdocs/core/modules/printing/printipp.modules.php @@ -244,17 +244,20 @@ class printing_printipp extends PrintingDriver */ public function getlistAvailablePrinters() { - global $conf, $db; include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php'; - $ipp = new CupsPrintIPP(); - $ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log', 'file', 3); // logging very verbose - $ipp->setHost($this->host); - $ipp->setPort($this->port); - $ipp->setUserName($this->userid); - if (!empty($this->user)) { - $ipp->setAuthentication($this->user, $this->password); + try { + $ipp = new CupsPrintIPP(); + $ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log', 'file', 3); // logging very verbose + $ipp->setHost($this->host); + $ipp->setPort($this->port); + $ipp->setUserName($this->userid); + if (!empty($this->user)) { + $ipp->setAuthentication($this->user, $this->password); + } + $ipp->getPrinters(); + } catch (Exception $e) { + setEventMessage($e->getMessage()); } - $ipp->getPrinters(); return $ipp->available_printers; } From b39eb2bc9ee957583ef8c64a37280f4b005babf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 20:43:17 +0100 Subject: [PATCH 45/53] add more --- htdocs/core/modules/printing/printipp.modules.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/modules/printing/printipp.modules.php b/htdocs/core/modules/printing/printipp.modules.php index a5df9e35744..6568f10549f 100644 --- a/htdocs/core/modules/printing/printipp.modules.php +++ b/htdocs/core/modules/printing/printipp.modules.php @@ -245,8 +245,8 @@ class printing_printipp extends PrintingDriver public function getlistAvailablePrinters() { include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php'; + $ipp = new CupsPrintIPP(); try { - $ipp = new CupsPrintIPP(); $ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log', 'file', 3); // logging very verbose $ipp->setHost($this->host); $ipp->setPort($this->port); @@ -256,7 +256,7 @@ class printing_printipp extends PrintingDriver } $ipp->getPrinters(); } catch (Exception $e) { - setEventMessage($e->getMessage()); + setEventMessage($e->getMessage(), 'errors'); } return $ipp->available_printers; } From 65af9e2591752ac3e603f344924218c1beac5267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20France?= Date: Fri, 28 Nov 2025 20:44:34 +0100 Subject: [PATCH 46/53] add more --- htdocs/core/modules/printing/printipp.modules.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/htdocs/core/modules/printing/printipp.modules.php b/htdocs/core/modules/printing/printipp.modules.php index 6568f10549f..17f57351398 100644 --- a/htdocs/core/modules/printing/printipp.modules.php +++ b/htdocs/core/modules/printing/printipp.modules.php @@ -246,18 +246,19 @@ class printing_printipp extends PrintingDriver { include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php'; $ipp = new CupsPrintIPP(); + $ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log', 'file', 3); // logging very verbose + $ipp->setHost($this->host); + $ipp->setPort($this->port); + $ipp->setUserName($this->userid); + if (!empty($this->user)) { + $ipp->setAuthentication($this->user, $this->password); + } try { - $ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log', 'file', 3); // logging very verbose - $ipp->setHost($this->host); - $ipp->setPort($this->port); - $ipp->setUserName($this->userid); - if (!empty($this->user)) { - $ipp->setAuthentication($this->user, $this->password); - } $ipp->getPrinters(); } catch (Exception $e) { setEventMessage($e->getMessage(), 'errors'); } + return $ipp->available_printers; } From b31f16c18f20bf38505202581cd8a80b77ba38b8 Mon Sep 17 00:00:00 2001 From: Dolibot Date: Sat, 29 Nov 2025 12:09:23 +0000 Subject: [PATCH 47/53] PHPStan > Update baseline --- dev/build/phpstan/phpstan-baseline.neon | 114 ------------------------ 1 file changed, 114 deletions(-) diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index 678d591e9ee..a7729ec1878 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -1578,18 +1578,6 @@ parameters: count: 1 path: ../../../htdocs/categories/categorie_list.php - - - message: '#^Method Categorie\:\:get_full_arbo\(\) should return \-1\|array\ but returns array\\.$#' - identifier: return.type - count: 1 - path: ../../../htdocs/categories/class/categorie.class.php - - - - message: '#^Property Categorie\:\:\$cats \(array\\) does not accept array\\.$#' - identifier: assign.propertyType - count: 2 - path: ../../../htdocs/categories/class/categorie.class.php - - message: '#^If condition is always true\.$#' identifier: if.alwaysTrue @@ -5646,48 +5634,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/html.form.class.php - - - message: '#^Property Form\:\:\$cache_conditions_paiements has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - - - message: '#^Property Form\:\:\$cache_demand_reason has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - - - message: '#^Property Form\:\:\$cache_invoice_subtype has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - - - message: '#^Property Form\:\:\$cache_transport_mode has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - - - message: '#^Property Form\:\:\$cache_types_fees has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - - - message: '#^Property Form\:\:\$cache_types_paiements has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - - - message: '#^Property Form\:\:\$cache_vatrates has no type specified\.$#' - identifier: missingType.property - count: 1 - path: ../../../htdocs/core/class/html.form.class.php - - message: '#^Right side of && is always true\.$#' identifier: booleanAnd.rightAlwaysTrue @@ -14004,18 +13950,6 @@ parameters: count: 1 path: ../../../htdocs/reception/card.php - - - message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''commande'' will always evaluate to false\.$#' - identifier: equal.alwaysFalse - count: 2 - path: ../../../htdocs/reception/card.php - - - - message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''propal'' will always evaluate to false\.$#' - identifier: equal.alwaysFalse - count: 2 - path: ../../../htdocs/reception/card.php - - message: '#^Negated boolean expression is always true\.$#' identifier: booleanNot.alwaysTrue @@ -14028,12 +13962,6 @@ parameters: count: 1 path: ../../../htdocs/reception/card.php - - - message: '#^Result of && is always false\.$#' - identifier: booleanAnd.alwaysFalse - count: 8 - path: ../../../htdocs/reception/card.php - - message: '#^Variable \$extrafields in empty\(\) always exists and is not falsy\.$#' identifier: empty.variable @@ -14184,24 +14112,6 @@ parameters: count: 2 path: ../../../htdocs/reception/contact.php - - - message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''commande'' will always evaluate to false\.$#' - identifier: equal.alwaysFalse - count: 1 - path: ../../../htdocs/reception/dispatch.php - - - - message: '#^Loose comparison using \=\= between ''''\|''CommandeFournisseur'' and ''propal'' will always evaluate to false\.$#' - identifier: equal.alwaysFalse - count: 1 - path: ../../../htdocs/reception/dispatch.php - - - - message: '#^Result of && is always false\.$#' - identifier: booleanAnd.alwaysFalse - count: 4 - path: ../../../htdocs/reception/dispatch.php - - message: '#^Variable \$objectsrc might not be defined\.$#' identifier: variable.undefined @@ -16044,12 +15954,6 @@ parameters: count: 1 path: ../../../htdocs/webhook/triggerhistory_list.php - - - message: '#^Loose comparison using \=\= between ''auto'' and ''auto'' will always evaluate to true\.$#' - identifier: equal.alwaysTrue - count: 1 - path: ../../../htdocs/webportal/class/context.class.php - - message: '#^Result of && is always false\.$#' identifier: booleanAnd.alwaysFalse @@ -16062,24 +15966,6 @@ parameters: count: 1 path: ../../../htdocs/webportal/class/html.formcardwebportal.class.php - - - message: '#^Comparison operation "\<\=" between int\<2, max\> and 1 is always false\.$#' - identifier: smallerOrEqual.alwaysFalse - count: 1 - path: ../../../htdocs/webportal/class/html.formlistwebportal.class.php - - - - message: '#^Offset ''total'' on \*NEVER\* in isset\(\) always exists and is not nullable\.$#' - identifier: isset.offset - count: 1 - path: ../../../htdocs/webportal/class/html.formlistwebportal.class.php - - - - message: '#^Result of && is always false\.$#' - identifier: booleanAnd.alwaysFalse - count: 1 - path: ../../../htdocs/webportal/class/html.formlistwebportal.class.php - - message: '#^Call to function is_array\(\) with list\ will always evaluate to true\.$#' identifier: function.alreadyNarrowedType From 5932aaa9db7400bfaa4547276c88486ef9b93237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Fali=C3=A8re?= Date: Sat, 29 Nov 2025 16:39:06 +0100 Subject: [PATCH 48/53] ENH: Accessibility on modulebuilder setup page Add label for input fields --- htdocs/modulebuilder/admin/setup.php | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/htdocs/modulebuilder/admin/setup.php b/htdocs/modulebuilder/admin/setup.php index d4222b926b6..6ed53954e5f 100644 --- a/htdocs/modulebuilder/admin/setup.php +++ b/htdocs/modulebuilder/admin/setup.php @@ -1,6 +1,7 @@ * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024 Benjamin Falière * * 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 @@ -144,61 +145,61 @@ if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) { } print ''; -print ''.$langs->trans("UseSpecificEditorName").''; +print ''; print ''; -print ''; +print ''; print ''; print ''; print ''; -print ''.$langs->trans("UseSpecificEditorURL").''; +print ''; print ''; -print ''; +print ''; print ''; print ''; if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) { print ''; - print ''.$langs->trans("UseSpecificFamily").''; + print ''; print ''; - print ''; + print ''; print ''; print ''; print ''; - print ''.$langs->trans("UseSpecificAuthor").''; + print ''; print ''; - print ''; + print ''; print ''; print ''; print ''; - print ''.$langs->trans("UseSpecificVersion").''; + print ''; print ''; - print ''; + print ''; print ''; print ''; } print ''; -print ''.$langs->trans("UseSpecificReadme").''; +print ''; print ''; -print ''; +print ''; print ''; print ''; print ''; -print ''.$langs->trans("AsciiToHtmlConverter").''; +print ''; print ''; -print ''; +print ''; print ' '.$langs->trans("Example").': asciidoc, asciidoctor'; print ''; print ''; print ''; -print ''.$langs->trans("AsciiToPdfConverter").''; +print ''; print ''; -print ''; +print ''; print ' '.$langs->trans("Example").': asciidoctor-pdf'; print ''; print ''; From 62ebfd6f5e3c45fbc355cc5c8dabab7e291b7fad Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 29 Nov 2025 16:53:58 +0100 Subject: [PATCH 49/53] Clarify supported versions for security reports --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index aacbeb1faf9..9126e7a977d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ This file contains some policies about the security reports on Dolibarr ERP CRM ## Supported Versions for security reports -Security report are valid only on current stable version (see https://dolibarr.org web site to get current stable version) or on development version (branch "develop" on https://github.com/Dolibarr/dolibarr). +Security report are valid only on any current stable version until the older LTS version (see https://dolibarr.org web site to get current stable version) or on development version (branch "develop" on https://github.com/Dolibarr/dolibarr). ## Reporting a Vulnerability From f4475746c320d1dce6d41ee05bf85e0ce330a776 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 29 Nov 2025 16:54:56 +0100 Subject: [PATCH 50/53] Update supported versions for security reports --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 9126e7a977d..41c0fd43de1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ This file contains some policies about the security reports on Dolibarr ERP CRM ## Supported Versions for security reports -Security report are valid only on any current stable version until the older LTS version (see https://dolibarr.org web site to get current stable version) or on development version (branch "develop" on https://github.com/Dolibarr/dolibarr). +Security report are valid only on any current stable version for the last 5 major versions (see https://dolibarr.org web site to get current stable version) or on development version (branch "develop" on https://github.com/Dolibarr/dolibarr). ## Reporting a Vulnerability From 2eee5bf2a1a1c89d69141e191de871c1d4f773ec Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 30 Nov 2025 14:48:33 +0100 Subject: [PATCH 51/53] CSS --- htdocs/societe/consumption.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/htdocs/societe/consumption.php b/htdocs/societe/consumption.php index f9b4fe84da0..b7d40da8429 100644 --- a/htdocs/societe/consumption.php +++ b/htdocs/societe/consumption.php @@ -29,12 +29,6 @@ // Load Dolibarr environment require "../main.inc.php"; -require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php'; - - /** * @var Conf $conf * @var DoliDB $db @@ -42,6 +36,10 @@ require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php'; * @var Translate $langs * @var User $user */ +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.class.php'; // Load translation files required by the page $langs->loadLangs(array("companies", "bills", "orders", "suppliers", "propal", "interventions", "contracts", "products")); @@ -508,7 +506,7 @@ if ($sql_select) { // Filters print ''; print ''; - print ''; + print ''; print ''; print ''; // date print $formother->select_month($month ? (string) $month : '-1', 'month', 1, 0, 'valignmiddle'); @@ -573,7 +571,7 @@ if ($sql_select) { } print ''; - print ''; + print ''; print $documentstatic->getNomUrl(1); print ''; print ''.dol_print_date($db->jdate($objp->dateprint), 'day').''; From b83a13656fb63ce50b670d11ade326e5758d0a7d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 30 Nov 2025 18:37:58 +0100 Subject: [PATCH 52/53] Add new phpunit tests --- dev/translation/ignore_translation_keys.lst | 2 - htdocs/blockedlog/class/blockedlog.class.php | 16 +++- htdocs/langs/en_US/errors.lang | 4 + test/phpunit/AllTests.php | 3 + test/phpunit/BlockedLogAndLNETest.php | 85 ++++++++++++++++++++ 5 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 test/phpunit/BlockedLogAndLNETest.php diff --git a/dev/translation/ignore_translation_keys.lst b/dev/translation/ignore_translation_keys.lst index b4f1071bc6a..f1f33bb9f1c 100644 --- a/dev/translation/ignore_translation_keys.lst +++ b/dev/translation/ignore_translation_keys.lst @@ -145,8 +145,6 @@ Barcode BarcodeDesc BarcodeStickersMask BillOfMaterialsLine -BlockLogNeedAmountsValue -BlockLogNeedElement BlockedLogAuthorityNeededToStoreYouFingerprintsInNonAlterableRemote BlockedLogAuthorityUrl BlockedLogSetup diff --git a/htdocs/blockedlog/class/blockedlog.class.php b/htdocs/blockedlog/class/blockedlog.class.php index 86141ed72bd..7c3e965e266 100644 --- a/htdocs/blockedlog/class/blockedlog.class.php +++ b/htdocs/blockedlog/class/blockedlog.class.php @@ -990,19 +990,29 @@ class BlockedLog // Check parameters/properties if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled) - $this->error = $langs->trans("BlockLogNeedAmountsValue"); + $langs->load("errors"); + $this->error = $langs->trans("ErrorBlockLogNeedAmountsValue"); dol_syslog($this->error, LOG_WARNING); return -1; } if (empty($this->element)) { - $this->error = $langs->trans("BlockLogNeedElement"); + $langs->load("errors"); + $this->error = $langs->trans("ErrorBlockLogNeedElement"); + dol_syslog($this->error, LOG_WARNING); + return -2; + } + + if (empty($this->object_data)) { + $langs->load("errors"); + $this->error = $langs->trans("ErrorBlockLogNeedObject"); dol_syslog($this->error, LOG_WARNING); return -2; } if (empty($this->action)) { - $this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog"); + $langs->load("errors"); + $this->error = $langs->trans("ErrorBadParameterWhenCallingCreateOfBlockedLog"); dol_syslog($this->error, LOG_WARNING); return -3; } diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index c118bbd2457..20c66ad8f15 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -369,6 +369,10 @@ ErrorPaymentAmountMustNotBeNull=Error, payment amount must be defined and not ze ErrorOneLineContainsADisactivatedProduct=Error, at least one product is not or no more on sale or for purchase ErrorCalendarIsNotYetOpenOrHasBeenClosed=This calendar is not yet open or has been closed ErrorFieldClassNotFoundForClassName=The class "%s" managing the field type "%s" is not found. +ErrorBlockLogNeedAmountsValue=The unalterbale log object needs amounts values to be set +ErrorBlockLogNeedElement=The unalterbale log object needs element type to be set +ErrorBlockLogNeedObject=The unalterbale log object needs object to be set +ErrorBadParameterWhenCallingCreateOfBlockedLog=Bad parameter when calling create of blocked log # 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/test/phpunit/AllTests.php b/test/phpunit/AllTests.php index f49d9994258..2c1c30bd9b5 100644 --- a/test/phpunit/AllTests.php +++ b/test/phpunit/AllTests.php @@ -253,6 +253,9 @@ class AllTests require_once dirname(__FILE__).'/AssetModelTest.php'; $suite->addTestSuite('AssetModelTest'); + require_once dirname(__FILE__).'/BlockedLogAndLNETest.php'; + $suite->addTestSuite('BlockedLogAndLNETest'); + // Rest require_once dirname(__FILE__).'/RestAPIUserTest.php'; $suite->addTestSuite('RestAPIUserTest'); diff --git a/test/phpunit/BlockedLogAndLNETest.php b/test/phpunit/BlockedLogAndLNETest.php new file mode 100644 index 00000000000..335a42ddd0d --- /dev/null +++ b/test/phpunit/BlockedLogAndLNETest.php @@ -0,0 +1,85 @@ + + * Copyright (C) 2023 Alexandre Janniaux + * Copyright (C) ---Put here your own copyright and developer email--- + * Copyright (C) 2024 Frédéric France + * + * 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 . + */ + +/** + * \file test/unit/BlockedLogAndLNETest.php + * \ingroup core + * \brief PHPUnit test for the BlockedLog and LNE class. + */ + +global $conf,$user,$langs,$db; +//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver +//require_once 'PHPUnit/Autoload.php'; +require_once dirname(__FILE__).'/../../htdocs/master.inc.php'; +require_once dirname(__FILE__).'/../../htdocs/compta/facture/class/facture.class.php'; +require_once dirname(__FILE__).'/../../htdocs/blockedlog/class/blockedlog.class.php'; +require_once dirname(__FILE__).'/CommonClassTest.class.php'; + +if (empty($user->id)) { + print "Load permissions for admin user nb 1\n"; + $user->fetch(1); + $user->loadRights(); +} +$conf->global->MAIN_DISABLE_ALL_MAILS = 1; + +$langs->load("main"); + + +/** + * Class for PHPUnit tests + * + * @backupGlobals disabled + * @backupStaticAttributes enabled + * @remarks backupGlobals must be disabled to have db,conf,user and lang not erased. + */ +class BlockedLogAndLNETest extends CommonClassTest +{ + /** + * testBlockedLogAndLNETest + * + * @return int + */ + public function testBlockedLogAndLNETest() + { + global $conf,$user,$langs,$db; + $conf = $this->savconf; + $user = $this->savuser; + $langs = $this->savlangs; + $db = $this->savdb; + + $localobject = new BlockedLog($db); + $localobject->action = 'TEST'; + + $element = new Facture($db); + $element->initAsSpecimen(); + $localobject->element = $element->element; + $localobject->object_data = $element; + + $result = $localobject->create($user); + + print __METHOD__." result=".$result."\n"; + $this->assertLessThan($result, 0); + + return $result; + } + + + // TODO Add more tests +} From ab3204a88a104067410388a1577419a94ce171e1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 1 Dec 2025 11:42:20 +0100 Subject: [PATCH 53/53] Debug v23 --- htdocs/admin/mails_templates.php | 60 +++++++++++++++----------------- htdocs/theme/eldy/global.inc.php | 2 +- htdocs/theme/md/style.css.php | 2 +- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index 832d883305b..9e038d67a49 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -524,9 +524,6 @@ if (empty($reshook)) { } // Rename some POST variables into a generic name - if ($field == 'fk_user' && !(GETPOSTINT('fk_user') > 0)) { - $_POST['fk_user'] = ''; - } if ($field == 'topic') { $_POST['topic'] = GETPOST('topic-'.$rowid); } @@ -548,7 +545,7 @@ if (empty($reshook)) { } $sql .= $field."="; - if (GETPOST($keycode) == '' || (!in_array($keycode, array('langcode', 'position', 'private', 'defaultfortype')) && !GETPOST($keycode))) { + if ((GETPOST($keycode) == '' && in_array($keycode, array('langcode'))) || (!in_array($keycode, array('langcode', 'position', 'private', 'defaultfortype')) && !GETPOST($keycode))) { $sql .= "null"; // langcode,... must be '' if not defined so the unique key that include lang will work } elseif (GETPOST($keycode) == '0' && $keycode == 'langcode') { $sql .= "''"; // langcode must be '' if not defined so the unique key that include lang will work @@ -560,7 +557,9 @@ if (empty($reshook)) { } } elseif ($keycode == 'content') { $sql .= "'".$db->escape(GETPOST($keycode, 'restricthtml'))."'"; - } elseif (in_array($keycode, array('joinfiles', 'defaultfortype', 'private', 'position'))) { + } elseif ($keycode == 'position') { + $sql .= (GETPOSTINT($keycode) > 0 ? GETPOSTINT($keycode) : 1); + } elseif (in_array($keycode, array('joinfiles', 'defaultfortype', 'private'))) { $sql .= GETPOSTINT($keycode); } else { $sql .= "'".$db->escape(GETPOST($keycode, 'alphanohtml'))."'"; @@ -572,10 +571,10 @@ if (empty($reshook)) { if (!$user->admin) { // A non admin user can only edit its own template $sql .= " AND fk_user = ".((int) $user->id); } - //print $sql;exit; + dol_syslog("actionmodify", LOG_DEBUG); - //print $sql; + //print $sql; exit; $resql = $db->query($sql); if (!$resql) { $error++; @@ -731,7 +730,6 @@ $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $param .= $hookmanager->resPrint; -$linkback = ''; $titlepicto = 'title_setup'; @@ -1164,7 +1162,8 @@ if ($num) { if ($obj) { if (($action == 'edit' || $action == 'preview') && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) { - print ''; + // TODO Move this 2 lines into a popup + print ''; $tmpaction = 'edit'; if ($action == 'edit') { @@ -1180,16 +1179,6 @@ if ($num) { $colspan = 0; - print ''; - print ''; - print ''; - print '
'; - if ($action == 'edit') { - print ''; - } - print ''; - print ''; - // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print ''; @@ -1203,20 +1192,16 @@ if ($num) { // Action column if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { print ''; - print ''; - print ''; - if ($action == 'edit') { - print ''; - } - print '
'; - print ''; print ''; $colspan++; } print "\n"; print ''; - print ''; + if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } + print ''; $fieldsforcontent = array('topic', 'email_from','joinfiles', 'content'); if (getDolGlobalString('MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES')) { @@ -1259,7 +1244,7 @@ if ($num) { if (!getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) { $okforextended = false; } - $doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 500, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '90%', ($action != 'edit' ? 1 : 0)); + $doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 450, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '80%', ($action != 'edit' ? 1 : 0)); print $doleditor->Create(1); } if ($tmpfieldlist == 'content_lines') { @@ -1269,16 +1254,27 @@ if ($num) { if (!getDolGlobalString('FCKEDITOR_ENABLE_MAIL')) { $okforextended = false; } - $doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 140, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '90%'); + $doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 140, 'dolibarr_mailings', 'In', false, $acceptlocallinktomedia, $okforextended, ROWS_6, '80%'); print $doleditor->Create(1); } print '
'; } } print ''; + print '
'; + print ''; + if ($action == 'edit') { + print ''; + } + print ''; + print '
'; print ''; - print "\n"; + if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { + print ''; + } + + print ''; $nbqualified++; } else { @@ -1509,7 +1505,7 @@ function fieldList($fieldlist, $obj = null, $tabname = '', $context = '') } elseif ($value == 'fk_user') { print ''; if ($user->admin && $context != 'preview') { - print $form->select_dolusers(GETPOSTISSET('fk_user') ? GETPOSTINT('fk_user') : (empty($obj->$value) ? '' : $obj->$value), 'fk_user', 1, array(), 0, ($user->admin ? '' : 'hierarchyme'), array(), '0', 0, 0, '', 0, '', 'minwidth75 maxwidth100'); + print $form->select_dolusers(GETPOSTISSET('fk_user') ? GETPOSTINT('fk_user') : (empty($obj->$value) ? '' : $obj->$value), 'fk_user', $langs->trans("Owner"), array(), 0, ($user->admin ? '' : 'hierarchyme'), array(), '0', 0, 0, '', 0, '', 'minwidth75 maxwidth100'); } else { if ($context == 'add') { // I am not admin and we show the add form print $user->getNomUrl(-1); // Me @@ -1536,7 +1532,7 @@ function fieldList($fieldlist, $obj = null, $tabname = '', $context = '') if ($context == 'edit') { $selectedlang = $obj->lang; } - print $formadmin->select_language($selectedlang, 'langcode', 0, array(), 1, 0, 0, 'maxwidth100'); + print $formadmin->select_language($selectedlang, 'langcode', 0, array(), $langs->trans("Language"), 0, 0, 'maxwidth100'); } else { if (!empty($obj->lang)) { print $obj->lang.' - '.$langs->trans('Language_'.$obj->lang); diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index fe005609ee9..404c780b2ef 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -4441,7 +4441,7 @@ td.border, div.tagtable div div.border { .nobordertop, .nobordertop tr:first-of-type td { border-top: none !important; } -.noborderbottom, .noborderbottom tr:last-of-type td { +.noborderbottom, tr.noborderbottom td, .noborderbottom tr:last-of-type td { border-bottom: none !important; } .bordertop { diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 3e2657d6a1b..1b55a2214c9 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -4489,7 +4489,7 @@ td.border, div.tagtable div div.border { .nobordertop, .nobordertop tr:first-of-type td { border-top: none !important; } -.noborderbottom, .noborderbottom tr:last-of-type td { +.noborderbottom, tr.noborderbottom td, .noborderbottom tr:last-of-type td { border-bottom: none !important; } .bordertop {