dolibarr 25.0.0-alpha
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-2025 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-2025 Charlene Benke <charlene.r@patas-monkey.com>
8 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024 Irvine FLEITH <irvine.fleith@atm-consulting.fr>
10 * Copyright (C) 2026 Jon Bendtsen <jon.bendtsen.github@jonb.dk>
11 * Copyright (C) 2026 Lenin Rivas <lenin.rivas777@gmail.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
33require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
34require_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
35require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
36
37if (!class_exists('FormCompany')) {
38 include DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
39}
40
50{
54 public $db;
55
59 public $track_id;
60
64 public $trackid;
65
69 public $fk_user_create;
70
74 public $message;
78 public $topic_title;
79
83 public $action;
84
88 public $withtopic;
92 public $withemail;
93
97 public $withsubstit;
98
102 public $withfile;
106 public $withfilereadonly;
107
111 public $backtopage;
112
116 public $ispublic; // to show information or not into public form
117
121 public $withtitletopic;
125 public $withtopicreadonly;
129 public $withreadid;
130
134 public $withcompany; // to show company drop-down list
138 public $withfromsocid;
142 public $withfromcontactid;
146 public $withnotifytiersatcreate;
150 public $withusercreate; // to show name of creating user in form
154 public $withcreatereadonly;
155
159 public $withextrafields;
160
164 public $withref; // to show ref field
168 public $withcancel;
169
173 public $type_code;
177 public $category_code;
181 public $severity_code;
182
183
187 public $substit = array();
191 public $param = array();
192
196 public $error;
200 public $errors = array();
201
202
208 public function __construct($db)
209 {
210 global $conf;
211
212 $this->db = $db;
213
214 $this->action = 'add';
215
216 $this->withcompany = (int) (!getDolGlobalInt("TICKETS_NO_COMPANY_ON_FORM") && isModEnabled("societe"));
217 $this->withfromsocid = 0;
218 $this->withfromcontactid = 0;
219 $this->withreadid = 0;
220 //$this->withtitletopic='';
221 $this->withnotifytiersatcreate = 0;
222 $this->withusercreate = 1;
223 $this->withcreatereadonly = 1;
224 $this->withemail = 0;
225 $this->withref = 0;
226 $this->withextrafields = 0; // to show extrafields or not
227 //$this->withtopicreadonly=0;
228 }
229
237 public static function checkRequiredFields(array $fields, int &$errors)
238 {
239 global $langs;
240
241 foreach ($fields as $field => $type) {
242 if (!GETPOST($field, $type['check'])) {
243 $errors++;
244 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities($type['langs'])), null, 'errors');
245 }
246 }
247 }
248
260 public function showForm($withdolfichehead = 0, $mode = 'edit', $public = 0, $with_contact = null, $action = '', $object = null)
261 {
262 global $conf, $langs, $user, $hookmanager;
263
264 $permissiontomanage = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('ticket', 'write')) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('ticket', 'manage_advance')));
265
266 // Load translation files required by the page
267 $langs->loadLangs(array('other', 'mails', 'ticket'));
268
269 if ($mode == 'create') {
270 $ref = GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : '';
271 $type_code = GETPOSTISSET('type_code') ? GETPOST('type_code', 'alpha') : '';
272 $category_code = GETPOSTISSET('category_code') ? GETPOST('category_code', 'alpha') : '';
273 $severity_code = GETPOSTISSET('severity_code') ? GETPOST('severity_code', 'alpha') : '';
274 $subject = GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : '';
275 $email = GETPOSTISSET('email') ? GETPOST('email', 'alpha') : '';
276 $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : '';
277 $projectid = GETPOSTISSET('projectid') ? GETPOSTINT('projectid') : 0;
278 $user_assign = GETPOSTISSET('fk_user_assign') ? GETPOSTINT('fk_user_assign') : $this->fk_user_create;
279 } else {
280 $ref = GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $object->ref;
281 $type_code = GETPOSTISSET('type_code') ? GETPOST('type_code', 'alpha') : $object->type_code;
282 $category_code = GETPOSTISSET('category_code') ? GETPOST('category_code', 'alpha') : $object->category_code;
283 $severity_code = GETPOSTISSET('severity_code') ? GETPOST('severity_code', 'alpha') : $object->severity_code;
284 $subject = GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : $object->subject;
285 $email = GETPOSTISSET('email') ? GETPOST('email', 'alpha') : $object->email_from;
286 $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : $object->message;
287 $projectid = GETPOSTISSET('projectid') ? GETPOSTINT('projectid') : (int) $object->fk_project;
288 $user_assign = GETPOSTISSET('fk_user_assign') ? GETPOSTINT('fk_user_assign') : $object->fk_user_assign;
289 }
290
291 $form = new Form($this->db);
292 $formcompany = new FormCompany($this->db);
293 $ticketstatic = new Ticket($this->db);
294
295 $soc = new Societe($this->db);
296 if (!empty($this->withfromsocid) && $this->withfromsocid > 0) {
297 $soc->fetch($this->withfromsocid);
298 }
299
300 $ticketstat = new Ticket($this->db);
301
302 $extrafields = new ExtraFields($this->db);
303 $extrafields->fetch_name_optionals_label($ticketstat->table_element);
304
305 print "\n<!-- Begin form TICKET -->\n";
306
307 if ($withdolfichehead) {
308 print dol_get_fiche_head([], 'card', '', 0, '');
309 }
310
311 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']).'">';
312
313 print '<input type="hidden" name="token" value="'.newToken().'">';
314 print '<input type="hidden" name="action" value="'.$this->action.'">';
315 if (!empty($object->id)) {
316 print '<input type="hidden" name="id" value="'. $object->id .'">';
317 }
318 print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
319 foreach ($this->param as $key => $value) {
320 print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
321 }
322 print '<input type="hidden" name="fk_user_create" value="'.$this->fk_user_create.'">';
323
324 print '<table class="border centpercent">';
325
326 // Ref
327 if ($this->withref) {
328 $defaultref = $ticketstat->getDefaultRef();
329
330 if ($mode == 'edit') {
331 $defaultref = (string) $object->ref;
332 }
333 print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("Ref").'</span></td><td>';
334 print '<input type="text" name="ref" value="'.dol_escape_htmltag($defaultref).'">';
335 print '</td></tr>';
336 }
337
338 // Title
339 if ($this->withemail) {
340 print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">'.$langs->trans("Email").'</span></label></td><td>';
341 print '<input class="text minwidth200" id="email" name="email" value="'.$email.'" autofocus>'; // Do not use "required", it breaks button cancel
342 print '</td></tr>';
343
344 if ($with_contact) {
345 // contact search and result
346 $html_contact_search = '';
347 $html_contact_search .= '<tr id="contact_search_line">';
348 $html_contact_search .= '<td class="titlefield">';
349 $html_contact_search .= '<label for="contact"><span class="fieldrequired">' . $langs->trans('Contact') . '</span></label>';
350 $html_contact_search .= '<input type="hidden" id="contact_id" name="contact_id" value="" />';
351 $html_contact_search .= '</td>';
352 $html_contact_search .= '<td id="contact_search_result"></td>';
353 $html_contact_search .= '</tr>';
354 print $html_contact_search;
355 // contact lastname
356 $html_contact_lastname = '';
357 $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>';
358 $html_contact_lastname .= '<input type="text" id="contact_lastname" name="contact_lastname" value="' . dolPrintHTMLForAttributeUrl(GETPOSTISSET('contact_lastname') ? GETPOST('contact_lastname', 'alphanohtml') : '') . '" />';
359 $html_contact_lastname .= '</td></tr>';
360 print $html_contact_lastname;
361 // contact firstname
362 $html_contact_firstname = '';
363 $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>';
364 $html_contact_firstname .= '<input type="text" id="contact_firstname" name="contact_firstname" value="' . dolPrintHTMLForAttribute(GETPOSTISSET('contact_firstname') ? GETPOST('contact_firstname', 'alphanohtml') : '') . '" />';
365 $html_contact_firstname .= '</td></tr>';
366 print $html_contact_firstname;
367 // company name
368 $html_company_name = '';
369 $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>';
370 $html_company_name .= '<input type="text" id="company_name" name="company_name" value="' . dolPrintHTMLForAttribute(GETPOSTISSET('company_name') ? GETPOST('company_name', 'alphanohtml') : '') . '" />';
371 $html_company_name .= '</td></tr>';
372 print $html_company_name;
373 // contact phone
374 $html_contact_phone = '';
375 $html_contact_phone .= '<tr id="contact_phone_line" class="contact_field"><td><label for="contact_phone"><span>' . $langs->trans('Phone') . '</span></label></td><td>';
376 $html_contact_phone .= '<input type="text" id="contact_phone" name="contact_phone" value="' . dolPrintHTMLForAttribute(GETPOSTISSET('contact_phone') ? GETPOST('contact_phone', 'alphanohtml') : '') . '" />';
377 $html_contact_phone .= '</td></tr>';
378 print $html_contact_phone;
379
380 // search contact form email
381 $langs->load('errors');
382 print '<script nonce="'.getNonce().'" type="text/javascript">
383 jQuery(document).ready(function() {
384 var contact = jQuery.parseJSON("'.dol_escape_js(json_encode($with_contact), 2).'");
385 jQuery("#contact_search_line").hide();
386 if (contact) {
387 if (contact.id > 0) {
388 jQuery("#contact_search_line").show();
389 jQuery("#contact_id").val(contact.id);
390 jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
391 jQuery(".contact_field").hide();
392 } else {
393 jQuery(".contact_field").show();
394 }
395 }
396
397 jQuery("#email").change(function() {
398 jQuery("#contact_search_line").show();
399 jQuery("#contact_search_result").html("'.dol_escape_js($langs->trans('Select2SearchInProgress')).'");
400 jQuery("#contact_id").val("");
401 jQuery("#contact_lastname").val("");
402 jQuery("#contact_firstname").val("");
403 jQuery("#company_name").val("");
404 jQuery("#contact_phone").val("");
405
406 jQuery.getJSON(
407 "'.dol_escape_js(dol_buildpath('/public/ticket/ajax/ajax.php', 1)).'",
408 {
409 action: "getContacts",
410 token: "'.currentToken().'",
411 email: jQuery("#email").val()
412 },
413 function(response) {
414 if (response.error) {
415 jQuery("#contact_search_result").html("<span class=\"error\">"+response.error+"</span>");
416 } else {
417 var contact_list = response.contacts;
418 if (contact_list.length == 1) {
419 var contact = contact_list[0];
420 jQuery("#contact_id").val(contact.id);
421 jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
422 jQuery(".contact_field").hide();
423 } else if (contact_list.length <= 0) {
424 jQuery("#contact_search_line").hide();
425 jQuery(".contact_field").show();
426 }
427 }
428 }
429 ).fail(function(jqxhr, textStatus, error) {
430 var error_msg = "'.dol_escape_js($langs->trans('ErrorAjaxRequestFailed')).'"+" ["+textStatus+"] : "+error;
431 jQuery("#contact_search_result").html("<span class=\"error\">"+error_msg+"</span>");
432 });
433 });
434 });
435 </script>';
436 }
437 }
438
439 // If ticket created from another object
440 $subelement = '';
441 if (isset($this->param['origin']) && $this->param['originid'] > 0) {
442 // Parse element/subelement (ex: project_task)
443 $element = $subelement = $this->param['origin'];
444 $regs = array();
445 if (preg_match('/^([^_]+)_([^_]+)/i', $this->param['origin'], $regs)) {
446 $element = $regs[1];
447 $subelement = $regs[2];
448 }
449
450 dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
451 $classname = ucfirst($subelement);
452 $objectsrc = new $classname($this->db);
453 '@phan-var-force CommonObject $objectsrc';
454 $objectsrc->fetch(GETPOSTINT('originid'));
455
456 if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
457 $objectsrc->fetch_lines();
458 }
459
460 $objectsrc->fetch_thirdparty();
461 $newclassname = $classname;
462 print '<tr><td>'.$langs->trans($newclassname).'</td><td colspan="2"><input name="'.$subelement.'id" value="'.GETPOST('originid').'" type="hidden" />'.$objectsrc->getNomUrl(1).'</td></tr>';
463 }
464
465 // Type of Ticket
466 print '<tr><td class="titlefield"><span class="fieldrequired"><label for="selecttype_code">'.$langs->trans("TicketTypeRequest").'</span></label></td><td>';
467 $this->selectTypesTickets($type_code, 'type_code', '', 2, 'ifone', 0, 0, 'minwidth200 maxwidth500');
468 print '</td></tr>';
469
470 // Group => Category
471 print '<tr><td><span class="fieldrequired"><label for="selectcategory_code">'.$langs->trans("TicketCategory").'</span></label></td><td>';
472 $filter = '';
473 if ($public) {
474 $filter = '(public:=:1)';
475 }
476 $this->selectGroupTickets($category_code, 'category_code', $filter, 2, 'ifone', 0, 0, 'minwidth200 maxwidth500');
477 print '</td></tr>';
478
479 // Severity => Priority
480 print '<tr><td><span class="fieldrequired"><label for="selectseverity_code">'.$langs->trans("TicketSeverity").'</span></label></td><td>';
481 $this->selectSeveritiesTickets($severity_code, 'severity_code', '', 2, 'ifone', 0, 0, 'minwidth200 maxwidth500');
482 print '</td></tr>';
483
484 if (isModEnabled('knowledgemanagement')) {
485 // KM Articles
486 print '<tr id="KWwithajax" class="hidden"><td></td></tr>';
487 print '<!-- Script to manage change of ticket group -->
488 <script nonce="'.getNonce().'">
489 jQuery(document).ready(function() {
490 function groupticketchange() {
491 console.log("We called groupticketchange, so we try to load list KM linked to event");
492 $("#KWwithajax").html("");
493 idgroupticket = $("#selectcategory_code").val();
494
495 console.log("We have selected id="+idgroupticket);
496
497 if (idgroupticket != "") {
498 $.ajax({ url: \''.DOL_URL_ROOT.'/core/ajax/fetchKnowledgeRecord.php\',
499 data: { action: \'getKnowledgeRecord\', idticketgroup: idgroupticket, token: \''.newToken().'\', lang:\''.$langs->defaultlang.'\', public:'.($public).' },
500 type: \'GET\',
501 success: function(response) {
502 var urllist = \'\';
503 console.log("We received response "+response);
504 if (typeof response == "object") {
505 console.log("response is already type object, no need to parse it");
506 } else {
507 console.log("response is type "+(typeof response));
508 response = JSON.parse(response);
509 }
510 for (key in response) {
511 answer = response[key].answer;
512 urllist += \'<li><a href="#" title="\'+response[key].title+\'" class="button_KMpopup" data-html="\'+answer+\'">\' +response[key].title+\'</a></li>\';
513 }
514 if (urllist != "") {
515 $("#KWwithajax").html(\'<td>'.$langs->trans("KMFoundForTicketGroup").'</td><td><ul>\'+urllist+\'</ul></td>\');
516 $("#KWwithajax").show();
517 $(".button_KMpopup").on("click",function(){
518 console.log("Open popup with jQuery(...).dialog() with KM article")
519 var $dialog = $("<div></div>").html($(this).attr("data-html"))
520 .dialog({
521 autoOpen: false,
522 modal: true,
523 height: (window.innerHeight - 150),
524 width: "80%",
525 title: $(this).attr("title"),
526 });
527 $dialog.dialog("open");
528 console.log($dialog);
529 })
530 }
531 },
532 error : function(output) {
533 console.error("Error on Fetch of KM articles");
534 },
535 });
536 }
537 };
538 $("#selectcategory_code").on("change",function() { groupticketchange(); });
539 if ($("#selectcategory_code").val() != "") {
540 groupticketchange();
541 }
542 });
543 </script>'."\n";
544 }
545
546 // Subject
547 if ($this->withtitletopic) {
548 print '<tr><td><label for="subject"><span class="fieldrequired">'.$langs->trans("Subject").'</span></label></td><td>';
549 // Answer to a ticket : display of the thread title in readonly
550 if ($this->withtopicreadonly) {
551 print $langs->trans('SubjectAnswerToTicket').' '.$this->topic_title;
552 } else {
553 if (isset($this->withreadid) && $this->withreadid > 0) {
554 $subject = $langs->trans('SubjectAnswerToTicket').' '.$this->withreadid.' : '.$this->topic_title;
555 }
556 print '<input class="text minwidth400imp" id="subject" name="subject" value="'.dolPrintHTMLForAttribute($subject).'"'.(empty($this->withemail) ? ' autofocus' : '').' spellcheck="false">';
557 }
558 print '</td></tr>';
559 }
560
561 // Message
562 print '<tr><td><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span></label></td><td>';
563
564 // If public form, display more information
565 $toolbarname = 'dolibarr_notes';
566 if ($this->ispublic) {
567 $toolbarname = 'dolibarr_details'; // TODO Allow image so user can do paste of image into content but we disallow file manager
568 print '<div class="warning hideonsmartphone">'.(getDolGlobalString("TICKET_PUBLIC_TEXT_HELP_MESSAGE", $langs->trans('TicketPublicPleaseBeAccuratelyDescribe'))).'</div>';
569 }
570 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
571 $uselocalbrowser = false;
572 $ckeditorenabledforticket = (getDolGlobalString('FCKEDITOR_ENABLE_TICKET') >= ($this->ispublic ? 2 : 1)); // 0=no, 1=from backoffice only, 2=from backoffice+public (very dangerous)
573 if (!$ckeditorenabledforticket) {
574 $msg = dol_string_nohtmltag($msg, 2);
575 }
576 $doleditor = new DolEditor('message', $msg, '100%', 230, $toolbarname, 'In', true, $uselocalbrowser, $ckeditorenabledforticket, ROWS_8, '90%');
577 $doleditor->Create();
578 print '</td></tr>';
579
580 // Categories
581 if (isModEnabled('category') && !$public) {
582 // Categories
583 print '<tr><td class="wordbreak"></td><td>';
584 print $form->selectCategories(Categorie::TYPE_TICKET, 'categories', $object);
585 print "</td></tr>";
586 }
587
588 // Attached files
589 if (!empty($this->withfile)) {
590 // Define list of attached files
591 $listofpaths = array();
592 $listofnames = array();
593 $listofmimes = array();
594 if (!empty($_SESSION["listofpaths"])) {
595 $listofpaths = explode(';', $_SESSION["listofpaths"]);
596 }
597
598 if (!empty($_SESSION["listofnames"])) {
599 $listofnames = explode(';', $_SESSION["listofnames"]);
600 }
601
602 if (!empty($_SESSION["listofmimes"])) {
603 $listofmimes = explode(';', $_SESSION["listofmimes"]);
604 }
605
606 $out = '<tr>';
607 $out .= '<td></td>';
608 $out .= '<td>';
609 // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
610 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
611 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
612 $out .= 'jQuery(document).ready(function () {';
613 $out .= ' jQuery(".removedfile").click(function() {';
614 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
615 $out .= ' });';
616 $out .= '})';
617 $out .= '</script>'."\n";
618 if (count($listofpaths)) {
619 foreach ($listofpaths as $key => $val) {
620 $out .= '<div id="attachfile_'.$key.'">';
621 $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
622 if (!$this->withfilereadonly) {
623 $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.'" />';
624 }
625 $out .= '<br></div>';
626 }
627 }
628 if ($this->withfile == 2) { // Can add other files
629 $maxfilesizearray = getMaxFileSizeArray();
630 $maxmin = $maxfilesizearray['maxmin'];
631 if ($maxmin > 0) {
632 $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
633 }
634 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
635 $out .= ' ';
636 $out .= '<input type="submit" class="button smallpaddingimp reposition" id="addfile" name="addfile" value="'.$langs->trans("MailingAddFile").'" />';
637 }
638 $out .= "</td></tr>\n";
639
640 // Improves user experience and prevents human error when creating tickets; files do not load.
641 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
642 jQuery(document).ready(function () {
643 jQuery("#addedfile").on("change", function() {
644 // Dispara el clic automáticamente al seleccionar archivo
645 jQuery("#addfile").click();
646 });
647 // Oculta el botón redundante si JS está activo
648 jQuery("#addfile").hide();
649 });
650 </script>';
651
652 print $out;
653 }
654
655 // User of creation
656 if ($this->withusercreate > 0 && $this->fk_user_create) {
657 print '<tr><td class="titlefield">'.$langs->trans("CreatedBy").'</td><td>';
658 $langs->load("users");
659 $fuser = new User($this->db);
660
661 if ($this->withcreatereadonly) {
662 if ($res = $fuser->fetch($this->fk_user_create)) {
663 print $fuser->getNomUrl(1);
664 }
665 }
666 print ' &nbsp; ';
667 print "</td></tr>\n";
668 }
669
670 // Customer or supplier
671 if ($this->withcompany) {
672 // force company and contact id for external user
673 if (empty($user->socid)) {
674 // Company
675 print '<tr><td class="titlefield">'.$langs->trans("ThirdParty").'</td><td>';
676 $events = array();
677 $events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
678 print img_picto('', 'company', 'class="paddingright"');
679 print $form->select_company($this->withfromsocid, 'socid', '', 1, 1, 0, $events, 0, 'minwidth200');
680 print '</td></tr>';
681 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
682 $htmlname = 'socid';
683 print '<script nonce="'.getNonce().'" type="text/javascript">
684 $(document).ready(function () {
685 jQuery("#'.$htmlname.'").change(function () {
686 var obj = '.json_encode($events).';
687 $.each(obj, function(key,values) {
688 if (values.method.length) {
689 runJsCodeForEvent'.$htmlname.'(values);
690 }
691 });
692 });
693
694 function runJsCodeForEvent'.$htmlname.'(obj) {
695 console.log("Run runJsCodeForEvent'.$htmlname.'");
696 var id = $("#'.$htmlname.'").val();
697 var method = obj.method;
698 var url = obj.url;
699 var htmlname = obj.htmlname;
700 var showempty = obj.showempty;
701 $.getJSON(url,
702 {
703 action: method,
704 id: id,
705 htmlname: htmlname,
706 showempty: showempty
707 },
708 function(response) {
709 $.each(obj.params, function(key,action) {
710 if (key.length) {
711 var num = response.num;
712 if (num > 0) {
713 $("#" + key).removeAttr(action);
714 } else {
715 $("#" + key).attr(action, action);
716 }
717 }
718 });
719 $("select#" + htmlname).html(response.value);
720 if (response.num) {
721 var selecthtml_str = response.value;
722 var selecthtml_dom=$.parseHTML(selecthtml_str);
723 if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
724 $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
725 }
726 } else {
727 $("#inputautocomplete"+htmlname).val("");
728 }
729 $("select#" + htmlname).change(); /* Trigger event change */
730 }
731 );
732 }
733 });
734 </script>';
735 }
736 if ($mode == 'create') {
737 // Contact and type
738 print '<tr><td>'.$langs->trans("Contact").'</td><td>';
739 // If no socid, set to -1 to avoid full contacts list
740 $selectedCompany = ($this->withfromsocid > 0) ? $this->withfromsocid : -1;
741 print img_picto('', 'contact', 'class="pictofixedwidth"');
742 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
743 print $form->select_contact($selectedCompany, $this->withfromcontactid, 'contactid', 3, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
744
745 print ' ';
746 $formcompany->selectTypeContact($ticketstatic, '', 'type', 'external', '', 0, 'maginleftonly maxwidth200');
747 print '</td></tr>';
748 }
749 } else {
750 print '<tr><td class="titlefield"><input type="hidden" name="socid" value="'.$user->socid.'"/></td>';
751 print '<td><input type="hidden" name="contactid" value="'.$user->contact_id.'"/></td>';
752 print '<td><input type="hidden" name="type" value="Z"/></td></tr>';
753 }
754
755 // Notify thirdparty at creation
756 if (empty($this->ispublic) && ($action == 'create' || $action == 'presend')) {
757 print '<tr><td><label for="notify_tiers_at_create">'.$langs->trans("TicketNotifyTiersAtCreation").'</label></td><td>';
758 print '<input type="checkbox" id="notify_tiers_at_create" name="notify_tiers_at_create"'.($this->withnotifytiersatcreate ? ' checked="checked"' : '').'>';
759 print '</td></tr>';
760 }
761
762 // User assigned
763 print '<tr><td>';
764 print $langs->trans("AssignedTo");
765 print '</td><td>';
766 if ($permissiontomanage) {
767 print img_picto('', 'user', 'class="pictofixedwidth"');
768 print $form->select_dolusers($user_assign, 'fk_user_assign', 1);
769 } else {
770 $userstat = new User($this->db);
771 $userstat->fetch($user_assign);
772 print $userstat->getNomUrl(-1);
773 }
774 print '</td>';
775 print '</tr>';
776 }
777
778 if ($subelement != 'project') {
779 if (isModEnabled('project') && !$this->ispublic) {
780 $formproject = new FormProjets($this->db);
781 print '<tr><td><label for="project"><span class="">'.$langs->trans("Project").'</span></label></td><td>';
782 print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(-1, $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
783 print '</td></tr>';
784 }
785 }
786
787 if ($subelement != 'contract' && $subelement != 'contrat') {
788 if (getDolGlobalString('TICKET_LINK_TO_CONTRACT_WITH_HARDLINK')) {
789 // Deprecated. Duplicate feature. Ticket can already be linked to contract with the generic "Link to" feature.
790 if (isModEnabled('contract') && !$this->ispublic) {
791 // This feature hang the application on large list of contracts, because the select component is not complete: it does not work like select of thirdparty or product to support large lists
792 // So we add a hidden option to avoid to have it used and the application locked, until the select_contract is fixed.
793 if (getDolGlobalString("CONTRACT_CAN_USE_THE_BUGGED_SELECT_COMPONENT")) {
794 $langs->load('contracts');
795 $formcontract = new FormContract($this->db);
796 print '<tr><td><label for="contract"><span class="">'.$langs->trans("Contract").'</span></label></td><td>';
797 print img_picto('', 'contract', 'class="pictofixedwidth"');
798 // socid is for internal users null and not 0 or -1
799 print $formcontract->select_contract($user->socid ?? -1, GETPOSTINT('contractid'), 'contractid', 0, 1, 1, 1);
800 print '</td></tr>';
801 }
802 }
803 }
804 }
805
806 // Other attributes
807 $parameters = array();
808 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $ticketstat, $action); // Note that $action and $object may have been modified by hook
809 if (empty($reshook)) {
810 if ($mode == 'create') {
811 print $object->showOptionals($extrafields, 'create');
812 } else {
813 print $object->showOptionals($extrafields, 'edit');
814 }
815 }
816
817 // Show line with Captcha
818 $captcha = '';
819 if ($public && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) {
820 print '<tr><td class="titlefield"></td><td><br>';
821
822 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
823 $captcha = getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_HANDLER', 'standard');
824
825 // List of directories where we can find captcha handlers
826 $dirModCaptcha = array_merge(array('main' => '/core/modules/security/captcha/'), is_array($conf->modules_parts['captcha']) ? $conf->modules_parts['captcha'] : array());
827
828 $fullpathclassfile = '';
829 foreach ($dirModCaptcha as $dir) {
830 $fullpathclassfile = dol_buildpath($dir."modCaptcha".ucfirst($captcha).'.class.php', 0, 2);
831 if ($fullpathclassfile) {
832 break;
833 }
834 }
835
836 if ($fullpathclassfile) {
837 include_once $fullpathclassfile;
838 $captchaobj = null;
839
840 // Charging the numbering class
841 $classname = "modCaptcha".ucfirst($captcha);
842 if (class_exists($classname)) {
844 $captchaobj = new $classname($this->db, $conf, $langs, $user);
845 '@phan-var-force ModeleCaptcha $captchaobj';
846
847 if (is_object($captchaobj) && method_exists($captchaobj, 'getCaptchaCodeForForm')) {
848 print $captchaobj->getCaptchaCodeForForm(''); // @phan-suppress-current-line PhanUndeclaredMethod
849 } else {
850 print 'Error, the captcha handler '.get_class($captchaobj).' does not have any method getCaptchaCodeForForm()';
851 }
852 } else {
853 print 'Error, the captcha handler class '.$classname.' was not found after the include';
854 }
855 } else {
856 print 'Error, the captcha handler '.$captcha.' has no class file found modCaptcha'.ucfirst($captcha);
857 }
858
859 print '<br></td></tr>';
860 }
861
862 print '</table>';
863
864 if ($withdolfichehead) {
865 print dol_get_fiche_end();
866 } else {
867 print '<br><br>';
868 }
869
870 if ($mode == 'create') {
871 print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "CreateTicket"), ($this->withcancel ? "Cancel" : ""));
872 } else {
873 print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "Save"), ($this->withcancel ? "Cancel" : ""));
874 }
875
876 print '<br>';
877
878 /*
879 print '<div class="center">';
880 print '<input type="submit" class="button" name="add" value="'.$langs->trans(($this->withreadid > 0 ? "SendResponse" : "CreateTicket")).'" />';
881 if ($this->withcancel) {
882 print " &nbsp; &nbsp; &nbsp;";
883 print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
884 }
885 print '</div>';
886 */
887
888 print '<input type="hidden" name="page_y">'."\n";
889
890 print "</form>\n";
891 print "<!-- End form TICKET -->\n";
892 }
893
909 public function selectTypesTickets($selected = '', $htmlname = 'tickettype', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $multiselect = 0, $disabledefault = 0)
910 {
911 global $langs, $user;
912
913 $selected = is_array($selected) ? $selected : (!empty($selected) ? explode(',', $selected) : array());
914 $ticketstat = new Ticket($this->db);
915
916 dol_syslog(get_class($this) . "::select_types_tickets " . implode(';', $selected) . ", " . $htmlname . ", " . $filtertype . ", " . $format . ", " . $multiselect, LOG_DEBUG);
917
918 $filterarray = array();
919
920 if ($filtertype != '' && $filtertype != '-1') {
921 $filterarray = explode(',', $filtertype);
922 }
923
924 $ticketstat->loadCacheTypesTickets();
925
926 print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.($multiselect ? '[]' : '').'"'.($multiselect ? ' multiple' : '').'>';
927 if ($empty && !$multiselect) {
928 print '<option value="">'.((is_numeric($empty) || $empty == 'ifone') ? '&nbsp;' : $empty).'</option>';
929 }
930
931 if (is_array($ticketstat->cache_types_tickets) && count($ticketstat->cache_types_tickets)) {
932 foreach ($ticketstat->cache_types_tickets as $id => $arraytypes) {
933 // We stop if we astto filter on some ticket type and code is not one requested.
934 if (count($filterarray) && !in_array($arraytypes['code'], $filterarray)) {
935 continue;
936 }
937
938 // If 'showempty' is enabled we discard empty line because an empty line has already been output.
939 if ($empty && empty($arraytypes['code'])) {
940 continue;
941 }
942
943 if ($format == 0) {
944 print '<option value="'.$id.'"';
945 }
946
947 if ($format == 1) {
948 print '<option value="'.$arraytypes['code'].'"';
949 }
950
951 if ($format == 2) {
952 print '<option value="'.$arraytypes['code'].'"';
953 }
954
955 if ($format == 3) {
956 print '<option value="'.$id.'"';
957 }
958
959 // If text is selected, we compare with code, otherwise with id
960 if (in_array($arraytypes['code'], $selected)) {
961 print ' selected="selected"';
962 } elseif (in_array($id, $selected)) {
963 print ' selected="selected"';
964 } elseif ($arraytypes['use_default'] == "1" && empty($disabledefault) && empty($selected) && !$multiselect) {
965 print ' selected="selected"';
966 } elseif (count($ticketstat->cache_types_tickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it
967 print ' selected="selected"';
968 }
969
970 print '>';
971
972 $value = '&nbsp;';
973 if ($format == 0) {
974 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
975 } elseif ($format == 1) {
976 $value = $arraytypes['code'];
977 } elseif ($format == 2) {
978 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
979 } elseif ($format == 3) {
980 $value = $arraytypes['code'];
981 }
982
983 print $value ? $value : '&nbsp;';
984 print '</option>';
985 }
986 }
987 print '</select>';
988 if (isset($user->admin) && $user->admin && !$noadmininfo) {
989 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
990 }
991
992 print ajax_combobox('select'.$htmlname);
993 }
994
1010 public function selectGroupTickets($selected = '', $htmlname = 'ticketcategory', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $use_multilevel = 0, $outputlangs = null)
1011 {
1012 global $conf, $langs, $user;
1013
1014 dol_syslog(get_class($this)."::selectCategoryTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
1015
1016 if (is_null($outputlangs) || !is_object($outputlangs)) {
1017 $outputlangs = $langs;
1018 }
1019 $outputlangs->load("ticket");
1020
1021 $publicgroups = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
1022
1023 $ticketstat = new Ticket($this->db);
1024 $ticketstat->loadCacheCategoriesTickets($publicgroups ? 1 : -1); // get list of active ticket groups
1025
1026 if ($use_multilevel <= 0) { // Only one combo list to select the group of ticket (default)
1027 print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
1028 if ($empty) {
1029 print '<option value="">'.((is_numeric($empty) || $empty == 'ifone') ? '&nbsp;' : $empty).'</option>';
1030 }
1031
1032 $categorytickets = $conf->cache['category_tickets'];
1033 '@phan-var-force array<int,array{code:string,label:string,use_default:int,pos:int,public:int,active:int,force_severity:?string,fk_parent:int}> $categorytickets';
1034 if (is_array($categorytickets) && count($categorytickets)) {
1035 foreach ($categorytickets as $id => $arraycategories) {
1036 // Exclude some record
1037 if ($publicgroups) {
1038 if (empty($arraycategories['public'])) {
1039 continue;
1040 }
1041 }
1042
1043 // We discard empty line if showempty is on because an empty line has already been output.
1044 if ($empty && empty($arraycategories['code'])) {
1045 continue;
1046 }
1047
1048 $label = ($arraycategories['label'] != '-' ? $arraycategories['label'] : '');
1049 if ($outputlangs->trans("TicketCategoryShort".$arraycategories['code']) != "TicketCategoryShort".$arraycategories['code']) {
1050 $label = $outputlangs->trans("TicketCategoryShort".$arraycategories['code']);
1051 } elseif ($outputlangs->trans($arraycategories['code']) != $arraycategories['code']) {
1052 $label = $outputlangs->trans($arraycategories['code']);
1053 }
1054
1055 if ($format == 0) {
1056 print '<option value="'.$id.'"';
1057 }
1058
1059 if ($format == 1) {
1060 print '<option value="'.$arraycategories['code'].'"';
1061 }
1062
1063 if ($format == 2) {
1064 print '<option value="'.$arraycategories['code'].'"';
1065 }
1066
1067 if ($format == 3) {
1068 print '<option value="'.$id.'"';
1069 }
1070
1071 // If selected is text, we compare with code, otherwise with id
1072 if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arraycategories['code']) {
1073 print ' selected="selected"';
1074 } elseif (isset($selected) && $selected == $id) {
1075 print ' selected="selected"';
1076 } elseif ($arraycategories['use_default'] == "1" && empty($selected) && (!$empty || $empty == 'ifone')) {
1077 print ' selected="selected"';
1078 } elseif (count($categorytickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it
1079 print ' selected="selected"';
1080 }
1081
1082 print '>';
1083
1084 $value = '';
1085 if ($format == 0) {
1086 $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
1087 }
1088
1089 if ($format == 1) {
1090 $value = $arraycategories['code'];
1091 }
1092
1093 if ($format == 2) {
1094 $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
1095 }
1096
1097 if ($format == 3) {
1098 $value = $arraycategories['code'];
1099 }
1100
1101 print $value ? $value : '&nbsp;';
1102 print '</option>';
1103 }
1104 }
1105 print '</select>';
1106 if (isset($user->admin) && $user->admin && !$noadmininfo) {
1107 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1108 }
1109
1110 print ajax_combobox('select'.$htmlname);
1111 } elseif ($htmlname != '') { // complexe mode using selection of group using a combo for each level (when using a hierarchy of groups).
1112 $selectedgroups = array();
1113 $groupvalue = "";
1114 $groupticket = GETPOST($htmlname, 'aZ09');
1115 $child_id = GETPOST($htmlname.'_child_id', 'aZ09') ? GETPOST($htmlname.'_child_id', 'aZ09') : 0;
1116 if (!empty($groupticket)) {
1117 $tmpgroupticket = $groupticket;
1118 $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code";
1119 $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc WHERE ctc.code = '".$this->db->escape($tmpgroupticket)."'";
1120 $resql = $this->db->query($sql);
1121 if ($resql) {
1122 $obj = $this->db->fetch_object($resql);
1123 $selectedgroups[] = $obj->code;
1124 while ($obj->fk_parent > 0) {
1125 $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)."'";
1126 $resql = $this->db->query($sql);
1127 if ($resql) {
1128 $obj = $this->db->fetch_object($resql);
1129 $selectedgroups[] = $obj->code;
1130 }
1131 }
1132 }
1133 }
1134
1135 $arrayidused = array();
1136 $arrayidusedconcat = array();
1137 $arraycodenotparent = array();
1138 $arraycodenotparent[] = "";
1139
1140 $stringtoprint = '<span class="supportemailfield bold">'.$langs->trans("GroupOfTicket").'</span> ';
1141 $stringtoprint .= '<select id="'.$htmlname.'" class="minwidth500" child_id="0">';
1142 $stringtoprint .= '<option value="">&nbsp;</option>';
1143
1144 $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ";
1145 $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";
1146 $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
1147 $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
1148 $public = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
1149 if ($public) {
1150 $sql .= " AND ctc.public = 1";
1151 }
1152 $sql .= " AND ctc.fk_parent = 0";
1153 $sql .= $this->db->order('ctc.pos', 'ASC');
1154
1155 $resql = $this->db->query($sql);
1156 if ($resql) {
1157 $num_rows_level0 = $this->db->num_rows($resql);
1158 $i = 0;
1159 while ($i < $num_rows_level0) {
1160 $obj = $this->db->fetch_object($resql);
1161 if ($obj) {
1162 $label = ($obj->label != '-' ? $obj->label : '');
1163 if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
1164 $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
1165 } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1166 $label = $outputlangs->trans($obj->code);
1167 }
1168
1169 $grouprowid = $obj->rowid;
1170 $groupvalue = $obj->code;
1171 $grouplabel = $label;
1172
1173 $isparent = $obj->isparent;
1174 if (is_array($selectedgroups)) {
1175 $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1176 } else {
1177 $iselected = $groupticket == $obj->code ? 'selected' : '';
1178 }
1179 $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>';
1180 if ($isparent == 'NOTPARENT') {
1181 $arraycodenotparent[] = $groupvalue;
1182 }
1183 $arrayidused[] = $grouprowid;
1184 $arrayidusedconcat[] = $grouprowid;
1185 }
1186 $i++;
1187 }
1188 } else {
1189 dol_print_error($this->db);
1190 }
1191 if (count($arrayidused) == 1) {
1192 return '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.dol_escape_htmltag($groupvalue).'">';
1193 } else {
1194 $stringtoprint .= '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'_select" class="maxwidth500 minwidth400" value="'.GETPOST($htmlname).'">';
1195 $stringtoprint .= '<input type="hidden" name="'.$htmlname.'_child_id" id="'.$htmlname.'_select_child_id" class="maxwidth500 minwidth400" '.GETPOST($htmlname).' value="'.GETPOST($htmlname."_child_id").'">';
1196 }
1197 $stringtoprint .= '</select>&nbsp;';
1198
1199 $levelid = 1; // The first combobox
1200 while ($levelid <= $use_multilevel) { // Loop to take the child of the combo
1201 $tabscript = array();
1202 $stringtoprint .= '<select id="'.$htmlname.'_child_'.$levelid.'" class="maxwidth500 minwidth400 groupticketchild" child_id="'.$levelid.'">';
1203 $stringtoprint .= '<option value="">&nbsp;</option>';
1204
1205 $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ctcjoin.code as codefather";
1206 $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
1207 $sql .= " JOIN ".$this->db->prefix()."c_ticket_category as ctcjoin ON ctc.fk_parent = ctcjoin.rowid";
1208 $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
1209 $sql .= " AND ctc.rowid NOT IN (".$this->db->sanitize(implode(',', $arrayidusedconcat)).")";
1210
1211 $public = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
1212 if ($public) {
1213 $sql .= " AND ctc.public = 1";
1214 }
1215 // Add a test to take only record that are direct child
1216 if (!empty($arrayidused)) {
1217 $sql .= " AND ctc.fk_parent IN ( ";
1218 foreach ($arrayidused as $idused) {
1219 $sql .= ((int) $idused).", ";
1220 }
1221 $sql = substr($sql, 0, -2);
1222 $sql .= ")";
1223 }
1224 $sql .= $this->db->order('ctc.pos', 'ASC');
1225
1226 $resql = $this->db->query($sql);
1227 if ($resql) {
1228 $num_rows = $this->db->num_rows($resql);
1229 $i = 0;
1230 $arrayidused = array();
1231 while ($i < $num_rows) {
1232 $obj = $this->db->fetch_object($resql);
1233 if ($obj) {
1234 $label = ($obj->label != '-' ? $obj->label : '');
1235 if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
1236 $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
1237 } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1238 $label = $outputlangs->trans($obj->code);
1239 }
1240
1241 $grouprowid = $obj->rowid;
1242 $groupvalue = $obj->code;
1243 $grouplabel = $label;
1244 $isparent = $obj->isparent;
1245 $fatherid = $obj->fk_parent;
1246 $arrayidused[] = $grouprowid;
1247 $arrayidusedconcat[] = $grouprowid;
1248 $groupcodefather = $obj->codefather;
1249 if ($isparent == 'NOTPARENT') {
1250 $arraycodenotparent[] = $groupvalue;
1251 }
1252 if (is_array($selectedgroups)) {
1253 $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1254 } else {
1255 $iselected = $groupticket == $obj->code ? 'selected' : '';
1256 }
1257 $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>';
1258 if (empty($tabscript[$groupcodefather])) {
1259 $tabscript[$groupcodefather] = 'if ($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").val() == "'.dol_escape_js($groupcodefather).'"){
1260 $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").show()
1261 console.log("We show child tickets of '.$groupcodefather.' group ticket")
1262 }else{
1263 $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").hide()
1264 console.log("We hide child tickets of '.$groupcodefather.' group ticket")
1265 }';
1266 }
1267 }
1268 $i++;
1269 }
1270 } else {
1271 dol_print_error($this->db);
1272 }
1273 $stringtoprint .= '</select>';
1274
1275 $stringtoprint .= '<script nonce="'.getNonce().'">';
1276 $stringtoprint .= 'arraynotparents = '.json_encode($arraycodenotparent).';'; // when the last visible combo list is number x, this is the array of group
1277 $stringtoprint .= 'if (arraynotparents.includes($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").val())){
1278 console.log("'.$htmlname.'_child_'.$levelid.'")
1279 if($("#'.$htmlname.'_child_'.$levelid.'").val() == "" && ($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")>'.$child_id.')){
1280 $("#'.$htmlname.'_child_'.$levelid.'").hide();
1281 console.log("We hide '.$htmlname.'_child_'.$levelid.' input")
1282 }
1283 if(arraynotparents.includes("'.$groupticket.'") && '.$child_id.' == 0){
1284 $("#ticketcategory_select_child_id").val($("#'.$htmlname.'").attr("child_id"))
1285 $("#ticketcategory_select").val($("#'.$htmlname.'").val()) ;
1286 console.log("We choose '.$htmlname.' input and reload hidden input");
1287 }
1288 }
1289 $("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").change(function() {
1290 child_id = $("#'.$htmlname.($levelid > 1 ? '_child_'.$levelid : '').'").attr("child_id");
1291
1292 /* Change of value to select this value*/
1293 if (arraynotparents.includes($(this).val()) || $(this).attr("child_id") == '.$use_multilevel.') {
1294 $("#ticketcategory_select").val($(this).val());
1295 $("#ticketcategory_select_child_id").val($(this).attr("child_id")) ;
1296 console.log("We choose to select "+ $(this).val());
1297 }else{
1298 if ($("#'.$htmlname.'_child_'.$levelid.' option").length <= 1) {
1299 $("#ticketcategory_select").val($(this).val());
1300 $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1301 console.log("We choose to select "+ $(this).val() + " and next combo has no item, so we keep this selection");
1302 } else {
1303 console.log("We choose to select "+ $(this).val() + " but next combo has some item, so we clean selected item");
1304 $("#ticketcategory_select").val("");
1305 $("#ticketcategory_select_child_id").val("");
1306 }
1307 }
1308
1309 console.log("We select a new value into combo child_id="+child_id);
1310
1311 // Hide all selected box that are child of the one modified
1312 $(".groupticketchild").each(function(){
1313 if ($(this).attr("child_id") > child_id) {
1314 console.log("hide child_id="+$(this).attr("child_id"));
1315 $(this).val("");
1316 $(this).hide();
1317 }
1318 })
1319
1320 // Now we enable the next combo
1321 $("#'.$htmlname.'_child_'.$levelid.'").val("");
1322 if (!arraynotparents.includes($(this).val()) && $("#'.$htmlname.'_child_'.$levelid.' option").length > 1) {
1323 console.log($("#'.$htmlname.'_child_'.$levelid.' option").length);
1324 $("#'.$htmlname.'_child_'.$levelid.'").show()
1325 } else {
1326 $("#'.$htmlname.'_child_'.$levelid.'").hide()
1327 }
1328 ';
1329 $levelid++;
1330 foreach ($tabscript as $script) {
1331 $stringtoprint .= $script;
1332 }
1333 $stringtoprint .= '})';
1334 $stringtoprint .= '</script>';
1335 }
1336 $stringtoprint .= '<script nonce="'.getNonce().'">';
1337 $stringtoprint .= '$("#'.$htmlname.'_child_'.$use_multilevel.'").change(function() {
1338 $("#ticketcategory_select").val($(this).val());
1339 $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1340 tmpvalselect = $("#ticketcategory_select").val();
1341 if(tmpvalselect == "" && $("#ticketcategory_select_child_id").val() >= 1){
1342 $("#ticketcategory_select_child_id").val($(this).attr("child_id")-1);
1343 }
1344 console.log($("#ticketcategory_select").val());
1345 })';
1346 $stringtoprint .= '</script>';
1347 $stringtoprint .= ajax_combobox($htmlname);
1348
1349 return $stringtoprint;
1350 }
1351 }
1352
1366 public function selectSeveritiesTickets($selected = '', $htmlname = 'ticketseverity', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '')
1367 {
1368 global $conf, $langs, $user;
1369
1370 $ticketstat = new Ticket($this->db);
1371
1372 dol_syslog(get_class($this)."::selectSeveritiesTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
1373
1374 $filterarray = array();
1375
1376 if ($filtertype != '' && $filtertype != '-1') {
1377 $filterarray = explode(',', $filtertype);
1378 }
1379
1380 $ticketstat->loadCacheSeveritiesTickets();
1381
1382 print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
1383 if ($empty) {
1384 print '<option value="">'.((is_numeric($empty) || $empty == 'ifone') ? '&nbsp;' : $empty).'</option>';
1385 }
1386
1387 $severitytickets = $conf->cache['severity_tickets'];
1388 '@phan-var-force array<int,array{code:string,label:string,use_default:int,pos:int}> $severitytickets';
1389 if (is_array($severitytickets) && count($severitytickets)) {
1390 foreach ($severitytickets as $id => $arrayseverities) {
1391 // Skip if filtering on specific payment modes was requested
1392 if (count($filterarray) && !in_array($arrayseverities['code'], $filterarray)) {
1393 continue;
1394 }
1395
1396 // We discard empty line if showempty is on because an empty line has already been output.
1397 if ($empty && empty($arrayseverities['code'])) {
1398 continue;
1399 }
1400
1401 if ($format == 0) {
1402 print '<option value="'.$id.'"';
1403 }
1404
1405 if ($format == 1) {
1406 print '<option value="'.$arrayseverities['code'].'"';
1407 }
1408
1409 if ($format == 2) {
1410 print '<option value="'.$arrayseverities['code'].'"';
1411 }
1412
1413 if ($format == 3) {
1414 print '<option value="'.$id.'"';
1415 }
1416
1417 // If text is selected, we compare with code, otherwise with id
1418 if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arrayseverities['code']) {
1419 print ' selected="selected"';
1420 } elseif (isset($selected) && $selected == $id) {
1421 print ' selected="selected"';
1422 } elseif ($arrayseverities['use_default'] == "1" && empty($selected) && (!$empty || $empty == 'ifone')) {
1423 print ' selected="selected"';
1424 } elseif (count($severitytickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it
1425 print ' selected="selected"';
1426 }
1427
1428 print '>';
1429
1430 $value = '';
1431 if ($format == 0) {
1432 $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1433 }
1434
1435 if ($format == 1) {
1436 $value = $arrayseverities['code'];
1437 }
1438
1439 if ($format == 2) {
1440 $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1441 }
1442
1443 if ($format == 3) {
1444 $value = $arrayseverities['code'];
1445 }
1446
1447 print $value ? $value : '&nbsp;';
1448 print '</option>';
1449 }
1450 }
1451 print '</select>';
1452 if (isset($user->admin) && $user->admin && !$noadmininfo) {
1453 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1454 }
1455
1456 print ajax_combobox('select'.$htmlname);
1457 }
1458
1459 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1465 public function clear_attached_files()
1466 {
1467 // phpcs:enable
1468 global $conf, $user;
1469 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1470
1471 // Set tmp user directory
1472 $vardir = $conf->user->dir_output."/".$user->id;
1473 $upload_dir = $vardir.'/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
1474 if (is_dir($upload_dir)) {
1475 dol_delete_dir_recursive($upload_dir);
1476 }
1477
1478 if (!empty($this->trackid)) { // TODO Always use trackid (ticXXX) instead of track_id (abcd123)
1479 $keytoavoidconflict = '-'.$this->trackid;
1480 } else {
1481 $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id;
1482 }
1483 unset($_SESSION["listofpaths".$keytoavoidconflict]);
1484 unset($_SESSION["listofnames".$keytoavoidconflict]);
1485 unset($_SESSION["listofmimes".$keytoavoidconflict]);
1486 }
1487
1495 public function showMessageForm($width = '40%', $fromPublicInterface = 0)
1496 {
1497 global $conf, $langs, $user, $hookmanager, $form;
1498
1499 $formmail = new FormMail($this->db);
1500 $addfileaction = 'addfile';
1501
1502 if (!is_object($form)) {
1503 $form = new Form($this->db);
1504 }
1505
1506 // Load translation files required by the page
1507 $langs->loadLangs(array('other', 'mails', 'ticket'));
1508
1509 // Clear temp files. Must be done at beginning, before call of triggers
1510 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1511 $this->clear_attached_files();
1512 }
1513
1514 // Define output language
1515 $outputlangs = $langs;
1516 $newlang = '';
1517 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
1518 $newlang = $this->param['langsmodels'];
1519 }
1520 if (!empty($newlang)) {
1521 $outputlangs = new Translate("", $conf);
1522 $outputlangs->setDefaultLang($newlang);
1523 $outputlangs->load('other');
1524 }
1525
1526 // Get message template for $this->param["models"] into c_email_templates
1527 $arraydefaultmessage = -1;
1528 if (isset($this->param['models']) && $this->param['models'] != 'none') {
1529 $model_id = 0;
1530 if (array_key_exists('models_id', $this->param)) {
1531 $model_id = (int) $this->param["models_id"];
1532 }
1533
1534 // If $model_id is empty, preselect the first one
1535 $usedefault = ($model_id ? -1 : 1);
1536 $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id, 1, '', $usedefault);
1537 if (isset($arraydefaultmessage->id) && empty($model_id)) {
1538 $model_id = $arraydefaultmessage->id;
1539 $this->param['models_id'] = $model_id;
1540 }
1541 }
1542
1543 // Define list of attached files
1544 $listofpaths = array();
1545 $listofnames = array();
1546 $listofmimes = array();
1547
1548 if (!empty($this->trackid)) {
1549 $keytoavoidconflict = '-'.$this->trackid;
1550 } else {
1551 $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
1552 }
1553 //var_dump($keytoavoidconflict);
1554 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1555 if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
1556 foreach ($this->param['fileinit'] as $path) {
1557 $formmail->add_attached_files($path, basename($path), dol_mimetype($path));
1558 }
1559 }
1560 }
1561 //var_dump($_SESSION);
1562 //var_dump($_SESSION["listofpaths".$keytoavoidconflict]);
1563 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1564 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1565 }
1566 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1567 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1568 }
1569 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1570 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1571 }
1572
1573 // Define output language
1574 $outputlangs = $langs;
1575 $newlang = '';
1576 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
1577 $newlang = $this->param['langsmodels'];
1578 }
1579 if (!empty($newlang)) {
1580 $outputlangs = new Translate("", $conf);
1581 $outputlangs->setDefaultLang($newlang);
1582 $outputlangs->load('other');
1583 }
1584
1585 print "\n<!-- Begin message_form TICKET -->\n";
1586
1587 $send_email = GETPOSTINT('send_email') ? GETPOSTINT('send_email') : 0;
1588
1589 // Example 1 : Adding jquery code
1590 print '<script nonce="'.getNonce().'" type="text/javascript">
1591 jQuery(document).ready(function() {
1592 send_email='.((int) $send_email).';
1593 if (send_email) {
1594 if (!jQuery("#send_msg_email").is(":checked")) {
1595 jQuery("#send_msg_email").prop("checked", true).trigger("change");
1596 }
1597 jQuery(".email_line").show();
1598 jQuery(".not_email_line").hide();
1599 } else {
1600 if (!jQuery("#private_message").is(":checked")) {
1601 jQuery("#private_message").prop("checked", true).trigger("change");
1602 }
1603 jQuery(".email_line").hide();
1604 jQuery(".not_email_line").show();
1605 }
1606 ';
1607
1608 // If constant set, allow to send private messages as email
1609 if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1610 print 'jQuery("#send_msg_email").click(function() {
1611 console.log("Click send_msg_email");
1612 if(jQuery(this).is(":checked")) {
1613 if (jQuery("#private_message").is(":checked")) {
1614 jQuery("#private_message").prop("checked", false).trigger("change");
1615 }
1616 jQuery(".email_line").show();
1617 jQuery(".not_email_line").hide();
1618 }
1619 else {
1620 jQuery(".email_line").hide();
1621 jQuery(".not_email_line").show();
1622 }
1623 });
1624
1625 jQuery("#private_message").click(function() {
1626 console.log("Click private_message");
1627 if (jQuery(this).is(":checked")) {
1628 if (jQuery("#send_msg_email").is(":checked")) {
1629 jQuery("#send_msg_email").prop("checked", false).trigger("change");
1630 }
1631 jQuery(".email_line").hide();
1632 jQuery(".not_email_line").show();
1633 }
1634 });';
1635 }
1636
1637 print '});
1638 </script>';
1639
1640 print '<form method="post" name="ticket" id="ticket" enctype="multipart/form-data" action="'.$this->param["returnurl"].'">';
1641 print '<input type="hidden" name="token" value="'.newToken().'">';
1642 print '<input type="hidden" name="action" value="'.$this->action.'">';
1643 print '<input type="hidden" name="actionbis" value="add_message">';
1644 print '<input type="hidden" name="backtopage" value="'.$this->backtopage.'">';
1645 if (!empty($this->trackid)) {
1646 print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
1647 } else {
1648 print '<input type="hidden" name="trackid" value="'.(empty($this->track_id) ? '' : $this->track_id).'">';
1649 $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
1650 }
1651 foreach ($this->param as $key => $value) {
1652 print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
1653 }
1654
1655 // Get message template
1656 $model_id = 0;
1657 if (array_key_exists('models_id', $this->param)) {
1658 $model_id = $this->param["models_id"];
1659 $usedefault = ($model_id ? -1 : 1);
1660 $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id, 1, '', $usedefault);
1661 }
1662
1663 $result = $formmail->fetchAllEMailTemplate(!empty($this->param["models"]) ? $this->param["models"] : "", $user, $outputlangs);
1664 if ($result < 0) {
1665 setEventMessages($this->error, $this->errors, 'errors');
1666 }
1667 $modelmail_array = array();
1668 foreach ($formmail->lines_model as $line) {
1669 $modelmail_array[$line->id] = $line->label;
1670 }
1671
1672 $ticketstat = new Ticket($this->db);
1673 $res = $ticketstat->fetch(0, '', $this->track_id);
1674
1675 print '<table class="border" width="'.$width.'">';
1676
1677 // External users can't send message email
1678 if ($user->hasRight("ticket", "write") && !$user->socid) {
1679 print '<tr><td class="width200"></td><td>';
1680 $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : (getDolGlobalInt('TICKETS_MESSAGE_FORCE_MAIL') ? 'checked' : ''));
1681 print '<input type="checkbox" name="send_email" value="1" id="send_msg_email" '.$checkbox_selected.'/> ';
1682 print '<label for="send_msg_email">'.$langs->trans('SendMessageByEmail').'</label>';
1683 $texttooltip = $langs->trans("TicketMessageSendEmailHelp");
1684 if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1685 $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2b");
1686 } else {
1687 $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2a", '{s1}');
1688 }
1689 $texttooltip = str_replace('{s1}', $langs->trans('MarkMessageAsPrivate'), $texttooltip);
1690 print ' '.$form->textwithpicto('', $texttooltip, 1, 'help');
1691
1692 // Section to selection email template
1693 if (count($modelmail_array) > 0) {
1694 print ' &nbsp; <span class="email_line">';
1695 print $formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], $langs->trans('SelectMailModel'), 0, 0, "", 0, 0, 0, '', 'minwidth200');
1696 if ($user->admin) {
1697 print info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv("Tools").' - '.$langs->transnoentitiesnoconv("EMailTemplates")), 1);
1698 }
1699 print ' &nbsp; ';
1700 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
1701 print '</span>';
1702 }
1703
1704 print '</td></tr>';
1705
1706 // Private message (not visible by customer/external user)
1707 if (!$user->socid) {
1708 print '<tr><td></td><td>';
1709 $checkbox_selected = (GETPOST('private_message', 'alpha') == "1" ? ' checked' : '');
1710 print '<input type="checkbox" name="private_message" value="1" id="private_message" '.$checkbox_selected.'/> ';
1711 print '<label for="private_message">'.$langs->trans('MarkMessageAsPrivate').'</label>';
1712 print ' '.$form->textwithpicto('', $langs->trans("TicketMessagePrivateHelp"), 1, 'help');
1713 print '</td></tr>';
1714 }
1715
1716 // Zone to select its email template
1717 /*
1718 if (count($modelmail_array) > 0) {
1719 print '<tr class="email_line"><td></td><td colspan="2"><div style="padding: 3px 0 3px 0">'."\n";
1720 print $formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], $langs->trans('SelectMailModel'), 0, 0, "", 0, 0, 0, '', 'minwidth200');
1721 if ($user->admin) {
1722 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1723 }
1724 print ' &nbsp; ';
1725 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
1726 print '</div></td>';
1727 }
1728 */
1729
1730 // From (and Reply-To if defined)
1731 $from = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
1732 $replyto = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_REPLYTO');
1733 print '<tr class="email_line"><td class="width200"><span class="">'.$langs->trans("MailFrom");
1734 if ($replyto) {
1735 print ' <span class="opacitymedium">('.$langs->trans("MailReply").')</span>';
1736 }
1737 print '</span></td>';
1738 print '<td><span class="">'.img_picto('', 'email', 'class="pictofixedwidth"').$from;
1739 if ($replyto) {
1740 print ' <span class="opacitymedium">('.$replyto.')</span>';
1741 }
1742 print '</span></td></tr>';
1743
1744 // Recipients / adressed-to
1745 $parameters = array();
1746 $action = '';
1747 $reshook = $hookmanager->executeHooks('printFieldTicketEmailTo', $parameters, $this, $action);
1748 if (empty($reshook)) {
1749 print '<tr class="email_line"><td class="fieldrequired">'.$langs->trans('MailRecipients');
1750 print ' '.$form->textwithpicto('', $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"), 1, 'help');
1751 print '</td><td>';
1752 $withto = array();
1753 if ($res) {
1754 $sendto_free = GETPOSTISSET('sendto') ? GETPOST('sendto', 'alphawithlgt') : '';
1755 print '<input class="minwidth200" id="sendto" name="sendto" spellcheck="false" placeholder="email@domain.com" value="'.dol_escape_htmltag($sendto_free).'" />';
1756
1757 // Build recipient list; keys are email addresses (used directly in newMessage())
1758 $contacts = $ticketstat->getInfosTicketInternalContact(1);
1759 $contacts = array_merge($contacts, $ticketstat->getInfosTicketExternalContact(1));
1760 $seen_emails = array();
1761
1762 if (is_array($contacts) && count($contacts) > 0) {
1763 foreach ($contacts as $info_sendto) {
1764 if ($info_sendto['email'] != '') {
1765 $email_lc = strtolower($info_sendto['email']);
1766 if (!in_array($email_lc, $seen_emails)) {
1767 $label_text = trim($info_sendto['firstname'].' '.$info_sendto['lastname']).' <'.$info_sendto['email'].'>';
1768 $label_html = dol_htmlentities(trim($info_sendto['firstname'].' '.$info_sendto['lastname']), ENT_QUOTES, 'UTF-8')
1769 .' <span class="opacitymedium">('.dol_htmlentities($info_sendto['libelle'], ENT_QUOTES, 'UTF-8').')</span>';
1770 $withto[$info_sendto['email']] = array(
1771 'id' => $info_sendto['email'],
1772 'label' => str_replace(array('<', '>'), array('(', ')'), $label_text),
1773 'labelhtml' => $label_html,
1774 );
1775 $seen_emails[] = $email_lc;
1776 }
1777 }
1778 }
1779 }
1780
1781 if (!empty($ticketstat->origin_replyto) && !in_array(strtolower($ticketstat->origin_replyto), $seen_emails)) {
1782 $email = (string) $ticketstat->origin_replyto;
1783 $withto[$email] = array(
1784 'id' => $email,
1785 'label' => $email,
1786 'labelhtml' => dol_escape_htmltag($email).' <span class="opacitymedium">('.$langs->trans('TicketEmailOriginIssuer').')</span>',
1787 );
1788 $seen_emails[] = strtolower($email);
1789 } elseif ($ticketstat->origin_email && !in_array(strtolower((string) $ticketstat->origin_email), $seen_emails)) {
1790 $email = (string) $ticketstat->origin_email;
1791 $withto[$email] = array(
1792 'id' => $email,
1793 'label' => $email,
1794 'labelhtml' => dol_escape_htmltag($email).' <span class="opacitymedium">('.$langs->trans('TicketEmailOriginIssuer').')</span>',
1795 );
1796 $seen_emails[] = strtolower($email);
1797 }
1798
1799 if ($ticketstat->fk_soc > 0) {
1800 $ticketstat->socid = $ticketstat->fk_soc;
1801 $ticketstat->fetch_thirdparty();
1802 if (!empty($ticketstat->thirdparty->email) && !in_array(strtolower((string) $ticketstat->thirdparty->email), $seen_emails)) {
1803 $email = (string) $ticketstat->thirdparty->email;
1804 $withto[$email] = array(
1805 'id' => $email,
1806 'label' => $email,
1807 'labelhtml' => dol_escape_htmltag($email).' <span class="opacitymedium">('.$langs->trans('Customer').')</span>',
1808 );
1809 $seen_emails[] = strtolower($email);
1810 }
1811 }
1812
1813 if (getDolGlobalInt('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
1814 $generic_email = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
1815 if (!in_array(strtolower($generic_email), $seen_emails)) {
1816 $withto[$generic_email] = array(
1817 'id' => $generic_email,
1818 'label' => $generic_email,
1819 'labelhtml' => dol_escape_htmltag($generic_email).' <span class="opacitymedium">(generic)</span>',
1820 );
1821 }
1822 }
1823
1824 // Preselect all contacts on first load; restore POST selection on re-display
1825 if (GETPOSTISSET('receiver_multiselect')) {
1826 $withtoselected = GETPOST('receiver', 'array');
1827 } else {
1828 $withtoselected = array_keys($withto);
1829 }
1830
1831 if (!empty($withto)) {
1832 print ' <span class="opacitymedium">'.$langs->trans("and").'/'.$langs->trans("or").'</span> ';
1833 print $form->multiselectarray('receiver', $withto, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0, '', '', '', 1);
1834 } else {
1835 // No contacts linked: emit the flag hidden so newMessage() still reads the free sendto input
1836 print '<input type="hidden" name="receiver_multiselect" value="1">';
1837 print ' &nbsp;<span class="opacitymedium"><small>'.$langs->trans('WarningNoEMailsAdded').'</small></span>';
1838 }
1839 }
1840 print '</td></tr>';
1841
1842 print '<tr class="email_line"><td>';
1843 print $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"), 1, 'help');
1844 print '</td><td>';
1845
1846 // Pre-fill with TICKET_SEND_INTERNAL_CC on first load
1847 if (GETPOSTISSET('receivercc_multiselect')) {
1848 $sendtocc_free = GETPOST('sendtocc', 'alphawithlgt');
1849 } else {
1850 $sendtocc_free = getDolGlobalString('TICKET_SEND_INTERNAL_CC');
1851 }
1852 print '<input class="minwidth200" id="sendtocc" name="sendtocc" spellcheck="false" value="'.dol_escape_htmltag($sendtocc_free).'" />';
1853
1854 // Reuse $withto contact list; nothing preselected for CC
1855 if (!empty($withto)) {
1856 print ' <span class="opacitymedium">'.$langs->trans("and").'/'.$langs->trans("or").'</span> ';
1857 $withtocc_selected = GETPOSTISSET('receivercc_multiselect') ? GETPOST('receivercc', 'array') : array();
1858 print $form->multiselectarray('receivercc', $withto, $withtocc_selected, 0, 0, 'inline-block minwidth500', 0, 0, '', '', '', 1);
1859 } else {
1860 // No contacts: emit the flag hidden so newMessage() still reads the free sendtocc input
1861 print '<input type="hidden" name="receivercc_multiselect" value="1">';
1862 }
1863 print '</td></tr>';
1864 } else {
1865 print $hookmanager->resPrint;
1866 }
1867 }
1868
1869 $uselocalbrowser = false;
1870
1871 // Summary
1872 if ($this->withtitletopic) {
1873 print '<tr class="not_email_line"><td><label for="summary"><span>'.$langs->trans("Summary").'</span></label></td><td>';
1874 // Answer to a ticket : display of the thread title in readonly
1875 if ($this->withtopicreadonly && $this->topic_title) {
1876 print $langs->trans('Summary').' '.$this->topic_title;
1877 } elseif (empty($this->withtopicreadonly)) {
1878 $subject = $this->topic_title;
1879 print '<input class="text minwidth500" maxlength="42" id="summary" name="summary" placeholder="" value="'.dolPrintHTMLForAttribute($subject).'"'.(empty($this->withemail) ? ' autofocus' : '').' />';
1880 }
1881 print '</td></tr>';
1882 }
1883
1884 $topic = "";
1885 foreach ($formmail->lines_model as $line) {
1886 if (!empty($this->substit) && $this->param['models_id'] == $line->id) {
1887 $topic = make_substitutions($line->topic, $this->substit);
1888 break;
1889 }
1890 }
1891 print '<tr class="email_line"><td class="fieldrequired">'.$langs->trans('MailTopic').'</td>';
1892 if (empty($topic)) {
1893 print '<td><input type="text" class="text minwidth500" name="subject" value="['.getDolGlobalString('MAIN_INFO_SOCIETE_NOM').' - '.$langs->trans("Ticket").' '.$ticketstat->ref.'] '. $ticketstat->subject .'" spellcheck="false">';
1894 } else {
1895 print '<td><input type="text" class="text minwidth500" name="subject" value="'.make_substitutions($topic, $this->substit).'" spellcheck="false">';
1896 }
1897 print '</td></tr>';
1898
1899 // Attached files
1900 if (!empty($this->withfile)) {
1901 $out = '<tr>';
1902 $out .= '<td>'.$langs->trans("MailFile").'</td>';
1903 $out .= '<td>';
1904 // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
1905 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
1906 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1907 $out .= 'jQuery(document).ready(function () {';
1908 $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
1909 $out .= ' jQuery("#addedfile").on("change", function() {';
1910 $out .= ' if (jQuery(this).val().length) {';
1911 $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", false);';
1912 $out .= ' } else {';
1913 $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
1914 $out .= ' }';
1915 $out .= ' });';
1916 $out .= ' jQuery(".removedfile").click(function() {';
1917 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
1918 $out .= ' });';
1919 $out .= '})';
1920 $out .= '</script>'."\n";
1921
1922 if (count($listofpaths)) {
1923 foreach ($listofpaths as $key => $val) {
1924 $out .= '<div id="attachfile_'.$key.'">';
1925 $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
1926 if (!$this->withfilereadonly) {
1927 $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.'" />';
1928 }
1929 $out .= '<br></div>';
1930 }
1931 } else {
1932 //$out .= $langs->trans("NoAttachedFiles").'<br>';
1933 }
1934 if ($this->withfile == 2) { // Can add other files
1935 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
1936 $out .= ' ';
1937 $out .= '<input type="submit" class="button smallpaddingimp reposition" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
1938 }
1939 $out .= "</td></tr>\n";
1940
1941 print $out;
1942 }
1943
1944 // MESSAGE
1945 $defaultmessage = "";
1946 if (is_object($arraydefaultmessage) && $arraydefaultmessage->content) {
1947 $defaultmessage = (string) $arraydefaultmessage->content;
1948 }
1949 $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1950
1951 // Deal with format differences between message and signature (text / HTML)
1952 if (dol_textishtml($defaultmessage) && !dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1953 $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1954 } elseif (!dol_textishtml($defaultmessage) && isset($this->substit['__USER_SIGNATURE__']) && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1955 $defaultmessage = dol_nl2br($defaultmessage);
1956 }
1957 if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1958 $defaultmessage = GETPOST('message', 'restricthtml');
1959 } else {
1960 $defaultmessage = make_substitutions($defaultmessage, $this->substit);
1961 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1962 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1963 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1964 }
1965
1966 // 0=no, 1=backoffice only, 2=backoffice+public. showMessageForm() is always email context, so also honour FCKEDITOR_ENABLE_MAIL.
1967 $ckeditorenabledforticket = (getDolGlobalString('FCKEDITOR_ENABLE_TICKET') >= ($fromPublicInterface ? 2 : 1))
1968 || (!$fromPublicInterface && getDolGlobalString('FCKEDITOR_ENABLE_MAIL'));
1969
1970 print '<!-- Message line from showMessageForm -->';
1971 print '<tr><td class="tdtop"><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span>';
1972 if ($user->hasRight("ticket", "write") && !$user->socid) {
1973 $texttooltip = $langs->trans("TicketMessageHelp");
1974 if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO') || getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
1975 $texttooltip .= '<br><br>'.$langs->trans("ForEmailMessageWillBeCompletedWith").'...';
1976 }
1977 $allowedmailtags = array('a', 'div', 'strong', 'em', 'i', 'u', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img');
1978 if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO')) {
1979 $mail_intro = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO'), $this->substit);
1980 print '<input type="hidden" name="mail_intro" value="'.dolPrintHTMLForAttribute($mail_intro, 0, $allowedmailtags).'">';
1981 $texttooltip .= '<br><u>'.$langs->trans("TicketMessageMailIntro").'</u><br>'.$mail_intro;
1982 }
1983 if (getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
1984 $mail_signature = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE'), $this->substit);
1985 print '<input type="hidden" name="mail_signature" value="'.dolPrintHTMLForAttribute($mail_signature, 0, $allowedmailtags).'">';
1986 $texttooltip .= '<br><br><u>'.$langs->trans("TicketMessageMailFooter").'</u><br>'.$mail_signature;
1987 }
1988 print $form->textwithpicto('', $texttooltip, 1, 'help');
1989 }
1990 print '</label></td>';
1991 $out = '<td class="tdtop">';
1992
1993 $out .= '<div class="div-layoutai">';
1994
1995 // Required to show editor assistants
1996 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
1997 $formmail = new FormMail($this->db);
1998
1999 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formai.class.php';
2000 $formai = new FormAI($this->db);
2001
2002 $formmail->withfckeditor = $ckeditorenabledforticket ? 1 : 0;
2003 $formmail->withlayout = ((string) $ckeditorenabledforticket && !$fromPublicInterface) ? 'email' : '';
2004 $formmail->withaiprompt = (isModEnabled('ai') && !$fromPublicInterface) ? 'text' : '';
2005
2006 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
2007 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
2008 $showlinktoai = ($formmail->withaiprompt ? 'textgenerationemail' : '');
2009 $showlinktoailabel = $langs->trans("AIEnhancements");
2010 $formatforouput = '';
2011 $htmlname = 'message';
2012
2013 $formai->substit = $this->substit;
2014
2015 // Fill $out
2016 $db = $this->db;
2017 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
2018
2019 $out .= '</td>';
2020 print $out;
2021
2022 print '</tr>';
2023
2024
2025 print '<tr><td colspan="2">';
2026 //$toolbarname = 'dolibarr_details';
2027 $toolbarname = 'dolibarr_notes';
2028 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
2029 $uselocalbrowser = false;
2030 if (!$ckeditorenabledforticket) {
2031 $defaultmessage = dol_string_nohtmltag($defaultmessage, 2);
2032 }
2033
2034 $doleditor = new DolEditor('message', $defaultmessage, '100%', 200, $toolbarname, '', false, $uselocalbrowser, $ckeditorenabledforticket, ROWS_6, '90%');
2035 $doleditor->Create();
2036
2037 print '</td></tr>';
2038
2039 // Footer
2040 // External users can't send message email
2041 /*if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_SIGNATURE)) {
2042 $mail_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
2043 print '<tr class="email_line"><td><label for="mail_intro">'.$langs->trans("TicketMessageMailFooter").'</label>';
2044 print $form->textwithpicto('', $langs->trans("TicketMessageMailFooterHelp"), 1, 'help');
2045 print '</td><td>';
2046 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
2047 $doleditor = new DolEditor('mail_signature', $mail_signature, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_2, 70);
2048 $doleditor->Create();
2049 print '</td></tr>';
2050 }
2051 */
2052
2053 print '</table>';
2054
2055 print '<br><center>';
2056 print '<input type="submit" class="button" name="btn_add_message" value="'.$langs->trans("Add").'"';
2057 // Add a javascript test to avoid to forget to submit file before sending email
2058 if ($this->withfile == 2 && !empty($conf->use_javascript_ajax)) {
2059 print ' onClick="if (document.ticket.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
2060 }
2061 print ' />';
2062 if (!empty($this->withcancel)) {
2063 print " &nbsp; &nbsp; ";
2064 print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
2065 }
2066 print "</center>\n";
2067
2068 print '<input type="hidden" name="page_y">'."\n";
2069
2070 print "</form><br>\n";
2071
2072 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
2073 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
2074 print '<script type="text/javascript">';
2075 print 'jQuery(document).ready(function () {';
2076 print ' $(document).on("keypress", \'#ticket\', function (e) { /* Note this is called at every key pressed ! */
2077 var code = e.keyCode || e.which;
2078 if (code == 13) {
2079 console.log("Enter was intercepted and blocked");
2080 e.preventDefault();
2081 return false;
2082 }
2083 });';
2084 print '})';
2085 print '</script>';
2086 }
2087
2088 print "<!-- End message_form TICKET -->\n";
2089 }
2090}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
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:476
$object ref
Definition info.php:90
Class to manage a WYSIWYG editor.
Class to manage standard extra fields.
Class to generate HTML forms for single email Usage: $formai = new FormAI($db) $formai->proprietes=1 ...
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 to manage a HTML form to send a unitary email Usage: $formail = new FormMail($db) $formmail->pr...
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)
selectTypesTickets($selected='', $htmlname='tickettype', $filtertype='', $format=0, $empty=0, $noadmininfo=0, $maxlength=0, $morecss='', $multiselect=0, $disabledefault=0)
Return html list of tickets type.
static checkRequiredFields(array $fields, int &$errors)
Check required fields.
showMessageForm($width='40%', $fromPublicInterface=0)
Show the form to add message on ticket.
__construct($db)
Constructor.
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.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0, $indexdatabase=1, $nolog=0, $level=0)
Remove a directory $dir and its subdirectories (or only files and subdirectories)
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
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.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
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.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
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.
getDolGlobalString($key, $default='')
Return a 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.
multi select button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
Definition html.lib.php:519
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:717
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
Definition html.lib.php:99
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='', $cssfordropdown='info_admin')
Show information in HTML for admin users or standard users.
dolPrintHTMLForAttributeUrl($s)
Return a string ready to be output on a href attribute (this one need a special because we need conte...
Definition html.lib.php:122
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...
Definition html.lib.php:172
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
Class to generate the form for creating a new ticket.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
getMaxFileSizeArray()
Return the max allowed for file upload.