';
$moreforfilter .= $langs->trans('AccountingCategory').': ';
diff --git a/htdocs/ai/admin/custom_prompt.php b/htdocs/ai/admin/custom_prompt.php
index c127674c744..83753c01a7a 100644
--- a/htdocs/ai/admin/custom_prompt.php
+++ b/htdocs/ai/admin/custom_prompt.php
@@ -27,7 +27,7 @@
// Load Dolibarr environment
require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
-require_once '../lib/ai.lib.php';
+require_once DOL_DOCUMENT_ROOT."/ai/lib/ai.lib.php";
/**
* @var Conf $conf
@@ -39,6 +39,8 @@ require_once '../lib/ai.lib.php';
$langs->loadLangs(array("admin", "website", "other"));
+$arrayofaifeatures = getLitOfAIFeatures();
+
// Parameters
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
@@ -81,18 +83,6 @@ $setupnotempty += count($formSetup->items);
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
-// List of AI features
-$arrayofaifeatures = array(
- 'textgenerationemail' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("EmailContent").')', 'picto'=>'', 'status'=>'development'),
- 'textgenerationwebpage' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("WebsitePage").')', 'picto'=>'', 'status'=>'development'),
- 'textgeneration' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("Other").')', 'picto'=>'', 'status'=>'notused'),
- 'imagegeneration' => array('label' => 'ImageGeneration', 'picto'=>'', 'status'=>'notused'),
- 'videogeneration' => array('label' => 'VideoGeneration', 'picto'=>'', 'status'=>'notused'),
- 'audiogeneration' => array('label' => 'AudioGeneration', 'picto'=>'', 'status'=>'notused'),
- 'transcription' => array('label' => 'Transcription', 'picto'=>'', 'status'=>'notused'),
- 'translation' => array('label' => 'Translation', 'picto'=>'', 'status'=>'notused')
-);
-
/*
* Actions
@@ -213,7 +203,7 @@ print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
// Configuration header
$head = aiAdminPrepareHead();
-print dol_get_fiche_head($head, 'custom', $langs->trans($title), -1, "fa-microchip");
+print dol_get_fiche_head($head, 'custom', $langs->trans($title), -1, "ai");
//$newbutton = '
';
$newbutton = '';
@@ -279,6 +269,7 @@ if ($action == 'edit' || $action == 'deleteproperty') {
$out .= '';
$out .= '';
+
$out .= '
';
$out .= '';
$out .= '';
@@ -314,6 +305,7 @@ if ($action == 'edit' || $action == 'deleteproperty') {
$out .= $form->buttonsSaveCancel("Add", "");
$out .= '';
+
$out .= ' ';
print $out;
@@ -374,7 +366,7 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') {
$out .= '';
$out .= ' ';
$out .= '';
- $out .= ' ';
+ $out .= ' ';
$out .= ' ';
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
@@ -383,6 +375,8 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') {
$formmail = new FormMail($db);
$htmlname = $key;
+ $out .= ' ';
+
// Fill $out
include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
diff --git a/htdocs/ai/admin/setup.php b/htdocs/ai/admin/setup.php
index 8df3b7bd9e2..2e04f1d2f2d 100644
--- a/htdocs/ai/admin/setup.php
+++ b/htdocs/ai/admin/setup.php
@@ -28,7 +28,8 @@
// Load Dolibarr environment
require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
-require_once '../lib/ai.lib.php';
+require_once DOL_DOCUMENT_ROOT."/core/class/doleditor.class.php";
+require_once DOL_DOCUMENT_ROOT."/ai/lib/ai.lib.php";
/**
* @var Conf $conf
@@ -38,7 +39,9 @@ require_once '../lib/ai.lib.php';
* @var User $user
*/
-$langs->loadLangs(array("admin"));
+$langs->loadLangs(array("admin", "website", "other"));
+
+$arrayofaifeatures = getLitOfAIFeatures();
// Parameters
$action = GETPOST('action', 'aZ09');
@@ -49,10 +52,7 @@ if (empty($action)) {
$action = 'edit';
}
-$value = GETPOST('value', 'alpha');
-$label = GETPOST('label', 'alpha');
-$scandir = GETPOST('scan_dir', 'alpha');
-$type = 'myobject';
+$content = GETPOST('content');
$error = 0;
$setupnotempty = 0;
@@ -69,6 +69,7 @@ $formSetup = new FormSetup($db);
// List all available IA
$arrayofia = array(
+ '-1' => $langs->trans('SelectAService'),
'chatgpt' => 'ChatGPT',
'groq' => 'Groq',
'custom' => 'Custom'
@@ -89,14 +90,14 @@ foreach ($arrayofia as $ia => $ialabel) {
$item->nameText = $langs->trans("AI_API_KEY").' ('.$ialabel.')';
$item->defaultFieldValue = '';
$item->fieldParams['hideGenerateButton'] = 1;
- $item->fieldParams['trClass'] = $ia;
- $item->cssClass = 'minwidth500 text-security';
+ $item->fieldParams['trClass'] = 'iaservice '.$ia;
+ $item->cssClass = 'minwidth500 text-security input'.$ia;
$item = $formSetup->newItem('AI_API_'.strtoupper($ia).'_URL'); // Name of constant must end with _KEY so it is encrypted when saved into database.
$item->nameText = $langs->trans("AI_API_URL").' ('.$ialabel.')';
$item->defaultFieldValue = '';
- $item->fieldParams['trClass'] = $ia;
- $item->cssClass = 'minwidth500';
+ $item->fieldParams['trClass'] = 'iaservice '.$ia;
+ $item->cssClass = 'minwidth500 input'.$ia;
}
$setupnotempty = + count($formSetup->items);
@@ -140,7 +141,7 @@ print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
// Configuration header
$head = aiAdminPrepareHead();
-print dol_get_fiche_head($head, 'settings', $langs->trans($title), -1, "fa-microchip");
+print dol_get_fiche_head($head, 'settings', $langs->trans($title), -1, "ai");
if ($action == 'edit') {
@@ -160,8 +161,86 @@ if (empty($setupnotempty)) {
print ' '.$langs->trans("NothingToSetup");
}
+print '';
+
// Page end
print dol_get_fiche_end();
+
+if (getDolGlobalString("AI_API_SERVICE")) {
+ // Section to test
+ print '';
+}
+
llxFooter();
$db->close();
diff --git a/htdocs/ai/ajax/generate_content.php b/htdocs/ai/ajax/generate_content.php
index 0f1e1f76a92..0cd6a125970 100644
--- a/htdocs/ai/ajax/generate_content.php
+++ b/htdocs/ai/ajax/generate_content.php
@@ -81,15 +81,17 @@ $format = empty($jsonData['format']) ? '' : $jsonData['format'];
$generatedContent = $ai->generateContent($instructions, 'auto', $function, $format);
-if (is_array($generatedContent) && $generatedContent['error']) {
+if (is_null($generatedContent) || (is_array($generatedContent) && $generatedContent['error'])) {
// Output error
if (!empty($generatedContent['code']) && $generatedContent['code'] == 429) {
print "Quota or allowed period exceeded. Retry Later !";
- } elseif ($generatedContent['code'] >= 400) {
+ } elseif (!empty($generatedContent['code']) && $generatedContent['code'] >= 400) {
print "Error : " . $generatedContent['message'];
print ''.$langs->trans('ErrorGoToModuleSetup').' ';
- } else {
+ } elseif (!empty($generatedContent['message'])) {
print "Error returned by API call: " . $generatedContent['message'];
+ } else {
+ print "Error API returned no answer";
}
} else {
if ($function == 'textgenerationemail' || $function == 'textgenerationwebpage') {
diff --git a/htdocs/ai/class/ai.class.php b/htdocs/ai/class/ai.class.php
index 922df84dcbb..8eb4ae4d642 100644
--- a/htdocs/ai/class/ai.class.php
+++ b/htdocs/ai/class/ai.class.php
@@ -80,6 +80,8 @@ class Ai
*/
public function generateContent($instructions, $model = 'auto', $function = 'textgeneration', $format = '')
{
+ global $dolibarr_main_data_root;
+
if (empty($this->apiKey)) {
return array('error' => true, 'message' => 'API key is not defined for the AI enabled service ('.$this->apiService.')');
}
@@ -192,14 +194,14 @@ class Ai
if (isset($configurations[$function])) {
if (isset($configurations[$function]['prePrompt'])) {
- $prePrompt = $configurations[$function]['prePrompt']; // TODO We can send prePrompt into a separated message with role system.
+ $prePrompt = $configurations[$function]['prePrompt'];
}
if (isset($configurations[$function]['postPrompt'])) {
$postPrompt = $configurations[$function]['postPrompt'];
}
}
- $fullInstructions = ($prePrompt ? $prePrompt.' ' : '').$instructions.($postPrompt ? '. '.$postPrompt : '');
+ $fullInstructions = $instructions.($postPrompt ? (preg_match('/[\.\!\?]$/', $instructions) ? '' : '.').' '.$postPrompt : '');
// Set payload string
/*{
@@ -224,18 +226,48 @@ class Ai
"temperature": 0.7,
"top_p": 0.95
}*/
- $payload = json_encode([
- 'messages' => [
- ['role' => 'user', 'content' => $fullInstructions]
- ],
- 'model' => $model,
- //'stream' => false
- ]);
- $headers = ([
+ $arrayforpayload = array(
+ 'messages' => array(array('role' => 'user', 'content' => $fullInstructions)),
+ 'model' => $model,
+ );
+
+ // Add a system message
+ $addDateTimeContext = false;
+ if ($addDateTimeContext) { // @phpstan-ignore-line
+ $prePrompt = ($prePrompt ? $prePrompt.(preg_match('/[\.\!\?]$/', $prePrompt) ? '' : '.').' ' : '').'Today we are '.dol_print_date(dol_now(), 'dayhourtext');
+ }
+ if ($prePrompt) {
+ $arrayforpayload['messages'][] = array('role' => 'system', 'content' => $prePrompt);
+ }
+
+ /*
+ $arrayforpayload['temperature'] = 0.7;
+ $arrayforpayload['max_tokens'] = -1;
+ $arrayforpayload['stream'] = false;
+ */
+
+ $payload = json_encode($arrayforpayload);
+
+ $headers = array(
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json'
- ]);
+ );
+
+ if (getDolGlobalString("AI_DEBUG")) {
+ if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir
+ $outputfile = $dolibarr_main_data_root."/dolibarr_ai.log";
+ $fp = fopen($outputfile, "w"); // overwrite
+
+ if ($fp) {
+ fwrite($fp, var_export($headers, true)."\n");
+ fwrite($fp, var_export($payload, true)."\n");
+
+ fclose($fp);
+ dolChmod($outputfile);
+ }
+ }
+ }
$localurl = 2; // Accept both local and external endpoints
$response = getURLContent($this->apiEndpoint, 'POST', $payload, 1, $headers, array('http', 'https'), $localurl);
@@ -248,7 +280,17 @@ class Ai
}
if (getDolGlobalString("AI_DEBUG")) {
- dol_syslog("response content = ".var_export($response['content'], true));
+ if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir
+ $outputfile = $dolibarr_main_data_root."/dolibarr_ai.log";
+ $fp = fopen($outputfile, "a");
+
+ if ($fp) {
+ fwrite($fp, var_export((empty($response['content']) ? 'No content result' : $response['content']), true)."\n");
+
+ fclose($fp);
+ dolChmod($outputfile);
+ }
+ }
}
// Decode JSON response
diff --git a/htdocs/ai/lib/ai.lib.php b/htdocs/ai/lib/ai.lib.php
index fe8c6232db0..8705f1e961f 100644
--- a/htdocs/ai/lib/ai.lib.php
+++ b/htdocs/ai/lib/ai.lib.php
@@ -23,6 +23,30 @@
* \brief Library files with common functions for Ai
*/
+
+/**
+ * Prepare admin pages header
+ *
+ * @return array>
+ */
+function getLitOfAIFeatures()
+{
+ global $langs;
+
+ $arrayofaifeatures = array(
+ 'textgenerationemail' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("EmailContent").')', 'picto'=>'', 'status'=>'dolibarr'),
+ 'textgenerationwebpage' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("WebsitePage").')', 'picto'=>'', 'status'=>'dolibarr'),
+ 'textgeneration' => array('label' => $langs->trans('TextGeneration').' ('.$langs->trans("Other").')', 'picto'=>'', 'status'=>'notused'),
+ 'imagegeneration' => array('label' => 'ImageGeneration', 'picto'=>'', 'status'=>'notused'),
+ 'videogeneration' => array('label' => 'VideoGeneration', 'picto'=>'', 'status'=>'notused'),
+ 'audiogeneration' => array('label' => 'AudioGeneration', 'picto'=>'', 'status'=>'notused'),
+ 'transcription' => array('label' => 'Transcription', 'picto'=>'', 'status'=>'notused'),
+ 'translation' => array('label' => 'Translation', 'picto'=>'', 'status'=>'notused')
+ );
+
+ return $arrayofaifeatures;
+}
+
/**
* Prepare admin pages header
*
diff --git a/htdocs/core/ajax/box.php b/htdocs/core/ajax/box.php
index 775f1465def..d1e2e1a4990 100644
--- a/htdocs/core/ajax/box.php
+++ b/htdocs/core/ajax/box.php
@@ -53,10 +53,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/infobox.class.php';
$boxid = GETPOSTINT('boxid');
$boxorder = GETPOST('boxorder');
-$zone = GETPOST('zone'); // Can be key for zone
-if ($zone !== '') {
- $zone = (int) $zone;
-}
+$zone = GETPOST('zone'); // Can be '0' or '1' or 'pagename'...
$userid = GETPOSTINT('userid');
// Security check
@@ -91,7 +88,7 @@ if ($boxorder && $zone != '' && $userid > 0) {
// boxorder value is the target order: "A:idboxA1,idboxA2,A-B:idboxB1,idboxB2,B"
dol_syslog("AjaxBox boxorder=".$boxorder." zone=".$zone." userid=".$userid, LOG_DEBUG);
- $result = InfoBox::saveboxorder($db, (int) $zone, $boxorder, $userid);
+ $result = InfoBox::saveboxorder($db, $zone, $boxorder, $userid);
if ($result > 0) {
$langs->load("boxes");
if (!GETPOST('closing')) {
diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php
index 81efbf470a7..ce57b90a4c7 100644
--- a/htdocs/core/class/CMailFile.class.php
+++ b/htdocs/core/class/CMailFile.class.php
@@ -1483,24 +1483,26 @@ class CMailFile
$outputfile = $dolibarr_main_data_root."/dolibarr_mail.log";
$fp = fopen($outputfile, "w"); // overwrite
- if ($this->sendmode == 'mail') {
- fwrite($fp, $this->headers);
- fwrite($fp, $this->eol); // This eol is added by the mail function, so we add it in log
- fwrite($fp, $this->message);
- } elseif ($this->sendmode == 'smtps') {
- fwrite($fp, $this->smtps->log); // this->smtps->log is filled only if MAIN_MAIL_DEBUG was set to on
- } elseif ($this->sendmode == 'swiftmailer') {
- fwrite($fp, "smtpheader=\n".$this->message->getHeaders()->toString()."\n");
- fwrite($fp, $this->logger->dump()); // this->logger is filled only if MAIN_MAIL_DEBUG was set to on
- }
+ if ($fp) {
+ if ($this->sendmode == 'mail') {
+ fwrite($fp, $this->headers);
+ fwrite($fp, $this->eol); // This eol is added by the mail function, so we add it in log
+ fwrite($fp, $this->message);
+ } elseif ($this->sendmode == 'smtps') {
+ fwrite($fp, $this->smtps->log); // this->smtps->log is filled only if MAIN_MAIL_DEBUG was set to on
+ } elseif ($this->sendmode == 'swiftmailer') {
+ fwrite($fp, "smtpheader=\n".$this->message->getHeaders()->toString()."\n");
+ fwrite($fp, $this->logger->dump()); // this->logger is filled only if MAIN_MAIL_DEBUG was set to on
+ }
- fclose($fp);
- dolChmod($outputfile);
+ fclose($fp);
+ dolChmod($outputfile);
- // Move dolibarr_mail.log into a dolibarr_mail.log.v123456789
- if (getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE')) {
- require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
- archiveOrBackupFile($outputfile, getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE'));
+ // Move dolibarr_mail.log into a dolibarr_mail.log.v123456789
+ if (getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE')) {
+ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
+ archiveOrBackupFile($outputfile, getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE'));
+ }
}
}
}
diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
index a4f954cbaff..6975ad29155 100644
--- a/htdocs/core/class/commonobject.class.php
+++ b/htdocs/core/class/commonobject.class.php
@@ -10360,9 +10360,9 @@ abstract class CommonObject
/**
* Create object in the database
*
- * @param User $user User that creates
- * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers
- * @return int<-1,max> Return integer <0 if KO, Id of created object if OK
+ * @param User $user User that creates
+ * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers
+ * @return int<-1,max> Return integer <0 if KO, Id of created object if OK
*/
public function createCommon(User $user, $notrigger = 0)
{
@@ -10382,6 +10382,7 @@ abstract class CommonObject
$fieldvalues['date_creation'] = $this->db->idate($now);
$this->date_creation = $this->db->idate($now);
}
+ // For backward compatibility, if a property ->fk_user_creat exists and not filled.
if (array_key_exists('fk_user_creat', $fieldvalues) && !($fieldvalues['fk_user_creat'] > 0)) {
$fieldvalues['fk_user_creat'] = $user->id;
$this->fk_user_creat = $user->id;
diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php
index 1fdd72ab371..c3904969a64 100644
--- a/htdocs/core/class/html.formmail.class.php
+++ b/htdocs/core/class/html.formmail.class.php
@@ -1493,6 +1493,7 @@ class FormMail extends Form
* @param string $format Format for output ('', 'html', ...)
* @param string $htmlContent HTML name of WYSIWYG field
* @return string HTML code to ask AI instruction and autofill result
+ * TODO Move into a file html.formai.class.php
*/
public function getSectionForAIPrompt($function = 'textgeneration', $format = '', $htmlContent = 'message')
{
@@ -1502,7 +1503,7 @@ class FormMail extends Form
$htmlContent = preg_replace('/[^a-z0-9_]/', '', $htmlContent);
- $out = '';
+ $out = '
';
$out .= '
';
$out .= '
';
$out .= '
';
@@ -1526,7 +1527,7 @@ class FormMail extends Form
});
$('#generate_button".$htmlContent."').click(function() {
- console.log('We click on generate_button".$htmlContent." ai button');
+ console.log('We click on generate_button".$htmlContent." ai button, so we make an ajax on url /ai/ajax/generate_content.php');
var instructions = $('#ai_instructions".$htmlContent."').val();
var timeoutfinished = 0;
@@ -1589,49 +1590,50 @@ class FormMail extends Form
CKEDITOR.instances.".$htmlContent.".setReadOnly(1);
}
- $.ajax({
- url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
- 'format': '".dol_escape_js($format)."', /* the format for output */
- 'function': '".dol_escape_js($function)."', /* the AI feature to call */
- 'instructions': instructions, /* the prompt string */
- }),
- success: function(response) {
- console.log('Add response into field \'#".$htmlContent."\': '+response);
+ $.ajax({
+ url: '". DOL_URL_ROOT."/ai/ajax/generate_content.php?token=".currentToken()."',
+ type: 'POST',
+ contentType: 'application/json',
+ data: JSON.stringify({
+ 'format': '".dol_escape_js($format)."', /* the format for output */
+ 'function': '".dol_escape_js($function)."', /* the AI feature to call */
+ 'instructions': instructions, /* the prompt string */
+ }),
+ success: function(response) {
+ console.log('Add response into field \'#".$htmlContent."\': '+response);
- jQuery('#".$htmlContent."').val(response); // If #htmlcontent is a input name or textarea
- jQuery('#".$htmlContent."').html(response); // If #htmlContent is a div
- //jQuery('#".$htmlContent."preview').val(response);
+ jQuery('#".$htmlContent."').val(response); // If #htmlcontent is a input name or textarea
+ jQuery('#".$htmlContent."').html(response); // If #htmlContent is a div
+ //jQuery('#".$htmlContent."preview').val(response);
- if (CKEDITOR.instances) {
- var editorInstance = CKEDITOR.instances.".$htmlContent.";
- if (editorInstance) {
- editorInstance.setReadOnly(0);
- editorInstance.setData(response);
+ if (CKEDITOR.instances) {
+ var editorInstance = CKEDITOR.instances.".$htmlContent.";
+ if (editorInstance) {
+ editorInstance.setReadOnly(0);
+ editorInstance.setData(response);
+ }
+ //var editorInstancepreview = CKEDITOR.instances.".$htmlContent."preview;
+ //if (editorInstancepreview) {
+ // editorInstancepreview.setData(response);
+ //}
}
- //var editorInstancepreview = CKEDITOR.instances.".$htmlContent."preview;
- //if (editorInstancepreview) {
- // editorInstancepreview.setData(response);
- //}
- }
- // remove readonly
- $('#ai_instructions".$htmlContent."').val('');
+ // remove readonly
+ $('#ai_instructions".$htmlContent."').val('');
- apicallfinished = 1;
- if (timeoutfinished) {
+ apicallfinished = 1;
+ if (timeoutfinished) {
+ $('#ai_status_message".$htmlContent."').hide();
+ }
+ },
+ error: function(xhr, status, error) {
+ alert(error);
+ console.error('error ajax', status, error);
$('#ai_status_message".$htmlContent."').hide();
}
- },
- error: function(xhr, status, error) {
- alert(error);
- console.error('error ajax', status, error);
- $('#ai_status_message".$htmlContent."').hide();
- }
- });
+ });
+ }
});
});
@@ -1658,7 +1660,7 @@ class FormMail extends Form
$websitepage = new WebsitePage($this->db);
$arrayofblogs = $websitepage->fetchAll('', 'DESC', 'date_creation', 0, 0, array('type_container' => 'blogpost'));
- $out = '
';
+ $out = '
';
// Define list of email layouts to use
$layouts = array(
diff --git a/htdocs/core/class/infobox.class.php b/htdocs/core/class/infobox.class.php
index cfec6d48773..68340e873d2 100644
--- a/htdocs/core/class/infobox.class.php
+++ b/htdocs/core/class/infobox.class.php
@@ -217,11 +217,11 @@ class InfoBox
/**
* Save order of boxes for area and user
*
- * @param DoliDB $dbs Database handler
- * @param int $zone Key of area (0 for Homepage, ...)
- * @param string $boxorder List of boxes with correct order 'A:123,456,...-B:789,321...'
- * @param int $userid Id of user
- * @return int Return integer <0 if KO, 0=Nothing done, > 0 if OK
+ * @param DoliDB $dbs Database handler
+ * @param int|string $zone Key of area ('0' for Homepage, '1', 'pagename', ...)
+ * @param string $boxorder List of boxes with correct order 'A:123,456,...-B:789,321...'
+ * @param int $userid Id of user
+ * @return int Return integer <0 if KO, 0=Nothing done, > 0 if OK
*/
public static function saveboxorder($dbs, $zone, $boxorder, $userid = 0)
{
@@ -252,6 +252,10 @@ class InfoBox
return -3;
}
+ if (!is_numeric($zone)) {
+ $zone = '0'; // Force $zone to a numeric value string
+ }
+
// Delete all lines
$sql = "DELETE FROM ".$dbs->prefix()."boxes";
$sql .= " WHERE entity = ".$conf->entity;
diff --git a/htdocs/core/class/timespent.class.php b/htdocs/core/class/timespent.class.php
index 87bb25277f1..fb79053c145 100644
--- a/htdocs/core/class/timespent.class.php
+++ b/htdocs/core/class/timespent.class.php
@@ -123,70 +123,87 @@ class TimeSpent extends CommonObject
'datec' => array('type' => 'datetime', 'label' => 'datec', 'enabled' => 1, 'position' => 16, 'notnull' => 0, 'visible' => -1,),
'note' => array('type' => 'text', 'label' => 'note', 'enabled' => 1, 'position' => 18, 'notnull' => 0, 'visible' => -1,),
);
+
/**
* @var int
*/
public $rowid;
+
/**
* @var string
*/
public $import_key;
+
/**
* @var int
*/
public $fk_element;
+
/**
* @var string
*/
public $elementtype;
+
/**
* @var int|string
*/
public $element_date;
+
/**
* @var int
*/
public $element_datehour;
+
/**
* @var int
*/
public $element_date_withhour;
+
/**
* @var int Note seems to be int (seconds) even if declared as double in DB.
*/
public $element_duration;
+
/**
* @var int
*/
public $fk_product;
+
/**
* @var int
*/
public $fk_user;
+
/**
* @var float
*/
public $thm;
+
/**
* @var int
*/
public $invoice_id;
+
/**
* @var int
*/
public $invoice_line_id;
+
/**
* @var int
*/
public $intervention_id;
+
/**
* @var int
*/
public $intervention_line_id;
+
/**
- * @var string
+ * @var ?int Date creation
*/
public $datec;
+
/**
* @var string
*/
diff --git a/htdocs/core/lib/geturl.lib.php b/htdocs/core/lib/geturl.lib.php
index 70ba14f40b1..20d22d47b7c 100644
--- a/htdocs/core/lib/geturl.lib.php
+++ b/htdocs/core/lib/geturl.lib.php
@@ -51,6 +51,10 @@ function getURLContent($url, $postorget = 'GET', $param = '', $followlocation =
dol_syslog("getURLContent postorget=".$postorget." URL=".$url." param=".$param);
+ if (!function_exists('curl_init')) {
+ return array('http_code' => 500, 'content' => '', 'curl_error_no' => 1, 'curl_error_msg' => 'PHP curl library must be installed');
+ }
+
//setting the curl parameters.
$ch = curl_init();
diff --git a/htdocs/core/modules/modAdherent.class.php b/htdocs/core/modules/modAdherent.class.php
index 1fae83e1c75..9e8d43dbe65 100644
--- a/htdocs/core/modules/modAdherent.class.php
+++ b/htdocs/core/modules/modAdherent.class.php
@@ -182,13 +182,12 @@ class modAdherent extends DolibarrModules
[
"MEMBER_ADDON_PDF_ODT_PATH",
"chaine",
- "DOL_DATA_ROOT/doctemplates/members",
+ "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/members",
"",
0,
],
];
-
// Boxes
//-------
$this->boxes = array(
@@ -439,8 +438,8 @@ class modAdherent extends DolibarrModules
// ODT template
/*
- $src=DOL_DOCUMENT_ROOT.'/install/doctemplates/orders/template_order.odt';
- $dirodt=DOL_DATA_ROOT.'/doctemplates/orders';
+ $src=DOL_DOCUMENT_ROOT.'/install/doctemplates/members/template_member.odt';
+ $dirodt=DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/members';
$dest=$dirodt.'/template_order.odt';
if (file_exists($src) && ! file_exists($dest)) {
diff --git a/htdocs/core/modules/modBom.class.php b/htdocs/core/modules/modBom.class.php
index 30117285934..3d5aee1e29f 100644
--- a/htdocs/core/modules/modBom.class.php
+++ b/htdocs/core/modules/modBom.class.php
@@ -128,7 +128,7 @@ class modBom extends DolibarrModules
$this->const = array(
1 => array('BOM_ADDON_PDF', 'chaine', 'generic_bom_odt', 'Name of PDF model of BOM', 0),
2 => array('BOM_ADDON', 'chaine', 'mod_bom_standard', 'Name of numbering rules of BOM', 0),
- 3 => array('BOM_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/boms', '', 0)
+ 3 => array('BOM_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT'.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/boms', '', 0)
);
// Some keys to add into the overwriting translation tables
@@ -480,7 +480,7 @@ class modBom extends DolibarrModules
// ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/boms/template_bom.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/boms';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/boms';
$dest = $dirodt.'/template_bom.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modContrat.class.php b/htdocs/core/modules/modContrat.class.php
index 879549cabe4..bbdadef52da 100644
--- a/htdocs/core/modules/modContrat.class.php
+++ b/htdocs/core/modules/modContrat.class.php
@@ -87,7 +87,7 @@ class modContrat extends DolibarrModules
[
"CONTRACT_ADDON_PDF_ODT_PATH",
"chaine",
- "DOL_DATA_ROOT/doctemplates/contracts",
+ "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/contracts",
"",
0,
],
@@ -231,7 +231,7 @@ class modContrat extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/contracts/template_contract.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/contracts';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/contracts';
$dest = $dirodt.'/template_contract.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modExpedition.class.php b/htdocs/core/modules/modExpedition.class.php
index 9860dc3d086..85fa70862ac 100644
--- a/htdocs/core/modules/modExpedition.class.php
+++ b/htdocs/core/modules/modExpedition.class.php
@@ -100,7 +100,7 @@ class modExpedition extends DolibarrModules
[
"EXPEDITION_ADDON_PDF_ODT_PATH",
"chaine",
- "DOL_DATA_ROOT/doctemplates/shipments",
+ "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/shipments",
"",
0,
],
@@ -121,7 +121,7 @@ class modExpedition extends DolibarrModules
[
"DELIVERY_ADDON_PDF_ODT_PATH",
"chaine",
- "DOL_DATA_ROOT/doctemplates/deliveries",
+ "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/deliveries",
"",
0,
],
@@ -133,6 +133,7 @@ class modExpedition extends DolibarrModules
0,
],
];
+
// Boxes
$this->boxes = array(
0 => array('file'=>'box_shipments.php', 'enabledbydefaulton'=>'Home'),
@@ -344,7 +345,7 @@ class modExpedition extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/shipments/template_shipment.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/shipments';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/shipments';
$dest = $dirodt.'/template_shipment.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php
index 107f99dd743..b29a3c0b7fb 100644
--- a/htdocs/core/modules/modFournisseur.class.php
+++ b/htdocs/core/modules/modFournisseur.class.php
@@ -118,7 +118,7 @@ class modFournisseur extends DolibarrModules
// Add ability ODT for Supplier orders
$this->const[$r][0] = "SUPPLIER_ORDER_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/supplier_orders";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/supplier_orders";
$this->const[$r][3] = '';
$this->const[$r][4] = 0;
$r++;
@@ -126,7 +126,7 @@ class modFournisseur extends DolibarrModules
// Add ability ODT for Supplier Invoices
$this->const[$r][0] = "SUPPLIER_INVOICE_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/supplier_invoices";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
$r++;
@@ -973,7 +973,7 @@ class modFournisseur extends DolibarrModules
//ODT template for Supplier Orders
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/supplier_orders/template_supplier_order.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/supplier_orders';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/supplier_orders';
$dest = $dirodt.'/template_supplier_order.odt';
if (file_exists($src) && !file_exists($dest)) {
@@ -994,7 +994,7 @@ class modFournisseur extends DolibarrModules
//ODT template for Supplier Invoice
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/supplier_invoices/template_supplier_invoices.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/supplier_invoices';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/supplier_invoices';
$dest = $dirodt.'/template_supplier_invoices.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modHoliday.class.php b/htdocs/core/modules/modHoliday.class.php
index 5e4002b26a4..453bb966a06 100644
--- a/htdocs/core/modules/modHoliday.class.php
+++ b/htdocs/core/modules/modHoliday.class.php
@@ -111,7 +111,7 @@ class modHoliday extends DolibarrModules
$this->const[$r][0] = "HOLIDAY_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/holiday";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/holiday";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
$r++;
@@ -308,7 +308,7 @@ class modHoliday extends DolibarrModules
//ODT template
/*$src=DOL_DOCUMENT_ROOT.'/install/doctemplates/holiday/template_holiday.odt';
- $dirodt=DOL_DATA_ROOT.'/doctemplates/holiday';
+ $dirodt=DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/holiday';
$dest=$dirodt.'/template_order.odt';
if (file_exists($src) && ! file_exists($dest))
diff --git a/htdocs/core/modules/modMrp.class.php b/htdocs/core/modules/modMrp.class.php
index acf4dbd737a..7f081c42c91 100644
--- a/htdocs/core/modules/modMrp.class.php
+++ b/htdocs/core/modules/modMrp.class.php
@@ -138,7 +138,7 @@ class modMrp extends DolibarrModules
$this->const = array(
//1=>array('MRP_MO_ADDON_PDF', 'chaine', 'vinci', 'Name of default PDF model of MO', 0),
2=>array('MRP_MO_ADDON', 'chaine', 'mod_mo_standard', 'Name of numbering rules of MO', 0),
- 3=>array('MRP_MO_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/mrps', '', 0)
+ 3=>array('MRP_MO_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT'.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/mrps', '', 0)
);
// Some keys to add into the overwriting translation tables
@@ -534,7 +534,7 @@ class modMrp extends DolibarrModules
// ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/mrps/template_mo.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/mrps';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/mrps';
$dest = $dirodt.'/template_mo.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modProjet.class.php b/htdocs/core/modules/modProjet.class.php
index 87bca4805ff..1e19dc844f5 100644
--- a/htdocs/core/modules/modProjet.class.php
+++ b/htdocs/core/modules/modProjet.class.php
@@ -92,7 +92,7 @@ class modProjet extends DolibarrModules
[
"PROJECT_ADDON_PDF_ODT_PATH",
"chaine",
- "DOL_DATA_ROOT/doctemplates/projects",
+ "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/projects",
"",
0,
],
@@ -113,7 +113,7 @@ class modProjet extends DolibarrModules
[
"PROJECT_TASK_ADDON_PDF_ODT_PATH",
"chaine",
- "DOL_DATA_ROOT/doctemplates/tasks",
+ "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/tasks",
"",
0,
],
@@ -380,7 +380,7 @@ class modProjet extends DolibarrModules
//ODT template for project
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/projects/template_project.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/projects';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/projects';
$dest = $dirodt.'/template_project.odt';
if (file_exists($src) && !file_exists($dest)) {
@@ -396,7 +396,7 @@ class modProjet extends DolibarrModules
//ODT template for tasks
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/tasks/template_task_summary.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/tasks';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/tasks';
$dest = $dirodt.'/template_task_summary.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modReception.class.php b/htdocs/core/modules/modReception.class.php
index 7c6b4f62cc2..560ab4383f7 100644
--- a/htdocs/core/modules/modReception.class.php
+++ b/htdocs/core/modules/modReception.class.php
@@ -92,7 +92,7 @@ class modReception extends DolibarrModules
$this->const[$r][0] = "RECEPTION_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/receptions";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/receptions";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
$r++;
@@ -267,7 +267,7 @@ class modReception extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/reception/template_reception.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/reception';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/reception';
$dest = $dirodt.'/template_reception.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modSociete.class.php b/htdocs/core/modules/modSociete.class.php
index 3af5d8edd79..fdfb7f17111 100644
--- a/htdocs/core/modules/modSociete.class.php
+++ b/htdocs/core/modules/modSociete.class.php
@@ -102,7 +102,7 @@ class modSociete extends DolibarrModules
$this->const[$r][0] = "COMPANY_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/thirdparties";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/thirdparties";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
$r++;
@@ -1034,7 +1034,7 @@ class modSociete extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/thirdparties/template_thirdparty.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/thirdparties';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/thirdparties';
$dest = $dirodt.'/template_thirdparty.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modStock.class.php b/htdocs/core/modules/modStock.class.php
index 2a49109cece..6f7aef10ebb 100644
--- a/htdocs/core/modules/modStock.class.php
+++ b/htdocs/core/modules/modStock.class.php
@@ -97,14 +97,14 @@ class modStock extends DolibarrModules
$r++;
$this->const[$r][0] = "STOCK_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/stocks";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/stocks";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
$r++;
$this->const[$r][0] = "MOUVEMENT_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/stocks/movements";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/stocks/movements";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
@@ -554,7 +554,7 @@ class modStock extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/stocks/template_warehouse.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/stocks';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/stocks';
$dest = $dirodt.'/template_warehouse.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modSupplierProposal.class.php b/htdocs/core/modules/modSupplierProposal.class.php
index 52d0dd1f546..7a379c29665 100644
--- a/htdocs/core/modules/modSupplierProposal.class.php
+++ b/htdocs/core/modules/modSupplierProposal.class.php
@@ -93,7 +93,7 @@ class modSupplierProposal extends DolibarrModules
$this->const[$r][0] = "SUPPLIER_PROPOSAL_ADDON_PDF_ODT_PATH";
$this->const[$r][1] = "chaine";
- $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/supplier_proposals";
+ $this->const[$r][2] = "DOL_DATA_ROOT".($conf->entity > 1 ? '/'.$conf->entity : '')."/doctemplates/supplier_proposals";
$this->const[$r][3] = "";
$this->const[$r][4] = 0;
@@ -164,7 +164,7 @@ class modSupplierProposal extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/supplier_proposals/template_supplier_proposal.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/supplier_proposals';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/supplier_proposals';
$dest = $dirodt.'/template_supplier_proposal.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/modules/modTicket.class.php b/htdocs/core/modules/modTicket.class.php
index a4a57221eb3..f97418018c5 100644
--- a/htdocs/core/modules/modTicket.class.php
+++ b/htdocs/core/modules/modTicket.class.php
@@ -110,7 +110,7 @@ class modTicket extends DolibarrModules
$this->const = array(
1 => array('TICKET_ENABLE_PUBLIC_INTERFACE', 'chaine', '0', 'Enable ticket public interface', 0),
2 => array('TICKET_ADDON', 'chaine', 'mod_ticket_simple', 'Ticket ref module', 0),
- 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0),
+ 3 => array('TICKET_ADDON_PDF_ODT_PATH', 'chaine', 'DOL_DATA_ROOT'.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/tickets', 'Ticket templates ODT/ODS directory for templates', 0),
4 => array('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND', 'chaine', 0, 'Automatically mark ticket as read when created from backend', 0),
5 => array('TICKET_DELAY_BEFORE_FIRST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time before a first answer to a ticket (in hours). Display a warning in tickets list if not respected.', 0),
6 => array('TICKET_DELAY_SINCE_LAST_RESPONSE', 'chaine', '0', 'Maximum wanted elapsed time between two answers on the same ticket (in hours). Display a warning in tickets list if not respected.', 0),
@@ -414,7 +414,7 @@ class modTicket extends DolibarrModules
//ODT template
$src = DOL_DOCUMENT_ROOT.'/install/doctemplates/tickets/template_ticket.odt';
- $dirodt = DOL_DATA_ROOT.'/doctemplates/tickets';
+ $dirodt = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/doctemplates/tickets';
$dest = $dirodt.'/template_ticket.odt';
if (file_exists($src) && !file_exists($dest)) {
diff --git a/htdocs/core/tpl/formlayoutai.tpl.php b/htdocs/core/tpl/formlayoutai.tpl.php
index 944f6d5722b..ba1e1412fb7 100644
--- a/htdocs/core/tpl/formlayoutai.tpl.php
+++ b/htdocs/core/tpl/formlayoutai.tpl.php
@@ -15,26 +15,22 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
.
- *
- * Need to have the following variables defined:
- * $conf
- * $formmail
- * $formwebsite (optional)
- * $showlinktolayout='emailing', 'email', 'websitepage', ...
- * $showlinktolayoutlabel='...'
- * $showlinktoai ('' or 'textgeneration', 'textgenerationemail', 'textgenerationwebpage', ...)
- * $showlinktoailabel='...'
- * $htmlname
*/
-/**
+
+ /**
* @var Conf $conf
- * @var ?FormMail $formmail
- * @var ?FormWebsite $formwebsite
- * @var string $htmlname
- * @var string $showlinktolayout
- * @var string $showlinktolayoutlabel
+ * @var ?FormMail $formmail
+ * @var ?FormWebsite $formwebsite
+ * @var string $htmlname
+ * @var string $showlinktolayout 'emailing', 'email', 'websitepage', ...
+ * @var string $showlinktolayoutlabel '...'
+ * @var string $showlinktoai '' or 'textgeneration', 'textgenerationemail', 'textgenerationwebpage', ...
+ * @var string $showlinktoailabel '...'
+ * @var string $htmlname
+ * @var ?string $out
*/
-// Protection to avoid direct call of template
+
+//Protection to avoid direct call of template
if (empty($conf) || !is_object($conf)) {
print "Error, template page can't be called as URL";
exit(1);
@@ -59,11 +55,12 @@ if (empty($htmlname)) {
@phan-var-force ?string $out
';
-if (!isset($out)) {
+if (!isset($out)) { // Init to empty string if not defined
$out = '';
}
+
// Add link to add layout
-if ($showlinktolayout) {
+if ($showlinktolayout) { // May be set only if MAIN_EMAIL_USE_LAYOUT is set
$out .= '
';
$out .= img_picto($showlinktolayoutlabel, 'layout', 'class="paddingrightonly"');
$out .= $showlinktolayoutlabel.'...';
@@ -72,10 +69,10 @@ if ($showlinktolayout) {
$out .= '