FormTicket   F
last analyzed

Complexity

Total Complexity 338

Size/Duplication

Total Lines 1742
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 888
dl 0
loc 1742
rs 1.712
c 0
b 0
f 0
wmc 338

8 Methods

Rating   Name   Duplication   Size   Complexity  
A clear_attached_files() 0 21 4
D selectSeveritiesTickets() 0 87 34
F selectGroupTickets() 0 336 79
F selectTypesTickets() 0 82 35
F showForm() 0 566 90
A checkRequiredFields() 0 8 3
A __construct() 0 19 2
F showMessageForm() 0 447 91

How to fix   Complexity   

Complex Class

Complex classes like FormTicket often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FormTicket, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* Copyright (C) 2013-2015  Jean-François FERRY         <[email protected]>
4
 * Copyright (C) 2016       Christophe Battarel         <[email protected]>
5
 * Copyright (C) 2019-2024  Frédéric France             <[email protected]>
6
 * Copyright (C) 2021       Juanjo Menent               <[email protected]>
7
 * Copyright (C) 2021       Alexandre Spangaro          <[email protected]>
8
 * Copyright (C) 2023       Charlene Benke	            <[email protected]>
9
 * Copyright (C) 2024		MDW							<[email protected]>
10
 * Copyright (C) 2024	    Irvine FLEITH		        <[email protected]>
11
 * Copyright (C) 2024       Rafael San José             <[email protected]>
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
27
namespace Dolibarr\Code\Core\Classes;
28
29
use Dolibarr\Code\Categories\Classes\Categorie;
30
use Dolibarr\Code\Contact\Classes\Contact;
31
use Dolibarr\Code\Societe\Classes\Societe;
32
use Dolibarr\Code\Ticket\Classes\Ticket;
33
use Dolibarr\Code\User\Classes\User;
34
use DoliDB;
35
36
/**
37
 *    \file       htdocs/core/class/html.formticket.class.php
38
 *    \ingroup    ticket
39
 *    \brief      File of class to generate the form for creating a new ticket.
40
 */
41
42
if (!class_exists('FormCompany')) {
43
    include DOL_DOCUMENT_ROOT . '/core/class/html.formcompany.class.php';
44
}
45
46
/**
47
 * Class to generate the form for creating a new ticket.
48
 * Usage:   $formticket = new FormTicket($db)
49
 *          $formticket->proprietes = 1 or string or array of values
50
 *          $formticket->show_form()  shows the form
51
 *
52
 * @package Ticket
53
 */
54
class FormTicket
55
{
56
    /**
57
     * @var DoliDB Database handler.
58
     */
59
    public $db;
60
61
    /**
62
     * @var string      A hash value of the ticket. Duplicate of ref but for public purposes.
63
     */
64
    public $track_id;
65
66
    /**
67
     * @var string      Email $trackid. Used also for the $keytoavoidconflict to name session vars to upload files.
68
     */
69
    public $trackid;
70
71
    /**
72
     * @var int ID
73
     */
74
    public $fk_user_create;
75
76
    public $message;
77
    public $topic_title;
78
79
    public $action;
80
81
    public $withtopic;
82
    public $withemail;
83
84
    /**
85
     * @var int $withsubstit Show substitution array
86
     */
87
    public $withsubstit;
88
89
    public $withfile;
90
    public $withfilereadonly;
91
92
    public $backtopage;
93
94
    public $ispublic;  // to show information or not into public form
95
96
    public $withtitletopic;
97
    public $withtopicreadonly;
98
    public $withreadid;
99
100
    public $withcompany;  // to show company drop-down list
101
    public $withfromsocid;
102
    public $withfromcontactid;
103
    public $withnotifytiersatcreate;
104
    public $withusercreate;  // to show name of creating user in form
105
    public $withcreatereadonly;
106
107
    /**
108
     * @var int withextrafields
109
     */
110
    public $withextrafields;
111
112
    public $withref;  // to show ref field
113
    public $withcancel;
114
115
    public $type_code;
116
    public $category_code;
117
    public $severity_code;
118
119
120
    /**
121
     *
122
     * @var array $substit Substitutions
123
     */
124
    public $substit = array();
125
    public $param = array();
126
127
    /**
128
     * @var string Error code (or message)
129
     */
130
    public $error;
131
    public $errors = array();
132
133
134
    /**
135
     * Constructor
136
     *
137
     * @param DoliDB $db Database handler
138
     */
139
    public function __construct($db)
140
    {
141
        global $conf;
142
143
        $this->db = $db;
144
145
        $this->action = 'add';
146
147
        $this->withcompany = !getDolGlobalInt("TICKETS_NO_COMPANY_ON_FORM") && isModEnabled("societe");
148
        $this->withfromsocid = 0;
149
        $this->withfromcontactid = 0;
150
        $this->withreadid = 0;
151
        //$this->withtitletopic='';
152
        $this->withnotifytiersatcreate = 0;
153
        $this->withusercreate = 1;
154
        $this->withcreatereadonly = 1;
155
        $this->withemail = 0;
156
        $this->withref = 0;
157
        $this->withextrafields = 0;  // to show extrafields or not
158
        //$this->withtopicreadonly=0;
159
    }
160
161
    /**
162
     *
163
     * Check required fields
164
     *
165
     * @param array<string, array<string, string>> $fields Array of fields to check
166
     * @param int $errors Reference of errors variable
167
     * @return void
168
     */
169
    public static function checkRequiredFields(array $fields, int &$errors)
170
    {
171
        global $langs;
172
173
        foreach ($fields as $field => $type) {
174
            if (!GETPOST($field, $type['check'])) {
175
                $errors++;
176
                setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities($type['langs'])), null, 'errors');
177
            }
178
        }
179
    }
180
181
    /**
182
     * Show the form to input ticket
183
     *
184
     * @param   int             $withdolfichehead       With dol_get_fiche_head() and dol_get_fiche_end()
185
     * @param   string          $mode                   Mode ('create' or 'edit')
186
     * @param   int             $public                 1=If we show the form for the public interface
187
     * @param   Contact|null    $with_contact           [=NULL] Contact to link to this ticket if it exists
188
     * @param   string          $action                 [=''] Action in card
189
     * @param   ?Ticket         $object                 [=NULL] Ticket object
190
     * @return  void
191
     */
192
    public function showForm($withdolfichehead = 0, $mode = 'edit', $public = 0, Contact $with_contact = null, $action = '', Ticket $object = null)
