diff --git a/ChangeLog b/ChangeLog
index cd9397939f5..2e8bfc968c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,50 @@
English Dolibarr ChangeLog
--------------------------------------------------------------
+***** ChangeLog for 14.0.2 compared to 14.0.1 *****
+
+FIX: #18353 Invoice list translation issue
+FIX: #18375 SQL Error on tasks statistics
+FIX: #18465
+FIX: #18484
+FIX: #18531
+FIX: #18542 REST API: set global $user variable to DolibarrApiAccess::user.
+FIX: #18544 Shipment REST API: load thirdparty object into the shipment before validating.
+FIX: #18544 Shipment rest api: load thirdparty object when validating
+FIX: #18565
+FIX: #18589 #18617
+FIX: #18591 : Remove double quotes of SQL Queries for postgresql compatibility
+FIX: #18666 Order / Shipment list: Don't SQL JOIN category table when not necessary.
+FIX: Accountancy - Some problems of length with general & subledger account
+FIX: add DISTINCT
+FIX: Add option $noescapecommand in executeCLI for better compatibility
+FIX: Add token to remove error when removing widget
+FIX: Add token when remove the last widget on home page
+FIX: an approved holiday can be canceled by an admin.
+FIX: better sql request
+FIX: change LOG_DEBUG with LOG_WARNING in syslog and remove sql error in syslog (already done)
+FIX: Collapsing of extrafields has disappeared.
+FIX: Date of payment of subscription must not be set to 1970-01-01.
+FIX: Export of website generates a package that contains a sql error
+FIX: Field already present in SQL request
+FIX: increase maxlength of password input
+FIX: invoice fetch not found syslog debug level instead of error
+FIX: Invoice list - Wrong name for column total_tva
+FIX: invoice validation: when checking if any vat rate has a negative amount, prevent false positives with -1E-14 amounts
+FIX: Manage credit note on situation invoice for calculate margin
+FIX: Menu List of project was not visible.
+FIX: migration script
+FIX: multicompany transverse mode compatibility
+FIX: option "Default value for field 'Refuse bulk emailings'"
+FIX: Recommended session.cookie_samesite must be 'Lax' not 'Strict'.
+FIX: Relative discount with high nb of decimals
+FIX: salary extrafields don't work and table is not well named
+FIX: Supplier invoice list - Wrong language key used
+FIX: wrong table_element_line
+FIX: wrong users count in multicompany transverse mode
+FIX: #yogosha6944 Protection against traversal path.
+
+
***** ChangeLog for 14.0.1 compared to 14.0.0 *****
FIX: $conf->task used but it does not exist, use $conf->projet instead
diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php
index 8e7ef3ef46c..e5a39c0d0a8 100755
--- a/build/generate_filelist_xml.php
+++ b/build/generate_filelist_xml.php
@@ -239,7 +239,7 @@ fclose($fp);
if (empty($buildzip)) {
print "File ".$outputfile." generated\n";
} else {
- $result = dol_compress_file($outputfile, $outputfile.'.zip');
+ $result = dol_compress_file($outputfile, $outputfile.'.zip', 'zip');
if ($result > 0) {
dol_delete_file($outputfile);
print "File ".$outputfile.".zip generated\n";
diff --git a/dev/examples/ldap/ldapsearch_sample1.txt b/dev/examples/ldap/ldapsearch_sample1.txt
index 5f667ffd7a4..a02ad632cd0 100644
--- a/dev/examples/ldap/ldapsearch_sample1.txt
+++ b/dev/examples/ldap/ldapsearch_sample1.txt
@@ -3,11 +3,26 @@
#
# Use this sample to search into a ldap
#
-# ldapsearch -h hostname -x
-# ldapsearch -h hostname -x -b "ou=people,dc=teclib,dc=infra"
-# ldapsearch -h hostname -x -z 0 -b "o=somecompany.com" -D "cn=manager,o=somecompany.com" -w password "(objectclass=*)"
-# ldapsearch -h hostname -x -b "o=somecompany.com" -D "cn=manager,o=somecompany.com" -w password "(objectclass=*)"
+
+# Anonymous access
+# ldapsearch -h hostname -p 389
+#
+# Login access (using a Bind DN)
+# ldapsearch -h hostname -p 389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
+# ldapsearch -H ldap://hostname:389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
+# ldapsearch -d1 -H ldap://hostname:389 -x -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
+# ldapsearch -H ldap://hostname:389 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password
+#
+# Login access in SSL (using a Bind DN)
+# ldapsearch -H ldaps://hostnamme:636 -z 0 -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password -b "cn=users,dc=ldap,dc=test,dc=local
+# If it fails, you may try to use "hostname" that is real name of certificate.
+# You must also check that /etc/ldap/ldap.conf contains the line TLS_CACERT /etc/ssl/certs/ca-certificates.crt
+
+# What to search
+# ldapsearch -h hostname -p 389 -x -D "uid=root,cn=users,dc=ldap,dc=test,dc=local" -w password -b "cn=users,dc=ldap,dc=test,dc=local"
+# ldapsearch -h hostname -p 389 -x -D "cn=manager,o=somecompany.com" -w password -b "ou=people,dc=teclib,dc=infra"
+# ldapsearch -h hostname -p 389 -x -D "cn=manager,o=somecompany.com" -w password -b "o=somecompany.com" "(objectclass=*)"
#
# Example to test a ldap search:
-# ldapsearch -h hostname -x -z 5 -b 'OU=Collaborateurs,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -D 'CN=UserAdmin,OU=Informatique,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -w password
+# ldapsearch -h hostname -p 389 -x -z 5 -b 'OU=Collaborateurs,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -D 'CN=UserAdmin,OU=Informatique,OU=Utilisateurs,OU=MyCompany,DC=bocal,DC=lan' -w password
diff --git a/htdocs/adherents/admin/member.php b/htdocs/adherents/admin/member.php
index 5a589756feb..018498c2457 100644
--- a/htdocs/adherents/admin/member.php
+++ b/htdocs/adherents/admin/member.php
@@ -25,7 +25,7 @@
*/
/**
- * \file htdocs/adherents/admin/adherent.php
+ * \file htdocs/adherents/admin/member.php
* \ingroup member
* \brief Page to setup the module Foundation
*/
diff --git a/htdocs/admin/dolistore/class/dolistore.class.php b/htdocs/admin/dolistore/class/dolistore.class.php
index bfcb751f9a9..5e7a229fee3 100644
--- a/htdocs/admin/dolistore/class/dolistore.class.php
+++ b/htdocs/admin/dolistore/class/dolistore.class.php
@@ -217,15 +217,15 @@ class Dolistore
for ($i = 0; $i < $nbofcateg; $i++) {
$cat = $this->categories[$i];
if ($cat->is_root_category == 1 && $parent == 0) {
- $html .= '
';
+ $html .= ' ';
$html .= self::get_categories($cat->id);
$html .= " \n";
} elseif (trim($cat->id_parent) == $parent && $cat->active == 1 && trim($cat->id_parent) != 0) { // si cat est de ce niveau
$select = ($cat->id == $this->categorie) ? ' selected' : '';
- $html .= 'description->language[$this->lang - 1])).'" ';
- $html .= '>'.$cat->name->language[$this->lang - 1].' '.$cat->nb_products_recursive.' ';
+ $html .= '>'.dol_escape_htmltag($cat->name->language[$this->lang - 1]).' '.dol_escape_htmltag($cat->nb_products_recursive).' ';
$html .= self::get_categories($cat->id);
$html .= " \n";
}
@@ -267,9 +267,9 @@ class Dolistore
// add image or default ?
if ($product->id_default_image != '') {
- $image_url = DOL_URL_ROOT.'/admin/dolistore/ajax/image.php?id_product='.$product->id.'&id_image='.$product->id_default_image;
- $images = '';
- $images .= ' ';
+ $image_url = DOL_URL_ROOT.'/admin/dolistore/ajax/image.php?id_product='.((int) $product->id).'&id_image='.((int) $product->id_default_image);
+ $images = '';
+ $images .= ' ';
} else {
$images = ' ';
}
@@ -277,11 +277,11 @@ class Dolistore
// free or pay ?
if ($product->price > 0) {
$price = ''.price(price2num($product->price, 'MT'), 0, $langs, 1, -1, -1, 'EUR').' '.$langs->trans("HT").' ';
- $download_link = ' ';
+ $download_link = ' ';
} else {
$price = ''.$langs->trans('Free').' ';
- $download_link = ' ';
- $download_link .= ' ';
+ $download_link = ' ';
+ $download_link .= ' ';
}
//checking versions
@@ -319,14 +319,14 @@ class Dolistore
//.''.$langs->trans("SeeInMarkerPlace").'
//output template
- $html .= '
- '.$newapp.$images.'
- '.$product->name->language[$this->lang - 1]
- .''.$version.'
- '.dol_print_date(dol_stringtotime($product->date_upd), 'dayhour').' - '.$langs->trans('Ref').': '.$product->reference.' - '.$langs->trans('Id').': '.$product->id.' '.$product->description_short->language[$this->lang - 1].' ';
+ $html .= '
+ '.dol_escape_htmltag($newapp.$images).'
+ '.dol_escape_htmltag($product->name->language[$this->lang - 1])
+ .''.dol_escape_htmltag($version).'
+ '.dol_print_date(dol_stringtotime($product->date_upd), 'dayhour').' - '.$langs->trans('Ref').': '.dol_escape_htmltag($product->reference).' - '.dol_escape_htmltag($langs->trans('Id')).': '.((int) $product->id).' '.dol_escape_htmltag($product->description_short->language[$this->lang - 1]).' ';
// do not load if display none
//$html .= ''.$product->description->language[$this->lang - 1].' ';
- $html .= ''.$price.' ';
+ $html .= ''.dol_escape_htmltag($price).' ';
$html .= ''.$download_link.' ';
$html .= ' ';
}
@@ -343,7 +343,7 @@ class Dolistore
public function get_previous_link($text = '<<')
{
// phpcs:enable
- return ''.$text.' ';
+ return ''.dol_escape_htmltag($text).' ';
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
@@ -356,7 +356,7 @@ class Dolistore
public function get_next_link($text = '>>')
{
// phpcs:enable
- return ''.$text.' ';
+ return ''.dol_escape_htmltag($text).' ';
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
diff --git a/htdocs/admin/ldap.php b/htdocs/admin/ldap.php
index 80897320e90..1a274f8cec1 100644
--- a/htdocs/admin/ldap.php
+++ b/htdocs/admin/ldap.php
@@ -43,6 +43,7 @@ $action = GETPOST('action', 'aZ09');
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$hookmanager->initHooks(array('adminldap', 'globaladmin'));
+
/*
* Actions
*/
@@ -150,7 +151,7 @@ $arraylist['0'] = $langs->trans("No");
$arraylist['ldap2dolibarr'] = $langs->trans("LDAPToDolibarr");
$arraylist['dolibarr2ldap'] = $langs->trans("DolibarrToLDAP");
print $form->selectarray('activesynchro', $arraylist, $conf->global->LDAP_SYNCHRO_ACTIVE);
-print ''.$langs->trans("LDAPDnSynchroActiveExample");
+print ' '.$langs->trans("LDAPDnSynchroActiveExample").' ';
if ($conf->global->LDAP_SYNCHRO_ACTIVE && !$conf->global->LDAP_USER_DN) {
print ''.$langs->trans("LDAPSetupNotComplete").' ';
}
@@ -163,7 +164,7 @@ if (!empty($conf->societe->enabled)) {
$arraylist['0'] = $langs->trans("No");
$arraylist['1'] = $langs->trans("DolibarrToLDAP");
print $form->selectarray('activecontact', $arraylist, $conf->global->LDAP_CONTACT_ACTIVE);
- print ''.$langs->trans("LDAPDnContactActiveExample").' ';
+ print ''.$langs->trans("LDAPDnContactActiveExample").' ';
}
// Synchro member active
@@ -174,7 +175,7 @@ if (!empty($conf->adherent->enabled)) {
$arraylist['1'] = $langs->trans("DolibarrToLDAP");
$arraylist['ldap2dolibarr'] = $langs->trans("LDAPToDolibarr").' ('.$langs->trans("SupportedForLDAPImportScriptOnly").')';
print $form->selectarray('activemembers', $arraylist, $conf->global->LDAP_MEMBER_ACTIVE);
- print ''.$langs->trans("LDAPDnMemberActiveExample").' ';
+ print ''.$langs->trans("LDAPDnMemberActiveExample").' ';
}
// Synchro member type active
@@ -185,7 +186,7 @@ if (!empty($conf->adherent->enabled)) {
$arraylist['1'] = $langs->trans("DolibarrToLDAP");
$arraylist['ldap2dolibarr'] = $langs->trans("LDAPToDolibarr").' ('.$langs->trans("SupportedForLDAPImportScriptOnly").')';
print $form->selectarray('activememberstypes', $arraylist, $conf->global->LDAP_MEMBER_TYPE_ACTIVE);
- print ''.$langs->trans("LDAPDnMemberTypeActiveExample").' ';
+ print ''.$langs->trans("LDAPDnMemberTypeActiveExample").' ';
}
// Fields from hook
@@ -214,33 +215,33 @@ $arraylist = array();
$arraylist['3'] = 'Version 3';
$arraylist['2'] = 'Version 2';
print $form->selectarray('LDAP_SERVER_PROTOCOLVERSION', $arraylist, $conf->global->LDAP_SERVER_PROTOCOLVERSION);
-print ''.$langs->trans("LDAPServerProtocolVersion").' ';
+print ''.$langs->trans("LDAPServerProtocolVersion").' ';
// Serveur primaire
print '';
print $langs->trans("LDAPPrimaryServer").' ';
-print ' ';
-print ' '.$langs->trans("LDAPServerExample").' ';
+print ' ';
+print ''.$langs->trans("LDAPServerExample").' ';
// Serveur secondaire
print '';
print $langs->trans("LDAPSecondaryServer").' ';
-print ' ';
-print ' '.$langs->trans("LDAPServerExample").' ';
+print ' ';
+print ''.$langs->trans("LDAPServerExample").' ';
// Port
print ''.$langs->trans("LDAPServerPort").' ';
if (!empty($conf->global->LDAP_SERVER_PORT)) {
- print ' ';
+ print ' ';
} else {
- print ' ';
+ print ' ';
}
-print ' '.$langs->trans("LDAPServerPortExample").' ';
+print ''.$langs->trans("LDAPServerPortExample").' ';
// DNserver
print ''.$langs->trans("LDAPServerDn").' ';
-print ' ';
-print ' '.$langs->trans("LDAPServerDnExample").' ';
+print ' ';
+print ''.$langs->trans("LDAPServerDnExample").' ';
// Utiliser TLS
print ''.$langs->trans("LDAPServerUseTLS").' ';
@@ -248,7 +249,7 @@ $arraylist = array();
$arraylist['0'] = $langs->trans("No");
$arraylist['1'] = $langs->trans("Yes");
print $form->selectarray('usetls', $arraylist, $conf->global->LDAP_SERVER_USE_TLS);
-print ' '.$langs->trans("LDAPServerUseTLSExample").' ';
+print ''.$langs->trans("LDAPServerUseTLSExample").' ';
print '';
print ''.$langs->trans("ForANonAnonymousAccess").' ';
@@ -257,18 +258,18 @@ print " \n";
// DNAdmin
print '';
print ''.$langs->trans("LDAPAdminDn").' ';
-print ' ';
-print ' '.$langs->trans("LDAPAdminDnExample").' ';
+print ' ';
+print ''.$langs->trans("LDAPAdminDnExample").' ';
// Pass
print '';
print ''.$langs->trans("LDAPPassword").' ';
if (!empty($conf->global->LDAP_ADMIN_PASS)) {
- print ' '; // je le met en visible pour test
+ print ' '; // je le met en visible pour test
} else {
- print ' ';
+ print ' ';
}
-print ' '.$langs->trans('Password').' (ex: secret) ';
+print ''.$langs->trans('Password').' (ex: secret) ';
print '';
diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php
index 658be446765..ccf12d5a104 100644
--- a/htdocs/admin/modules.php
+++ b/htdocs/admin/modules.php
@@ -1025,16 +1025,16 @@ if ($mode == 'marketplace') {
print '