dolibarr 22.0.5
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');
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))) { // 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 $object->close($user);
482
483 setEventMessages('<div class="confirm">' . $langs->trans('TicketMarkedAsClosed') . '</div>', null, 'mesgs');
484
485 $url = 'card.php?track_id=' . GETPOST('track_id', 'alpha');
486 header("Location: " . $url);
487 exit;
488 } else {
489 setEventMessages($object->error, $object->errors, 'errors');
490 $action = '';
491 }
492 }
493
494 if ($action == 'confirm_delete_ticket' && GETPOST('confirm', 'alpha') == "yes" && $permissiontodelete) {
495 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
496 if ($object->delete($user) > 0) {
497 setEventMessages('<div class="confirm">' . $langs->trans('TicketDeletedSuccess') . '</div>', null, 'mesgs');
498 header("Location: " . DOL_URL_ROOT . "/ticket/list.php");
499 exit;
500 } else {
501 $langs->load("errors");
502 $mesg = '<div class="error">' . $langs->trans($object->error) . '</div>';
503 $action = '';
504 }
505 }
506 }
507
508 // Set parent company
509 if ($action == 'set_thirdparty' && $user->hasRight('ticket', 'write')) {
510 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
511 $result = $object->setCustomer(GETPOSTINT('editcustomer'));
512 $url = $_SERVER["PHP_SELF"] . '?track_id=' . GETPOST('track_id', 'alpha');
513 header("Location: " . $url);
514 exit();
515 }
516 }
517
518 // Set progress status
519 if ($action == 'set_progression' && $user->hasRight('ticket', 'write')) {
520 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
521 $result = $object->setProgression(GETPOSTINT('progress'));
522
523 $url = 'card.php?track_id=' . $object->track_id;
524 header("Location: " . $url);
525 exit();
526 }
527 }
528
529 // Set categories
530 if ($action == 'set_categories' && $user->hasRight('ticket', 'write')) {
531 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
532 $result = $object->setCategories(GETPOST('categories', 'array'));
533
534 $url = 'card.php?track_id=' . $object->track_id;
535 header("Location: " . $url);
536 exit();
537 }
538 }
539
540 // Set Subject
541 if ($action == 'setsubject' && $user->hasRight('ticket', 'write')) {
542 if ($object->fetch(GETPOSTINT('id'))) {
543 if ($action == 'setsubject') { // Test on permission already done
544 $object->subject = GETPOST('subject', 'alphanohtml');
545 }
546
547 if ($action == 'setsubject' && empty($object->subject)) { // Test on permission already done
548 $error++;
549 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")), null, 'errors');
550 }
551
552 if (!$error) {
553 if (!$object->update($user) >= 0) {
554 $error++;
555 setEventMessages($object->error, $object->errors, 'errors');
556 }
557 }
558
559 header("Location: " . $_SERVER['PHP_SELF'] . "?track_id=" . $object->track_id);
560 exit;
561 }
562 }
563
564 if ($action == 'confirm_reopen' && $user->hasRight('ticket', 'manage') && !GETPOST('cancel')) {
565 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
566 // prevent browser refresh from reopening ticket several times
567 if ($object->status == Ticket::STATUS_CLOSED || $object->status == Ticket::STATUS_CANCELED) {
568 if ($object->fk_user_assign != null) {
569 $res = $object->setStatut(Ticket::STATUS_ASSIGNED, null, '', $triggermodname);
570 } else {
571 $res = $object->setStatut(Ticket::STATUS_NOT_READ, null, '', $triggermodname);
572 }
573 if ($res) {
574 $url = 'card.php?track_id=' . $object->track_id;
575 header("Location: " . $url);
576 exit();
577 } else {
578 $error++;
579 setEventMessages($object->error, $object->errors, 'errors');
580 }
581 }
582 }
583 } elseif ($action == 'classin' && $permissiontoadd) {
584 // Categorisation dans projet
585 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
586 $object->setProject($projectid);
587 $url = 'card.php?track_id=' . $object->track_id;
588 header("Location: " . $url);
589 exit();
590 }
591 } elseif ($action == 'setcontract' && $permissiontoadd) {
592 // Categorisation dans contrat
593 if ($object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha')) >= 0) {
594 $object->setContract(GETPOSTINT('contractid'));
595 $url = 'card.php?track_id=' . $object->track_id;
596 header("Location: " . $url);
597 exit();
598 }
599 } elseif ($action == "set_message" && $user->hasRight('ticket', 'manage')) {
600 if (!GETPOST('cancel')) {
601 $object->fetch(0, '', GETPOST('track_id', 'alpha'));
602 //$oldvalue_message = $object->message;
603 $fieldtomodify = GETPOST('message_initial', 'restricthtml');
604
605 $object->message = $fieldtomodify;
606 $ret = $object->update($user);
607 if ($ret > 0) {
608 //include_once DOL_DOCUMENT_ROOT.'/core/class/utils_diff.class.php';
609 // output the result of comparing two files as plain text
610 //$log_action .= Diff::toString(Diff::compare(strip_tags($oldvalue_message), strip_tags($object->message)));
611
612 setEventMessages($langs->trans('TicketMessageSuccesfullyUpdated'), null, 'mesgs');
613 } else {
614 $error++;
615 setEventMessages($object->error, $object->errors, 'errors');
616 }
617 }
618
619 $action = 'view';
620 } elseif ($action == 'confirm_set_status' && $permissiontoadd && !GETPOST('cancel')) {
621 // Reopen ticket
622 if ($object->fetch(GETPOSTINT('id'), GETPOST('track_id', 'alpha')) >= 0) {
623 $new_status = GETPOSTINT('new_status');
624
625 $res = $object->setStatut($new_status, null, '', 'TICKET_MODIFY');
626
627 if ($res) {
628 $url = 'card.php?track_id=' . $object->track_id;
629 header("Location: " . $url);
630 exit();
631 } else {
632 $error++;
633 setEventMessages($object->error, $object->errors, 'errors');
634 }
635 }
636 }
637
638 // Action to update an extrafield
639 if ($action == "update_extras" && $permissiontoeditextra) {
640 $object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha'));
641
642 $attribute_name = GETPOST('attribute', 'aZ09');
643
644 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
645 if ($ret < 0) {
646 $error++;
647 }
648
649 if (!$error) {
650 $result = $object->updateExtraField($attribute_name, $triggermodname);
651 if ($result < 0) {
652 setEventMessages($object->error, $object->errors, 'errors');
653 $error++;
654 }
655 }
656
657 if ($error) {
658 $action = 'edit_extras';
659 }
660 }
661
662 if ($action == "change_property" && GETPOST('btn_update_ticket_prop', 'alpha') && $permissiontoadd) {
663 $object->fetch(GETPOSTINT('id'), '', GETPOST('track_id', 'alpha'));
664
665 $object->type_code = GETPOST('update_value_type', 'aZ09');
666 $object->severity_code = GETPOST('update_value_severity', 'aZ09');
667 $object->category_code = GETPOST('update_value_category', 'aZ09');
668
669 $ret = $object->update($user);
670 if ($ret > 0) {
671 setEventMessages($langs->trans('TicketUpdated'), null, 'mesgs');
672 } else {
673 $error++;
674 setEventMessages($object->error, $object->errors, 'errors');
675 }
676 $action = 'view';
677 }
678
679
680 $permissiondellink = $user->hasRight('ticket', 'write');
681 include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
682
683 // Actions when printing a doc from card
684 include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php';
685
686 // Actions to build doc
687 include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php';
688
689 // Actions to send emails
690 $triggersendname = 'TICKET_SENTBYMAIL';
691 $paramname = 'id';
692 $autocopy = 'MAIN_MAIL_AUTOCOPY_TICKET_TO'; // used to know the automatic BCC to add
693 $trackid = 'tic' . $object->id;
694 include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php';
695
696 // Set $action to correct value for the case we used presend action to add a message
697 if (GETPOSTISSET('actionbis') && $action == 'presend') { // Test on permission not required here
698 $action = 'presend_addmessage';
699 }
700}
701
702
703/*
704 * View
705 */
706
707$userstat = new User($db);
708$form = new Form($db);
709$formfile = new FormFile($db);
710$formticket = new FormTicket($db);
711if (isModEnabled('project')) {
712 $formproject = new FormProjets($db);
713}
714
715$help_url = 'EN:Module_Ticket|FR:DocumentationModuleTicket';
716
717$title = $actionobject->getTitle($action, $object);
718
719llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-ticket page-card');
720
721if ($action == 'create' || $action == 'presend') {
722 if (empty($permissiontoadd)) {
723 accessforbidden('NotEnoughPermissions', 0, 1);
724 }
725
726 $formticket = new FormTicket($db);
727
728 print load_fiche_titre($langs->trans('NewTicket'), '', 'ticket');
729
730 $formticket->trackid = ''; // TODO Use a unique key 'tic' to avoid conflict in upload file feature
731
732 if (GETPOST("mode", "aZ09") == 'init' && empty($_POST)) {
733 $formticket->clear_attached_files();
734 }
735
736 $formticket->withfromsocid = $socid ? $socid : $user->socid;
737 $formticket->withfromcontactid = $contactid ? $contactid : '';
738 $formticket->withtitletopic = 1;
739 $formticket->withnotifytiersatcreate = ($notifyTiers ? 1 : (getDolGlobalString('TICKET_CHECK_NOTIFY_THIRDPARTY_AT_CREATION') ? 1 : 0));
740 $formticket->withusercreate = 0;
741 $formticket->withref = 1;
742 $formticket->fk_user_create = $user->id;
743 $formticket->withfile = 2;
744 $formticket->withextrafields = 1;
745 $formticket->param = array('origin' => GETPOST('origin'), 'originid' => GETPOST('originid'));
746
747 $formticket->withcancel = 1;
748
749 // Init list of files
750 if (GETPOST("mode", "aZ09") == 'init') {
751 $formticket->clear_attached_files();
752 }
753
754 $formticket->showForm(1, 'create', 0, null, $action, $object);
755
756 print dol_get_fiche_end();
757} elseif ($action == 'edit' && $user->rights->ticket->write && $object->status < Ticket::STATUS_CLOSED) {
758 if (empty($permissiontoadd)) {
759 accessforbidden('NotEnoughPermissions', 0, 1);
760 }
761
762 $formticket = new FormTicket($db);
763
765
766 print dol_get_fiche_head($head, 'tabTicket', $langs->trans('Ticket'), -1, 'ticket');
767
768 $formticket->trackid = $object->track_id; // TODO Use a unique key 'tic' to avoid conflict in upload file feature
769 $formticket->withfromsocid = $object->socid;
770 $formticket->withtitletopic = 1;
771 // $formticket->withnotifytiersatcreate = ($notifyTiers ? 1 : (getDolGlobalString('TICKET_CHECK_NOTIFY_THIRDPARTY_AT_CREATION') ? 1 : 0));
772 $formticket->withnotifytiersatcreate = 0;
773 $formticket->withusercreate = 0;
774 $formticket->withref = 1;
775 $formticket->fk_user_create = $user->id;
776 $formticket->withfile = 0;
777 $formticket->action = 'update';
778 $formticket->withextrafields = 1;
779 $formticket->param = array('origin' => GETPOST('origin'), 'originid' => GETPOST('originid'));
780
781 $formticket->withcancel = 1;
782
783 $formticket->showForm(0, 'edit', 0, null, $action, $object);
784
785 print dol_get_fiche_end();
786} elseif ($object->id) {
787 if (!empty($res) && $res > 0) {
788 // or for unauthorized internals users
789 if (!$user->socid && (getDolGlobalString('TICKET_LIMIT_VIEW_ASSIGNED_ONLY') && $object->fk_user_assign != $user->id) && !$user->hasRight('ticket', 'manage')) {
790 accessforbidden('', 0, 1);
791 }
792
793 $formconfirm = '';
794
795 // Confirmation close
796 if ($action == 'close') {
797 $thirdparty_contacts = $object->getInfosTicketExternalContact(1);
798 $contacts_select = array(
799 '-2' => $langs->trans('TicketNotifyAllTiersAtClose'),
800 '-3' => $langs->trans('TicketNotNotifyTiersAtClose')
801 );
802 foreach ($thirdparty_contacts as $thirdparty_contact) {
803 $contacts_select[$thirdparty_contact['id']] = $thirdparty_contact['civility'] . ' ' . $thirdparty_contact['lastname'] . ' ' . $thirdparty_contact['firstname'];
804 }
805
806 // Default select all or no contact
807 $default = (getDolGlobalString('TICKET_NOTIFY_AT_CLOSING') ? '-2' : '-3');
808 $formquestion = array(
809 array(
810 'name' => 'contactid',
811 'type' => 'select',
812 'label' => $langs->trans('NotifyThirdpartyOnTicketClosing'),
813 'values' => $contacts_select,
814 'default' => $default
815 ),
816 );
817
818 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_close", $formquestion, '', 1);
819 }
820 // Confirmation abandon
821 if ($action == 'abandon') {
822 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("AbandonTicket"), $langs->trans("ConfirmAbandonTicket"), "confirm_abandon", '', '', 1);
823 }
824 // Confirmation delete
825 if ($action == 'delete') {
826 $formconfirm = $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("Delete"), $langs->trans("ConfirmDeleteTicket"), "confirm_delete_ticket", '', '', 1);
827 }
828 // Confirm reopen
829 if ($action == 'reopen') {
830 $formconfirm = $form->formconfirm($url_page_current.'?track_id='.$object->track_id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenTicket'), 'confirm_reopen', '', '', 1);
831 }
832 // Confirmation status change
833 if ($action == 'set_status') {
834 $new_status = GETPOSTINT('new_status');
835 //var_dump($url_page_current . "?track_id=" . $object->track_id);
836 $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);
837 }
838
839 // Call Hook formConfirm
840 $parameters = array('formConfirm' => $formconfirm);
841 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
842 if (empty($reshook)) {
843 $formconfirm .= $hookmanager->resPrint;
844 } elseif ($reshook > 0) {
845 $formconfirm = $hookmanager->resPrint;
846 }
847
848 // Print form confirm
849 print $formconfirm;
850
851 // project info
852 if ($projectid > 0) {
853 $projectstat = new Project($db);
854 if ($projectstat->fetch($projectid) > 0) {
855 $projectstat->fetch_thirdparty();
856
857 // To verify role of users
858 //$userAccess = $object->restrictedProjectArea($user,'read');
859 $userWrite = $projectstat->restrictedProjectArea($user, 'write');
860 //$userDelete = $object->restrictedProjectArea($user,'delete');
861 //print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
862
863 $head = project_prepare_head($projectstat);
864
865 print dol_get_fiche_head($head, 'ticket', $langs->trans("Project"), 0, ($projectstat->public ? 'projectpub' : 'project'));
866
867 print '<table class="border centpercent">';
868
869 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
870
871 // Ref
872 print '<tr><td>'.$langs->trans('Ref').'</td><td colspan="3">';
873 // Define a complementary filter for search of next/prev ref.
874 if (!$user->hasRight('projet', 'all', 'lire')) {
875 $objectsListId = $projectstat->getProjectsAuthorizedForUser($user, $mine, 0);
876 $projectstat->next_prev_filter = "rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
877 }
878 print $form->showrefnav($projectstat, 'ref', $linkback, 1, 'ref', 'ref', '');
879 print '</td></tr>';
880
881 // Label
882 print '<tr><td>'.$langs->trans("Label").'</td><td>'.$projectstat->title.'</td></tr>';
883
884 // Customer
885 print "<tr><td>".$langs->trans("ThirdParty")."</td>";
886 print '<td colspan="3">';
887 if ($projectstat->thirdparty->id > 0) {
888 print $projectstat->thirdparty->getNomUrl(1);
889 } else {
890 print '&nbsp;';
891 }
892
893 print '</td></tr>';
894
895 // Visibility
896 print '<tr><td>'.$langs->trans("Visibility").'</td><td>';
897 if ($projectstat->public) {
898 print $langs->trans('SharedProject');
899 } else {
900 print $langs->trans('PrivateProject');
901 }
902
903 print '</td></tr>';
904
905 // Status
906 print '<tr><td>'.$langs->trans("Status").'</td><td>'.$projectstat->getLibStatut(4).'</td></tr>';
907
908 print "</table>";
909
910 print dol_get_fiche_end();
911 } else {
912 print "ErrorRecordNotFound";
913 }
914 } elseif ($socid > 0) {
915 $object->fetch_thirdparty();
916 $head = societe_prepare_head($object->thirdparty);
917
918 print dol_get_fiche_head($head, 'ticket', $langs->trans("ThirdParty"), 0, 'company');
919
920 dol_banner_tab($object->thirdparty, 'socid', '', ($user->socid ? 0 : 1), 'rowid', 'nom');
921
922 print dol_get_fiche_end();
923 }
924
925 if (!$user->socid && getDolGlobalString('TICKET_LIMIT_VIEW_ASSIGNED_ONLY')) {
926 $object->next_prev_filter = "te.fk_user_assign:=:".((int) $user->id);
927 } elseif ($user->socid > 0) {
928 $object->next_prev_filter = "te.fk_soc:=:".((int) $user->socid);
929 }
930
932
933 print dol_get_fiche_head($head, 'tabTicket', $langs->trans("Ticket"), -1, 'ticket', 0, '', '', 0, '', 1);
934
935 $morehtmlref = '<div class="refidno">';
936
937 if ($user->hasRight('ticket', 'write') && !$user->socid) {
938 $morehtmlref .= '<a class="editfielda" href="'.$url_page_current.'?action=editsubject&token='.newToken().'&track_id='.$object->track_id.'">'.img_edit($langs->transnoentitiesnoconv('SetTitle'), 0).'</a> ';
939 }
940 if ($action != 'editsubject') {
941 $morehtmlref .= dolPrintLabel($object->subject);
942 } else {
943 $morehtmlref .= '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
944 $morehtmlref .= '<input type="hidden" name="action" value="setsubject">';
945 $morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
946 $morehtmlref .= '<input type="hidden" name="id" value="'.$object->id.'">';
947 $morehtmlref .= '<input type="text" class="minwidth300" id="subject" name="subject" value="'.$object->subject.'" autofocus="">';
948 $morehtmlref .= '<input type="submit" class="smallpaddingimp button valignmiddle" name="modify" value="'.$langs->trans("Modify").'">';
949 $morehtmlref .= '<input type="submit" class="smallpaddingimp button button-cancel vlignmiddle" name="cancel" value="'.$langs->trans("Cancel").'">';
950 $morehtmlref .= '</form>';
951 }
952
953 // Author
954 $createdbyshown = 0;
955 if ($object->fk_user_create > 0) {
956 $morehtmlref .= '<br>';
957 //$morehtmlref .= '<span class="opacitymedium">'.$langs->trans("CreatedBy").'</span> ';
958
959 $fuser = new User($db);
960 $fuser->fetch($object->fk_user_create);
961 $morehtmlref .= $fuser->getNomUrl(-1);
962 $createdbyshown++;
963 }
964
965 $createdfrompublicticket = 0;
966 $createdfromemailcollector = 0;
967 if (!empty($object->origin_email) && (empty($object->email_msgid) || preg_match('/dolibarr\-tic\d+/', $object->email_msgid))) {
968 // If ticket create from public interface - TODO Add a more robust test to know if created by public interface
969 $createdfrompublicticket = 1;
970 } elseif (!empty($object->email_msgid)) {
971 // If ticket create by emailcollector - TODO Add a more robust test to know if created by email collector (using import key ?)
972 $createdfromemailcollector = 1;
973 }
974
975 //var_dump($object);
976 $htmltooltip = '';
977 if ($createdfrompublicticket) {
978 $htmltooltip .= $langs->trans("OriginEmail").': '.$object->origin_email;
979 $htmltooltip .= '<br>'.$langs->trans("IP").': '.dol_print_ip($object->ip);
980 $morehtmlref .= ($createdbyshown ? ' - ' : '<br>');
981 //$morehtmlref .= ($createdbyshown ? '' : '<span class="opacitymedium">'.$langs->trans("CreatedBy").' </span> ');
982 $morehtmlref .= img_picto('', 'email', 'class="paddingrightonly"');
983 $morehtmlref .= dol_escape_htmltag($object->origin_email).' <small class="hideonsmartphone opacitymedium">- '.$form->textwithpicto($langs->trans("CreatedByPublicPortal"), $htmltooltip, 1, 'help', '', 0, 3, 'tooltipcreatedbyportal').'</small>';
984 } elseif ($createdfromemailcollector) {
985 $langs->load("mails");
986
987 $htmltooltip .= '<b>'.$langs->trans("EmailMsgID").':</b> '.$object->email_msgid;
988 $htmltooltip .= '<br><b>'.$langs->trans("EmailDate").':</b> '.dol_print_date($object->email_date, 'dayhour');
989 $htmltooltip .= '<br><b>'.$langs->trans("MailFrom").':</b> '.$object->origin_email;
990 $htmltooltip .= '<br><b>'.$langs->trans("MailReply").':</b> '.$object->origin_replyto;
991 $htmltooltip .= '<br><b>'.$langs->trans("MailReferences").':</b> '.$object->origin_references;
992 $morehtmlref .= ($createdbyshown ? ' - ' : '<br>');
993 //$morehtmlref .= ($createdbyshown ? '' : '<span class="opacitymedium">'.$langs->trans("CreatedBy").'</span> ');
994 $morehtmlref .= img_picto('From', 'email', 'class="paddingrightonly"');
995 $morehtmlref .= dol_escape_htmltag($object->origin_email);
996 if ($object->origin_replyto) {
997 $morehtmlref .= ' - '.img_picto('ReplyTo', 'email', 'class="paddingrightonly"');
998 $morehtmlref .= dol_escape_htmltag($object->origin_replyto);
999 }
1000 $morehtmlref .= ' <small class="hideonsmartphone opacitymedium">- '.$form->textwithpicto($langs->trans("CreatedByEmailCollector"), $htmltooltip, 1, 'help', '', 0, 3, 'tooltipcreatedbyemailcollector').'</small>';
1001 }
1002
1003 $permissiontoedit = $object->status < 8 && !$user->socid && $user->hasRight('ticket', 'write');
1004 //$permissiontoedit = 0;
1005
1006 // Thirdparty
1007 if (isModEnabled("societe")) {
1008 $morehtmlref .= '<br>';
1009 if ($action != 'editcustomer' && $permissiontoedit) {
1010 $morehtmlref .= img_picto($langs->trans("ThirdParty"), 'company', 'class="pictofixedwidth"');
1011 $morehtmlref .= '<a class="editfielda" href="'.$url_page_current.'?action=editcustomer&token='.newToken().'&track_id='.$object->track_id.'">'.img_edit($langs->transnoentitiesnoconv('SetThirdParty'), 0).'</a> ';
1012 }
1013 $morehtmlref .= $form->form_thirdparty($url_page_current.'?track_id='.$object->track_id, (string) $object->socid, $action == 'editcustomer' ? 'editcustomer' : 'none', '', 1, 0, 0, array(), 1);
1014 if (!empty($object->socid)) {
1015 $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>';
1016 }
1017 }
1018
1019 // Project
1020 if (isModEnabled('project')) {
1021 $langs->load("projects");
1022 $morehtmlref .= '<br>';
1023 if ($permissiontoedit) {
1024 $object->fetchProject();
1025 $morehtmlref .= img_picto($langs->trans("Project"), 'project'.((is_object($object->project) && $object->project->public) ? 'pub' : ''), 'class="pictofixedwidth"');
1026 if ($action != 'classify') {
1027 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
1028 }
1029 $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');
1030 } else {
1031 if (!empty($object->fk_project)) {
1032 $object->fetchProject();
1033 $morehtmlref .= $object->project->getNomUrl(1);
1034 if ($object->project->title) {
1035 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($object->project->title).'</span>';
1036 }
1037 }
1038 }
1039 }
1040
1041 // Contract
1042 if (getDolGlobalString('TICKET_LINK_TO_CONTRACT_WITH_HARDLINK')) {
1043 // Deprecated. Duplicate feature. Ticket can already be linked to contract with the generic "Link to" feature.
1044 if (isModEnabled('contract')) {
1045 $langs->load('contracts');
1046 $morehtmlref .= '<br>';
1047 if ($permissiontoedit) {
1048 $morehtmlref .= img_picto($langs->trans("Contract"), 'contract', 'class="pictofixedwidth"');
1049 if ($action == 'edit_contrat') {
1050 $formcontract = new FormContract($db);
1051 $morehtmlref .= $formcontract->formSelectContract($_SERVER["PHP_SELF"].'?id='.$object->id, $object->socid, $object->fk_contract, 'contratid', 0, 1, 1, 1);
1052 } else {
1053 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit_contrat&token='.newToken().'&id='.$object->id.'">';
1054 $morehtmlref .= img_edit($langs->trans('SetContract'));
1055 $morehtmlref .= '</a>';
1056 }
1057 } else {
1058 if (!empty($object->fk_contract)) {
1059 $contratstatic = new Contrat($db);
1060 $contratstatic->fetch($object->fk_contract);
1061 //print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
1062 $morehtmlref .= $contratstatic->getNomUrl(0, 0, 1);
1063 }
1064 }
1065 }
1066 }
1067
1068 $morehtmlref .= '</div>';
1069
1070 $linkback = '<a href="'.DOL_URL_ROOT.'/ticket/list.php?restore_lastsearch_values=1"><strong>'.$langs->trans("BackToList").'</strong></a> ';
1071
1072 dol_banner_tab($object, 'ref', $linkback, ($user->socid ? 0 : 1), 'ref', 'ref', $morehtmlref);
1073
1074 print '<div class="fichecenter">';
1075 print '<div class="fichehalfleft">';
1076 print '<div class="underbanner clearboth"></div>';
1077
1078 print '<table class="border tableforfield centpercent">';
1079
1080 // Track ID
1081 print '<tr><td class="titlefieldmiddle">'.$langs->trans("TicketTrackId").'</td><td>';
1082 if (!empty($object->track_id)) {
1083 if (empty($object->ref)) {
1084 $object->ref = (string) $object->id;
1085 print $form->showrefnav($object, 'id', $linkback, 1, 'rowid', 'track_id');
1086 } else {
1087 print dolPrintLabel($object->track_id);
1088 }
1089 } else {
1090 print $langs->trans('None');
1091 }
1092 print '</td></tr>';
1093
1094 // Subject
1095 /*
1096 print '<tr><td>';
1097 print $form->editfieldkey("Subject", 'subject', $object->subject, $object, $user->hasRight('ticket', 'write') && !$user->socid, 'string');
1098 print '</td><td>';
1099 print $form->editfieldval("Subject", 'subject', $object->subject, $object, $user->hasRight('ticket', 'write') && !$user->socid, 'string');
1100 print '</td></tr>';
1101 */
1102
1103 // Creation date
1104 print '<tr><td>'.$langs->trans("DateCreation").'</td><td>';
1105 print dol_print_date($object->datec, 'dayhour', 'tzuser');
1106 print '<span class="opacitymedium"><span class="small"> - '.$langs->trans("TimeElapsedSince").': <b><i>'.convertSecondToTime(roundUpToNextMultiple($now - $object->datec, 60)).'</i></b></span></span>';
1107 print '</td></tr>';
1108
1109 // Origin
1110 /*
1111 if ($object->email_msgid) {
1112 $texttoshow = $langs->trans("CreatedByEmailCollector");
1113 } elseif ($object->origin_email) {
1114 $texttoshow = $langs->trans("FromPublicEmail");
1115 }
1116 if ($texttoshow) {
1117 print '<tr><td class="titlefield fieldname_email_origin">';
1118 print $langs->trans("Origin");
1119 print '</td>';
1120 print '<td class="valuefield fieldname_email_origin">';
1121 print $texttoshow;
1122 print '</td></tr>';
1123 }
1124 */
1125
1126 // Read date
1127 print '<tr><td>'.$langs->trans("TicketReadOn").'</td><td>';
1128 if (!empty($object->date_read)) {
1129 print dol_print_date($object->date_read, 'dayhour', 'tzuser');
1130 print '<span class="opacitymedium"><span class="small"> - '.$langs->trans("TimeElapsedSince").': ';
1131 //print '<b><i>'.convertSecondToTime(roundUpToNextMultiple($object->date_read - $object->datec, 60)).'</i></b>';
1132 //print ' / ';
1133 print '<b><i>'.convertSecondToTime(roundUpToNextMultiple($now - $object->date_read, 60)).'</i></b></span></span>';
1134 }
1135 print '</td></tr>';
1136
1137 // Close date
1138 print '<tr><td>'.$langs->trans("TicketCloseOn").'</td><td>';
1139 if (!empty($object->date_close)) {
1140 print dol_print_date($object->date_close, 'dayhour', 'tzuser');
1141 }
1142 print '</td></tr>';
1143
1144 // User assigned
1145 print '<tr><td>';
1146 print '<table class="nobordernopadding" width="100%"><tr><td class="nowrap">';
1147 print $langs->trans("AssignedTo");
1148 if (isset($object->status) && $object->status < $object::STATUS_CLOSED && GETPOST('set', 'alpha') != "assign_ticket" && $user->hasRight('ticket', 'manage')) {
1149 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>';
1150 }
1151 print '</td></tr></table>';
1152 print '</td><td>';
1153 if (GETPOST('set', 'alpha') != "assign_ticket" && $object->fk_user_assign > 0) {
1154 $userstat->fetch($object->fk_user_assign);
1155 print $userstat->getNomUrl(-1);
1156 }
1157
1158 // Show user list to assignate one if status is "read"
1159 if (GETPOST('set', 'alpha') == "assign_ticket" && $object->status < 8 && !$user->socid && $user->hasRight('ticket', 'write')) {
1160 print '<form method="post" name="ticket" enctype="multipart/form-data" action="'.$url_page_current.'">';
1161 print '<input type="hidden" name="token" value="'.newToken().'">';
1162 print '<input type="hidden" name="action" value="assign_user">';
1163 print '<input type="hidden" name="track_id" value="'.$object->track_id.'">';
1164 //print '<label for="fk_user_assign">'.$langs->trans("AssignUser").'</label> ';
1165 print $form->select_dolusers(empty($object->fk_user_assign) ? $user->id : $object->fk_user_assign, 'fk_user_assign', 1);
1166 print ' <input type="submit" class="button smallpaddingimp" name="btn_assign_user" value="'.$langs->trans("Validate").'" />';
1167 print '</form>';
1168 }
1169 print '</td></tr>';
1170
1171 // Progression
1172 print '<tr><td>';
1173 print '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
1174 print $langs->trans('Progression').'</td><td class="left">';
1175 print '</td>';
1176 if ($action != 'progression' && isset($object->status) && $object->status < $object::STATUS_CLOSED && !$user->socid) {
1177 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>';
1178 }
1179 print '</tr></table>';
1180 print '</td><td>';
1181 if ($user->hasRight('ticket', 'write') && $action == 'progression') {
1182 print '<form action="'.$url_page_current.'" method="post">';
1183 print '<input type="hidden" name="token" value="'.newToken().'">';
1184 print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1185 print '<input type="hidden" name="action" value="set_progression">';
1186 print '<input type="text" class="flat width75" name="progress" value="'.$object->progress.'">';
1187 print ' <input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
1188 print '</form>';
1189 } else {
1190 print($object->progress > 0 ? $object->progress : '0').'%';
1191 }
1192 print '</td>';
1193 print '</tr>';
1194
1195 // Timing (Duration sum of linked fichinter)
1196 if (isModEnabled('intervention')) {
1197 $object->fetchObjectLinked();
1198 $num = count($object->linkedObjects);
1199 $timing = 0;
1200 $foundinter = 0;
1201 if ($num) {
1202 foreach ($object->linkedObjects as $objecttype => $objects) {
1203 if ($objecttype == "fichinter") {
1204 '@phan-var-force Fichinter[] $objects';
1205 foreach ($objects as $fichinter) {
1206 $foundinter++;
1208 $timing += $fichinter->duration;
1209 }
1210 }
1211 }
1212 }
1213 print '<tr><td>';
1214 print $form->textwithpicto($langs->trans("TicketDurationAuto"), $langs->trans("TicketDurationAutoInfos"), 1);
1215 print '</td><td>';
1216 print $foundinter ? convertSecondToTime($timing, 'all', getDolGlobalInt('MAIN_DURATION_OF_WORKDAY')) : '';
1217 print '</td></tr>';
1218 }
1219
1220 // Other attributes
1221 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
1222
1223 print '</table>';
1224
1225
1226 // End of left column and beginning of right column
1227 print '</div><div class="fichehalfright">';
1228
1229
1230 print '<form method="post" name="formticketproperties" action="'.$url_page_current.'">';
1231 print '<input type="hidden" name="token" value="'.newToken().'">';
1232 print '<input type="hidden" name="action" value="change_property">';
1233 print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1234 print '<input type="hidden" name="trackid" value="'.$trackid.'">';
1235
1236 // Classification of ticket
1237 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
1238 print '<table class="border tableforfield centpercent margintable bordertopimp">';
1239 print '<tr class="liste_titre">';
1240 print '<td>';
1241 print $langs->trans('TicketProperties');
1242 print '</td>';
1243 print '<td>';
1244 if (GETPOST('set', 'alpha') == 'properties' && $user->hasRight('ticket', 'write')) {
1245 print '<input type="submit" class="button smallpaddingimp" name="btn_update_ticket_prop" value="'.$langs->trans("Modify").'" />';
1246 } else {
1247 // Button to edit Properties
1248 if (isset($object->status) && ($object->status < $object::STATUS_NEED_MORE_INFO || !getDolGlobalInt('TICKET_DISALLOW_CLASSIFICATION_MODIFICATION_EVEN_IF_CLOSED')) && $user->hasRight('ticket', 'write')) {
1249 print ' <a class="editfielda" href="card.php?track_id='.$object->track_id.'&set=properties">'.img_edit($langs->trans('Modify')).'</a>';
1250 }
1251 }
1252 print '</td>';
1253 print '</tr>';
1254
1255 if (GETPOST('set', 'alpha') == 'properties' && $user->hasRight('ticket', 'write')) {
1256 print '<tr>';
1257 // Type
1258 print '<td class="titlefield">';
1259 print $langs->trans('Type');
1260 print '</td><td>';
1261 $formticket->selectTypesTickets($object->type_code, 'update_value_type', '', 2);
1262 print '</td>';
1263 print '</tr>';
1264 // Group
1265 print '<tr>';
1266 print '<td>';
1267 print $langs->trans('TicketCategory');
1268 print '</td><td>';
1269 $formticket->selectGroupTickets($object->category_code, 'update_value_category', '', 2, 0, 0, 0, 'maxwidth500 widthcentpercentminusxx');
1270 print '</td>';
1271 print '</tr>';
1272 // Severity
1273 print '<tr>';
1274 print '<td>';
1275 print $langs->trans('TicketSeverity');
1276 print '</td><td>';
1277 $formticket->selectSeveritiesTickets($object->severity_code, 'update_value_severity', '', 2);
1278 print '</td>';
1279 print '</tr>';
1280 } else {
1281 // Type
1282 print '<tr><td class="titlefield">'.$langs->trans("Type").'</td><td>';
1283 if (!empty($object->type_code)) {
1284 print $langs->getLabelFromKey($db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code);
1285 }
1286 print '</td></tr>';
1287 // Group
1288 $s = '';
1289 if (!empty($object->category_code)) {
1290 $s = $langs->getLabelFromKey($db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code);
1291 }
1292 print '<tr><td>'.$langs->trans("TicketCategory").'</td><td class="tdoverflowmax200" title="'.dol_escape_htmltag($s).'">';
1293 print dol_escape_htmltag($s);
1294 print '</td></tr>';
1295 // Severity
1296 print '<tr><td>'.$langs->trans("TicketSeverity").'</td><td>';
1297 if (!empty($object->severity_code)) {
1298 print $langs->getLabelFromKey($db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code);
1299 }
1300 print '</td></tr>';
1301 }
1302 print '</table>'; // End table actions
1303 print '</div>';
1304
1305 print '</form>';
1306
1307 // Tags/Categories
1308 if (isModEnabled('category')) {
1309 print '<!-- tag/categories -->'."\n";
1310 print '<table class="border centpercent tableforfield">';
1311 print '<tr>';
1312 print '<td class="valignmiddle titlefield">';
1313 print '<table class="nobordernopadding centpercent"><tr><td class="none">';
1314 print $langs->trans("Categories");
1315 if ($action != 'categories' && !$user->socid) {
1316 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>';
1317 }
1318 print '</td>';
1319 print '</table>';
1320 print '</td>';
1321
1322 if ($user->hasRight('ticket', 'write') && $action == 'categories') {
1323 print '<td colspan="3">';
1324 print '<form action="'.$url_page_current.'" method="POST">';
1325 print '<input type="hidden" name="token" value="'.newToken().'">';
1326 print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1327 print '<input type="hidden" name="action" value="set_categories">';
1328 print $form->selectCategories(Categorie::TYPE_TICKET, 'categories', $object);
1329 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Save').'">';
1330 print '</form>';
1331 print "</td>";
1332 } else {
1333 print '<td colspan="3">';
1334 print $form->showCategories($object->id, Categorie::TYPE_TICKET, 1);
1335 print "</td></tr>";
1336 }
1337
1338 print '</table>';
1339 }
1340
1341 // View Original message
1342 $actionobject->viewTicketOriginalMessage($user, $action, $object);
1343
1344
1345 // Display navbar with links to change ticket status
1346 print '<!-- navbar with status -->';
1347 if (!$user->socid && $user->hasRight('ticket', 'write') && isset($object->status) && $object->status < $object::STATUS_CLOSED) {
1348 $actionobject->viewStatusActions($object);
1349 }
1350
1351
1352 if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
1353 print load_fiche_titre($langs->trans('Contacts'), '', 'title_companies.png');
1354
1355 print '<div class="div-table-responsive-no-min">';
1356 print '<div class="tagtable centpercent noborder allwidth">';
1357
1358 print '<div class="tagtr liste_titre">';
1359 print '<div class="tagtd">'.$langs->trans("Source").'</div>
1360 <div class="tagtd">' . $langs->trans("Company").'</div>
1361 <div class="tagtd">' . $langs->trans("Contacts").'</div>
1362 <div class="tagtd">' . $langs->trans("ContactType").'</div>
1363 <div class="tagtd">' . $langs->trans("Phone").'</div>
1364 <div class="tagtd center">' . $langs->trans("Status").'</div>';
1365 print '</div><!-- tagtr -->';
1366
1367 // Contact list
1368 $companystatic = new Societe($db);
1369 $contactstatic = new Contact($db);
1370 $userstatic = new User($db);
1371 $var = false;
1372 foreach (array('internal', 'external') as $source) {
1373 $tmpobject = $object;
1374 $tab = $tmpobject->listeContact(-1, $source);
1375 // '@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';
1376 $num = is_array($tab) ? count($tab) : 0;
1377 $i = 0;
1378 foreach (array_keys($tab) as $i) {
1379 $tab_i = &$tab[$i];
1380 $var = !$var;
1381 print '<div class="tagtr '.($var ? 'pair' : 'impair').'">';
1382
1383 print '<div class="tagtd left">';
1384 if ($tab_i['source'] == 'internal') {
1385 echo $langs->trans("User");
1386 }
1387
1388 if ($tab_i['source'] == 'external') {
1389 echo $langs->trans("ThirdPartyContact");
1390 }
1391
1392 print '</div>';
1393 print '<div class="tagtd left">';
1394
1395 if ($tab_i['socid'] > 0) {
1396 $companystatic->fetch($tab_i['socid']);
1397 echo $companystatic->getNomUrl(-1);
1398 }
1399 if ($tab_i['socid'] < 0) {
1400 echo getDolGlobalString('MAIN_INFO_SOCIETE_NOM');
1401 }
1402 if (!$tab_i['socid']) {
1403 echo '&nbsp;';
1404 }
1405 print '</div>';
1406
1407 print '<div class="tagtd">';
1408 if ($tab_i['source'] == 'internal') {
1409 if ($userstatic->fetch($tab_i['id'])) {
1410 print $userstatic->getNomUrl(-1);
1411 }
1412 }
1413 if ($tab_i['source'] == 'external') {
1414 if ($contactstatic->fetch($tab_i['id'])) {
1415 print $contactstatic->getNomUrl(-1);
1416 }
1417 }
1418 print ' </div>
1419 <div class="tagtd">' . $tab_i['libelle'].'</div>';
1420
1421 print '<div class="tagtd">';
1422
1423 print dol_print_phone($tab_i['phone'], '', 0, 0, 'AC_TEL').'<br>';
1424
1425 if (array_key_exists('phone_perso', $tab_i) && !empty($tab_i['phone_perso'])) {
1426 //print img_picto($langs->trans('PhonePerso'),'object_phoning.png','',0,0,0).' ';
1427 print '<br>'.dol_print_phone((string) $tab_i['phone_perso'], '', 0, 0, 'AC_TEL').'<br>';
1428 }
1429 if (!empty($tab_i['phone_mobile'])) {
1430 //print img_picto($langs->trans('PhoneMobile'),'object_phoning.png','',0,0,0).' ';
1431 print dol_print_phone($tab_i['phone_mobile'], '', 0, 0, 'AC_TEL').'<br>';
1432 }
1433 print '</div>';
1434
1435 print '<div class="tagtd center">';
1436 if ($object->status >= 0) {
1437 echo '<a href="contact.php?track_id='.$object->track_id.'&amp;action=swapstatut&amp;ligne='.$tab_i['rowid'].'">';
1438 }
1439
1440 if ($tab_i['source'] == 'internal') {
1441 $userstatic->id = $tab_i['id'];
1442 $userstatic->lastname = $tab_i['lastname'];
1443 $userstatic->firstname = $tab_i['firstname'];
1444 echo $userstatic->LibStatut($tab_i['statuscontact'], 3);
1445 }
1446 if ($tab_i['source'] == 'external') {
1447 $contactstatic->id = $tab_i['id'];
1448 $contactstatic->lastname = $tab_i['lastname'];
1449 $contactstatic->firstname = $tab_i['firstname'];
1450 echo $contactstatic->LibStatut($tab_i['statuscontact'], 3);
1451 }
1452 if ($object->status >= 0) {
1453 echo '</a>';
1454 }
1455
1456 print '</div>';
1457
1458 print '</div><!-- tagtr -->';
1459
1460 $i++;
1461 }
1462 }
1463
1464 print '</div><!-- contact list -->';
1465 print '</div>';
1466 }
1467
1468 print '</div></div>';
1469 print '<div class="clearboth"></div>';
1470
1471 print dol_get_fiche_end();
1472
1473
1474 // Buttons for actions
1475 if ($action != 'presend' && $action != 'presend_addmessage' && $action != 'editline') {
1476 print '<div class="tabsAction">'."\n";
1477 $parameters = array();
1478 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1479 if ($reshook < 0) {
1480 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1481 }
1482
1483 if (empty($reshook)) {
1484 // Email
1485 if (isset($object->status) && $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage") {
1486 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend_addmessage&send_email=1&private_message=0&mode=init&token='.newToken().'&track_id='.$object->track_id.'#formmailbeforetitle', '');
1487 }
1488
1489 // Show link to add a message (if read and not closed)
1490 if (isset($object->status) && $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage") {
1491 print dolGetButtonAction('', $langs->trans('TicketAddPrivateMessage'), 'default', $_SERVER["PHP_SELF"].'?action=presend_addmessage&mode=init&token='.newToken().'&track_id='.$object->track_id.'#formmailbeforetitle', '');
1492 }
1493
1494 // Link to create an intervention
1495 // socid is needed otherwise fichinter ask it and forgot origin after form submit :\
1496 if (!$object->fk_soc && $user->hasRight("ficheinter", "creer")) {
1497 print dolGetButtonAction($langs->trans('UnableToCreateInterIfNoSocid'), $langs->trans('TicketAddIntervention'), 'default', $_SERVER['PHP_SELF']. '#', '', false);
1498 }
1499 if ($object->fk_soc > 0 && isset($object->status) && $object->status < Ticket::STATUS_CLOSED && $user->hasRight('ficheinter', 'creer')) {
1500 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, '');
1501 }
1502
1503 // Close ticket if status is read
1504 if (isset($object->status) && $object->status >= 0 && $object->status < Ticket::STATUS_CLOSED && $user->hasRight('ticket', 'write')) {
1505 print dolGetButtonAction('', $langs->trans('CloseTicket'), 'default', $_SERVER["PHP_SELF"].'?action=close&token='.newToken().'&track_id='.$object->track_id, '');
1506 }
1507
1508 // Abandon ticket if status is read
1509 if (isset($object->status) && $object->status > 0 && $object->status < Ticket::STATUS_CLOSED && $user->hasRight('ticket', 'write')) {
1510 print dolGetButtonAction('', $langs->trans('AbandonTicket'), 'default', $_SERVER["PHP_SELF"].'?action=abandon&token='.newToken().'&track_id='.$object->track_id, '');
1511 }
1512
1513 // Re-open ticket
1514 if (!$user->socid && (isset($object->status) && ($object->status == Ticket::STATUS_CLOSED || $object->status == Ticket::STATUS_CANCELED)) && !$user->socid) {
1515 print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&track_id='.$object->track_id, '');
1516 }
1517
1518 // Edit ticket
1519 if ($permissiontoedit) {
1520 print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoedit);
1521 }
1522
1523 // Delete ticket
1524 if ($user->hasRight('ticket', 'delete') && !$user->socid) {
1525 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&track_id='.$object->track_id, '');
1526 }
1527 }
1528 print '</div>'."\n";
1529 }
1530
1531 // Select mail models is same action as presend
1532 if (GETPOST('modelselected')) {
1533 $action = 'presend';
1534 }
1535 // Set $action to correct value for the case we used presend action to add a message
1536 if (GETPOSTISSET('actionbis') && $action == 'presend') {
1537 $action = 'presend_addmessage';
1538 }
1539
1540 // add a message
1541 if ($action == 'presend' || $action == 'presend_addmessage') {
1542 if ($object->fk_soc > 0) {
1543 $object->fetch_thirdparty();
1544 }
1545
1546 $outputlangs = $langs;
1547 $newlang = '';
1548 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
1549 $newlang = GETPOST('lang_id', 'aZ09');
1550 } elseif (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && is_object($object->thirdparty)) {
1551 $newlang = $object->thirdparty->default_lang;
1552 }
1553 if (!empty($newlang)) {
1554 $outputlangs = new Translate("", $conf);
1555 $outputlangs->setDefaultLang($newlang);
1556 }
1557
1558 $arrayoffamiliestoexclude = array('objectamount');
1559
1560 $action = 'add_message'; // action to use to post the message
1561 $modelmail = 'ticket_send';
1562
1563 // Substitution array
1564 $morehtmlright = '';
1565 $help = "";
1566 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0, $arrayoffamiliestoexclude, $object);
1567 complete_substitutions_array($substitutionarray, $outputlangs, $object);
1568 $morehtmlright .= $form->textwithpicto('<span class="opacitymedium">'.$langs->trans("TicketMessageSubstitutionReplacedByGenericValues").'</span>', $help, 1, 'helpclickable', '', 0, 3, 'helpsubstitution');
1569
1570 print '<div>';
1571
1572 print '<div id="formmailbeforetitle" name="formmailbeforetitle"></div>';
1573
1574 print load_fiche_titre($langs->trans('TicketAddMessage'), $morehtmlright, 'messages@ticket');
1575
1576 print '<hr>';
1577
1578 $formticket = new FormTicket($db);
1579
1580 $formticket->action = $action;
1581 $formticket->track_id = $object->track_id;
1582 $formticket->ref = $object->ref;
1583 $formticket->id = $object->id;
1584 $formticket->trackid = 'tic'.$object->id;
1585
1586 $formticket->withfile = 2;
1587 $formticket->withcancel = 1;
1588 $formticket->param = array('fk_user_create' => $user->id);
1589 $formticket->param['langsmodels'] = (empty($newlang) ? $langs->defaultlang : $newlang);
1590
1591 // Table of additional post parameters
1592 $formticket->param['models'] = $modelmail;
1593 $formticket->param['models_id'] = GETPOSTINT('modelmailselected');
1594 //$formticket->param['socid']=$object->fk_soc;
1595 $formticket->param['returnurl'] = $_SERVER["PHP_SELF"].'?track_id='.urldecode($object->track_id);
1596
1597 $formticket->withsubstit = 1;
1598 $formticket->substit = $substitutionarray;
1599 $formticket->backtopage = $backtopage;
1600
1601 $formticket->showMessageForm('100%');
1602 print '</div>';
1603 }
1604
1605 // Show messages on card (Note: this is a duplicate of the view Events/Agenda but on the main tab)
1606 if (getDolGlobalString('TICKET_SHOW_MESSAGES_ON_CARD')) {
1607 $param = '&id='.$object->id;
1608 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1609 $param .= '&contextpage='.$contextpage;
1610 }
1611 if ($limit > 0 && $limit != $conf->liste_limit) {
1612 $param .= '&limit='.$limit;
1613 }
1614 if ($actioncode) {
1615 $param .= '&actioncode='.urlencode($actioncode);
1616 }
1617 if ($search_agenda_label) {
1618 $param .= '&search_agenda_label='.urlencode($search_agenda_label);
1619 }
1620
1621 $morehtmlright = '';
1622
1623 $messagingUrl = DOL_URL_ROOT.'/ticket/agenda.php?track_id='.$object->track_id;
1624 $morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fa fa-bars imgforviewmode', $messagingUrl, '', 1);
1625
1626 // Show link to add a message (if read and not closed)
1627 $btnstatus = $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage" && $action != "add_message";
1628 $url = 'card.php?track_id='.$object->track_id.'&action=presend_addmessage&mode=init';
1629 $morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fa fa-comment-dots', $url, 'add-new-ticket-title-button', (int) $btnstatus);
1630
1631 // Show link to add event (if read and not closed)
1632 $btnstatus = $object->status < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage" && $action != "add_message";
1633 $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);
1634 $morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, 'add-new-ticket-even-button', (int) $btnstatus);
1635
1636 print_barre_liste($langs->trans("ActionsOnTicket"), 0, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', 0, -1, '', 0, $morehtmlright, '', 0, 1, 1);
1637
1638 // List of all actions
1639 $filters = array();
1640 $filters['search_agenda_label'] = $search_agenda_label;
1641 $filters['search_rowid'] = $search_rowid;
1642
1643 show_actions_messaging($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder);
1644 }
1645
1646 if ($action != 'presend' && $action != 'presend_addmessage' && $action != 'add_message') {
1647 print '<div class="fichecenter"><div class="fichehalfleft">';
1648 print '<a name="builddoc"></a>'; // ancre
1649 /*
1650 * Generated documents
1651 */
1652 $filename = dol_sanitizeFileName($object->ref);
1653 $filedir = $upload_dir."/".dol_sanitizeFileName($object->ref);
1654 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
1655 $genallowed = $permissiontoadd;
1656 $delallowed = $permissiontodelete;
1657 $codelang = '';
1658 if ($object->fk_soc > 0) {
1659 $object->fetch_thirdparty();
1660 $codelang = $object->thirdparty->default_lang;
1661 }
1662
1663 print $formfile->showdocuments('ticket', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $codelang);
1664
1665 // Show links to link elements
1666 $tmparray = $form->showLinkToObjectBlock($object, array(), array('ticket'), 1);
1667 $linktoelem = $tmparray['linktoelem'];
1668 $htmltoenteralink = $tmparray['htmltoenteralink'];
1669 print $htmltoenteralink;
1670
1671 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
1672
1673 // Show direct link to public interface
1674 print '<br><!-- Link to public interface -->'."\n";
1675 print showDirectPublicLink($object).'<br>';
1676 print '</div>';
1677
1678 if (!getDolGlobalString('MAIN_HIDE_MESSAGES_ON_CARD')) {
1679 print '<div class="fichehalfright">';
1680
1681 $MAXEVENT = 10;
1682
1683 $morehtmlcenter = '<div class="nowraponall">';
1684 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT.'/ticket/messaging.php?id='.$object->id);
1685 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullList'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/ticket/agenda.php?id='.$object->id);
1686 $morehtmlcenter .= '</div>';
1687
1688 // List of actions on element
1689 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
1690 $formactions = new FormActions($db);
1691 $somethingshown = $formactions->showactions($object, 'ticket', $socid, 1, 'listactions', $MAXEVENT, '', $morehtmlcenter);
1692
1693 print '</div>';
1694 }
1695
1696 print '</div>';
1697 }
1698 }
1699}
1700
1701// End of page
1702llxFooter();
1703$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
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:244
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.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
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.
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_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
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_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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.
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
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...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
Class to generate the form for creating a new ticket.
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
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.