193
    {
194
        global $conf, $langs, $user, $hookmanager;
195
196
        // Load translation files required by the page
197
        $langs->loadLangs(array('other', 'mails', 'ticket'));
198
199
        if ($mode == 'create') {
200
            $ref = GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : '';
201
            $type_code = GETPOSTISSET('type_code') ? GETPOST('type_code', 'alpha') : '';
202
            $category_code = GETPOSTISSET('category_code') ? GETPOST('category_code', 'alpha') : '';
203
            $severity_code = GETPOSTISSET('severity_code') ? GETPOST('severity_code', 'alpha') : '';
204
            $subject = GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : '';
205
            $email = GETPOSTISSET('email') ? GETPOST('email', 'alpha') : '';
206
            $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : '';
207
            $projectid = GETPOSTISSET('projectid') ? GETPOST('projectid', 'int') : '';
208
            $user_assign = GETPOSTISSET('fk_user_assign') ? GETPOSTINT('fk_user_assign') : $this->fk_user_create;
209
        } else {
210
            $ref = GETPOSTISSET("ref") ? GETPOST("ref", 'alpha') : $object->ref;
211
            $type_code = GETPOSTISSET('type_code') ? GETPOST('type_code', 'alpha') : $object->type_code;
212
            $category_code = GETPOSTISSET('category_code') ? GETPOST('category_code', 'alpha') : $object->category_code;
213
            $severity_code = GETPOSTISSET('severity_code') ? GETPOST('severity_code', 'alpha') : $object->severity_code;
214
            $subject = GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : $object->subject;
215
            $email = GETPOSTISSET('email') ? GETPOST('email', 'alpha') : $object->email_from;
216
            $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : $object->message;
217
            $projectid = GETPOSTISSET('projectid') ? GETPOST('projectid', 'int') : $object->fk_project;
218
            $user_assign = GETPOSTISSET('fk_user_assign') ? GETPOSTINT('fk_user_assign') : $object->fk_user_assign;
219
        }
220
221
        $form = new Form($this->db);
222
        $formcompany = new FormCompany($this->db);
223
        $ticketstatic = new Ticket($this->db);
224
225
        $soc = new Societe($this->db);
226
        if (!empty($this->withfromsocid) && $this->withfromsocid > 0) {
227
            $soc->fetch($this->withfromsocid);
228
        }
229
230
        $ticketstat = new Ticket($this->db);
231
232
        $extrafields = new ExtraFields($this->db);
233
        $extrafields->fetch_name_optionals_label($ticketstat->table_element);
234
235
        print "\n<!-- Begin form TICKET -->\n";
236
237
        if ($withdolfichehead) {
238
            print dol_get_fiche_head(null, 'card', '', 0, '');
239
        }
240
241
        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']) . '">';
242
        print '<input type="hidden" name="token" value="' . newToken() . '">';
243
        print '<input type="hidden" name="action" value="' . $this->action . '">';
244
        if (!empty($object->id)) print '<input type="hidden" name="id" value="' . $object->id . '">';
245
        print '<input type="hidden" name="trackid" value="' . $this->trackid . '">';
246
        foreach ($this->param as $key => $value) {
247
            print '<input type="hidden" name="' . $key . '" value="' . $value . '">';
248
        }
249
        print '<input type="hidden" name="fk_user_create" value="' . $this->fk_user_create . '">';
250
251
        print '<table class="border centpercent">';
252
253
        if ($this->withref) {
254
            // Ref
255
            $defaultref = $ticketstat->getDefaultRef();
256
257
            if ($mode == 'edit') {
258
                $defaultref = $object->ref;
259
            }
260
            print '<tr><td class="titlefieldcreate"><span class="fieldrequired">' . $langs->trans("Ref") . '</span></td><td>';
261
            print '<input type="text" name="ref" value="' . dol_escape_htmltag($defaultref) . '">';
262
            print '</td></tr>';
263
        }
264
265
        // TITLE
266
        if ($this->withemail) {
267
            print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">' . $langs->trans("Email") . '</span></label></td><td>';
268
            print '<input class="text minwidth200" id="email" name="email" value="' . $email . '" autofocus>';
269
            print '</td></tr>';
270
271
            if ($with_contact) {
272
                // contact search and result
273
                $html_contact_search = '';
274
                $html_contact_search .= '<tr id="contact_search_line">';
275
                $html_contact_search .= '<td class="titlefield">';
276
                $html_contact_search .= '<label for="contact"><span class="fieldrequired">' . $langs->trans('Contact') . '</span></label>';
277
                $html_contact_search .= '<input type="hidden" id="contact_id" name="contact_id" value="" />';
278
                $html_contact_search .= '</td>';
279
                $html_contact_search .= '<td id="contact_search_result"></td>';
280
                $html_contact_search .= '</tr>';
281
                print $html_contact_search;
282
                // contact lastname
283
                $html_contact_lastname = '';
284
                $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>';
285
                $html_contact_lastname .= '<input type="text" id="contact_lastname" name="contact_lastname" value="' . dol_escape_htmltag(GETPOSTISSET('contact_lastname') ? GETPOST('contact_lastname', 'alphanohtml') : '') . '" />';
286
                $html_contact_lastname .= '</td></tr>';
287
                print $html_contact_lastname;
288
                // contact firstname
289
                $html_contact_firstname = '';
290
                $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>';
291
                $html_contact_firstname .= '<input type="text" id="contact_firstname" name="contact_firstname" value="' . dol_escape_htmltag(GETPOSTISSET('contact_firstname') ? GETPOST('contact_firstname', 'alphanohtml') : '') . '" />';
292
                $html_contact_firstname .= '</td></tr>';
293
                print $html_contact_firstname;
294
                // company name
295
                $html_company_name = '';
296
                $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>';
297
                $html_company_name .= '<input type="text" id="company_name" name="company_name" value="' . dol_escape_htmltag(GETPOSTISSET('company_name') ? GETPOST('company_name', 'alphanohtml') : '') . '" />';
298
                $html_company_name .= '</td></tr>';
299
                print $html_company_name;
300
                // contact phone
301
                $html_contact_phone = '';
302
                $html_contact_phone .= '<tr id="contact_phone_line" class="contact_field"><td><label for="contact_phone"><span>' . $langs->trans('Phone') . '</span></label></td><td>';
303
                $html_contact_phone .= '<input type="text" id="contact_phone" name="contact_phone" value="' . dol_escape_htmltag(GETPOSTISSET('contact_phone') ? GETPOST('contact_phone', 'alphanohtml') : '') . '" />';
304
                $html_contact_phone .= '</td></tr>';
305
                print $html_contact_phone;
306
307
                // search contact form email
308
                $langs->load('errors');
309
                print '<script nonce="' . getNonce() . '" type="text/javascript">
310
                    jQuery(document).ready(function() {
311
                        var contact = jQuery.parseJSON("' . dol_escape_js(json_encode($with_contact), 2) . '");
312
                        jQuery("#contact_search_line").hide();
313
                        if (contact) {
314
                        	if (contact.id > 0) {
315
                        		jQuery("#contact_search_line").show();
316
                        		jQuery("#contact_id").val(contact.id);
317
								jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
318
								jQuery(".contact_field").hide();
319
                        	} else {
320
                        		jQuery(".contact_field").show();
321
                        	}
322
                        }
323
324
                    	jQuery("#email").change(function() {
325
                            jQuery("#contact_search_line").show();
326
                            jQuery("#contact_search_result").html("' . dol_escape_js($langs->trans('Select2SearchInProgress')) . '");
327
                            jQuery("#contact_id").val("");
328
                            jQuery("#contact_lastname").val("");
329
                            jQuery("#contact_firstname").val("");
330
                            jQuery("#company_name").val("");
331
                            jQuery("#contact_phone").val("");
332
333
                            jQuery.getJSON(
334
                                "' . dol_escape_js(dol_buildpath('/public/ticket/ajax/ajax.php', 1)) . '",
335
								{
336
									action: "getContacts",
337
									email: jQuery("#email").val()
338
								},
339
								function(response) {
340
									if (response.error) {
341
                                        jQuery("#contact_search_result").html("<span class=\"error\">"+response.error+"</span>");
342
									} else {
343
                                        var contact_list = response.contacts;
344
										if (contact_list.length == 1) {
345
                                            var contact = contact_list[0];
346
											jQuery("#contact_id").val(contact.id);
347
											jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
348
                                            jQuery(".contact_field").hide();
349
										} else if (contact_list.length <= 0) {
350
                                            jQuery("#contact_search_line").hide();
351
                                            jQuery(".contact_field").show();
352
										}
353
									}
354
								}
355
                            ).fail(function(jqxhr, textStatus, error) {
356
    							var error_msg = "' . dol_escape_js($langs->trans('ErrorAjaxRequestFailed')) . '"+" ["+textStatus+"] : "+error;
357
                                jQuery("#contact_search_result").html("<span class=\"error\">"+error_msg+"</span>");
358
                            });
359
                        });
360
                    });
361
                    </script>';
362
            }
363
        }
364
365
        // If ticket created from another object
366
        $subelement = '';
367
        if (isset($this->param['origin']) && $this->param['originid'] > 0) {
368
            // Parse element/subelement (ex: project_task)
369
            $element = $subelement = $this->param['origin'];
370
            $regs = array();
371
            if (preg_match('/^([^_]+)_([^_]+)/i', $this->param['origin'], $regs)) {
372
                $element = $regs[1];
373
                $subelement = $regs[2];
374
            }
375
376
            dol_include_once('/' . $element . '/class/' . $subelement . '.class.php');
377
            $classname = ucfirst($subelement);
378
            $objectsrc = new $classname($this->db);
379
            $objectsrc->fetch(GETPOSTINT('originid'));
380
381
            if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
382
                $objectsrc->fetch_lines();
383
            }
384
385
            $objectsrc->fetch_thirdparty();
386
            $newclassname = $classname;
387
            print '<tr><td>' . $langs->trans($newclassname) . '</td><td colspan="2"><input name="' . $subelement . 'id" value="' . GETPOST('originid') . '" type="hidden" />' . $objectsrc->getNomUrl(1) . '</td></tr>';
388
        }
389
390
        // Type of Ticket
391
        print '<tr><td class="titlefield"><span class="fieldrequired"><label for="selecttype_code">' . $langs->trans("TicketTypeRequest") . '</span></label></td><td>';
392
        $this->selectTypesTickets($type_code, 'type_code', '', 2, 1, 0, 0, 'minwidth200');
393
        print '</td></tr>';
394
395
        // Group => Category
396
        print '<tr><td><span class="fieldrequired"><label for="selectcategory_code">' . $langs->trans("TicketCategory") . '</span></label></td><td>';
397
        $filter = '';
398
        if ($public) {
399
            $filter = 'public=1';
400
        }
401
        $this->selectGroupTickets($category_code, 'category_code', $filter, 2, 1, 0, 0, 'minwidth200');
402
        print '</td></tr>';
403
404
        // Severity => Priority
405
        print '<tr><td><span class="fieldrequired"><label for="selectseverity_code">' . $langs->trans("TicketSeverity") . '</span></label></td><td>';
406
        $this->selectSeveritiesTickets($severity_code, 'severity_code', '', 2, 1);
407
        print '</td></tr>';
