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-2026 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 class="tdtop"><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span></label></td><td class="tdtop">';
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
574 // Add layout and AI tools for message (only for backoffice users)
575 if (!$this->ispublic) {
576 $out = '';
577 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
578 $formmail = new FormMail($this->db);
579 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formai.class.php';
580 $formai = new FormAI($this->db);
581
582 $formmail->withfckeditor = $ckeditorenabledforticket ? 1 : 0;
583 //$formmail->withlayout = ($ckeditorenabledforticket) ? 'email' : '';
584 $formmail->withaiprompt = (isModEnabled('ai')) ? 'text' : '';
585
586 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
587 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
588 $showlinktoai = ($formmail->withaiprompt ? 'textgenerationemail' : '');
589 $showlinktoailabel = $langs->trans("AIEnhancements");
590 $htmlname = 'message';
591
592 $formai->substit = $this->substit;
593
594 // Fill $out
595 $db = $this->db;
596 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
597 print $out;
598 print '<br>';
599 }
600
601 if (!$ckeditorenabledforticket) {
602 $msg = dol_string_nohtmltag($msg, 2);
603 }
604 $doleditor = new DolEditor('message', $msg, '100%', 230, $toolbarname, 'In', true, $uselocalbrowser, $ckeditorenabledforticket, ROWS_8, '90%');
605 $doleditor->Create();
606 print '</td></tr>';
607
608 // Categories
609 if (isModEnabled('category') && !$public) {
610 // Categories
611 print '<tr><td class="wordbreak">'.$langs->trans("Categories").'</td><td>';
612 print $form->selectCategories(Categorie::TYPE_TICKET, 'categories', $object);
613 print "</td></tr>";
614 }
615
616 // Attached files
617 if (!empty($this->withfile)) {
618 // Define list of attached files
619 $listofpaths = array();
620 $listofnames = array();
621 $listofmimes = array();
622 if (!empty($_SESSION["listofpaths"])) {
623 $listofpaths = explode(';', $_SESSION["listofpaths"]);
624 }
625
626 if (!empty($_SESSION["listofnames"])) {
627 $listofnames = explode(';', $_SESSION["listofnames"]);
628 }
629
630 if (!empty($_SESSION["listofmimes"])) {
631 $listofmimes = explode(';', $_SESSION["listofmimes"]);
632 }
633
634 $out = '<tr>';
635 $out .= '<td>';
636 $out .= $langs->trans("LinkedFiles");
637 $out .='</td>';
638 $out .= '<td>';
639 // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
640 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
641 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
642 $out .= 'jQuery(document).ready(function () {';
643 $out .= ' jQuery(".removedfile").click(function() {';
644 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
645 $out .= ' });';
646 $out .= '})';
647 $out .= '</script>'."\n";
648 if (count($listofpaths)) {
649 foreach ($listofpaths as $key => $val) {
650 $out .= '<div id="attachfile_'.$key.'">';
651 $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
652 if (!$this->withfilereadonly) {
653 $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.'" />';
654 }
655 $out .= '<br></div>';
656 }
657 }
658 if ($this->withfile == 2) { // Can add other files
659 $maxfilesizearray = getMaxFileSizeArray();
660 $maxmin = $maxfilesizearray['maxmin'];
661 if ($maxmin > 0) {
662 $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
663 }
664 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
665 $out .= ' ';
666 $out .= '<input type="submit" class="button smallpaddingimp reposition" id="addfile" name="addfile" value="'.$langs->trans("MailingAddFile").'" />';
667 }
668 $out .= "</td></tr>\n";
669
670 // Improves user experience and prevents human error when creating tickets; files do not load.
671 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
672 jQuery(document).ready(function () {
673 jQuery("#addedfile").on("change", function() {
674 // Dispara el clic automáticamente al seleccionar archivo
675 jQuery("#addfile").click();
676 });
677 // Oculta el botón redundante si JS está activo
678 jQuery("#addfile").hide();
679 });
680 </script>';
681
682 print $out;
683 }
684
685 // User of creation
686 if ($this->withusercreate > 0 && $this->fk_user_create) {
687 print '<tr><td class="titlefield">'.$langs->trans("CreatedBy").'</td><td>';
688 $langs->load("users");
689 $fuser = new User($this->db);
690
691 if ($this->withcreatereadonly) {
692 if ($res = $fuser->fetch($this->fk_user_create)) {
693 print $fuser->getNomUrl(1);
694 }
695 }
696 print ' &nbsp; ';
697 print "</td></tr>\n";
698 }
699
700 // Customer or supplier
701 if ($this->withcompany) {
702 // force company and contact id for external user
703 if (empty($user->socid)) {
704 // Company
705 print '<tr><td class="titlefield">'.$langs->trans("ThirdParty").'</td><td>';
706 $events = array();
707 $events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
708 print img_picto('', 'company', 'class="pictofixedwidth"');
709 print $form->select_company($this->withfromsocid, 'socid', '', 1, 1, 0, $events, 0, 'minwidth200');
710 print '</td></tr>';
711 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
712 $htmlname = 'socid';
713 print '<script nonce="'.getNonce().'" type="text/javascript">
714 $(document).ready(function () {
715 jQuery("#'.$htmlname.'").change(function () {
716 var obj = '.json_encode($events).';
717 $.each(obj, function(key,values) {
718 if (values.method.length) {
719 runJsCodeForEvent'.$htmlname.'(values);
720 }
721 });
722 });
723
724 function runJsCodeForEvent'.$htmlname.'(obj) {
725 console.log("Run runJsCodeForEvent'.$htmlname.'");
726 var id = $("#'.$htmlname.'").val();
727 var method = obj.method;
728 var url = obj.url;
729 var htmlname = obj.htmlname;
730 var showempty = obj.showempty;
731 $.getJSON(url,
732 {
733 action: method,
734 id: id,
735 htmlname: htmlname,
736 showempty: showempty
737 },
738 function(response) {
739 $.each(obj.params, function(key,action) {
740 if (key.length) {
741 var num = response.num;
742 if (num > 0) {
743 $("#" + key).removeAttr(action);
744 } else {
745 $("#" + key).attr(action, action);
746 }
747 }
748 });
749 $("select#" + htmlname).html(response.value);
750 if (response.num) {
751 var selecthtml_str = response.value;
752 var selecthtml_dom=$.parseHTML(selecthtml_str);
753 if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
754 $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
755 }
756 } else {
757 $("#inputautocomplete"+htmlname).val("");
758 }
759 $("select#" + htmlname).change(); /* Trigger event change */
760 }
761 );
762 }
763 });
764 </script>';
765 }
766 if ($mode == 'create') {
767 // Contact and type
768 print '<tr><td>'.$langs->trans("Contact").'</td><td>';
769 // If no socid, set to -1 to avoid full contacts list
770 $selectedCompany = ($this->withfromsocid > 0) ? $this->withfromsocid : -1;
771 print img_picto('', 'contact', 'class="pictofixedwidth"');
772 // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
773 print $form->select_contact($selectedCompany, $this->withfromcontactid, 'contactid', 3, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
774
775 print ' ';
776 $formcompany->selectTypeContact($ticketstatic, '', 'type', 'external', '', 0, 'maginleftonly maxwidth200');
777 print '</td></tr>';
778 }
779 } else {
780 print '<tr><td class="titlefield"><input type="hidden" name="socid" value="'.$user->socid.'"/></td>';
781 print '<td><input type="hidden" name="contactid" value="'.$user->contact_id.'"/></td>';
782 print '<td><input type="hidden" name="type" value="Z"/></td></tr>';
783 }
784
785 // Notify thirdparty at creation
786 if (empty($this->ispublic) && ($action == 'create' || $action == 'presend')) {
787 print '<tr><td><label for="notify_tiers_at_create">'.$langs->trans("TicketNotifyTiersAtCreation").'</label></td><td>';
788 print '<input type="checkbox" id="notify_tiers_at_create" name="notify_tiers_at_create"'.($this->withnotifytiersatcreate ? ' checked="checked"' : '').'>';
789 print '</td></tr>';
790 }
791
792 // User assigned
793 print '<tr><td>';
794 print $langs->trans("AssignedTo");
795 print '</td><td>';
796 if ($permissiontomanage) {
797 print img_picto('', 'user', 'class="pictofixedwidth"');
798 print $form->select_dolusers($user_assign, 'fk_user_assign', 1);
799 } else {
800 $userstat = new User($this->db);
801 $userstat->fetch($user_assign);
802 print $userstat->getNomUrl(-1);
803 }
804 print '</td>';
805 print '</tr>';
806 }
807
808 if ($subelement != 'project') {
809 if (isModEnabled('project') && !$this->ispublic) {
810 $formproject = new FormProjets($this->db);
811 print '<tr><td><label for="project"><span class="">'.$langs->trans("Project").'</span></label></td><td>';
812 print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects(-1, $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
813 print '</td></tr>';
814 }
815 }
816
817 if ($subelement != 'contract' && $subelement != 'contrat') {
818 if (getDolGlobalString('TICKET_LINK_TO_CONTRACT_WITH_HARDLINK')) {
819 // Deprecated. Duplicate feature. Ticket can already be linked to contract with the generic "Link to" feature.
820 if (isModEnabled('contract') && !$this->ispublic) {
821 // 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
822 // So we add a hidden option to avoid to have it used and the application locked, until the select_contract is fixed.
823 if (getDolGlobalString("CONTRACT_CAN_USE_THE_BUGGED_SELECT_COMPONENT")) {
824 $langs->load('contracts');
825 $formcontract = new FormContract($this->db);
826 print '<tr><td><label for="contract"><span class="">'.$langs->trans("Contract").'</span></label></td><td>';
827 print img_picto('', 'contract', 'class="pictofixedwidth"');
828 // socid is for internal users null and not 0 or -1
829 print $formcontract->select_contract($user->socid ?? -1, GETPOSTINT('contractid'), 'contractid', 0, 1, 1, 1);
830 print '</td></tr>';
831 }
832 }
833 }
834 }
835
836 // Other attributes
837 $parameters = array();
838 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $ticketstat, $action); // Note that $action and $object may have been modified by hook
839 if (empty($reshook)) {
840 if ($mode == 'create') {
841 print $object->showOptionals($extrafields, 'create');
842 } else {
843 print $object->showOptionals($extrafields, 'edit');
844 }
845 }
846
847 // Show line with Captcha
848 $captcha = '';
849 if ($public && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) {
850 print '<tr><td class="titlefield"></td><td><br>';
851
852 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
853 $captcha = getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_HANDLER', 'standard');
854
855 // List of directories where we can find captcha handlers
856 $dirModCaptcha = array_merge(array('main' => '/core/modules/security/captcha/'), is_array($conf->modules_parts['captcha']) ? $conf->modules_parts['captcha'] : array());
857
858 $fullpathclassfile = '';
859 foreach ($dirModCaptcha as $dir) {
860 $fullpathclassfile = dol_buildpath($dir."modCaptcha".ucfirst($captcha).'.class.php', 0, 2);
861 if ($fullpathclassfile) {
862 break;
863 }
864 }
865
866 if ($fullpathclassfile) {
867 include_once $fullpathclassfile;
868 $captchaobj = null;
869
870 // Charging the numbering class
871 $classname = "modCaptcha".ucfirst($captcha);
872 if (class_exists($classname)) {
874 $captchaobj = new $classname($this->db, $conf, $langs, $user);
875 '@phan-var-force ModeleCaptcha $captchaobj';
876
877 if (is_object($captchaobj) && method_exists($captchaobj, 'getCaptchaCodeForForm')) {
878 print $captchaobj->getCaptchaCodeForForm(''); // @phan-suppress-current-line PhanUndeclaredMethod
879 } else {
880 print 'Error, the captcha handler '.get_class($captchaobj).' does not have any method getCaptchaCodeForForm()';
881 }
882 } else {
883 print 'Error, the captcha handler class '.$classname.' was not found after the include';
884 }
885 } else {
886 print 'Error, the captcha handler '.$captcha.' has no class file found modCaptcha'.ucfirst($captcha);
887 }
888
889 print '<br></td></tr>';
890 }
891
892 print '</table>';
893
894 if ($withdolfichehead) {
895 print dol_get_fiche_end();
896 } else {
897 print '<br><br>';
898 }
899
900 if ($mode == 'create') {
901 print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "CreateTicket"), ($this->withcancel ? "Cancel" : ""));
902 } else {
903 print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "Save"), ($this->withcancel ? "Cancel" : ""));
904 }
905
906 print '<br>';
907
908 /*
909 print '<div class="center">';
910 print '<input type="submit" class="button" name="add" value="'.$langs->trans(($this->withreadid > 0 ? "SendResponse" : "CreateTicket")).'" />';
911 if ($this->withcancel) {
912 print " &nbsp; &nbsp; &nbsp;";
913 print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
914 }
915 print '</div>';
916 */
917
918 print '<input type="hidden" name="page_y">'."\n";
919
920 print "</form>\n";
921 print "<!-- End form TICKET -->\n";
922 }
923
939 public function selectTypesTickets($selected = '', $htmlname = 'tickettype', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $multiselect = 0, $disabledefault = 0)
940 {
941 global $langs, $user;
942
943 $selected = is_array($selected) ? $selected : (!empty($selected) ? explode(',', $selected) : array());
944 $ticketstat = new Ticket($this->db);
945
946 dol_syslog(get_class($this) . "::select_types_tickets " . implode(';', $selected) . ", " . $htmlname . ", " . $filtertype . ", " . $format . ", " . $multiselect, LOG_DEBUG);
947
948 $filterarray = array();
949
950 if ($filtertype != '' && $filtertype != '-1') {
951 $filterarray = explode(',', $filtertype);
952 }
953
954 $ticketstat->loadCacheTypesTickets();
955
956 print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.($multiselect ? '[]' : '').'"'.($multiselect ? ' multiple' : '').'>';
957 if ($empty && !$multiselect) {
958 print '<option value="">'.((is_numeric($empty) || $empty == 'ifone') ? '&nbsp;' : $empty).'</option>';
959 }
960
961 if (is_array($ticketstat->cache_types_tickets) && count($ticketstat->cache_types_tickets)) {
962 foreach ($ticketstat->cache_types_tickets as $id => $arraytypes) {
963 // We stop if we astto filter on some ticket type and code is not one requested.
964 if (count($filterarray) && !in_array($arraytypes['code'], $filterarray)) {
965 continue;
966 }
967
968 // If 'showempty' is enabled we discard empty line because an empty line has already been output.
969 if ($empty && empty($arraytypes['code'])) {
970 continue;
971 }
972
973 if ($format == 0) {
974 print '<option value="'.$id.'"';
975 }
976
977 if ($format == 1) {
978 print '<option value="'.$arraytypes['code'].'"';
979 }
980
981 if ($format == 2) {
982 print '<option value="'.$arraytypes['code'].'"';
983 }
984
985 if ($format == 3) {
986 print '<option value="'.$id.'"';
987 }
988
989 // If text is selected, we compare with code, otherwise with id
990 if (in_array($arraytypes['code'], $selected)) {
991 print ' selected="selected"';
992 } elseif (in_array($id, $selected)) {
993 print ' selected="selected"';
994 } elseif ($arraytypes['use_default'] == "1" && empty($disabledefault) && empty($selected) && !$multiselect) {
995 print ' selected="selected"';
996 } elseif (count($ticketstat->cache_types_tickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it
997 print ' selected="selected"';
998 }
999
1000 print '>';
1001
1002 $value = '&nbsp;';
1003 if ($format == 0) {
1004 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
1005 } elseif ($format == 1) {
1006 $value = $arraytypes['code'];
1007 } elseif ($format == 2) {
1008 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
1009 } elseif ($format == 3) {
1010 $value = $arraytypes['code'];
1011 }
1012
1013 print $value ? $value : '&nbsp;';
1014 print '</option>';
1015 }
1016 }
1017 print '</select>';
1018 if (isset($user->admin) && $user->admin && !$noadmininfo) {
1019 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1020 }
1021
1022 print ajax_combobox('select'.$htmlname);
1023 }
1024
1040 public function selectGroupTickets($selected = '', $htmlname = 'ticketcategory', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $use_multilevel = 0, $outputlangs = null)
1041 {
1042 global $conf, $langs, $user;
1043
1044 dol_syslog(get_class($this)."::selectCategoryTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
1045
1046 if (is_null($outputlangs) || !is_object($outputlangs)) {
1047 $outputlangs = $langs;
1048 }
1049 $outputlangs->load("ticket");
1050
1051 $publicgroups = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
1052
1053 $ticketstat = new Ticket($this->db);
1054 $ticketstat->loadCacheCategoriesTickets($publicgroups ? 1 : -1); // get list of active ticket groups
1055
1056 if ($use_multilevel <= 0) { // Only one combo list to select the group of ticket (default)
1057 print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
1058 if ($empty) {
1059 print '<option value="">'.((is_numeric($empty) || $empty == 'ifone') ? '&nbsp;' : $empty).'</option>';
1060 }
1061
1062 $categorytickets = $conf->cache['category_tickets'];
1063 '@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';
1064 if (is_array($categorytickets) && count($categorytickets)) {
1065 foreach ($categorytickets as $id => $arraycategories) {
1066 // Exclude some record
1067 if ($publicgroups) {
1068 if (empty($arraycategories['public'])) {
1069 continue;
1070 }
1071 }
1072
1073 // We discard empty line if showempty is on because an empty line has already been output.
1074 if ($empty && empty($arraycategories['code'])) {
1075 continue;
1076 }
1077
1078 $label = ($arraycategories['label'] != '-' ? $arraycategories['label'] : '');
1079 if ($outputlangs->trans("TicketCategoryShort".$arraycategories['code']) != "TicketCategoryShort".$arraycategories['code']) {
1080 $label = $outputlangs->trans("TicketCategoryShort".$arraycategories['code']);
1081 } elseif ($outputlangs->trans($arraycategories['code']) != $arraycategories['code']) {
1082 $label = $outputlangs->trans($arraycategories['code']);
1083 }
1084
1085 if ($format == 0) {
1086 print '<option value="'.$id.'"';
1087 }
1088
1089 if ($format == 1) {
1090 print '<option value="'.$arraycategories['code'].'"';
1091 }
1092
1093 if ($format == 2) {
1094 print '<option value="'.$arraycategories['code'].'"';
1095 }
1096
1097 if ($format == 3) {
1098 print '<option value="'.$id.'"';
1099 }
1100
1101 // If selected is text, we compare with code, otherwise with id
1102 if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arraycategories['code']) {
1103 print ' selected="selected"';
1104 } elseif (isset($selected) && $selected == $id) {
1105 print ' selected="selected"';
1106 } elseif ($arraycategories['use_default'] == "1" && empty($selected) && (!$empty || $empty == 'ifone')) {
1107 print ' selected="selected"';
1108 } elseif (count($categorytickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it
1109 print ' selected="selected"';
1110 }
1111
1112 print '>';
1113
1114 $value = '';
1115 if ($format == 0) {
1116 $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
1117 }
1118
1119 if ($format == 1) {
1120 $value = $arraycategories['code'];
1121 }
1122
1123 if ($format == 2) {
1124 $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
1125 }
1126
1127 if ($format == 3) {
1128 $value = $arraycategories['code'];
1129 }
1130
1131 print $value ? $value : '&nbsp;';
1132 print '</option>';
1133 }
1134 }
1135 print '</select>';
1136 if (isset($user->admin) && $user->admin && !$noadmininfo) {
1137 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1138 }
1139
1140 print ajax_combobox('select'.$htmlname);
1141 } elseif ($htmlname != '') { // complexe mode using selection of group using a combo for each level (when using a hierarchy of groups).
1142 $selectedgroups = array();
1143 $groupvalue = "";
1144 $groupticket = GETPOST($htmlname, 'aZ09');
1145 $child_id = GETPOST($htmlname.'_child_id', 'aZ09') ? GETPOST($htmlname.'_child_id', 'aZ09') : 0;
1146 if (!empty($groupticket)) {
1147 $tmpgroupticket = $groupticket;
1148 $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code";
1149 $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc WHERE ctc.code = '".$this->db->escape($tmpgroupticket)."'";
1150 $resql = $this->db->query($sql);
1151 if ($resql) {
1152 $obj = $this->db->fetch_object($resql);
1153 $selectedgroups[] = $obj->code;
1154 while ($obj->fk_parent > 0) {
1155 $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)."'";
1156 $resql = $this->db->query($sql);
1157 if ($resql) {
1158 $obj = $this->db->fetch_object($resql);
1159 $selectedgroups[] = $obj->code;
1160 }
1161 }
1162 }
1163 }
1164
1165 $arrayidused = array();
1166 $arrayidusedconcat = array();
1167 $arraycodenotparent = array();
1168 $arraycodenotparent[] = "";
1169
1170 $stringtoprint = '<span class="supportemailfield bold">'.$langs->trans("GroupOfTicket").'</span> ';
1171 $stringtoprint .= '<select id="'.$htmlname.'" class="minwidth500" child_id="0">';
1172 $stringtoprint .= '<option value="">&nbsp;</option>';
1173
1174 $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ";
1175 $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";
1176 $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
1177 $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
1178 $public = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
1179 if ($public) {
1180 $sql .= " AND ctc.public = 1";
1181 }
1182 $sql .= " AND ctc.fk_parent = 0";
1183 $sql .= $this->db->order('ctc.pos', 'ASC');
1184
1185 $resql = $this->db->query($sql);
1186 if ($resql) {
1187 $num_rows_level0 = $this->db->num_rows($resql);
1188 $i = 0;
1189 while ($i < $num_rows_level0) {
1190 $obj = $this->db->fetch_object($resql);
1191 if ($obj) {
1192 $label = ($obj->label != '-' ? $obj->label : '');
1193 if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
1194 $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
1195 } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1196 $label = $outputlangs->trans($obj->code);
1197 }
1198
1199 $grouprowid = $obj->rowid;
1200 $groupvalue = $obj->code;
1201 $grouplabel = $label;
1202
1203 $isparent = $obj->isparent;
1204 if (is_array($selectedgroups)) {
1205 $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1206 } else {
1207 $iselected = $groupticket == $obj->code ? 'selected' : '';
1208 }
1209 $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>';
1210 if ($isparent == 'NOTPARENT') {
1211 $arraycodenotparent[] = $groupvalue;
1212 }
1213 $arrayidused[] = $grouprowid;
1214 $arrayidusedconcat[] = $grouprowid;
1215 }
1216 $i++;
1217 }
1218 } else {
1219 dol_print_error($this->db);
1220 }
1221 if (count($arrayidused) == 1) {
1222 return '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.dol_escape_htmltag($groupvalue).'">';
1223 } else {
1224 $stringtoprint .= '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'_select" class="maxwidth500 minwidth400" value="'.GETPOST($htmlname).'">';
1225 $stringtoprint .= '<input type="hidden" name="'.$htmlname.'_child_id" id="'.$htmlname.'_select_child_id" class="maxwidth500 minwidth400" '.GETPOST($htmlname).' value="'.GETPOST($htmlname."_child_id").'">';
1226 }
1227 $stringtoprint .= '</select>&nbsp;';
1228
1229 $levelid = 1; // The first combobox
1230 while ($levelid <= $use_multilevel) { // Loop to take the child of the combo
1231 $tabscript = array();
1232 $stringtoprint .= '<select id="'.$htmlname.'_child_'.$levelid.'" class="maxwidth500 minwidth400 groupticketchild" child_id="'.$levelid.'">';
1233 $stringtoprint .= '<option value="">&nbsp;</option>';
1234
1235 $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ctcjoin.code as codefather";
1236 $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
1237 $sql .= " JOIN ".$this->db->prefix()."c_ticket_category as ctcjoin ON ctc.fk_parent = ctcjoin.rowid";
1238 $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
1239 $sql .= " AND ctc.rowid NOT IN (".$this->db->sanitize(implode(',', $arrayidusedconcat)).")";
1240
1241 $public = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
1242 if ($public) {
1243 $sql .= " AND ctc.public = 1";
1244 }
1245 // Add a test to take only record that are direct child
1246 if (!empty($arrayidused)) {
1247 $sql .= " AND ctc.fk_parent IN ( ";
1248 foreach ($arrayidused as $idused) {
1249 $sql .= ((int) $idused).", ";
1250 }
1251 $sql = substr($sql, 0, -2);
1252 $sql .= ")";
1253 }
1254 $sql .= $this->db->order('ctc.pos', 'ASC');
1255
1256 $resql = $this->db->query($sql);
1257 if ($resql) {
1258 $num_rows = $this->db->num_rows($resql);
1259 $i = 0;
1260 $arrayidused = array();
1261 while ($i < $num_rows) {
1262 $obj = $this->db->fetch_object($resql);
1263 if ($obj) {
1264 $label = ($obj->label != '-' ? $obj->label : '');
1265 if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
1266 $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
1267 } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1268 $label = $outputlangs->trans($obj->code);
1269 }
1270
1271 $grouprowid = $obj->rowid;
1272 $groupvalue = $obj->code;
1273 $grouplabel = $label;
1274 $isparent = $obj->isparent;
1275 $fatherid = $obj->fk_parent;
1276 $arrayidused[] = $grouprowid;
1277 $arrayidusedconcat[] = $grouprowid;
1278 $groupcodefather = $obj->codefather;
1279 if ($isparent == 'NOTPARENT') {
1280 $arraycodenotparent[] = $groupvalue;
1281 }
1282 if (is_array($selectedgroups)) {
1283 $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1284 } else {
1285 $iselected = $groupticket == $obj->code ? 'selected' : '';
1286 }
1287 $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>';
1288 if (empty($tabscript[$groupcodefather])) {
1289 $tabscript[$groupcodefather] = 'if ($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").val() == \''.dol_escape_js($groupcodefather).'\'){
1290 $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").show()
1291 console.log("We show child tickets of '.$groupcodefather.' group ticket")
1292 }else{
1293 $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").hide()
1294 console.log("We hide child tickets of '.$groupcodefather.' group ticket")
1295 }';
1296 }
1297 }
1298 $i++;
1299 }
1300 } else {
1301 dol_print_error($this->db);
1302 }
1303 $stringtoprint .= '</select>';
1304
1305 $stringtoprint .= '<script nonce="'.getNonce().'">';
1306 $stringtoprint .= 'arraynotparents = '.json_encode($arraycodenotparent).';'; // when the last visible combo list is number x, this is the array of group
1307 $stringtoprint .= 'if (arraynotparents.includes($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").val())){
1308 console.log("'.$htmlname.'_child_'.$levelid.'")
1309 if($("#'.$htmlname.'_child_'.$levelid.'").val() == "" && ($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")>'.$child_id.')){
1310 $("#'.$htmlname.'_child_'.$levelid.'").hide();
1311 console.log("We hide '.$htmlname.'_child_'.$levelid.' input")
1312 }
1313 if(arraynotparents.includes("'.$groupticket.'") && '.$child_id.' == 0){
1314 $("#ticketcategory_select_child_id").val($("#'.$htmlname.'").attr("child_id"))
1315 $("#ticketcategory_select").val($("#'.$htmlname.'").val()) ;
1316 console.log("We choose '.$htmlname.' input and reload hidden input");
1317 }
1318 }
1319 $("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid - 1) : '').'").change(function() {
1320 child_id = $("#'.$htmlname.($levelid > 1 ? '_child_'.$levelid : '').'").attr("child_id");
1321
1322 /* Change of value to select this value*/
1323 if (arraynotparents.includes($(this).val()) || $(this).attr("child_id") == '.$use_multilevel.') {
1324 $("#ticketcategory_select").val($(this).val());
1325 $("#ticketcategory_select_child_id").val($(this).attr("child_id")) ;
1326 console.log("We choose to select "+ $(this).val());
1327 }else{
1328 if ($("#'.$htmlname.'_child_'.$levelid.' option").length <= 1) {
1329 $("#ticketcategory_select").val($(this).val());
1330 $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1331 console.log("We choose to select "+ $(this).val() + " and next combo has no item, so we keep this selection");
1332 } else {
1333 console.log("We choose to select "+ $(this).val() + " but next combo has some item, so we clean selected item");
1334 $("#ticketcategory_select").val("");
1335 $("#ticketcategory_select_child_id").val("");
1336 }
1337 }
1338
1339 console.log("We select a new value into combo child_id="+child_id);
1340
1341 // Hide all selected box that are child of the one modified
1342 $(".groupticketchild").each(function(){
1343 if ($(this).attr("child_id") > child_id) {
1344 console.log("hide child_id="+$(this).attr("child_id"));
1345 $(this).val("");
1346 $(this).hide();
1347 }
1348 })
1349
1350 // Now we enable the next combo
1351 $("#'.$htmlname.'_child_'.$levelid.'").val("");
1352 if (!arraynotparents.includes($(this).val()) && $("#'.$htmlname.'_child_'.$levelid.' option").length > 1) {
1353 console.log($("#'.$htmlname.'_child_'.$levelid.' option").length);
1354 $("#'.$htmlname.'_child_'.$levelid.'").show()
1355 } else {
1356 $("#'.$htmlname.'_child_'.$levelid.'").hide()
1357 }
1358 ';
1359 $levelid++;
1360 foreach ($tabscript as $script) {
1361 $stringtoprint .= $script;
1362 }
1363 $stringtoprint .= '})';
1364 $stringtoprint .= '</script>';
1365 }
1366 $stringtoprint .= '<script nonce="'.getNonce().'">';
1367 $stringtoprint .= '$("#'.$htmlname.'_child_'.$use_multilevel.'").change(function() {
1368 $("#ticketcategory_select").val($(this).val());
1369 $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1370 tmpvalselect = $("#ticketcategory_select").val();
1371 if(tmpvalselect == "" && $("#ticketcategory_select_child_id").val() >= 1){
1372 $("#ticketcategory_select_child_id").val($(this).attr("child_id")-1);
1373 }
1374 console.log($("#ticketcategory_select").val());
1375 })';
1376 $stringtoprint .= '</script>';
1377 $stringtoprint .= ajax_combobox($htmlname);
1378
1379 return $stringtoprint;
1380 }
1381 }
1382
1396 public function selectSeveritiesTickets($selected = '', $htmlname = 'ticketseverity', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '')
1397 {
1398 global $conf, $langs, $user;
1399
1400 $ticketstat = new Ticket($this->db);
1401
1402 dol_syslog(get_class($this)."::selectSeveritiesTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
1403
1404 $filterarray = array();
1405
1406 if ($filtertype != '' && $filtertype != '-1') {
1407 $filterarray = explode(',', $filtertype);
1408 }
1409
1410 $ticketstat->loadCacheSeveritiesTickets();
1411
1412 print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
1413 if ($empty) {
1414 print '<option value="">'.((is_numeric($empty) || $empty == 'ifone') ? '&nbsp;' : $empty).'</option>';
1415 }
1416
1417 $severitytickets = $conf->cache['severity_tickets'];
1418 '@phan-var-force array<int,array{code:string,label:string,use_default:int,pos:int}> $severitytickets';
1419 if (is_array($severitytickets) && count($severitytickets)) {
1420 foreach ($severitytickets as $id => $arrayseverities) {
1421 // Skip if filtering on specific payment modes was requested
1422 if (count($filterarray) && !in_array($arrayseverities['code'], $filterarray)) {
1423 continue;
1424 }
1425
1426 // We discard empty line if showempty is on because an empty line has already been output.
1427 if ($empty && empty($arrayseverities['code'])) {
1428 continue;
1429 }
1430
1431 if ($format == 0) {
1432 print '<option value="'.$id.'"';
1433 }
1434
1435 if ($format == 1) {
1436 print '<option value="'.$arrayseverities['code'].'"';
1437 }
1438
1439 if ($format == 2) {
1440 print '<option value="'.$arrayseverities['code'].'"';
1441 }
1442
1443 if ($format == 3) {
1444 print '<option value="'.$id.'"';
1445 }
1446
1447 // If text is selected, we compare with code, otherwise with id
1448 if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arrayseverities['code']) {
1449 print ' selected="selected"';
1450 } elseif (isset($selected) && $selected == $id) {
1451 print ' selected="selected"';
1452 } elseif ($arrayseverities['use_default'] == "1" && empty($selected) && (!$empty || $empty == 'ifone')) {
1453 print ' selected="selected"';
1454 } elseif (count($severitytickets) == 1 && (!$empty || $empty == 'ifone')) { // If only 1 choice, we autoselect it
1455 print ' selected="selected"';
1456 }
1457
1458 print '>';
1459
1460 $value = '';
1461 if ($format == 0) {
1462 $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1463 }
1464
1465 if ($format == 1) {
1466 $value = $arrayseverities['code'];
1467 }
1468
1469 if ($format == 2) {
1470 $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1471 }
1472
1473 if ($format == 3) {
1474 $value = $arrayseverities['code'];
1475 }
1476
1477 print $value ? $value : '&nbsp;';
1478 print '</option>';
1479 }
1480 }
1481 print '</select>';
1482 if (isset($user->admin) && $user->admin && !$noadmininfo) {
1483 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1484 }
1485
1486 print ajax_combobox('select'.$htmlname);
1487 }
1488
1489 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1495 public function clear_attached_files()
1496 {
1497 // phpcs:enable
1498 global $conf, $user;
1499 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1500
1501 // Set tmp user directory
1502 $vardir = $conf->user->dir_output."/".$user->id;
1503 $upload_dir = $vardir.'/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
1504 if (is_dir($upload_dir)) {
1505 dol_delete_dir_recursive($upload_dir);
1506 }
1507
1508 if (!empty($this->trackid)) { // TODO Always use trackid (ticXXX) instead of track_id (abcd123)
1509 $keytoavoidconflict = '-'.$this->trackid;
1510 } else {
1511 $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id;
1512 }
1513 unset($_SESSION["listofpaths".$keytoavoidconflict]);
1514 unset($_SESSION["listofnames".$keytoavoidconflict]);
1515 unset($_SESSION["listofmimes".$keytoavoidconflict]);
1516 }
1517
1525 public function showMessageForm($width = '40%', $fromPublicInterface = 0)
1526 {
1527 global $conf, $langs, $user, $hookmanager, $form;
1528
1529 $formmail = new FormMail($this->db);
1530 $addfileaction = 'addfile';
1531
1532 if (!is_object($form)) {
1533 $form = new Form($this->db);
1534 }
1535
1536 // Load translation files required by the page
1537 $langs->loadLangs(array('other', 'mails', 'ticket'));
1538
1539 // Clear temp files. Must be done at beginning, before call of triggers
1540 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1541 $this->clear_attached_files();
1542 }
1543
1544 // Define output language
1545 $outputlangs = $langs;
1546 $newlang = '';
1547 if (getDolGlobalInt('MAIN_MULTILANGS') && isset($this->param['langsmodels'])) {
1548 $newlang = $this->param['langsmodels'];
1549 }
1550 if (!empty($newlang)) {
1551 $outputlangs = new Translate("", $conf);
1552 $outputlangs->setDefaultLang($newlang);
1553 $outputlangs->load('other');
1554 }
1555
1556 // Get message template for $this->param["models"] into c_email_templates
1557 $arraydefaultmessage = -1;
1558 if (isset($this->param['models']) && $this->param['models'] != 'none') {
1559 $model_id = 0;
1560 if (array_key_exists('models_id', $this->param)) {
1561 $model_id = (int) $this->param["models_id"];
1562 }
1563
1564 // If $model_id is empty, preselect the first one
1565 $usedefault = ($model_id ? -1 : 1);
1566 $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id, 1, '', $usedefault);
1567 if (isset($arraydefaultmessage->id) && empty($model_id)) {
1568 $model_id = $arraydefaultmessage->id;
1569 $this->param['models_id'] = $model_id;
1570 }
1571 }
1572
1573 // Define list of attached files
1574 $listofpaths = array();
1575 $listofnames = array();
1576 $listofmimes = array();
1577
1578 if (!empty($this->trackid)) {
1579 $keytoavoidconflict = '-'.$this->trackid;
1580 } else {
1581 $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
1582 }
1583 //var_dump($keytoavoidconflict);
1584 if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1585 if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
1586 foreach ($this->param['fileinit'] as $path) {
1587 $formmail->add_attached_files($path, basename($path), dol_mimetype($path));
1588 }
1589 }
1590 }
1591 //var_dump($_SESSION);
1592 //var_dump($_SESSION["listofpaths".$keytoavoidconflict]);
1593 if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
1594 $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
1595 }
1596 if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
1597 $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
1598 }
1599 if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
1600 $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
1601 }
1602
1603 // Define output language
1604 $outputlangs = $langs;
1605 $newlang = '';
1606 if (getDolGlobalInt('MAIN_MULTILANGS') && isset($this->param['langsmodels'])) {
1607 $newlang = $this->param['langsmodels'];
1608 }
1609 if (!empty($newlang)) {
1610 $outputlangs = new Translate("", $conf);
1611 $outputlangs->setDefaultLang($newlang);
1612 $outputlangs->load('other');
1613 }
1614
1615 print "\n<!-- Begin message_form TICKET -->\n";
1616
1617 $send_email = GETPOSTINT('send_email') ? GETPOSTINT('send_email') : 0;
1618
1619 // Example 1 : Adding jquery code
1620 print '<script nonce="'.getNonce().'" type="text/javascript">
1621 jQuery(document).ready(function() {
1622 send_email='.((int) $send_email).';
1623 if (send_email) {
1624 if (!jQuery("#send_msg_email").is(":checked")) {
1625 jQuery("#send_msg_email").prop("checked", true).trigger("change");
1626 }
1627 jQuery(".email_line").show();
1628 jQuery(".not_email_line").hide();
1629 } else {
1630 if (!jQuery("#private_message").is(":checked")) {
1631 jQuery("#private_message").prop("checked", true).trigger("change");
1632 }
1633 jQuery(".email_line").hide();
1634 jQuery(".not_email_line").show();
1635 }
1636 ';
1637
1638 // If constant set, allow to send private messages as email
1639 if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1640 print 'jQuery("#send_msg_email").click(function() {
1641 console.log("Click send_msg_email");
1642 if(jQuery(this).is(":checked")) {
1643 if (jQuery("#private_message").is(":checked")) {
1644 jQuery("#private_message").prop("checked", false).trigger("change");
1645 }
1646 jQuery(".email_line").show();
1647 jQuery(".not_email_line").hide();
1648 }
1649 else {
1650 jQuery(".email_line").hide();
1651 jQuery(".not_email_line").show();
1652 }
1653 });
1654
1655 jQuery("#private_message").click(function() {
1656 console.log("Click private_message");
1657 if (jQuery(this).is(":checked")) {
1658 if (jQuery("#send_msg_email").is(":checked")) {
1659 jQuery("#send_msg_email").prop("checked", false).trigger("change");
1660 }
1661 jQuery(".email_line").hide();
1662 jQuery(".not_email_line").show();
1663 }
1664 });';
1665 }
1666
1667 print '});
1668 </script>';
1669
1670 print '<form method="post" name="ticket" id="ticket" enctype="multipart/form-data" action="'.$this->param["returnurl"].'">';
1671 print '<input type="hidden" name="token" value="'.newToken().'">';
1672 print '<input type="hidden" name="action" value="'.$this->action.'">';
1673 print '<input type="hidden" name="actionbis" value="add_message">';
1674 print '<input type="hidden" name="backtopage" value="'.$this->backtopage.'">';
1675 if (!empty($this->trackid)) {
1676 print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
1677 } else {
1678 print '<input type="hidden" name="trackid" value="'.(empty($this->track_id) ? '' : $this->track_id).'">';
1679 $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
1680 }
1681 foreach ($this->param as $key => $value) {
1682 print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
1683 }
1684
1685 // Get message template
1686 $model_id = 0;
1687 if (array_key_exists('models_id', $this->param)) {
1688 $model_id = $this->param["models_id"];
1689 $usedefault = ($model_id ? -1 : 1);
1690 $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id, 1, '', $usedefault);
1691 }
1692
1693 $result = $formmail->fetchAllEMailTemplate(!empty($this->param["models"]) ? $this->param["models"] : "", $user, $outputlangs);
1694 if ($result < 0) {
1695 setEventMessages($this->error, $this->errors, 'errors');
1696 }
1697 $modelmail_array = array();
1698 foreach ($formmail->lines_model as $line) {
1699 $modelmail_array[$line->id] = $line->label;
1700 }
1701
1702 $ticketstat = new Ticket($this->db);
1703 $res = $ticketstat->fetch(0, '', $this->track_id);
1704
1705 print '<table class="border" width="'.$width.'">';
1706
1707 // External users can't send message email
1708 if ($user->hasRight("ticket", "write") && !$user->socid) {
1709 print '<tr><td class="width200"></td><td>';
1710 $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : (getDolGlobalInt('TICKETS_MESSAGE_FORCE_MAIL') ? 'checked' : ''));
1711 print '<input type="checkbox" name="send_email" value="1" id="send_msg_email" '.$checkbox_selected.'/> ';
1712 print '<label for="send_msg_email">'.$langs->trans('SendMessageByEmail').'</label>';
1713 $texttooltip = $langs->trans("TicketMessageSendEmailHelp");
1714 if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1715 $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2b");
1716 } else {
1717 $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2a", '{s1}');
1718 }
1719 $texttooltip = str_replace('{s1}', $langs->trans('MarkMessageAsPrivate'), $texttooltip);
1720 print ' '.$form->textwithpicto('', $texttooltip, 1, 'help');
1721
1722 // Section to selection email template
1723 if (count($modelmail_array) > 0) {
1724 print ' &nbsp; <span class="email_line">';
1725 print $formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], $langs->trans('SelectMailModel'), 0, 0, "", 0, 0, 0, '', 'minwidth200');
1726 if ($user->admin) {
1727 print info_admin($langs->trans("YouCanChangeValuesForThisListFrom", $langs->transnoentitiesnoconv("Tools").' - '.$langs->transnoentitiesnoconv("EMailTemplates")), 1);
1728 }
1729 print ' &nbsp; ';
1730 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
1731 print '</span>';
1732 }
1733
1734 print '</td></tr>';
1735
1736 // Private message (not visible by customer/external user)
1737 if (!$user->socid) {
1738 print '<tr><td></td><td>';
1739 $checkbox_selected = (GETPOST('private_message', 'alpha') == "1" ? ' checked' : '');
1740 print '<input type="checkbox" name="private_message" value="1" id="private_message" '.$checkbox_selected.'/> ';
1741 print '<label for="private_message">'.$langs->trans('MarkMessageAsPrivate').'</label>';
1742 print ' '.$form->textwithpicto('', $langs->trans("TicketMessagePrivateHelp"), 1, 'help');
1743 print '</td></tr>';
1744 }
1745
1746 // Zone to select its email template
1747 /*
1748 if (count($modelmail_array) > 0) {
1749 print '<tr class="email_line"><td></td><td colspan="2"><div style="padding: 3px 0 3px 0">'."\n";
1750 print $formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], $langs->trans('SelectMailModel'), 0, 0, "", 0, 0, 0, '', 'minwidth200');
1751 if ($user->admin) {
1752 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1753 }
1754 print ' &nbsp; ';
1755 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
1756 print '</div></td>';
1757 }
1758 */
1759
1760 // From (and Reply-To if defined)
1761 $from = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
1762 $replyto = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_REPLYTO');
1763 print '<tr class="email_line"><td class="width200"><span class="">'.$langs->trans("MailFrom");
1764 if ($replyto) {
1765 print ' <span class="opacitymedium">('.$langs->trans("MailReply").')</span>';
1766 }
1767 print '</span></td>';
1768 print '<td><span class="">'.img_picto('', 'email', 'class="pictofixedwidth"').$from;
1769 if ($replyto) {
1770 print ' <span class="opacitymedium">('.$replyto.')</span>';
1771 }
1772 print '</span></td></tr>';
1773
1774 // Recipients / adressed-to
1775 $parameters = array();
1776 $action = '';
1777 $reshook = $hookmanager->executeHooks('printFieldTicketEmailTo', $parameters, $this, $action);
1778 if (empty($reshook)) {
1779 print '<tr class="email_line"><td class="fieldrequired">'.$langs->trans('MailRecipients');
1780 print ' '.$form->textwithpicto('', $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"), 1, 'help');
1781 print '</td><td>';
1782 $withto = array();
1783 if ($res) {
1784 $sendto_free = GETPOSTISSET('sendto') ? GETPOST('sendto', 'alphawithlgt') : '';
1785 print '<input class="minwidth200" id="sendto" name="sendto" spellcheck="false" placeholder="email@domain.com" value="'.dol_escape_htmltag($sendto_free).'" />';
1786
1787 // Build recipient list; keys are email addresses (used directly in newMessage())
1788 $contacts = $ticketstat->getInfosTicketInternalContact(1);
1789 $contacts = array_merge($contacts, $ticketstat->getInfosTicketExternalContact(1));
1790 $seen_emails = array();
1791
1792 if (is_array($contacts) && count($contacts) > 0) {
1793 foreach ($contacts as $info_sendto) {
1794 if ($info_sendto['email'] != '') {
1795 $email_lc = strtolower($info_sendto['email']);
1796 if (!in_array($email_lc, $seen_emails)) {
1797 $label_text = trim($info_sendto['firstname'].' '.$info_sendto['lastname']).' <'.$info_sendto['email'].'>';
1798 $label_html = dol_htmlentities(trim($info_sendto['firstname'].' '.$info_sendto['lastname']), ENT_QUOTES, 'UTF-8')
1799 .' <span class="opacitymedium">('.dol_htmlentities($info_sendto['libelle'], ENT_QUOTES, 'UTF-8').')</span>';
1800 $withto[$info_sendto['email']] = array(
1801 'id' => $info_sendto['email'],
1802 'label' => str_replace(array('<', '>'), array('(', ')'), $label_text),
1803 'labelhtml' => $label_html,
1804 );
1805 $seen_emails[] = $email_lc;
1806 }
1807 }
1808 }
1809 }
1810
1811 if (!empty($ticketstat->origin_replyto) && !in_array(strtolower($ticketstat->origin_replyto), $seen_emails)) {
1812 $email = (string) $ticketstat->origin_replyto;
1813 $withto[$email] = array(
1814 'id' => $email,
1815 'label' => $email,
1816 'labelhtml' => dol_escape_htmltag($email).' <span class="opacitymedium">('.$langs->trans('TicketEmailOriginIssuer').')</span>',
1817 );
1818 $seen_emails[] = strtolower($email);
1819 } elseif ($ticketstat->origin_email && !in_array(strtolower((string) $ticketstat->origin_email), $seen_emails)) {
1820 $email = (string) $ticketstat->origin_email;
1821 $withto[$email] = array(
1822 'id' => $email,
1823 'label' => $email,
1824 'labelhtml' => dol_escape_htmltag($email).' <span class="opacitymedium">('.$langs->trans('TicketEmailOriginIssuer').')</span>',
1825 );
1826 $seen_emails[] = strtolower($email);
1827 }
1828
1829 if ($ticketstat->fk_soc > 0) {
1830 $ticketstat->socid = $ticketstat->fk_soc;
1831 $ticketstat->fetch_thirdparty();
1832 if (!empty($ticketstat->thirdparty->email) && !in_array(strtolower((string) $ticketstat->thirdparty->email), $seen_emails)) {
1833 $email = (string) $ticketstat->thirdparty->email;
1834 $withto[$email] = array(
1835 'id' => $email,
1836 'label' => $email,
1837 'labelhtml' => dol_escape_htmltag($email).' <span class="opacitymedium">('.$langs->trans('Customer').')</span>',
1838 );
1839 $seen_emails[] = strtolower($email);
1840 }
1841 }
1842
1843 if (getDolGlobalInt('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS') && getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO')) {
1844 $generic_email = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO');
1845 if (!in_array(strtolower($generic_email), $seen_emails)) {
1846 $withto[$generic_email] = array(
1847 'id' => $generic_email,
1848 'label' => $generic_email,
1849 'labelhtml' => dol_escape_htmltag($generic_email).' <span class="opacitymedium">(generic)</span>',
1850 );
1851 }
1852 }
1853
1854 // Preselect all contacts on first load; restore POST selection on re-display
1855 if (GETPOSTISSET('receiver_multiselect')) {
1856 $withtoselected = GETPOST('receiver', 'array');
1857 } else {
1858 $withtoselected = array_keys($withto);
1859 }
1860
1861 if (!empty($withto)) {
1862 print ' <span class="opacitymedium">'.$langs->trans("and").'/'.$langs->trans("or").'</span> ';
1863 print $form->multiselectarray('receiver', $withto, $withtoselected, 0, 0, 'inline-block minwidth500', 0, 0, '', '', '', 1);
1864 } else {
1865 // No contacts linked: emit the flag hidden so newMessage() still reads the free sendto input
1866 print '<input type="hidden" name="receiver_multiselect" value="1">';
1867 print ' &nbsp;<span class="opacitymedium"><small>'.$langs->trans('WarningNoEMailsAdded').'</small></span>';
1868 }
1869 }
1870 print '</td></tr>';
1871
1872 print '<tr class="email_line"><td>';
1873 print $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"), 1, 'help');
1874 print '</td><td>';
1875
1876 // Pre-fill with TICKET_SEND_INTERNAL_CC on first load
1877 if (GETPOSTISSET('receivercc_multiselect')) {
1878 $sendtocc_free = GETPOST('sendtocc', 'alphawithlgt');
1879 } else {
1880 $sendtocc_free = getDolGlobalString('TICKET_SEND_INTERNAL_CC');
1881 }
1882 print '<input class="minwidth200" id="sendtocc" name="sendtocc" spellcheck="false" value="'.dol_escape_htmltag($sendtocc_free).'" />';
1883
1884 // Reuse $withto contact list; nothing preselected for CC
1885 if (!empty($withto)) {
1886 print ' <span class="opacitymedium">'.$langs->trans("and").'/'.$langs->trans("or").'</span> ';
1887 $withtocc_selected = GETPOSTISSET('receivercc_multiselect') ? GETPOST('receivercc', 'array') : array();
1888 print $form->multiselectarray('receivercc', $withto, $withtocc_selected, 0, 0, 'inline-block minwidth500', 0, 0, '', '', '', 1);
1889 } else {
1890 // No contacts: emit the flag hidden so newMessage() still reads the free sendtocc input
1891 print '<input type="hidden" name="receivercc_multiselect" value="1">';
1892 }
1893 print '</td></tr>';
1894 } else {
1895 print $hookmanager->resPrint;
1896 }
1897 }
1898
1899 $uselocalbrowser = false;
1900
1901 // Summary
1902 if ($this->withtitletopic) {
1903 print '<tr class="not_email_line"><td><label for="summary"><span>'.$langs->trans("Summary").'</span></label></td><td>';
1904 // Answer to a ticket : display of the thread title in readonly
1905 if ($this->withtopicreadonly && $this->topic_title) {
1906 print $langs->trans('Summary').' '.$this->topic_title;
1907 } elseif (empty($this->withtopicreadonly)) {
1908 $subject = $this->topic_title;
1909 print '<input class="text minwidth500" maxlength="42" id="summary" name="summary" placeholder="" value="'.dolPrintHTMLForAttribute($subject).'"'.(empty($this->withemail) ? ' autofocus' : '').' />';
1910 }
1911 print '</td></tr>';
1912 }
1913
1914 $topic = "";
1915 foreach ($formmail->lines_model as $line) {
1916 if (!empty($this->substit) && $this->param['models_id'] == $line->id) {
1917 $topic = make_substitutions($line->topic, $this->substit);
1918 break;
1919 }
1920 }
1921 print '<tr class="email_line"><td class="fieldrequired">'.$langs->trans('MailTopic').'</td>';
1922 if (empty($topic)) {
1923 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">';
1924 } else {
1925 print '<td><input type="text" class="text minwidth500" name="subject" value="'.make_substitutions($topic, $this->substit).'" spellcheck="false">';
1926 }
1927 print '</td></tr>';
1928
1929 // Attached files
1930 if (!empty($this->withfile)) {
1931 $out = '<tr>';
1932 $out .= '<td>'.$langs->trans("MailFile").'</td>';
1933 $out .= '<td>';
1934 // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
1935 $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
1936 $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
1937 $out .= 'jQuery(document).ready(function () {';
1938 $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
1939 $out .= ' jQuery("#addedfile").on("change", function() {';
1940 $out .= ' if (jQuery(this).val().length) {';
1941 $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", false);';
1942 $out .= ' } else {';
1943 $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
1944 $out .= ' }';
1945 $out .= ' });';
1946 $out .= ' jQuery(".removedfile").click(function() {';
1947 $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
1948 $out .= ' });';
1949 $out .= '})';
1950 $out .= '</script>'."\n";
1951
1952 if (count($listofpaths)) {
1953 foreach ($listofpaths as $key => $val) {
1954 $out .= '<div id="attachfile_'.$key.'">';
1955 $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
1956 if (!$this->withfilereadonly) {
1957 $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.'" />';
1958 }
1959 $out .= '<br></div>';
1960 }
1961 } else {
1962 //$out .= $langs->trans("NoAttachedFiles").'<br>';
1963 }
1964 if ($this->withfile == 2) { // Can add other files
1965 $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
1966 $out .= ' ';
1967 $out .= '<input type="submit" class="button smallpaddingimp reposition" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
1968 }
1969 $out .= "</td></tr>\n";
1970
1971 print $out;
1972 }
1973
1974 // MESSAGE
1975 $defaultmessage = "";
1976 if (is_object($arraydefaultmessage) && $arraydefaultmessage->content) {
1977 $defaultmessage = (string) $arraydefaultmessage->content;
1978 }
1979 $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1980
1981 // Deal with format differences between message and signature (text / HTML)
1982 if (dol_textishtml($defaultmessage) && !dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1983 $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1984 } elseif (!dol_textishtml($defaultmessage) && isset($this->substit['__USER_SIGNATURE__']) && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1985 $defaultmessage = dol_nl2br($defaultmessage);
1986 }
1987 if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1988 $defaultmessage = GETPOST('message', 'restricthtml');
1989 } else {
1990 $defaultmessage = make_substitutions($defaultmessage, $this->substit);
1991 // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1992 $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1993 $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1994 }
1995
1996 // 0=no, 1=backoffice only, 2=backoffice+public. showMessageForm() is always email context, so also honour FCKEDITOR_ENABLE_MAIL.
1997 $ckeditorenabledforticket = (getDolGlobalString('FCKEDITOR_ENABLE_TICKET') >= ($fromPublicInterface ? 2 : 1))
1998 || (!$fromPublicInterface && getDolGlobalString('FCKEDITOR_ENABLE_MAIL'));
1999
2000 print '<!-- Message line from showMessageForm -->';
2001 print '<tr><td class="tdtop"><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span>';
2002 if ($user->hasRight("ticket", "write") && !$user->socid) {
2003 $texttooltip = $langs->trans("TicketMessageHelp");
2004 if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO') || getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
2005 $texttooltip .= '<br><br>'.$langs->trans("ForEmailMessageWillBeCompletedWith").'...';
2006 }
2007 $allowedmailtags = array('a', 'div', 'strong', 'em', 'i', 'u', 'p', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img');
2008 if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO')) {
2009 $mail_intro = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO'), $this->substit);
2010 print '<input type="hidden" name="mail_intro" value="'.dolPrintHTMLForAttribute($mail_intro, 0, $allowedmailtags).'">';
2011 $texttooltip .= '<br><u>'.$langs->trans("TicketMessageMailIntro").'</u><br>'.$mail_intro;
2012 }
2013 if (getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
2014 $mail_signature = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE'), $this->substit);
2015 print '<input type="hidden" name="mail_signature" value="'.dolPrintHTMLForAttribute($mail_signature, 0, $allowedmailtags).'">';
2016 $texttooltip .= '<br><br><u>'.$langs->trans("TicketMessageMailFooter").'</u><br>'.$mail_signature;
2017 }
2018 print $form->textwithpicto('', $texttooltip, 1, 'help');
2019 }
2020 print '</label></td>';
2021 $out = '<td class="tdtop">';
2022
2023 $out .= '<div class="div-layoutai">';
2024
2025 // Required to show editor assistants
2026 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2027 $formmail = new FormMail($this->db);
2028
2029 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formai.class.php';
2030 $formai = new FormAI($this->db);
2031
2032 $formmail->withfckeditor = $ckeditorenabledforticket ? 1 : 0;
2033 $formmail->withlayout = ((string) $ckeditorenabledforticket && !$fromPublicInterface) ? 'email' : '';
2034 $formmail->withaiprompt = (isModEnabled('ai') && !$fromPublicInterface) ? 'text' : '';
2035
2036 $showlinktolayout = ($formmail->withfckeditor && getDolGlobalInt('MAIN_EMAIL_USE_LAYOUT')) ? $formmail->withlayout : '';
2037 $showlinktolayoutlabel = $langs->trans("FillMessageWithALayout");
2038 $showlinktoai = ($formmail->withaiprompt ? 'textgenerationemail' : '');
2039 $showlinktoailabel = $langs->trans("AIEnhancements");
2040 $formatforouput = '';
2041 $htmlname = 'message';
2042
2043 $formai->substit = $this->substit;
2044
2045 // Fill $out
2046 $db = $this->db;
2047 include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
2048
2049 $out .= '</td>';
2050 print $out;
2051
2052 print '</tr>';
2053
2054
2055 print '<tr><td colspan="2">';
2056 //$toolbarname = 'dolibarr_details';
2057 $toolbarname = 'dolibarr_notes';
2058 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
2059 $uselocalbrowser = false;
2060 if (!$ckeditorenabledforticket) {
2061 $defaultmessage = dol_string_nohtmltag($defaultmessage, 2);
2062 }
2063
2064 $doleditor = new DolEditor('message', $defaultmessage, '100%', 200, $toolbarname, '', false, $uselocalbrowser, $ckeditorenabledforticket, ROWS_6, '90%');
2065 $doleditor->Create();
2066
2067 print '</td></tr>';
2068
2069 // Footer
2070 // External users can't send message email
2071 /*if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_SIGNATURE)) {
2072 $mail_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
2073 print '<tr class="email_line"><td><label for="mail_intro">'.$langs->trans("TicketMessageMailFooter").'</label>';
2074 print $form->textwithpicto('', $langs->trans("TicketMessageMailFooterHelp"), 1, 'help');
2075 print '</td><td>';
2076 include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
2077 $doleditor = new DolEditor('mail_signature', $mail_signature, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_2, 70);
2078 $doleditor->Create();
2079 print '</td></tr>';
2080 }
2081 */
2082
2083 print '</table>';
2084
2085 print '<br><center>';
2086 print '<input type="submit" class="button" name="btn_add_message" value="'.$langs->trans("Add").'"';
2087 // Add a javascript test to avoid to forget to submit file before sending email
2088 if ($this->withfile == 2 && !empty($conf->use_javascript_ajax)) {
2089 print ' onClick="if (document.ticket.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
2090 }
2091 print ' />';
2092 if (!empty($this->withcancel)) {
2093 print " &nbsp; &nbsp; ";
2094 print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
2095 }
2096 print "</center>\n";
2097
2098 print '<input type="hidden" name="page_y">'."\n";
2099
2100 print "</form><br>\n";
2101
2102 // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
2103 if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
2104 print '<script type="text/javascript">';
2105 print 'jQuery(document).ready(function () {';
2106 print ' $(document).on("keypress", \'#ticket\', function (e) { /* Note this is called at every key pressed ! */
2107 var code = e.keyCode || e.which;
2108 if (code == 13) {
2109 console.log("Enter was intercepted and blocked");
2110 e.preventDefault();
2111 return false;
2112 }
2113 });';
2114 print '})';
2115 print '</script>';
2116 }
2117
2118 print "<!-- End message_form TICKET -->\n";
2119 }
2120}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
$propal type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition propal.php:280
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='', $placeholder='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:477
$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.
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.
__construct($db)
Constructor.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as p label as s rowid as s nom as s email
Sender: Who sends the email ("Sender" has sent emails on behalf of "From").
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
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.
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.
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 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
treeview li table
No Email.
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:540
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:738
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
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.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Definition html.lib.php:181
Class to generate the form for creating a new ticket.
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:140
getMaxFileSizeArray()
Return the max allowed for file upload.
if(empty( $takeposterminal)) fail($message)
Abort invoice creation with a given error message.
Definition invoice.php:125