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