408
409
        if (isModEnabled('knowledgemanagement')) {
410
            // KM Articles
411
            print '<tr id="KWwithajax" class="hidden"><td></td></tr>';
412
            print '<!-- Script to manage change of ticket group -->
413
			<script nonce="' . getNonce() . '">
414
			jQuery(document).ready(function() {
415
				function groupticketchange() {
416
					console.log("We called groupticketchange, so we try to load list KM linked to event");
417
					$("#KWwithajax").html("");
418
					idgroupticket = $("#selectcategory_code").val();
419
420
					console.log("We have selected id="+idgroupticket);
421
422
					if (idgroupticket != "") {
423
						$.ajax({ url: \'' . constant('BASE_URL') . '/core/ajax/fetchKnowledgeRecord.php\',
424
							 data: { action: \'getKnowledgeRecord\', idticketgroup: idgroupticket, token: \'' . newToken() . '\', lang:\'' . $langs->defaultlang . '\', public:' . ($public) . ' },
425
							 type: \'GET\',
426
							 success: function(response) {
427
								var urllist = \'\';
428
								console.log("We received response "+response);
429
								if (typeof response == "object") {
430
									console.log("response is already type object, no need to parse it");
431
								} else {
432
									console.log("response is type "+(typeof response));
433
									response = JSON.parse(response);
434
								}
435
								for (key in response) {
436
									answer = response[key].answer;
437
									urllist += \'<li><a href="#" title="\'+response[key].title+\'" class="button_KMpopup" data-html="\'+answer+\'">\' +response[key].title+\'</a></li>\';
438
								}
439
								if (urllist != "") {
440
									$("#KWwithajax").html(\'<td>' . $langs->trans("KMFoundForTicketGroup") . '</td><td><ul>\'+urllist+\'</ul></td>\');
441
									$("#KWwithajax").show();
442
									$(".button_KMpopup").on("click",function(){
443
										console.log("Open popup with jQuery(...).dialog() with KM article")
444
										var $dialog = $("<div></div>").html($(this).attr("data-html"))
445
											.dialog({
446
												autoOpen: false,
447
												modal: true,
448
												height: (window.innerHeight - 150),
449
												width: "80%",
450
												title: $(this).attr("title"),
451
											});
452
										$dialog.dialog("open");
453
										console.log($dialog);
454
									})
455
								}
456
							 },
457
							 error : function(output) {
458
								console.error("Error on Fetch of KM articles");
459
							 },
460
						});
461
					}
462
				};
463
				$("#selectcategory_code").on("change",function() { groupticketchange(); });
464
				if ($("#selectcategory_code").val() != "") {
465
					groupticketchange();
466
				}
467
			});
468
			</script>' . "\n";
469
        }
470
471
        // Subject
472
        if ($this->withtitletopic) {
473
            print '<tr><td><label for="subject"><span class="fieldrequired">' . $langs->trans("Subject") . '</span></label></td><td>';
474
            // Answer to a ticket : display of the thread title in readonly
475
            if ($this->withtopicreadonly) {
476
                print $langs->trans('SubjectAnswerToTicket') . ' ' . $this->topic_title;
477
            } else {
478
                if (isset($this->withreadid) && $this->withreadid > 0) {
479
                    $subject = $langs->trans('SubjectAnswerToTicket') . ' ' . $this->withreadid . ' : ' . $this->topic_title;
480
                }
481
                print '<input class="text minwidth500" id="subject" name="subject" value="' . $subject . '"' . (empty($this->withemail) ? ' autofocus' : '') . ' />';
482
            }
483
            print '</td></tr>';
484
        }
485
486
        // MESSAGE
487
        print '<tr><td><label for="message"><span class="fieldrequired">' . $langs->trans("Message") . '</span></label></td><td>';
488
489
        // If public form, display more information
490
        $toolbarname = 'dolibarr_notes';
491
        if ($this->ispublic) {
492
            $toolbarname = 'dolibarr_details';
493
            print '<div class="warning hideonsmartphone">' . (getDolGlobalString("TICKET_PUBLIC_TEXT_HELP_MESSAGE", $langs->trans('TicketPublicPleaseBeAccuratelyDescribe'))) . '</div>';
494
        }
495
        $uselocalbrowser = true;
496
        $doleditor = new DolEditor('message', $msg, '100%', 230, $toolbarname, 'In', true, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_8, '90%');
497
        $doleditor->Create();
498
        print '</td></tr>';
499
500
        if ($public && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) {
501
            require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/security2.lib.php';
502
            print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">' . $langs->trans("SecurityCode") . '</span></label></td><td>';
503
            print '<span class="span-icon-security inline-block">';
504
            print '<input id="securitycode" placeholder="' . $langs->trans("SecurityCode") . '" class="flat input-icon-security width125" type="text" maxlength="5" name="code" tabindex="3" />';
505
            print '</span>';
506
            print '<span class="nowrap inline-block">';
507
            print '<img class="inline-block valignmiddle" src="' . constant('BASE_URL') . '/core/antispamimage.php" border="0" width="80" height="32" id="img_securitycode" />';
508
            print '<a class="inline-block valignmiddle" href="" tabindex="4" data-role="button">' . img_picto($langs->trans("Refresh"), 'refresh', 'id="captcha_refresh_img"') . '</a>';
509
            print '</span>';
510
            print '</td></tr>';
511
        }
512
513
        // Categories
514
        if (isModEnabled('category')) {
515
            $cate_arbo = $form->select_all_categories(Categorie::TYPE_TICKET, '', 'parent', 64, 0, 3);
516
517
            if (count($cate_arbo)) {
518
                // Categories
519
                print '<tr><td class="wordbreak">' . $langs->trans("Categories") . '</td><td>';
520
                print img_picto('', 'category', 'class="pictofixedwidth"') . $form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
521
                print "</td></tr>";
522
            }
523
        }
524
525
        // Attached files
526
        if (!empty($this->withfile)) {
527
            // Define list of attached files
528
            $listofpaths = array();
529
            $listofnames = array();
530
            $listofmimes = array();
531
            if (!empty($_SESSION["listofpaths"])) {
532
                $listofpaths = explode(';', $_SESSION["listofpaths"]);
533
            }
534
535
            if (!empty($_SESSION["listofnames"])) {
536
                $listofnames = explode(';', $_SESSION["listofnames"]);
537
            }
538
539
            if (!empty($_SESSION["listofmimes"])) {
540
                $listofmimes = explode(';', $_SESSION["listofmimes"]);
541
            }
542
543
            $out = '<tr>';
544
            $out .= '<td>' . $langs->trans("MailFile") . '</td>';
545
            $out .= '<td>';
546
            // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
547
            $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">' . "\n";
548
            $out .= '<script nonce="' . getNonce() . '" type="text/javascript">';
549
            $out .= 'jQuery(document).ready(function () {';
550
            $out .= '    jQuery(".removedfile").click(function() {';
551
            $out .= '        jQuery(".removedfilehidden").val(jQuery(this).val());';
552
            $out .= '    });';
553
            $out .= '})';
554
            $out .= '</script>' . "\n";
555
            if (count($listofpaths)) {
556
                foreach ($listofpaths as $key => $val) {
557
                    $out .= '<div id="attachfile_' . $key . '">';
558
                    $out .= img_mime($listofnames[$key]) . ' ' . $listofnames[$key];
559
                    if (!$this->withfilereadonly) {
560
                        $out .= ' <input type="image" style="border: 0px;" src="' . constant('DOL_URL_ROOT') . '/theme/' . $conf->theme . '/img/delete.png" value="' . ($key + 1) . '" class="removedfile" id="removedfile_' . $key . '" name="removedfile_' . $key . '" />';
561
                    }
562
                    $out .= '<br></div>';
563
                }
564
            } else {
565
                $out .= '<span class="opacitymedium">' . $langs->trans("NoAttachedFiles") . '</span><br>';
566
            }
567
            if ($this->withfile == 2) { // Can add other files
568
                $maxfilesizearray = getMaxFileSizeArray();
569
                $maxmin = $maxfilesizearray['maxmin'];
570
                if ($maxmin > 0) {
571
                    $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">';  // MAX_FILE_SIZE must precede the field type=file
572
                }
573
                $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="' . $langs->trans("Upload") . '" />';
574
                $out .= ' ';
575
                $out .= '<input type="submit" class="button smallpaddingimp reposition" id="addfile" name="addfile" value="' . $langs->trans("MailingAddFile") . '" />';
576
            }
577
            $out .= "</td></tr>\n";
578
579
            print $out;
580
        }
581
582
        // User of creation
583
        if ($this->withusercreate > 0 && $this->fk_user_create) {
584
            print '<tr><td class="titlefield">' . $langs->trans("CreatedBy") . '</td><td>';
585
            $langs->load("users");
586
            $fuser = new User($this->db);
587
588
            if ($this->withcreatereadonly) {
589
                if ($res = $fuser->fetch($this->fk_user_create)) {
590
                    print $fuser->getNomUrl(1);
591
                }
592
            }
593
            print ' &nbsp; ';
594
            print "</td></tr>\n";
595
        }
596
597
        // Customer or supplier
598
        if ($this->withcompany) {
599
            // force company and contact id for external user
600
            if (empty($user->socid)) {
601
                // Company
602
                print '<tr><td class="titlefield">' . $langs->trans("ThirdParty") . '</td><td>';
603
                $events = array();
604
                $events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
605
                print img_picto('', 'company', 'class="paddingright"');
606
                print $form->select_company($this->withfromsocid, 'socid', '', 1, 1, '', $events, 0, 'minwidth200');
607
                print '</td></tr>';
608
                if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
609
                    $htmlname = 'socid';
610
                    print '<script nonce="' . getNonce() . '" type="text/javascript">
611
                    $(document).ready(function () {
612
                        jQuery("#' . $htmlname . '").change(function () {
613
                            var obj = ' . json_encode($events) . ';
614
                            $.each(obj, function(key,values) {
615
                                if (values.method.length) {
616
                                    runJsCodeForEvent' . $htmlname . '(values);
617
                                }
618
                            });
619
                        });
620
621
                        function runJsCodeForEvent' . $htmlname . '(obj) {
622
                            console.log("Run runJsCodeForEvent' . $htmlname . '");
623
                            var id = $("#' . $htmlname . '").val();
624
                            var method = obj.method;
625
                            var url = obj.url;
626
                            var htmlname = obj.htmlname;
627
                            var showempty = obj.showempty;
628
                            $.getJSON(url,
629
                                    {
630
                                        action: method,
631
                                        id: id,
632
                                        htmlname: htmlname,
633
                                        showempty: showempty
634
                                    },
635
                                    function(response) {
636
                                        $.each(obj.params, function(key,action) {
637
                                            if (key.length) {
638
                                                var num = response.num;
639
                                                if (num > 0) {
640
                                                    $("#" + key).removeAttr(action);
641
                                                } else {
642
                                                    $("#" + key).attr(action, action);
643
                                                }
644
                                            }
645
                                        });
646
                                        $("select#" + htmlname).html(response.value);
647
                                        if (response.num) {
648
                                            var selecthtml_str = response.value;
649
                                            var selecthtml_dom=$.parseHTML(selecthtml_str);
650
											if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
651
                                            	$("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
652
											}
653
                                        } else {
654
                                            $("#inputautocomplete"+htmlname).val("");
655
                                        }
656
                                        $("select#" + htmlname).change();	/* Trigger event change */
657
                                    }
658
                            );
659
                        }
660
                    });
661
                    </script>';
662
                }
663
                if ($mode == 'create') {
664
                    // Contact and type
665
                    print '<tr><td>' . $langs->trans("Contact") . '</td><td>';
666
                    // If no socid, set to -1 to avoid full contacts list
667
                    $selectedCompany = ($this->withfromsocid > 0) ? $this->withfromsocid : -1;
668
                    print img_picto('', 'contact', 'class="paddingright"');
669
                    // @phan-suppress-next-line PhanPluginSuspiciousParamOrder
670
                    print $form->select_contact($selectedCompany, $this->withfromcontactid, 'contactid', 3, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
671
672
                    print ' ';
673
                    $formcompany->selectTypeContact($ticketstatic, '', 'type', 'external', '', 0, 'maginleftonly');
674
                    print '</td></tr>';
675
                }
676
            } else {
677
                print '<tr><td class="titlefield"><input type="hidden" name="socid" value="' . $user->socid . '"/></td>';
678
                print '<td><input type="hidden" name="contactid" value="' . $user->contact_id . '"/></td>';
679
                print '<td><input type="hidden" name="type" value="Z"/></td></tr>';
680
            }
681
682
            // Notify thirdparty at creation
683
            if (empty($this->ispublic) && $action == 'create') {
684
                print '<tr><td><label for="notify_tiers_at_create">' . $langs->trans("TicketNotifyTiersAtCreation") . '</label></td><td>';
685
                print '<input type="checkbox" id="notify_tiers_at_create" name="notify_tiers_at_create"' . ($this->withnotifytiersatcreate ? ' checked="checked"' : '') . '>';
686
                print '</td></tr>';
687
            }
688
689
            // User assigned
690
            print '<tr><td>';
691
            print $langs->trans("AssignedTo");
692
            print '</td><td>';
693
            print img_picto('', 'user', 'class="pictofixedwidth"');
694
            print $form->select_dolusers($user_assign, 'fk_user_assign', 1);
695
            print '</td>';
696
            print '</tr>';
697
        }
698
699
        if ($subelement != 'project') {
700
            if (isModEnabled('project') && !$this->ispublic) {
701
                $formproject = new FormProjets($this->db);
702
                print '<tr><td><label for="project"><span class="">' . $langs->trans("Project") . '</span></label></td><td>';
703
                print img_picto('', 'project') . $formproject->select_projects(-1, $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
704
                print '</td></tr>';
705
            }
706
        }
707
708
        if ($subelement != 'contract') {
709
            if (isModEnabled('contract') && !$this->ispublic) {
710
                $langs->load('contracts');
711
                $formcontract = new FormContract($this->db);
712
                print '<tr><td><label for="contract"><span class="">' . $langs->trans("Contract") . '</span></label></td><td>';
713
                print img_picto('', 'contract');
714
                print $formcontract->select_contract(-1, GETPOSTINT('contactid'), 'contractid', 0, 1, 1, 1);
715
                print '</td></tr>';
716
            }
717
        }
718
719
        // Other attributes
720
        $parameters = array();
721
        $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $ticketstat, $action); // Note that $action and $object may have been modified by hook
722
        if (empty($reshook)) {
723
            if ($mode == 'create') {
724
                print $object->showOptionals($extrafields, 'create');
0 ignored issues
show
Bug introduced by
The method showOptionals() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

724
                print $object->/** @scrutinizer ignore-call */ showOptionals($extrafields, 'create');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
725
            } else {
726
                print $object->showOptionals($extrafields, 'edit');
727
            }
728
        }
729
730
        print '</table>';
731
732
        if ($withdolfichehead) {
733
            print dol_get_fiche_end();
734
        }
735
736
        print '<br><br>';
737
738
        if ($mode == 'create') {
739
            print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "CreateTicket"), ($this->withcancel ? "Cancel" : ""));
740
        } else {
741
            print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "Save"), ($this->withcancel ? "Cancel" : ""));
