dolibarr 23.0.3
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2013-2016 Jean-François FERRY <hello@librethic.io>
3 * Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr>
4 * Copyright (C) 2018 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2021-2025 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
7 * Copyright (C) 2022-2023 Charlene Benke <charlene@patas-monkey.com>
8 * Copyright (C) 2023 Benjamin Falière <benjamin.faliere@altairis.fr>
9 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
10 * Copyright (C) 2024 Irvine FLEITH <irvine.fleith@atm-consulting.fr>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 */
25
32// Load Dolibarr environment
33require '../main.inc.php';
34require_once DOL_DOCUMENT_ROOT.'/ticket/class/actions_ticket.class.php';
35require_once DOL_DOCUMENT_ROOT.'/core/class/html.formticket.class.php';
36require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
42require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
43
44if (isModEnabled('project')) {
45 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
46 include_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
47 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
48}
49if (isModEnabled('contract')) {
50 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formcontract.class.php';
51 include_once DOL_DOCUMENT_ROOT.'/core/lib/contract.lib.php';
52 include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
53}
54
63// Load translation files required by the page
64$langs->loadLangs(array("companies", "other", "ticket"));
65
66// Get parameters
67$id = GETPOSTINT('id');
68$ref = GETPOST('ref', 'alpha');
69$track_id = GETPOST('track_id', 'alpha', 3);
70$socid = GETPOSTINT('socid');
71$contactid = GETPOSTINT('contactid');
72$projectid = GETPOSTINT('projectid');
73$notifyTiers = GETPOST("notify_tiers_at_create", 'alpha');
74
75$action = GETPOST('action', 'aZ09');
76$cancel = GETPOST('cancel', 'alpha');
77$backtopage = GETPOST('backtopage', 'alpha');
78$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha');
79$contextpage = GETPOST('contextpage', 'aZ');
80
81$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
82$sortfield = GETPOST('sortfield', 'aZ09comma') ? GETPOST('sortfield', 'aZ09comma') : "a.datep";
83$sortorder = GETPOST('sortorder', 'aZ09comma') ? GETPOST('sortorder', 'aZ09comma') : "desc";
84$search_rowid = GETPOST('search_rowid');
85$search_agenda_label = GETPOST('search_agenda_label');
86
87if (GETPOST('actioncode', 'array')) {
88 $actioncode = GETPOST('actioncode', 'array', 3);
89 if (!count($actioncode)) {
90 $actioncode = '0';
91 }
92} else {
93 $actioncode = GETPOST("actioncode", "alpha", 3) ? GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : getDolGlobalString('AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT'));
94}
95
96
97// Initialize a technical object to manage hooks of ticket. Note that conf->hooks_modules contains array array
98$hookmanager->initHooks(array('ticketcard', 'globalcard'));
99
100$object = new Ticket($db);
101$extrafields = new ExtraFields($db);
102
103// Fetch optionals attributes and labels
104$extrafields->fetch_name_optionals_label($object->table_element);
105
106$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
107
108// Initialize array of search criteria
109$search_all = GETPOST("search_all", 'alpha');
110$search = array();
111foreach ($object->fields as $key => $val) {
112 if (GETPOST('search_'.$key, 'alpha')) {
113 $search[$key] = GETPOST('search_'.$key, 'alpha');
114 }
115}
116
117if (empty($action) && empty($id) && empty($ref)) {
118 $action = 'view';
119}
120
121// Select mail models is same action as add_message
122if (GETPOST('modelselected', 'alpha')) {
123 $action = 'presend';
124}
125
126// Load object
127//include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'. Include fetch and fetch_thirdparty but not fetch_optionals
128if ($id || $track_id || $ref) {
129 $res = $object->fetch($id, $ref, $track_id);
130 if ($res >= 0) {
131 $id = $object->id;
132 $track_id = $object->track_id;
133 }
134}
135
136$now = dol_now();
137
138$actionobject = new ActionsTicket($db);
139
140// Store current page url
141$url_page_current = DOL_URL_ROOT.'/ticket/card.php';
142
143// Security check - Protection if external user
144if ($user->socid > 0) {
145 $socid = $user->socid;
146}
147$result = restrictedArea($user, 'ticket', $object->id);
148
149$triggermodname = 'TICKET_MODIFY';
150
151// Permissions
152$permissiontoread = $user->hasRight('ticket', 'read');
153$permissiontoadd = $user->hasRight('ticket', 'write');
154$permissiontodelete = $user->hasRight('ticket', 'delete');
155$permissiontoeditextra = $permissiontoadd;
156if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
157 // For action 'update_extras', is there a specific permission set for the attribute to update
158 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
159}
160
161$upload_dir = $conf->ticket->dir_output;
162
163
164
165/*
166 * Actions
167 */
168
169$parameters = array();
170$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
171if ($reshook < 0) {
172 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
173}
174
175$error = 0;
176if (empty($reshook)) {
177 // Purge search criteria
178 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // All test are required to be compatible with all browsers{
179 $actioncode = '';
180 $search_agenda_label = '';
181 }
182
183 $backurlforlist = DOL_URL_ROOT . '/ticket/list.php';
184
185 if (empty($backtopage) || ($cancel && empty($id))) {
186 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
187 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
188 $backtopage = $backurlforlist;
189 } else {
190 $backtopage = DOL_URL_ROOT . '/ticket/card.php?id=' . ((!empty($id) && $id > 0) ? $id : '__ID__');
191 }
192 }
193 }
194
195 if ($cancel) {
196 if (!empty($backtopageforcancel)) {
197 header("Location: " . $backtopageforcancel);
198 exit;
199 } elseif (!empty($backtopage)) {
200 header("Location: " . $backtopage);
201 exit;
202 }
203 $action = 'view';
204 }
205
206 if ((($action == 'add' && GETPOST('save', 'alpha')) || ($action == 'update' && $object->status < Ticket::STATUS_CLOSED)) && $permissiontoadd) {
207 $ifErrorAction = ($action == 'add' ? 'create' : 'edit'); // Test on permission not required here
208 if ($action == 'add') { // Test on permission already done
209 $object->track_id = null;
210 }
211 $error = 0;
212
213 $fieldsToCheck = [
214 'ref' => ['check' => 'alpha', 'langs' => 'Ref'],
215 'type_code' => ['check' => 'alpha', 'langs' => 'TicketTypeRequest'],
216 'category_code' => ['check' => 'alpha', 'langs' => 'TicketCategory'],
217 'severity_code' => ['check' => 'alpha', 'langs' => 'TicketSeverity'],
218 'subject' => ['check' => 'alphanohtml', 'langs' => 'Subject'],
219 'message' => ['check' => 'restricthtml', 'langs' => 'Message']
220 ];
221
222 FormTicket::checkRequiredFields($fieldsToCheck, $error);
223
224 if (!empty($error)) {
225 $action = $ifErrorAction;
226 }
227
228 $ret = $extrafields->setOptionalsFromPost(null, $object);
229 if ($ret < 0) {
230 $error++;
231 }
232 $getRef = GETPOST('ref', 'alpha');
233
234 if (!empty($getRef)) {
235 $isExistingRef = $object->checkExistingRef($action, $getRef);
236 } else {
237 $isExistingRef = true;
238 }
239
240 $style = '';
241
242 if ($isExistingRef) {
243 if ($action == 'update') { // Test on permission already done
244 $error++;
245 $action = 'edit';
246 $style = 'errors';
247 } elseif ($action == 'add') { // Test on permission already done
248 $object->ref = $object->getDefaultRef();
249 $object->track_id = null;
250 $style = 'warnings';
251 }
252 if (!empty($getRef)) {
253 setEventMessage($langs->trans('TicketRefAlreadyUsed', $getRef, $object->ref), $style);
254 }
255 }
256 if (!$error) {
257 $db->begin();
258
259 $object->type_code = GETPOST('type_code', 'alpha');
260 $object->category_code = GETPOST('category_code', 'alpha');
261 $object->severity_code = GETPOST('severity_code', 'alpha');
262 $object->subject = GETPOST('subject', 'alpha');
263 $object->message = GETPOST('message', 'restricthtml');
264 $object->fk_soc = GETPOSTINT('socid');
265 $fk_user_assign = GETPOSTINT('fk_user_assign');
266 $object->fk_project = GETPOSTINT('projectid');
267 $object->fk_contract = GETPOSTISSET('contractid') ? GETPOSTINT('contractid') : GETPOSTINT('contratid');
268
269 if ($fk_user_assign > 0) {
270 $object->fk_user_assign = $fk_user_assign;
271 $object->status = $object::STATUS_ASSIGNED;
272 }
273
274 if ($action == 'add') { // Test on permission already done
275 $object->type_code = GETPOST("type_code", 'alpha');
276 $object->type_label = $langs->trans($langs->getLabelFromKey($db, $object->type_code, 'c_ticket_type', 'code', 'label'));
277 $object->category_label = $langs->trans($langs->getLabelFromKey($db, $object->category_code, 'c_ticket_category', 'code', 'label'));
278 $object->severity_label = $langs->trans($langs->getLabelFromKey($db, $object->severity_code, 'c_ticket_severity', 'code', 'label'));
279 $object->fk_user_create = $user->id;
280 $object->email_from = $user->email;
281 $object->origin_email = null;
282 $notifyTiers = GETPOST("notify_tiers_at_create", 'alpha');
283 $object->notify_tiers_at_create = empty($notifyTiers) ? 0 : 1;
284 $object->context['contact_id'] = GETPOSTINT('contactid');
285 $id = $object->create($user);
286 } else {
287 $id = $object->update($user);
288 }
289
290 if ($id <= 0) {
291 $error++;
292 setEventMessages($object->error, $object->errors, 'errors');
293 $action = $ifErrorAction;
294 }
295
296 if (!$error) {
297 // Category association
298 $categories = GETPOST('categories', 'array:int');
299 $object->setCategories($categories);
300 }
301
302 if ($action == 'add') { // Test on permission already done
303 if (!$error) {
304 // Add contact
305 $contactid = GETPOSTINT('contactid');
306 $type_contact = GETPOST("type", 'alpha');
307
308 if ($contactid > 0 && $type_contact) {
309 $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
310 $result = $object->add_contact($contactid, $typeid, 'external');
311 }
312
313 // Link ticket to project
314 if (GETPOST('origin', 'alpha') == 'projet') {
315 $projectid = GETPOSTINT('originid');
316 } else {
317 $projectid = GETPOSTINT('projectid');
318 }
319
320 if ($projectid > 0) {
321 $object->setProject($projectid);
322 }
323
324 // Auto mark as read if created from backend
325 if (getDolGlobalString('TICKET_AUTO_READ_WHEN_CREATED_FROM_BACKEND') && $user->hasRight('ticket', 'write')) {
326 if (!$object->markAsRead($user) > 0) {
327 setEventMessages($object->error, $object->errors, 'errors');
328 }
329 }
330
331 // Auto assign user
332 if ((empty($fk_user_assign) && getDolGlobalInt('TICKET_AUTO_ASSIGN_USER_CREATE') == 1) || (getDolGlobalInt('TICKET_AUTO_ASSIGN_USER_CREATE') == 2)) {
333 $result = $object->assignUser($user, $user->id, 1);
334 $object->add_contact($user->id, "SUPPORTTEC", 'internal');
335 }
336 }
337
338 if (!$error) {
339 // File transfer
340 $object->copyFilesForTicket(''); // trackid is forced to '' because files were uploaded when no id for ticket exists yet and trackid was ''
341 }
342 }
343 if (!$error) {
344 $db->commit();
345
346 if (!empty($backtopage)) {
347 if (empty($id)) {
348 $url = $backtopage;
349 } else {
350 $url = 'card.php?track_id=' . urlencode($object->track_id);
351 }
352 } else {
353 $url = 'card.php?track_id=' . urlencode($object->track_id);
354 }
355
356 header("Location: " . $url);
357 exit;
358 } else {
359 $db->rollback();
360 setEventMessages($object->error, $object->errors, 'errors');
361 }
362 } else {
363 $action = $ifErrorAction;
364 }
365 }
366
367 // Mark as Read
368 if ($action == "set_read" && $permissiontoadd) {
369 $object->fetch(0, '', GETPOST("track_id", 'alpha'));
370
371 if ($object->markAsRead($user) > 0) {
372 setEventMessages($langs->trans('TicketMarkedAsRead'), null, 'mesgs');
373
374 header("Location: card.php?track_id=" . $object->track_id);
375 exit;
376 } else {
377 setEventMessages($object->error, $object->errors, 'errors');
378 }
379 $action = 'view';
380 }
381
382 // Assign to someone
383 if ($action == "assign_user" && GETPOST('btn_assign_user', 'alpha') && $permissiontoadd) {
384 $object->fetch(0, '', GETPOST("track_id", 'alpha'));
385 $useroriginassign = $object->fk_user_assign;
386 $usertoassign = GETPOSTINT('fk_user_assign');
387
388 /*if (! ($usertoassign > 0)) {
389 $error++;
390 array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("AssignedTo")));
391 $action = 'view';
392 }*/
393
394 if (!$error) {
395 $ret = $object->assignUser($user, $usertoassign);
396 if ($ret < 0) {
397 $error++;
398 }
399 }
400
401 if (!$error) { // Update list of contacts
402 // If a user has already been assigned, we delete him from the contacts.
403 if ($useroriginassign > 0) {
404 $internal_contacts = $object->listeContact(-1, 'internal', 0, 'SUPPORTTEC');
405 foreach ($internal_contacts as $key => $contact) {
406 if ($contact['id'] !== $usertoassign) {
407 $result = $object->delete_contact($contact['rowid']);
408 if ($result < 0) {
409 $error++;
410 setEventMessages($object->error, $object->errors, 'errors');
411 }
412 }
413 }
414 }
415
416 if ($usertoassign > 0 && $usertoassign !== $useroriginassign) {
417 $result = $object->add_contact($usertoassign, "SUPPORTTEC", 'internal', $notrigger = 0);
418 if ($result < 0) {
419 $error++;
420 setEventMessages($object->error, $object->errors, 'errors');
421 }
422 }
423 }
424
425 if (!$error) {
426 // Log action in ticket logs table
427 $object->fetch_user($usertoassign);
428
429 setEventMessages($langs->trans('TicketAssigned'), null, 'mesgs');
430 header("Location: card.php?track_id=" . $object->track_id);
431 exit;
432 } else {
433 array_push($object->errors, $object->error);
434 }
435 $action = 'view';
436 }
437
438 // Action to add a message (private or not, with email or not).
439 // This may also send an email (concatenated with email_intro and email footer if checkbox was selected)
440 if ($action == 'add_message' && GETPOSTISSET('btn_add_message') && $permissiontoread) {
441 $ret = $object->newMessage($user, $action, GETPOSTINT('private_message'), 0);
442
443 if ($ret > 0) {
444 if (!empty($backtopage)) {
445 $url = $backtopage;
446 } else {
447 $url = 'card.php?track_id=' . urlencode($object->track_id);
448 }
449
450 header("Location: " . $url);
451 exit;
452 } else {
453 setEventMessages($object->error, $object->errors, 'errors');
454 $action = 'presend';
455 }
456 }
457
458 if (($action == "confirm_close" || $action == "confirm_abandon") && GETPOST('confirm', 'alpha') == 'yes' && $permissiontoadd) {
459 $object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha'));
460 if (GETPOSTISSET('contactid')) {
461 $object->context['contact_id'] = GETPOSTINT('contactid');
462 }
463
464 if ($object->close($user, ($action == "confirm_abandon" ? 1 : 0)) > 0) { // Test on pemrission already done
465 setEventMessages($langs->trans('TicketMarkedAsClosed'), null, 'mesgs');
466
467 $url = 'card.php?track_id=' . GETPOST('track_id', 'alpha');
468 header("Location: " . $url);
469 exit;
470 } else {
471 $action = '';
472 setEventMessages($object->error, $object->errors, 'errors');
473 }
474 }
475
476 if ($action == "confirm_public_close" && GETPOST('confirm', 'alpha') == 'yes' && $permissiontoadd) {
477 $object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha'));
478 if ($_SESSION['email_customer'] == $object->origin_email || $_SESSION['email_customer'] == $object->thirdparty->email) {
479 $object->context['contact_id'] = GETPOSTINT('contactid');
480
481 if ($object->close($user) > 0) {
482 setEventMessages('<div class="confirm">' . $langs->trans('TicketMarkedAsClosed') . '</div>', null, 'mesgs');
483
484 $url = 'card.php?track_id=' . GETPOST('track_id', 'alpha');
485 header("Location: " . $url);
486 exit;
487 }
488 setEventMessages($object->error, $object->errors, 'errors');
489 $action = '';
490 } else {
491 setEventMessages($object->error, $object->errors, 'errors');
492 $action = '';
493 }
494 }
495
496 if ($action == 'confirm_clone' && GETPOST('confirm', 'alpha') == "yes" && $permissiontoadd) {
497 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
498 $newid = $object->createFromClone($user, $object->id);
499 if ($newid > 0) {
500 header("Location: " . DOL_URL_ROOT . "/ticket/card.php?id=".$newid);
501 exit;
502 } else {
503 setEventMessages($object->error, $object->errors, 'errors');
504 $action = '';
505 }
506 }
507 }
508
509 if ($action == 'confirm_delete_ticket' && GETPOST('confirm', 'alpha') == "yes" && $permissiontodelete) {
510 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
511 if ($object->delete($user) > 0) {
512 setEventMessages('<div class="confirm">' . $langs->trans('TicketDeletedSuccess') . '</div>', null, 'mesgs');
513 header("Location: " . DOL_URL_ROOT . "/ticket/list.php");
514 exit;
515 } else {
516 $langs->load("errors");
517 $mesg = '<div class="error">' . $langs->trans($object->error) . '</div>';
518 $action = '';
519 }
520 }
521 }
522
523 // Set parent company
524 if ($action == 'set_thirdparty' && $user->hasRight('ticket', 'write')) {
525 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
526 $result = $object->setCustomer(GETPOSTINT('editcustomer'));
527 $url = $_SERVER["PHP_SELF"] . '?track_id=' . GETPOST('track_id', 'alpha');
528 header("Location: " . $url);
529 exit();
530 }
531 }
532
533 // Set progress status
534 if ($action == 'set_progression' && $user->hasRight('ticket', 'write')) {
535 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
536 $result = $object->setProgression(GETPOSTINT('progress'));
537
538 $url = 'card.php?track_id=' . $object->track_id;
539 header("Location: " . $url);
540 exit();
541 }
542 }
543
544 // Set categories
545 if ($action == 'set_categories' && $user->hasRight('ticket', 'write')) {
546 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
547 $result = $object->setCategories(GETPOST('categories', 'array'));
548
549 $url = 'card.php?track_id=' . $object->track_id;
550 header("Location: " . $url);
551 exit();
552 }
553 }
554
555 // Set Subject
556 if ($action == 'setsubject' && $user->hasRight('ticket', 'write')) {
557 if ($object->fetch(GETPOSTINT('id'))) {
558 if ($action == 'setsubject') { // Test on permission already done
559 $object->subject = GETPOST('subject', 'alphanohtml');
560 }
561
562 if ($action == 'setsubject' && empty($object->subject)) { // Test on permission already done
563 $error++;
564 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")), null, 'errors');
565 }
566
567 if (!$error) {
568 if (!$object->update($user) >= 0) {
569 $error++;
570 setEventMessages($object->error, $object->errors, 'errors');
571 }
572 }
573
574 header("Location: " . $_SERVER['PHP_SELF'] . "?track_id=" . $object->track_id);
575 exit;
576 }
577 }
578
579 if ($action == 'confirm_reopen' && $user->hasRight('ticket', 'manage') && !GETPOST('cancel')) {
580 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
581 // prevent browser refresh from reopening ticket several times
582 if ($object->status == Ticket::STATUS_CLOSED || $object->status == Ticket::STATUS_CANCELED) {
583 if ($object->fk_user_assign != null) {
584 $res = $object->setStatut(Ticket::STATUS_ASSIGNED, null, '', $triggermodname);
585 } else {
586 $res = $object->setStatut(Ticket::STATUS_NOT_READ, null, '', $triggermodname);
587 }
588 if ($res) {
589 $url = 'card.php?track_id=' . $object->track_id;
590 header("Location: " . $url);
591 exit();
592 } else {
593 $error++;
594 setEventMessages($object->error, $object->errors, 'errors');
595 }
596 }
597 }
598 } elseif ($action == 'classin' && $permissiontoadd) {
599 // Categorisation dans projet
600 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
601 $object->setProject($projectid);
602 $url = 'card.php?track_id=' . $object->track_id;
603 header("Location: " . $url);
604 exit();
605 }
606 } elseif ($action == 'setcontract' && $permissiontoadd) {
607 // Categorisation dans contrat
608 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
609 $object->setContract(GETPOSTINT('contractid'));
610 $url = 'card.php?track_id=' . $object->track_id;
611 header("Location: " . $url);
612 exit();
613 }
614 } elseif ($action == "set_message" && $user->hasRight('ticket', 'manage')) {
615 if (!GETPOST('cancel')) {
616 $object->fetch(0, '', GETPOST('track_id', 'alpha'));
617 //$oldvalue_message = $object->message;
618 $fieldtomodify = GETPOST('message_initial', 'restricthtml');
619
620 $object->message = $fieldtomodify;
621 $ret = $object->update($user);
622 if ($ret > 0) {
623 //include_once DOL_DOCUMENT_ROOT.'/core/class/utils_diff.class.php';
624 // output the result of comparing two files as plain text
625 //$log_action .= Diff::toString(Diff::compare(strip_tags($oldvalue_message), strip_tags($object->message)));
626
627 setEventMessages($langs->trans('TicketMessageSuccesfullyUpdated'), null, 'mesgs');
628 } else {
629 $error++;
630 setEventMessages($object->error, $object->errors, 'errors');
631 }
632 }
633
634 $action = 'view';
635 } elseif ($action == 'confirm_set_status' && $permissiontoadd && !GETPOST('cancel')) {
636 // Reopen ticket
637 if ($object->fetch(GETPOSTINT('id'), GETPOST('track_id', 'alpha')) >= 0) {
638 $new_status = GETPOSTINT('new_status');
639
640 $res = $object->setStatut($new_status, null, '', 'TICKET_MODIFY');
641
642 if ($res) {
643 $url = 'card.php?track_id=' . $object->track_id;
644 header("Location: " . $url);
645 exit();
646 } else {
647 $error++;
648 setEventMessages($object->error, $object->errors, 'errors');
649 }
650 }
651 }
652
653 // Action to update an extrafield
654 if ($action == "update_extras" && $permissiontoeditextra) {
655 $object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha'));
656
657 $attribute_name = GETPOST('attribute', 'aZ09');
658
659 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
660 if ($ret < 0) {
661 $error++;
662 }
663
664 if (!$error) {
665 $result = $object->updateExtraField($attribute_name, $triggermodname);
666 if ($result < 0) {
667 setEventMessages($object->error, $object->errors, 'errors');
668 $error++;
669 }
670 }
671
672 if ($error) {
673 $action = 'edit_extras';
674 }
675 }
676
677 if ($action == "change_property" && GETPOST('btn_update_ticket_prop', 'alpha') && $permissiontoadd) {
678 $object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha'));
679
680 $object->type_code = GETPOST('update_value_type', 'aZ09');
681 $object->severity_code = GETPOST('update_value_severity', 'aZ09');
682 $object->category_code = GETPOST('update_value_category', 'aZ09');
683
684 $ret = $object->update($user);
685 if ($ret > 0) {
686 setEventMessages($langs->trans('TicketUpdated'), null, 'mesgs');
687 } else {
688 $error++;
689 setEventMessages($object->error, $object->errors, 'errors');
690 }
691 $action = 'view';
692 }
693
694 // Actions when printing a doc from card
695 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
696
697 $permissiondellink = $user->hasRight('ticket', 'write');
698 include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
699
700 // Actions when printing a doc from card
701 include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php';
702
703 // Actions to build doc
704 include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php';
705
706 // Actions to send emails
707 $triggersendname = 'TICKET_SENTBYMAIL';
708 $paramname = 'id';
709 $autocopy = 'MAIN_MAIL_AUTOCOPY_TICKET_TO'; // used to know the automatic BCC to add
710 $trackid = 'tic' . $object->id;
711 include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php';
712
713 // Set $action to correct value for the case we used presend action to add a message
714 if (GETPOSTISSET('actionbis') && $action == 'presend') { // Test on permission not required here
715 $action = 'presend_addmessage';
716 }
717}
718
719
720/*
721 * View
722 */
723
724$userstat = new User($db);
725$form = new Form($db);
726$formfile = new FormFile($db);
727$formticket = new FormTicket($db);
728if (isModEnabled('project')) {
729 $formproject = new FormProjets($db);
730}
731
732$help_url = 'EN:Module_Ticket|FR:DocumentationModuleTicket';
733
734$title = $actionobject->getTitle($action, $object);
735
736llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-ticket page-card');
737
738if ($action == 'create' || $action == 'presend') {
739 if (empty($permissiontoadd)) {
740 accessforbidden('NotEnoughPermissions', 0, 1);
741 }
742
743 $formticket = new FormTicket($db);
744
745 print load_fiche_titre($langs->trans('NewTicket'), '', 'ticket');
746
747 $formticket->trackid = ''; // TODO Use a unique key 'tic' to avoid conflict in upload file feature
748
749 if (GETPOST("mode", "aZ09") == 'init' && empty($_POST)) {
750 $formticket->clear_attached_files();
751 }
752
753 $formticket->withfromsocid = $socid ? $socid : $user->socid;
754 $formticket->withfromcontactid = $contactid ? $contactid : '';
755 $formticket->withtitletopic = 1;
756 $formticket->withnotifytiersatcreate = ($notifyTiers ? 1 : (getDolGlobalString('TICKET_CHECK_NOTIFY_THIRDPARTY_AT_CREATION') ? 1 : 0));
757 $formticket->withusercreate = 0;
758 $formticket->withref = 1;
759 $formticket->fk_user_create = $user->id;
760 $formticket->withfile = 2;
761 $formticket->withextrafields = 1;
762 $formticket->param = array('origin' => GETPOST('origin'), 'originid' => GETPOST('originid'));
763
764 $formticket->withcancel = 1;
765
766 // Init list of files
767 if (GETPOST("mode", "aZ09") == 'init') {
768 $formticket->clear_attached_files();
769 }
770
771 $formticket->showForm(1, 'create', 0, null, $action, $object);
772
773 print dol_get_fiche_end();
774} elseif ($action == 'edit' && $user->hasRight('ticket', 'write') && $object->status < Ticket::STATUS_CLOSED) {
775 if (empty($permissiontoadd)) {
776 accessforbidden('NotEnoughPermissions', 0, 1);
777 }
778
779 $formticket = new FormTicket($db);
780
781 $head = ticket_prepare_head($object);
782
783 print dol_get_fiche_head($head, 'tabTicket', $langs->trans('Ticket'), -1, 'ticket');
784
785 $formticket->trackid = $object->track_id; // TODO Use a unique key 'tic' to avoid conflict in upload file feature
786 $formticket->withfromsocid = $object->socid;
787 $formticket->withtitletopic = 1;
788 // $formticket->withnotifytiersatcreate = ($notifyTiers ? 1 : (getDolGlobalString('TICKET_CHECK_NOTIFY_THIRDPARTY_AT_CREATION') ? 1 : 0));
789 $formticket->withnotifytiersatcreate = 0;
790 $formticket->withusercreate = 0;
791 $formticket->withref = 1;
792 $formticket->fk_user_create = $user->id;
793 $formticket->withfile = 0;
794 $formticket->action = 'update';
795 $formticket->withextrafields = 1;
796 $formticket->param = array('origin' => GETPOST('origin'), 'originid' => GETPOST('originid'));
797
798 $formticket->withcancel = 1;
799
800 $formticket->showForm(0, 'edit', 0, null, $action, $object);
801
802 print dol_get_fiche_end();
803} elseif ($object->id) {
804 if (!empty($res) && $res > 0) {
805 // or for unauthorized internals users
806 if (!$user->socid && (getDolGlobalString('TICKET_LIMIT_VIEW_ASSIGNED_ONLY') && $object->fk_user_assign != $user->id) && !$user->hasRight('ticket', 'manage')) {
807 accessforbidden('', 0, 1);
808 }
809
810 $formconfirm = '';
811
812 // Confirmation close
813 if ($action == 'close') {
814 $thirdparty_contacts = $object->getInfosTicketExternalContact(1);
815 $contacts_select = array(
816 '-2' => $langs->trans('TicketNotifyAllTiersAtClose'),
817 '-3' => $langs->trans('TicketNotNotifyTiersAtClose')
818 );
819 foreach ($thirdparty_contacts as $thirdparty_contact) {
820 $contacts_select[$thirdparty_contact['id']] = $thirdparty_contact['civility'] . ' ' . $thirdparty_contact['lastname'] . ' ' . $thirdparty_contact['firstname'];
821 }
822
823 // Default select all or no contact
824 $default = (getDolGlobalString('TICKET_NOTIFY_AT_CLOSING') ? '-2' : '-3');
825 $formquestion = array(
826 array(
827 'name' => 'contactid',
828 'type' => 'select',
829 'label' => $langs->trans('NotifyThirdpartyOnTicketClosing'),
830 'values' => $contacts_select,
831 'default' => $default
832 ),
833 );
834
835 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_close", $formquestion, '', 1);
836 }
837 // Confirmation abandon
838 if ($action == 'abandon') {
839 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("AbandonTicket"), $langs->trans("ConfirmAbandonTicket"), "confirm_abandon", '', '', 1);
840 }
841 // Confirmation delete
842 if ($action == 'delete') {
843 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("Delete"), $langs->trans("ConfirmDeleteTicket"), "confirm_delete_ticket", '', '', 1);
844 }
845 // Confirm reopen
846 if ($action == 'reopen') {
847 $formconfirm = $form->formconfirm($url_page_current.'?track_id='.$object->track_id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenTicket'), 'confirm_reopen', '', '', 1);
848 }
849 // Confirmation status change
850 if ($action == 'set_status') {
851 $new_status = GETPOSTINT('new_status');
852 //var_dump($url_page_current . "?track_id=" . $object->track_id);
853 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id."&new_status=".$new_status, $langs->trans("TicketChangeStatus"), $langs->trans("TicketConfirmChangeStatus", $langs->transnoentities($object->labelStatusShort[$new_status])), "confirm_set_status", '', '', 1);
854 }
855 // Clone confirmation
856 if ($action == 'clone') {
857 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', '', 'yes', 1);
858 }
859
860 // Call Hook formConfirm
861 $parameters = array('formConfirm' => $formconfirm);
862 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
863 if (empty($reshook)) {
864 $formconfirm .= $hookmanager->resPrint;
865 } elseif ($reshook > 0) {
866 $formconfirm = $hookmanager->resPrint;
867 }
868
869 // Print form confirm
870 print $formconfirm;
871
872 // project info
873 if ($projectid > 0) {
874 $projectstat = new Project($db);
875 if ($projectstat->fetch($projectid) > 0) {
876 $projectstat->fetch_thirdparty();
877
878 // To verify role of users
879 //$userAccess = $object->restrictedProjectArea($user,'read');
880 $userWrite = $projectstat->restrictedProjectArea($user, 'write');
881 //$userDelete = $object->restrictedProjectArea($user,'delete');
882 //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
883
884 $head = project_prepare_head($projectstat);
885
886 print dol_get_fiche_head($head, 'ticket', $langs->trans("Project"), 0, ($projectstat->public ? 'projectpub' : 'project'));
887
888 print '<table class="border centpercent">';
889
890 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
891
892 // Ref
893 print '<tr><td>'.$langs->trans('Ref').'</td><td colspan="3">';
894 // Define a complementary filter for search of next/prev ref.
895 if (!$user->hasRight('projet', 'all', 'lire')) {
896 $objectsListId = $projectstat->getProjectsAuthorizedForUser($user, $mine, 0);
897 $projectstat->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
898 }
899 print $form->showrefnav($projectstat, 'ref', $linkback, 1, 'ref', 'ref', '');
900 print '</td></tr>';
901
902 // Label
903 print '<tr><td>'.$langs->trans("Label").'</td><td>'.$projectstat->title.'</td></tr>';
904
905 // Customer
906 print "<tr><td>".$langs->trans("ThirdParty")."</td>";
907 print '<td colspan="3">';
908 if ($projectstat->thirdparty->id > 0) {
909 print $projectstat->thirdparty->getNomUrl(1);
910 } else {
911 print '&nbsp;';
912 }
913
914 print '</td></tr>';
915
916 // Visibility
917 print '<tr><td>'.$langs->trans("Visibility").'</td><td>';
918 if ($projectstat->public) {
919 print $langs->trans('SharedProject');
920 } else {
921 print $langs->trans('PrivateProject');
922 }
923
924 print '</td></tr>';
925
926 // Status
927 print '<tr><td>'.$langs->trans("Status").'</td><td>'.$projectstat->getLibStatut(4).'</td></tr>';
928
929 print "</table>";
930
931 print dol_get_fiche_end();
932 } else {
933 print "ErrorRecordNotFound";
934 }
935 } elseif ($socid > 0) {
936 $object->fetch_thirdparty();
937 $head = societe_prepare_head($object->thirdparty);
938
939 print dol_get_fiche_head($head, 'ticket', $langs->trans("ThirdParty"), 0, 'company');
940
941 dol_banner_tab($object->thirdparty, 'socid', '', ($user->socid ? 0 : 1), 'rowid', 'nom');
942
943 print dol_get_fiche_end();
944 }
945
946 if (!$user->socid && getDolGlobalString('TICKET_LIMIT_VIEW_ASSIGNED_ONLY')) {
947 $object->next_prev_filter = "te.fk_user_assign:=:".((int) $user->id);
948 } elseif ($user->socid > 0) {
949 $object->next_prev_filter = "te.fk_soc:=:".((int) $user->socid);
950 }
951
952 $head = ticket_prepare_head($object);
953
954 print dol_get_fiche_head($head, 'tabTicket', $langs->trans("Ticket"), -1, 'ticket', 0, '', '', 0, '', 1);
955
956 $morehtmlref = '<div class="refidno">';
957
958 if ($user->hasRight('ticket', 'write') && !$user->socid) {
959 $morehtmlref .= '<a class="editfielda" href="'.$url_page_current.'?action=editsubject&token='.newToken().'&track_id='.$object->track_id.'">'.img_edit($langs->transnoentitiesnoconv('SetTitle'), 0).'</a> ';
960 }
961 if ($action != 'editsubject') {
962 $morehtmlref .= dolPrintLabel($object->subject);
963 } else {
964 $morehtmlref .= '<form method="post" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
965 $morehtmlref .= '<input type="hidden" name="action" value="setsubject">';
966 $morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
967 $morehtmlref .= '<input type="hidden" name="id" value="'.$object->id.'">';
968 $morehtmlref .= '<input type="text" class="minwidth300" id="subject" name="subject" value="'.$object->subject.'" autofocus="">';
969 $morehtmlref .= '<input type="submit" class="smallpaddingimp button valignmiddle" name="modify" value="'.$langs->trans("Modify").'">';
970 $morehtmlref .= '<input type="submit" class="smallpaddingimp button button-cancel valignmiddle" name="cancel" value="'.$langs->trans("Cancel").'">';
971 $morehtmlref .= '</form>';
972 }
973
974 // Author
975 $createdbyshown = 0;
976 if ($object->fk_user_create > 0) {
977 $morehtmlref .= '<br>';
978 //$morehtmlref .= '<span class="opacitymedium">'.$langs->trans("CreatedBy").'</span> ';
979
980 $fuser = new User($db);
981 $fuser->fetch($object->fk_user_create);
982 $morehtmlref .= $fuser->getNomUrl(-1);
983 $createdbyshown++;
984 }
985
986 $createdfrompublicticket = 0;
987 $createdfromemailcollector = 0;
988 if (!empty($object->origin_email) && (empty($object->email_msgid) || preg_match('/dolibarr\-tic\d+/', $object->email_msgid))) {
989 // If ticket create from public interface - TODO Add a more robust test to know if created by public interface
990 $createdfrompublicticket = 1;
991 } elseif (!empty($object->email_msgid)) {
992 // If ticket create by emailcollector - TODO Add a more robust test to know if created by email collector (using import key ?)
993 $createdfromemailcollector = 1;
994 }
995
996 //var_dump($object);
997 $htmltooltip = '';
998 if ($createdfrompublicticket) {
999 $htmltooltip .= $langs->trans("OriginEmail").': '.$object->origin_email;
1000 $htmltooltip .= '<br>'.$langs->trans("IP").': '.dol_print_ip($object->ip);
1001 $morehtmlref .= ($createdbyshown ? ' - ' : '<br>');
1002 //$morehtmlref .= ($createdbyshown ? '' : '<span class="opacitymedium">'.$langs->trans("CreatedBy").' </span> ');
1003 $morehtmlref .= img_picto('', 'email', 'class="paddingrightonly"');
1004 $morehtmlref .= dol_escape_htmltag($object->origin_email).' <small class="hideonsmartphone opacitymedium">- '.$form->textwithpicto($langs->trans("CreatedByPublicPortal"), $htmltooltip, 1, 'help', '', 0, 3, 'tooltipcreatedbyportal').'</small>';
1005 } elseif ($createdfromemailcollector) {
1006 $langs->load("mails");
1007
1008 $htmltooltip .= '<b>'.$langs->trans("EmailMsgID").':</b> '.$object->email_msgid;
1009 $htmltooltip .= '<br><b>'.$langs->trans("EmailDate").':</b> '.dol_print_date($object->email_date, 'dayhour');
1010 $htmltooltip .= '<br><b>'.$langs->trans("MailFrom").':</b> '.$object->origin_email;
1011 $htmltooltip .= '<br><b>'.$langs->trans("MailReply").':</b> '.$object->origin_replyto;
1012 $htmltooltip .= '<br><b>'.$langs->trans("MailReferences").':</b> '.$object->origin_references;
1013 $morehtmlref .= ($createdbyshown ? ' - ' : '<br>');
1014 //$morehtmlref .= ($createdbyshown ? '' : '<span class="opacitymedium">'.$langs->trans("CreatedBy").'</span> ');
1015 $morehtmlref .= img_picto('From', 'email', 'class="paddingrightonly"');
1016 $morehtmlref .= dol_escape_htmltag($object->origin_email);
1017 if ($object->origin_replyto) {
1018 $morehtmlref .= ' - '.img_picto('ReplyTo', 'email', 'class="paddingrightonly"');
1019 $morehtmlref .= dol_escape_htmltag($object->origin_replyto);
1020 }
1021 $morehtmlref .= ' <small class="hideonsmartphone opacitymedium">- '.$form->textwithpicto($langs->trans("CreatedByEmailCollector"), $htmltooltip, 1, 'help', '', 0, 3, 'tooltipcreatedbyemailcollector').'</small>';
1022 }
1023
1024 $permissiontoedit = $object->status < 8 && !$user->socid && $user->hasRight('ticket', 'write');
1025 //$permissiontoedit = 0;
1026
1027 // Thirdparty
1028 if (isModEnabled("societe")) {
1029 $morehtmlref .= '<br>';
1030 if ($action != 'editcustomer' && $permissiontoedit) {
1031 $morehtmlref .= img_picto($langs->trans("ThirdParty"), 'company', 'class="pictofixedwidth"');
1032 $morehtmlref .= '<a class="editfielda" href="'.$url_page_current.'?action=editcustomer&token='.newToken().'&track_id='.$object->track_id.'">'.img_edit($langs->transnoentitiesnoconv('SetThirdParty'), 0).'</a> ';
1033 }
1034 $morehtmlref .= $form->form_thirdparty($url_page_current.'?track_id='.$object->track_id, (string) $object->socid, $action == 'editcustomer' ? 'editcustomer' : 'none', '', 1, 0, 0, array(), 1);
1035 if (!empty($object->socid)) {
1036 $morehtmlref .= ' - <a href="'.DOL_URL_ROOT.'/ticket/list.php?socid='.$object->socid.'&sortfield=t.datec&sortorder=desc'.(getDolGlobalBool('TICKET_CLIENT_OTHER_TICKET_ONLY_OPEN') ? '&search_fk_statut[]=openall' : '').'">'.img_picto($langs->trans("Tickets"), 'ticket', 'class="pictofixedwidth"').' '.$langs->trans("TicketHistory").'</a>';
1037 }
1038 }
1039
1040 // Project
1041 if (isModEnabled('project')) {
1042 $langs->load("projects");
1043 $morehtmlref .= '<br>';
1044 if ($permissiontoedit) {
1045 $object->fetchProject();
1046 $morehtmlref .= img_picto($langs->trans("Project"), 'project'.((is_object($object->project) && $object->project->public) ? 'pub' : ''), 'class="pictofixedwidth"');
1047 if ($action != 'classify') {
1048 $morehtmlref .= '<a class="editfielda" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true).'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
1049 }
1050 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
1051 } else {
1052 if (!empty($object->fk_project)) {
1053 $object->fetchProject();
1054 $morehtmlref .= $object->project->getNomUrl(1);
1055 if ($object->project->title) {
1056 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($object->project->title).'</span>';
1057 }
1058 }
1059 }
1060 }
1061
1062 // Contract
1063 if (getDolGlobalString('TICKET_LINK_TO_CONTRACT_WITH_HARDLINK')) {
1064 // Deprecated. Duplicate feature. Ticket can already be linked to contract with the generic "Link to" feature.
1065 if (isModEnabled('contract')) {
1066 $langs->load('contracts');
1067 $morehtmlref .= '<br>';
1068 if ($permissiontoedit) {
1069 $morehtmlref .= img_picto($langs->trans("Contract"), 'contract', 'class="pictofixedwidth"');
1070 if ($action == 'edit_contrat') {
1071 $formcontract = new FormContract($db);
1072 $morehtmlref .= $formcontract->formSelectContract($_SERVER["PHP_SELF"].'?id='.$object->id, $object->socid, $object->fk_contract, 'contratid', 0, 1, 1, 1);
1073 } else {
1074 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit_contrat&token='.newToken().'&id='.$object->id.'">';
1075 $morehtmlref .= img_edit($langs->trans('SetContract'));
1076 $morehtmlref .= '</a>';
1077 }
1078 } else {
1079 if (!empty($object->fk_contract)) {
1080 $contratstatic = new Contrat($db);
1081 $contratstatic->fetch($object->fk_contract);
1082 //print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
1083 $morehtmlref .= $contratstatic->getNomUrl(0, 0, 1);
1084 }
1085 }
1086 }
1087 }
1088
1089 $morehtmlref .= '</div>';
1090
1091 $linkback = '<a href="'.DOL_URL_ROOT.'/ticket/list.php?restore_lastsearch_values=1"><strong>'.$langs->trans("BackToList").'</strong></a> ';
1092
1093 dol_banner_tab($object, 'ref', $linkback, ($user->socid ? 0 : 1), 'ref', 'ref', $morehtmlref);
1094
1095 print '<div class="fichecenter">';
1096 print '<div class="fichehalfleft">';
1097 print '<div class="underbanner clearboth"></div>';
1098
1099 print '<table class="border tableforfield centpercent">';
1100
1101 // Track ID
1102 print '<tr><td class="titlefieldmiddle">'.$langs->trans("TicketTrackId").'</td><td>';
1103 if (!empty($object->track_id)) {
1104 if (empty($object->ref)) {
1105 $object->ref = (string) $object->id;
1106 print $form->showrefnav($object, 'id', $linkback, 1, 'rowid', 'track_id');
1107 } else {
1108 print dolPrintLabel($object->track_id);
1109 }
1110 } else {
1111 print $langs->trans('None');
1112 }
1113 print '</td></tr>';
1114
1115 // Subject
1116 /*
1117 print '<tr><td>';
1118 print $form->editfieldkey("Subject", 'subject', $object->subject, $object, $user->hasRight('ticket', 'write') && !$user->socid, 'string');
1119 print '</td><td>';
1120 print $form->editfieldval("Subject", 'subject', $object->subject, $object, $user->hasRight('ticket', 'write') && !$user->socid, 'string');
1121 print '</td></tr>';
1122 */
1123
1124 // Creation date
1125 print '<tr><td>'.$langs->trans("DateCreation").'</td><td>';
1126 print dol_print_date($object->datec, 'dayhour', 'tzuser');
1127 print '<span class="opacitymedium"><span class="small"> - '.$langs->trans("TimeElapsedSince").': <b><i>'.convertSecondToTime(roundUpToNextMultiple($now - $object->datec, 60)).'</i></b></span></span>';
1128 print '</td></tr>';
1129
1130 // Origin
1131 /*
1132 if ($object->email_msgid) {
1133 $texttoshow = $langs->trans("CreatedByEmailCollector");
1134 } elseif ($object->origin_email) {
1135 $texttoshow = $langs->trans("FromPublicEmail");
1136 }
1137 if ($texttoshow) {
1138 print '<tr><td class="titlefield fieldname_email_origin">';
1139 print $langs->trans("Origin");
1140 print '</td>';
1141 print '<td class="valuefield fieldname_email_origin">';
1142 print $texttoshow;
1143 print '</td></tr>';
1144 }
1145 */
1146
1147 // Read date
1148 print '<tr><td>'.$langs->trans("TicketReadOn").'</td><td>';
1149 if (!empty($object->date_read)) {
1150 print dol_print_date($object->date_read, 'dayhour', 'tzuser');
1151 print '<span class="opacitymedium"><span class="small"> - '.$langs->trans("TimeElapsedSince").': ';
1152 //print '<b><i>'.convertSecondToTime(roundUpToNextMultiple($object->date_read - $object->datec, 60)).'</i></b>';
1153 //print ' / ';
1154 print '<b><i>'.convertSecondToTime(roundUpToNextMultiple($now - $object->date_read, 60)).'</i></b></span></span>';
1155 }
1156 print '</td></tr>';
1157
1158 // Close date
1159 print '<tr><td>'.$langs->trans("TicketCloseOn").'</td><td>';
1160 if (!empty($object->date_close)) {
1161 print dol_print_date($object->date_close, 'dayhour', 'tzuser');
1162 }
1163 print '</td></tr>';
1164
1165 // User assigned
1166 print '<tr><td>';
1167 print '<table class="nobordernopadding" width="100%"><tr><td class="nowrap">';
1168 print $langs->trans("AssignedTo");
1169 if (isset($object->status) && $object->status < $object::STATUS_CLOSED && GETPOST('set', 'alpha') != "assign_ticket" && $user->hasRight('ticket', 'manage')) {
1170 print '</td><td class="right"><a class="editfielda" href="'.$url_page_current.'?track_id='.urlencode($object->track_id).'&set=assign_ticket">'.img_edit($langs->trans('Modify')).'</a>';
1171 }
1172 print '</td></tr></table>';
1173 print '</td><td>';
1174 if (GETPOST('set', 'alpha') != "assign_ticket" && $object->fk_user_assign > 0) {
1175 $userstat->fetch($object->fk_user_assign);
1176 print $userstat->getNomUrl(-1);
1177 }
1178
1179 // Show user list to assignate one if status is "read"
1180 if (GETPOST('set', 'alpha') == "assign_ticket" && $object->status < 8 && !$user->socid && $user->hasRight('ticket', 'write')) {
1181 print '<form method="post" name="ticket" enctype="multipart/form-data" action="'.$url_page_current.'">';
1182 print '<input type="hidden" name="token" value="'.newToken().'">';
1183 print '<input type="hidden" name="action" value="assign_user">';
1184 print '<input type="hidden" name="track_id" value="'.$object->track_id.'">';
1185 //print '<label for="fk_user_assign">'.$langs->trans("AssignUser").'</label> ';
1186 print $form->select_dolusers(empty($object->fk_user_assign) ? $user->id : $object->fk_user_assign, 'fk_user_assign', 1);
1187 print ' <input type="submit" class="button smallpaddingimp" name="btn_assign_user" value="'.$langs->trans("Validate").'" />';
1188 print '</form>';
1189 }
1190 print '</td></tr>';
1191
1192 // Progression
1193 print '<tr><td>';
1194 print '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
1195 print $langs->trans('Progression').'</td><td class="left">';
1196 print '</td>';
1197 if ($action != 'progression' && isset($object->status) && $object->status < $object::STATUS_CLOSED && !$user->socid) {
1198 print '<td class="right"><a class="editfielda" href="'.$url_page_current.'?action=progression&token='.newToken().'&track_id='.urlencode($object->track_id).'">'.img_edit($langs->trans('Modify')).'</a></td>';
1199 }
1200 print '</tr></table>';
1201 print '</td><td>';
1202 if ($user->hasRight('ticket', 'write') && $action == 'progression') {
1203 print '<form action="'.$url_page_current.'" method="post">';
1204 print '<input type="hidden" name="token" value="'.newToken().'">';
1205 print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1206 print '<input type="hidden" name="action" value="set_progression">';
1207 print '<input type="text" class="flat width75" name="progress" value="'.$object->progress.'">';
1208 print ' <input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
1209 print '</form>';
1210 } else {
1211 print($object->progress > 0 ? $object->progress : '0').'%';
1212 }
1213 print '</td>';
1214 print '</tr>';
1215
1216 // Timing (Duration sum of linked fichinter)
1217 if (isModEnabled('intervention')) {
1218 $object->fetchObjectLinked();
1219 $num = count($object->linkedObjects);
1220 $timing = 0;
1221 $foundinter = 0;
1222 if ($num) {
1223 foreach ($object->linkedObjects as $objecttype => $objects) {
1224 if ($objecttype == "fichinter") {
1225 '@phan-var-force Fichinter[] $objects';
1226 foreach ($objects as $fichinter) {
1227 $foundinter++;
1229 $timing += $fichinter->duration;
1230 }
1231 }
1232 }
1233 }
1234 print '<tr><td>';
1235 print $form->textwithpicto($langs->trans("TicketDurationAuto"), $langs->trans("TicketDurationAutoInfos"), 1);
1236 print '</td><td>';
1237 print $foundinter ? convertSecondToTime($timing, 'all', getDolGlobalInt('MAIN_DURATION_OF_WORKDAY')) : '';
1238 print '</td></tr>';
1239 }
1240
1241 // Other attributes
1242 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
1243
1244 print '</table>';
1245
1246
1247 // End of left column and beginning of right column
1248 print '</div><div class="fichehalfright">';
1249
1250
1251 print '<form method="post" name="formticketproperties" action="'.$url_page_current.'">';
1252 print '<input type="hidden" name="token" value="'.newToken().'">';
1253 print '<input type="hidden" name="action" value="change_property">';
1254 print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1255 print '<input type="hidden" name="trackid" value="'.$trackid.'">';
1256
1257 // Classification of ticket
1258 print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you don't need reserved height for your table
1259 print '<table class="border tableforfield centpercent margintable bordertopimp">';
1260 print '<tr class="liste_titre">';
1261 print '<td>';
1262 print $langs->trans('TicketProperties');
1263 print '</td>';
1264 print '<td>';
1265 if (GETPOST('set', 'alpha') == 'properties' && $user->hasRight('ticket', 'write')) {
1266 print '<input type="submit" class="button smallpaddingimp" name="btn_update_ticket_prop" value="'.$langs->trans("Modify").'" />';
1267 } else {
1268 // Button to edit Properties
1269 if (isset($object->status) && ($object->status < $object::STATUS_NEED_MORE_INFO || !getDolGlobalInt('TICKET_DISALLOW_CLASSIFICATION_MODIFICATION_EVEN_IF_CLOSED')) && $user->hasRight('ticket', 'write')) {
1270 print ' <a class="editfielda" href="card.php?track_id='.$object->track_id.'&set=properties">'.img_edit($langs->trans('Modify')).'</a>';
1271 }
1272 }
1273 print '</td>';
1274 print '</tr>';
1275
1276 if (GETPOST('set', 'alpha') == 'properties' && $user->hasRight('ticket', 'write')) {
1277 print '<tr>';
1278 // Type
1279 print '<td class="titlefield">';
1280 print $langs->trans('Type');
1281 print '</td><td>';
1282 $formticket->selectTypesTickets($object->type_code, 'update_value_type', '', 2);
1283 print '</td>';
1284 print '</tr>';
1285 // Group
1286 print '<tr>';
1287 print '<td>';
1288 print $langs->trans('TicketCategory');
1289 print '</td><td>';
1290 $formticket->selectGroupTickets($object->category_code, 'update_value_category', '', 2, 0, 0, 0, 'maxwidth500 widthcentpercentminusxx');
1291 print '</td>';
1292 print '</tr>';
1293 // Severity
1294 print '<tr>';
1295 print '<td>';
1296 print $langs->trans('TicketSeverity');
1297 print '</td><td>';
1298 $formticket->selectSeveritiesTickets($object->severity_code, 'update_value_severity', '', 2);
1299 print '</td>';
1300 print '</tr>';
1301 } else {
1302 // Type
1303 print '<tr><td class="titlefield">'.$langs->trans("Type").'</td><td>';
1304 if (!empty($object->type_code)) {
1305 print $langs->getLabelFromKey($db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code);
1306 }
1307 print '</td></tr>';
1308 // Group
1309 $s = '';
1310 if (!empty($object->category_code)) {
1311 $s = $langs->getLabelFromKey($db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code);
1312 }
1313 print '<tr><td>'.$langs->trans("TicketCategory").'</td><td class="tdoverflowmax200" title="'.dol_escape_htmltag($s).'">';
1314 print dol_escape_htmltag($s);
1315 print '</td></tr>';
1316 // Severity
1317 print '<tr><td>'.$langs->trans("TicketSeverity").'</td><td>';
1318 if (!empty($object->severity_code)) {
1319 print $langs->getLabelFromKey($db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code);
1320 }
1321 print '</td></tr>';
1322 }
1323 print '</table>'; // End table actions
1324 print '</div>';
1325
1326 print '</form>';
1327
1328 // Tags/Categories
1329 if (isModEnabled('category')) {
1330 print '<!-- tag/categories -->'."\n";
1331 print '<table class="border centpercent tableforfield">';
1332 print '<tr>';
1333 print '<td class="valignmiddle titlefield">';
1334 print '<table class="nobordernopadding centpercent"><tr><td class="none">';
1335 print $langs->trans("Categories");
1336 if ($action != 'categories' && !$user->socid) {
1337 print '</td><td class="right"><a class="editfielda" href="'.$url_page_current.'?action=categories&track_id='.urlencode($object->track_id).'">'.img_edit($langs->trans('Modify')).'</a>';
1338 }
1339 print '</td>';
1340 print '</table>';
1341 print '</td>';
1342
1343 if ($user->hasRight('ticket', 'write') && $action == 'categories') {
1344 print '<td colspan="3">';
1345 print '<form action="'.$url_page_current.'" method="POST">';
1346 print '<input type="hidden" name="token" value="'.newToken().'">';
1347 print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1348 print '<input type="hidden" name="action" value="set_categories">';
1349 print $form->selectCategories(Categorie::TYPE_TICKET, 'categories', $object);
1350 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Save').'">';
1351 print '</form>';
1352 print "</td>";
1353 } else {
1354 print '<td colspan="3">';
1355 print $form->showCategories($object->id, Categorie::TYPE_TICKET, 1);
1356 print "</td></tr>";
1357 }
1358
1359 print '</table>';
1360 }
1361
1362 // View Original message
1363 $actionobject->viewTicketOriginalMessage($user, $action, $object);
1364
1365
1366 // Display navbar with links to change ticket status
1367 print '<!-- navbar with status -->';
1368 if (!$user->socid && $user->hasRight('ticket', 'write') && isset($object->status) && $object->status < $object::STATUS_CLOSED) {
1369 $actionobject->viewStatusActions($object);
1370 }
1371
1372
1373 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
1374 print load_fiche_titre($langs->trans('Contacts'), '', 'title_companies.png');
1375
1376 print '<div class="div-table-responsive-no-min">';
1377 print '<div class="tagtable centpercent noborder allwidth">';
1378
1379 print '<div class="tagtr liste_titre">';
1380 print '<div class="tagtd">'.$langs->trans("Source").'</div>
1381 <div class="tagtd">' . $langs->trans("Company").'</div>
1382 <div class="tagtd">' . $langs->trans("Contacts").'</div>
1383 <div class="tagtd">' . $langs->trans("ContactType").'</div>
1384 <div class="tagtd">' . $langs->trans("Phone").'</div>
1385 <div class="tagtd center">' . $langs->trans("Status").'</div>';
1386 print '</div><!-- tagtr -->';
1387
1388 // Contact list
1389 $companystatic = new Societe($db);
1390 $contactstatic = new Contact($db);
1391 $userstatic = new User($db);
1392 $var = false;
1393 foreach (array('internal', 'external') as $source) {
1394 $tmpobject = $object;
1395 $tab = $tmpobject->listeContact(-1, $source);
1396 // '@phan-var-force array<array{source:string,id:int,rowid:int,email:string,civility:string,firstname:string,lastname:string,labeltype:string,libelle:string,socid:int,code:string,status:int,statuscontact:int,fk_c_typecontact:string,phone:string,phone_mobile:string,phone_perso?:string,nom:string}> $tab';
1397 $num = is_array($tab) ? count($tab) : 0;
1398 $i = 0;
1399 foreach (array_keys($tab) as $i) {
1400 $tab_i = &$tab[$i];
1401 $var = !$var;
1402 print '<div class="tagtr '.($var ? 'pair' : 'impair').'">';
1403
1404 print '<div class="tagtd left">';
1405 if ($tab_i['source'] == 'internal') {
1406 echo $langs->trans("User");
1407 }
1408
1409 if ($tab_i['source'] == 'external') {
1410 echo $langs->trans("ThirdPartyContact");
1411 }
1412
1413 print '</div>';
1414 print '<div class="tagtd left">';
1415
1416 if ($tab_i['socid'] > 0) {
1417 $companystatic->fetch($tab_i['socid']);
1418 echo $companystatic->getNomUrl(-1);
1419 }
1420 if ($tab_i['socid'] < 0) {
1421 echo getDolGlobalString('MAIN_INFO_SOCIETE_NOM');
1422 }
1423 if (!$tab_i['socid']) {
1424 echo '&nbsp;';
1425 }
1426 print '</div>';
1427
1428 print '<div class="tagtd">';
1429 if ($tab_i['source'] == 'internal') {
1430 if ($userstatic->fetch($tab_i['id'])) {
1431 print $userstatic->getNomUrl(-1);
1432 }
1433 }
1434 if ($tab_i['source'] == 'external') {
1435 if ($contactstatic->fetch($tab_i['id'])) {
1436 print $contactstatic->getNomUrl(-1);
1437 }
1438 }
1439 print ' </div>
1440 <div class="tagtd">' . $tab_i['libelle'].'</div>';
1441
1442 print '<div class="tagtd">';
1443
1444 print dol_print_phone($tab_i['phone'], '', 0, 0, 'AC_TEL').'<br>';
1445
1446 if (array_key_exists('phone_perso', $tab_i) && !empty($tab_i['phone_perso'])) {
1447 //print img_picto($langs->trans('PhonePerso'),'object_phoning.png','',0,0,0).' ';
1448 print '<br>'.dol_print_phone((string) $tab_i['phone_perso'], '', 0, 0, 'AC_TEL').'<br>';
1449 }
1450 if (!empty($tab_i['phone_mobile'])) {
1451 //print img_picto($langs->trans('PhoneMobile'),'object_phoning.png','',0,0,0).' ';
1452 print dol_print_phone($tab_i['phone_mobile'], '', 0, 0, 'AC_TEL').'<br>';
1453 }
1454 print '</div>';
1455
1456 print '<div class="tagtd center">';
1457 if ($object->status >= 0) {
1458 echo '<a href="contact.php?track_id='.$object->track_id.'&amp;action=swapstatut&amp;ligne='.$tab_i['rowid'].'">';
1459 }
1460
1461 if ($tab_i['source'] == 'internal') {
1462 $userstatic->id = $tab_i['id'];
1463 $userstatic->lastname = $tab_i['lastname'];
1464 $userstatic->firstname = $tab_i['firstname'];
1465 echo $userstatic->LibStatut($tab_i['statuscontact'], 3);
1466 }
1467 if ($tab_i['source'] == 'external') {
1468 $contactstatic->id = $tab_i['id'];
1469 $contactstatic->lastname = $tab_i['lastname'];
1470 $contactstatic->firstname = $tab_i['firstname'];
1471 echo $contactstatic->LibStatut($tab_i['statuscontact'], 3);
1472 }
1473 if ($object->status >= 0) {
1474 echo '</a>';
1475 }
1476
1477 print '</div>';
1478
1479 print '</div><!-- tagtr -->';
1480
1481 $i++;
1482 }
1483 }
1484
1485 print '</div><!-- contact list -->';
1486 print '</div>';
1487 }
1488
1489 print '</div></div>';
1490 print '<div class="clearboth"></div>';
1491
1492 print dol_get_fiche_end();
1493
1494
1495 // Buttons for actions
1496 if ($action != 'presend' && $action != 'presend_addmessage' && $action != 'editline') {
1497 print '<div class="tabsAction">'."\n";
1498 $parameters = array();
1499 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1500 if ($reshook < 0) {
1501 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1502 }
1503
1504 if (empty($reshook)) {
1505 // Email
1506 if (isset($object->status) && $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage") {
1507 print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER["PHP_SELF"].'?action=presend_addmessage&send_email=1&private_message=0&mode=init&token='.newToken().'&track_id='.$object->track_id.'#formmailbeforetitle', '');
1508 }
1509
1510 // Show link to add a message (if read and not closed)
1511 if (isset($object->status) && $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage") {
1512 print dolGetButtonAction('', $langs->trans('TicketAddPrivateMessage'), 'default', $_SERVER["PHP_SELF"].'?action=presend_addmessage&mode=init&token='.newToken().'&track_id='.$object->track_id.'#formmailbeforetitle', '');
1513 }
1514
1515 // Link to create an intervention
1516 // socid is needed otherwise fichinter ask it and forgot origin after form submit :\
1517 if (!$object->fk_soc && $user->hasRight("ficheinter", "creer")) {
1518 print dolGetButtonAction($langs->trans('UnableToCreateInterIfNoSocid'), $langs->trans('TicketAddIntervention'), 'default', $_SERVER['PHP_SELF']. '#', '', false);
1519 }
1520 if ($object->fk_soc > 0 && isset($object->status) && $object->status < Ticket::STATUS_CLOSED && $user->hasRight('ficheinter', 'creer')) {
1521 print dolGetButtonAction('', $langs->trans('TicketAddIntervention'), 'default', DOL_URL_ROOT.'/fichinter/card.php?action=create&token='.newToken().'&socid='. $object->fk_soc.'&origin=ticket_ticket&originid='. $object->id, '');
1522 }
1523
1524 // Close ticket if status is read
1525 if (isset($object->status) && $object->status >= 0 && $object->status < Ticket::STATUS_CLOSED && $user->hasRight('ticket', 'write')) {
1526 print dolGetButtonAction('', $langs->trans('CloseTicket'), 'default', $_SERVER["PHP_SELF"].'?action=close&token='.newToken().'&track_id='.$object->track_id, '');
1527 }
1528
1529 // Abandon ticket if status is read
1530 if (isset($object->status) && $object->status > 0 && $object->status < Ticket::STATUS_CLOSED && $user->hasRight('ticket', 'write')) {
1531 print dolGetButtonAction('', $langs->trans('AbandonTicket'), 'default', $_SERVER["PHP_SELF"].'?action=abandon&token='.newToken().'&track_id='.$object->track_id, '');
1532 }
1533
1534 // Re-open ticket
1535 if (!$user->socid && (isset($object->status) && ($object->status == Ticket::STATUS_CLOSED || $object->status == Ticket::STATUS_CANCELED)) && !$user->socid) {
1536 print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&track_id='.$object->track_id, '');
1537 }
1538
1539 // Edit ticket
1540 if ($permissiontoedit) {
1541 print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoedit);
1542 }
1543
1544 // Clone
1545 if ($permissiontoadd) {
1546 print dolGetButtonAction('', $langs->trans('ToClone'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=clone&token='.newToken(), '', $permissiontoadd);
1547 }
1548
1549 // Delete ticket
1550 if ($user->hasRight('ticket', 'delete') && !$user->socid) {
1551 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&track_id='.$object->track_id, '');
1552 }
1553 }
1554 print '</div>'."\n";
1555 }
1556
1557 // Select mail models is same action as presend
1558 if (GETPOST('modelselected')) {
1559 $action = 'presend';
1560 }
1561 // Set $action to correct value for the case we used presend action to add a message
1562 if (GETPOSTISSET('actionbis') && $action == 'presend') {
1563 $action = 'presend_addmessage';
1564 }
1565
1566 // add a message
1567 if ($action == 'presend' || $action == 'presend_addmessage') {
1568 if ($object->fk_soc > 0) {
1569 $object->fetch_thirdparty();
1570 }
1571
1572 $outputlangs = $langs;
1573 $newlang = '';
1574 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
1575 $newlang = GETPOST('lang_id', 'aZ09');
1576 } elseif (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && is_object($object->thirdparty)) {
1577 $newlang = $object->thirdparty->default_lang;
1578 }
1579 if (!empty($newlang)) {
1580 $outputlangs = new Translate("", $conf);
1581 $outputlangs->setDefaultLang($newlang);
1582 }
1583
1584 $arrayoffamiliestoexclude = array('objectamount');
1585
1586 $action = 'add_message'; // action to use to post the message
1587 $modelmail = 'ticket_send';
1588
1589 // Substitution array
1590 $morehtmlright = '';
1591 $help = "";
1592 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, $arrayoffamiliestoexclude, $object);
1593 complete_substitutions_array($substitutionarray, $outputlangs, $object);
1594 $morehtmlright .= $form->textwithpicto('<span class="opacitymedium">'.$langs->trans("TicketMessageSubstitutionReplacedByGenericValues").'</span>', $help, 1, 'helpclickable', '', 0, 3, 'helpsubstitution');
1595
1596 print '<div>';
1597
1598 print '<div id="formmailbeforetitle" name="formmailbeforetitle"></div>';
1599
1600 print load_fiche_titre($langs->trans('TicketAddMessage'), $morehtmlright, 'messages@ticket');
1601
1602 print '<hr>';
1603
1604 $formticket = new FormTicket($db);
1605
1606 $formticket->action = $action;
1607 $formticket->track_id = $object->track_id;
1608 $formticket->ref = $object->ref;
1609 $formticket->id = $object->id;
1610 $formticket->trackid = 'tic'.$object->id;
1611
1612 $formticket->withfile = 2;
1613 $formticket->withcancel = 1;
1614 $formticket->param = array('fk_user_create' => $user->id);
1615 $formticket->param['langsmodels'] = (empty($newlang) ? $langs->defaultlang : $newlang);
1616
1617 // Table of additional post parameters
1618 $formticket->param['models'] = $modelmail;
1619 $formticket->param['models_id'] = GETPOSTINT('modelmailselected');
1620 //$formticket->param['socid']=$object->fk_soc;
1621 $formticket->param['returnurl'] = $_SERVER["PHP_SELF"].'?track_id='.urldecode($object->track_id);
1622
1623 $formticket->withsubstit = 1;
1624 $formticket->substit = $substitutionarray;
1625 $formticket->backtopage = $backtopage;
1626
1627 $formticket->showMessageForm('100%');
1628 print '</div>';
1629 }
1630
1631 // Show messages on card (Note: this is a duplicate of the view Events/Agenda but on the main tab)
1632 if (getDolGlobalString('TICKET_SHOW_MESSAGES_ON_CARD')) {
1633 $param = '&id='.$object->id;
1634 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1635 $param .= '&contextpage='.$contextpage;
1636 }
1637 if ($limit > 0 && $limit != $conf->liste_limit) {
1638 $param .= '&limit='.$limit;
1639 }
1640 if ($actioncode) {
1641 $param .= '&actioncode='.urlencode($actioncode);
1642 }
1643 if ($search_agenda_label) {
1644 $param .= '&search_agenda_label='.urlencode($search_agenda_label);
1645 }
1646
1647 $morehtmlright = '';
1648
1649 $messagingUrl = DOL_URL_ROOT.'/ticket/agenda.php?track_id='.$object->track_id;
1650 $morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fa fa-bars imgforviewmode', $messagingUrl, '', 1);
1651
1652 // Show link to add a message (if read and not closed)
1653 $btnstatus = $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage" && $action != "add_message";
1654 $url = 'card.php?track_id='.$object->track_id.'&action=presend_addmessage&mode=init';
1655 $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-comment-dots', $url, 'add-new-ticket-title-button', (int) $btnstatus);
1656
1657 // Show link to add event (if read and not closed)
1658 $btnstatus = $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage" && $action != "add_message";
1659 $url = dol_buildpath('/comm/action/card.php', 1).'?action=create&datep='.date('YmdHi').'&origin=ticket&originid='.$object->id.'&projectid='.$object->fk_project.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?track_id='.$object->track_id);
1660 $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-even-button', (int) $btnstatus);
1661
1662 print_barre_liste($langs->trans("ActionsOnTicket"), 0, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', 0, -1, '', 0, $morehtmlright, '', 0, 1, 1);
1663
1664 // List of all actions
1665 $filters = array();
1666 $filters['search_agenda_label'] = $search_agenda_label;
1667 $filters['search_rowid'] = $search_rowid;
1668
1669 show_actions_messaging($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder);
1670 }
1671
1672 if ($action != 'presend' && $action != 'presend_addmessage' && $action != 'add_message') {
1673 print '<div class="fichecenter"><div class="fichehalfleft">';
1674 print '<a name="builddoc"></a>'; // ancre
1675 /*
1676 * Generated documents
1677 */
1678 $filename = dol_sanitizeFileName($object->ref);
1679 $filedir = $upload_dir."/".dol_sanitizeFileName($object->ref);
1680 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
1681 $genallowed = $permissiontoadd;
1682 $delallowed = $permissiontodelete;
1683 $codelang = '';
1684 if ($object->fk_soc > 0) {
1685 $object->fetch_thirdparty();
1686 $codelang = $object->thirdparty->default_lang;
1687 }
1688
1689 print $formfile->showdocuments('ticket', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $codelang);
1690
1691 // Show links to link elements
1692 $tmparray = $form->showLinkToObjectBlock($object, array(), array('ticket'), 1);
1693 $linktoelem = $tmparray['linktoelem'];
1694 $htmltoenteralink = $tmparray['htmltoenteralink'];
1695 print $htmltoenteralink;
1696
1697 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
1698
1699 // Show direct link to public interface
1700 print '<br><!-- Link to public interface -->'."\n";
1701 print showDirectPublicLink($object).'<br>';
1702 print '</div>';
1703
1704 if (!getDolGlobalString('MAIN_HIDE_MESSAGES_ON_CARD')) {
1705 print '<div class="fichehalfright">';
1706
1707 $MAXEVENT = 10;
1708
1709 $morehtmlcenter = '<div class="nowraponall">';
1710 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT.'/ticket/messaging.php?id='.$object->id);
1711 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/ticket/agenda.php?id='.$object->id);
1712 $morehtmlcenter .= '</div>';
1713
1714 // List of actions on element
1715 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
1716 $formactions = new FormActions($db);
1717 $somethingshown = $formactions->showactions($object, 'ticket', $socid, 1, 'listactions', $MAXEVENT, '', $morehtmlcenter);
1718
1719 print '</div>';
1720 }
1721
1722 print '</div>';
1723 }
1724 }
1725}
1726
1727// End of page
1728llxFooter();
1729$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class Actions of the module ticket.
Class to manage contact/addresses.
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to manage generation of HTML components for contract module.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class to manage building of HTML components.
static checkRequiredFields(array $fields, int &$errors)
Check required fields.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
societe_prepare_head(Societe $object)
Return array of tabs to used on pages for third parties cards.
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:247
dol_now($mode='gmt')
Return date for now.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon=null, $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dol_print_ip($ip, $mode=0, $showname=0)
Return an IP formatted to be shown on screen.
dol_print_phone($phone, $countrycode='', $contactid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0, $attop=0)
Set event message in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolPrintLabel($s, $escapeonlyhtmltags=0)
Return a string label (so on 1 line only and that should not contains any HTML) ready to be output on...
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
Class to generate the form for creating a new ticket.
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
if(getDolGlobalString( 'TAKEPOS_SHOW_CUSTOMER')) print $langs trans('Date')." left Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
Definition receipt.php:464
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
showDirectPublicLink($object)
Return string with full Url.
ticket_prepare_head($object)
Build tabs for a Ticket object.