diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index 97083e95f96..13a13dcb046 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -403,38 +403,38 @@ function isModEnabled($module)
*/
function getWarningDelay($module, $parmlevel1, $parmlevel2 = '')
{
- global $conf;
+ global $conf;
- // For compatibility with bad naming on module
- $moduletomoduletouse = array(
- 'invoice' => 'facture',
- );
- $moduleParmsMapping = array(
- 'product' => 'produit',
- );
+ // For compatibility with bad naming on module
+ $moduletomoduletouse = array(
+ 'invoice' => 'facture',
+ );
+ $moduleParmsMapping = array(
+ 'product' => 'produit',
+ );
- if (!empty($moduletomoduletouse[$module])) {
- $module = $moduletomoduletouse[$module];
- }
+ if (!empty($moduletomoduletouse[$module])) {
+ $module = $moduletomoduletouse[$module];
+ }
- $warningDelayPath = $parmlevel1;
- if (!empty($moduleParmsMapping[$warningDelayPath])) {
- $warningDelayPath = $moduleParmsMapping[$warningDelayPath];
- }
+ $warningDelayPath = $parmlevel1;
+ if (!empty($moduleParmsMapping[$warningDelayPath])) {
+ $warningDelayPath = $moduleParmsMapping[$warningDelayPath];
+ }
- if ($parmlevel2) {
- if (!empty($conf->$module->$warningDelayPath->warning_delay)) {
- if (!empty($conf->$module->$warningDelayPath->$parmlevel2->warning_delay)) {
- return (int) $conf->$module->$warningDelayPath->$parmlevel2->warning_delay;
- }
- }
- } else {
- if (!empty($conf->$module->$warningDelayPath->warning_delay)) {
- return (int) $conf->$module->$warningDelayPath->$parmlevel1->warning_delay;
+ if ($parmlevel2) {
+ if (!empty($conf->$module->$warningDelayPath->warning_delay)) {
+ if (!empty($conf->$module->$warningDelayPath->$parmlevel2->warning_delay)) {
+ return (int) $conf->$module->$warningDelayPath->$parmlevel2->warning_delay;
}
}
+ } else {
+ if (!empty($conf->$module->$warningDelayPath->warning_delay)) {
+ return (int) $conf->$module->$warningDelayPath->$parmlevel1->warning_delay;
+ }
+ }
- return 0;
+ return 0;
}
/**
@@ -2595,7 +2595,7 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename =
$data['ip'] .= (($j == 1) ? ' [via ' : ',').$remoteip;
}
$data['ip'] .= (($j > 0) ? ']' : '');
- } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) ) {
+ } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$tmpips = explode(',', $_SERVER['HTTP_CLIENT_IP']);
$data['ip'] = '';
$foundremoteip = 0;
@@ -7258,9 +7258,30 @@ function price2num($amount, $rounding = '', $option = 0)
}
//print "QQ".$amount."
\n";
- // Now make replace (the main goal of function)
+ // Now make replaceents (the main goal of function)
+
if ($thousand != ',' && $thousand != '.') {
- $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
+ // Accept the two types of decimal points french users (i.e., using ' ' for thousands)
+
+ // REGEX: Find the integral and decimal parts.
+ //
+ // We require that the decimal point only appears once in $amount.
+ // The regex `/^(?[^,]*,|[^.]*\.)(?[^.,]*)$/u` can be broken down as follows:
+ // - `(?[^,]*,|[^.]*\.)` is any accepted sequence up to the last potential decimal point '.' or ',' and named `int`.
+ // It covers two cases:
+ // - `[^,]*,`: Any sequence of characters that is not ',' with ',' accepted as the decimal point (from start of string because of earlier `^`);
+ // - `[^.]*\.`: Any sequence of characters that is not a '.' with '.' accepted as the decimal point (from start of string.
+ // - `(?[^.,]*)`: The sequence after the character accepted as the decimal point, not including it.
+ if (preg_match('/^(?[^,]*,|[^.]*\.)(?[^.,]*)$/u', $amount, $matches)) {
+ $intPart = $matches['int'];
+ $decPart = $matches['dec'];
+
+ // Remove all commas and dots from intPart
+ $intPart = str_replace(['.', ','], '', $intPart);
+
+ // Combine intPart and decPart with a dot
+ $amount = $intPart . $dec . $decPart;
+ }
}
$amount = str_replace(' ', '', $amount); // To avoid spaces
@@ -12122,16 +12143,23 @@ function dolExplodeKeepIfQuotes($input)
* @return string
*/
static function ($a, $b, $c) {
- if ($a !== '') return $a;
- if ($b !== '') return $b;
- if ($c !== '') return $c;
+ if ($a !== '') {
+ return $a;
+ }
+ if ($b !== '') {
+ return $b;
+ }
+ if ($c !== '') {
+ return $c;
+ }
return '';
},
$matches[1],
$matches[2],
$matches[3]
);
- return array_values(array_filter($result,
+ return array_values(array_filter(
+ $result,
/**
* Filter out empty strings from the result array.
*
@@ -12140,7 +12168,8 @@ function dolExplodeKeepIfQuotes($input)
*/
static function ($val) {
return $val !== '';
- }));
+ }
+ ));
}
diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php
index 88bbbccd788..a80f7f66e10 100644
--- a/test/phpunit/FunctionsLibTest.php
+++ b/test/phpunit/FunctionsLibTest.php
@@ -2,6 +2,7 @@
/* Copyright (C) 2010-2014 Laurent Destailleur
* Copyright (C) 2015 Juanjo Menent
* Copyright (C) 2023 Alexandre Janniaux
+ * Copyright (C) 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
@@ -482,10 +483,10 @@ class FunctionsLibTest extends CommonClassTest
/**
- * testGetBrowserInfo
- *
- * @return void
- */
+ * testGetBrowserInfo
+ *
+ * @return void
+ */
public function testGetBrowserInfo()
{
// MSIE 5.0
@@ -1618,6 +1619,9 @@ class FunctionsLibTest extends CommonClassTest
$this->assertEquals('12.4', price2num('12.4$'));
$this->assertEquals('12.4', price2num('12r.4$'));
+ $this->assertEquals('1.023210.00', price2num('1.023,210.00'), 'Test invalid 1.023,210.00 with en_US');
+ $this->assertEquals('1023.21000', price2num('1,023.210,00'), 'Test invalid 1,023.210,00 with en_US');
+
// For spanish language SeparatorThousand=. and SeparatorDecimal=,
$newlangs2 = new Translate('', $conf);
$newlangs2->setDefaultLang('es_ES');
@@ -1667,11 +1671,10 @@ class FunctionsLibTest extends CommonClassTest
$this->assertEquals(21500000, price2num('21 500 000'), 'Test 21 500 000 give 21500000 with french language');
$this->assertEquals(21500, price2num('21500.00'), 'Test 21500.00 give 21500 with french language');
$this->assertEquals(21500, price2num('21500,00'), 'Test 21500,00 give 21500 with french language');
- /*
+
$this->assertEquals(21500, price2num('21.500,00'), 'Test 21.500,00 give 21500 with french language');
$this->assertEquals('1.023.210.00', price2num('1.023,210.00'), 'Test invalid 1.023,210.00 with french language');
$this->assertEquals('1.023.210.00', price2num('1,023.210,00'), 'Test invalid 1,023.210,00 with french language');
- */
$langs = $oldlangs;