742
        }
743
744
        /*
745
        print '<div class="center">';
746
        print '<input type="submit" class="button" name="add" value="'.$langs->trans(($this->withreadid > 0 ? "SendResponse" : "CreateTicket")).'" />';
747
        if ($this->withcancel) {
748
            print " &nbsp; &nbsp; &nbsp;";
749
            print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
750
        }
751
        print '</div>';
752
        */
753
754
        print '<input type="hidden" name="page_y">' . "\n";
755
756
        print "</form>\n";
757
        print "<!-- End form TICKET -->\n";
758
    }
759
760
    /**
761
     *      Return html list of tickets type
762
     *
763
     *      @param  string|array    $selected       Id of preselected field or array of Ids
764
     *      @param  string          $htmlname       Nom de la zone select
765
     *      @param  string          $filtertype     To filter on field type in llx_c_ticket_type (array('code'=>xx,'label'=>zz))
766
     *      @param  int             $format         0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code
767
     *      @param  int             $empty          1=peut etre vide, 0 sinon
768
     *      @param  int             $noadmininfo    0=Add admin info, 1=Disable admin info
769
     *      @param  int             $maxlength      Max length of label
770
     *      @param  string          $morecss        More CSS
771
     *      @param  int             $multiselect    Is multiselect ?
772
     *      @return void
773
     */
774
    public function selectTypesTickets($selected = '', $htmlname = 'tickettype', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $multiselect = 0)
775
    {
776
        global $langs, $user;
777
778
        $selected = is_array($selected) ? $selected : (!empty($selected) ? explode(',', $selected) : array());
779
        $ticketstat = new Ticket($this->db);
780
781
        dol_syslog(get_only_class($this) . "::select_types_tickets " . implode(';', $selected) . ", " . $htmlname . ", " . $filtertype . ", " . $format . ", " . $multiselect, LOG_DEBUG);
782
783
        $filterarray = array();
784
785
        if ($filtertype != '' && $filtertype != '-1') {
786
            $filterarray = explode(',', $filtertype);
787
        }
788
789
        $ticketstat->loadCacheTypesTickets();
790
791
        print '<select id="select' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . ($multiselect ? '[]' : '') . '"' . ($multiselect ? ' multiple' : '') . '>';
792
        if ($empty) {
793
            print '<option value="">&nbsp;</option>';
794
        }
795
796
        if (is_array($ticketstat->cache_types_tickets) && count($ticketstat->cache_types_tickets)) {
797
            foreach ($ticketstat->cache_types_tickets as $id => $arraytypes) {
798
                // On passe si on a demande de filtrer sur des modes de paiments particuliers
799
                if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
800
                    continue;
801
                }
802
803
                // If 'showempty' is enabled we discard empty line because an empty line has already been output.
804
                if ($empty && empty($arraytypes['code'])) {
805
                    continue;
806
                }
807
808
                if ($format == 0) {
809
                    print '<option value="' . $id . '"';
810
                }
811
812
                if ($format == 1) {
813
                    print '<option value="' . $arraytypes['code'] . '"';
814
                }
815
816
                if ($format == 2) {
817
                    print '<option value="' . $arraytypes['code'] . '"';
818
                }
819
820
                if ($format == 3) {
821
                    print '<option value="' . $id . '"';
822
                }
823
824
                // If text is selected, we compare with code, otherwise with id
825
                if (in_array($arraytypes['code'], $selected)) {
826
                    print ' selected="selected"';
827
                } elseif (in_array($id, $selected)) {
828
                    print ' selected="selected"';
829
                } elseif ($arraytypes['use_default'] == "1" && !$selected && !$empty) {
830
                    print ' selected="selected"';
831
                }
832
833
                print '>';
834
835
                $value = '&nbsp;';
836
                if ($format == 0) {
837
                    $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
838
                } elseif ($format == 1) {
839
                    $value = $arraytypes['code'];
840
                } elseif ($format == 2) {
841
                    $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
842
                } elseif ($format == 3) {
843
                    $value = $arraytypes['code'];
844
                }
845
846
                print $value ? $value : '&nbsp;';
847
                print '</option>';
848
            }
849
        }
850
        print '</select>';
851
        if (isset($user->admin) && $user->admin && !$noadmininfo) {
852
            print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
853
        }
854
855
        print ajax_combobox('select' . $htmlname);
856
    }
857
858
    /**
859
     *      Return html list of ticket analytic codes
860
     *
861
     *      @param  string      $selected           Id pre-selected category
862
     *      @param  string      $htmlname           Name of select component
863
     *      @param  string      $filtertype         To filter on some properties in llx_c_ticket_category ('public = 1'). This parameter must not come from input of users.
864
     *      @param  int         $format             0 = id+label, 1 = code+code, 2 = code+label, 3 = id+code
865
     *      @param  int         $empty              1 = can be empty, 0 = or not
866
     *      @param  int         $noadmininfo        0 = ddd admin info, 1 = disable admin info
867
     *      @param  int         $maxlength          Max length of label
868
     *      @param  string      $morecss            More CSS
869
     *      @param  int         $use_multilevel     If > 0 create a multilevel select which use $htmlname example: $use_multilevel = 1 permit to have 2 select boxes.
870
     *      @param  Translate   $outputlangs        Output language
871
     *      @return string|void                     String of HTML component
872
     */
873
    public function selectGroupTickets($selected = '', $htmlname = 'ticketcategory', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $use_multilevel = 0, $outputlangs = null)
