diff --git a/ChangeLog b/ChangeLog
index 7a87f3fbc2d..cbd76fe7c37 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,8 +29,8 @@ For users:
---------------
NEW: PHP 8.1 compatibility:
- Warning: Application works correctly with PHP8 and 8.1 but you may experience a lot of PHP warning into the PHP server log files (depending
- on the PHP setup). Removal of all PHP warnings on server side is planned for v17.
+ Warning!! Application works correctly with PHP8 and 8.1 but you will experience a lot of PHP warnings into the PHP server
+ log files (depending on your PHP setup). Removal of all PHP warnings on server side is planned for v17.
NEW: Support for recurring purchase invoices.
NEW: #20292 Include German public holidays
NEW: Can show ZATCA QR-Code on PDFs
diff --git a/htdocs/comm/mailing/card.php b/htdocs/comm/mailing/card.php
index 81e36c006ca..e59389a87b7 100644
--- a/htdocs/comm/mailing/card.php
+++ b/htdocs/comm/mailing/card.php
@@ -477,7 +477,7 @@ if (empty($reshook)) {
}
}
- $trackid = 'emailingtest';
+ $trackid = 'emailing-test';
$mailfile = new CMailFile($tmpsujet, $object->sendto, $object->email_from, $tmpbody, $arr_file, $arr_mime, $arr_name, '', '', 0, $msgishtml, $object->email_errorsto, $arr_css, $trackid, '', 'emailing');
$result = $mailfile->sendfile();
diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php
index a8d54909065..56b8943f5ad 100644
--- a/htdocs/compta/facture/list.php
+++ b/htdocs/compta/facture/list.php
@@ -2385,7 +2385,7 @@ if ($resql) {
// Note public
if (!empty($arrayfields['f.note_public']['checked'])) {
print '
';
- print dol_escape_htmltag($obj->note_public);
+ print dol_string_nohtmltag($obj->note_public);
print ' ';
if (!$i) {
$totalarray['nbfield']++;
@@ -2394,7 +2394,7 @@ if ($resql) {
// Note private
if (!empty($arrayfields['f.note_private']['checked'])) {
print '';
- print dol_escape_htmltag($obj->note_private);
+ print dol_string_nohtmltag($obj->note_private);
print ' ';
if (!$i) {
$totalarray['nbfield']++;
diff --git a/htdocs/conf/conf.php.example b/htdocs/conf/conf.php.example
index b58ac33707e..4090130bc36 100644
--- a/htdocs/conf/conf.php.example
+++ b/htdocs/conf/conf.php.example
@@ -162,8 +162,9 @@ $dolibarr_main_db_readonly=0;
// dolibarr_main_instance_unique_id
// An secret ID that is unique for each installation.
-// This value is also visible and never propagated outside of Dolibarr, so it can be used as a salt / key for some encryption.
-// To propagate a unique key, you propagate the value concatenated with a string with a hash function. Example: md5('dolibarr'+dolibarr_main_instance_unique_id)
+// This value is also visible and never propagated outside of Dolibarr, so it can be used as a salt / key for some encryption (For example to get
+// a unique hashed key, application will hash the value concatenated with a string. Example: md5('dolibarr'+dolibarr_main_instance_unique_id)
+// WARNING: Changing this value will also make some sensitive values encrypted in database wrong.
// Default value: randomly defined during installation
// Examples:
// $dolibarr_main_instance_unique_id='84b5bc91f83b56e458db71e0adac2b62';
diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php
index 05489c3dc50..ba9ebfd81c4 100644
--- a/htdocs/core/class/html.formfile.class.php
+++ b/htdocs/core/class/html.formfile.class.php
@@ -838,6 +838,7 @@ class FormFile
// Show file name with link to download
$out .= '';
+ $out .= $this->showPreview($file, $modulepart, $relativepath, 0, $param, 'paddingright')."\n";
$out .= 'trans("File").': '.$file["name"]);
- $out .= dol_trunc($file["name"], 40);
- $out .= ' '."\n";
- $out .= $this->showPreview($file, $modulepart, $relativepath, 0, $param);
+ $out .= dol_trunc($file["name"], 150);
+ $out .= '';
$out .= ' ';
// Show file size
@@ -1300,6 +1300,11 @@ class FormFile
// File name
print '';
+ // Preview link
+ if (!$editline) {
+ print $this->showPreview($file, $modulepart, $filepath, 0, '&entity='.(!empty($object->entity) ? $object->entity : $conf->entity), 'paddingright') . "\n";
+ }
+
// Show file name with link to download
//print "XX".$file['name']; //$file['name'] must be utf8
print '\n";
@@ -2072,9 +2073,10 @@ class FormFile
* @param string $relativepath Relative path of docs
* @param integer $ruleforpicto Rule for picto: 0=Use the generic preview picto, 1=Use the picto of mime type of file). Use a negative value to show a generic picto even if preview not available.
* @param string $param More param on http links
+ * @param string $moreclass Add more class to class style
* @return string $out Output string with HTML
*/
- public function showPreview($file, $modulepart, $relativepath, $ruleforpicto = 0, $param = '')
+ public function showPreview($file, $modulepart, $relativepath, $ruleforpicto = 0, $param = '', $moreclass = '')
{
global $langs, $conf;
@@ -2082,7 +2084,7 @@ class FormFile
if ($conf->browser->layout != 'phone' && !empty($conf->use_javascript_ajax)) {
$urladvancedpreview = getAdvancedPreviewUrl($modulepart, $relativepath, 1, $param); // Return if a file is qualified for preview.
if (count($urladvancedpreview)) {
- $out .= ' ';
+ $out .= ' ';
//$out.= ' ';
if (empty($ruleforpicto)) {
//$out.= img_picto($langs->trans('Preview').' '.$file['name'], 'detail');
diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php
index 3f26a98c728..5e12a30ba0e 100644
--- a/htdocs/core/class/notify.class.php
+++ b/htdocs/core/class/notify.class.php
@@ -456,7 +456,7 @@ class Notify
$notifcodedefid = $obj->adid;
$trackid = '';
if ($obj->type_target == 'tocontactid') {
- $trackid = 'con'.$obj->cid;
+ $trackid = 'ctc'.$obj->cid;
}
if ($obj->type_target == 'touserid') {
$trackid = 'use'.$obj->cid;
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index a4ee4e5b802..7b3aa47af17 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -1456,9 +1456,9 @@ function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapeta
// escape quotes and backslashes, newlines, etc.
if ($escapeonlyhtmltags) {
- $tmp = htmlspecialchars_decode($stringtoescape, ENT_COMPAT);
+ $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
} else {
- $tmp = html_entity_decode($stringtoescape, ENT_COMPAT, 'UTF-8');
+ $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
}
if (!$keepb) {
$tmp = strtr($tmp, array(""=>'', ' '=>''));
diff --git a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php
index 335024554fc..a8932934bd1 100644
--- a/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php
+++ b/htdocs/core/triggers/interface_95_modWebhook_WebhookTriggers.class.php
@@ -52,7 +52,7 @@ class InterfaceWebhookTriggers extends DolibarrTriggers
$this->description = "Webhook triggers.";
// 'development', 'experimental', 'dolibarr' or version
$this->version = 'development';
- $this->picto = 'webhook@webhook';
+ $this->picto = 'webhook';
}
/**
diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php
index 006376cfd55..47d62197a70 100644
--- a/htdocs/emailcollector/class/emailcollector.class.php
+++ b/htdocs/emailcollector/class/emailcollector.class.php
@@ -1478,22 +1478,38 @@ class EmailCollector extends CommonObject
$headers['Subject'] = $this->decodeSMTPSubject($headers['Subject']);
+ $emailto = $this->decodeSMTPSubject($overview[0]->to);
+
dol_syslog("** Process email ".$iforemailloop." References: ".$headers['References']." Subject: ".$headers['Subject']);
+ $trackidfoundintorecipienttype = '';
+ $trackidfoundintorecipientid = 0;
+ $reg = array();
+ // See also later list of all supported tags...
+ if (preg_match('/\+(thi|ctc|use|mem|sub|proj|tas|con|tic|job|pro|ord|inv|spro|sor|sin|leav|stockinv|job|surv|salary)([0-9]+)@/', $emailto, $reg)) {
+ $trackidfoundintorecipienttype = $reg[1];
+ $trackidfoundintorecipientid = $reg[2];
+ } elseif (preg_match('/\+emailing-(\w+)@/', $emailto, $reg)) { // Can be 'emailing-test' or 'emailing-IdMailing-IdRecipient'
+ $trackidfoundintorecipienttype = 'emailing';
+ $trackidfoundintorecipientid = $reg[1];
+ }
+
// If there is a filter on trackid
if ($searchfilterdoltrackid > 0) {
- if (empty($headers['References']) || !preg_match('/@'.preg_quote($host, '/').'/', $headers['References'])) {
- $nbemailprocessed++;
- dol_syslog(" Discarded - No header References found");
- continue; // Exclude email
+ if (empty($trackidfoundintorecipienttype)) {
+ if (empty($headers['References']) || !preg_match('/@'.preg_quote($host, '/').'/', $headers['References'])) {
+ $nbemailprocessed++;
+ dol_syslog(" Discarded - No suffix in email recipient and no Header References found matching signature of application so with a trackid");
+ continue; // Exclude email
+ }
}
}
if ($searchfilternodoltrackid > 0) {
- if (!empty($headers['References']) && preg_match('/@'.preg_quote($host, '/').'/', $headers['References'])) {
+ if (!empty($trackidfoundintorecipienttype) || (!empty($headers['References']) && preg_match('/@'.preg_quote($host, '/').'/', $headers['References']))) {
$nbemailprocessed++;
- dol_syslog(" Discarded - Header References found and matching signature of application");
+ dol_syslog(" Discarded - Suffix found into email or Header References found and matching signature of application so with a trackid");
continue; // Exclude email
}
}
@@ -1705,13 +1721,19 @@ class EmailCollector extends CommonObject
foreach ($arrayofreferences as $reference) {
//print "Process mail ".$iforemailloop." email_msgid ".$msgid.", date ".dol_print_date($date, 'dayhour').", subject ".$subject.", reference ".dol_escape_htmltag($reference)." \n";
- $resultsearchtrackid = preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote($host, '/').'/', $reference, $reg);
- if (empty($resultsearchtrackid) && getDolGlobalString('EMAIL_ALTERNATIVE_HOST_SIGNATURE')) {
- $resultsearchtrackid = preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote(getDolGlobalString('EMAIL_ALTERNATIVE_HOST_SIGNATURE'), '/').'/', $reference, $reg);
+ if (!empty($trackidfoundintorecipienttype)) {
+ $resultsearchtrackid = -1;
+ $reg[1] = $trackidfoundintorecipienttype;
+ $reg[2] = $trackidfoundintorecipientid;
+ } else {
+ $resultsearchtrackid = preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote($host, '/').'/', $reference, $reg);
+ if (empty($resultsearchtrackid) && getDolGlobalString('EMAIL_ALTERNATIVE_HOST_SIGNATURE')) {
+ $resultsearchtrackid = preg_match('/dolibarr-([a-z]+)([0-9]+)@'.preg_quote(getDolGlobalString('EMAIL_ALTERNATIVE_HOST_SIGNATURE'), '/').'/', $reference, $reg);
+ }
}
- if ($resultsearchtrackid) {
- // This is a Dolibarr reference of the server
+ if (!empty($resultsearchtrackid)) {
+ // We found a tracker (in recipient email or into a Reference matching the Dolibarr server)
$trackid = $reg[1].$reg[2];
$objectid = $reg[2];
diff --git a/htdocs/fichinter/list.php b/htdocs/fichinter/list.php
index 858ea2d3a4b..731442695d2 100644
--- a/htdocs/fichinter/list.php
+++ b/htdocs/fichinter/list.php
@@ -802,7 +802,7 @@ while ($i < $imaxinloop) {
// Note public
if (!empty($arrayfields['f.note_public']['checked'])) {
print ' ';
- print dol_escape_htmltag($obj->note_public);
+ print dol_string_nohtmltag($obj->note_public);
print ' ';
if (!$i) {
$totalarray['nbfield']++;
@@ -811,7 +811,7 @@ while ($i < $imaxinloop) {
// Note private
if (!empty($arrayfields['f.note_private']['checked'])) {
print '';
- print dol_escape_htmltag($obj->note_private);
+ print dol_string_nohtmltag($obj->note_private);
print ' ';
if (!$i) {
$totalarray['nbfield']++;
diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php
index 1fdc1816544..5524783e275 100644
--- a/htdocs/fourn/class/fournisseur.product.class.php
+++ b/htdocs/fourn/class/fournisseur.product.class.php
@@ -578,7 +578,7 @@ class ProductFournisseur extends Product
$sql .= " pfp.supplier_reputation, pfp.fk_user, pfp.datec,";
$sql .= " pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code,";
$sql .= " pfp.barcode, pfp.fk_barcode_type, pfp.packaging,";
- $sql .= " p.ref as product_ref";
+ $sql .= " p.ref as product_ref, p.tosell as status, p.tobuy as status_buy";
$sql .= " FROM ".MAIN_DB_PREFIX."product_fournisseur_price as pfp, ".MAIN_DB_PREFIX."product as p";
$sql .= " WHERE pfp.rowid = ".(int) $rowid;
$sql .= " AND pfp.fk_product = p.rowid";
@@ -594,7 +594,8 @@ class ProductFournisseur extends Product
$this->fk_product = $obj->fk_product;
$this->product_id = $obj->fk_product;
$this->product_ref = $obj->product_ref;
-
+ $this->status = $obj->status;
+ $this->status_buy = $obj->status_buy;
$this->fourn_id = $obj->fk_soc;
$this->fourn_ref = $obj->ref_fourn; // deprecated
$this->ref_supplier = $obj->ref_fourn;
@@ -670,7 +671,7 @@ class ProductFournisseur extends Product
// phpcs:enable
global $conf;
- $sql = "SELECT s.nom as supplier_name, s.rowid as fourn_id, p.ref as product_ref,";
+ $sql = "SELECT s.nom as supplier_name, s.rowid as fourn_id, p.ref as product_ref, p.tosell as status, p.tobuy as status_buy, ";
$sql .= " pfp.rowid as product_fourn_pri_id, pfp.entity, pfp.ref_fourn, pfp.desc_fourn, pfp.fk_product as product_fourn_id, pfp.fk_supplier_price_expression,";
$sql .= " pfp.price, pfp.quantity, pfp.unitprice, pfp.remise_percent, pfp.remise, pfp.tva_tx, pfp.fk_availability, pfp.charges, pfp.info_bits, pfp.delivery_time_days, pfp.supplier_reputation,";
$sql .= " pfp.multicurrency_price, pfp.multicurrency_unitprice, pfp.multicurrency_tx, pfp.fk_multicurrency, pfp.multicurrency_code, pfp.datec, pfp.tms,";
@@ -699,6 +700,8 @@ class ProductFournisseur extends Product
$prodfourn->product_ref = $record["product_ref"];
$prodfourn->product_fourn_price_id = $record["product_fourn_pri_id"];
+ $prodfourn->status = $record["status"];
+ $prodfourn->status_buy = $record["status_buy"];
$prodfourn->product_fourn_id = $record["product_fourn_id"];
$prodfourn->product_fourn_entity = $record["entity"];
$prodfourn->ref_supplier = $record["ref_fourn"];
diff --git a/htdocs/install/fileconf.php b/htdocs/install/fileconf.php
index 14f1ee2a1cd..f8dcdfe230b 100644
--- a/htdocs/install/fileconf.php
+++ b/htdocs/install/fileconf.php
@@ -448,7 +448,10 @@ if (!empty($force_install_noedit)) {
>
-
@@ -503,7 +507,10 @@ if (!empty($force_install_noedit)) {
>
-
@@ -613,30 +621,13 @@ jQuery(document).ready(function() {
});
- function init_needroot()
- {
- console.log("init_needroot force_install_noedit=");
- /*alert(jQuery("#db_create_database").prop("checked")); */
- if (jQuery("#db_create_database").is(":checked") || jQuery("#db_create_user").is(":checked"))
- {
- jQuery(".hideroot").show();
-
- jQuery(".needroot").removeAttr('disabled');
-
- }
- else
- {
- jQuery(".hideroot").hide();
- jQuery(".needroot").prop('disabled', true);
- }
- }
-
init_needroot();
jQuery("#db_create_database").click(function() {
+ console.log("click on db_create_database");
init_needroot();
});
jQuery("#db_create_user").click(function() {
+ console.log("click on db_create_user");
init_needroot();
});
@@ -644,6 +635,27 @@ jQuery(document).ready(function() {
});
+function init_needroot()
+{
+ console.log("init_needroot force_install_noedit=");
+ /*alert(jQuery("#db_create_database").prop("checked")); */
+ if (jQuery("#db_create_database").is(":checked") || jQuery("#db_create_user").is(":checked"))
+ {
+ console.log("init_needroot show root section");
+ jQuery(".hideroot").show();
+
+ jQuery(".needroot").removeAttr('disabled');
+
+ }
+ else
+ {
+ console.log("init_needroot hide root section");
+ jQuery(".hideroot").hide();
+ jQuery(".needroot").prop('disabled', true);
+ }
+}
+
function checkDatabaseName(databasename) {
if (databasename.match(/[;\.]/)) { return false; }
return true;
@@ -651,6 +663,8 @@ function checkDatabaseName(databasename) {
function jscheckparam()
{
+ console.log("Click on jscheckparam");
+
ok=true;
if (document.forminstall.main_dir.value == '')
@@ -688,12 +702,14 @@ function jscheckparam()
{
ok=false;
alert('transnoentities("YouAskToCreateDatabaseSoRootRequired")); ?>');
+ init_needroot();
}
// If create user asked
else if (document.forminstall.db_create_user.checked == true && (document.forminstall.db_user_root.value == ''))
{
ok=false;
alert('transnoentities("YouAskToCreateDatabaseUserSoRootRequired")); ?>');
+ init_needroot();
}
return ok;
diff --git a/htdocs/install/inc.php b/htdocs/install/inc.php
index a20c3489866..657e9841100 100644
--- a/htdocs/install/inc.php
+++ b/htdocs/install/inc.php
@@ -530,7 +530,7 @@ function pFooter($nonext = 0, $setuplang = '', $jscheckfunction = '', $withpleas
print ' ';
}
- print ''."\n";
+ print ' '."\n";
// If there is some logs in buffer to show
if (isset($conf->logbuffer) && count($conf->logbuffer)) {
diff --git a/htdocs/langs/en_US/install.lang b/htdocs/langs/en_US/install.lang
index 1b9eb767416..ad8217153be 100644
--- a/htdocs/langs/en_US/install.lang
+++ b/htdocs/langs/en_US/install.lang
@@ -213,4 +213,4 @@ ClickOnLinkOrRemoveManualy=If an upgrade is in progress, please wait. If not, cl
Loaded=Loaded
FunctionTest=Function test
NodoUpgradeAfterDB=No action requested by external modules after upgrade of database
-NodoUpgradeAfterFiles=No action requested by external modules after upgrade of files or directories
\ No newline at end of file
+NodoUpgradeAfterFiles=No action requested by external modules after upgrade of files or directories
diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php
index 6d89923f20e..9969ea061e9 100644
--- a/htdocs/main.inc.php
+++ b/htdocs/main.inc.php
@@ -1445,6 +1445,7 @@ function top_httphead($contenttype = 'text/html', $forcenocache = 0)
$contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSP');
if (!is_object($hookmanager)) {
+ include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
$hookmanager = new HookManager($db);
}
$hookmanager->initHooks(array("main"));
diff --git a/htdocs/user/group/card.php b/htdocs/user/group/card.php
index e5ffc83d6eb..c17893e7eb4 100644
--- a/htdocs/user/group/card.php
+++ b/htdocs/user/group/card.php
@@ -449,7 +449,7 @@ if ($action == 'create') {
print '';
print '';
print $useringroup->getNomUrl(-1, '', 0, 0, 24, 0, 'login');
- if ($useringroup->admin && !$useringroup->entity) {
+ if (isModEnabled('multicompany') && $useringroup->admin && empty($useringroup->entity)) {
print img_picto($langs->trans("SuperAdministrator"), 'redstar');
} elseif ($useringroup->admin) {
print img_picto($langs->trans("Administrator"), 'star');