dolibarr  20.0.0-beta
html.formticket.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2013-2015 Jean-François FERRY <hello@librethic.io>
3  * Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr>
4  * Copyright (C) 2019-2024 Frédéric France <frederic.france@free.fr>
5  * Copyright (C) 2021 Juanjo Menent <jmenent@2byte.es>
6  * Copyright (C) 2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
7  * Copyright (C) 2023 Charlene Benke <charlene.r@patas-monkey.com>
8  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9  * Copyright (C) 2024 Irvine FLEITH <irvine.fleith@atm-consulting.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
31 require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
32 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
33 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
34 
35 if (!class_exists('FormCompany')) {
36  include DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
37 }
38 
48 {
52  public $db;
53 
57  public $track_id;
58 
62  public $trackid;
63 
67  public $fk_user_create;
68 
69  public $message;
70  public $topic_title;
71 
72  public $action;
73 
74  public $withtopic;
75  public $withemail;
76 
80  public $withsubstit;
81 
82  public $withfile;
83  public $withfilereadonly;
84 
85  public $backtopage;
86 
87  public $ispublic; // to show information or not into public form
88 
89  public $withtitletopic;
90  public $withtopicreadonly;
91  public $withreadid;
92 
93  public $withcompany; // to show company drop-down list
94  public $withfromsocid;
95  public $withfromcontactid;
96  public $withnotifytiersatcreate;
97  public $withusercreate; // to show name of creating user in form
98  public $withcreatereadonly;
99 
103  public $withextrafields;
104 
105  public $withref; // to show ref field
106  public $withcancel;
107 
108  public $type_code;
109  public $category_code;
110  public $severity_code;
111 
112 
117  public $substit = array();
118  public $param = array();
119 
123  public $error;
124  public $errors = array();
125 
126 
132  public function __construct($db)
133  {
134  global $conf;
135 
136  $this->db = $db;
137 
138  $this->action = 'add';
139 
140  $this->withcompany = !getDolGlobalInt("TICKETS_NO_COMPANY_ON_FORM") && isModEnabled("societe");
141  $this->withfromsocid = 0;
142  $this->withfromcontactid = 0;
143  $this->withreadid = 0;
144  //$this->withtitletopic='';
145  $this->withnotifytiersatcreate = 0;
146  $this->withusercreate = 1;
147  $this->withcreatereadonly = 1;
148  $this->withemail = 0;
149  $this->withref = 0;
150  $this->withextrafields = 0; // to show extrafields or not
151  //$this->withtopicreadonly=0;
152  }
153 
162  public static function checkRequiredFields(array $fields, int &$errors)
163  {
164  global $langs;
165 
166  foreach ($fields as $field => $type) {
167  if (!GETPOST($field, $type['check'])) {
168  $errors++;
169  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities($type['langs'])), null, 'errors');
170  }
171  }
172  }
173 
185  public function showForm($withdolfichehead = 0, $mode = 'edit', $public = 0, Contact $with_contact = null, $action = '', Ticket $object = null)
186  {
187  global $conf, $langs, $user, $hookmanager;
188 
189  // Load translation files required by the page
190  $langs->loadLangs(array('other', 'mails', 'ticket'));
191 
192  if ($mode == 'create') {
193  $ref = GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : '';
194  $type_code = GETPOSTISSET('type_code') ? GETPOST('type_code', 'alpha') : '';
195  $category_code = GETPOSTISSET('category_code') ? GETPOST('category_code', 'alpha') : '';
196  $severity_code = GETPOSTISSET('severity_code') ? GETPOST('severity_code', 'alpha') : '';
197  $subject = GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : '';
198  $email = GETPOSTISSET('email') ? GETPOST('email', 'alpha') : '';
199  $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : '';
200  $projectid = GETPOSTISSET('projectid') ? GETPOST('projectid', 'int') : '';
201  $user_assign = GETPOSTISSET('fk_user_assign') ? GETPOSTINT('fk_user_assign') : $this->fk_user_create;
202  } else {
203  $ref = GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $object->ref;
204  $type_code = GETPOSTISSET('type_code') ? GETPOST('type_code', 'alpha') : $object->type_code;
205  $category_code = GETPOSTISSET('category_code') ? GETPOST('category_code', 'alpha') : $object->category_code;
206  $severity_code = GETPOSTISSET('severity_code') ? GETPOST('severity_code', 'alpha') : $object->severity_code;
207  $subject = GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : $object->subject;
208  $email = GETPOSTISSET('email') ? GETPOST('email', 'alpha') : $object->email_from;
209  $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : $object->message;
210  $projectid = GETPOSTISSET('projectid') ? GETPOST('projectid', 'int') : $object->fk_project;
211  $user_assign = GETPOSTISSET('fk_user_assign') ? GETPOSTINT('fk_user_assign') : $object->fk_user_assign;
212  }
213 
214  $form = new Form($this->db);
215  $formcompany = new FormCompany($this->db);
216  $ticketstatic = new Ticket($this->db);
217 
218  $soc = new Societe($this->db);
219  if (!empty($this->withfromsocid) && $this->withfromsocid > 0) {
220  $soc->fetch($this->withfromsocid);
221  }
222 
223  $ticketstat = new Ticket($this->db);
224 
225  $extrafields = new ExtraFields($this->db);
226  $extrafields->fetch_name_optionals_label($ticketstat->table_element);
227 
228  print "\n<!-- Begin form TICKET -->\n";
229 
230  if ($withdolfichehead) {
231  print dol_get_fiche_head(null, 'card', '', 0, '');
232  }
233 
234  print '<form method="POST" '.($withdolfichehead ? '' : 'style="margin-bottom: 30px;" ').'name="ticket" id="form_create_ticket" enctype="multipart/form-data" action="'.(!empty($this->param["returnurl"]) ? $this->param["returnurl"] : $_SERVER['PHP_SELF']).'">';
235  print '<input type="hidden" name="token" value="'.newToken().'">';
236  print '<input type="hidden" name="action" value="'.$this->action.'">';
237  if (!empty($object->id)) print '<input type="hidden" name="id" value="'. $object->id .'">';
238  print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
239  foreach ($this->param as $key => $value) {
240  print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
241  }
242  print '<input type="hidden" name="fk_user_create" value="'.$this->fk_user_create.'">';
243 
244  print '<table class="border centpercent">';
245 
246  if ($this->withref) {
247  // Ref
248  $defaultref = $ticketstat->getDefaultRef();
249 
250  if ($mode == 'edit') {
251  $defaultref = $object->ref;
252  }
253  print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("Ref").'</span></td><td>';
254  print '<input type="text" name="ref" value="'.dol_escape_htmltag($defaultref).'">';
255  print '</td></tr>';
256  }
257 
258  // TITLE
259  if ($this->withemail) {
260  print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">'.$langs->trans("Email").'</span></label></td><td>';
261  print '<input class="text minwidth200" id="email" name="email" value="'.$email.'" autofocus>';
262  print '</td></tr>';
263 
264  if ($with_contact) {
265  // contact search and result
266  $html_contact_search = '';
267  $html_contact_search .= '<tr id="contact_search_line">';
268  $html_contact_search .= '<td class="titlefield">';
269  $html_contact_search .= '<label for="contact"><span class="fieldrequired">' . $langs->trans('Contact') . '</span></label>';
270  $html_contact_search .= '<input type="hidden" id="contact_id" name="contact_id" value="" />';
271  $html_contact_search .= '</td>';
272  $html_contact_search .= '<td id="contact_search_result"></td>';
273  $html_contact_search .= '</tr>';
274  print $html_contact_search;
275  // contact lastname
276  $html_contact_lastname = '';
277  $html_contact_lastname .= '<tr id="contact_lastname_line" class="contact_field"><td class="titlefield"><label for="contact_lastname"><span class="fieldrequired">' . $langs->trans('Lastname') . '</span></label></td><td>';
278  $html_contact_lastname .= '<input type="text" id="contact_lastname" name="contact_lastname" value="' . dol_escape_htmltag(GETPOSTISSET('contact_lastname') ? GETPOST('contact_lastname', 'alphanohtml') : '') . '" />';
279  $html_contact_lastname .= '</td></tr>';
280  print $html_contact_lastname;
281  // contact firstname
282  $html_contact_firstname = '';
283  $html_contact_firstname .= '<tr id="contact_firstname_line" class="contact_field"><td class="titlefield"><label for="contact_firstname"><span class="fieldrequired">' . $langs->trans('Firstname') . '</span></label></td><td>';
284  $html_contact_firstname .= '<input type="text" id="contact_firstname" name="contact_firstname" value="' . dol_escape_htmltag(GETPOSTISSET('contact_firstname') ? GETPOST('contact_firstname', 'alphanohtml') : '') . '" />';
285  $html_contact_firstname .= '</td></tr>';
286  print $html_contact_firstname;
287  // company name
288  $html_company_name = '';
289  $html_company_name .= '<tr id="contact_company_name_line" class="contact_field"><td><label for="company_name"><span>' . $langs->trans('Company') . '</span></label></td><td>';
290  $html_company_name .= '<input type="text" id="company_name" name="company_name" value="' . dol_escape_htmltag(GETPOSTISSET('company_name') ? GETPOST('company_name', 'alphanohtml') : '') . '" />';
291  $html_company_name .= '</td></tr>';
292  print $html_company_name;
293  // contact phone
294  $html_contact_phone = '';
295  $html_contact_phone .= '<tr id="contact_phone_line" class="contact_field"><td><label for="contact_phone"><span>' . $langs->trans('Phone') . '</span></label></td><td>';
296  $html_contact_phone .= '<input type="text" id="contact_phone" name="contact_phone" value="' . dol_escape_htmltag(GETPOSTISSET('contact_phone') ? GETPOST('contact_phone', 'alphanohtml') : '') . '" />';
297  $html_contact_phone .= '</td></tr>';
298  print $html_contact_phone;
299 
300  // search contact form email
301  $langs->load('errors');
302  print '<script nonce="'.getNonce().'" type="text/javascript">
303  jQuery(document).ready(function() {
304  var contact = jQuery.parseJSON("'.dol_escape_js(json_encode($with_contact), 2).'");
305  jQuery("#contact_search_line").hide();
306  if (contact) {
307  if (contact.id > 0) {
308  jQuery("#contact_search_line").show();
309  jQuery("#contact_id").val(contact.id);
310  jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
311  jQuery(".contact_field").hide();
312  } else {
313  jQuery(".contact_field").show();
314  }
315  }
316 
317  jQuery("#email").change(function() {
318  jQuery("#contact_search_line").show();
319  jQuery("#contact_search_result").html("'.dol_escape_js($langs->trans('Select2SearchInProgress')).'");
320  jQuery("#contact_id").val("");
321  jQuery("#contact_lastname").val("");
322  jQuery("#contact_firstname").val("");
323  jQuery("#company_name").val("");
324  jQuery("#contact_phone").val("");
325 
326  jQuery.getJSON(
327  "'.dol_escape_js(dol_buildpath('/public/ticket/ajax/ajax.php', 1)).'",
328  {
329  action: "getContacts",
330  email: jQuery("#email").val()
331  },
332  function(response) {
333  if (response.error) {
334  jQuery("#contact_search_result").html("<span class=\"error\">"+response.error+"</span>");
335  } else {
336  var contact_list = response.contacts;
337  if (contact_list.length == 1) {
338  var contact = contact_list[0];
339  jQuery("#contact_id").val(contact.id);
340  jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
341  jQuery(".contact_field").hide();
342  } else if (contact_list.length <= 0) {
343  jQuery("#contact_search_line").hide();
344  jQuery(".contact_field").show();
345  }
346  }
347  }
348  ).fail(function(jqxhr, textStatus, error) {
349  var error_msg = "'.dol_escape_js($langs->trans('ErrorAjaxRequestFailed')).'"+" ["+textStatus+"] : "+error;
350  jQuery("#contact_search_result").html("<span class=\"error\">"+error_msg+"</span>");
351  });
352  });
353  });
354  </script>';
355  }
356  }
357 
358  // If ticket created from another object
359  $subelement = '';
360  if (isset($this->param['origin']) && $this->param['originid'] > 0) {
361  // Parse element/subelement (ex: project_task)
362  $element = $subelement = $this->param['origin'];
363  $regs = array();
364  if (preg_match('/^([^_]+)_([^_]+)/i', $this->param['origin'], $regs)) {
365  $element = $regs[1];
366  $subelement = $regs[2];
367  }
368 
369  dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
370  $classname = ucfirst($subelement);
371  $objectsrc = new $classname($this->db);
372  $objectsrc->fetch(GETPOSTINT('originid'));
373 
374  if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
375  $objectsrc->fetch_lines();
376  }
377 
378  $objectsrc->fetch_thirdparty();
379  $newclassname = $classname;
380  print '<tr><td>'.$langs->trans($newclassname).'</td><td colspan="2"><input name="'.$subelement.'id" value="'.GETPOST('originid').'" type="hidden" />'.$objectsrc->getNomUrl(1).'</td></tr>';
381  }
382 
383  // Type of Ticket
384  print '<tr><td class="titlefield"><span class="fieldrequired"><label for="selecttype_code">'.$langs->trans("TicketTypeRequest").'</span></label></td><td>';
385  $this->selectTypesTickets($type_code, 'type_code', '', 2, 1, 0, 0, 'minwidth200');
386  print '</td></tr>';
387 
388  // Group => Category
389  print '<tr><td><span class="fieldrequired"><label for="selectcategory_code">'.$langs->trans("TicketCategory").'</span></label></td><td>';
390  $filter = '';
391  if ($public) {
392  $filter = 'public=1';
393  }
394  $this->selectGroupTickets($category_code, 'category_code', $filter, 2, 1, 0, 0, 'minwidth200');
395  print '</td></tr>';
396 
397  // Severity => Priority
398  print '<tr><td><span class="fieldrequired"><label for="selectseverity_code">'.$langs->trans("TicketSeverity").'</span></label></td><td>';
399  $this->selectSeveritiesTickets($severity_code, 'severity_code', '', 2, 1);
400  print '</td></tr>';
401 
402  if (isModEnabled('knowledgemanagement')) {
403  // KM Articles
404  print '<tr id="KWwithajax" class="hidden"><td></td></tr>';
405  print '<!-- Script to manage change of ticket group -->
406  <script nonce="'.getNonce().'">
407  jQuery(document).ready(function() {
408  function groupticketchange() {
409  console.log("We called groupticketchange, so we try to load list KM linked to event");
410  $("#KWwithajax").html("");
411  idgroupticket = $("#selectcategory_code").val();
412 
413  console.log("We have selected id="+idgroupticket);
414 
415  if (idgroupticket != "") {
416  $.ajax({ url: \''.DOL_URL_ROOT.'/core/ajax/fetchKnowledgeRecord.php\',
417  data: { action: \'getKnowledgeRecord\', idticketgroup: idgroupticket, token: \''.newToken().'\', lang:\''.$langs->defaultlang.'\', public:'.($public).' },
418  type: \'GET\',
419  success: function(response) {
420  var urllist = \'\';
421  console.log("We received response "+response);
422  if (typeof response == "object") {
423  console.log("response is already type object, no need to parse it");
424  } else {
425  console.log("response is type "+(typeof response));
426  response = JSON.parse(response);
427  }
428  for (key in response) {
429  answer = response[key].answer;
430  urllist += \'<li><a href="#" title="\'+response[key].title+\'" class="button_KMpopup" data-html="\'+answer+\'">\' +response[key].title+\'</a></li>\';
431  }
432  if (urllist != "") {
433  $("#KWwithajax").html(\'<td>'.$langs->trans("KMFoundForTicketGroup").'</td><td><ul>\'+urllist+\'</ul></td>\');
434  $("#KWwithajax").show();
435  $(".button_KMpopup").on("click",function(){
436  console.log("Open popup with jQuery(...).dialog() with KM article")
437  var $dialog = $("<div></div>").html($(this).attr("data-html"))
438  .dialog({
439  autoOpen: false,
440  modal: true,
441  height: (window.innerHeight - 150),
442  width: "80%",
443  title: $(this).attr("title"),
444  });
445  $dialog.dialog("open");
446  console.log($dialog);
447  })
448  }
449  },
450  error : function(output) {
451  console.error("Error on Fetch of KM articles");
452  },
453  });
454  }
455  };
456  $("#selectcategory_code").on("change",function() { groupticketchange(); });
457  if ($("#selectcategory_code").val() != "") {
458  groupticketchange();
459  }
460  });
461  </script>'."\n";
462  }
463 
464  // Subject
465  if ($this->withtitletopic) {
466  print '<tr><td><label for="subject"><span class="fieldrequired">'.$langs->trans("Subject").'</span></label></td><td>';
467  // Answer to a ticket : display of the thread title in readonly
468  if ($this->withtopicreadonly) {
469  print $langs->trans('SubjectAnswerToTicket').' '.$this->topic_title;
470  } else {
471  if (isset($this->withreadid) && $this->withreadid > 0) {
472  $subject = $langs->trans('SubjectAnswerToTicket').' '.$this->withreadid.' : '.$this->topic_title;
473  }
474  print '<input class="text minwidth500" id="subject" name="subject" value="'.$subject.'"'.(empty($this->withemail) ? ' autofocus' : '').' />';
475  }
476  print '</td></tr>';
477  }
478 
479  // MESSAGE
480  print '<tr><td><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span></label></td><td>';
481 
482  // If public form, display more information
483  $toolbarname = 'dolibarr_notes';
484  if ($this->ispublic) {
485  $toolbarname = 'dolibarr_details';
486  print '<div class="warning hideonsmartphone">'.(getDolGlobalString("TICKET_PUBLIC_TEXT_HELP_MESSAGE", $langs->trans('TicketPublicPleaseBeAccuratelyDescribe'))).'</div>';
487  }
488  include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
489  $uselocalbrowser = true;
490  $doleditor = new DolEditor('message', $msg, '100%', 230, $toolbarname, 'In', true, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_8, '90%');
491  $doleditor->Create();
492  print '</td></tr>';
493 
494  if ($public && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) {
495  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
496  print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">'.$langs->trans("SecurityCode").'</span></label></td><td>';
497  print '<span class="span-icon-security inline-block">';
498  print '<input id="securitycode" placeholder="'.$langs->trans("SecurityCode").'" class="flat input-icon-security width125" type="text" maxlength="5" name="code" tabindex="3" />';
499  print '</span>';
500  print '<span class="nowrap inline-block">';
501  print '<img class="inline-block valignmiddle" src="'.DOL_URL_ROOT.'/core/antispamimage.php" border="0" width="80" height="32" id="img_securitycode" />';
502  print '<a class="inline-block valignmiddle" href="" tabindex="4" data-role="button">'.img_picto($langs->trans("Refresh"), 'refresh', 'id="captcha_refresh_img"').'</a>';
503  print '</span>';
504  print '</td></tr>';
505  }
506 
507  // Categories
508  if (isModEnabled('category')) {
509  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
510  $cate_arbo = $form->select_all_categories(Categorie::TYPE_TICKET, '', 'parent', 64, 0, 3);
511 
512  if (count($cate_arbo)) {
513  // Categories
514  print '<tr><td class="wordbreak">'.$langs->trans("Categories").'</td><td>';
515  print img_picto('', 'category', 'class="pictofixedwidth"').$form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
516  print "</td></tr>";
517  }
518  }
519 
520  // Attached files
521  if (!empty($this->withfile)) {
522  // Define list of attached files
523  $listofpaths = array();
524  $listofnames = array();
525  $listofmimes = array();
526  if (!empty($_SESSION["listofpaths"])) {
527  $listofpaths = explode(';', $_SESSION["listofpaths"]);
528  }
529 
530  if (!empty($_SESSION["listofnames"])) {
531  $listofnames = explode(';', $_SESSION["listofnames"]);
532  }
533 
534  if (!empty($_SESSION["listofmimes"])) {
535  $listofmimes = explode(';', $_SESSION["listofmimes"]);
536  }
537 
538  $out = '<tr>';
539  $out .= '<td>'.$langs->trans("MailFile").'</td>';
540  $out .= '<td>';
541  // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
542  $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
543  $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
544  $out .= 'jQuery(document).ready(function () {';
545  $out .= ' jQuery(".removedfile").click(function() {';
546  $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
547  $out .= ' });';
548  $out .= '})';
549  $out .= '</script>'."\n";
550  if (count($listofpaths)) {
551  foreach ($listofpaths as $key => $val) {
552  $out .= '<div id="attachfile_'.$key.'">';
553  $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
554  if (!$this->withfilereadonly) {
555  $out .= ' <input type="image" style="border: 0px;" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/delete.png" value="'.($key + 1).'" class="removedfile" id="removedfile_'.$key.'" name="removedfile_'.$key.'" />';
556  }
557  $out .= '<br></div>';
558  }
559  } else {
560  $out .= '<span class="opacitymedium">'.$langs->trans("NoAttachedFiles").'</span><br>';
561  }
562  if ($this->withfile == 2) { // Can add other files
563  $maxfilesizearray = getMaxFileSizeArray();
564  $maxmin = $maxfilesizearray['maxmin'];
565  if ($maxmin > 0) {
566  $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
567  }
568  $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
569  $out .= ' ';
570  $out .= '<input type="submit" class="button smallpaddingimp reposition" id="addfile" name="addfile" value="'.$langs->trans("MailingAddFile").'" />';
571  }
572  $out .= "</td></tr>\n";
573 
574  print $out;
575  }
576 
577  // User of creation
578  if ($this->withusercreate > 0 && $this->fk_user_create) {
579  print '<tr><td class="titlefield">'.$langs->trans("CreatedBy").'</td><td>';
580  $langs->load("users");
581  $fuser = new User($this->db);
582 
583  if ($this->withcreatereadonly) {
584  if ($res = $fuser->fetch($this->fk_user_create)) {
585  print $fuser->getNomUrl(1);
586  }
587  }
588  print ' &nbsp; ';
589  print "</td></tr>\n";
590  }
591 
592  // Customer or supplier
593  if ($this->withcompany) {
594  // force company and contact id for external user
595  if (empty($user->socid)) {
596  // Company
597  print '<tr><td class="titlefield">'.$langs->trans("ThirdParty").'</td><td>';
598  $events = array();
599  $events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
600  print img_picto('', 'company', 'class="paddingright"');
601  print $form->select_company($this->withfromsocid, 'socid', '', 1, 1, '', $events, 0, 'minwidth200');
602  print '</td></tr>';
603  if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
604  $htmlname = 'socid';
605  print '<script nonce="'.getNonce().'" type="text/javascript">
606  $(document).ready(function () {
607  jQuery("#'.$htmlname.'").change(function () {
608  var obj = '.json_encode($events).';
609  $.each(obj, function(key,values) {
610  if (values.method.length) {
611  runJsCodeForEvent'.$htmlname.'(values);
612  }
613  });
614  });
615 
616  function runJsCodeForEvent'.$htmlname.'(obj) {
617  console.log("Run runJsCodeForEvent'.$htmlname.'");
618  var id = $("#'.$htmlname.'").val();
619  var method = obj.method;
620  var url = obj.url;
621  var htmlname = obj.htmlname;
622  var showempty = obj.showempty;
623  $.getJSON(url,
624  {
625  action: method,
626  id: id,
627  htmlname: htmlname,
628  showempty: showempty
629  },
630  function(response) {
631  $.each(obj.params, function(key,action) {
632  if (key.length) {
633  var num = response.num;
634  if (num > 0) {
635  $("#" + key).removeAttr(action);
636  } else {
637  $("#" + key).attr(action, action);
638  }
639  }
640  });
641  $("select#" + htmlname).html(response.value);
642  if (response.num) {
643  var selecthtml_str = response.value;
644  var selecthtml_dom=$.parseHTML(selecthtml_str);
645  if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
646  $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
647  }
648  } else {
649  $("#inputautocomplete"+htmlname).val("");
650  }
651  $("select#" + htmlname).change(); /* Trigger event change */
652  }
653  );
654  }
655  });
656  </script>';
657  }
658  if ($mode == 'create') {
659  // Contact and type
660  print '<tr><td>'.$langs->trans("Contact").'</td><td>';
661  // If no socid, set to -1 to avoid full contacts list
662  $selectedCompany = ($this->withfromsocid > 0) ? $this->withfromsocid : -1;
663  print img_picto('', 'contact', 'class="paddingright"');
664  // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
665  print $form->select_contact($selectedCompany, $this->withfromcontactid, 'contactid', 3, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
666 
667  print ' ';
668  $formcompany->selectTypeContact($ticketstatic, '', 'type', 'external', '', 0, 'maginleftonly');
669  print '</td></tr>';
670  }
671  } else {
672  print '<tr><td class="titlefield"><input type="hidden" name="socid" value="'.$user->socid.'"/></td>';
673  print '<td><input type="hidden" name="contactid" value="'.$user->contact_id.'"/></td>';
674  print '<td><input type="hidden" name="type" value="Z"/></td></tr>';
675  }
676 
677  // Notify thirdparty at creation
678  if (empty($this->ispublic) && $action == 'create') {
679  print '<tr><td><label for="notify_tiers_at_create">'.$langs->trans("TicketNotifyTiersAtCreation").'</label></td><td>';
680  print '<input type="checkbox" id="notify_tiers_at_create" name="notify_tiers_at_create"'.($this->withnotifytiersatcreate ? ' checked="checked"' : '').'>';
681  print '</td></tr>';
682  }
683 
684  // User assigned
685  print '<tr><td>';
686  print $langs->trans("AssignedTo");
687  print '</td><td>';
688  print img_picto('', 'user', 'class="pictofixedwidth"');
689  print $form->select_dolusers($user_assign, 'fk_user_assign', 1);
690  print '</td>';
691  print '</tr>';
692  }
693 
694  if ($subelement != 'project') {
695  if (isModEnabled('project') && !$this->ispublic) {
696  $formproject = new FormProjets($this->db);
697  print '<tr><td><label for="project"><span class="">'.$langs->trans("Project").'</span></label></td><td>';
698  print img_picto('', 'project').$formproject->select_projects(-1, $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
699  print '</td></tr>';
700  }
701  }
702 
703  if ($subelement != 'contract') {
704  if (isModEnabled('contract') && !$this->ispublic) {
705  $langs->load('contracts');
706  $formcontract = new FormContract($this->db);
707  print '<tr><td><label for="contract"><span class="">'.$langs->trans("Contract").'</span></label></td><td>';
708  print img_picto('', 'contract');
709  print $formcontract->select_contract(-1, GETPOSTINT('contactid'), 'contractid', 0, 1, 1, 1);
710  print '</td></tr>';
711  }
712  }
713 
714  // Other attributes
715  $parameters = array();
716  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $ticketstat, $action); // Note that $action and $object may have been modified by hook
717  if (empty($reshook)) {
718  if ($mode == 'create') {
719  print $object->showOptionals($extrafields, 'create');
720  } else {
721  print $object->showOptionals($extrafields, 'edit');
722  }
723  }
724 
725  print '</table>';
726 
727  if ($withdolfichehead) {
728  print dol_get_fiche_end();
729  }
730 
731  print '<br><br>';
732 
733  if ($mode == 'create') {
734  print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "CreateTicket"), ($this->withcancel ? "Cancel" : ""));
735  } else {
736  print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "Save"), ($this->withcancel ? "Cancel" : ""));
737  }
738 
739  /*
740  print '<div class="center">';
741  print '<input type="submit" class="button" name="add" value="'.$langs->trans(($this->withreadid > 0 ? "SendResponse" : "CreateTicket")).'" />';
742  if ($this->withcancel) {
743  print " &nbsp; &nbsp; &nbsp;";
744  print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
745  }
746  print '</div>';
747  */
748 
749  print '<input type="hidden" name="page_y">'."\n";
750 
751  print "</form>\n";
752  print "<!-- End form TICKET -->\n";
753  }
754 
769  public function selectTypesTickets($selected = '', $htmlname = 'tickettype', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $multiselect = 0)
770  {
771  global $langs, $user;
772 
773  $selected = is_array($selected) ? $selected : (!empty($selected) ? explode(',', $selected) : array());
774  $ticketstat = new Ticket($this->db);
775 
776  dol_syslog(get_class($this) . "::select_types_tickets " . implode(';', $selected) . ", " . $htmlname . ", " . $filtertype . ", " . $format . ", " . $multiselect, LOG_DEBUG);
777 
778  $filterarray = array();
779 
780  if ($filtertype != '' && $filtertype != '-1') {
781  $filterarray = explode(',', $filtertype);
782  }
783 
784  $ticketstat->loadCacheTypesTickets();
785 
786  print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.($multiselect ? '[]' : '').'"'.($multiselect ? ' multiple' : '').'>';
787  if ($empty) {
788  print '<option value="">&nbsp;</option>';
789  }
790 
791  if (is_array($ticketstat->cache_types_tickets) && count($ticketstat->cache_types_tickets)) {
792  foreach ($ticketstat->cache_types_tickets as $id => $arraytypes) {
793  // On passe si on a demande de filtrer sur des modes de paiments particuliers
794  if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
795  continue;
796  }
797 
798  // If 'showempty' is enabled we discard empty line because an empty line has already been output.
799  if ($empty && empty($arraytypes['code'])) {
800  continue;
801  }
802 
803  if ($format == 0) {
804  print '<option value="'.$id.'"';
805  }
806 
807  if ($format == 1) {
808  print '<option value="'.$arraytypes['code'].'"';
809  }
810 
811  if ($format == 2) {
812  print '<option value="'.$arraytypes['code'].'"';
813  }
814 
815  if ($format == 3) {
816  print '<option value="'.$id.'"';
817  }
818 
819  // If text is selected, we compare with code, otherwise with id
820  if (in_array($arraytypes['code'], $selected)) {
821  print ' selected="selected"';
822  } elseif (in_array($id, $selected)) {
823  print ' selected="selected"';
824  } elseif ($arraytypes['use_default'] == "1" && !$selected && !$empty) {
825  print ' selected="selected"';
826  }
827 
828  print '>';
829 
830  $value = '&nbsp;';
831  if ($format == 0) {
832  $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
833  } elseif ($format == 1) {
834  $value = $arraytypes['code'];
835  } elseif ($format == 2) {
836  $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
837  } elseif ($format == 3) {
838  $value = $arraytypes['code'];
839  }
840 
841  print $value ? $value : '&nbsp;';
842  print '</option>';
843  }
844  }
845  print '</select>';
846  if (isset($user->admin) && $user->admin && !$noadmininfo) {
847  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
848  }
849 
850  print ajax_combobox('select'.$htmlname);
851  }
852 
868  public function selectGroupTickets($selected = '', $htmlname = 'ticketcategory', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $use_multilevel = 0, $outputlangs = null)
869  {
870  global $conf, $langs, $user;
871 
872  dol_syslog(get_class($this)."::selectCategoryTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
873 
874  if (is_null($outputlangs) || !is_object($outputlangs)) {
875  $outputlangs = $langs;
876  }
877  $outputlangs->load("ticket");
878 
879  $publicgroups = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
880 
881  $ticketstat = new Ticket($this->db);
882  $ticketstat->loadCacheCategoriesTickets($publicgroups ? 1 : -1); // get list of active ticket groups
883 
884  if ($use_multilevel <= 0) {
885  print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
886  if ($empty) {
887  print '<option value="">&nbsp;</option>';
888  }
889 
890  if (is_array($ticketstat->cache_category_tickets) && count($ticketstat->cache_category_tickets)) {
891  foreach ($ticketstat->cache_category_tickets as $id => $arraycategories) {
892  // Exclude some record
893  if ($publicgroups) {
894  if (empty($arraycategories['public'])) {
895  continue;
896  }
897  }
898 
899  // We discard empty line if showempty is on because an empty line has already been output.
900  if ($empty && empty($arraycategories['code'])) {
901  continue;
902  }
903 
904  $label = ($arraycategories['label'] != '-' ? $arraycategories['label'] : '');
905  if ($outputlangs->trans("TicketCategoryShort".$arraycategories['code']) != "TicketCategoryShort".$arraycategories['code']) {
906  $label = $outputlangs->trans("TicketCategoryShort".$arraycategories['code']);
907  } elseif ($outputlangs->trans($arraycategories['code']) != $arraycategories['code']) {
908  $label = $outputlangs->trans($arraycategories['code']);
909  }
910 
911  if ($format == 0) {
912  print '<option value="'.$id.'"';
913  }
914 
915  if ($format == 1) {
916  print '<option value="'.$arraycategories['code'].'"';
917  }
918 
919  if ($format == 2) {
920  print '<option value="'.$arraycategories['code'].'"';
921  }
922 
923  if ($format == 3) {
924  print '<option value="'.$id.'"';
925  }
926 
927  // If selected is text, we compare with code, otherwise with id
928  if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arraycategories['code']) {
929  print ' selected="selected"';
930  } elseif (isset($selected) && $selected == $id) {
931  print ' selected="selected"';
932  } elseif ($arraycategories['use_default'] == "1" && !$selected && !$empty) {
933  print ' selected="selected"';
934  } elseif (count($ticketstat->cache_category_tickets) == 1) {
935  print ' selected="selected"';
936  }
937 
938  print '>';
939 
940  $value = '';
941  if ($format == 0) {
942  $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
943  }
944 
945  if ($format == 1) {
946  $value = $arraycategories['code'];
947  }
948 
949  if ($format == 2) {
950  $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
951  }
952 
953  if ($format == 3) {
954  $value = $arraycategories['code'];
955  }
956 
957  print $value ? $value : '&nbsp;';
958  print '</option>';
959  }
960  }
961  print '</select>';
962  if (isset($user->admin) && $user->admin && !$noadmininfo) {
963  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
964  }
965 
966  print ajax_combobox('select'.$htmlname);
967  } elseif ($htmlname != '') {
968  $selectedgroups = array();
969  $groupvalue = "";
970  $groupticket = GETPOST($htmlname, 'aZ09');
971  $child_id = GETPOST($htmlname.'_child_id', 'aZ09') ? GETPOST($htmlname.'_child_id', 'aZ09') : 0;
972  if (!empty($groupticket)) {
973  $tmpgroupticket = $groupticket;
974  $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code";
975  $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc WHERE ctc.code = '".$this->db->escape($tmpgroupticket)."'";
976  $resql = $this->db->query($sql);
977  if ($resql) {
978  $obj = $this->db->fetch_object($resql);
979  $selectedgroups[] = $obj->code;
980  while ($obj->fk_parent > 0) {
981  $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code FROM ".$this->db->prefix()."c_ticket_category as ctc WHERE ctc.rowid ='".$this->db->escape($obj->fk_parent)."'";
982  $resql = $this->db->query($sql);
983  if ($resql) {
984  $obj = $this->db->fetch_object($resql);
985  $selectedgroups[] = $obj->code;
986  }
987  }
988  }
989  }
990 
991  $arrayidused = array();
992  $arrayidusedconcat = array();
993  $arraycodenotparent = array();
994  $arraycodenotparent[] = "";
995 
996  $stringtoprint = '<span class="supportemailfield bold">'.$langs->trans("GroupOfTicket").'</span> ';
997  $stringtoprint .= '<select id="'.$htmlname.'" class="minwidth500" child_id="0">';
998  $stringtoprint .= '<option value="">&nbsp;</option>';
999 
1000  $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ";
1001  $sql .= $this->db->ifsql("ctc.rowid NOT IN (SELECT ctcfather.rowid FROM ".MAIN_DB_PREFIX."c_ticket_category as ctcfather JOIN ".MAIN_DB_PREFIX."c_ticket_category as ctcjoin ON ctcfather.rowid = ctcjoin.fk_parent WHERE ctcjoin.active > 0)", "'NOTPARENT'", "'PARENT'")." as isparent";
1002  $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
1003  $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
1004  if ($filtertype == 'public=1') {
1005  $sql .= " AND ctc.public = 1";
1006  }
1007  $sql .= " AND ctc.fk_parent = 0";
1008  $sql .= $this->db->order('ctc.pos', 'ASC');
1009 
1010  $resql = $this->db->query($sql);
1011  if ($resql) {
1012  $num_rows_level0 = $this->db->num_rows($resql);
1013  $i = 0;
1014  while ($i < $num_rows_level0) {
1015  $obj = $this->db->fetch_object($resql);
1016  if ($obj) {
1017  $label = ($obj->label != '-' ? $obj->label : '');
1018  if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
1019  $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
1020  } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1021  $label = $outputlangs->trans($obj->code);
1022  }
1023 
1024  $grouprowid = $obj->rowid;
1025  $groupvalue = $obj->code;
1026  $grouplabel = $label;
1027 
1028  $isparent = $obj->isparent;
1029  if (is_array($selectedgroups)) {
1030  $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1031  } else {
1032  $iselected = $groupticket == $obj->code ? 'selected' : '';
1033  }
1034  $stringtoprint .= '<option '.$iselected.' class="'.$htmlname.dol_escape_htmltag($grouprowid).'" value="'.dol_escape_htmltag($groupvalue).'" data-html="'.dol_escape_htmltag($grouplabel).'">'.dol_escape_htmltag($grouplabel).'</option>';
1035  if ($isparent == 'NOTPARENT') {
1036  $arraycodenotparent[] = $groupvalue;
1037  }
1038  $arrayidused[] = $grouprowid;
1039  $arrayidusedconcat[] = $grouprowid;
1040  }
1041  $i++;
1042  }
1043  } else {
1044  dol_print_error($this->db);
1045  }
1046  if (count($arrayidused) == 1) {
1047  return '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.dol_escape_htmltag($groupvalue).'">';
1048  } else {
1049  $stringtoprint .= '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'_select" class="maxwidth500 minwidth400" value="'.GETPOST($htmlname).'">';
1050  $stringtoprint .= '<input type="hidden" name="'.$htmlname.'_child_id" id="'.$htmlname.'_select_child_id" class="maxwidth500 minwidth400" '.GETPOST($htmlname).' value="'.GETPOST($htmlname."_child_id").'">';
1051  }
1052  $stringtoprint .= '</select>&nbsp;';
1053 
1054  $levelid = 1; // The first combobox
1055  while ($levelid <= $use_multilevel) { // Loop to take the child of the combo
1056  $tabscript = array();
1057  $stringtoprint .= '<select id="'.$htmlname.'_child_'.$levelid.'" class="maxwidth500 minwidth400 groupticketchild" child_id="'.$levelid.'">';
1058  $stringtoprint .= '<option value="">&nbsp;</option>';
1059 
1060  $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ctcjoin.code as codefather";
1061  $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
1062  $sql .= " JOIN ".$this->db->prefix()."c_ticket_category as ctcjoin ON ctc.fk_parent = ctcjoin.rowid";
1063  $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
1064  $sql .= " AND ctc.rowid NOT IN (".$this->db->sanitize(implode(',', $arrayidusedconcat)).")";
1065 
1066  if ($filtertype == 'public=1') {
1067  $sql .= " AND ctc.public = 1";
1068  }
1069  // Add a test to take only record that are direct child
1070  if (!empty($arrayidused)) {
1071  $sql .= " AND ctc.fk_parent IN ( ";
1072  foreach ($arrayidused as $idused) {
1073  $sql .= $idused.", ";
1074  }
1075  $sql = substr($sql, 0, -2);
1076  $sql .= ")";
1077  }
1078  $sql .= $this->db->order('ctc.pos', 'ASC');
1079 
1080  $resql = $this->db->query($sql);
1081  if ($resql) {
1082  $num_rows = $this->db->num_rows($resql);
1083  $i = 0;
1084  $arrayidused = array();
1085  while ($i < $num_rows) {
1086  $obj = $this->db->fetch_object($resql);
1087  if ($obj) {
1088  $label = ($obj->label != '-' ? $obj->label : '');
1089  if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
1090  $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
1091  } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1092  $label = $outputlangs->trans($obj->code);
1093  }
1094 
1095  $grouprowid = $obj->rowid;
1096  $groupvalue = $obj->code;
1097  $grouplabel = $label;
1098  $isparent = $obj->isparent;
1099  $fatherid = $obj->fk_parent;
1100  $arrayidused[] = $grouprowid;
1101  $arrayidusedconcat[] = $grouprowid;
1102  $groupcodefather = $obj->codefather;
1103  if ($isparent == 'NOTPARENT') {
1104  $arraycodenotparent[] = $groupvalue;
1105  }
1106  if (is_array($selectedgroups)) {
1107  $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1108  } else {
1109  $iselected = $groupticket == $obj->code ? 'selected' : '';
1110  }
1111  $stringtoprint .= '<option '.$iselected.' class="'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'" value="'.dol_escape_htmltag($groupvalue).'" data-html="'.dol_escape_htmltag($grouplabel).'">'.dol_escape_htmltag($grouplabel).'</option>';
1112  if (empty($tabscript[$groupcodefather])) {
1113  $tabscript[$groupcodefather] = 'if ($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").val() == "'.dol_escape_js($groupcodefather).'"){
1114  $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").show()
1115  console.log("We show child tickets of '.$groupcodefather.' group ticket")
1116  }else{
1117  $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").hide()
1118  console.log("We hide child tickets of '.$groupcodefather.' group ticket")
1119  }';
1120  }
1121  }
1122  $i++;
1123  }
1124  } else {
1125  dol_print_error($this->db);
1126  }
1127  $stringtoprint .= '</select>';
1128 
1129  $stringtoprint .= '<script nonce="'.getNonce().'">';
1130  $stringtoprint .= 'arraynotparents = '.json_encode($arraycodenotparent).';'; // when the last visible combo list is number x, this is the array of group
1131  $stringtoprint .= 'if (arraynotparents.includes($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").val())){
1132  console.log("'.$htmlname.'_child_'.$levelid.'")
1133  if($("#'.$htmlname.'_child_'.$levelid.'").val() == "" && ($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")>'.$child_id.')){
1134  $("#'.$htmlname.'_child_'.$levelid.'").hide();
1135  console.log("We hide '.$htmlname.'_child_'.$levelid.' input")
1136  }
1137  if(arraynotparents.includes("'.$groupticket.'") && '.$child_id.' == 0){
1138  $("#ticketcategory_select_child_id").val($("#'.$htmlname.'").attr("child_id"))
1139  $("#ticketcategory_select").val($("#'.$htmlname.'").val()) ;
1140  console.log("We choose '.$htmlname.' input and reload hidden input");
1141  }
1142  }
1143  $("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").change(function() {
1144  child_id = $("#'.$htmlname.($levelid > 1 ? '_child_'.$levelid : '').'").attr("child_id");
1145 
1146  /* Change of value to select this value*/
1147  if (arraynotparents.includes($(this).val()) || $(this).attr("child_id") == '.$use_multilevel.') {
1148  $("#ticketcategory_select").val($(this).val());
1149  $("#ticketcategory_select_child_id").val($(this).attr("child_id")) ;
1150  console.log("We choose to select "+ $(this).val());
1151  }else{
1152  if ($("#'.$htmlname.'_child_'.$levelid.' option").length <= 1) {
1153  $("#ticketcategory_select").val($(this).val());
1154  $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1155  console.log("We choose to select "+ $(this).val() + " and next combo has no item, so we keep this selection");
1156  } else {
1157  console.log("We choose to select "+ $(this).val() + " but next combo has some item, so we clean selected item");
1158  $("#ticketcategory_select").val("");
1159  $("#ticketcategory_select_child_id").val("");
1160  }
1161  }
1162 
1163  console.log("We select a new value into combo child_id="+child_id);
1164 
1165  // Hide all selected box that are child of the one modified
1166  $(".groupticketchild").each(function(){
1167  if ($(this).attr("child_id") > child_id) {
1168  console.log("hide child_id="+$(this).attr("child_id"));
1169  $(this).val("");
1170  $(this).hide();
1171  }
1172  })
1173 
1174  // Now we enable the next combo
1175  $("#'.$htmlname.'_child_'.$levelid.'").val("");
1176  if (!arraynotparents.includes($(this).val()) && $("#'.$htmlname.'_child_'.$levelid.' option").length > 1) {
1177  console.log($("#'.$htmlname.'_child_'.$levelid.' option").length);
1178  $("#'.$htmlname.'_child_'.$levelid.'").show()
1179  } else {
1180  $("#'.$htmlname.'_child_'.$levelid.'").hide()
1181  }
1182  ';
1183  $levelid++;
1184  foreach ($tabscript as $script) {
1185  $stringtoprint .= $script;
1186  }
1187  $stringtoprint .= '})';
1188  $stringtoprint .= '</script>';
1189  }
1190  $stringtoprint .= '<script nonce="'.getNonce().'">';
1191  $stringtoprint .= '$("#'.$htmlname.'_child_'.$use_multilevel.'").change(function() {
1192  $("#ticketcategory_select").val($(this).val());
1193  $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1194  tmpvalselect = $("#ticketcategory_select").val();
1195  if(tmpvalselect == "" && $("#ticketcategory_select_child_id").val() >= 1){
1196  $("#ticketcategory_select_child_id").val($(this).attr("child_id")-1);
1197  }
1198  console.log($("#ticketcategory_select").val());
1199  })';
1200  $stringtoprint .= '</script>';
1201  $stringtoprint .= ajax_combobox($htmlname);
1202 
1203  return $stringtoprint;
1204  }
1205  }
1206 
1220  public function selectSeveritiesTickets($selected = '', $htmlname = 'ticketseverity', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '')
1221  {
1222  global $conf, $langs, $user;
1223 
1224  $ticketstat = new Ticket($this->db);
1225 
1226  dol_syslog(get_class($this)."::selectSeveritiesTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
1227 
1228  $filterarray = array();
1229 
1230  if ($filtertype != '' && $filtertype != '-1') {
1231  $filterarray = explode(',', $filtertype);
1232  }
1233 
1234  $ticketstat->loadCacheSeveritiesTickets();
1235 
1236  print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
1237  if ($empty) {
1238  print '<option value="">&nbsp;</option>';
1239  }
1240 
1241  if (is_array($conf->cache['severity_tickets']) && count($conf->cache['severity_tickets'])) {
1242  foreach ($conf->cache['severity_tickets'] as $id => $arrayseverities) {
1243  // On passe si on a demande de filtrer sur des modes de paiments particuliers
1244  if (count($filterarray) && !in_array($arrayseverities['type'], $filterarray)) {
1245  continue;
1246  }
1247 
1248  // We discard empty line if showempty is on because an empty line has already been output.
1249  if ($empty && empty($arrayseverities['code'])) {
1250  continue;
1251  }
1252 
1253  if ($format == 0) {
1254  print '<option value="'.$id.'"';
1255  }
1256 
1257  if ($format == 1) {
1258  print '<option value="'.$arrayseverities['code'].'"';
1259  }
1260 
1261  if ($format == 2) {
1262  print '<option value="'.$arrayseverities['code'].'"';
1263  }
1264 
1265  if ($format == 3) {
1266  print '<option value="'.$id.'"';
1267  }
1268 
1269  // If text is selected, we compare with code, otherwise with id
1270  if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arrayseverities['code']) {
1271  print ' selected="selected"';
1272  } elseif (isset($selected) && $selected == $id) {
1273  print ' selected="selected"';
1274  } elseif ($arrayseverities['use_default'] == "1" && !$selected && !$empty) {
1275  print ' selected="selected"';
1276  }
1277 
1278  print '>';
1279 
1280  $value = '';
1281  if ($format == 0) {
1282  $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1283  }
1284 
1285  if ($format == 1) {
1286  $value = $arrayseverities['code'];
1287  }
1288 
1289  if ($format == 2) {
1290  $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1291  }
1292 
1293  if ($format == 3) {
1294  $value = $arrayseverities['code'];
1295  }
1296 
1297  print $value ? $value : '&nbsp;';
1298  print '</option>';
1299  }
1300  }
1301  print '</select>';
1302  if (isset($user->admin) && $user->admin && !$noadmininfo) {
1303  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1304  }
1305 
1306  print ajax_combobox('select'.$htmlname);
1307  }
1308 
1309  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1315  public function clear_attached_files()
1316  {
1317  // phpcs:enable
1318  global $conf, $user;
1319  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1320 
1321  // Set tmp user directory
1322  $vardir = $conf->user->dir_output."/".$user->id;
1323  $upload_dir = $vardir.'/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
1324  if (is_dir($upload_dir)) {
1325  dol_delete_dir_recursive($upload_dir);
1326  }
1327 
1328  if (!empty($this->trackid)) { // TODO Always use trackid (ticXXX) instead of track_id (abcd123)
1329  $keytoavoidconflict = '-'.$this->trackid;
1330  } else {
1331  $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id;
1332  }
1333  unset($_SESSION["listofpaths".$keytoavoidconflict]);
1334  unset($_SESSION["listofnames".$keytoavoidconflict]);
1335  unset($_SESSION["listofmimes".$keytoavoidconflict]);
1336  }
1337 
1344  public function showMessageForm($width = '40%')
1345  {
1346  global $conf, $langs, $user, $hookmanager, $form, $mysoc;
1347 
1348  $formmail = new FormMail($this->db);
1349  $addfileaction = 'addfile';
1350 
1351  if (!is_object($form)) {
1352  $form = new Form($this->db);
1353  }
1354 
1355  // Load translation files required by the page
1356  $langs->loadLangs(array('other', 'mails', 'ticket'));
1357 
1358  // Clear temp files. Must be done at beginning, before call of triggers
1359  if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1360  $this->clear_attached_files();
1361  }
1362 
1363  // Define output language
1364  $outputlangs = $langs;
1365  $newlang = '';
1366  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
1367  $newlang = $this->param['langsmodels'];
1368  }
1369  if (!empty($newlang)) {
1370  $outputlangs = new Translate("", $conf);
1371  $outputlangs->setDefaultLang($newlang);
1372  $outputlangs->load('other');
1373  }
1374 
1375  // Get message template for $this->param["models"] into c_email_templates
1376  $arraydefaultmessage = -1;
1377  if (isset($this->param['models']) && $this->param['models'] != 'none') {
1378  $model_id = 0;
1379  if (array_key_exists('models_id', $this->param)) {
1380  $model_id = (int) $this->param["models_id"];
1381  }
1382 
1383  $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id); // If $model_id is empty, preselect the first one
1384  }
1385 
1386  // Define list of attached files
1387  $listofpaths = array();
1388  $listofnames = array();
1389  $listofmimes = array();
1390 
1391  if (!empty($this->trackid)) {
1392  $keytoavoidconflict = '-'.$this->trackid;
1393  } else {
1394  $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
1395  }
1396  //var_dump($keytoavoidconflict);
1397  if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1398  if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
1399  foreach ($this->param['fileinit'] as $path) {
1400  $formmail->add_attached_files($path, basename($path), dol_mimetype($path));
1401  }
1402  }
1403  }
1404  //var_dump($_SESSION);
1405  //var_dump($_SESSION["listofpaths".$keytoavoidconflict]);
1406  if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1407  $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1408  }
1409  if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1410  $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1411  }
1412  if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1413  $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1414  }
1415 
1416  // Define output language
1417  $outputlangs = $langs;
1418  $newlang = '';
1419  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
1420  $newlang = $this->param['langsmodels'];
1421  }
1422  if (!empty($newlang)) {
1423  $outputlangs = new Translate("", $conf);
1424  $outputlangs->setDefaultLang($newlang);
1425  $outputlangs->load('other');
1426  }
1427 
1428  print "\n<!-- Begin message_form TICKET -->\n";
1429 
1430  $send_email = GETPOSTINT('send_email') ? GETPOSTINT('send_email') : 0;
1431 
1432  // Example 1 : Adding jquery code
1433  print '<script nonce="'.getNonce().'" type="text/javascript">
1434  jQuery(document).ready(function() {
1435  send_email=' . $send_email.';
1436  if (send_email) {
1437  if (!jQuery("#send_msg_email").is(":checked")) {
1438  jQuery("#send_msg_email").prop("checked", true).trigger("change");
1439  }
1440  jQuery(".email_line").show();
1441  } else {
1442  if (!jQuery("#private_message").is(":checked")) {
1443  jQuery("#private_message").prop("checked", true).trigger("change");
1444  }
1445  jQuery(".email_line").hide();
1446  }
1447  ';
1448 
1449  // If constant set, allow to send private messages as email
1450  if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1451  print 'jQuery("#send_msg_email").click(function() {
1452  console.log("Click send_msg_email");
1453  if(jQuery(this).is(":checked")) {
1454  if (jQuery("#private_message").is(":checked")) {
1455  jQuery("#private_message").prop("checked", false).trigger("change");
1456  }
1457  jQuery(".email_line").show();
1458  }
1459  else {
1460  jQuery(".email_line").hide();
1461  }
1462  });
1463 
1464  jQuery("#private_message").click(function() {
1465  console.log("Click private_message");
1466  if (jQuery(this).is(":checked")) {
1467  if (jQuery("#send_msg_email").is(":checked")) {
1468  jQuery("#send_msg_email").prop("checked", false).trigger("change");
1469  }
1470  jQuery(".email_line").hide();
1471  }
1472  });';
1473  }
1474 
1475  print '});
1476  </script>';
1477 
1478 
1479  print '<form method="post" name="ticket" id="ticket" enctype="multipart/form-data" action="'.$this->param["returnurl"].'">';
1480  print '<input type="hidden" name="token" value="'.newToken().'">';
1481  print '<input type="hidden" name="action" value="'.$this->action.'">';
1482  print '<input type="hidden" name="actionbis" value="add_message">';
1483  print '<input type="hidden" name="backtopage" value="'.$this->backtopage.'">';
1484  if (!empty($this->trackid)) {
1485  print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
1486  } else {
1487  print '<input type="hidden" name="trackid" value="'.(empty($this->track_id) ? '' : $this->track_id).'">';
1488  $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
1489  }
1490  foreach ($this->param as $key => $value) {
1491  print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
1492  }
1493 
1494  // Get message template
1495  $model_id = 0;
1496  if (array_key_exists('models_id', $this->param)) {
1497  $model_id = $this->param["models_id"];
1498  $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id);
1499  }
1500 
1501  $result = $formmail->fetchAllEMailTemplate(!empty($this->param["models"]) ? $this->param["models"] : "", $user, $outputlangs);
1502  if ($result < 0) {
1503  setEventMessages($this->error, $this->errors, 'errors');
1504  }
1505  $modelmail_array = array();
1506  foreach ($formmail->lines_model as $line) {
1507  $modelmail_array[$line->id] = $line->label;
1508  }
1509 
1510  print '<table class="border" width="'.$width.'">';
1511 
1512  // External users can't send message email
1513  if ($user->hasRight("ticket", "write") && !$user->socid) {
1514  $ticketstat = new Ticket($this->db);
1515  $res = $ticketstat->fetch('', '', $this->track_id);
1516 
1517  print '<tr><td></td><td>';
1518  $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : (getDolGlobalInt('TICKETS_MESSAGE_FORCE_MAIL') ? 'checked' : ''));
1519  print '<input type="checkbox" name="send_email" value="1" id="send_msg_email" '.$checkbox_selected.'/> ';
1520  print '<label for="send_msg_email">'.$langs->trans('SendMessageByEmail').'</label>';
1521  $texttooltip = $langs->trans("TicketMessageSendEmailHelp");
1522  if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1523  $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2b");
1524  } else {
1525  $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2a", '{s1}');
1526  }
1527  $texttooltip = str_replace('{s1}', $langs->trans('MarkMessageAsPrivate'), $texttooltip);
1528  print ' '.$form->textwithpicto('', $texttooltip, 1, 'help');
1529  print '</td></tr>';
1530 
1531  // Private message (not visible by customer/external user)
1532  if (!$user->socid) {
1533  print '<tr><td></td><td>';
1534  $checkbox_selected = (GETPOST('private_message', 'alpha') == "1" ? ' checked' : '');
1535  print '<input type="checkbox" name="private_message" value="1" id="private_message" '.$checkbox_selected.'/> ';
1536  print '<label for="private_message">'.$langs->trans('MarkMessageAsPrivate').'</label>';
1537  print ' '.$form->textwithpicto('', $langs->trans("TicketMessagePrivateHelp"), 1, 'help');
1538  print '</td></tr>';
1539  }
1540 
1541  // Zone to select its email template
1542  if (count($modelmail_array) > 0) {
1543  print '<tr class="email_line"><td></td><td colspan="2"><div style="padding: 3px 0 3px 0">'."\n";
1544  print $langs->trans('SelectMailModel').': '.$formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], 1, 0, "", "", 0, 0, 0, '', 'minwidth200');
1545  if ($user->admin) {
1546  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1547  }
1548  print ' &nbsp; ';
1549  print '<input type="submit" class="button" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
1550  print '</div></td>';
1551  }
1552 
1553  // From
1554  $from = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
1555  print '<tr class="email_line"><td><span class="">'.$langs->trans("MailFrom").'</span></td>';
1556  print '<td><span class="">'.img_picto('', 'email', 'class="pictofixedwidth"').$from.'</span></td></tr>';
1557 
1558  // Subject/topic
1559  $topic = "";
1560  foreach ($formmail->lines_model as $line) {
1561  if ($this->param['models_id'] == $line->id) {
1562  $topic = $line->topic;
1563  break;
1564  }
1565  }
1566  print '<tr class="email_line"><td>'.$langs->trans('Subject').'</td>';
1567  if (empty($topic)) {
1568  print '<td><input type="text" class="text minwidth500" name="subject" value="['.getDolGlobalString('MAIN_INFO_SOCIETE_NOM').' - '.$langs->trans("Ticket").' '.$ticketstat->ref.'] '. $ticketstat->subject .'" />';
1569  } else {
1570  print '<td><input type="text" class="text minwidth500" name="subject" value="['.getDolGlobalString('MAIN_INFO_SOCIETE_NOM').' - '.$langs->trans("Ticket").' '.$ticketstat->ref.'] '.$topic.'" />';
1571  }
1572  print '</td></tr>';
1573 
1574  // Recipients / adressed-to
1575  print '<tr class="email_line"><td>'.$langs->trans('MailRecipients');
1576  print ' '.$form->textwithpicto('', $langs->trans("TicketMessageRecipientsHelp"), 1, 'help');
1577  print '</td><td>';
1578  if ($res) {
1579  // Retrieve email of all contacts (internal and external)
1580  $contacts = $ticketstat->getInfosTicketInternalContact(1);
1581  $contacts = array_merge($contacts, $ticketstat->getInfosTicketExternalContact(1));
1582 
1583  $sendto = array();
1584 
1585  // Build array to display recipient list
1586  if (is_array($contacts) && count($contacts) > 0) {
1587  foreach ($contacts as $key => $info_sendto) {
1588  if ($info_sendto['email'] != '') {
1589  $sendto[] = dol_escape_htmltag(trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">").' <small class="opacitymedium">('.dol_escape_htmltag($info_sendto['libelle']).")</small>";
1590  }
1591  }
1592  }
1593 
1594  if (!empty($ticketstat->origin_replyto) && !in_array($ticketstat->origin_replyto, $sendto)) {
1595  $sendto[] = dol_escape_htmltag($ticketstat->origin_replyto).' <small class="opacitymedium">('.$langs->trans("TicketEmailOriginIssuer").")</small>";
1596  } elseif ($ticketstat->origin_email && !in_array($ticketstat->origin_email, $sendto)) {
1597  $sendto[] = dol_escape_htmltag($ticketstat->origin_email).' <small class="opacitymedium">('.$langs->trans("TicketEmailOriginIssuer").")</small>";
1598  }
1599 
1600  if ($ticketstat->fk_soc > 0) {
1601  $ticketstat->socid = $ticketstat->fk_soc;
1602  $ticketstat->fetch_thirdparty();
1603 
1604  if (!empty($ticketstat->thirdparty->email) && !in_array($ticketstat->thirdparty->email, $sendto)) {
1605  $sendto[] = $ticketstat->thirdparty->email.' <small class="opacitymedium">('.$langs->trans('Customer').')</small>';
1606  }
1607  }
1608 
1609  if (getDolGlobalInt('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS')) {
1610  $sendto[] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO').' <small class="opacitymedium">(generic email)</small>';
1611  }
1612 
1613  // Print recipient list
1614  if (is_array($sendto) && count($sendto) > 0) {
1615  print img_picto('', 'email', 'class="pictofixedwidth"');
1616  print implode(', ', $sendto);
1617  } else {
1618  print '<div class="warning">'.$langs->trans('WarningNoEMailsAdded').' '.$langs->trans('TicketGoIntoContactTab').'</div>';
1619  }
1620  }
1621  print '</td></tr>';
1622  }
1623 
1624  $uselocalbrowser = false;
1625 
1626  // Intro
1627  // External users can't send message email
1628  /*
1629  if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_INTRO)) {
1630  $mail_intro = GETPOST('mail_intro') ? GETPOST('mail_intro') : $conf->global->TICKET_MESSAGE_MAIL_INTRO;
1631  print '<tr class="email_line"><td><label for="mail_intro">';
1632  print $form->textwithpicto($langs->trans("TicketMessageMailIntro"), $langs->trans("TicketMessageMailIntroHelp"), 1, 'help');
1633  print '</label>';
1634 
1635  print '</td><td>';
1636  include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1637 
1638  $doleditor = new DolEditor('mail_intro', $mail_intro, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_2, 70);
1639 
1640  $doleditor->Create();
1641  print '</td></tr>';
1642  }
1643  */
1644 
1645  // Attached files
1646  if (!empty($this->withfile)) {
1647  $out = '<tr>';
1648  $out .= '<td>'.$langs->trans("MailFile").'</td>';
1649  $out .= '<td>';
1650  // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
1651  $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
1652  $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1653  $out .= 'jQuery(document).ready(function () {';
1654  $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
1655  $out .= ' jQuery("#addedfile").on("change", function() {';
1656  $out .= ' if (jQuery(this).val().length) {';
1657  $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", false);';
1658  $out .= ' } else {';
1659  $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
1660  $out .= ' }';
1661  $out .= ' });';
1662  $out .= ' jQuery(".removedfile").click(function() {';
1663  $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
1664  $out .= ' });';
1665  $out .= '})';
1666  $out .= '</script>'."\n";
1667 
1668  if (count($listofpaths)) {
1669  foreach ($listofpaths as $key => $val) {
1670  $out .= '<div id="attachfile_'.$key.'">';
1671  $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
1672  if (!$this->withfilereadonly) {
1673  $out .= ' <input type="image" style="border: 0px;" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/delete.png" value="'.($key + 1).'" class="removedfile reposition" id="removedfile_'.$key.'" name="removedfile_'.$key.'" />';
1674  }
1675  $out .= '<br></div>';
1676  }
1677  } else {
1678  //$out .= $langs->trans("NoAttachedFiles").'<br>';
1679  }
1680  if ($this->withfile == 2) { // Can add other files
1681  $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
1682  $out .= ' ';
1683  $out .= '<input type="submit" class="button smallpaddingimp reposition" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
1684  }
1685  $out .= "</td></tr>\n";
1686 
1687  print $out;
1688  }
1689 
1690  // MESSAGE
1691 
1692  $defaultmessage = "";
1693  if (is_object($arraydefaultmessage) && $arraydefaultmessage->content) {
1694  $defaultmessage = $arraydefaultmessage->content;
1695  }
1696  $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1697 
1698  // Deal with format differences between message and signature (text / HTML)
1699  if (dol_textishtml($defaultmessage) && !dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1700  $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1701  } elseif (!dol_textishtml($defaultmessage) && isset($this->substit['__USER_SIGNATURE__']) && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1702  $defaultmessage = dol_nl2br($defaultmessage);
1703  }
1704  if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1705  $defaultmessage = GETPOST('message', 'restricthtml');
1706  } else {
1707  $defaultmessage = make_substitutions($defaultmessage, $this->substit);
1708  // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1709  $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1710  $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1711  }
1712 
1713  print '<tr><td colspan="2"><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span>';
1714  if ($user->hasRight("ticket", "write") && !$user->socid) {
1715  $texttooltip = $langs->trans("TicketMessageHelp");
1716  if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO') || getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
1717  $texttooltip .= '<br><br>'.$langs->trans("ForEmailMessageWillBeCompletedWith").'...';
1718  }
1719  if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO')) {
1720  $mail_intro = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO'), $this->substit);
1721  print '<input type="hidden" name="mail_intro" value="'.$mail_intro.'">';
1722  $texttooltip .= '<br><u>'.$langs->trans("TicketMessageMailIntro").'</u><br>'.$mail_intro;
1723  }
1724  if (getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
1725  $mail_signature = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE'), $this->substit);
1726  print '<input type="hidden" name="mail_signature" value="'.$mail_signature.'">';
1727  $texttooltip .= '<br><br><u>'.$langs->trans("TicketMessageMailFooter").'</u><br>'.$mail_signature;
1728  }
1729  print $form->textwithpicto('', $texttooltip, 1, 'help');
1730  }
1731  print '</label></td></tr>';
1732 
1733 
1734  print '<tr><td colspan="2">';
1735  //$toolbarname = 'dolibarr_details';
1736  $toolbarname = 'dolibarr_notes';
1737  include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1738  $doleditor = new DolEditor('message', $defaultmessage, '100%', 200, $toolbarname, '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_5, '90%');
1739  $doleditor->Create();
1740  print '</td></tr>';
1741 
1742  // Footer
1743  // External users can't send message email
1744  /*if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_SIGNATURE)) {
1745  $mail_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
1746  print '<tr class="email_line"><td><label for="mail_intro">'.$langs->trans("TicketMessageMailFooter").'</label>';
1747  print $form->textwithpicto('', $langs->trans("TicketMessageMailFooterHelp"), 1, 'help');
1748  print '</td><td>';
1749  include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1750  $doleditor = new DolEditor('mail_signature', $mail_signature, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_2, 70);
1751  $doleditor->Create();
1752  print '</td></tr>';
1753  }
1754  */
1755 
1756  print '</table>';
1757 
1758  print '<br><center>';
1759  print '<input type="submit" class="button" name="btn_add_message" value="'.$langs->trans("Add").'"';
1760  // Add a javascript test to avoid to forget to submit file before sending email
1761  if ($this->withfile == 2 && !empty($conf->use_javascript_ajax)) {
1762  print ' onClick="if (document.ticket.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
1763  }
1764  print ' />';
1765  if (!empty($this->withcancel)) {
1766  print " &nbsp; &nbsp; ";
1767  print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
1768  }
1769  print "</center>\n";
1770 
1771  print '<input type="hidden" name="page_y">'."\n";
1772 
1773  print "</form><br>\n";
1774 
1775  // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1776  if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1777  print '<script type="text/javascript">';
1778  print 'jQuery(document).ready(function () {';
1779  print ' $(document).on("keypress", \'#ticket\', function (e) { /* Note this is called at every key pressed ! */
1780  var code = e.keyCode || e.which;
1781  if (code == 13) {
1782  console.log("Enter was intercepted and blocked");
1783  e.preventDefault();
1784  return false;
1785  }
1786  });';
1787  print '})';
1788  print '</script>';
1789  }
1790 
1791  print "<!-- End form TICKET -->\n";
1792  }
1793 }
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:456
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
Class to build HTML component for third parties management Only common components are here.
Class to manage generation of HTML components for contract module.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class to manage building of HTML components.
selectGroupTickets($selected='', $htmlname='ticketcategory', $filtertype='', $format=0, $empty=0, $noadmininfo=0, $maxlength=0, $morecss='', $use_multilevel=0, $outputlangs=null)
Return html list of ticket analytic codes.
selectSeveritiesTickets($selected='', $htmlname='ticketseverity', $filtertype='', $format=0, $empty=0, $noadmininfo=0, $maxlength=0, $morecss='')
Return html list of ticket severitys (priorities)
static checkRequiredFields(array $fields, int &$errors)
Check required fields.
showMessageForm($width='40%')
Show the form to add message on ticket.
selectTypesTickets($selected='', $htmlname='tickettype', $filtertype='', $format=0, $empty=0, $noadmininfo=0, $maxlength=0, $morecss='', $multiselect=0)
Return html list of tickets type.
__construct($db)
Constructor.
showForm($withdolfichehead=0, $mode='edit', $public=0, Contact $with_contact=null, $action='', Ticket $object=null)
Show the form to input ticket.
clear_attached_files()
Clear list of attached files in send mail form (also stored in session)
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:50
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
Definition: files.lib.php:1609
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information in HTML for admin users or standard users.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
table tableforfield button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
Definition: style.css.php:887
Class to generate the form for creating a new ticket.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:123
getMaxFileSizeArray()
Return the max allowed for file upload.