874
    {
875
        global $conf, $langs, $user;
876
877
        dol_syslog(get_only_class($this) . "::selectCategoryTickets " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
878
879
        if (is_null($outputlangs) || !is_object($outputlangs)) {
880
            $outputlangs = $langs;
881
        }
882
        $outputlangs->load("ticket");
883
884
        $publicgroups = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
885
886
        $ticketstat = new Ticket($this->db);
887
        $ticketstat->loadCacheCategoriesTickets($publicgroups ? 1 : -1);    // get list of active ticket groups
888
889
        if ($use_multilevel <= 0) {
890
            print '<select id="select' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
891
            if ($empty) {
892
                print '<option value="">&nbsp;</option>';
893
            }
894
895
            if (is_array($ticketstat->cache_category_tickets) && count($ticketstat->cache_category_tickets)) {
896
                foreach ($ticketstat->cache_category_tickets as $id => $arraycategories) {
897
                    // Exclude some record
898
                    if ($publicgroups) {
899
                        if (empty($arraycategories['public'])) {
900
                            continue;
901
                        }
902
                    }
903
904
                    // We discard empty line if showempty is on because an empty line has already been output.
905
                    if ($empty && empty($arraycategories['code'])) {
906
                        continue;
907
                    }
908
909
                    $label = ($arraycategories['label'] != '-' ? $arraycategories['label'] : '');
910
                    if ($outputlangs->trans("TicketCategoryShort" . $arraycategories['code']) != "TicketCategoryShort" . $arraycategories['code']) {
911
                        $label = $outputlangs->trans("TicketCategoryShort" . $arraycategories['code']);
912
                    } elseif ($outputlangs->trans($arraycategories['code']) != $arraycategories['code']) {
913
                        $label = $outputlangs->trans($arraycategories['code']);
914
                    }
915
916
                    if ($format == 0) {
917
                        print '<option value="' . $id . '"';
918
                    }
919
920
                    if ($format == 1) {
921
                        print '<option value="' . $arraycategories['code'] . '"';
922
                    }
923
924
                    if ($format == 2) {
925
                        print '<option value="' . $arraycategories['code'] . '"';
926
                    }
927
928
                    if ($format == 3) {
929
                        print '<option value="' . $id . '"';
930
                    }
931
932
                    // If selected is text, we compare with code, otherwise with id
933
                    if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arraycategories['code']) {
934
                        print ' selected="selected"';
935
                    } elseif (isset($selected) && $selected == $id) {
936
                        print ' selected="selected"';
937
                    } elseif ($arraycategories['use_default'] == "1" && !$selected && !$empty) {
938
                        print ' selected="selected"';
939
                    } elseif (count($ticketstat->cache_category_tickets) == 1) {
940
                        print ' selected="selected"';
941
                    }
942
943
                    print '>';
944
945
                    $value = '';
946
                    if ($format == 0) {
947
                        $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
948
                    }
949
950
                    if ($format == 1) {
951
                        $value = $arraycategories['code'];
952
                    }
953
954
                    if ($format == 2) {
955
                        $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
956
                    }
957
958
                    if ($format == 3) {
959
                        $value = $arraycategories['code'];
960
                    }
961
962
                    print $value ? $value : '&nbsp;';
963
                    print '</option>';
964
                }
965
            }
966
            print '</select>';
967
            if (isset($user->admin) && $user->admin && !$noadmininfo) {
968
                print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
969
            }
970
971
            print ajax_combobox('select' . $htmlname);
972
        } elseif ($htmlname != '') {
973
            $selectedgroups = array();
974
            $groupvalue = "";
975
            $groupticket = GETPOST($htmlname, 'aZ09');
976
            $child_id = GETPOST($htmlname . '_child_id', 'aZ09') ? GETPOST($htmlname . '_child_id', 'aZ09') : 0;
977
            if (!empty($groupticket)) {
978
                $tmpgroupticket = $groupticket;
979
                $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code";
980
                $sql .= " FROM " . $this->db->prefix() . "c_ticket_category as ctc WHERE ctc.code = '" . $this->db->escape($tmpgroupticket) . "'";
981
                $resql = $this->db->query($sql);
982
                if ($resql) {
983
                    $obj = $this->db->fetch_object($resql);
984
                    $selectedgroups[] = $obj->code;
985
                    while ($obj->fk_parent > 0) {
986
                        $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) . "'";
987
                        $resql = $this->db->query($sql);
988
                        if ($resql) {
989
                            $obj = $this->db->fetch_object($resql);
990
                            $selectedgroups[] = $obj->code;
991
                        }
992
                    }
993
                }
994
            }
995
996
            $arrayidused = array();
997
            $arrayidusedconcat = array();
998
            $arraycodenotparent = array();
999
            $arraycodenotparent[] = "";
1000
1001
            $stringtoprint = '<span class="supportemailfield bold">' . $langs->trans("GroupOfTicket") . '</span> ';
1002
            $stringtoprint .= '<select id="' . $htmlname . '" class="minwidth500" child_id="0">';
1003
            $stringtoprint .= '<option value="">&nbsp;</option>';
1004
1005
            $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ";
1006
            $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";
1007
            $sql .= " FROM " . $this->db->prefix() . "c_ticket_category as ctc";
1008
            $sql .= " WHERE ctc.active > 0 AND ctc.entity = " . ((int) $conf->entity);
1009
            if ($filtertype == 'public=1') {
1010
                $sql .= " AND ctc.public = 1";
1011
            }
1012
            $sql .= " AND ctc.fk_parent = 0";
1013
            $sql .= $this->db->order('ctc.pos', 'ASC');
1014
1015
            $resql = $this->db->query($sql);
1016
            if ($resql) {
1017
                $num_rows_level0 = $this->db->num_rows($resql);
1018
                $i = 0;
1019
                while ($i < $num_rows_level0) {
1020
                    $obj = $this->db->fetch_object($resql);
1021
                    if ($obj) {
1022
                        $label = ($obj->label != '-' ? $obj->label : '');
1023
                        if ($outputlangs->trans("TicketCategoryShort" . $obj->code) != "TicketCategoryShort" . $obj->code) {
1024
                            $label = $outputlangs->trans("TicketCategoryShort" . $obj->code);
1025
                        } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1026
                            $label = $outputlangs->trans($obj->code);
1027
                        }
1028
1029
                        $grouprowid = $obj->rowid;
1030
                        $groupvalue = $obj->code;
1031
                        $grouplabel = $label;
1032
1033
                        $isparent = $obj->isparent;
1034
                        if (is_array($selectedgroups)) {
1035
                            $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1036
                        } else {
1037
                            $iselected = $groupticket == $obj->code ? 'selected' : '';
1038
                        }
1039
                        $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>';
1040
                        if ($isparent == 'NOTPARENT') {
1041
                            $arraycodenotparent[] = $groupvalue;
1042
                        }
1043
                        $arrayidused[] = $grouprowid;
1044
                        $arrayidusedconcat[] = $grouprowid;
1045
                    }
1046
                    $i++;
1047
                }
1048
            } else {
1049
                dol_print_error($this->db);
1050
            }
1051
            if (count($arrayidused) == 1) {
1052
                return '<input type="hidden" name="' . $htmlname . '" id="' . $htmlname . '" value="' . dol_escape_htmltag($groupvalue) . '">';
1053
            } else {
1054
                $stringtoprint .= '<input type="hidden" name="' . $htmlname . '" id="' . $htmlname . '_select" class="maxwidth500 minwidth400" value="' . GETPOST($htmlname) . '">';
1055
                $stringtoprint .= '<input type="hidden" name="' . $htmlname . '_child_id" id="' . $htmlname . '_select_child_id" class="maxwidth500 minwidth400" ' . GETPOST($htmlname) . ' value="' . GETPOST($htmlname . "_child_id") . '">';
1056
            }
1057
            $stringtoprint .= '</select>&nbsp;';
1058
1059
            $levelid = 1;   // The first combobox
1060
            while ($levelid <= $use_multilevel) {   // Loop to take the child of the combo
1061
                $tabscript = array();
1062
                $stringtoprint .= '<select id="' . $htmlname . '_child_' . $levelid . '" class="maxwidth500 minwidth400 groupticketchild" child_id="' . $levelid . '">';
1063
                $stringtoprint .= '<option value="">&nbsp;</option>';
1064
1065
                $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ctcjoin.code as codefather";
1066
                $sql .= " FROM " . $this->db->prefix() . "c_ticket_category as ctc";
1067
                $sql .= " JOIN " . $this->db->prefix() . "c_ticket_category as ctcjoin ON ctc.fk_parent = ctcjoin.rowid";
1068
                $sql .= " WHERE ctc.active > 0 AND ctc.entity = " . ((int) $conf->entity);
1069
                $sql .= " AND ctc.rowid NOT IN (" . $this->db->sanitize(implode(',', $arrayidusedconcat)) . ")";
1070
1071
                if ($filtertype == 'public=1') {
1072
                    $sql .= " AND ctc.public = 1";
1073
                }
1074
                // Add a test to take only record that are direct child
1075
                if (!empty($arrayidused)) {
1076
                    $sql .= " AND ctc.fk_parent IN ( ";
1077
                    foreach ($arrayidused as $idused) {
1078
                        $sql .= $idused . ", ";
1079
                    }
1080
                    $sql = substr($sql, 0, -2);
1081
                    $sql .= ")";
1082
                }
1083
                $sql .= $this->db->order('ctc.pos', 'ASC');
1084
1085
                $resql = $this->db->query($sql);
1086
                if ($resql) {
1087
                    $num_rows = $this->db->num_rows($resql);
1088
                    $i = 0;
1089
                    $arrayidused = array();
1090
                    while ($i < $num_rows) {
1091
                        $obj = $this->db->fetch_object($resql);
1092
                        if ($obj) {
1093
                            $label = ($obj->label != '-' ? $obj->label : '');
1094
                            if ($outputlangs->trans("TicketCategoryShort" . $obj->code) != "TicketCategoryShort" . $obj->code) {
1095
                                $label = $outputlangs->trans("TicketCategoryShort" . $obj->code);
1096
                            } elseif ($outputlangs->trans($obj->code) != $obj->code) {
1097
                                $label = $outputlangs->trans($obj->code);
1098
                            }
1099
1100
                            $grouprowid = $obj->rowid;
1101
                            $groupvalue = $obj->code;
1102
                            $grouplabel = $label;
1103
                            $isparent = $obj->isparent;
1104
                            $fatherid = $obj->fk_parent;
1105
                            $arrayidused[] = $grouprowid;
1106
                            $arrayidusedconcat[] = $grouprowid;
1107
                            $groupcodefather = $obj->codefather;
1108
                            if ($isparent == 'NOTPARENT') {
1109
                                $arraycodenotparent[] = $groupvalue;
1110
                            }
1111
                            if (is_array($selectedgroups)) {
1112
                                $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
1113
                            } else {
1114
                                $iselected = $groupticket == $obj->code ? 'selected' : '';
1115
                            }
1116
                            $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>';
1117
                            if (empty($tabscript[$groupcodefather])) {
1118
                                $tabscript[$groupcodefather] = 'if ($("#' . $htmlname . ($levelid > 1 ? '_child_' . ($levelid - 1) : '') . '").val() == "' . dol_escape_js($groupcodefather) . '"){
1119
									$(".' . $htmlname . '_' . dol_escape_htmltag($fatherid) . '_child_' . $levelid . '").show()
1120
									console.log("We show child tickets of ' . $groupcodefather . ' group ticket")
1121
								}else{
1122
									$(".' . $htmlname . '_' . dol_escape_htmltag($fatherid) . '_child_' . $levelid . '").hide()
1123
									console.log("We hide child tickets of ' . $groupcodefather . ' group ticket")
1124
								}';
1125
                            }
1126
                        }
1127
                        $i++;
1128
                    }
1129
                } else {
1130
                    dol_print_error($this->db);
1131
                }
1132
                $stringtoprint .= '</select>';
1133
1134
                $stringtoprint .= '<script nonce="' . getNonce() . '">';
1135
                $stringtoprint .= 'arraynotparents = ' . json_encode($arraycodenotparent) . ';';    // when the last visible combo list is number x, this is the array of group
1136
                $stringtoprint .= 'if (arraynotparents.includes($("#' . $htmlname . ($levelid > 1 ? '_child_' . ($levelid - 1) : '') . '").val())){
1137
					console.log("' . $htmlname . '_child_' . $levelid . '")
1138
					if($("#' . $htmlname . '_child_' . $levelid . '").val() == "" && ($("#' . $htmlname . '_child_' . $levelid . '").attr("child_id")>' . $child_id . ')){
1139
						$("#' . $htmlname . '_child_' . $levelid . '").hide();
1140
						console.log("We hide ' . $htmlname . '_child_' . $levelid . ' input")
1141
					}
