Browse Source

Debug v16 - Fix for postgresql - Fix for sql loading per module - php8

Laurent Destailleur 3 năm trước cách đây
mục cha
commit
f52a7a26f6
63 tập tin đã thay đổi với 626 bổ sung364 xóa
  1. 3 0
      htdocs/admin/dolistore/class/PSWebServiceLibrary.class.php
  2. 2 2
      htdocs/admin/eventorganization.php
  3. 2 2
      htdocs/admin/hrm.php
  4. 2 2
      htdocs/admin/knowledgemanagement.php
  5. 181 180
      htdocs/admin/mails_templates.php
  6. 7 3
      htdocs/admin/modulehelp.php
  7. 2 2
      htdocs/admin/workstation.php
  8. 2 2
      htdocs/asset/admin/setup.php
  9. 6 5
      htdocs/core/class/translate.class.php
  10. 9 4
      htdocs/core/db/pgsql.class.php
  11. 2 2
      htdocs/core/lib/usergroups.lib.php
  12. 127 92
      htdocs/core/modules/DolibarrModules.class.php
  13. 1 1
      htdocs/core/modules/modAsset.class.php
  14. 1 1
      htdocs/core/modules/modDeplacement.class.php
  15. 1 1
      htdocs/core/modules/modDon.class.php
  16. 1 1
      htdocs/core/modules/modHRM.class.php
  17. 1 1
      htdocs/core/modules/modIntracommreport.class.php
  18. 1 1
      htdocs/core/modules/modKnowledgeManagement.class.php
  19. 1 1
      htdocs/core/modules/modLoan.class.php
  20. 1 1
      htdocs/core/modules/modMailing.class.php
  21. 1 1
      htdocs/core/modules/modOpenSurvey.class.php
  22. 1 1
      htdocs/core/modules/modPartnership.class.php
  23. 1 1
      htdocs/core/modules/modRecruitment.class.php
  24. 1 1
      htdocs/core/modules/modStock.class.php
  25. 1 1
      htdocs/core/modules/modTicket.class.php
  26. 1 1
      htdocs/core/modules/modWebsite.class.php
  27. 1 1
      htdocs/core/modules/modWorkstation.class.php
  28. 1 1
      htdocs/core/modules/modZapier.class.php
  29. 2 0
      htdocs/hrm/admin/evaluation_extrafields.php
  30. 2 0
      htdocs/hrm/admin/job_extrafields.php
  31. 2 0
      htdocs/hrm/admin/skill_extrafields.php
  32. 0 0
      htdocs/install/mysql/data/llx_c_partnership_type-partnership.sql
  33. 2 0
      htdocs/install/mysql/migration/15.0.0-16.0.0.sql
  34. 3 1
      htdocs/install/mysql/tables/llx_societe_account.key.sql
  35. 20 0
      htdocs/install/pgsql/functions/functions-don.sql
  36. 19 0
      htdocs/install/pgsql/functions/functions-loan.sql
  37. 20 0
      htdocs/install/pgsql/functions/functions-mailing.sql
  38. 21 0
      htdocs/install/pgsql/functions/functions-opensurvey.sql
  39. 20 0
      htdocs/install/pgsql/functions/functions-partnership.sql
  40. 23 0
      htdocs/install/pgsql/functions/functions-recruitment.sql
  41. 21 0
      htdocs/install/pgsql/functions/functions-website.sql
  42. 0 15
      htdocs/install/pgsql/functions/functions.sql
  43. 1 0
      htdocs/install/step1.php
  44. 2 2
      htdocs/install/step4.php
  45. 1 1
      htdocs/main.inc.php
  46. 2 1
      htdocs/modulebuilder/admin/setup.php
  47. 2 0
      htdocs/modulebuilder/template/admin/myobject_extrafields.php
  48. 2 2
      htdocs/modulebuilder/template/admin/setup.php
  49. 1 1
      htdocs/modulebuilder/template/core/modules/modMyModule.class.php
  50. 2 0
      htdocs/partnership/admin/partnership_extrafields.php
  51. 1 0
      htdocs/product/admin/inventory_extrafields.php
  52. 1 0
      htdocs/product/admin/stock_mouvement_extrafields.php
  53. 2 0
      htdocs/recruitment/admin/candidature_extrafields.php
  54. 2 0
      htdocs/recruitment/admin/jobposition_extrafields.php
  55. 1 0
      htdocs/recruitment/admin/public_interface.php
  56. 2 2
      htdocs/recruitment/admin/setup.php
  57. 2 2
      htdocs/recruitment/admin/setup_candidatures.php
  58. 2 2
      htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php
  59. 2 2
      htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php
  60. 2 2
      htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php
  61. 77 16
      htdocs/user/class/user.class.php
  62. 2 2
      htdocs/user/group/card.php
  63. 1 1
      htdocs/user/group/perms.php

+ 3 - 0
htdocs/admin/dolistore/class/PSWebServiceLibrary.class.php

