From 97b811f170b2c4cddde0ecc4fe3d5c49272d77f9 Mon Sep 17 00:00:00 2001 From: HB9HIL Date: Mon, 8 Dec 2025 21:44:47 +0100 Subject: [PATCH 01/14] Fixed Typo in German Language --- htdocs/langs/de_DE/accountancy.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/de_DE/accountancy.lang b/htdocs/langs/de_DE/accountancy.lang index b9ea42dab2e..8b6333c7186 100644 --- a/htdocs/langs/de_DE/accountancy.lang +++ b/htdocs/langs/de_DE/accountancy.lang @@ -186,7 +186,7 @@ ACCOUNTING_RESULT_LOSS=Ergebnisabrechnungskonto (Verlust) ACCOUNTING_CLOSURE_DEFAULT_JOURNAL=Journal für Abschlussbuchungen ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT=Kontengruppen, die zur Berechnung der Bilanz verwendet werden ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNTHelp=Legen Sie hier die Liste der Kontengruppen (definiert im Kontenplan) fest, die verwendet werden müssen, um alle Konten zur Berechnung der Bilanz zu finden. Trennen Sie die einzelnen Werte durch Kommas.
Beispiel: CAPIT,IMMOSTOCK,FINAN,THIRDPARTY -ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT=Kontenruppen, die zur Berechnung der Gewinn- und Verlustrechnung verwendet werden +ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT=Kontengruppen, die zur Berechnung der Gewinn- und Verlustrechnung verwendet werden ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENTHelp=Legen Sie hier die Liste der Kontengruppen (definiert im Kontenplan) fest, die verwendet werden müssen, um alle Konten zu finden um die Gewinn- und Verlustrechnung zu berechnen. Trennen Sie die einzelnen Werte durch Kommas.
Beispiel: ERLÖSE,AUFWENDUNGEN ACCOUNTING_ACCOUNT_TRANSFER_CASH=Konto (aus dem Kontenplan), das als Verrechnungskonto/Transferkonto für Banküberweisungen verwendet werden soll TransitionalAccount=Überweisungskonto From 56c6b48effb60a3f2bb78f305ed6fce24f38b930 Mon Sep 17 00:00:00 2001 From: Dolibot Date: Tue, 9 Dec 2025 12:11:04 +0000 Subject: [PATCH 02/14] PHPStan > Update baseline --- dev/build/phpstan/phpstan-baseline.neon | 36 ------------------------- 1 file changed, 36 deletions(-) diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index a7729ec1878..b34cfc57794 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -7356,24 +7356,6 @@ parameters: count: 1 path: ../../../htdocs/core/modules/import/import_csv.modules.php - - - message: '#^Property ModeleImports\:\:\$errors \(array\\) does not accept array\\|string\>\.$#' - identifier: assign.propertyType - count: 3 - path: ../../../htdocs/core/modules/import/import_csv.modules.php - - - - message: '#^Property ModeleImports\:\:\$errors \(array\\) does not accept array\\|string\>\.$#' - identifier: assign.propertyType - count: 3 - path: ../../../htdocs/core/modules/import/import_csv.modules.php - - - - message: '#^Property ModeleImports\:\:\$warnings \(array\\) does not accept array\\|string\>\.$#' - identifier: assign.propertyType - count: 1 - path: ../../../htdocs/core/modules/import/import_csv.modules.php - - message: '#^Variable \$key might not be defined\.$#' identifier: variable.undefined @@ -7422,24 +7404,6 @@ parameters: count: 1 path: ../../../htdocs/core/modules/import/import_xlsx.modules.php - - - message: '#^Property ModeleImports\:\:\$errors \(array\\) does not accept array\\|string\>\.$#' - identifier: assign.propertyType - count: 3 - path: ../../../htdocs/core/modules/import/import_xlsx.modules.php - - - - message: '#^Property ModeleImports\:\:\$errors \(array\\) does not accept array\\|string\>\.$#' - identifier: assign.propertyType - count: 3 - path: ../../../htdocs/core/modules/import/import_xlsx.modules.php - - - - message: '#^Property ModeleImports\:\:\$warnings \(array\\) does not accept array\\|string\>\.$#' - identifier: assign.propertyType - count: 1 - path: ../../../htdocs/core/modules/import/import_xlsx.modules.php - - message: '#^Variable \$where might not be defined\.$#' identifier: variable.undefined From add27583167310239f3e42d614cecbb2f461472d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 9 Dec 2025 14:30:40 +0100 Subject: [PATCH 03/14] CSS --- htdocs/core/lib/functions.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index cf1ce76ae39..23e46a5376a 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -6583,7 +6583,7 @@ function img_allow($allow, $titlealt = 'default') * @param string $morecss More CSS * @return string Return img tag */ -function img_credit_card($brand, $morecss = null) +function img_credit_card($brand, $morecss = 'fa-2x inline-block valignmiddle') { if (is_null($morecss)) { $morecss = 'fa-2x'; From 2bdcec1e636f6da7265d50066d40043386d5bb44 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 9 Dec 2025 14:51:03 +0100 Subject: [PATCH 04/14] Doc --- htdocs/core/class/translate.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/translate.class.php b/htdocs/core/class/translate.class.php index 0380fb35e4f..5e544e7b64e 100644 --- a/htdocs/core/class/translate.class.php +++ b/htdocs/core/class/translate.class.php @@ -824,9 +824,9 @@ class Translate /** * Return translation of a key depending on country * - * @param string $str string root to translate - * @param string $countrycode country code (FR, ...) - * @return string translated string + * @param string $str String root to translate. Example 'TotalHT', 'AmountLT1', 'ProfId1', 'ProfId2', 'LocalTax1IsUsedExample', ... + * @param string $countrycode Country code (FR, ...) + * @return string Translated string * @see transcountrynoentities(), picto_from_langcode() */ public function transcountry($str, $countrycode) From 9d39ac76de1a7bf73fa209f96f892a267149efe5 Mon Sep 17 00:00:00 2001 From: MDW Date: Tue, 9 Dec 2025 14:50:21 +0100 Subject: [PATCH 05/14] Qual(menu): Replace str_pad with str_repeat (fix phan notices) The changes replace instances of `str_pad('', $level)` with `str_repeat(' ', $level)`. This fixes suspicious argument order notices for str_pad (in phan). --- htdocs/core/menus/standard/auguria_menu.php | 20 ++++++++++---------- htdocs/core/menus/standard/eldy_menu.php | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/htdocs/core/menus/standard/auguria_menu.php b/htdocs/core/menus/standard/auguria_menu.php index 8812052ba66..2775ebdcdfd 100644 --- a/htdocs/core/menus/standard/auguria_menu.php +++ b/htdocs/core/menus/standard/auguria_menu.php @@ -2,7 +2,7 @@ /* Copyright (C) 2007 Patrick Raguin * Copyright (C) 2009 Regis Houssin * Copyright (C) 2008-2013 Laurent Destailleur - * 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 @@ -244,12 +244,12 @@ class MenuManager // Start a new ul level 1 $level = 1; - print str_pad('', $level).''."\n"; // end ul level 1 + print str_repeat(' ', $level - 1).''."\n"; // end ul level 1 } elseif ($val['enabled'] == 2) { print '
  • '; diff --git a/htdocs/core/menus/standard/eldy_menu.php b/htdocs/core/menus/standard/eldy_menu.php index 983b43e6169..00bba6c0239 100644 --- a/htdocs/core/menus/standard/eldy_menu.php +++ b/htdocs/core/menus/standard/eldy_menu.php @@ -1,7 +1,7 @@ * Copyright (C) 2007-2009 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 @@ -246,12 +246,12 @@ class MenuManager // Start a new ul level 1 $level = 1; - print str_pad('', $level).''."\n"; // end ul level 1 + print str_repeat(' ', $level - 1).'
  • '."\n"; // end ul level 1 } elseif ($val['enabled'] == 2) { print '
  • '; From 245fdda75b954d19eca4247294f8afb39b8e7929 Mon Sep 17 00:00:00 2001 From: MDW Date: Tue, 9 Dec 2025 14:53:25 +0100 Subject: [PATCH 06/14] Qual: Update deleteLine method parameter type for $fuser The parameter `$fuser` in the `deleteLine` method has been updated to explicitly accept a `?User` type, which is the type that is expected by ExpenseReport::call_trigger --- htdocs/expensereport/class/expensereport.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index 44dd126b498..228bf211b96 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -2356,11 +2356,11 @@ class ExpenseReport extends CommonObject * deleteline * * @param int $rowid Row id - * @param User|string $fuser User + * @param ?User $fuser User * @param int<0,1> $notrigger 1=No trigger * @return int<-1,1> Return integer <0 if KO, >0 if OK */ - public function deleteLine($rowid, $fuser = '', $notrigger = 0) + public function deleteLine($rowid, $fuser = null, $notrigger = 0) { $error = 0; From 6f4516f310e1e943d46d35698604f505e6c4770a Mon Sep 17 00:00:00 2001 From: MDW Date: Tue, 9 Dec 2025 14:59:58 +0100 Subject: [PATCH 07/14] Qual: Allow null for $outputlangs in get_date_range # Qual: Allow null for $outputlangs in get_date_range `null` is already the default for $outputlangs so allow it as an argument value (fixes phan notice) --- .../boxes/box_members_last_subscriptions.php | 2 +- htdocs/core/lib/functions.lib.php | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/htdocs/core/boxes/box_members_last_subscriptions.php b/htdocs/core/boxes/box_members_last_subscriptions.php index 25c40cee881..cbac8ba68e7 100644 --- a/htdocs/core/boxes/box_members_last_subscriptions.php +++ b/htdocs/core/boxes/box_members_last_subscriptions.php @@ -3,7 +3,7 @@ * Copyright (C) 2004-2017 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2015-2025 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * 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 diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 23e46a5376a..a3b0e6c7aca 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -9385,8 +9385,10 @@ function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = ' * @return string Translated string for the key */ function ($m) { - return '__BRACKETSTART' . $m[1] . 'BRACKETEND__'; }, - $out); + return '__BRACKETSTART' . $m[1] . 'BRACKETEND__'; + }, + $out + ); $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL); @@ -9402,8 +9404,10 @@ function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = ' * @return string Translated string for the key */ function ($m) { - return '__[' . $m[1] . ']__'; }, - $out); + return '__[' . $m[1] . ']__'; + }, + $out + ); // Remove the trick added to solve pb with text in utf8 and text without parent tag //$out = preg_replace('/^'.preg_quote('', '/').'/', '', $out); @@ -10973,8 +10977,8 @@ function print_date_range($date_start, $date_end, $format = '', $outputlangs = n * @param int $date_start Start date * @param int $date_end End date * @param string $format Output date format ('day', 'dayhour', ...) - * @param Translate $outputlangs Output language - * @param integer $withparenthesis 1=Add space and parenthesis, 0=no parenthesis, 2=Add parenthesis + * @param ?Translate $outputlangs Output language + * @param int<0,2> $withparenthesis 1=Add space and parenthesis, 0=no parenthesis, 2=Add parenthesis * @return string String */ function get_date_range($date_start, $date_end, $format = '', $outputlangs = null, $withparenthesis = 1) From d400c0d89af86d55b0afbf108a5e6c39e9158c51 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 9 Dec 2025 16:27:49 +0100 Subject: [PATCH 08/14] Debug v23 - Pbwith high number of products Add filter on country into partnership selector. --- .../modules/mailings/modules_mailings.php | 2 +- .../modules/mailings/partnership.modules.php | 35 ++++++++----- .../thirdparties_services_expired.modules.php | 49 +++++++++++-------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/htdocs/core/modules/mailings/modules_mailings.php b/htdocs/core/modules/mailings/modules_mailings.php index c6316114463..2a888c09f51 100644 --- a/htdocs/core/modules/mailings/modules_mailings.php +++ b/htdocs/core/modules/mailings/modules_mailings.php @@ -414,7 +414,7 @@ class MailingTargets // This can't be abstract as it is used for some method $widget[$j]['relpath'] = $relpath[$key]; $widget[$j]['iscoreorexternal'] = $iscoreorexternal[$key]; $widget[$j]['version'] = empty($objMod->version) ? '' : $objMod->version; - $widget[$j]['status'] = img_picto($langs->trans("Active"), 'tick'); + $widget[$j]['status'] = img_picto($langs->trans("Active"), 'tick', 'class="pictofixedwidth"'); if ($disabledbyname > 0 || $disabledbymodule > 1) { $widget[$j]['status'] = ''; } diff --git a/htdocs/core/modules/mailings/partnership.modules.php b/htdocs/core/modules/mailings/partnership.modules.php index b0cddaf5cf1..9f74591539f 100644 --- a/htdocs/core/modules/mailings/partnership.modules.php +++ b/htdocs/core/modules/mailings/partnership.modules.php @@ -93,14 +93,17 @@ class mailing_partnership extends MailingTargets $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."partnership as p, ".MAIN_DB_PREFIX."c_partnership_type as pt"; $sql .= " WHERE s.email <> ''"; $sql .= " AND s.entity IN (".getEntity('societe').")"; - $sql .= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".((int) $mailing_id).")"; + $sql .= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing = ".((int) $mailing_id).")"; $sql .= " AND p.fk_soc = s.rowid"; $sql .= " AND pt.rowid = p.fk_type"; + if (GETPOSTINT('countryid') > 0) { + $sql .= " AND s.fk_pays = ".((int) GETPOSTINT('countryid')); + } if (GETPOSTINT('filter') > 0) { - $sql .= " AND pt.rowid=".(GETPOSTINT('filter')); + $sql .= " AND pt.rowid = ".((int) GETPOSTINT('filter')); } if (GETPOSTISSET('filter_status_partnership') && GETPOSTINT('filter_status_partnership') >= 0) { - $sql .= " AND p.status = ".GETPOSTINT('filter_status_partnership'); + $sql .= " AND p.status = ".((int) GETPOSTINT('filter_status_partnership')); } if (empty($this->evenunsubscribe)) { $sql .= " AND NOT EXISTS (SELECT rowid FROM ".MAIN_DB_PREFIX."mailing_unsubscribe as mu WHERE mu.email = s.email and mu.entity = ".((int) $conf->entity).")"; @@ -112,14 +115,17 @@ class mailing_partnership extends MailingTargets $sql .= " FROM ".MAIN_DB_PREFIX."adherent as s, ".MAIN_DB_PREFIX."partnership as p, ".MAIN_DB_PREFIX."c_partnership_type as pt"; $sql .= " WHERE s.email <> ''"; $sql .= " AND s.entity IN (".getEntity('member').")"; - $sql .= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".((int) $mailing_id).")"; + $sql .= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing = ".((int) $mailing_id).")"; $sql .= " AND p.fk_member = s.rowid"; $sql .= " AND pt.rowid = p.fk_type"; + if (GETPOSTINT('countryid') > 0) { + $sql .= " AND s.country = ".((int) GETPOSTINT('countryid')); + } if (GETPOSTINT('filter') > 0) { - $sql .= " AND pt.rowid=".(GETPOSTINT('filter')); + $sql .= " AND pt.rowid=".((int) GETPOSTINT('filter')); } if (GETPOSTISSET('filter_status_partnership') && GETPOSTINT('filter_status_partnership') >= 0) { - $sql .= " AND p.status = ".GETPOSTINT('filter_status_partnership'); + $sql .= " AND p.status = ".((int) GETPOSTINT('filter_status_partnership')); } if (empty($this->evenunsubscribe)) { $sql .= " AND NOT EXISTS (SELECT rowid FROM ".MAIN_DB_PREFIX."mailing_unsubscribe as mu WHERE mu.email = s.email and mu.entity = ".((int) $conf->entity).")"; @@ -237,13 +243,14 @@ class mailing_partnership extends MailingTargets $langs->load("companies"); + // Add filter on partnership type $s = ' '; - // filter_status_thirdparties + // Add filter on thirdparties status include_once DOL_DOCUMENT_ROOT.'/partnership/class/partnership.class.php'; $tmppartnership = new Partnership($this->db); + $dummy = $tmppartnership->getLibStatut(0); // We call this only to have $tmppartnership->labelStatus loaded $s .= $form->selectarray('filter_status_partnership', $tmppartnership->labelStatus, GETPOST('filter_status_partnership'), $langs->trans("Status")); + // Add filter on country + $s .= $form->select_country(GETPOST('countryid'), 'countryid', '', 0, 'minwidth150 maxwidth200', '', $langs->trans("Country"), 0, 0, array(), 0, 0); + return $s; } diff --git a/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php b/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php index 32154603dad..054dcd09eb6 100644 --- a/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php +++ b/htdocs/core/modules/mailings/thirdparties_services_expired.modules.php @@ -57,7 +57,7 @@ class mailing_thirdparties_services_expired extends MailingTargets /** * @var array */ - public $arrayofproducts = array(); + //public $arrayofproducts = array(); /** @@ -67,14 +67,13 @@ class mailing_thirdparties_services_expired extends MailingTargets */ public function __construct($db) { - global $conf; - $this->db = $db; + /* $this->arrayofproducts = array(); // List of services - $sql = "SELECT ref FROM ".MAIN_DB_PREFIX."product"; + $sql = "SELECT id, ref FROM ".MAIN_DB_PREFIX."product"; $sql .= " WHERE entity IN (".getEntity('product').")"; if (!getDolGlobalString('CONTRACT_SUPPORT_PRODUCTS')) { $sql .= " AND fk_product_type = 1"; // By default, only services @@ -89,11 +88,12 @@ class mailing_thirdparties_services_expired extends MailingTargets while ($i < $num) { $obj = $this->db->fetch_object($result); $i++; - $this->arrayofproducts[$i] = $obj->ref; + $this->arrayofproducts[$obj->id] = $obj->ref; } } else { dol_print_error($this->db); } + */ } @@ -106,40 +106,37 @@ class mailing_thirdparties_services_expired extends MailingTargets */ public function add_to_target($mailing_id) { - global $conf; + global $conf, $langs; // phpcs:enable - $key = GETPOSTINT('filter'); + $productid = GETPOSTINT('productid'); $cibles = array(); $j = 0; - $product = ''; - if ($key == '0') { - $this->error = "Error: You must choose a filter"; + if ($productid <= 0) { + $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")); $this->errors[] = $this->error; return -1; } - $product = $this->arrayofproducts[$key]; - $now = dol_now(); - // La requete doit retourner: id, email, name + // Request must return: id, email, name $sql = "SELECT s.rowid as id, s.email, s.nom as name, cd.rowid as cdid, cd.date_ouverture as date_start_real, cd.date_fin_validite as date_end, cd.fk_contrat"; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as c"; $sql .= ", ".MAIN_DB_PREFIX."contratdet as cd, ".MAIN_DB_PREFIX."product as p"; $sql .= " WHERE s.entity IN (".getEntity('societe').")"; - $sql .= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".((int) $mailing_id).")"; + $sql .= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing = ".((int) $mailing_id).")"; $sql .= " AND s.rowid = c.fk_soc AND cd.fk_contrat = c.rowid AND s.email != ''"; - $sql .= " AND cd.statut= 4 AND cd.fk_product=p.rowid AND p.ref = '".$this->db->escape($product)."'"; + $sql .= " AND cd.statut= 4 AND cd.fk_product = p.rowid AND p.rowid = ".((int) $productid); $sql .= " AND cd.date_fin_validite < '".$this->db->idate($now)."'"; if (empty($this->evenunsubscribe)) { $sql .= " AND NOT EXISTS (SELECT rowid FROM ".MAIN_DB_PREFIX."mailing_unsubscribe as mu WHERE mu.email = s.email and mu.entity = ".((int) $conf->entity).")"; } $sql .= " ORDER BY s.email"; - // Stocke destinataires dans cibles + // Save target emails $result = $this->db->query($sql); if ($result) { $num = $this->db->num_rows($result); @@ -153,8 +150,8 @@ class mailing_thirdparties_services_expired extends MailingTargets if ($old != $obj->email) { $cibles[$j] = array( 'email' => $obj->email, - 'lastname' => $obj->name, // For thirdparties, lastname must be name - 'firstname' => '', // For thirdparties, firstname is '' + 'lastname' => $obj->name, // For thirdparties, lastname must be name + 'firstname' => '', // For thirdparties, firstname is '' 'other' => ('DateStart='.dol_print_date($this->db->jdate($obj->date_start_real), 'day')).';'. // date start real ('DateEnd='.dol_print_date($this->db->jdate($obj->date_end), 'day')).';'. // date end planned @@ -241,9 +238,20 @@ class mailing_thirdparties_services_expired extends MailingTargets */ public function formFilter() { - global $langs; + global $form, $langs, $user; - $s = img_picto('', 'product', 'class="pictofixedwidth"').''; if (count($this->arrayofproducts)) { $langs->loadLangs(array("products")); $s .= ''; @@ -255,6 +263,7 @@ class mailing_thirdparties_services_expired extends MailingTargets } $s .= ''; $s .= ajax_combobox("filter_services_expired"); + */ return $s; } From 332662aeaa6ec3682043a19ed11f146b881f8b3e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 9 Dec 2025 20:56:05 +0100 Subject: [PATCH 09/14] WIP LNE --- .../blockedlog/admin/blockedlog_archives.php | 24 ++++++++------ htdocs/blockedlog/admin/blockedlog_list.php | 4 +-- htdocs/blockedlog/class/blockedlog.class.php | 32 +++++++++---------- htdocs/langs/en_US/blockedlog.lang | 1 + 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/htdocs/blockedlog/admin/blockedlog_archives.php b/htdocs/blockedlog/admin/blockedlog_archives.php index 3c37541cd4b..752605831d5 100644 --- a/htdocs/blockedlog/admin/blockedlog_archives.php +++ b/htdocs/blockedlog/admin/blockedlog_archives.php @@ -186,8 +186,8 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / } */ - $dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 1); - $datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 12); + $dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') > 0 ? GETPOSTINT('monthtoexport') : 1); + $datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') > 0 ? GETPOSTINT('monthtoexport') : 12); if ($datee >= dol_now()) { setEventMessages($langs->trans("ErrorPeriodMustBePastToAllowExport"), null, "errors"); @@ -280,7 +280,7 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / $fh = fopen($tmpfile, 'w'); // Print line with title - fwrite($fh, "BEGIN - date=".$yearmonthdateofexport." - period=".$yearmonthtoexport + fwrite($fh, "BEGIN - date=".$yearmonthdateofexport." - period=".$yearmonthtoexport." - format=V1" .';'.$langs->transnoentities('Id') .';'.$langs->transnoentities('DateCreation') .';'.$langs->transnoentities('Action') @@ -295,6 +295,7 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / .';'.$langs->transnoentities('Fingerprint') .';'.$langs->transnoentities('Status') .';'.$langs->transnoentities('FingerprintExport') + .';'.$langs->transnoentities('FingerprintFormat') //.';'.$langs->transnoentities('FingerprintExportHMAC') ."\n"); @@ -307,14 +308,13 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / $block_static->id = $obj->rowid; $block_static->entity = $obj->entity; - - $block_static->date_creation = $db->jdate($obj->date_creation); // TODO Use gmt + $block_static->date_creation = $db->jdate($obj->date_creation); // jdate(date_creation) is UTC $block_static->amounts = (float) $obj->amounts; // Database store value with 8 digits, we cut ending 0 them with (flow) $block_static->vat = $obj->vat; $block_static->action = $obj->action; - $block_static->date_object = $db->jdate($obj->date_object); // TODO Use gmt ? + $block_static->date_object = $db->jdate($obj->date_object); // jdate(date_object) is UTC $block_static->ref_object = $obj->ref_object; $block_static->user_fullname = $obj->user_fullname; @@ -341,7 +341,7 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / $block_static->debuginfo = $obj->debuginfo; //var_dump($block->id.' '.$block->signature, $block->object_data); - $checksignature = $block_static->checkSignature($previoushash); // If $previoushash is not defined, checkSignature will search it + $checksignature = $block_static->checkSignature($previoushash); // If $previoushash is not defined, checkSignature will search it if ($checksignature) { $statusofrecord = 'Valid'; @@ -360,8 +360,11 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / $statusofrecordnote = $langs->trans("PreviousFingerprint").': '.$previoushash.($statusofrecordnote ? ' - '.$statusofrecordnote : ''); } - $signatureexport = 'TODO'; - $signatureexporthmac = 'TODO'; + $concatenateddata = $block_static->buildKeyForSignature(); + + // Version archive V1=sha256 + $signatureexport = dol_hash($previoushash.$concatenateddata, 'sha256'); // SHA256 + //$signatureexporthmac = 'TODO'; fwrite($fh, ';'.$block_static->id @@ -377,7 +380,8 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { / .';"'.str_replace('"', '""', $block_static->object_version).'";"' .str_replace('"', '""', $block_static->signature).'";"' .str_replace('"', '""', $statusofrecord).'";"' - .str_replace('"', '""', $signatureexport).'";' + .str_replace('"', '""', $signatureexport).'";"' + .str_replace('"', '""', $block_static->object_format).'";' //.str_replace('"', '""', $signatureexporthmac).'"' //.';'.$statusofrecordnote ."\n"); diff --git a/htdocs/blockedlog/admin/blockedlog_list.php b/htdocs/blockedlog/admin/blockedlog_list.php index 2a44e0b631c..9a40628312a 100644 --- a/htdocs/blockedlog/admin/blockedlog_list.php +++ b/htdocs/blockedlog/admin/blockedlog_list.php @@ -64,7 +64,7 @@ $search_startday = GETPOSTINT('search_startday'); $search_endyear = GETPOSTINT('search_endyear'); $search_endmonth = GETPOSTINT('search_endmonth'); $search_endday = GETPOSTINT('search_endday'); -$search_id = GETPOST('search_id', 'alpha'); +$search_id = GETPOST('search_id', 'alpha'); // Can be a USF search string $search_fk_user = GETPOST('search_fk_user', 'intcomma'); $search_start = -1; if (GETPOST('search_startyear') != '') { @@ -384,7 +384,7 @@ $help_url = "EN:Module_Unalterable_Archives_-_Logs|FR:Module_Archives_-_Logs_Ina llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'bodyforlist mod-blockedlog page-admin_blockedlog_list'); -$blocks = $block_static->getLog('all', (int) $search_id, $MAXLINES, $sortfield, $sortorder, (int) $search_fk_user, $search_start, $search_end, $search_ref, $search_amount, $search_code, $search_signature); +$blocks = $block_static->getLog('all', (string) $search_id, $MAXLINES, $sortfield, $sortorder, (int) $search_fk_user, $search_start, $search_end, $search_ref, $search_amount, $search_code, $search_signature); if (!is_array($blocks)) { if ($blocks == -2) { setEventMessages($langs->trans("TooManyRecordToScanRestrictFilters", $MAXLINES), null, 'errors'); diff --git a/htdocs/blockedlog/class/blockedlog.class.php b/htdocs/blockedlog/class/blockedlog.class.php index 3981bca7afa..71a19dfa656 100644 --- a/htdocs/blockedlog/class/blockedlog.class.php +++ b/htdocs/blockedlog/class/blockedlog.class.php @@ -980,15 +980,15 @@ class BlockedLog $this->id = $obj->rowid; $this->entity = $obj->entity; - $this->date_creation = $this->db->jdate($obj->date_creation); // TODO Use gmt ? - $this->date_modification = $this->db->jdate($obj->tms); // TODO Use gmt ? + $this->date_creation = $this->db->jdate($obj->date_creation); // jdate(date_creation)is UTC + $this->date_modification = $this->db->jdate($obj->tms); // jdate(tms) is UTC $this->amounts = (float) $obj->amounts; $this->action = $obj->action; $this->element = $obj->element; $this->fk_object = $obj->fk_object; - $this->date_object = $this->db->jdate($obj->date_object); // TODO Use gmt ? + $this->date_object = $this->db->jdate($obj->date_object); // jdate(date_object) is UTC $this->ref_object = $obj->ref_object; $this->fk_user = $obj->fk_user; @@ -1132,9 +1132,9 @@ class BlockedLog try { $previoushash = $this->getPreviousHash(1, 0); // This get last record and lock database until insert is done and transaction closed - $concatenatedata = $this->buildKeyForSignature(); // All the information for the hash (meta data + data saved) + $concatenateddata = $this->buildKeyForSignature(); // All the information for the hash (meta data + data saved) - $this->signature = $this->buildFinalSignatureHash($previoushash.$concatenatedata); // Build the hmac signature + $this->signature = $this->buildFinalSignatureHash($previoushash.$concatenateddata); // Build the hmac signature // For debug: $this->debuginfo = $this->buildFirstPartOfKeyForSignature(); // Not used @@ -1150,7 +1150,7 @@ class BlockedLog if ($forcesignature) { $this->signature = $forcesignature; } - //var_dump($concatenatedata);var_dump($previoushash);var_dump($this->signature); + //var_dump($concatenateddata);var_dump($previoushash);var_dump($this->signature); $sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog ("; $sql .= " date_creation,"; @@ -1232,15 +1232,15 @@ class BlockedLog $previoushash = $this->getPreviousHash(0, $this->id); } - $concatenatedata = ''; + $concatenateddata = ''; $signature = ''; // Recalculate the signature try { // Build the string for the signature - $concatenatedata = $this->buildKeyForSignature(); + $concatenateddata = $this->buildKeyForSignature(); - $signature = $this->buildFinalSignatureHash($previoushash.$concatenatedata); + $signature = $this->buildFinalSignatureHash($previoushash.$concatenateddata); } catch (Exception $e) { $res = ($signature === $this->signature); $this->error = $e->getMessage(); @@ -1262,13 +1262,13 @@ class BlockedLog if ($returnarray) { if ($returnarray == 1) { - unset($concatenatedata); + unset($concatenateddata); return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash); - } else { // Consume much memory ($concatenatedata is a large var) - return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature' => $concatenatedata); + } else { // Consume much memory ($concatenateddata is a large var) + return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature' => $concatenateddata); } } else { - unset($concatenatedata); + unset($concatenateddata); return $res; } } @@ -1299,12 +1299,10 @@ class BlockedLog /** * Return the string for signature (clear data). - * Note: rowid of line not included as it is not a business data and this allow to make backup of a year - * and restore it into another database with different ids without comprimising checksums * * @return string Key for signature */ - private function buildKeyForSignature() + public function buildKeyForSignature() { //print_r($this->object_data); if ($this->object_format == '') { @@ -1415,7 +1413,7 @@ class BlockedLog * Return array of log objects (with criteria) * * @param string $element Element to search - * @param int $fk_object Id of object to search + * @param string|int $fk_object Id of object to search. Can be a UFS search criteria. * @param int<0,max> $limit Max number of element, 0 for all * @param string $sortfield Sort field * @param string $sortorder Sort order diff --git a/htdocs/langs/en_US/blockedlog.lang b/htdocs/langs/en_US/blockedlog.lang index f419e83f0f6..6889b96acf7 100644 --- a/htdocs/langs/en_US/blockedlog.lang +++ b/htdocs/langs/en_US/blockedlog.lang @@ -25,6 +25,7 @@ ListOfTrackedEvents=List of tracked events Fingerprint=Fingerprint FingerprintExport=Fingerprint export FingerprintExportHMAC=Fingerprint export HMAC +FingerprintFormat=Fingerprint format DownloadLogCSV=Export unalterable logs (CSV) DataOfArchivedEvent=Complete data of archived event DataOfArchivedEventHelp=This field contains the complementary data that was archived on real time. Even if some parent business event could have been canceled or modified, the data stored here is the original data, and it can't be modified. From 64f966eddffda2287854f9947f70f66d3c35c925 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 9 Dec 2025 21:14:03 +0100 Subject: [PATCH 10/14] Debug v23 --- htdocs/commande/list_det.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/htdocs/commande/list_det.php b/htdocs/commande/list_det.php index 8cd8008bee6..037a23c4cd6 100644 --- a/htdocs/commande/list_det.php +++ b/htdocs/commande/list_det.php @@ -36,6 +36,13 @@ */ require '../main.inc.php'; +/** + * @var Conf $conf + * @var DoliDB $db + * @var HookManager $hookmanager + * @var Translate $langs + * @var User $user + */ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; @@ -55,14 +62,6 @@ if (isModEnabled('category')) { require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; } -/** - * @var Conf $conf - * @var DoliDB $db - * @var HookManager $hookmanager - * @var Translate $langs - * @var User $user - */ - // Load translation files required by the page $langs->loadLangs(array("categories", "orders", 'sendings', 'companies', 'compta', 'bills', 'stocks', 'products')); @@ -156,10 +155,10 @@ $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; if (!$sortfield) { - $sortfield = 'pr.ref'; + $sortfield = 'c.ref'; } if (!$sortorder) { - $sortorder = 'ASC'; + $sortorder = 'DESC'; } $show_shippable_command = GETPOST('show_shippable_command', 'aZ09'); From e8bb08ea47215c716b6cfdd5a7c7caa85f68fedc Mon Sep 17 00:00:00 2001 From: antonin_tdj <50403308+ibuiv@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:50:52 +0100 Subject: [PATCH 11/14] FIX Enhance VAT loading logic for supplier and buyer Refactor VAT loading to handle supplier and buyer roles dynamically. --- htdocs/core/tpl/objectline_title.tpl.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/htdocs/core/tpl/objectline_title.tpl.php b/htdocs/core/tpl/objectline_title.tpl.php index fff2656659b..c97a08012e7 100644 --- a/htdocs/core/tpl/objectline_title.tpl.php +++ b/htdocs/core/tpl/objectline_title.tpl.php @@ -104,7 +104,10 @@ if (in_array($object->element, array('propal', 'commande', 'facture', 'supplier_ //print ''; if (GETPOST('mode', 'aZ09') == 'vatforalllines') { print '
    '; - print $form->load_tva('vatforalllines', '', $mysoc, $object->thirdparty, 0, 0, '', false, 1); + $societe_vendeuse = strpos($object->element, 'supplier') === false ? $mysoc : $object->thirdparty; + $societe_acheteuse = strpos($object->element, 'supplier') === false ? $object->thirdparty : $mysoc; + $vat_mode = strpos($object->element, 'supplier') === false ? 1 : 2; + print $form->load_tva('vatforalllines', '', $societe_vendeuse, $societe_acheteuse, 0, 0, '', false, 1, $vat_mode); print ''; print '
    '; } From 2d0c5540118c1d2799b62b6fea9c6c47b3b9dc40 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 10 Dec 2025 15:33:33 +0100 Subject: [PATCH 12/14] Debug v23 Missing button for Prepare Credit Transfer --- htdocs/fourn/facture/card.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index dac2fa36b2f..cd5e84b528a 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -138,6 +138,7 @@ $usercancreatecontract = $user->hasRight("contrat", "creer"); // Advanced permissions $usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($usercancreate)) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("fournisseur", "supplier_invoice_advance", "validate"))); $usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight("fournisseur", "supplier_invoice_advance", "send")); +$usercancreatecreditransfer = $user->hasRight('paymentbybanktransfer', 'create'); // Permissions for includes $permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php @@ -4221,6 +4222,24 @@ if ($action == 'create') { } } + // Request a direct debit order + if ($object->status > FactureFournisseur::STATUS_DRAFT && $object->paid == 0) { + $langs->load("withdrawals"); + if ($resteapayer > 0) { + if ($usercancreatecreditransfer) { + if (!$objectidnext && $object->close_code != 'replaced') { // Not replaced by another invoice + print '
    '.$langs->trans("MakeBankTransferOrder").''; + } else { + print ''.$langs->trans('MakeBankTransferOrder').''; + } + } else { + //print ''.$langs->trans("MakeWithdrawRequest").''; + } + } else { + //print ''.$langs->trans("MakeWithdrawRequest").''; + } + } + // Create payment if ($object->type != FactureFournisseur::TYPE_CREDIT_NOTE && $object->status == FactureFournisseur::STATUS_VALIDATED && $object->paid == 0) { print ''.$langs->trans('DoPayment').''; // must use facid because id is for payment id not invoice From d1c829a79fed37b0f773189ee1932fe7d347071a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 11 Dec 2025 01:07:44 +0100 Subject: [PATCH 13/14] Fix CI --- htdocs/core/boxes/box_members_last_subscriptions.php | 2 +- htdocs/core/lib/functions.lib.php | 12 ++++++------ htdocs/core/menus/standard/auguria_menu.php | 9 ++++++++- htdocs/core/menus/standard/eldy_menu.php | 2 ++ htdocs/core/modules/mailings/partnership.modules.php | 2 +- .../thirdparties_services_expired.modules.php | 10 ++++++---- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/htdocs/core/boxes/box_members_last_subscriptions.php b/htdocs/core/boxes/box_members_last_subscriptions.php index 25c40cee881..fb423ed92d2 100644 --- a/htdocs/core/boxes/box_members_last_subscriptions.php +++ b/htdocs/core/boxes/box_members_last_subscriptions.php @@ -140,7 +140,7 @@ class box_members_last_subscriptions extends ModeleBoxes 'asis' => 1, ); - $daterange = get_date_range($this->db->jdate($obj->date_start), $this->db->jdate($obj->date_end), '', null, 0); + $daterange = get_date_range($this->db->jdate($obj->date_start), $this->db->jdate($obj->date_end), '', $langs, 0); $this->info_box_contents[$line][] = array( 'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone" title="'.dol_escape_htmltag($daterange).'"', 'text' => ''.$daterange.'', diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 23e46a5376a..f08d497922d 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -10970,12 +10970,12 @@ function print_date_range($date_start, $date_end, $format = '', $outputlangs = n /** * Format output for start and end date * - * @param int $date_start Start date - * @param int $date_end End date - * @param string $format Output date format ('day', 'dayhour', ...) - * @param Translate $outputlangs Output language - * @param integer $withparenthesis 1=Add space and parenthesis, 0=no parenthesis, 2=Add parenthesis - * @return string String + * @param int $date_start Start date + * @param int $date_end End date + * @param string $format Output date format ('day', 'dayhour', ...) + * @param Translate|null $outputlangs Output language + * @param integer $withparenthesis 1=Add space and parenthesis, 0=no parenthesis, 2=Add parenthesis + * @return string String */ function get_date_range($date_start, $date_end, $format = '', $outputlangs = null, $withparenthesis = 1) { diff --git a/htdocs/core/menus/standard/auguria_menu.php b/htdocs/core/menus/standard/auguria_menu.php index 8812052ba66..0eb23d9bfc2 100644 --- a/htdocs/core/menus/standard/auguria_menu.php +++ b/htdocs/core/menus/standard/auguria_menu.php @@ -244,11 +244,13 @@ class MenuManager // Start a new ul level 1 $level = 1; + // @phan-suppress-next-line PhanParamSuspiciousOrder print str_pad('', $level).''."\n"; // end ul level 1 - print str_pad('', $level - 1).'
  • '."\n"; // end ul level 1 + // @phan-suppress-next-line PhanParamSuspiciousOrder + print str_pad('', $level - 1).''."\n"; // end ul level 1 } elseif ($val['enabled'] == 2) { print '
  • '; diff --git a/htdocs/core/menus/standard/eldy_menu.php b/htdocs/core/menus/standard/eldy_menu.php index 983b43e6169..a0ee8ce41b1 100644 --- a/htdocs/core/menus/standard/eldy_menu.php +++ b/htdocs/core/menus/standard/eldy_menu.php @@ -246,11 +246,13 @@ class MenuManager // Start a new ul level 1 $level = 1; + // @phan-suppress-next-line PhanParamSuspiciousOrder print str_pad('', $level).'