1142
					if(arraynotparents.includes("' . $groupticket . '") && ' . $child_id . ' == 0){
1143
						$("#ticketcategory_select_child_id").val($("#' . $htmlname . '").attr("child_id"))
1144
						$("#ticketcategory_select").val($("#' . $htmlname . '").val()) ;
1145
						console.log("We choose ' . $htmlname . ' input and reload hidden input");
1146
					}
1147
				}
1148
				$("#' . $htmlname . ($levelid > 1 ? '_child_' . ($levelid - 1) : '') . '").change(function() {
1149
					child_id = $("#' . $htmlname . ($levelid > 1 ? '_child_' . $levelid : '') . '").attr("child_id");
1150
1151
					/* Change of value to select this value*/
1152
					if (arraynotparents.includes($(this).val()) || $(this).attr("child_id") == ' . $use_multilevel . ') {
1153
						$("#ticketcategory_select").val($(this).val());
1154
						$("#ticketcategory_select_child_id").val($(this).attr("child_id")) ;
1155
						console.log("We choose to select "+ $(this).val());
1156
					}else{
1157
						if ($("#' . $htmlname . '_child_' . $levelid . ' option").length <= 1) {
1158
							$("#ticketcategory_select").val($(this).val());
1159
							$("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1160
							console.log("We choose to select "+ $(this).val() + " and next combo has no item, so we keep this selection");
1161
						} else {
1162
							console.log("We choose to select "+ $(this).val() + " but next combo has some item, so we clean selected item");
1163
							$("#ticketcategory_select").val("");
1164
							$("#ticketcategory_select_child_id").val("");
1165
						}
1166
					}
1167
1168
					console.log("We select a new value into combo child_id="+child_id);
1169
1170
					// Hide all selected box that are child of the one modified
1171
					$(".groupticketchild").each(function(){
1172
						if ($(this).attr("child_id") > child_id) {
1173
							console.log("hide child_id="+$(this).attr("child_id"));
1174
							$(this).val("");
1175
							$(this).hide();
1176
						}
1177
					})
1178
1179
					// Now we enable the next combo
1180
					$("#' . $htmlname . '_child_' . $levelid . '").val("");
1181
					if (!arraynotparents.includes($(this).val()) && $("#' . $htmlname . '_child_' . $levelid . ' option").length > 1) {
1182
						console.log($("#' . $htmlname . '_child_' . $levelid . ' option").length);
1183
						$("#' . $htmlname . '_child_' . $levelid . '").show()
1184
					} else {
1185
						$("#' . $htmlname . '_child_' . $levelid . '").hide()
1186
					}
1187
				';
1188
                $levelid++;
1189
                foreach ($tabscript as $script) {
1190
                    $stringtoprint .= $script;
1191
                }
1192
                $stringtoprint .= '})';
1193
                $stringtoprint .= '</script>';
1194
            }
1195
            $stringtoprint .= '<script nonce="' . getNonce() . '">';
1196
            $stringtoprint .= '$("#' . $htmlname . '_child_' . $use_multilevel . '").change(function() {
1197
				$("#ticketcategory_select").val($(this).val());
1198
				$("#ticketcategory_select_child_id").val($(this).attr("child_id"));
1199
				tmpvalselect = $("#ticketcategory_select").val();
1200
				if(tmpvalselect == "" && $("#ticketcategory_select_child_id").val() >= 1){
1201
					$("#ticketcategory_select_child_id").val($(this).attr("child_id")-1);
1202
				}
1203
				console.log($("#ticketcategory_select").val());
1204
			})';
1205
            $stringtoprint .= '</script>';
1206
            $stringtoprint .= ajax_combobox($htmlname);
1207
1208
            return $stringtoprint;
1209
        }
1210
    }
1211
1212
    /**
1213
     *      Return html list of ticket severitys (priorities)
1214
     *
1215
     *      @param  string  $selected    Id severity pre-selected
1216
     *      @param  string  $htmlname    Name of the select area
1217
     *      @param  string  $filtertype  To filter on field type in llx_c_ticket_severity (array('code'=>xx,'label'=>zz))
1218
     *      @param  int     $format      0 = id+label, 1 = code+code, 2 = code+label, 3 = id+code
1219
     *      @param  int     $empty       1 = can be empty, 0 = or not
1220
     *      @param  int     $noadmininfo 0 = add admin info, 1 = disable admin info
1221
     *      @param  int     $maxlength   Max length of label
1222
     *      @param  string  $morecss     More CSS
1223
     *      @return void
1224
     */
1225
    public function selectSeveritiesTickets($selected = '', $htmlname = 'ticketseverity', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '')
1226
    {
1227
        global $conf, $langs, $user;
1228
1229
        $ticketstat = new Ticket($this->db);
1230
1231
        dol_syslog(get_only_class($this) . "::selectSeveritiesTickets " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
1232
1233
        $filterarray = array();
1234
1235
        if ($filtertype != '' && $filtertype != '-1') {
1236
            $filterarray = explode(',', $filtertype);
1237
        }
1238
1239
        $ticketstat->loadCacheSeveritiesTickets();
1240
1241
        print '<select id="select' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
1242
        if ($empty) {
1243
            print '<option value="">&nbsp;</option>';
1244
        }
1245
1246
        if (is_array($conf->cache['severity_tickets']) && count($conf->cache['severity_tickets'])) {
1247
            foreach ($conf->cache['severity_tickets'] as $id => $arrayseverities) {
1248
                // On passe si on a demande de filtrer sur des modes de paiments particuliers
1249
                if (count($filterarray) && !in_array($arrayseverities['type'], $filterarray)) {
1250
                    continue;
1251
                }
1252
1253
                // We discard empty line if showempty is on because an empty line has already been output.
1254
                if ($empty && empty($arrayseverities['code'])) {
1255
                    continue;
1256
                }
1257
1258
                if ($format == 0) {
1259
                    print '<option value="' . $id . '"';
1260
                }
1261
1262
                if ($format == 1) {
1263
                    print '<option value="' . $arrayseverities['code'] . '"';
1264
                }
1265
1266
                if ($format == 2) {
1267
                    print '<option value="' . $arrayseverities['code'] . '"';
1268
                }
1269
1270
                if ($format == 3) {
1271
                    print '<option value="' . $id . '"';
1272
                }
1273
1274
                // If text is selected, we compare with code, otherwise with id
1275
                if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arrayseverities['code']) {
1276
                    print ' selected="selected"';
1277
                } elseif (isset($selected) && $selected == $id) {
1278
                    print ' selected="selected"';
1279
                } elseif ($arrayseverities['use_default'] == "1" && !$selected && !$empty) {
1280
                    print ' selected="selected"';
1281
                }
1282
1283
                print '>';
1284
1285
                $value = '';
1286
                if ($format == 0) {
1287
                    $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1288
                }
1289
1290
                if ($format == 1) {
1291
                    $value = $arrayseverities['code'];
1292
                }
1293
1294
                if ($format == 2) {
1295
                    $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
1296
                }
1297
1298
                if ($format == 3) {
1299
                    $value = $arrayseverities['code'];
1300
                }
1301
1302
                print $value ? $value : '&nbsp;';
1303
                print '</option>';
1304
            }
1305
        }
1306
        print '</select>';
1307
        if (isset($user->admin) && $user->admin && !$noadmininfo) {
1308
            print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1309
        }
1310
1311
        print ajax_combobox('select' . $htmlname);
1312
    }
1313
1314
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1315
    /**
1316
     * Clear list of attached files in send mail form (also stored in session)
1317
     *
1318
     * @return  void
1319
     */
1320
    public function clear_attached_files()
1321
    {
1322
		// phpcs:enable
1323
        global $conf, $user;
1324
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
1325
1326
        // Set tmp user directory
1327
        $vardir = $conf->user->dir_output . "/" . $user->id;
1328
        $upload_dir = $vardir . '/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
1329
        if (is_dir($upload_dir)) {
1330
            dol_delete_dir_recursive($upload_dir);
1331
        }
1332
1333
        if (!empty($this->trackid)) { // TODO Always use trackid (ticXXX) instead of track_id (abcd123)
1334
            $keytoavoidconflict = '-' . $this->trackid;
1335
        } else {
1336
            $keytoavoidconflict = empty($this->track_id) ? '' : '-' . $this->track_id;
1337
        }
1338
        unset($_SESSION["listofpaths" . $keytoavoidconflict]);
1339
        unset($_SESSION["listofnames" . $keytoavoidconflict]);
1340
        unset($_SESSION["listofmimes" . $keytoavoidconflict]);
1341
    }
1342
1343
    /**
1344
     * Show the form to add message on ticket
1345
     *
1346
     * @param   string  $width          Width of form
1347
     * @return  void
1348
     */
1349
    public function showMessageForm($width = '40%')
1350
    {
1351
        global $conf, $langs, $user, $hookmanager, $form, $mysoc;
1352
1353
        $formmail = new FormMail($this->db);
1354
        $addfileaction = 'addfile';
1355
1356
        if (!is_object($form)) {
1357
            $form = new Form($this->db);
1358
        }
1359
1360
        // Load translation files required by the page
1361
        $langs->loadLangs(array('other', 'mails', 'ticket'));
1362
1363
        // Clear temp files. Must be done at beginning, before call of triggers
1364
        if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1365
            $this->clear_attached_files();
1366
        }
1367
1368
        // Define output language
1369
        $outputlangs = $langs;
1370
        $newlang = '';
1371
        if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
1372
            $newlang = $this->param['langsmodels'];
1373
        }
1374
        if (!empty($newlang)) {
1375
            $outputlangs = new Translate("", $conf);
1376
            $outputlangs->setDefaultLang($newlang);
1377
            $outputlangs->load('other');
1378
        }
1379
1380
        // Get message template for $this->param["models"] into c_email_templates
1381
        $arraydefaultmessage = -1;
1382
        if (isset($this->param['models']) && $this->param['models'] != 'none') {
1383
            $model_id = 0;
1384
            if (array_key_exists('models_id', $this->param)) {
1385
                $model_id = (int) $this->param["models_id"];
1386
            }
1387
1388
            $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id); // If $model_id is empty, preselect the first one
1389
        }
