';
diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php
index ffabe10d68d83..360488a241015 100644
--- a/htdocs/admin/dict.php
+++ b/htdocs/admin/dict.php
@@ -8,7 +8,7 @@
* Copyright (C) 2011 Remy Younes
* Copyright (C) 2012-2015 Marcos García
* Copyright (C) 2012 Christophe Battarel
- * Copyright (C) 2011-2023 Alexandre Spangaro
+ * Copyright (C) 2011-2024 Alexandre Spangaro
* Copyright (C) 2015 Ferran Marcet
* Copyright (C) 2016 Raphaël Doursenaud
* Copyright (C) 2019-2024 Frédéric France
@@ -723,10 +723,8 @@
'supplier_proposal' => img_picto('', 'supplier_proposal', 'class="pictofixedwidth"').$langs->trans('SupplierProposal'),
'order_supplier' => img_picto('', 'supplier_order', 'class="pictofixedwidth"').$langs->trans('SupplierOrder'),
'invoice_supplier' => img_picto('', 'supplier_invoice', 'class="pictofixedwidth"').$langs->trans('SupplierBill'),
+ 'conferenceorbooth' => img_picto('', 'eventorganization', 'class="pictofixedwidth"').$langs->trans('ConferenceOrBooth'),
);
- if (getDolGlobalString('MAIN_FEATURES_LEVEL') && getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
- $elementList['conferenceorbooth'] = img_picto('', 'eventorganization', 'class="pictofixedwidth"').$langs->trans('ConferenceOrBooth');
- }
complete_elementList_with_modules($elementList);
diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
index 555778e7124b0..c8965d32c6ae0 100644
--- a/htdocs/core/class/html.form.class.php
+++ b/htdocs/core/class/html.form.class.php
@@ -5128,7 +5128,7 @@ public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0,
$resql = $this->db->query($sql);
if ($resql && $this->db->num_rows($resql) > 0) {
if ($showempty) {
- $return .= '';
+ $return .= '';
}
while ($res = $this->db->fetch_object($resql)) {
@@ -5144,6 +5144,8 @@ public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0,
}
}
$return .= '';
+
+ $return .= ajax_combobox($htmlname);
}
return $return;
}
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index 6f47d17176133..0fd073885de84 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -1567,6 +1567,7 @@ function dol_get_object_properties($obj, $properties = [])
* @param T $object Object to clone
* @param int $native 0=Full isolation method, 1=Native PHP method, 2=Full isolation method keeping only scalar and array properties (recommended)
* @return T Clone object
+ *
* @see https://php.net/manual/language.oop5.cloning.php
* @phan-suppress PhanTypeExpectedObjectPropAccess
*/
@@ -10523,7 +10524,7 @@ function verifCond($strToEvaluate, $onlysimplestring = '1')
* @param int<0,1> $hideerrors 1=Hide errors
* @param string $onlysimplestring '0' (deprecated, do not use it anymore)=Accept all chars,
* '1' (most common use)=Accept only simple string with char 'a-z0-9\s^$_+-.*>&|=!?():"\',/@';',
- * '2' (used for example for the compute property of extrafields)=Accept also '[]'
+ * '2' (used for example for the compute property of extrafields)=Accept also '<[]'
* @return void|string Nothing or return result of eval (even if type can be int, it is safer to assume string and find all potential typing issues as abs(dol_eval(...)).
* @see verifCond(), checkPHPCode() to see sanitizing rules that should be very close.
* @phan-suppress PhanPluginUnsafeEval
@@ -10551,21 +10552,31 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
if ($onlysimplestring == '1' || $onlysimplestring == '2') {
// We must accept with 1: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
// We must accept with 1: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
- // We must accept with 2: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
+ // We must accept with 2: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) <= 99) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
- // Check if there is dynamic call (first we check chars are all into use a whitelist chars)
+ // Check if there is dynamic call (first we check chars are all into a whitelist chars)
$specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
if ($onlysimplestring == '2') {
- $specialcharsallowed .= '[]';
+ $specialcharsallowed .= '<[]';
}
if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
$specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
}
if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
if ($returnvalue) {
- return 'Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s;
+ return 'Bad string syntax to evaluate (found chars that are not chars for a simple one line clean eval string): '.$s;
+ } else {
+ dol_syslog('Bad string syntax to evaluate (found chars that are not chars for a simple one line clean eval string): '.$s, LOG_WARNING);
+ return '';
+ }
+ }
+
+ // Check if there is a < or <= without spaces before/after
+ if (preg_match('/<=?[^\s]/', $s)) {
+ if ($returnvalue) {
+ return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found a < or <= without space before and after): '.$s;
} else {
- dol_syslog('Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s, LOG_WARNING);
+ dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found a < or <= without space before and after): '.$s, LOG_WARNING);
return '';
}
}
@@ -10580,15 +10591,17 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
}
}
- // Now we check if we try dynamic call (by removing white list pattern of using parenthesis then testing if a parenthesis exists)
+ // Now we check if we try dynamic call
+ // First we remove white list pattern of using parenthesis then testing if one open parenthesis exists
$savescheck = '';
$scheck = $s;
while ($scheck && $savescheck != $scheck) {
$savescheck = $scheck;
$scheck = preg_replace('/->[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
$scheck = preg_replace('/::[a-zA-Z0-9_]+\(/', '->__METHOD__', $scheck); // accept parenthesis in '...::method(...'
- $scheck = preg_replace('/^\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
- $scheck = preg_replace('/\s\(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... (' like in 'if ($a == 1)'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
+ $scheck = preg_replace('/^\(+/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with "__PARENTHESIS__ with a space after "to allow following substitutions
+ $scheck = preg_replace('/\&\&\s+\(/', '__ANDPARENTHESIS__ ', $scheck); // accept parenthesis in '... (' like in '&& (...'. Must replace with "__PARENTHESIS__ with a space after" to allow following substitutions
+ $scheck = preg_replace('/\|\|\s+\(/', '__ORPARENTHESIS__ ', $scheck); // accept parenthesis in '... (' like in '|| (...'. Must replace with "__PARENTHESIS__ with a space after" to allow following substitutions
$scheck = preg_replace('/^!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
$scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
$scheck = preg_replace('/^!\(/', '__NOTANDPARENTHESIS__', $scheck); // accept parenthesis in '!('
@@ -10597,6 +10610,7 @@ function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1'
}
//print 'scheck='.$scheck." : ".strpos($scheck, '(')." \n";
+ // Now test if it remains 1 one parenthesis.
if (strpos($scheck, '(') !== false) {
if ($returnvalue) {
return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s;
diff --git a/htdocs/core/lib/invoice2.lib.php b/htdocs/core/lib/invoice2.lib.php
index bf2e51a47fdf0..72703a72fc4db 100644
--- a/htdocs/core/lib/invoice2.lib.php
+++ b/htdocs/core/lib/invoice2.lib.php
@@ -47,12 +47,63 @@
* @param string $paymentbankid Only if payment on this bank account id
* @param int[] $thirdpartiesid List of thirdparties id when using filter=excludethirdpartiesid or filter=onlythirdpartiesid
* @param string $fileprefix Prefix to add into filename of generated PDF
+ * @param int $donotmerge 0=Default, 1=Disable the merge so do only the regeneration of PDFs.
+ * @param string $mode 'invoice' for invoices, 'proposal' for proposal, ...
* @return int Error code
*/
-function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, $usestdout, $regenerate = '', $filesuffix = '', $paymentbankid = '', $thirdpartiesid = [], $fileprefix = 'mergedpdf')
+function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, $usestdout, $regenerate = '', $filesuffix = '', $paymentbankid = '', $thirdpartiesid = [], $fileprefix = 'mergedpdf', $donotmerge = 0, $mode = 'invoice')
{
+ if ($mode == 'invoice') {
+ require_once DOL_DOCUMENT_ROOT."/compta/facture/class/facture.class.php";
+ require_once DOL_DOCUMENT_ROOT."/core/modules/facture/modules_facture.php";
+
+ $table = "facture";
+ $dir_output = $conf->facture->dir_output;
+ $date = "datef";
+
+ if ($diroutputpdf == 'auto') {
+ $diroutputpdf = $conf->invoice->dir_output.'/temp';
+ }
+ } elseif ($mode == 'order') {
+ require_once DOL_DOCUMENT_ROOT."/commande/class/commande.class.php";
+ require_once DOL_DOCUMENT_ROOT."/core/modules/commande/modules_commande.php";
+
+ $table = "commande";
+ $dir_output = $conf->order->dir_output;
+ $date = "date";
+
+ if ($diroutputpdf == 'auto') {
+ $diroutputpdf = $conf->order->dir_output.'/temp';
+ }
+ } elseif ($mode == 'proposal') {
+ require_once DOL_DOCUMENT_ROOT."/comm/propal/class/propal.class.php";
+ require_once DOL_DOCUMENT_ROOT."/core/modules/propale/modules_propale.php";
+
+ $table = "propal";
+ $dir_output = $conf->propal->dir_output;
+ $date = "datep";
+
+ if ($diroutputpdf == 'auto') {
+ $diroutputpdf = $conf->propal->dir_output.'/temp';
+ }
+ } elseif ($mode == 'shipment') {
+ require_once DOL_DOCUMENT_ROOT."/expedition/class/expedition.class.php";
+ require_once DOL_DOCUMENT_ROOT."/core/modules/expedition/modules_expedition.php";
+
+ $table = "propal";
+ $dir_output = $conf->shipment->dir_output;
+ $date = "date";
+
+ if ($diroutputpdf == 'auto') {
+ $diroutputpdf = $conf->shipment->dir_output.'/temp';
+ }
+ } else {
+ print "Bad value for mode";
+ return -1;
+ }
+
$sql = "SELECT DISTINCT f.rowid, f.ref";
- $sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
+ $sql .= " FROM ".MAIN_DB_PREFIX.$table." as f";
$sqlwhere = '';
$sqlorder = '';
if (in_array('all', $filter)) {
@@ -65,10 +116,11 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
$sqlwhere .= " AND";
}
$sqlwhere .= " f.fk_statut > 0";
- $sqlwhere .= " AND f.datef >= '".$db->idate($dateafterdate)."'";
- $sqlwhere .= " AND f.datef <= '".$db->idate($datebeforedate)."'";
- $sqlorder = " ORDER BY f.datef ASC";
+ $sqlwhere .= " AND f.".$db->sanitize($date)." >= '".$db->idate($dateafterdate)."'";
+ $sqlwhere .= " AND f.".$db->sanitize($date)." <= '".$db->idate($datebeforedate)."'";
+ $sqlorder = " ORDER BY ".$db->sanitize($date)." ASC";
}
+ // Filter for invoices only
if (in_array('nopayment', $filter)) {
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture";
if (empty($sqlwhere)) {
@@ -79,6 +131,7 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
$sqlwhere .= " f.fk_statut > 0";
$sqlwhere .= " AND pf.fk_paiement IS NULL";
}
+ // Filter for invoices only
if (in_array('payments', $filter) || in_array('bank', $filter)) {
$sql .= ", ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."paiement as p";
if (in_array('bank', $filter)) {
@@ -102,6 +155,7 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
}
$sqlorder = " ORDER BY p.datep ASC";
}
+ // Filter for invoices only
if (in_array('nodeposit', $filter)) {
if (empty($sqlwhere)) {
$sqlwhere = ' WHERE ';
@@ -110,6 +164,7 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
}
$sqlwhere .= ' type <> 3';
}
+ // Filter for invoices only
if (in_array('noreplacement', $filter)) {
if (empty($sqlwhere)) {
$sqlwhere = ' WHERE ';
@@ -118,6 +173,7 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
}
$sqlwhere .= ' type <> 1';
}
+ // Filter for invoices only
if (in_array('nocreditnote', $filter)) {
if (empty($sqlwhere)) {
$sqlwhere = ' WHERE ';
@@ -167,9 +223,6 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
if ($resql = $db->query($sql)) {
$num = $db->num_rows($resql);
$cpt = 0;
- $oldemail = '';
- $message = '';
- $total = '';
if ($num) {
// First loop on each resultset to build PDF
@@ -178,7 +231,17 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
while ($cpt < $num) {
$obj = $db->fetch_object($resql);
- $fac = new Facture($db);
+ $fac = null;
+ if ($mode == 'invoice') {
+ $fac = new Facture($db);
+ } elseif ($mode == 'order') {
+ $fac = new Commande($db);
+ } elseif ($mode == 'proposal') {
+ $fac = new Propal($db);
+ } elseif ($mode == 'shipment') {
+ $fac = new Expedition($db);
+ }
+
$result = $fac->fetch($obj->rowid);
if ($result > 0) {
$outputlangs = $langs;
@@ -188,15 +251,15 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
$outputlangs->setDefaultLang($newlangid);
}
}
- $filename = $conf->facture->dir_output.'/'.$fac->ref.'/'.$fac->ref.'.pdf';
+ $filename = $dir_output.'/'.$fac->ref.'/'.$fac->ref.'.pdf';
if ($regenerate || !dol_is_file($filename)) {
if ($usestdout) {
- print "Build PDF for invoice ".$obj->ref." - Lang = ".$outputlangs->defaultlang."\n";
+ print "Build PDF for document ".$obj->ref." - Lang = ".$outputlangs->defaultlang."\n";
}
$result = $fac->generateDocument($regenerate ? $regenerate : $fac->model_pdf, $outputlangs);
} else {
if ($usestdout) {
- print "PDF for invoice ".$obj->ref." already exists\n";
+ print "PDF for document ".$obj->ref." already exists\n";
}
}
@@ -207,15 +270,18 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte
if ($result <= 0) {
$error++;
if ($usestdout) {
- print "Error: Failed to build PDF for invoice ".($fac->ref ? $fac->ref : ' id '.$obj->rowid)."\n";
+ print "Error: Failed to build PDF for document ".($fac->ref ? $fac->ref : ' id '.$obj->rowid)."\n";
} else {
- dol_syslog("Failed to build PDF for invoice ".($fac->ref ? $fac->ref : ' id '.$obj->rowid), LOG_ERR);
+ dol_syslog("Failed to build PDF for document ".($fac->ref ? $fac->ref : ' id '.$obj->rowid), LOG_ERR);
}
}
$cpt++;
}
+ if ($donotmerge) {
+ return 1;
+ }
// Define format of output PDF
$formatarray = pdf_getFormat($langs);
diff --git a/htdocs/core/lib/memory.lib.php b/htdocs/core/lib/memory.lib.php
index 239b9f26f1db7..78523378ec317 100644
--- a/htdocs/core/lib/memory.lib.php
+++ b/htdocs/core/lib/memory.lib.php
@@ -63,10 +63,11 @@
* @param string $memoryid Memory id of shared area
* @param mixed $data Data to save. It must not be a null value.
* @param int $expire ttl in seconds, 0 never expire
+ * @param int $filecache 1 Enable file cache if no other session cache available, 0 Disabled (default)
* @return int Return integer <0 if KO, 0 if nothing is done, Nb of bytes written if OK
* @see dol_getcache()
*/
-function dol_setcache($memoryid, $data, $expire = 0)
+function dol_setcache($memoryid, $data, $expire = 0, $filecache = 0)
{
global $conf;
@@ -124,6 +125,31 @@ function dol_setcache($memoryid, $data, $expire = 0)
} elseif (getDolGlobalInt('MAIN_OPTIMIZE_SPEED') & 0x02) { // This is a really not reliable cache ! Use Memcached instead.
// Using shmop
$result = dol_setshmop($memoryid, $data, $expire);
+ } elseif ($filecache > 0) {
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+ $now = dol_now();
+ $memoryid = session_name().'_'.$memoryid;
+ $dircache = 'dolcache';
+ $pathcache = DOL_DATA_ROOT.'/'.$dircache;
+ if (!dol_is_dir($pathcache)) {
+ $result = dol_mkdir($pathcache);
+ if ($result < 0) {
+ return $result;
+ }
+ }
+ if ($expire != 0) {
+ $expire = dol_time_plus_duree($now, $expire, 's');
+ }
+
+ $cachedata = array("expire" => $expire, "data" => $data);
+ $cachejson = dolEncrypt(json_encode($cachedata));
+ if (!dol_is_file($pathcache.'/'.$memoryid.'.cache')) {
+ $result = file_put_contents($pathcache.'/'.$memoryid.'.cache', $cachejson);
+ } else {
+ return 0;
+ }
} else {
// No intersession cache system available, we use at least the perpage cache
$conf->cache['cachememory_'.$memoryid] = $data;
@@ -137,10 +163,11 @@ function dol_setcache($memoryid, $data, $expire = 0)
* Read a memory area shared by all users, all sessions on server
*
* @param string $memoryid Memory id of shared area
+ * @param int $filecache 1 Enable file cache if no other session cache available, 0 Disabled (default)
* @return int|mixed Return integer <0 if KO, data if OK, null if not found into cache or no caching feature enabled
* @see dol_setcache()
*/
-function dol_getcache($memoryid)
+function dol_getcache($memoryid, $filecache = 0)
{
global $conf;
@@ -203,6 +230,31 @@ function dol_getcache($memoryid)
// Using shmop
$data = dol_getshmop($memoryid);
return $data;
+ } elseif ($filecache > 0) {
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+ $now = dol_now();
+ $memoryid = session_name().'_'.$memoryid;
+ $dircache = 'dolcache';
+ $pathcache = DOL_DATA_ROOT.'/'.$dircache;
+ if (!dol_is_file($pathcache.'/'.$memoryid.'.cache')) {
+ return null;
+ }
+ $data = file_get_contents($pathcache.'/'.$memoryid.'.cache');
+ if (!$data) {
+ return -1;
+ }
+ $json = json_decode(dolDecrypt($data));
+ if ($json->expire > $now) {
+ return $json->data;
+ } else {
+ $result = dol_delete_file($pathcache.'/'.$memoryid.'.cache');
+ if (!$result) {
+ return -2;
+ }
+ }
+ return null;
} else {
// No intersession cache system available, we use at least the perpage cache
if (isset($conf->cache['cachememory_'.$memoryid])) {
diff --git a/htdocs/core/lib/modulebuilder.lib.php b/htdocs/core/lib/modulebuilder.lib.php
index eff2df330a2c7..67d57193729b9 100644
--- a/htdocs/core/lib/modulebuilder.lib.php
+++ b/htdocs/core/lib/modulebuilder.lib.php
@@ -411,7 +411,7 @@ function rebuildObjectSql($destdir, $module, $objectname, $newmask, $readdir = '
foreach ($object->fields as $key => $val) {
$i++;
if (!empty($val['index'])) {
- $texttoinsert .= "ALTER TABLE llx_".strtolower($module).'_'.strtolower($objectname)." ADD INDEX idx_".strtolower($module).'_'.strtolower($objectname)."_".$key." (".$key.");";
+ $texttoinsert .= "ALTER TABLE llx_".strtolower($module).'_'.strtolower($objectname)." ADD ".($key == 'ref' ? "UNIQUE INDEX uk_" : "INDEX idx_").strtolower($module).'_'.strtolower($objectname)."_".$key." (".$key.($key == 'ref' && array_key_exists('entity', $object->fields) ? ", entity" : "").");";
$texttoinsert .= "\n";
}
if (!empty($val['foreignkey'])) {
diff --git a/htdocs/core/lib/website2.lib.php b/htdocs/core/lib/website2.lib.php
index 0323e67265ada..c82484fc0566f 100644
--- a/htdocs/core/lib/website2.lib.php
+++ b/htdocs/core/lib/website2.lib.php
@@ -720,10 +720,19 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
}
}
+ $phpfullcodestringnew = $phpfullcodestring;
+
// Then check forbidden commands
if (!$error) {
- $forbiddenphpstrings = array('$$', '$_', '}[');
- //$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
+ if (getDolGlobalString("WEBSITE_DISALLOW_DOLLAR_UNDERSCORE")) {
+ $phpfullcodestring = preg_replace('/\$_COOKIE\[/', '__DOLLARCOOKIE__', $phpfullcodestring);
+ $phpfullcodestring = preg_replace('/\$_FILES\[/', '__DOLLARFILES__', $phpfullcodestring);
+ $phpfullcodestring = preg_replace('/\$_SESSION\[/', '__DOLLARSESSION__', $phpfullcodestring);
+ $forbiddenphpstrings = array('$$', '$_', '}[');
+ } else {
+ $forbiddenphpstrings = array('$$', '}[');
+ }
+ //$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_FILES', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
$forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', 'ReflectionFunction'));
$forbiddenphpfunctions = array();
@@ -818,8 +827,8 @@ function checkPHPCode(&$phpfullcodestringold, &$phpfullcodestring)
// No need to block $conf->global->aaa() because PHP try to run the method aaa of $conf->global and not the function into $conf->global->aaa.
- // Then check if installmodules does not block dynamic PHP code change.
- if ($phpfullcodestringold != $phpfullcodestring) {
+ // Then check if installmodules.lock does not block dynamic PHP code change.
+ if ($phpfullcodestringold != $phpfullcodestringnew) {
if (!$error) {
$dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
$allowimportsite = true;
diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php
index 4cf2258fded39..96cfc189c13c2 100644
--- a/htdocs/core/tpl/objectline_create.tpl.php
+++ b/htdocs/core/tpl/objectline_create.tpl.php
@@ -1317,7 +1317,7 @@ function setforpredef() {
jQuery("#select_type").val(-1);
jQuery("#select_type").addClass("placeholder");
- jQuery("#select_type").trigger("change");
+ /* jQuery("#select_type").trigger("change"); // Disabled. This create troubles. Never mind if the rester of combo is not done when using an ajax select_type combo. We don't use it because we are not able to call a focus on a change event of this combo. */
jQuery("#prod_entry_mode_free").prop('checked',false).change();
jQuery("#prod_entry_mode_predef").prop('checked',true).change();
diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php
index 9e34f4ba39fb5..93bc95c0a1291 100644
--- a/htdocs/core/tpl/objectline_view.tpl.php
+++ b/htdocs/core/tpl/objectline_view.tpl.php
@@ -52,6 +52,8 @@
* @var Translate $langs
* @var User $user
*
+ * @var string $action
+ * @var int $i
* @var 0|1 $forceall
* @var int $num
* @var 0|1 $senderissupplier
diff --git a/htdocs/document.php b/htdocs/document.php
index 6ed099120436d..067eac0d7bbed 100644
--- a/htdocs/document.php
+++ b/htdocs/document.php
@@ -129,7 +129,7 @@ function llxFooter($comment = '', $zone = 'private', $disabledoutputofmessages =
$hashp = GETPOST('hashp', 'aZ09');
$modulepart = GETPOST('modulepart', 'alpha');
$urlsource = GETPOST('urlsource', 'alpha');
-$entity = GETPOSTINT('entity') ? GETPOSTINT('entity') : $conf->entity;
+$entity = GETPOSTINT('entity');
// Security check
if (empty($modulepart) && empty($hashp)) {
diff --git a/htdocs/install/mysql/data/llx_c_type_contact.sql b/htdocs/install/mysql/data/llx_c_type_contact.sql
index 50a952bbea129..39813dfb70fff 100644
--- a/htdocs/install/mysql/data/llx_c_type_contact.sql
+++ b/htdocs/install/mysql/data/llx_c_type_contact.sql
@@ -125,4 +125,4 @@ insert into llx_c_type_contact (element, source, code, libelle, active ) values
insert into llx_c_type_contact (element, source, code, libelle, active ) values ('conferenceorbooth', 'external', 'RESPONSIBLE', 'Booth responsible', 1);
-- Thirdparty
-insert into llx_c_type_contact (element, source, code, libelle, active ) values ('societe', 'internal', 'SALESREPTHIRD', 'Sales Representative', 1);
+insert into llx_c_type_contact (element, source, code, libelle, active ) values ('societe', 'external', 'SALESREPTHIRD', 'Sales Representative', 1);
diff --git a/htdocs/install/pgsql/functions/functions-bom.sql b/htdocs/install/pgsql/functions/functions-bom.sql
new file mode 100644
index 0000000000000..e31c64e170ec2
--- /dev/null
+++ b/htdocs/install/pgsql/functions/functions-bom.sql
@@ -0,0 +1,23 @@
+-- ============================================================================
+-- Copyright (C) 2024 Laurent Destailleur
+--
+-- 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 .
+--
+-- ============================================================================
+
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bom FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bom_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bomline FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bomline_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
diff --git a/htdocs/install/pgsql/functions/functions-mo.sql b/htdocs/install/pgsql/functions/functions-mo.sql
new file mode 100644
index 0000000000000..37b92ae526919
--- /dev/null
+++ b/htdocs/install/pgsql/functions/functions-mo.sql
@@ -0,0 +1,23 @@
+-- ============================================================================
+-- Copyright (C) 2024 Laurent Destailleur
+--
+-- 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 .
+--
+-- ============================================================================
+
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_mo FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_mo_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_production FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_production_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
diff --git a/htdocs/install/pgsql/functions/functions.sql b/htdocs/install/pgsql/functions/functions.sql
index 1d3587c8e7cc4..5260a44a8c3ce 100644
--- a/htdocs/install/pgsql/functions/functions.sql
+++ b/htdocs/install/pgsql/functions/functions.sql
@@ -75,10 +75,6 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bank_account FOR EAC
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bank_account_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_blockedlog FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_blockedlog_authority FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bom FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bom_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bomline FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bom_bomline_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_bordereau_cheque FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_boxes_def FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_c_email_templates FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
@@ -127,10 +123,6 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_fichinterdet_extrafi
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_delivery FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_localtax FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_menu FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_mo FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_mo_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_production FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mrp_production_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_notify FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_notify_def FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_paiement FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang
index bff22a33e9fe6..4bb38cda648eb 100644
--- a/htdocs/langs/en_US/companies.lang
+++ b/htdocs/langs/en_US/companies.lang
@@ -33,8 +33,8 @@ CountryIsInEEC=Country is inside the European Economic Community
PriceFormatInCurrentLanguage=Price display format in the current language and currency
ThirdPartyName=Third-party name
ThirdPartyEmail=Third-party email
-ThirdParty=Third-party
-ThirdParties=Third-parties
+ThirdParty=Third party
+ThirdParties=Third parties
ThirdPartyProspects=Prospects
ThirdPartyProspectsStats=Prospects
ThirdPartyCustomers=Customers
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index 4099d76274578..73e7e6fd306b0 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -1155,6 +1155,7 @@ ContactDefault_project_task=Task
ContactDefault_propal=Proposal
ContactDefault_supplier_proposal=Supplier Proposal
ContactDefault_ticket=Ticket
+ContactDefault_societe=Third party
ContactAddedAutomatically=Contact added from third-party contact roles
More=More
ShowDetails=Show details
diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang
index 2d8d05e9761fc..ededc52cbfc5c 100644
--- a/htdocs/langs/en_US/products.lang
+++ b/htdocs/langs/en_US/products.lang
@@ -209,6 +209,7 @@ unitL=Liter
unitT=ton
unitKG=kg
unitG=Gram
+unitGAL=gallon
unitMG=mg
unitLB=pound
unitOZ=ounce
diff --git a/htdocs/product/canvas/product/tpl/card_create.tpl.php b/htdocs/product/canvas/product/tpl/card_create.tpl.php
index 5e4621b24c1a7..1f750f1108a48 100644
--- a/htdocs/product/canvas/product/tpl/card_create.tpl.php
+++ b/htdocs/product/canvas/product/tpl/card_create.tpl.php
@@ -1,6 +1,6 @@
- * Copyright (C) 2024 Frédéric France
+/* Copyright (C) 2010-2018 Regis Houssin
+ * 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
@@ -16,10 +16,14 @@
* along with this program. If not, see .
*/
/**
+ * @var Canvas $this
* @var Conf $conf
* @var Form $form
* @var Translate $langs
* @var User $user
+ *
+ * @var string $canvas
+ * @var int $refalreadyexists
*/
// Protection to avoid direct call of template
if (empty($conf) || !is_object($conf)) {
diff --git a/htdocs/product/canvas/product/tpl/card_edit.tpl.php b/htdocs/product/canvas/product/tpl/card_edit.tpl.php
index b6a95262e0dd0..1248221093495 100644
--- a/htdocs/product/canvas/product/tpl/card_edit.tpl.php
+++ b/htdocs/product/canvas/product/tpl/card_edit.tpl.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2010-2018 Regis Houssin
* Copyright (C) 2024 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
diff --git a/htdocs/product/canvas/product/tpl/card_view.tpl.php b/htdocs/product/canvas/product/tpl/card_view.tpl.php
index 3cf61f55d2fc1..e7b26f58762ec 100644
--- a/htdocs/product/canvas/product/tpl/card_view.tpl.php
+++ b/htdocs/product/canvas/product/tpl/card_view.tpl.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2010-2018 Regis Houssin
* Copyright (C) 2024 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
diff --git a/htdocs/product/canvas/service/tpl/card_create.tpl.php b/htdocs/product/canvas/service/tpl/card_create.tpl.php
index 875b790e68841..6266cdbda478e 100644
--- a/htdocs/product/canvas/service/tpl/card_create.tpl.php
+++ b/htdocs/product/canvas/service/tpl/card_create.tpl.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2010-2018 Regis Houssin
* Copyright (C) 2024 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,14 @@
* along with this program. If not, see .
*/
/**
+ * @var Canvas $this
* @var Conf $conf
* @var Form $form
* @var Translate $langs
* @var User $user
+ *
+ * @var string $canvas
+ * @var int $refalreadyexists
*/
// Protection to avoid direct call of template
if (empty($conf) || !is_object($conf)) {
diff --git a/htdocs/product/canvas/service/tpl/card_edit.tpl.php b/htdocs/product/canvas/service/tpl/card_edit.tpl.php
index eb40955a2009e..a95415aac722d 100644
--- a/htdocs/product/canvas/service/tpl/card_edit.tpl.php
+++ b/htdocs/product/canvas/service/tpl/card_edit.tpl.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2010-2018 Regis Houssin
* Copyright (C) 2024 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
diff --git a/htdocs/product/canvas/service/tpl/card_view.tpl.php b/htdocs/product/canvas/service/tpl/card_view.tpl.php
index 2b48f913b0e88..b5fd7372b3989 100644
--- a/htdocs/product/canvas/service/tpl/card_view.tpl.php
+++ b/htdocs/product/canvas/service/tpl/card_view.tpl.php
@@ -1,5 +1,5 @@
+/* Copyright (C) 2010-2018 Regis Houssin
* Copyright (C) 2024 Frédéric France
*
* This program is free software; you can redistribute it and/or modify
diff --git a/htdocs/product/list.php b/htdocs/product/list.php
index 0f7d57db40c8d..287e00cd4c96c 100644
--- a/htdocs/product/list.php
+++ b/htdocs/product/list.php
@@ -119,7 +119,7 @@
$search_accountancy_code_buy_export = GETPOST("search_accountancy_code_buy_export", 'alpha');
$search_import_key = GETPOST("search_import_key", 'alpha');
$search_finished = GETPOST("search_finished");
-$search_units = GETPOST('search_units', 'alpha');
+$search_units = GETPOST('search_units', 'int');
$type = GETPOST("type", 'alpha');
// Show/hide child product variants
@@ -583,6 +583,7 @@
if (dol_strlen($canvas) > 0) {
$sql .= " AND p.canvas = '".$db->escape($canvas)."'";
}
+
// Search for tag/category ($searchCategoryProductList is an array of ID)
if (!empty($searchCategoryProductList)) {
$searchCategoryProductSqlList = array();
@@ -641,9 +642,10 @@
if ($search_accountancy_code_buy_export) {
$sql .= natural_search($alias_product_perentity . '.accountancy_code_buy_export', clean_account($search_accountancy_code_buy_export));
}
-if (getDolGlobalString('PRODUCT_USE_UNITS') && $search_units) {
+if (getDolGlobalString('PRODUCT_USE_UNITS') && $search_units && $search_units != '-1') {
$sql .= natural_search('cu.rowid', $search_units);
}
+
// Add where from extra fields
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
// Add where from hooks
diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php
index 6f3e138c5875a..f4ffea34d182b 100644
--- a/htdocs/projet/element.php
+++ b/htdocs/projet/element.php
@@ -1324,10 +1324,11 @@
print "\n";
// Ref
- print '