From f2a6d1eedc90dfdcbad6314514aa300de67b4c0f Mon Sep 17 00:00:00 2001 From: Vincent Maury Date: Mon, 30 Mar 2026 19:58:58 +0200 Subject: [PATCH 01/17] Add clone before updating price (#37664) * Add clone before updating price It could be very usefull to have the old values of a product when using PRODUCT_PRICE_MODIFY trigger in a custom module * Update price.php --------- Co-authored-by: Laurent Destailleur --- htdocs/product/price.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 102599fb35d..95e3450a82f 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -288,6 +288,7 @@ if (empty($reshook)) { if (($action == 'update_price' || $action == 'update_level_price') && !$cancel && $permissiontoadd) { $error = 0; $pricestoupdate = array(); + $object->oldcopy = dol_clone($object, 2); $psq = GETPOSTINT('psqflag'); From adf9e3d27032bbd4ed3e69a463cd6ea67eec6d99 Mon Sep 17 00:00:00 2001 From: splohmer <113967431+splohmer@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:06:24 +0200 Subject: [PATCH 02/17] FIX - show correct shippable icon if order has multiple lines with same product (#37656) In the current implementation it checks only line by line against the stock. This can lead to not correct show of shippable orders icon as this can be incorrect due to multiple lines with the same product. Example: Stock of product A is 2. There are two lines with this product A. In the previous implementation it will check the first line against the stock 2-2=0 -> ok and then the same result for the next line but this is not correct as it doesn't reflect previous lines. --- htdocs/commande/list.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index 0a428bf579a..953a717011b 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -3003,6 +3003,8 @@ while ($i < $imaxinloop) { $generic_commande->getLinesArray(); // Load array ->lines $generic_commande->loadExpeditions(); // Load array ->expeditions + $stock = []; + $numlines = count($generic_commande->lines); // Loop on each line of order for ($lig = 0; $lig < $numlines; $lig++) { $orderLine = $generic_commande->lines[$lig]; @@ -3027,9 +3029,15 @@ while ($i < $imaxinloop) { $generic_product->stock_theorique = $productstat_cachevirtual[$orderLine->fk_product]['stock_reel']; } - if ($reliquat > $generic_product->stock_reel) { + if (!array_key_exists($orderLine->fk_product, $stock)) { + $stock[$orderLine->fk_product] = $generic_product->stock_reel; + } + + if ($reliquat > $stock[$orderLine->fk_product]) { $notshippable++; } + + $stock[$orderLine->fk_product] = $stock[$orderLine->fk_product] - $reliquat; if (!getDolGlobalString('SHIPPABLE_ORDER_ICON_IN_LIST')) { // Default code. Default should be this case. $text_info .= $reliquat.' x '.$orderLine->product_ref.' '.dol_trunc($orderLine->product_label, 20); $text_info .= ' - '.$langs->trans("Stock").': '.$generic_product->stock_reel.''; From 446559b7097a21c4e4c6fffb35f05cbc3e4b3cac Mon Sep 17 00:00:00 2001 From: Francis Appels Date: Mon, 30 Mar 2026 21:11:41 +0200 Subject: [PATCH 03/17] Fix #37642 regression (#37673) --- dev/build/makepack-dolibarrmodule.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/build/makepack-dolibarrmodule.pl b/dev/build/makepack-dolibarrmodule.pl index 856bedc6126..93d6d0d2181 100755 --- a/dev/build/makepack-dolibarrmodule.pl +++ b/dev/build/makepack-dolibarrmodule.pl @@ -157,7 +157,7 @@ foreach my $PROJECT (@PROJECTLIST) { . ucfirst($PROJECT) . ".class.php" ); - $custom = 0; + $custom = 1; if ( !$result ) { $result = open( $IN, @@ -180,7 +180,7 @@ foreach my $PROJECT (@PROJECTLIST) { } } else { - $custom = 1; + $custom = 0; } while (<$IN>) { if ( $_ =~ /this->version\s*=\s*'([\d\.]+)'/ ) { From ff9b2dda787a5cb68a98b53c71bd93d13b065ac9 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 31 Mar 2026 23:54:33 +0200 Subject: [PATCH 04/17] Fix trans and spellcheck --- htdocs/admin/const.php | 4 ++-- htdocs/admin/system/security.php | 2 +- htdocs/admin/tools/dolibarr_import.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/admin/const.php b/htdocs/admin/const.php index b921e787195..e5d0ac61528 100644 --- a/htdocs/admin/const.php +++ b/htdocs/admin/const.php @@ -226,10 +226,10 @@ print "\n"; print "\n"; print ''; -print ''; +print ''; print ''."\n"; print ''; -print ''; +print ''; print ''; print ''; print ''; diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php index fc083f02c8a..aae653710b7 100644 --- a/htdocs/admin/system/security.php +++ b/htdocs/admin/system/security.php @@ -860,7 +860,7 @@ $exampletodecrypt = GETPOST('exampletodecrypt', 'password'); print ''.$langs->trans("AlgorithmFor", $langs->transnoentitiesnoconv("SensitiveData")); print $form->textwithpicto('', 'reversible encryption done with dolEncrypt/dolDecrypt'); -print ' = '.constant('MAIN_SECURITY_REVERSIBLE_ALGO').' with a random seed + a crypt key defined into the conf.php file (in $dolibarr_main_dolcrypt_key or $dolibarr_main_instance_unique_id)
'; +print ' = '.constant('MAIN_SECURITY_REVERSIBLE_ALGO').' with a random seed + a crypt key defined into the conf.php file (in $dolibarr_main_instance_unique_id or $dolibarr_main_dolcrypt_key)
'; print '
'; print ''; print ''; diff --git a/htdocs/admin/tools/dolibarr_import.php b/htdocs/admin/tools/dolibarr_import.php index efccd48a58a..f11f797c0c3 100644 --- a/htdocs/admin/tools/dolibarr_import.php +++ b/htdocs/admin/tools/dolibarr_import.php @@ -246,7 +246,7 @@ print '
3< print '
'; print ''; -print $langs->trans("RestoreDesc4", 'dolibarr_main_dolcrypt_key or dolibarr_main_instance_unique_id').'
'; +print $langs->trans("RestoreDesc4", 'dolibarr_main_instance_unique_id '.$langs->transnoentitiesnoconv("or").' dolibarr_main_dolcrypt_key').'
'; print '
'; print '
'; From 97b6622bc74e785ead26fabdfd9dd545d0d95492 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 1 Apr 2026 00:18:10 +0200 Subject: [PATCH 05/17] Fix install/upgrade --- .../tables/llx_accounting_analytic_account-accounting.key.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_accounting_analytic_account-accounting.key.sql b/htdocs/install/mysql/tables/llx_accounting_analytic_account-accounting.key.sql index c0041a11909..7cbbc26be1e 100644 --- a/htdocs/install/mysql/tables/llx_accounting_analytic_account-accounting.key.sql +++ b/htdocs/install/mysql/tables/llx_accounting_analytic_account-accounting.key.sql @@ -17,4 +17,5 @@ -- ======================================================================== ALTER TABLE llx_accounting_analytic_account ADD UNIQUE INDEX uk_accounting_analytic_account(code, entity); -ALTER TABLE llx_accounting_analytic_account ADD CONSTRAINT fk_accounting_analytic_account_fk_axis FOREIGN KEY (fk_axis) REFERENCES llx_accounting_analytic_axis (rowid); +-- Disabled, we can t add a onstraint on a table that is created after. Name of tables must be modified so order will match parent table first, child table after. +--ALTER TABLE llx_accounting_analytic_account ADD CONSTRAINT fk_accounting_analytic_account_fk_axis FOREIGN KEY (fk_axis) REFERENCES llx_accounting_analytic_axis (rowid); From 4edfa4d348c9a6077b801bb9d940e08c3e11bee0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 1 Apr 2026 00:22:30 +0200 Subject: [PATCH 06/17] Straight contrainst when not critical must be avoid to avoid backup/restore trouble. --- htdocs/install/mysql/tables/llx_asset_model-asset.key.sql | 3 --- 1 file changed, 3 deletions(-) diff --git a/htdocs/install/mysql/tables/llx_asset_model-asset.key.sql b/htdocs/install/mysql/tables/llx_asset_model-asset.key.sql index 5c301e5c147..ad40e7cc5ff 100644 --- a/htdocs/install/mysql/tables/llx_asset_model-asset.key.sql +++ b/htdocs/install/mysql/tables/llx_asset_model-asset.key.sql @@ -20,6 +20,3 @@ ALTER TABLE llx_asset_model ADD INDEX idx_asset_model_entity (entity); ALTER TABLE llx_asset_model ADD INDEX idx_asset_model_ref (ref); ALTER TABLE llx_asset_model ADD INDEX idx_asset_model_pays (fk_pays); ALTER TABLE llx_asset_model ADD UNIQUE INDEX uk_asset_model (entity, ref); - -ALTER TABLE llx_asset_model ADD CONSTRAINT fk_asset_model_user_creat FOREIGN KEY (fk_user_creat) REFERENCES llx_user (rowid); -ALTER TABLE llx_asset_model ADD CONSTRAINT fk_asset_model_user_modif FOREIGN KEY (fk_user_modif) REFERENCES llx_user (rowid); From 5a508b473e674fb8d7c785e91c833d3eb8670c7d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 1 Apr 2026 01:05:01 +0200 Subject: [PATCH 07/17] Fix upgrade must not run upgrade for not enabled modules. --- htdocs/install/upgrade.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/htdocs/install/upgrade.php b/htdocs/install/upgrade.php index e16eb5acb18..a662ee14333 100644 --- a/htdocs/install/upgrade.php +++ b/htdocs/install/upgrade.php @@ -162,6 +162,7 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ $db = getDoliDBInstance($conf->db->type, $conf->db->host, $conf->db->user, $conf->db->pass, $conf->db->name, (int) $conf->db->port); + // Create the global $hookmanager object include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; $hookmanager = new HookManager($db); @@ -397,18 +398,26 @@ if (!GETPOST('action', 'aZ09') || preg_match('/upgrade/i', GETPOST('action', 'aZ } if (count($modulesfile)) { + $conf->setValues($db); // Load conf so we knowmodules that are enabled + print '
'; foreach ($modulesfile as $modulefilelong => $modulefileshort) { if (in_array($modulefilelong, $listoffileprocessed)) { continue; } + $dirofmodule = preg_replace('/\//', '', preg_replace('/\/sql\/[a-z0-8_]+\.sql$/', '', $modulefileshort)); - print ''.$langs->trans("ChoosedMigrateScript").' (external modules)'.$modulefileshort.''."\n"; + if (isModEnabled($dirofmodule)) { + print ''.$langs->trans("ChoosedMigrateScript").' (external modules '.$dirofmodule.')'.$modulefileshort.''."\n"; - // Run sql script - $okmodule = run_sql($modulefilelong, 0, 0, 1); // Note: Result of migration of external module should not decide if we continue migration of Dolibarr or not. - $listoffileprocessed[$modulefilelong] = $modulefilelong; + // Run sql script + $okmodule = run_sql($modulefilelong, 0, 0, 1); // Note: Result of migration of external module should not decide if we continue migration of Dolibarr or not. + $listoffileprocessed[$modulefilelong] = $modulefilelong; + } else { + print ''.$langs->trans("ChoosedMigrateScript").' (external modules '.$dirofmodule.')'.$modulefileshort.''."\n"; + print ''.$langs->trans("ProcessMigrateScript").'Ignored (module not enabled)'."\n"; + } } } } From dcc5a8e024a57bdce025a03e3f09a30d19332eac Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 1 Apr 2026 11:53:06 +0200 Subject: [PATCH 08/17] FIX add http code 503 on deadlock --- htdocs/blockedlog/class/blockedlog.class.php | 3 ++- htdocs/public/stripe/ipn.php | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/htdocs/blockedlog/class/blockedlog.class.php b/htdocs/blockedlog/class/blockedlog.class.php index 728ed73003a..8e937ed2da1 100644 --- a/htdocs/blockedlog/class/blockedlog.class.php +++ b/htdocs/blockedlog/class/blockedlog.class.php @@ -1527,7 +1527,8 @@ class BlockedLog $previoussignature = $obj->signature; } } else { - dol_print_error($this->db); + dol_print_error($this->db); // can happen after a deadlock when too many requests do create into blocked log happen at the same time. + http_response_code(503); exit; } } diff --git a/htdocs/public/stripe/ipn.php b/htdocs/public/stripe/ipn.php index 952c2273770..bf25bad6586 100644 --- a/htdocs/public/stripe/ipn.php +++ b/htdocs/public/stripe/ipn.php @@ -536,7 +536,9 @@ if ($event->type == 'payout.created' && getDolGlobalString('STRIPE_AUTO_RECORD_P dol_syslog('* Record payment type PRE for invoice id ' . $invoice_id . '. It includes closing of invoice and regenerating document.', LOG_DEBUG, 0, '_payment'); // This include closing invoices to 'paid' (and trigger including unsuspending) and regenerating document - $paiement_id = $paiement->create($user, 1); + $thirdpartyofpayment = null; // TODO Load thirdparty from $invoice_id + + $paiement_id = $paiement->create($user, 1, $thirdpartyofpayment); if ($paiement_id < 0) { $postactionmessages[] = $paiement->error . ($paiement->error ? ' ' : '') . implode("
\n", $paiement->errors); $ispostactionok = -1; From dac638ee024353c5a7d25c86220814f57b8f30e3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 2 Apr 2026 12:14:49 +0200 Subject: [PATCH 09/17] Fix filter --- .../interface_95_modWebhook_WebhookTriggers.class.php | 2 +- htdocs/install/mysql/migration/22.0.0-23.0.0.sql | 4 ++++ htdocs/webhook/target_card.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php index 977c902eeb0..5044088c06d 100644 --- a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php +++ b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php @@ -132,7 +132,7 @@ class InterfaceWebhookTriggers extends DolibarrTriggers if (empty($response['curl_error_no']) && $response['http_code'] >= 200 && $response['http_code'] < 300) { $nbPosts++; } else { - $errormsg = "The WebHook for ".$action." failed to get URL ".$tmpobject->url." with httpcode=".(!empty($response['http_code']) ? $response['http_code'] : "")." curl_error_no=".(!empty($response['curl_error_no']) ? $response['curl_error_no'] : ""); + $errormsg = "The WebHook for triggercode ".$action." failed to do the GET URL ".$tmpobject->url." with httpcode=".(!empty($response['http_code']) ? $response['http_code'] : "")." curl_error_no=".(!empty($response['curl_error_no']) ? $response['curl_error_no'] : ""); $errorforhistory ++; if ($tmpobject->type == Target::TYPE_BLOCKING) { 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 9c82f0f5a6b..8feb364fbfc 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 @@ -150,6 +150,10 @@ ALTER TABLE llx_oauth_token ADD COLUMN apicount_total BIGINT UNSIGNED DEFAULT 0; ALTER TABLE llx_webhook_target ADD COLUMN entity integer DEFAULT 1 NOT NULL; +-- In case of table exists +ALTER TABLE llx_webhook_history MODIFY COLUMN url varchar(255); + +-- In cas table does not exist CREATE TABLE llx_webhook_history( -- BEGIN MODULEBUILDER FIELDS rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL, diff --git a/htdocs/webhook/target_card.php b/htdocs/webhook/target_card.php index 5edd96bdaf8..bf89d8ecae3 100644 --- a/htdocs/webhook/target_card.php +++ b/htdocs/webhook/target_card.php @@ -185,7 +185,7 @@ if (empty($reshook)) { if (empty($response['curl_error_no']) && $response['http_code'] >= 200 && $response['http_code'] < 300) { setEventMessages($langs->trans("Success"), null); } else { - $errormsg = "The WebHook for triggercode: ".$triggercode." failed to get URL ".$url." with httpcode=".(!empty($response['http_code']) ? $response['http_code'] : "")." curl_error_no=".(!empty($response['curl_error_no']) ? $response['curl_error_no'] : ""); + $errormsg = "The WebHook for triggercode: ".$triggercode." failed to do the GET of URL ".$url." with httpcode=".(!empty($response['http_code']) ? $response['http_code'] : "")." curl_error_no=".(!empty($response['curl_error_no']) ? $response['curl_error_no'] : ""); setEventMessages($langs->trans($errormsg), null, 'errors'); } } From 4d9c16e7e067c82cf9c2ea40162f3ebce695a120 Mon Sep 17 00:00:00 2001 From: HENRY Florian Date: Fri, 3 Apr 2026 03:04:40 +0200 Subject: [PATCH 10/17] fix: php8 warning on accounting link invoice supplier (#37693) * fix: php8 warning * fix: php8 warning * fix: php8 warning --- htdocs/accountancy/supplier/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/supplier/index.php b/htdocs/accountancy/supplier/index.php index 4b485491fb7..3efb716f3f9 100644 --- a/htdocs/accountancy/supplier/index.php +++ b/htdocs/accountancy/supplier/index.php @@ -209,9 +209,9 @@ if ($action == 'validatehistory' && $user->hasRight('accounting', 'bind', 'write $product_static->label = $objp->product_label; $product_static->status = !empty($objp->status) ? $objp->status : 0; $product_static->status_buy = !empty($objp->status_buy) ? $objp->status_buy : 0; - $product_static->accountancy_code_sell = $objp->code_sell; - $product_static->accountancy_code_sell_intra = $objp->code_sell_intra; - $product_static->accountancy_code_sell_export = $objp->code_sell_export; + $product_static->accountancy_code_sell = !empty($objp->code_sell)? $objp->code_sell : ""; + $product_static->accountancy_code_sell_intra = !empty($objp->code_sell_intra)? $objp->code_sell_intra : ""; + $product_static->accountancy_code_sell_export = !empty($objp->code_sell_export)? $objp->code_sell_export : ""; $product_static->accountancy_code_buy = !empty($objp->code_buy) ? $objp->code_buy : ""; $product_static->accountancy_code_buy_intra = !empty($objp->code_buy_intra) ? $objp->code_buy_intra : ""; $product_static->accountancy_code_buy_export = !empty($objp->code_buy_export) ? $objp->code_buy_export : ""; From 39ccb1e951a09b649b6bfe39d83bcb19593abe1e Mon Sep 17 00:00:00 2001 From: Joachim Kueter Date: Fri, 3 Apr 2026 03:20:16 +0200 Subject: [PATCH 11/17] Fix #37677 (#37678) Updating date in existing time spent entry does not change date if done via UI in v22. In v23+ changing date alone via UI works, but when also changing task at same time, date will not get changed without this fix. See description in #37677 --- htdocs/projet/class/task.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index d3232461071..767edcc8caf 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -2079,7 +2079,7 @@ class Task extends CommonObjectLine } // Clean parameters - if (empty($this->timespent_datehour)) { + if (empty($this->timespent_datehour) || ($this->timespent_date != $this->timespent_datehour)) { $this->timespent_datehour = $this->timespent_date; } if (isset($this->timespent_note)) { From 630b2dc42c8adb6538e3e2ee02cdac563a738510 Mon Sep 17 00:00:00 2001 From: kkhelifa-opendsi Date: Fri, 3 Apr 2026 05:13:18 +0200 Subject: [PATCH 12/17] FIX : Fix not manage deposit account when get accounting code to bind when you have not selected a default account for deposit (#37680) --- htdocs/accountancy/class/accountingaccount.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/accountancy/class/accountingaccount.class.php b/htdocs/accountancy/class/accountingaccount.class.php index edba5a85afd..401654b68cf 100644 --- a/htdocs/accountancy/class/accountingaccount.class.php +++ b/htdocs/accountancy/class/accountingaccount.class.php @@ -877,7 +877,8 @@ class AccountingAccount extends CommonObject } // Manage Deposit - if (getDolGlobalString('ACCOUNTING_ACCOUNT_' . strtoupper($type) . '_DEPOSIT')) { + $account_deposit = getDolGlobalString('ACCOUNTING_ACCOUNT_' . strtoupper($type) . '_DEPOSIT'); + if (!empty($account_deposit) && $account_deposit != '-1') { if ($factureDet->desc == "(DEPOSIT)" || $facture->type == $facture::TYPE_DEPOSIT) { $accountdeposittoventilated = new self($this->db); if ($type == 'customer') { From df29df79d566c4b21b2a385ec5569792f08c6666 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 3 Apr 2026 18:57:23 +0200 Subject: [PATCH 13/17] FIX Closing td and showing options --- htdocs/admin/security_captcha.php | 46 +++++++++++++++++-------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/htdocs/admin/security_captcha.php b/htdocs/admin/security_captcha.php index c5d5e9ddbcc..4813bd60f37 100644 --- a/htdocs/admin/security_captcha.php +++ b/htdocs/admin/security_captcha.php @@ -133,6 +133,12 @@ print dol_get_fiche_head($head, 'captcha', '', -1); print '
'; +// Set if a captcha is used on at least one place +$showavailablecaptcha = 0; +if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA')) { + $showavailablecaptcha = 1; +} + print '
'; print ''; print ''; @@ -163,8 +169,11 @@ if (isModEnabled('societe')) { print ''.img_picto($langs->trans("Enabled"), 'on').''; } } + print ''; + if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_THIRDPARTY')) { + $showavailablecaptcha = 1; + } } -print ''; if (isModEnabled('ticket')) { print ''; } -print ''; if (isModEnabled('member')) { print ''; } -print ''; if (isModEnabled('don')) { print ''; @@ -219,29 +237,15 @@ if (isModEnabled('recruitment')) { print ''.img_picto($langs->trans("Enabled"), 'on').''; } } + if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_RECRUITMENT')) { + $showavailablecaptcha = 1; + } + print ''; } -print ''; print '
' . $langs->trans("UseCaptchaCode").' - Public ticket creation'; @@ -177,8 +186,11 @@ if (isModEnabled('ticket')) { print ''.img_picto($langs->trans("Enabled"), 'on').''; } } + if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) { + $showavailablecaptcha = 1; + } + print '
' . $langs->trans("UseCaptchaCode").' - Membership public subscription'; @@ -191,8 +203,11 @@ if (isModEnabled('member')) { print ''.img_picto($langs->trans("Enabled"), 'on').''; } } + if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_MEMBER')) { + $showavailablecaptcha = 1; + } + print '
' . $langs->trans("UseCaptchaCode").' - Donation public form'; @@ -205,6 +220,9 @@ if (isModEnabled('don')) { print ''.img_picto($langs->trans("Enabled"), 'on').''; } } + if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_DONATION')) { + $showavailablecaptcha = 1; + } } print '
'; print '
'; -// Set if a captcha is used on at least one place -$showavailablecaptcha = 0; -if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA')) { - $showavailablecaptcha = 1; -} -if (isModEnabled('societe') && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_THIRDPARTY')) { - $showavailablecaptcha = 1; -} -if (isModEnabled('ticket') && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) { - $showavailablecaptcha = 1; -} -if (isModEnabled('member') && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_MEMBER')) { - $showavailablecaptcha = 1; -} -if (isModEnabled('don') && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_DONATION')) { - $showavailablecaptcha = 1; -} $selectedcaptcha = getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_HANDLER', 'standard'); From 3e35e7d27971dbd910def7f2a6e7edd1f8bca00d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 3 Apr 2026 19:01:06 +0200 Subject: [PATCH 14/17] Fix closing tr --- htdocs/admin/security_captcha.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/security_captcha.php b/htdocs/admin/security_captcha.php index 4813bd60f37..90893d3be20 100644 --- a/htdocs/admin/security_captcha.php +++ b/htdocs/admin/security_captcha.php @@ -223,8 +223,8 @@ if (isModEnabled('don')) { if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_DONATION')) { $showavailablecaptcha = 1; } + print ''; } -print ''; if (isModEnabled('recruitment')) { print '' . $langs->trans("UseCaptchaCode").' - Recruitment public form'; From d9d9b5395dbcd04cd467492ccb3b4e81106cd5b0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 3 Apr 2026 19:06:15 +0200 Subject: [PATCH 15/17] CSS --- htdocs/public/recruitment/view.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/public/recruitment/view.php b/htdocs/public/recruitment/view.php index 5f893c854b4..13885d4ee3b 100644 --- a/htdocs/public/recruitment/view.php +++ b/htdocs/public/recruitment/view.php @@ -471,11 +471,11 @@ if ($action != 'dosubmit') { print ''."\n"; print ''.$langs->trans("Email").''; - print img_picto("", "email").''; + print img_picto("", "email", 'class="pictofixedwidth"').''; print ''."\n"; print ''.$langs->trans("Phone").''; - print img_picto("", "phone").''; + print img_picto("", "phone", 'class="pictofixedwidth"').''; print ''."\n"; print ''.$langs->trans("DateOfBirth").''; From 811cc1c275ede780d4f962b0630821b8fc51d764 Mon Sep 17 00:00:00 2001 From: PsyCrow <93346975+PsyCrow-code@users.noreply.github.com> Date: Fri, 3 Apr 2026 13:57:48 -0600 Subject: [PATCH 16/17] Fix #37707 Can pay invoices of all child of parent company (#37708) * FIX #37707 Can pay invoices of all child of parent company Update SQL query to include invoices with same parent company. FIX #37707 * Fix SQL query syntax for fk_soc condition FIX #37707 Can pay supplier invoices with the same parent company Paying invoices of all child of parent company doesn't work on supplier invoices only for customer invoices. This fix replicate the where clause in /htdocs/compta/paiement.php used for customer invoices. * Change entity condition in SQL query for payments --- htdocs/fourn/facture/paiement.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/htdocs/fourn/facture/paiement.php b/htdocs/fourn/facture/paiement.php index e5117c0c93b..1d713b1f130 100644 --- a/htdocs/fourn/facture/paiement.php +++ b/htdocs/fourn/facture/paiement.php @@ -562,9 +562,18 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie $sql .= ' SUM(pf.amount) as am, SUM(pf.multicurrency_amount) as multicurrency_am'; $sql .= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as f'; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid'; - $sql .= " WHERE f.entity = ".((int) $conf->entity); - $sql .= ' AND f.fk_soc = '.((int) $object->socid); - $sql .= ' AND f.paye = 0'; + $sql .= ' WHERE f.entity = '.((int) $conf->entity); + $sql .= ' AND (f.fk_soc = '.((int) $object->socid); + $aux = $object->fetch_thirdparty(); + // Can pay invoices of all child of parent company + if (getDolGlobalString('FACTURE_PAYMENTS_ON_DIFFERENT_THIRDPARTIES_BILLS') && !empty($object->thirdparty->parent)) { + $sql .= ' OR f.fk_soc IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'societe WHERE parent = '.((int) $object->thirdparty->parent).')'; + } + // Can pay invoices of all child of myself + if (getDolGlobalString('FACTURE_PAYMENTS_ON_SUBSIDIARY_COMPANIES')) { + $sql .= ' OR f.fk_soc IN (SELECT rowid FROM '.MAIN_DB_PREFIX.'societe WHERE parent = '.((int) $object->thirdparty->id).')'; + } + $sql .= ') AND f.paye = 0'; $sql .= ' AND f.fk_statut = 1'; // Status=0 => unvalidated, Status=2 => canceled if (!$displayAllInvoices) { From b18f4ecc696427e22ff5d6770ad9c87b142d0a68 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 3 Apr 2026 22:45:33 +0200 Subject: [PATCH 17/17] FIX #GHSA-hq5j-39f9-qxcv --- htdocs/projet/class/project.class.php | 12 ++++++------ htdocs/projet/element.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 00ad778458c..6c5ec8bbc9d 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -2056,7 +2056,7 @@ class Project extends CommonObject public function update_element($tableName, $elementSelectId) { // phpcs:enable - $sql = "UPDATE ".MAIN_DB_PREFIX.$tableName; + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->db->sanitize($tableName); if ($tableName == "actioncomm") { $sql .= " SET fk_project=".$this->id; @@ -2092,14 +2092,14 @@ class Project extends CommonObject public function remove_element($tableName, $elementSelectId, $projectfield = 'fk_projet') { // phpcs:enable - $sql = "UPDATE ".MAIN_DB_PREFIX.$tableName; + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->db->sanitize($tableName); if ($tableName == "actioncomm") { - $sql .= " SET fk_project=NULL"; - $sql .= " WHERE id=".((int) $elementSelectId); + $sql .= " SET fk_project = NULL"; + $sql .= " WHERE id = ".((int) $elementSelectId); } else { - $sql .= " SET ".$projectfield."=NULL"; - $sql .= " WHERE rowid=".((int) $elementSelectId); + $sql .= " SET ".$this->db->sanitize($projectfield)." = NULL"; + $sql .= " WHERE rowid = ".((int) $elementSelectId); } dol_syslog(get_class($this)."::remove_element", LOG_DEBUG); diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 40d2234d902..a97b5b5c818 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -741,7 +741,7 @@ if (!empty($hookmanager->resArray)) { } if ($action == "addelement") { - $tablename = GETPOST("tablename"); + $tablename = GETPOST("tablename", "aZ09"); $elementselectid = GETPOSTINT("elementselect"); $result = $object->update_element($tablename, $elementselectid); if ($result < 0) {