1390
1391
        // Define list of attached files
1392
        $listofpaths = array();
1393
        $listofnames = array();
1394
        $listofmimes = array();
1395
1396
        if (!empty($this->trackid)) {
1397
            $keytoavoidconflict = '-' . $this->trackid;
1398
        } else {
1399
            $keytoavoidconflict = empty($this->track_id) ? '' : '-' . $this->track_id; // track_id instead of trackid
1400
        }
1401
        //var_dump($keytoavoidconflict);
1402
        if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
1403
            if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
1404
                foreach ($this->param['fileinit'] as $path) {
1405
                    $formmail->add_attached_files($path, basename($path), dol_mimetype($path));
1406
                }
1407
            }
1408
        }
1409
        //var_dump($_SESSION);
1410
        //var_dump($_SESSION["listofpaths".$keytoavoidconflict]);
1411
        if (!empty($_SESSION["listofpaths" . $keytoavoidconflict])) {
1412
            $listofpaths = explode(';', $_SESSION["listofpaths" . $keytoavoidconflict]);
1413
        }
1414
        if (!empty($_SESSION["listofnames" . $keytoavoidconflict])) {
1415
            $listofnames = explode(';', $_SESSION["listofnames" . $keytoavoidconflict]);
1416
        }
1417
        if (!empty($_SESSION["listofmimes" . $keytoavoidconflict])) {
1418
            $listofmimes = explode(';', $_SESSION["listofmimes" . $keytoavoidconflict]);
1419
        }
1420
1421
        // Define output language
1422
        $outputlangs = $langs;
1423
        $newlang = '';
1424
        if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
1425
            $newlang = $this->param['langsmodels'];
1426
        }
1427
        if (!empty($newlang)) {
1428
            $outputlangs = new Translate("", $conf);
1429
            $outputlangs->setDefaultLang($newlang);
1430
            $outputlangs->load('other');
1431
        }
1432
1433
        print "\n<!-- Begin message_form TICKET -->\n";
1434
1435
        $send_email = GETPOSTINT('send_email') ? GETPOSTINT('send_email') : 0;
1436
1437
        // Example 1 : Adding jquery code
1438
        print '<script nonce="' . getNonce() . '" type="text/javascript">
1439
		jQuery(document).ready(function() {
1440
			send_email=' . $send_email . ';
1441
			if (send_email) {
1442
				if (!jQuery("#send_msg_email").is(":checked")) {
1443
					jQuery("#send_msg_email").prop("checked", true).trigger("change");
1444
				}
1445
				jQuery(".email_line").show();
1446
			} else {
1447
				if (!jQuery("#private_message").is(":checked")) {
1448
					jQuery("#private_message").prop("checked", true).trigger("change");
1449
				}
1450
				jQuery(".email_line").hide();
1451
			}
1452
		';
1453
1454
        // If constant set, allow to send private messages as email
1455
        if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1456
            print 'jQuery("#send_msg_email").click(function() {
1457
					console.log("Click send_msg_email");
1458
					if(jQuery(this).is(":checked")) {
1459
						if (jQuery("#private_message").is(":checked")) {
1460
							jQuery("#private_message").prop("checked", false).trigger("change");
1461
						}
1462
						jQuery(".email_line").show();
1463
					}
1464
					else {
1465
						jQuery(".email_line").hide();
1466
					}
1467
				});
1468
1469
				jQuery("#private_message").click(function() {
1470
					console.log("Click private_message");
1471
					if (jQuery(this).is(":checked")) {
1472
						if (jQuery("#send_msg_email").is(":checked")) {
1473
							jQuery("#send_msg_email").prop("checked", false).trigger("change");
1474
						}
1475
						jQuery(".email_line").hide();
1476
					}
1477
				});';
1478
        }
1479
1480
        print '});
1481
		</script>';
1482
1483
1484
        print '<form method="post" name="ticket" id="ticket" enctype="multipart/form-data" action="' . $this->param["returnurl"] . '">';
1485
        print '<input type="hidden" name="token" value="' . newToken() . '">';
1486
        print '<input type="hidden" name="action" value="' . $this->action . '">';
1487
        print '<input type="hidden" name="actionbis" value="add_message">';
1488
        print '<input type="hidden" name="backtopage" value="' . $this->backtopage . '">';
1489
        if (!empty($this->trackid)) {
1490
            print '<input type="hidden" name="trackid" value="' . $this->trackid . '">';
1491
        } else {
1492
            print '<input type="hidden" name="trackid" value="' . (empty($this->track_id) ? '' : $this->track_id) . '">';
1493
            $keytoavoidconflict = empty($this->track_id) ? '' : '-' . $this->track_id; // track_id instead of trackid
1494
        }
1495
        foreach ($this->param as $key => $value) {
1496
            print '<input type="hidden" name="' . $key . '" value="' . $value . '">';
1497
        }
1498
1499
        // Get message template
1500
        $model_id = 0;
1501
        if (array_key_exists('models_id', $this->param)) {
1502
            $model_id = $this->param["models_id"];
1503
            $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id);
1504
        }
1505
1506
        $result = $formmail->fetchAllEMailTemplate(!empty($this->param["models"]) ? $this->param["models"] : "", $user, $outputlangs);
1507
        if ($result < 0) {
1508
            setEventMessages($this->error, $this->errors, 'errors');
1509
        }
1510
        $modelmail_array = array();
1511
        foreach ($formmail->lines_model as $line) {
1512
            $modelmail_array[$line->id] = $line->label;
1513
        }
1514
1515
        print '<table class="border" width="' . $width . '">';
1516
1517
        // External users can't send message email
1518
        if ($user->hasRight("ticket", "write") && !$user->socid) {
1519
            $ticketstat = new Ticket($this->db);
1520
            $res = $ticketstat->fetch('', '', $this->track_id);
1521
1522
            print '<tr><td></td><td>';
1523
            $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : (getDolGlobalInt('TICKETS_MESSAGE_FORCE_MAIL') ? 'checked' : ''));
1524
            print '<input type="checkbox" name="send_email" value="1" id="send_msg_email" ' . $checkbox_selected . '/> ';
1525
            print '<label for="send_msg_email">' . $langs->trans('SendMessageByEmail') . '</label>';
1526
            $texttooltip = $langs->trans("TicketMessageSendEmailHelp");
1527
            if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
1528
                $texttooltip .= ' ' . $langs->trans("TicketMessageSendEmailHelp2b");
1529
            } else {
1530
                $texttooltip .= ' ' . $langs->trans("TicketMessageSendEmailHelp2a", '{s1}');
1531
            }
1532
            $texttooltip = str_replace('{s1}', $langs->trans('MarkMessageAsPrivate'), $texttooltip);
1533
            print ' ' . $form->textwithpicto('', $texttooltip, 1, 'help');
1534
            print '</td></tr>';
1535
1536
            // Private message (not visible by customer/external user)
1537
            if (!$user->socid) {
1538
                print '<tr><td></td><td>';
1539
                $checkbox_selected = (GETPOST('private_message', 'alpha') == "1" ? ' checked' : '');
1540
                print '<input type="checkbox" name="private_message" value="1" id="private_message" ' . $checkbox_selected . '/> ';
1541
                print '<label for="private_message">' . $langs->trans('MarkMessageAsPrivate') . '</label>';
1542
                print ' ' . $form->textwithpicto('', $langs->trans("TicketMessagePrivateHelp"), 1, 'help');
1543
                print '</td></tr>';
1544
            }
1545
1546
            // Zone to select its email template
1547
            if (count($modelmail_array) > 0) {
1548
                print '<tr class="email_line"><td></td><td colspan="2"><div style="padding: 3px 0 3px 0">' . "\n";
1549
                print $langs->trans('SelectMailModel') . ': ' . $formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], 1, 0, "", "", 0, 0, 0, '', 'minwidth200');
1550
                if ($user->admin) {
1551
                    print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1552
                }
1553
                print ' &nbsp; ';
1554
                print '<input type="submit" class="button" value="' . $langs->trans('Apply') . '" name="modelselected" id="modelselected">';
1555
                print '</div></td>';
1556
            }
1557
1558
            // From
1559
            $from = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_FROM');
1560
            print '<tr class="email_line"><td><span class="">' . $langs->trans("MailFrom") . '</span></td>';
1561
            print '<td><span class="">' . img_picto('', 'email', 'class="pictofixedwidth"') . $from . '</span></td></tr>';
1562
1563
            // Subject/topic
1564
            $topic = "";
1565
            foreach ($formmail->lines_model as $line) {
1566
                if ($this->param['models_id'] == $line->id) {
1567
                    $topic = $line->topic;
1568
                    break;
1569
                }
1570
            }
1571
            print '<tr class="email_line"><td>' . $langs->trans('Subject') . '</td>';
1572
            if (empty($topic)) {
1573
                print '<td><input type="text" class="text minwidth500" name="subject" value="[' . getDolGlobalString('MAIN_INFO_SOCIETE_NOM') . ' - ' . $langs->trans("Ticket") . ' ' . $ticketstat->ref . '] ' . $ticketstat->subject . '" />';
1574
            } else {
1575
                print '<td><input type="text" class="text minwidth500" name="subject" value="' . make_substitutions($topic, $this->substit) . '" />';
1576
            }
1577
            print '</td></tr>';
1578
1579
            // Recipients / adressed-to
1580
            print '<tr class="email_line"><td>' . $langs->trans('MailRecipients');
1581
            print ' ' . $form->textwithpicto('', $langs->trans("TicketMessageRecipientsHelp"), 1, 'help');
1582
            print '</td><td>';