@@ -232,6 +232,9 @@ class PrestaShopWebservice
 		if ($response != '') {
 			libxml_clear_errors();
 			libxml_use_internal_errors(true);
+			if (!function_exists('simplexml_load_string')) {
+				throw new PrestaShopWebserviceException('Method simplexml_load_string not available. Your PHP does not support xml.');
+			}
 			$xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA|LIBXML_NONET);
 			if (libxml_get_errors()) {
 				$msg = var_export(libxml_get_errors(), true);

+ 2 - 2
htdocs/admin/eventorganization.php

@@ -457,7 +457,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'EVENTORGANIZATION_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -597,7 +597,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'EVENTORGANIZATION_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&amp;token='.newToken().'&amp;object='.urlencode(strtolower($myTmpObjectKey)).'&amp;value='.$name.'&amp;scan_dir='.$module->scandir.'&amp;label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 2 - 2
htdocs/admin/hrm.php

@@ -279,7 +279,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'HRMTEST_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -421,7 +421,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'HRMTEST_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&amp;token='.newToken().'&amp;object='.urlencode(strtolower($myTmpObjectKey)).'&amp;value='.$name.'&amp;scan_dir='.$module->scandir.'&amp;label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 2 - 2
htdocs/admin/knowledgemanagement.php

@@ -403,7 +403,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'KNOWLEDGEMANAGEMENT_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -545,7 +545,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'KNOWLEDGEMANAGEMENT_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&amp;token='.newToken().'&amp;object='.urlencode(strtolower($myTmpObjectKey)).'&amp;value='.$name.'&amp;scan_dir='.$module->scandir.'&amp;label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 181 - 180
htdocs/admin/mails_templates.php

@@ -554,7 +554,7 @@ $help_url = '';
 if (!empty($user->admin) && (empty($_SESSION['leftmenu']) || $_SESSION['leftmenu'] != 'email_templates')) {
 	$title = $langs->trans("EMailsSetup");
 } else {
-	$title = $langs->trans("EMailsTemplates");
+	$title = $langs->trans("EMailTemplates");
 }
 
 llxHeader('', $title, $help_url);
@@ -949,214 +949,215 @@ if ($resql) {
 		while ($i < $num) {
 			$obj = $db->fetch_object($resql);
 
-			if ($action == 'edit' && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) {
-				print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
+			if ($obj) {
+				if ($action == 'edit' && ($rowid == (!empty($obj->rowid) ? $obj->rowid : $obj->code))) {
+					print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
 
-				$tmpaction = 'edit';
-				$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
-				$reshook = $hookmanager->executeHooks('editEmailTemplateFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
-				$error = $hookmanager->error; $errors = $hookmanager->errors;
+					$tmpaction = 'edit';
+					$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
+					$reshook = $hookmanager->executeHooks('editEmailTemplateFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
+					$error = $hookmanager->error; $errors = $hookmanager->errors;
 
-				// Show fields
-				if (empty($reshook)) {
-					fieldList($fieldlist, $obj, $tabname[$id], 'edit');
-				}
+					// Show fields
+					if (empty($reshook)) {
+						fieldList($fieldlist, $obj, $tabname[$id], 'edit');
+					}
 
-				print '<td></td><td></td><td></td>';
-				print '<td class="center">';
-				print '<input type="hidden" name="page" value="'.$page.'">';
-				print '<input type="hidden" name="rowid" value="'.$rowid.'">';
-				print '<input type="submit" class="button buttongen button-save" name="actionmodify" value="'.$langs->trans("Modify").'">';
-				print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
-				print '<input type="submit" class="button buttongen button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
-				print '</td>';
-
-				$fieldsforcontent = array('topic', 'joinfiles', 'content');
-				if (!empty($conf->global->MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES)) {
-					$fieldsforcontent = array('topic', 'joinfiles', 'content', 'content_lines');
-				}
-				foreach ($fieldsforcontent as $tmpfieldlist) {
-					$showfield = 1;
-					$align = "left";
-					$valuetoshow = $obj->{$tmpfieldlist};
-
-					$class = 'tddict';
-					// Show value for field
-					if ($showfield) {
-						// Show line for topic, joinfiles and content
-						print '</tr><tr class="oddeven" nohover tr-'.$tmpfieldlist.'-'.$rowid.' ">';
-						print '<td colspan="8">';
-						if ($tmpfieldlist == 'topic') {
-							print '<strong>'.$form->textwithpicto($langs->trans("Topic"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'</strong> ';
-							print '<input type="text" class="flat minwidth500" name="'.$tmpfieldlist.'-'.$rowid.'" value="'.(!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : '').'">';
-						}
-						if ($tmpfieldlist == 'joinfiles') {
-							print '<strong>'.$form->textwithpicto($langs->trans("FilesAttachedToEmail"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'</strong> ';
-							print '<input type="text" class="flat maxwidth50" name="'.$tmpfieldlist.'-'.$rowid.'" value="'.(!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : '').'">';
-						}
-						if ($tmpfieldlist == 'content') {
-							print $form->textwithpicto($langs->trans("Content"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'<br>';
-							$okforextended = true;
-							if (empty($conf->global->FCKEDITOR_ENABLE_MAIL)) {
-								$okforextended = false;
+					print '<td></td><td></td><td></td>';
+					print '<td class="center">';
+					print '<input type="hidden" name="page" value="'.$page.'">';
+					print '<input type="hidden" name="rowid" value="'.$rowid.'">';
+					print '<input type="submit" class="button buttongen button-save" name="actionmodify" value="'.$langs->trans("Modify").'">';
+					print '<div name="'.(!empty($obj->rowid) ? $obj->rowid : $obj->code).'"></div>';
+					print '<input type="submit" class="button buttongen button-cancel" name="actioncancel" value="'.$langs->trans("Cancel").'">';
+					print '</td>';
+
+					$fieldsforcontent = array('topic', 'joinfiles', 'content');
+					if (!empty($conf->global->MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES)) {
+						$fieldsforcontent = array('topic', 'joinfiles', 'content', 'content_lines');
+					}
+					foreach ($fieldsforcontent as $tmpfieldlist) {
+						$showfield = 1;
+						$align = "left";
+						$valuetoshow = $obj->{$tmpfieldlist};
+
+						$class = 'tddict';
+						// Show value for field
+						if ($showfield) {
+							// Show line for topic, joinfiles and content
+							print '</tr><tr class="oddeven" nohover tr-'.$tmpfieldlist.'-'.$rowid.' ">';
+							print '<td colspan="8">';
+							if ($tmpfieldlist == 'topic') {
+								print '<strong>'.$form->textwithpicto($langs->trans("Topic"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'</strong> ';
+								print '<input type="text" class="flat minwidth500" name="'.$tmpfieldlist.'-'.$rowid.'" value="'.(!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : '').'">';
+							}
+							if ($tmpfieldlist == 'joinfiles') {
+								print '<strong>'.$form->textwithpicto($langs->trans("FilesAttachedToEmail"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'</strong> ';
+								print '<input type="text" class="flat maxwidth50" name="'.$tmpfieldlist.'-'.$rowid.'" value="'.(!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : '').'">';
+							}
+							if ($tmpfieldlist == 'content') {
+								print $form->textwithpicto($langs->trans("Content"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'<br>';
+								$okforextended = true;
+								if (empty($conf->global->FCKEDITOR_ENABLE_MAIL)) {
+									$okforextended = false;
+								}
+								$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 500, 'dolibarr_mailings', 'In', 0, true, $okforextended, ROWS_6, '90%');
+								print $doleditor->Create(1);
 							}
-							$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (!empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 500, 'dolibarr_mailings', 'In', 0, true, $okforextended, ROWS_6, '90%');
-							print $doleditor->Create(1);
+							if ($tmpfieldlist == 'content_lines') {
+								print $form->textwithpicto($langs->trans("ContentForLines"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'<br>';
+								$okforextended = true;
+								if (empty($conf->global->FCKEDITOR_ENABLE_MAIL))
+									$okforextended = false;
+								$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (! empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 140, 'dolibarr_mailings', 'In', 0, false, $okforextended, ROWS_6, '90%');
+								print $doleditor->Create(1);
+							}
+							print '</td>';
+							print '<td></td>';
+							print '<td></td>';
 						}
-						if ($tmpfieldlist == 'content_lines') {
-							print $form->textwithpicto($langs->trans("ContentForLines"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'<br>';
-							$okforextended = true;
-							if (empty($conf->global->FCKEDITOR_ENABLE_MAIL))
-								$okforextended = false;
-							$doleditor = new DolEditor($tmpfieldlist.'-'.$rowid, (! empty($obj->{$tmpfieldlist}) ? $obj->{$tmpfieldlist} : ''), '', 140, 'dolibarr_mailings', 'In', 0, false, $okforextended, ROWS_6, '90%');
-							print $doleditor->Create(1);
+					}
+
+					print "</tr>\n";
+				} else {
+					// If template is for a module, check module is enabled.
+					if ($obj->module) {
+						$tempmodulekey = $obj->module;
+						if (empty($conf->$tempmodulekey) || empty($conf->$tempmodulekey->enabled)) {
+							$i++;
+							continue;
 						}
-						print '</td>';
-						print '<td></td>';
-						print '<td></td>';
 					}
-				}
 
-				print "</tr>\n";
-			} else {
-				// If template is for a module, check module is enabled.
-				if ($obj->module) {
-					$tempmodulekey = $obj->module;
-					if (empty($conf->$tempmodulekey) || empty($conf->$tempmodulekey->enabled)) {
+					$keyforobj = 'type_template';
+					if (!in_array($obj->$keyforobj, array_keys($elementList))) {
 						$i++;
-						continue;
+						continue; // It means this is a type of template not into elementList (may be because enabled condition of this type is false because module is not enabled)
+					}
+					// Test on 'enabled'
+					if (!dol_eval($obj->enabled, 1, 1, '1')) {
+						$i++;
+						continue; // Email template not qualified
 					}
-				}
-
-				$keyforobj = 'type_template';
-				if (!in_array($obj->$keyforobj, array_keys($elementList))) {
-					$i++;
-					continue; // It means this is a type of template not into elementList (may be because enabled condition of this type is false because module is not enabled)
-				}
-				// Test on 'enabled'
-				if (!dol_eval($obj->enabled, 1, 1, '1')) {
-					$i++;
-					continue; // Email template not qualified
-				}
 
-				print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
+					print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
 
-				$tmpaction = 'view';
-				$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
-				$reshook = $hookmanager->executeHooks('viewEmailTemplateFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
+					$tmpaction = 'view';
+					$parameters = array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
+					$reshook = $hookmanager->executeHooks('viewEmailTemplateFieldlist', $parameters, $obj, $tmpaction); // Note that $action and $object may have been modified by some hooks
 
-				$error = $hookmanager->error; $errors = $hookmanager->errors;
+					$error = $hookmanager->error; $errors = $hookmanager->errors;
 
-				if (empty($reshook)) {
-					foreach ($fieldlist as $field => $value) {
-						if (in_array($fieldlist[$field], array('content', 'content_lines'))) {
-							continue;
-						}
-						$showfield = 1;
-						$align = "";
-						$class = "tddict";
-						$title = '';
-						$valuetoshow = $obj->{$fieldlist[$field]};
-						if ($value == 'label' || $value == 'topic') {
-							if ($langs->trans($valuetoshow) != $valuetoshow) {
-								$valuetoshow = $langs->trans($valuetoshow);
+					if (empty($reshook)) {
+						foreach ($fieldlist as $field => $value) {
+							if (in_array($fieldlist[$field], array('content', 'content_lines'))) {
+								continue;
 							}
-							$valuetoshow = dol_escape_htmltag($valuetoshow);
-						}
-						if ($value == 'label') {
-							$class .= ' tdoverflowmax100';
-						}
-						if ($value == 'topic') {
-							$class .= 'tdoverflowmax200 small';
-						}
-						if ($value == 'type_template') {
-							$valuetoshow = isset($elementList[$valuetoshow]) ? $elementList[$valuetoshow] : $valuetoshow;
-							$align = "center";
-						}
-						if ($value == 'lang' && $valuetoshow) {
-							$valuetoshow = $valuetoshow.' - '.$langs->trans("Language_".$valuetoshow);
-						}
-						if ($value == 'fk_user') {
-							if ($valuetoshow > 0) {
-								$fuser = new User($db);
-								$fuser->fetch($valuetoshow);
-								$valuetoshow = $fuser->getNomUrl(1);
+							$showfield = 1;
+							$align = "";
+							$class = "tddict";
+							$title = '';
+							$valuetoshow = $obj->{$fieldlist[$field]};
+							if ($value == 'label' || $value == 'topic') {
+								if ($langs->trans($valuetoshow) != $valuetoshow) {
+									$valuetoshow = $langs->trans($valuetoshow);
+								}
+								$valuetoshow = dol_escape_htmltag($valuetoshow);
 							}
-						}
-						if ($value == 'private') {
-							$align = "center";
-							if ($valuetoshow) {
-								$valuetoshow = yn($valuetoshow);
-							} else {
-								$valuetoshow = '';
+							if ($value == 'label') {
+								$class .= ' tdoverflowmax100';
 							}
-						}
-						if ($value == 'position') {
-							$align = "center";
-						}
-						if ($value == 'joinfiles') {
-							$align = "center";
-							if ($valuetoshow) {
-								$valuetoshow = 1;
-							} else {
-								$valuetoshow = '';
+							if ($value == 'topic') {
+								$class .= 'tdoverflowmax200 small';
+							}
+							if ($value == 'type_template') {
+								$valuetoshow = isset($elementList[$valuetoshow]) ? $elementList[$valuetoshow] : $valuetoshow;
+								$align = "center";
+							}
+							if ($value == 'lang' && $valuetoshow) {
+								$valuetoshow = $valuetoshow.' - '.$langs->trans("Language_".$valuetoshow);
+							}
+							if ($value == 'fk_user') {
+								if ($valuetoshow > 0) {
+									$fuser = new User($db);
+									$fuser->fetch($valuetoshow);
+									$valuetoshow = $fuser->getNomUrl(1);
+								}
+							}
+							if ($value == 'private') {
+								$align = "center";
+								if ($valuetoshow) {
+									$valuetoshow = yn($valuetoshow);
+								} else {
+									$valuetoshow = '';
+								}
+							}
+							if ($value == 'position') {
+								$align = "center";
+							}
+							if ($value == 'joinfiles') {
+								$align = "center";
+								if ($valuetoshow) {
+									$valuetoshow = 1;
+								} else {
+									$valuetoshow = '';
+								}
+							}
+							if ($align) {
+								$class .= ' '.$align;
 							}
-						}
-						if ($align) {
-							$class .= ' '.$align;
-						}
 
-						// Show value for field
-						if ($showfield) {
-							print '<!-- '.$fieldlist[$field].' -->';
-							print '<td class="'.$class.'"';
-							if (in_array($value, array('code', 'label', 'topic'))) {
-								print ' title="'.dol_escape_htmltag($valuetoshow).'"';
+							// Show value for field
+							if ($showfield) {
+								print '<!-- '.$fieldlist[$field].' -->';
+								print '<td class="'.$class.'"';
+								if (in_array($value, array('code', 'label', 'topic'))) {
+									print ' title="'.dol_escape_htmltag($valuetoshow).'"';
+								}
+								print '>';
+								print $valuetoshow;
+								print '</td>';
 							}
-							print '>';
-							print $valuetoshow;
-							print '</td>';
 						}
 					}
-				}
 
-				// Can an entry be erased or disabled ?
-				$iserasable = 1; $canbedisabled = 1; $canbemodified = 1; // true by default
-				if (!$user->admin && $obj->fk_user != $user->id) {
-					$iserasable = 0;
-					$canbedisabled = 0;
-					$canbemodified = 0;
-				}
+					// Can an entry be erased or disabled ?
+					$iserasable = 1; $canbedisabled = 1; $canbemodified = 1; // true by default
+					if (!$user->admin && $obj->fk_user != $user->id) {
+						$iserasable = 0;
+						$canbedisabled = 0;
+						$canbemodified = 0;
+					}
 
-				$url = $_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.(!empty($obj->rowid) ? $obj->rowid : (!empty($obj->code) ? $obj->code : '')).'&code='.(!empty($obj->code) ?urlencode($obj->code) : '');
-				if ($param) {
-					$url .= '&'.$param;
-				}
+					$url = $_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.(!empty($obj->rowid) ? $obj->rowid : (!empty($obj->code) ? $obj->code : '')).'&code='.(!empty($obj->code) ?urlencode($obj->code) : '');
+					if ($param) {
+						$url .= '&'.$param;
+					}
 
-				// Status / Active
-				print '<td class="center nowrap">';
-				if ($canbedisabled) {
-					print '<a href="'.$url.'&action='.$acts[$obj->active].'&token='.newToken().'">'.$actl[$obj->active].'</a>';
-				} else {
-					print '<span class="opacitymedium">'.$actl[$obj->active].'</span>';
-				}
-				print "</td>";
+					// Status / Active
+					print '<td class="center nowrap">';
+					if ($canbedisabled) {
+						print '<a href="'.$url.'&action='.$acts[$obj->active].'&token='.newToken().'">'.$actl[$obj->active].'</a>';
+					} else {
+						print '<span class="opacitymedium">'.$actl[$obj->active].'</span>';
+					}
+					print "</td>";
 
-				// Modify link / Delete link
-				print '<td class="center nowraponall" width="64">';
-				if ($canbemodified) {
-					print '<a class="reposition editfielda" href="'.$url.'&action=edit&token='.newToken().'">'.img_edit().'</a>';
-				}
-				if ($iserasable) {
-					print '<a class="marginleftonly" href="'.$url.'&action=delete&token='.newToken().'">'.img_delete().'</a>';
-					//else print '<a href="#">'.img_delete().'</a>';    // Some dictionary can be edited by other profile than admin
-				}
-				print '</td>';
+					// Modify link / Delete link
+					print '<td class="center nowraponall" width="64">';
+					if ($canbemodified) {
+						print '<a class="reposition editfielda" href="'.$url.'&action=edit&token='.newToken().'">'.img_edit().'</a>';
+					}
+					if ($iserasable) {
+						print '<a class="marginleftonly" href="'.$url.'&action=delete&token='.newToken().'">'.img_delete().'</a>';
+						//else print '<a href="#">'.img_delete().'</a>';    // Some dictionary can be edited by other profile than admin
+					}
+					print '</td>';
 
-				print "</tr>\n";
+					print "</tr>\n";
+				}
 			}
 
-
 			$i++;
 		}
 	}

+ 7 - 3
htdocs/admin/modulehelp.php

@@ -172,6 +172,10 @@ foreach ($modulesdir as $dir) {
 										$moduleposition = '80'; // External modules at end by default
 									}
 
+									if (empty($familyinfo[$familykey]['position'])) {
+										$familyinfo[$familykey]['position'] = '0';
+									}
+
 									$orders[$i] = $familyinfo[$familykey]['position']."_".$familykey."_".$moduleposition."_".$j; // Sort by family, then by module position then number
 									$dirmod[$i] = $dir;
 									//print $i.'-'.$dirmod[$i].'<br>';
@@ -250,19 +254,19 @@ if (!empty($conf->global->$const_name)) {
 	$text .= $langs->trans("Disabled");
 }
 $tmp = $objMod->getLastActivationInfo();
-$authorid = $tmp['authorid'];
+$authorid = (empty($tmp['authorid']) ? '' : $tmp['authorid']);
 if ($authorid > 0) {
 	$tmpuser = new User($db);
 	$tmpuser->fetch($authorid);
 	$text .= '<br><span class="opacitymedium">'.$langs->trans("LastActivationAuthor").':</span> ';
 	$text .= $tmpuser->getNomUrl(1);
 }
-$ip = $tmp['ip'];
+$ip = (empty($tmp['ip']) ? '' : $tmp['ip']);
 if ($ip) {
 	$text .= '<br><span class="opacitymedium">'.$langs->trans("LastActivationIP").':</span> ';
 	$text .= $ip;
 }
-$lastactivationversion = $tmp['lastactivationversion'];
+$lastactivationversion = (empty($tmp['lastactivationversion']) ? '' : $tmp['lastactivationversion']);
 if ($lastactivationversion) {
 	$text .= '<br><span class="opacitymedium">'.$langs->trans("LastActivationVersion").':</span> ';
 	$text .= $lastactivationversion;

+ 2 - 2
htdocs/admin/workstation.php

@@ -295,7 +295,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'WORKSTATION_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -437,7 +437,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'WORKSTATION_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											print img_picto($langs->trans("Default"), 'on');
 										} else {
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&amp;token='.newToken().'&amp;value='.$name.'&amp;scan_dir='.$module->scandir.'&amp;label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';

+ 2 - 2
htdocs/asset/admin/setup.php

@@ -266,7 +266,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'ASSET_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -408,7 +408,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'ASSET_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 6 - 5
htdocs/core/class/translate.class.php

@@ -1089,11 +1089,12 @@ class Translate
 			$i = 0;
 			while ($i < $num) {
 				$obj = $db->fetch_object($resql);
-
-				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
-				$this->cache_currencies[$obj->code_iso]['label'] = ($obj->code_iso && $this->trans("Currency".$obj->code_iso) != "Currency".$obj->code_iso ? $this->trans("Currency".$obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
-				$this->cache_currencies[$obj->code_iso]['unicode'] = (array) json_decode($obj->unicode, true);
-				$label[$obj->code_iso] = $this->cache_currencies[$obj->code_iso]['label'];
+				if ($obj) {
+					// If a translation exists, we use it lese we use the default label
+					$this->cache_currencies[$obj->code_iso]['label'] = ($obj->code_iso && $this->trans("Currency".$obj->code_iso) != "Currency".$obj->code_iso ? $this->trans("Currency".$obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
+					$this->cache_currencies[$obj->code_iso]['unicode'] = (array) json_decode($obj->unicode, true);
+					$label[$obj->code_iso] = $this->cache_currencies[$obj->code_iso]['label'];
+				}
 				$i++;
 			}
 			if (empty($currency_code)) {

+ 9 - 4
htdocs/core/db/pgsql.class.php

@@ -116,7 +116,7 @@ class DoliDBPgsql extends DoliDB
 			$this->connected = false;
 			$this->ok = false;
 			$this->error = 'Host, login or password incorrect';
-			dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect ".$this->error, LOG_ERR);
+			dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect ".$this->error.'. Failed to connect to host='.$host.' port='.$port.' user='.$user, LOG_ERR);
 		}
 
 		// Si connexion serveur ok et si connexion base demandee, on essaie connexion base
@@ -423,7 +423,7 @@ class DoliDBPgsql extends DoliDB
 		}
 
 		// if local connection failed or not requested, use TCP/IP
-		if (!$this->db) {
+		if (empty($this->db)) {
 			if (!$host) {
 				$host = "localhost";
 			}
@@ -432,7 +432,11 @@ class DoliDBPgsql extends DoliDB
 			}
 
 			$con_string = "host='".$host."' port='".$port."' dbname='".$name."' user='".$login."' password='".$passwd."'";
-			$this->db = @pg_connect($con_string);
+			try {
+				$this->db = @pg_connect($con_string);
+			} catch (Exception $e) {
+				print $e->getMessage();
+			}
 		}
 
 		// now we test if at least one connect method was a success
@@ -916,7 +920,8 @@ class DoliDBPgsql extends DoliDB
 		// Test charset match LC_TYPE (pgsql error otherwise)
 		//print $charset.' '.setlocale(LC_CTYPE,'0'); exit;
 
-		$sql = "CREATE DATABASE '".$this->escape($database)."' OWNER '".$this->escape($owner)."' ENCODING '".$this->escape($charset)."'";
+		// NOTE: Do not use ' around the database name
+		$sql = "CREATE DATABASE ".$this->escape($database)." OWNER '".$this->escape($owner)."' ENCODING '".$this->escape($charset)."'";
 		dol_syslog($sql, LOG_DEBUG);
 		$ret = $this->query($sql);
 		return $ret;

+ 2 - 2
htdocs/core/lib/usergroups.lib.php

@@ -29,10 +29,10 @@
 /**
  * Prepare array with list of tabs
  *
- * @param   Object	$object		Object related to tabs
+ * @param   User	$object		Object related to tabs
  * @return  array				Array of tabs to show
  */
-function user_prepare_head($object)
+function user_prepare_head(User $object)
 {
 	global $langs, $conf, $user, $db;
 

+ 127 - 92
htdocs/core/modules/DolibarrModules.class.php

@@ -956,11 +956,11 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
 			$err++;
 		} else {
 			$obj = $this->db->fetch_object($resql);
-			$tmp = array();
-			if ($obj->note) {
-				$tmp = json_decode($obj->note, true);
-			}
 			if ($obj) {
+				$tmp = array();
+				if ($obj->note) {
+					$tmp = json_decode($obj->note, true);
+				}
 				return array(
 					'authorid' => $tmp['authorid'],
 					'ip' => $tmp['ip'],
@@ -1054,16 +1054,16 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
 	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps,PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
 	/**
 	 * Create tables and keys required by module:
-	 * - Files module.sql with create table instructions
-	 * - Then modules.key.sql with create keys instructions
+	 * - Files table.sql or table-module.sql with create table instructions
+	 * - Then table.key.sql or table-module.key.sql with create keys instructions
 	 * - Then data_xxx.sql (usualy provided by external modules only)
 	 * - Then update_xxx.sql (usualy provided by external modules only)
-	 * Files must be stored in directory defined by reldir (Example: '/install/mysql/tables' or '/module/sql/')
+	 * Files must be stored in subdirectory 'tables' or 'data' into directory $reldir (Example: '/install/mysql/' or '/module/sql/')
 	 * This function may also be called by :
-	 * - _load_tables('/install/mysql/tables/', 'modulename') into the this->init() of core module descriptors.
+	 * - _load_tables('/install/mysql/', 'modulename') into the this->init() of core module descriptors.
 	 * - _load_tables('/mymodule/sql/') into the this->init() of external module descriptors.
 	 *
-	 * @param  	string 	$reldir 			Relative directory where to scan files. Example: '/install/mysql/tables' or '/module/sql/'
+	 * @param  	string 	$reldir 			Relative directory where to scan files. Example: '/install/mysql/' or '/module/sql/'
 	 * @param	string	$onlywithsuffix		Only with the defined suffix
 	 * @return 	int             			<=0 if KO, >0 if OK
 	 */
@@ -1084,112 +1084,147 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
 		$ok = 1;
 		foreach ($conf->file->dol_document_root as $dirroot) {
 			if ($ok) {
-				$dir = $dirroot.$reldir;
+				$dirsql = $dirroot.$reldir;
 				$ok = 0;
 
-				$handle = @opendir($dir); // Dir may not exists
-				if (is_resource($handle)) {
-					$dirfound++;
+				// We will loop on xxx/, xxx/tables/, xxx/data/
+				$listofsubdir = array('', 'tables/', 'data/');
+				if ($this->db->type == 'pgsql') {
+					$listofsubdir[] = '../pgsql/functions/';
+				}
 
-					// Run llx_mytable.sql files, then llx_mytable_*.sql
-					$files = array();
-					while (($file = readdir($handle)) !== false) {
-						$files[] = $file;
-					}
-					sort($files);
-					foreach ($files as $file) {
-						if ($onlywithsuffix) {
-							if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
-								//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
-								continue;
-							} else {
-								//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
-							}
+				foreach ($listofsubdir as $subdir) {
+					$dir = $dirsql.$subdir;
+
+					$handle = @opendir($dir); // Dir may not exists
+					if (is_resource($handle)) {
+						$dirfound++;
+
+						// Run llx_mytable.sql files, then llx_mytable_*.sql
+						$files = array();
+						while (($file = readdir($handle)) !== false) {
+							$files[] = $file;
 						}
-						if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_' && substr($file, 0, 4) != 'data') {
-							$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
-							if ($result <= 0) {
-								$error++;
+						sort($files);
+						foreach ($files as $file) {
+							if ($onlywithsuffix) {
+								if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
+									//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
+									continue;
+								} else {
+									//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
+								}
+							}
+							if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_') {
+								$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
+								if ($result <= 0) {
+									$error++;
+								}
 							}
 						}
-					}
 
-					rewinddir($handle);
+						rewinddir($handle);
 
-					// Run llx_mytable.key.sql files (Must be done after llx_mytable.sql) then then llx_mytable_*.key.sql
-					$files = array();
-					while (($file = readdir($handle)) !== false) {
-						$files[] = $file;
-					}
-					sort($files);
-					foreach ($files as $file) {
-						if ($onlywithsuffix) {
-							if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
-								//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
-								continue;
-							} else {
-								//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
-							}
+						// Run llx_mytable.key.sql files (Must be done after llx_mytable.sql) then then llx_mytable_*.key.sql
+						$files = array();
+						while (($file = readdir($handle)) !== false) {
+							$files[] = $file;
 						}
-						if (preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_' && substr($file, 0, 4) != 'data') {
-							$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
-							if ($result <= 0) {
-								$error++;
+						sort($files);
+						foreach ($files as $file) {
+							if ($onlywithsuffix) {
+								if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
+									//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
+									continue;
+								} else {
+									//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
+								}
+							}
+							if (preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_') {
+								$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
+								if ($result <= 0) {
+									$error++;
+								}
 							}
 						}
-					}
 
-					rewinddir($handle);
+						rewinddir($handle);
 
-					// Run data_xxx.sql files (Must be done after llx_mytable.key.sql)
-					$files = array();
-					while (($file = readdir($handle)) !== false) {
-							   $files[] = $file;
-					}
-					sort($files);
-					foreach ($files as $file) {
-						if ($onlywithsuffix) {
-							if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
-								//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
-								continue;
-							} else {
-								//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
-							}
+						// Run functions-xxx.sql files (Must be done after llx_mytable.key.sql)
+						$files = array();
+						while (($file = readdir($handle)) !== false) {
+							$files[] = $file;
 						}
-						if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'data') {
-							$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
-							if ($result <= 0) {
-								$error++;
+						sort($files);
+						foreach ($files as $file) {
+							if ($onlywithsuffix) {
+								if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
+									//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
+									continue;
+								} else {
+									//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
+								}
+							}
+							if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 9) == 'functions') {
+								$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
+								if ($result <= 0) {
+									$error++;
+								}
 							}
 						}
-					}
 
-					rewinddir($handle);
+						rewinddir($handle);
 
-					// Run update_xxx.sql files
-					$files = array();
-					while (($file = readdir($handle)) !== false) {
-							   $files[] = $file;
-					}
-					sort($files);
-					foreach ($files as $file) {
-						if ($onlywithsuffix) {
-							if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
-								//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
-								continue;
-							} else {
-								//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
+						// Run data_xxx.sql files (Must be done after llx_mytable.key.sql)
+						$files = array();
+						while (($file = readdir($handle)) !== false) {
+								   $files[] = $file;
+						}
+						sort($files);
+						foreach ($files as $file) {
+							if ($onlywithsuffix) {
+								if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
+									//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
+									continue;
+								} else {
+									//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
+								}
 							}
+							if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'data') {
+								$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
+								if ($result <= 0) {
+									$error++;
+								}
+							}
+						}
+
+						rewinddir($handle);
+
+						// Run update_xxx.sql files
+						$files = array();
+						while (($file = readdir($handle)) !== false) {
+								   $files[] = $file;
 						}
-						if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 6) == 'update') {
-							$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
-							if ($result <= 0) {
-								$error++;
+						sort($files);
+						foreach ($files as $file) {
+							if ($onlywithsuffix) {
+								if (!preg_match('/\-'.preg_quote($onlywithsuffix, '/').'\./i', $file)) {
+									//print 'File '.$file.' does not match suffix '.$onlywithsuffix.' so it is discarded<br>'."\n";
+									continue;
+								} else {
+									//print 'File '.$file.' match suffix '.$onlywithsuffix.' so we keep it<br>'."\n";
+								}
+							}
+							if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 6) == 'update') {
+								$result = run_sql($dir.$file, empty($conf->global->MAIN_DISPLAY_SQL_INSTALL_LOG) ? 1 : 0, '', 1);
+								if ($result <= 0) {
+									$error++;
+								}
 							}
 						}
-					}
 
-					closedir($handle);
+						closedir($handle);
+					}
 				}
 
 				if ($error == 0) {

+ 1 - 1
htdocs/core/modules/modAsset.class.php

@@ -240,7 +240,7 @@ class modAsset extends DolibarrModules
 	 */
 	public function init($options = '')
 	{
-		$result = $this->_load_tables('/install/mysql/tables/', 'asset');
+		$result = $this->_load_tables('/install/mysql/', 'asset');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modDeplacement.class.php

@@ -159,7 +159,7 @@ class modDeplacement extends DolibarrModules
 	 */
 	public function init($options = '')
 	{
-		$result = $this->_load_tables('/install/mysql/tables/', 'deplacement');
+		$result = $this->_load_tables('/install/mysql/', 'deplacement');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modDon.class.php

@@ -155,7 +155,7 @@ class modDon extends DolibarrModules
 	{
 		global $conf;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'deplacement');
+		$result = $this->_load_tables('/install/mysql/', 'don');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modHRM.class.php

@@ -280,7 +280,7 @@ class modHRM extends DolibarrModules
 		// Permissions
 		$this->remove($options);
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'hrm');
+		$result = $this->_load_tables('/install/mysql/', 'hrm');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modIntracommreport.class.php

@@ -138,7 +138,7 @@ class modIntracommreport extends DolibarrModules
 	{
 		global $conf;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'intracommreport');
+		$result = $this->_load_tables('/install/mysql/', 'intracommreport');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modKnowledgeManagement.class.php

@@ -442,7 +442,7 @@ class modKnowledgeManagement extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'knowledgemanagement');
+		$result = $this->_load_tables('/install/mysql/', 'knowledgemanagement');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modLoan.class.php

@@ -160,7 +160,7 @@ class modLoan extends DolibarrModules
 	{
 		global $conf;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'loan');
+		$result = $this->_load_tables('/install/mysql/', 'loan');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modMailing.class.php

@@ -159,7 +159,7 @@ class modMailing extends DolibarrModules
 	 */
 	public function init($options = '')
 	{
-		$result = $this->_load_tables('/install/mysql/tables/', 'mailing');
+		$result = $this->_load_tables('/install/mysql/', 'mailing');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modOpenSurvey.class.php

@@ -184,7 +184,7 @@ class modOpenSurvey extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'opensurvey');
+		$result = $this->_load_tables('/install/mysql/', 'opensurvey');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modPartnership.class.php

@@ -410,7 +410,7 @@ class modPartnership extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'partnership');
+		$result = $this->_load_tables('/install/mysql/', 'partnership');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modRecruitment.class.php

@@ -403,7 +403,7 @@ class modRecruitment extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'recruitment');
+		$result = $this->_load_tables('/install/mysql/', 'recruitment');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modStock.class.php

@@ -434,7 +434,7 @@ class modStock extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'stock');
+		$result = $this->_load_tables('/install/mysql/', 'stock');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modTicket.class.php

@@ -331,7 +331,7 @@ class modTicket extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'ticket');
+		$result = $this->_load_tables('/install/mysql/', 'ticket');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modWebsite.class.php

@@ -164,7 +164,7 @@ class modWebsite extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'website');
+		$result = $this->_load_tables('/install/mysql/', 'website');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modWorkstation.class.php

@@ -390,7 +390,7 @@ class modWorkstation extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		$result = $this->_load_tables('/install/mysql/tables/', 'workstation');
+		$result = $this->_load_tables('/install/mysql/', 'workstation');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 1 - 1
htdocs/core/modules/modZapier.class.php

@@ -281,7 +281,7 @@ class modZapier extends DolibarrModules
 	 */
 	public function init($options = '')
 	{
-		$result = $this->_load_tables('/install/mysql/tables/', 'zapier');
+		$result = $this->_load_tables('/install/mysql/', 'zapier');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
 		}

+ 2 - 0
htdocs/hrm/admin/evaluation_extrafields.php

@@ -91,6 +91,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Evaluation");
+
 $help_url = '';
 $page_name = "HrmSetup";
 

+ 2 - 0
htdocs/hrm/admin/job_extrafields.php

@@ -91,6 +91,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Job");
+
 $help_url = '';
 $page_name = "HrmSetup";
 

+ 2 - 0
htdocs/hrm/admin/skill_extrafields.php

@@ -91,6 +91,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Skills");
+
 $help_url = '';
 $page_name = "HrmSetup";
 

+ 0 - 0
htdocs/install/mysql/data/llx_c_partnership_type.sql → htdocs/install/mysql/data/llx_c_partnership_type-partnership.sql


+ 2 - 0
htdocs/install/mysql/migration/15.0.0-16.0.0.sql

@@ -105,6 +105,8 @@ ALTER TABLE llx_bank ADD COLUMN amount_main_currency double(24,8) NULL;
 
 -- v16
 
+ALTER TABLE llx_societe_account DROP FOREIGN KEY llx_societe_account_fk_website;
+
 UPDATE llx_cronjob set label = 'RecurringInvoicesJob' where label = 'RecurringInvoices';
 UPDATE llx_cronjob set label = 'RecurringSupplierInvoicesJob' where label = 'RecurringSupplierInvoices';
 

+ 3 - 1
htdocs/install/mysql/tables/llx_societe_account.key.sql

@@ -25,6 +25,8 @@ ALTER TABLE llx_societe_account ADD INDEX idx_societe_account_fk_soc (fk_soc);
 ALTER TABLE llx_societe_account ADD UNIQUE INDEX uk_societe_account_login_website_soc(entity, fk_soc, login, site, fk_website);
 ALTER TABLE llx_societe_account ADD UNIQUE INDEX uk_societe_account_key_account_soc(entity, fk_soc, key_account, site, fk_website);
 
-ALTER TABLE llx_societe_account ADD CONSTRAINT llx_societe_account_fk_website FOREIGN KEY (fk_website) REFERENCES llx_website(rowid);
+-- Table website does not always exists
+--ALTER TABLE llx_societe_account ADD CONSTRAINT llx_societe_account_fk_website FOREIGN KEY (fk_website) REFERENCES llx_website(rowid);
+
 ALTER TABLE llx_societe_account ADD CONSTRAINT llx_societe_account_fk_societe FOREIGN KEY (fk_soc) REFERENCES llx_societe(rowid);
 

+ 20 - 0
htdocs/install/pgsql/functions/functions-don.sql

@@ -0,0 +1,20 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_don FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_don_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();

+ 19 - 0
htdocs/install/pgsql/functions/functions-loan.sql

@@ -0,0 +1,19 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_loan FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();

+ 20 - 0
htdocs/install/pgsql/functions/functions-mailing.sql

@@ -0,0 +1,20 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mailing FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mailing_cibles FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();

+ 21 - 0
htdocs/install/pgsql/functions/functions-opensurvey.sql

@@ -0,0 +1,21 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_opensurvey_comments FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_opensurvey_sondage FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_opensurvey_user_studs FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();

+ 20 - 0
htdocs/install/pgsql/functions/functions-partnership.sql

@@ -0,0 +1,20 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_partnership FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_partnership_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();

+ 23 - 0
htdocs/install/pgsql/functions/functions-recruitment.sql

@@ -0,0 +1,23 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentjobposition FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentjobposition_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentcandidature FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentcandidature_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+

+ 21 - 0
htdocs/install/pgsql/functions/functions-website.sql

@@ -0,0 +1,21 @@
+-- ============================================================================
+-- Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
+--
+-- 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 <https://www.gnu.org/licenses/>.
+--
+-- ============================================================================
+
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_website FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_website_page FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
+

+ 0 - 15
htdocs/install/pgsql/functions/functions.sql

@@ -100,9 +100,6 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_contratdet_extrafiel
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_contratdet_log FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_subscription FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_cronjob FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_deplacement FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_don FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_don_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_ecm_directories FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_ecm_files FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_element_resources FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
@@ -126,19 +123,13 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_fichinter FOR EACH R
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_fichinter_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_fichinterdet_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 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_loan 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_mailing FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_mailing_cibles 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_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_opensurvey_comments FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_opensurvey_sondage FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_opensurvey_user_studs 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();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_paiementcharge FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_paiementfourn FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
@@ -165,10 +156,6 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_propal_extrafields F
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_propal_merge_pdf_product FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_propaldet_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_resource FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentjobposition FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentjobposition_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentcandidature FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_recruitment_recruitmentcandidature_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_salary FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_societe FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_societe_address FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
@@ -187,5 +174,3 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_user FOR EACH ROW EX
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_user_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_usergroup FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
 CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_usergroup_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_website FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();
-CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_website_page FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms();

+ 1 - 0
htdocs/install/step1.php

@@ -261,6 +261,7 @@ if (!$error) {
 				$error++;
 			}
 		}
+
 		// If we need simple access
 		if (!$error && (empty($db_create_database) && empty($db_create_user))) {
 			$db = getDoliDBInstance($db_type, $db_host, $db_user, $db_pass, $db_name, $db_port);

+ 2 - 2
htdocs/install/step4.php

@@ -82,9 +82,9 @@ if ($db->ok) {
 	print '<tr><td><label for="login">'.$langs->trans("Login").' :</label></td><td>';
 	print '<input id="login" name="login" type="text" value="'.(GETPOSTISSET("login") ? GETPOST("login", 'alpha') : (isset($force_install_dolibarrlogin) ? $force_install_dolibarrlogin : '')).'"'.(@$force_install_noedit == 2 && $force_install_dolibarrlogin !== null ? ' disabled' : '').'></td></tr>';
 	print '<tr><td><label for="pass">'.$langs->trans("Password").' :</label></td><td>';
-	print '<input type="password" id="pass" name="pass" autocomplete="new-password" minlength="6"></td></tr>';
+	print '<input type="password" id="pass" name="pass" autocomplete="new-password" minlength="8"></td></tr>';
 	print '<tr><td><label for="pass_verif">'.$langs->trans("PasswordAgain").' :</label></td><td>';
-	print '<input type="password" id="pass_verif" name="pass_verif" autocomplete="new-password" minlength="6"></td></tr>';
+	print '<input type="password" id="pass_verif" name="pass_verif" autocomplete="new-password" minlength="8"></td></tr>';
 	print '</table>';
 
 	if (isset($_GET["error"]) && $_GET["error"] == 1) {

+ 1 - 1
htdocs/main.inc.php

@@ -2150,7 +2150,7 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
 		$dropdownBody .= '<br><b>'.$langs->transcountry("ProfId6", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID6"), 6).'</span>';
 	}
 	$dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
-	$dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.$langs->trans("Country".$mysoc->country_code).'</span>';
+	$dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
 
 	$dropdownBody .= '</div>';
 

+ 2 - 1
htdocs/modulebuilder/admin/setup.php

@@ -89,7 +89,8 @@ if (preg_match('/del_(.*)/', $action, $reg)) {
 
 $form = new Form($db);
 
-llxHeader('', $langs->trans("ModulebuilderSetup"));
+$help_url = '';
+llxHeader('', $langs->trans("ModulebuilderSetup"), $help_url);
 
 $linkback = '<a href="'.($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php').'">'.$langs->trans("BackToModuleList").'</a>';
 

+ 2 - 0
htdocs/modulebuilder/template/admin/myobject_extrafields.php

@@ -91,6 +91,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("MyObject");
+
 $help_url = '';
 $page_name = "MyModuleSetup";
 

+ 2 - 2
htdocs/modulebuilder/template/admin/setup.php

@@ -531,7 +531,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -673,7 +673,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'MYMODULE_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 1 - 1
htdocs/modulebuilder/template/core/modules/modMyModule.class.php

@@ -428,7 +428,7 @@ class modMyModule extends DolibarrModules
 	{
 		global $conf, $langs;
 
-		//$result = $this->_load_tables('/install/mysql/tables/', 'mymodule');
+		//$result = $this->_load_tables('/install/mysql/', 'mymodule');
 		$result = $this->_load_tables('/mymodule/sql/');
 		if ($result < 0) {
 			return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default')

+ 2 - 0
htdocs/partnership/admin/partnership_extrafields.php

@@ -65,6 +65,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Partnership");
+
 $help_url = '';
 $title = $langs->trans("PartnershipSetup");
 

+ 1 - 0
htdocs/product/admin/inventory_extrafields.php

@@ -73,6 +73,7 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Inventory");
 
 llxHeader('', $langs->trans("InventorySetup"), $help_url);
 

+ 1 - 0
htdocs/product/admin/stock_mouvement_extrafields.php

@@ -73,6 +73,7 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("StockMovement");
 
 llxHeader('', $langs->trans("StockSetup"), $help_url);
 

+ 2 - 0
htdocs/recruitment/admin/candidature_extrafields.php

@@ -59,7 +59,9 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Candidature");
 
+$help_url = '';
 llxHeader('', $langs->trans("RecruitmentSetup"), $help_url);
 
 

+ 2 - 0
htdocs/recruitment/admin/jobposition_extrafields.php

@@ -59,7 +59,9 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("JobPosition");
 
+$help_url = '';
 llxHeader('', $langs->trans("RecruitmentSetup"), $help_url);
 
 

+ 1 - 0
htdocs/recruitment/admin/public_interface.php

@@ -96,6 +96,7 @@ print dol_get_fiche_head($head, 'publicurl', '', -1, '');
 
 print '<span class="opacitymedium">'.$langs->trans("PublicInterfaceRecruitmentDesc").'</span><br><br>';
 
+$param = '';
 
 $enabledisablehtml = $langs->trans("EnablePublicRecruitmentPages").' ';
 if (empty($conf->global->RECRUITMENT_ENABLE_PUBLIC_INTERFACE)) {

+ 2 - 2
htdocs/recruitment/admin/setup.php

@@ -330,7 +330,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'RECRUITMENT_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -473,7 +473,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'RECRUITMENT_'.strtoupper($myTmpObjectKey).'_ADDON_PDF';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 2 - 2
htdocs/recruitment/admin/setup_candidatures.php

@@ -328,7 +328,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 
 								print '<td class="center">';
 								$constforvar = 'RECRUITMENT_'.strtoupper($myTmpObjectKey).'_ADDON';
-								if ($conf->global->$constforvar == $file) {
+								if (getDolGlobalString($constforvar) == $file) {
 									print img_picto($langs->trans("Activated"), 'switch_on');
 								} else {
 									print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
@@ -471,7 +471,7 @@ foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
 										// Default
 										print '<td class="center">';
 										$constforvar = 'RECRUITMENT_'.strtoupper($myTmpObjectKey).'_ADDON';
-										if ($conf->global->$constforvar == $name) {
+										if (getDolGlobalString($constforvar) == $name) {
 											//print img_picto($langs->trans("Default"), 'on');
 											// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
 											print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';

+ 2 - 2
htdocs/recruitment/core/modules/recruitment/doc/doc_generic_recruitmentjobposition_odt.modules.php

@@ -130,7 +130,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi
 		// List of directories area
 		$texte .= '<tr><td>';
 		$texttitle = $langs->trans("ListOfDirectories");
-		$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON_PDF_ODT_PATH)));
+		$listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON_PDF_ODT_PATH'))));
 		$listoffiles = array();
 		foreach ($listofdir as $key => $tmpdir) {
 			$tmpdir = trim($tmpdir);
@@ -155,7 +155,7 @@ class doc_generic_recruitmentjobposition_odt extends ModelePDFRecruitmentJobPosi
 		$texte .= $form->textwithpicto($texttitle, $texthelp, 1, 'help', '', 1);
 		$texte .= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">';
 		$texte .= '<textarea class="flat" cols="60" name="value1">';
-		$texte .= $conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON_PDF_ODT_PATH;
+		$texte .= getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADDON_PDF_ODT_PATH');
 		$texte .= '</textarea>';
 		$texte .= '</div><div style="display: inline-block; vertical-align: middle;">';
 		$texte .= '<input type="submit" class="button small reposition" name="modify" value="'.$langs->trans("Modify").'">';

+ 2 - 2
htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php

@@ -849,8 +849,8 @@ class pdf_standard_recruitmentjobposition extends ModelePDFRecruitmentJobPositio
 		pdf_pagehead($pdf, $outputlangs, $this->page_hauteur);
 
 		// Show Draft Watermark
-		if ($object->statut == $object::STATUS_DRAFT && (!empty($conf->global->FACTURE_DRAFT_WATERMARK))) {
-			  pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->FACTURE_DRAFT_WATERMARK);
+		if ($object->statut == $object::STATUS_DRAFT && (!empty($conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_DRAFT_WATERMARK))) {
+			pdf_watermark($pdf, $outputlangs, $this->page_hauteur, $this->page_largeur, 'mm', $conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_DRAFT_WATERMARK);
 		}
 
 		$pdf->SetTextColor(0, 0, 60);

+ 2 - 2
htdocs/recruitment/core/modules/recruitment/mod_recruitmentjobposition_advanced.php

@@ -79,7 +79,7 @@ class mod_recruitmentjobposition_advanced extends ModeleNumRefRecruitmentJobPosi
 
 		// Parametrage du prefix
 		$texte .= '<tr><td>'.$langs->trans("Mask").':</td>';
-		$texte .= '<td class="right">'.$form->textwithpicto('<input type="text" class="flat minwidth175" name="maskRecruitmentJobPosition" value="'.$conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_ADVANCED_MASK.'">', $tooltip, 1, 1).'</td>';
+		$texte .= '<td class="right">'.$form->textwithpicto('<input type="text" class="flat minwidth175" name="maskRecruitmentJobPosition" value="'.getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADVANCED_MASK').'">', $tooltip, 1, 1).'</td>';
 
 		$texte .= '<td class="left" rowspan="2">&nbsp; <input type="submit" class="button button-edit" name="Button"value="'.$langs->trans("Modify").'"></td>';
 
@@ -132,7 +132,7 @@ class mod_recruitmentjobposition_advanced extends ModeleNumRefRecruitmentJobPosi
 		require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 
 		// We get cursor rule
-		$mask = $conf->global->RECRUITMENT_RECRUITMENTJOBPOSITION_ADVANCED_MASK;
+		$mask = getDolGlobalString('RECRUITMENT_RECRUITMENTJOBPOSITION_ADVANCED_MASK');
 
 		if (!$mask) {
 			$this->error = 'NotConfigured';

+ 77 - 16
htdocs/user/class/user.class.php

@@ -297,7 +297,7 @@ class User extends CommonObject
 	public $all_permissions_are_loaded;
 
 	/**
-	 * @var int Number of rights granted to the user
+	 * @var int Number of rights granted to the user. Value loaded after a getrights().
 	 */
 	public $nb_rights;
 
@@ -883,15 +883,18 @@ class User extends CommonObject
 				$i = 0;
 				while ($i < $num) {
 					$obj = $this->db->fetch_object($result);
-					$nid = $obj->id;
 
-					$sql = "DELETE FROM ".$this->db->prefix()."user_rights WHERE fk_user = ".((int) $this->id)." AND fk_id = ".((int) $nid)." AND entity = ".((int) $entity);
-					if (!$this->db->query($sql)) {
-						$error++;
-					}
-					$sql = "INSERT INTO ".$this->db->prefix()."user_rights (entity, fk_user, fk_id) VALUES (".((int) $entity).", ".((int) $this->id).", ".((int) $nid).")";
-					if (!$this->db->query($sql)) {
-						$error++;
+					if ($obj) {
+						$nid = $obj->id;
+
+						$sql = "DELETE FROM ".$this->db->prefix()."user_rights WHERE fk_user = ".((int) $this->id)." AND fk_id = ".((int) $nid)." AND entity = ".((int) $entity);
+						if (!$this->db->query($sql)) {
+							$error++;
+						}
+						$sql = "INSERT INTO ".$this->db->prefix()."user_rights (entity, fk_user, fk_id) VALUES (".((int) $entity).", ".((int) $this->id).", ".((int) $nid).")";
+						if (!$this->db->query($sql)) {
+							$error++;
+						}
 					}
 
 					$i++;
@@ -1096,6 +1099,14 @@ class User extends CommonObject
 			}
 		}
 
+		// For avoid error
+		if (!isset($this->rights) || !is_object($this->rights)) {
+			$this->rights = new stdClass(); // For avoid error
+		}
+		if (!isset($this->rights->user) || !is_object($this->rights->user)) {
+			$this->rights->user = new stdClass(); // For avoid error
+		}
+
 		// Get permission of users + Get permissions of groups
 
 		// First user permissions
@@ -1121,7 +1132,6 @@ class User extends CommonObject
 		if ($resql) {
 			$num = $this->db->num_rows($resql);
 			$i = 0;
-
 			while ($i < $num) {
 				$obj = $this->db->fetch_object($resql);
 
@@ -1131,9 +1141,6 @@ class User extends CommonObject
 					$subperms = $obj->subperms;
 
 					if (!empty($perms)) {
-						if (!isset($this->rights) || !is_object($this->rights)) {
-							$this->rights = new stdClass(); // For avoid error
-						}
 						if (!empty($module)) {
 							if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
 								$this->rights->$module = new stdClass();
@@ -1200,9 +1207,6 @@ class User extends CommonObject
 					$subperms = $obj->subperms;
 
 					if (!empty($perms)) {
-						if (!isset($this->rights) || !is_object($this->rights)) {
-							$this->rights = new stdClass(); // For avoid error
-						}
 						if (!empty($module)) {
 							if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
 								$this->rights->$module = new stdClass();
@@ -1232,6 +1236,63 @@ class User extends CommonObject
 			$this->db->free($resql);
 		}
 
+		// Force permission on user for admin
+		if (!empty($this->admin)) {
+			if (empty($this->rights->user->user)) {
+				$this->rights->user->user = new stdClass();
+			}
+			$listofpermtotest = array('lire', 'creer', 'password', 'supprimer', 'export');
+			foreach ($listofpermtotest as $permtotest) {
+				if (empty($this->rights->user->user->$permtotest)) {
+					$this->rights->user->user->$permtotest = 1;
+					$this->nb_rights++;
+				}
+			}
+			if (empty($this->rights->user->self)) {
+				$this->rights->user->self = new stdClass();
+			}
+			$listofpermtotest = array('creer', 'password');
+			foreach ($listofpermtotest as $permtotest) {
+				if (empty($this->rights->user->self->$permtotest)) {
+					$this->rights->user->self->$permtotest = 1;
+					$this->nb_rights++;
+				}
+			}
+			// Add test on advanced permissions
+			if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS)) {
+				if (empty($this->rights->user->user_advance)) {
+					$this->rights->user->user_advance = new stdClass();
+				}
+				$listofpermtotest = array('readperms', 'write');
+				foreach ($listofpermtotest as $permtotest) {
+					if (empty($this->rights->user->user_advance->$permtotest)) {
+						$this->rights->user->user_advance->$permtotest = 1;
+						$this->nb_rights++;
+					}
+				}
+				if (empty($this->rights->user->self_advance)) {
+					$this->rights->user->self_advance = new stdClass();
+				}
+				$listofpermtotest = array('readperms', 'writeperms');
+				foreach ($listofpermtotest as $permtotest) {
+					if (empty($this->rights->user->self_advance->$permtotest)) {
+						$this->rights->user->self_advance->$permtotest = 1;
+						$this->nb_rights++;
+					}
+				}
+				if (empty($this->rights->user->group_advance)) {
+					$this->rights->user->group_advance = new stdClass();
+				}
+				$listofpermtotest = array('read', 'readperms', 'write', 'delete');
+				foreach ($listofpermtotest as $permtotest) {
+					if (empty($this->rights->user) || empty($this->rights->user->group_advance->$permtotest)) {
+						$this->rights->user->group_advance->$permtotest = 1;
+						$this->nb_rights++;
+					}
+				}
+			}
+		}
+
 		// For backward compatibility
 		if (isset($this->rights->propale) && !isset($this->rights->propal)) {
 			$this->rights->propal = $this->rights->propale;

+ 2 - 2
htdocs/user/group/card.php

@@ -454,7 +454,7 @@ if ($action == 'create') {
 						print '<td class="center">'.$useringroup->getLibStatut(5).'</td>';
 						print '<td class="right">';
 						if (!empty($user->admin)) {
-							print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&amp;action=removeuser&amp;user='.$useringroup->id.'">';
+							print '<a href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=removeuser&token='.newToken().'&user='.$useringroup->id.'">';
 							print img_picto($langs->trans("RemoveFromGroup"), 'unlink');
 							print '</a>';
 						} else {
@@ -483,7 +483,7 @@ if ($action == 'create') {
 			$genallowed = $user->rights->user->user->creer;
 			$delallowed = $user->rights->user->user->supprimer;
 
-			$somethingshown = $formfile->showdocuments('usergroup', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang);
+			$somethingshown = $formfile->showdocuments('usergroup', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', 0, '', $mysoc->default_lang);
 
 			// Show links to link elements
 			$linktoelem = $form->showLinkToObjectBlock($object, null, null);

+ 1 - 1
htdocs/user/group/perms.php

@@ -328,7 +328,7 @@ if ($object->id > 0) {
 			//print img_object('', $picto, 'class="inline-block pictoobjectwidth"').' '.$objMod->getName();
 			print '</td>';
 
-			if (is_array($permsgroupbyentity[$entity])) {
+			if (!empty($permsgroupbyentity[$entity]) && is_array($permsgroupbyentity[$entity])) {
 				if (in_array($obj->id, $permsgroupbyentity[$entity])) {
 					// Own permission by group
 					if ($caneditperms) {