Passed
Pull Request — dev (#8)
by Rafael
58:47
created

FormTicket   F

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

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