1583
            if ($res) {
1584
                // Retrieve email of all contacts (internal and external)
1585
                $contacts = $ticketstat->getInfosTicketInternalContact(1);
1586
                $contacts = array_merge($contacts, $ticketstat->getInfosTicketExternalContact(1));
1587
1588
                $sendto = array();
1589
1590
                // Build array to display recipient list
1591
                if (is_array($contacts) && count($contacts) > 0) {
1592
                    foreach ($contacts as $key => $info_sendto) {
1593
                        if ($info_sendto['email'] != '') {
1594
                            $sendto[] = dol_escape_htmltag(trim($info_sendto['firstname'] . " " . $info_sendto['lastname']) . " <" . $info_sendto['email'] . ">") . ' <small class="opacitymedium">(' . dol_escape_htmltag($info_sendto['libelle']) . ")</small>";
1595
                        }
1596
                    }
1597
                }
1598
1599
                if (!empty($ticketstat->origin_replyto) && !in_array($ticketstat->origin_replyto, $sendto)) {
1600
                    $sendto[] = dol_escape_htmltag($ticketstat->origin_replyto) . ' <small class="opacitymedium">(' . $langs->trans("TicketEmailOriginIssuer") . ")</small>";
1601
                } elseif ($ticketstat->origin_email && !in_array($ticketstat->origin_email, $sendto)) {
1602
                    $sendto[] = dol_escape_htmltag($ticketstat->origin_email) . ' <small class="opacitymedium">(' . $langs->trans("TicketEmailOriginIssuer") . ")</small>";
1603
                }
1604
1605
                if ($ticketstat->fk_soc > 0) {
1606
                    $ticketstat->socid = $ticketstat->fk_soc;
1607
                    $ticketstat->fetch_thirdparty();
1608
1609
                    if (!empty($ticketstat->thirdparty->email) && !in_array($ticketstat->thirdparty->email, $sendto)) {
1610
                        $sendto[] = $ticketstat->thirdparty->email . ' <small class="opacitymedium">(' . $langs->trans('Customer') . ')</small>';
1611
                    }
1612
                }
1613
1614
                if (getDolGlobalInt('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS')) {
1615
                    $sendto[] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO') . ' <small class="opacitymedium">(generic email)</small>';
1616
                }
1617
1618
                // Print recipient list
1619
                if (is_array($sendto) && count($sendto) > 0) {
1620
                    print img_picto('', 'email', 'class="pictofixedwidth"');
1621
                    print implode(', ', $sendto);
1622
                } else {
1623
                    print '<div class="warning">' . $langs->trans('WarningNoEMailsAdded') . ' ' . $langs->trans('TicketGoIntoContactTab') . '</div>';
1624
                }
1625
            }
1626
            print '</td></tr>';
1627
        }
1628
1629
        $uselocalbrowser = false;
1630
1631
        // Intro
1632
        // External users can't send message email
1633
        /*
1634
        if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_INTRO)) {
1635
            $mail_intro = GETPOST('mail_intro') ? GETPOST('mail_intro') : $conf->global->TICKET_MESSAGE_MAIL_INTRO;
1636
            print '<tr class="email_line"><td><label for="mail_intro">';
1637
            print $form->textwithpicto($langs->trans("TicketMessageMailIntro"), $langs->trans("TicketMessageMailIntroHelp"), 1, 'help');
1638
            print '</label>';
1639
1640
            print '</td><td>';
1641
            include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1642
1643
            $doleditor = new DolEditor('mail_intro', $mail_intro, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_2, 70);
1644
1645
            $doleditor->Create();
1646
            print '</td></tr>';
1647
        }
1648
        */
1649
1650
        // Attached files
1651
        if (!empty($this->withfile)) {
1652
            $out = '<tr>';
1653
            $out .= '<td>' . $langs->trans("MailFile") . '</td>';
1654
            $out .= '<td>';
1655
            // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
1656
            $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">' . "\n";
1657
            $out .= '<script nonce="' . getNonce() . '" type="text/javascript">';
1658
            $out .= 'jQuery(document).ready(function () {';
1659
            $out .= '    jQuery("#' . $addfileaction . '").prop("disabled", true);';
1660
            $out .= '    jQuery("#addedfile").on("change", function() {';
1661
            $out .= '        if (jQuery(this).val().length) {';
1662
            $out .= '            jQuery("#' . $addfileaction . '").prop("disabled", false);';
1663
            $out .= '        } else {';
1664
            $out .= '            jQuery("#' . $addfileaction . '").prop("disabled", true);';
1665
            $out .= '        }';
1666
            $out .= '    });';
1667
            $out .= '    jQuery(".removedfile").click(function() {';
1668
            $out .= '        jQuery(".removedfilehidden").val(jQuery(this).val());';
1669
            $out .= '    });';
1670
            $out .= '})';
1671
            $out .= '</script>' . "\n";
1672
1673
            if (count($listofpaths)) {
1674
                foreach ($listofpaths as $key => $val) {
1675
                    $out .= '<div id="attachfile_' . $key . '">';
1676
                    $out .= img_mime($listofnames[$key]) . ' ' . $listofnames[$key];
1677
                    if (!$this->withfilereadonly) {
1678
                        $out .= ' <input type="image" style="border: 0px;" src="' . constant('DOL_URL_ROOT') . '/theme/' . $conf->theme . '/img/delete.png" value="' . ($key + 1) . '" class="removedfile reposition" id="removedfile_' . $key . '" name="removedfile_' . $key . '" />';
1679
                    }
1680
                    $out .= '<br></div>';
1681
                }
1682
            } else {
1683
                //$out .= $langs->trans("NoAttachedFiles").'<br>';
1684
            }
1685
            if ($this->withfile == 2) { // Can add other files
1686
                $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="' . $langs->trans("Upload") . '" />';
1687
                $out .= ' ';
1688
                $out .= '<input type="submit" class="button smallpaddingimp reposition" id="' . $addfileaction . '" name="' . $addfileaction . '" value="' . $langs->trans("MailingAddFile") . '" />';
1689
            }
1690
            $out .= "</td></tr>\n";
1691
1692
            print $out;
1693
        }
1694
1695
        // MESSAGE
1696
1697
        $defaultmessage = "";
1698
        if (is_object($arraydefaultmessage) && $arraydefaultmessage->content) {
1699
            $defaultmessage = $arraydefaultmessage->content;
1700
        }
1701
        $defaultmessage = str_replace('\n', "\n", $defaultmessage);
1702
1703
        // Deal with format differences between message and signature (text / HTML)
1704
        if (dol_textishtml($defaultmessage) && !dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1705
            $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
1706
        } elseif (!dol_textishtml($defaultmessage) && isset($this->substit['__USER_SIGNATURE__']) && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
1707
            $defaultmessage = dol_nl2br($defaultmessage);
1708
        }
1709
        if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
1710
            $defaultmessage = GETPOST('message', 'restricthtml');
1711
        } else {
1712
            $defaultmessage = make_substitutions($defaultmessage, $this->substit);
1713
            // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
1714
            $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
1715
            $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
1716
        }
1717
1718
        print '<tr><td colspan="2"><label for="message"><span class="fieldrequired">' . $langs->trans("Message") . '</span>';
1719
        if ($user->hasRight("ticket", "write") && !$user->socid) {
1720
            $texttooltip = $langs->trans("TicketMessageHelp");
1721
            if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO') || getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
1722
                $texttooltip .= '<br><br>' . $langs->trans("ForEmailMessageWillBeCompletedWith") . '...';
1723
            }
1724
            if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO')) {
1725
                $mail_intro = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO'), $this->substit);
1726
                print '<input type="hidden" name="mail_intro" value="' . $mail_intro . '">';
1727
                $texttooltip .= '<br><u>' . $langs->trans("TicketMessageMailIntro") . '</u><br>' . $mail_intro;
1728
            }
1729
            if (getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
1730
                $mail_signature = make_substitutions(getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE'), $this->substit);
1731
                print '<input type="hidden" name="mail_signature" value="' . $mail_signature . '">';
1732
                $texttooltip .= '<br><br><u>' . $langs->trans("TicketMessageMailFooter") . '</u><br>' . $mail_signature;
1733
            }
1734
            print $form->textwithpicto('', $texttooltip, 1, 'help');
1735
        }
1736
        print '</label></td></tr>';
1737
1738
1739
        print '<tr><td colspan="2">';
1740
        //$toolbarname = 'dolibarr_details';
1741
        $toolbarname = 'dolibarr_notes';
1742
        $doleditor = new DolEditor('message', $defaultmessage, '100%', 200, $toolbarname, '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_5, '90%');
1743
        $doleditor->Create();
1744
        print '</td></tr>';
1745
1746
        // Footer
1747
        // External users can't send message email
1748
        /*if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_SIGNATURE)) {
1749
            $mail_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
1750
            print '<tr class="email_line"><td><label for="mail_intro">'.$langs->trans("TicketMessageMailFooter").'</label>';
1751
            print $form->textwithpicto('', $langs->trans("TicketMessageMailFooterHelp"), 1, 'help');
1752
            print '</td><td>';
1753
            include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1754
            $doleditor = new DolEditor('mail_signature', $mail_signature, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_2, 70);
1755
            $doleditor->Create();
1756
            print '</td></tr>';
1757
        }
1758
        */
1759
1760
        print '</table>';
1761
1762
        print '<br><center>';
1763
        print '<input type="submit" class="button" name="btn_add_message" value="' . $langs->trans("Add") . '"';
1764
        // Add a javascript test to avoid to forget to submit file before sending email
1765
        if ($this->withfile == 2 && !empty($conf->use_javascript_ajax)) {
1766
            print ' onClick="if (document.ticket.addedfile.value != \'\') { alert(\'' . dol_escape_js($langs->trans("FileWasNotUploaded")) . '\'); return false; } else { return true; }"';
1767
        }
1768
        print ' />';
1769
        if (!empty($this->withcancel)) {
1770
            print " &nbsp; &nbsp; ";
1771
            print '<input class="button button-cancel" type="submit" name="cancel" value="' . $langs->trans("Cancel") . '">';
1772
        }
1773
        print "</center>\n";
1774
1775
        print '<input type="hidden" name="page_y">' . "\n";
1776
1777
        print "</form><br>\n";
1778
1779
        // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
1780
        if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
1781
            print '<script type="text/javascript">';
1782
            print 'jQuery(document).ready(function () {';
1783
            print '		$(document).on("keypress", \'#ticket\', function (e) {		/* Note this is called at every key pressed ! */
1784
	    					var code = e.keyCode || e.which;
1785
	    					if (code == 13) {
1786
								console.log("Enter was intercepted and blocked");
1787
	        					e.preventDefault();
1788
	        					return false;
1789
	    					}
1790
						});';
1791
            print '})';
1792
            print '</script>';
1793
        }
1794
1795
        print "<!-- End form TICKET -->\n";
1796
    }
1797
}
1798