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		Frédéric France		<frederic.france@netlogic.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21/**
22 *    \file     htdocs/ticket/card.php
23 *    \ingroup 	ticket
24 */
25
26require '../main.inc.php';
27require_once DOL_DOCUMENT_ROOT.'/ticket/class/actions_ticket.class.php';
28require_once DOL_DOCUMENT_ROOT.'/core/class/html.formticket.class.php';
29require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
30require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
31require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
33require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
34if (!empty($conf->projet->enabled)) {
35	include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
36	include_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
37	include_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
38}
39if (!empty($conf->contrat->enabled)) {
40	include_once DOL_DOCUMENT_ROOT.'/core/lib/contract.lib.php';
41	include_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
42	include_once DOL_DOCUMENT_ROOT.'/core/class/html.formcontract.class.php';
43}
44
45// Load translation files required by the page
46$langs->loadLangs(array("companies", "other", "ticket"));
47
48// Get parameters
49$id        = GETPOST('id', 'int');
50$socid     = GETPOST('socid', 'int');
51$track_id  = GETPOST('track_id', 'alpha', 3);
52$ref       = GETPOST('ref', 'alpha');
53$projectid = GETPOST('projectid', 'int');
54$cancel    = GETPOST('cancel', 'alpha');
55$action    = GETPOST('action', 'aZ09');
56$backtopage = GETPOST('$backtopage', 'alpha');
57
58$notifyTiers = GETPOST("notify_tiers_at_create", 'alpha');
59
60$sortfield = GETPOST('sortfield', 'aZ09comma');
61$sortorder = GETPOST('sortorder', 'aZ09comma');
62
63if (GETPOST('actioncode', 'array')) {
64	$actioncode = GETPOST('actioncode', 'array', 3);
65	if (!count($actioncode)) {
66		$actioncode = '0';
67	}
68} else {
69	$actioncode = GETPOST("actioncode", "alpha", 3) ?GETPOST("actioncode", "alpha", 3) : (GETPOST("actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE_FOR_OBJECT));
70}
71$search_agenda_label = GETPOST('search_agenda_label');
72
73// Initialize technical object to manage hooks of ticket. Note that conf->hooks_modules contains array array
74$hookmanager->initHooks(array('ticketcard', 'globalcard'));
75
76$object = new Ticket($db);
77$extrafields = new ExtraFields($db);
78
79// Fetch optionals attributes and labels
80$extrafields->fetch_name_optionals_label($object->table_element);
81
82$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
83
84// Initialize array of search criterias
85$search_all = GETPOST("search_all", 'alpha');
86$search = array();
87foreach ($object->fields as $key => $val) {
88	if (GETPOST('search_'.$key, 'alpha')) {
89		$search[$key] = GETPOST('search_'.$key, 'alpha');
90	}
91}
92
93if (empty($action) && empty($id) && empty($ref)) {
94	$action = 'view';
95}
96
97//Select mail models is same action as add_message
98if (GETPOST('modelselected', 'alpha')) {
99	$action = 'presend';
100}
101
102// Load object
103//include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php';  // Must be include, not include_once  // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals
104if ($id || $track_id || $ref) {
105	$res = $object->fetch($id, $ref, $track_id);
106	if ($res >= 0) {
107		$id = $object->id;
108		$track_id = $object->track_id;
109	}
110}
111
112// Store current page url
113$url_page_current = DOL_URL_ROOT.'/ticket/card.php';
114
115// Security check - Protection if external user
116$socid = 0;
117if ($user->socid > 0) $socid = $user->socid;
118$result = restrictedArea($user, 'ticket', $object->id);
119
120$triggermodname = 'TICKET_MODIFY';
121$permissiontoadd = $user->rights->ticket->write;
122
123$actionobject = new ActionsTicket($db);
124
125$now = dol_now();
126
127
128/*
129 * Actions
130 */
131
132$parameters = array();
133$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
134if ($reshook < 0) {
135	setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
136}
137
138$error = 0;
139if (empty($reshook)) {
140	// Purge search criteria
141	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{
142		$actioncode = '';
143		$search_agenda_label = '';
144	}
145
146	if ($cancel) {
147		if (!empty($backtopage)) {
148			header("Location: ".$backtopage);
149			exit;
150		}
151
152		$action = 'view';
153	}
154
155	// Action to add an action (not a message)
156	if (GETPOST('add', 'alpha') && !empty($user->rights->ticket->write)) {
157		$error = 0;
158
159		if (!GETPOST("subject", 'alphanohtml')) {
160			$error++;
161			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")), null, 'errors');
162			$action = 'create';
163		} elseif (!GETPOST("message", 'restricthtml')) {
164			$error++;
165			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Message")), null, 'errors');
166			$action = 'create';
167		}
168		$ret = $extrafields->setOptionalsFromPost(null, $object);
169		if ($ret < 0) {
170			$error++;
171		}
172
173		if (!$error) {
174			$db->begin();
175
176			$object->ref = GETPOST("ref", 'alphanohtml');
177			$object->fk_soc = GETPOST("socid", 'int') > 0 ? GETPOST("socid", 'int') : 0;
178			$object->subject = GETPOST("subject", 'alphanohtml');
179			$object->message = GETPOST("message", 'restricthtml');
180
181			$object->type_code = GETPOST("type_code", 'alpha');
182			$object->type_label = $langs->trans($langs->getLabelFromKey($db, $object->type_code, 'c_ticket_type', 'code', 'label'));
183			$object->category_code = GETPOST("category_code", 'alpha');
184			$object->category_label = $langs->trans($langs->getLabelFromKey($db, $object->category_code, 'c_ticket_category', 'code', 'label'));
185			$object->severity_code = GETPOST("severity_code", 'alpha');
186			$object->severity_label = $langs->trans($langs->getLabelFromKey($db, $object->severity_code, 'c_ticket_severity', 'code', 'label'));
187			$object->email_from = $user->email;
188			$notifyTiers = GETPOST("notify_tiers_at_create", 'alpha');
189			$object->notify_tiers_at_create = empty($notifyTiers) ? 0 : 1;
190
191			$object->fk_project = $projectid;
192
193			$id = $object->create($user);
194			if ($id <= 0) {
195				$error++;
196				setEventMessages($object->error, $object->errors, 'errors');
197				$action = 'create';
198			}
199
200			if (!$error) {
201				// Add contact
202				$contactid = GETPOST('contactid', 'int');
203				$type_contact = GETPOST("type", 'alpha');
204
205				if ($contactid > 0 && $type_contact) {
206					$typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
207					$result = $object->add_contact($contactid, $typeid, 'external');
208				}
209
210				// Link ticket to project
211				if ($projectid > 0) {
212					$object->setProject($projectid);
213				}
214
215				// Auto assign user
216				if (!empty($conf->global->TICKET_AUTO_ASSIGN_USER_CREATE)) {
217					$result = $object->assignUser($user, $user->id, 1);
218					$object->add_contact($user->id, "SUPPORTTEC", 'internal');
219				}
220
221				// Auto assign contrat
222				$contractid = 0;
223				if (!empty($conf->global->TICKET_AUTO_ASSIGN_CONTRACT_CREATE)) {
224					$contrat = new Contrat($db);
225					$contrat->socid = $object->fk_soc;
226					$list = $contrat->getListOfContracts();
227
228					if (is_array($list) && !empty($list)) {
229						if (count($list) == 1) {
230							$contractid = $list[0]->id;
231							$object->setContract($contractid);
232						} else {
233						}
234					}
235				}
236
237				// Auto create fiche intervention
238				if (!empty($conf->global->TICKET_AUTO_CREATE_FICHINTER_CREATE)) {
239					$fichinter = new Fichinter($db);
240					$fichinter->socid = $object->fk_soc;
241					$fichinter->fk_project = $projectid;
242					$fichinter->fk_contrat = $contractid;
243					$fichinter->author = $user->id;
244					$fichinter->model_pdf = 'soleil';
245					$fichinter->origin = $object->element;
246					$fichinter->origin_id = $object->id;
247
248					// Extrafields
249					$extrafields->fetch_name_optionals_label($fichinter->table_element);
250					$array_options = $extrafields->getOptionalsFromPost($fichinter->table_element);
251					$fichinter->array_options = $array_options;
252
253					$id = $fichinter->create($user);
254					if ($id <= 0) {
255						setEventMessages($fichinter->error, null, 'errors');
256					}
257				}
258			}
259
260			if (!$error) {
261				// File transfer
262				$object->copyFilesForTicket();
263			}
264
265			if (!$error) {
266				$db->commit();
267
268				if (!empty($backtopage)) {
269					$url = $backtopage;
270				} else {
271					$url = 'card.php?track_id='.$object->track_id;
272				}
273
274				header("Location: ".$url);
275				exit;
276			} else {
277				$db->rollback();
278				setEventMessages($object->error, $object->errors, 'errors');
279			}
280		} else {
281			setEventMessages($object->error, $object->errors, 'errors');
282		}
283	}
284
285	if ($action == 'update' && $user->rights->ticket->write && $object->fk_statut < Ticket::STATUS_CLOSED) {
286		$error = 0;
287
288		$ret = $object->fetch(GETPOST('id', 'int'), GETPOST('ref', 'alpha'), GETPOST('track_id', 'alpha'));
289		if ($ret < 0) {
290			$error++;
291			array_push($object->errors, $langs->trans('ErrorTicketIsNotValid'));
292		}
293
294		// check fields
295		if (!$error) {
296			if (!GETPOST('subject', 'alpha')) {
297				$error++;
298				array_push($object->errors, $langs->trans('ErrorFieldRequired', $langs->transnoentities('Subject')));
299			}
300			$ret = $extrafields->setOptionalsFromPost(null, $object);
301			if ($ret < 0) {
302				$error++;
303			}
304		}
305
306		if (!$error) {
307			$db->begin();
308
309			$object->subject = GETPOST('subject', 'alpha');
310			$object->type_code = GETPOST('type_code', 'alpha');
311			$object->category_code = GETPOST('category_code', 'alpha');
312			$object->severity_code = GETPOST('severity_code', 'alpha');
313
314			$ret = $object->update($user);
315			if ($ret <= 0) {
316				$error++;
317			}
318
319			if ($error) {
320				$db->rollback();
321			} else {
322				$db->commit();
323			}
324		}
325
326		if ($error) {
327			setEventMessages($object->error, $object->errors, 'errors');
328			$action = 'edit';
329		} else {
330			if (!empty($backtopage)) {
331				$url = $backtopage;
332			} else {
333				$url = 'card.php?track_id='.$object->track_id;
334			}
335
336			header('Location: '.$url);
337			exit();
338		}
339	}
340
341	// Mark as Read
342	if ($action == "mark_ticket_read" && $user->rights->ticket->write) {
343		$object->fetch('', '', GETPOST("track_id", 'alpha'));
344
345		if ($object->markAsRead($user) > 0) {
346			setEventMessages($langs->trans('TicketMarkedAsRead'), null, 'mesgs');
347
348			header("Location: card.php?track_id=".$object->track_id."&action=view");
349			exit;
350		} else {
351			setEventMessages($object->error, $object->errors, 'errors');
352		}
353		$action = 'view';
354	}
355
356	// Assign to someone
357	if ($action == "assign_user" && GETPOST('btn_assign_user', 'alpha') && $user->rights->ticket->write) {
358		$object->fetch('', '', GETPOST("track_id", 'alpha'));
359		$useroriginassign = $object->fk_user_assign;
360		$usertoassign = GETPOST('fk_user_assign', 'int');
361
362		/*if (! ($usertoassign > 0)) {
363		 $error++;
364		 array_push($object->errors, $langs->trans("ErrorFieldRequired", $langs->transnoentities("AssignedTo")));
365		 $action = 'view';
366		 }*/
367
368		if (!$error) {
369			$ret = $object->assignUser($user, $usertoassign);
370			if ($ret < 0) {
371				$error++;
372			}
373		}
374
375		if (!$error) {    // Update list of contacts
376			// Si déjà un user assigné on le supprime des contacts
377			if ($useroriginassign > 0) {
378				$internal_contacts = $object->listeContact(-1, 'internal');
379
380				foreach ($internal_contacts as $key => $contact) {
381					if ($contact['code'] == "SUPPORTTEC" && $contact['id'] == $useroriginassign) {
382					}
383					{
384						//print "user à effacer : ".$useroriginassign;
385						$object->delete_contact($contact['rowid']);
386					}
387				}
388			}
389
390			if ($usertoassign > 0) {
391				$object->add_contact($usertoassign, "SUPPORTTEC", 'internal', $notrigger = 0);
392			}
393		}
394
395		if (!$error) {
396			// Log action in ticket logs table
397			$object->fetch_user($usertoassign);
398			$log_action = $langs->trans('TicketLogAssignedTo', $object->user->getFullName($langs));
399
400			setEventMessages($langs->trans('TicketAssigned'), null, 'mesgs');
401
402			header("Location: card.php?track_id=".$object->track_id."&action=view");
403			exit;
404		} else {
405			array_push($object->errors, $object->error);
406		}
407		$action = 'view';
408	}
409
410	// Action to add an action (not a message)
411	if ($action == 'add_message' && GETPOSTISSET('btn_add_message') && $user->rights->ticket->read) {
412		$ret = $object->newMessage($user, $action, (GETPOST('private_message', 'alpha') == "on" ? 1 : 0));
413
414		if ($ret > 0) {
415			if (!empty($backtopage)) {
416				$url = $backtopage;
417			} else {
418				$url = 'card.php?action=view&track_id='.$object->track_id;
419			}
420
421			header("Location: ".$url);
422			exit;
423		} else {
424			setEventMessages($object->error, null, 'errors');
425			$action = 'presend';
426		}
427	}
428
429	if (($action == "confirm_close" || $action == "confirm_abandon") && GETPOST('confirm', 'alpha') == 'yes' && $user->rights->ticket->write) {
430		$object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha'));
431
432		if ($object->close($user, ($action == "confirm_abandon" ? 1 : 0))) {
433			setEventMessages($langs->trans('TicketMarkedAsClosed'), null, 'mesgs');
434
435			$url = 'card.php?action=view&track_id='.GETPOST('track_id', 'alpha');
436			header("Location: ".$url);
437		} else {
438			$action = '';
439			setEventMessages($object->error, $object->errors, 'errors');
440		}
441	}
442
443	if ($action == "confirm_public_close" && GETPOST('confirm', 'alpha') == 'yes') {
444		$object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha'));
445		if ($_SESSION['email_customer'] == $object->origin_email || $_SESSION['email_customer'] == $object->thirdparty->email) {
446			$object->close($user);
447
448			// Log action in ticket logs table
449			$log_action = $langs->trans('TicketLogClosedBy', $_SESSION['email_customer']);
450
451			setEventMessages('<div class="confirm">'.$langs->trans('TicketMarkedAsClosed').'</div>', null, 'mesgs');
452
453			$url = 'card.php?action=view_ticket&track_id='.GETPOST('track_id', 'alpha');
454			header("Location: ".$url);
455		} else {
456			setEventMessages($object->error, $object->errors, 'errors');
457			$action = '';
458		}
459	}
460
461	if ($action == 'confirm_delete_ticket' && GETPOST('confirm', 'alpha') == "yes" && $user->rights->ticket->delete) {
462		if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) {
463			if ($object->delete($user) > 0) {
464				setEventMessages('<div class="confirm">'.$langs->trans('TicketDeletedSuccess').'</div>', null, 'mesgs');
465				Header("Location: ".DOL_URL_ROOT."/ticket/list.php");
466				exit;
467			} else {
468				$langs->load("errors");
469				$mesg = '<div class="error">'.$langs->trans($object->error).'</div>';
470				$action = '';
471			}
472		}
473	}
474
475	// Set parent company
476	if ($action == 'set_thirdparty' && $user->rights->ticket->write) {
477		if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) {
478			$result = $object->setCustomer(GETPOST('editcustomer', 'int'));
479			$url = 'card.php?action=view&track_id='.GETPOST('track_id', 'alpha');
480			header("Location: ".$url);
481			exit();
482		}
483	}
484
485	if ($action == 'set_progression' && $user->rights->ticket->write) {
486		if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) {
487			$result = $object->setProgression(GETPOST('progress', 'alpha'));
488
489			$url = 'card.php?action=view&track_id='.$object->track_id;
490			header("Location: ".$url);
491			exit();
492		}
493	}
494
495	if ($action == 'setsubject' && $user->rights->ticket->write) {
496		if ($object->fetch(GETPOST('id', 'int'))) {
497			if ($action == 'setsubject') {
498				$object->subject = GETPOST('subject', 'alphanohtml');
499			}
500
501			if ($action == 'setsubject' && empty($object->subject)) {
502				$error++;
503				setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Subject")), null, 'errors');
504			}
505
506			if (!$error) {
507				if ($object->update($user) >= 0) {
508					header("Location: ".$_SERVER['PHP_SELF']."?track_id=".$object->track_id);
509					exit;
510				} else {
511					$error++;
512					setEventMessages($object->error, $object->errors, 'errors');
513				}
514			}
515		}
516	}
517
518	if ($action == 'confirm_reopen' && $user->rights->ticket->manage && !GETPOST('cancel')) {
519		if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) {
520			// prevent browser refresh from reopening ticket several times
521			if ($object->fk_statut == Ticket::STATUS_CLOSED || $object->fk_statut == Ticket::STATUS_CANCELED) {
522				$res = $object->setStatut(Ticket::STATUS_ASSIGNED);
523				if ($res) {
524					// Log action in ticket logs table
525					$log_action = $langs->trans('TicketLogReopen');
526
527					$url = 'card.php?action=view&track_id='.$object->track_id;
528					header("Location: ".$url);
529					exit();
530				} else {
531					$error++;
532					setEventMessages($object->error, $object->errors, 'errors');
533				}
534			}
535		}
536	} elseif ($action == 'classin' && $user->rights->ticket->write) {
537		// Categorisation dans projet
538		if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) {
539			$object->setProject($projectid);
540			$url = 'card.php?action=view&track_id='.$object->track_id;
541			header("Location: ".$url);
542			exit();
543		}
544	} elseif ($action == 'setcontract' && $user->rights->ticket->write) {
545		// Categorisation dans contrat
546		if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) {
547			$object->setContract(GETPOST('contractid', 'int'));
548			$url = 'card.php?action=view&track_id='.$object->track_id;
549			header("Location: ".$url);
550			exit();
551		}
552	} elseif ($action == "set_message" && $user->rights->ticket->manage) {
553		// altairis: manage cancel button
554		if (!GETPOST('cancel')) {
555			$object->fetch('', '', GETPOST('track_id', 'alpha'));
556			$oldvalue_message = $object->message;
557			$fieldtomodify = GETPOST('message_initial', 'restricthtml');
558
559			$object->message = $fieldtomodify;
560			$ret = $object->update($user);
561			if ($ret > 0) {
562				$log_action = $langs->trans('TicketInitialMessageModified')." \n";
563				// include the Diff class
564				dol_include_once('/ticket/class/utils_diff.class.php');
565				// output the result of comparing two files as plain text
566				$log_action .= Diff::toString(Diff::compare(strip_tags($oldvalue_message), strip_tags($object->message)));
567
568				setEventMessages($langs->trans('TicketMessageSuccesfullyUpdated'), null, 'mesgs');
569			} else {
570				$error++;
571				setEventMessages($object->error, $object->errors, 'errors');
572			}
573		}
574
575		$action = 'view';
576	} elseif ($action == 'confirm_set_status' && $user->rights->ticket->write && !GETPOST('cancel')) {
577		// Reopen ticket
578		if ($object->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) {
579			$new_status = GETPOST('new_status', 'int');
580			$old_status = $object->fk_statut;
581			$res = $object->setStatut($new_status);
582			if ($res) {
583				// Log action in ticket logs table
584				$log_action = $langs->trans('TicketLogStatusChanged', $langs->transnoentities($object->statuts_short[$old_status]), $langs->transnoentities($object->statuts_short[$new_status]));
585
586				$url = 'card.php?action=view&track_id='.$object->track_id;
587				header("Location: ".$url);
588				exit();
589			} else {
590				$error++;
591				setEventMessages($object->error, $object->errors, 'errors');
592			}
593		}
594	}
595
596	// Action to update one extrafield
597	if ($action == "update_extras" && !empty($permissiontoadd)) {
598		$object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha'));
599
600		$ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
601		if ($ret < 0) {
602			$error++;
603		}
604
605		if (!$error) {
606			$result = $object->insertExtraFields(empty($triggermodname) ? '' : $triggermodname, $user);
607			if ($result < 0) {
608				$error++;
609			}
610		}
611
612		if ($error) {
613			setEventMessages($object->error, $object->errors, 'errors');
614			$action = 'edit_extras';
615		} else {
616			setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
617			$action = 'view';
618		}
619	}
620
621	if ($action == "change_property" && GETPOST('btn_update_ticket_prop', 'alpha') && $user->rights->ticket->write) {
622		$object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha'));
623
624		$object->type_code = GETPOST('update_value_type', 'aZ09');
625		$object->severity_code = GETPOST('update_value_severity', 'aZ09');
626		$object->category_code = GETPOST('update_value_category', 'aZ09');
627
628		$ret = $object->update($user);
629		if ($ret > 0) {
630			$log_action = $langs->trans('TicketLogPropertyChanged', $oldvalue_label, $newvalue_label);
631
632			setEventMessages($langs->trans('TicketUpdated'), null, 'mesgs');
633		} else {
634			$error++;
635			setEventMessages($object->error, $object->errors, 'errors');
636		}
637		$action = 'view';
638	}
639
640
641	$permissiondellink = $user->rights->ticket->write;
642	include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
643
644	// Actions to build doc
645	$upload_dir = $conf->ticket->dir_output;
646	$permissiontoadd = $user->rights->ticket->write;
647	include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
648
649	// Actions to send emails
650	$triggersendname = 'TICKET_SENTBYMAIL';
651	$paramname = 'id';
652	$autocopy = 'MAIN_MAIL_AUTOCOPY_TICKET_TO'; // used to know the automatic BCC to add
653	$trackid = 'tic'.$object->id;
654	include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
655
656	// Set $action to correct value for the case we used presend action to add a message
657	if (GETPOSTISSET('actionbis') && $action == 'presend') {
658		$action = 'presend_addmessage';
659	}
660}
661
662
663/*
664 * View
665 */
666
667$userstat = new User($db);
668$form = new Form($db);
669$formticket = new FormTicket($db);
670if (!empty($conf->projet->enabled)) {
671	$formproject = new FormProjets($db);
672}
673
674$help_url = 'EN:Module_Ticket|FR:DocumentationModuleTicket';
675
676$page_title = $actionobject->getTitle($action);
677
678llxHeader('', $page_title, $help_url);
679
680if ($action == 'create' || $action == 'presend') {
681	$formticket = new FormTicket($db);
682
683	print load_fiche_titre($langs->trans('NewTicket'), '', 'ticket');
684
685	$formticket->withfromsocid = $socid ? $socid : $user->socid;
686	$formticket->withfromcontactid = $contactid ? $contactid : '';
687	$formticket->withtitletopic = 1;
688	$formticket->withnotifytiersatcreate = ($notifyTiers ? 1 : 0);
689	$formticket->withusercreate = 0;
690	$formticket->withref = 1;
691	$formticket->fk_user_create = $user->id;
692	$formticket->withfile = 2;
693	$formticket->withextrafields = 1;
694	$formticket->param = array('origin' => GETPOST('origin'), 'originid' => GETPOST('originid'));
695
696	$formticket->showForm(1, 'create', 0);
697	/*} elseif ($action == 'edit' && $user->rights->ticket->write && $object->fk_statut < Ticket::STATUS_CLOSED) {
698	$formticket = new FormTicket($db);
699
700	$head = ticket_prepare_head($object);
701
702	print '<form method="POST" name="form_ticket" id="form_edit_ticket" action="'.$_SERVER['PHP_SELF'].'?track_id='.$object->track_id.'">';
703	print '<input type="hidden" name="token" value="'.newToken().'">';
704	print '<input type="hidden" name="action" value="update">';
705	print '<input type="hidden" name="tack_id" value="'.$object->track_id.'">';
706
707	print dol_get_fiche_head($head, 'card', $langs->trans('Ticket'), 0, 'ticket');
708
709	print '<div class="fichecenter2">';
710	print '<table class="border" width="100%">';
711
712	// Type
713	print '<tr><td class="titlefield"><span class="fieldrequired"><label for="selecttype_code">'.$langs->trans("TicketTypeRequest").'</span></label></td><td>';
714	$formticket->selectTypesTickets((GETPOSTISSET('type_code') ? GETPOST('type_code') : $object->type_code), 'type_code', '', '2');
715	print '</td></tr>';
716
717	// Severity
718	print '<tr><td><span class="fieldrequired"><label for="selectseverity_code">'.$langs->trans("TicketSeverity").'</span></label></td><td>';
719	$formticket->selectSeveritiesTickets((GETPOSTISSET('severity_code') ? GETPOST('severity_code') : $object->severity_code), 'severity_code', '', '2');
720	print '</td></tr>';
721
722	// Group
723	print '<tr><td><span class="fieldrequired"><label for="selectcategory_code">'.$langs->trans("TicketCategory").'</span></label></td><td>';
724	$formticket->selectGroupTickets((GETPOSTISSET('category_code') ? GETPOST('category_code') : $object->category_code), 'category_code', '', '2');
725	print '</td></tr>';
726
727	// Subject
728	print '<tr><td><label for="subject"><span class="fieldrequired">'.$langs->trans("Subject").'</span></label></td><td>';
729	print '<input class="text minwidth200" id="subject" name="subject" value="'.dol_escape_htmltag(GETPOSTISSET('subject') ? GETPOST('subject', 'alpha') : $object->subject).'" />';
730	print '</td></tr>';
731
732	// Other attributes
733	$parameters = array('colspan' => ' colspan="3"', 'colspanvalue' => '3');
734	$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
735	print $hookmanager->resPrint;
736	if (empty($reshook)) {
737		print $object->showOptionals($extrafields, 'edit');
738	}
739
740	print '</table>';
741	print '</div>';
742
743	print dol_get_fiche_end();
744
745	print '<div class="center">';
746	print '<input type="submit" class="button button-save" name="save" value="'.$langs->trans("Save").'">';
747	print ' &nbsp; &nbsp; ';
748	print '<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'">';
749	print '</div>';
750
751	print '</form>'; */
752} elseif (empty($action) || $action == 'view' || $action == 'addlink' || $action == 'dellink' || $action == 'presend' || $action == 'presend_addmessage' || $action == 'close' || $action == 'abandon' || $action == 'delete' || $action == 'editcustomer' || $action == 'progression' || $action == 'reopen'
753	|| $action == 'editsubject' || $action == 'edit_extras' || $action == 'update_extras' || $action == 'edit_extrafields' || $action == 'set_extrafields' || $action == 'classify' || $action == 'sel_contract' || $action == 'edit_message_init' || $action == 'set_status' || $action == 'dellink') {
754	if ($res > 0) {
755		// or for unauthorized internals users
756		if (!$user->socid && (!empty($conf->global->TICKET_LIMIT_VIEW_ASSIGNED_ONLY) && $object->fk_user_assign != $user->id) && !$user->rights->ticket->manage) {
757			accessforbidden('', 0, 1);
758		}
759
760		// Confirmation close
761		if ($action == 'close') {
762			print $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_close", '', '', 1);
763			if ($ret == 'html') {
764				print '<br>';
765			}
766		}
767		// Confirmation abandon
768		if ($action == 'abandon') {
769			print $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("AbandonTicket"), $langs->trans("ConfirmAbandonTicket"), "confirm_abandon", '', '', 1);
770			if ($ret == 'html') {
771				print '<br>';
772			}
773		}
774		// Confirmation delete
775		if ($action == 'delete') {
776			print $form->formconfirm($url_page_current."?track_id=".$object->track_id, $langs->trans("Delete"), $langs->trans("ConfirmDeleteTicket"), "confirm_delete_ticket", '', '', 1);
777		}
778		// Confirm reopen
779		if ($action == 'reopen') {
780			print $form->formconfirm($url_page_current.'?track_id='.$object->track_id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenTicket'), 'confirm_reopen', '', '', 1);
781		}
782		// Confirmation status change
783		if ($action == 'set_status') {
784			$new_status = GETPOST('new_status');
785			//var_dump($url_page_current . "?track_id=" . $object->track_id);
786			print $form->formconfirm($url_page_current."?track_id=".$object->track_id."&new_status=".GETPOST('new_status'), $langs->trans("TicketChangeStatus"), $langs->trans("TicketConfirmChangeStatus", $langs->transnoentities($object->statuts_short[$new_status])), "confirm_set_status", '', '', 1);
787		}
788
789		// project info
790		if ($projectid > 0) {
791			$projectstat = new Project($db);
792			if ($projectstat->fetch($projectid) > 0) {
793				$projectstat->fetch_thirdparty();
794
795				// To verify role of users
796				//$userAccess = $object->restrictedProjectArea($user,'read');
797				$userWrite = $projectstat->restrictedProjectArea($user, 'write');
798				//$userDelete = $object->restrictedProjectArea($user,'delete');
799				//print "userAccess=".$userAccess." userWrite=".$userWrite." userDelete=".$userDelete;
800
801				$head = project_prepare_head($projectstat);
802				print dol_get_fiche_head($head, 'ticket', $langs->trans("Project"), 0, ($projectstat->public ? 'projectpub' : 'project'));
803
804				/*
805				 *   Projet synthese pour rappel
806				 */
807				print '<table class="border centpercent">';
808
809				$linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
810
811				// Ref
812				print '<tr><td width="30%">'.$langs->trans('Ref').'</td><td colspan="3">';
813				// Define a complementary filter for search of next/prev ref.
814				if (!$user->rights->projet->all->lire) {
815					$objectsListId = $projectstat->getProjectsAuthorizedForUser($user, $mine, 0);
816					$projectstat->next_prev_filter = " rowid IN (".$db->sanitize(count($objectsListId) ? join(',', array_keys($objectsListId)) : '0').")";
817				}
818				print $form->showrefnav($projectstat, 'ref', $linkback, 1, 'ref', 'ref', '');
819				print '</td></tr>';
820
821				// Label
822				print '<tr><td>'.$langs->trans("Label").'</td><td>'.$projectstat->title.'</td></tr>';
823
824				// Customer
825				print "<tr><td>".$langs->trans("ThirdParty")."</td>";
826				print '<td colspan="3">';
827				if ($projectstat->thirdparty->id > 0) {
828					print $projectstat->thirdparty->getNomUrl(1);
829				} else {
830					print '&nbsp;';
831				}
832
833				print '</td></tr>';
834
835				// Visibility
836				print '<tr><td>'.$langs->trans("Visibility").'</td><td>';
837				if ($projectstat->public) {
838					print $langs->trans('SharedProject');
839				} else {
840					print $langs->trans('PrivateProject');
841				}
842
843				print '</td></tr>';
844
845				// Statut
846				print '<tr><td>'.$langs->trans("Status").'</td><td>'.$projectstat->getLibStatut(4).'</td></tr>';
847
848				print "</table>";
849
850				print '</div>';
851			} else {
852				print "ErrorRecordNotFound";
853			}
854		} elseif ($socid > 0) {
855			$object->fetch_thirdparty();
856			$head = societe_prepare_head($object->thirdparty);
857
858			print dol_get_fiche_head($head, 'ticket', $langs->trans("ThirdParty"), 0, 'company');
859
860			dol_banner_tab($object->thirdparty, 'socid', '', ($user->socid ? 0 : 1), 'rowid', 'nom');
861
862			print dol_get_fiche_end();
863		}
864
865		if (!$user->socid && !empty($conf->global->TICKET_LIMIT_VIEW_ASSIGNED_ONLY)) {
866			$object->next_prev_filter = "te.fk_user_assign = '".$user->id."'";
867		} elseif ($user->socid > 0) {
868			$object->next_prev_filter = "te.fk_soc = '".$user->socid."'";
869		}
870
871		$head = ticket_prepare_head($object);
872
873		print dol_get_fiche_head($head, 'tabTicket', $langs->trans("Ticket"), -1, 'ticket');
874
875		$morehtmlref = '<div class="refidno">';
876		$morehtmlref .= $object->subject;
877		// Author
878		if ($object->fk_user_create > 0) {
879			$morehtmlref .= '<br>'.$langs->trans("CreatedBy").' : ';
880
881			$langs->load("users");
882			$fuser = new User($db);
883			$fuser->fetch($object->fk_user_create);
884			$morehtmlref .= $fuser->getNomUrl(-1);
885		}
886		if (!empty($object->origin_email)) {
887			$morehtmlref .= '<br>'.$langs->trans("CreatedBy").' : ';
888			$morehtmlref .= img_picto('', 'email', 'class="paddingrightonly"');
889			$morehtmlref .= dol_escape_htmltag($object->origin_email).' <small class="hideonsmartphone opacitymedium">('.$langs->trans("TicketEmailOriginIssuer").')</small>';
890		}
891
892		// Thirdparty
893		if (!empty($conf->societe->enabled)) {
894			$morehtmlref .= '<br>'.$langs->trans('ThirdParty').' ';
895			if ($action != 'editcustomer' && $object->fk_statut < 8 && !$user->socid && $user->rights->ticket->write) {
896				$morehtmlref .= '<a class="editfielda" href="'.$url_page_current.'?action=editcustomer&track_id='.$object->track_id.'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 0).'</a> : ';
897			}
898			if ($action == 'editcustomer') {
899				$morehtmlref .= $form->form_thirdparty($url_page_current.'?track_id='.$object->track_id, $object->socid, 'editcustomer', '', 1, 0, 0, array(), 1);
900			} else {
901				$morehtmlref .= $form->form_thirdparty($url_page_current.'?track_id='.$object->track_id, $object->socid, 'none', '', 1, 0, 0, array(), 1);
902			}
903		}
904
905		// Project
906		if (!empty($conf->projet->enabled)) {
907			$langs->load("projects");
908			$morehtmlref .= '<br>'.$langs->trans('Project').' ';
909			if ($user->rights->ticket->write) {
910				if ($action != 'classify') {
911					$morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&amp;id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a>';
912				}
913				$morehtmlref .= ' : ';
914				if ($action == 'classify') {
915					//$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
916					$morehtmlref .= '<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
917					$morehtmlref .= '<input type="hidden" name="action" value="classin">';
918					$morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
919					$morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500');
920					$morehtmlref .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
921					$morehtmlref .= '</form>';
922				} else {
923					$morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
924				}
925			} else {
926				if (!empty($object->fk_project)) {
927					$proj = new Project($db);
928					$proj->fetch($object->fk_project);
929					$morehtmlref .= $proj->getNomUrl(1);
930				} else {
931					$morehtmlref .= '';
932				}
933			}
934		}
935
936		$morehtmlref .= '</div>';
937
938		$linkback = '<a href="'.DOL_URL_ROOT.'/ticket/list.php?restore_lastsearch_values=1"><strong>'.$langs->trans("BackToList").'</strong></a> ';
939
940		dol_banner_tab($object, 'ref', $linkback, ($user->socid ? 0 : 1), 'ref', 'ref', $morehtmlref);
941
942		print '<div class="fichecenter">';
943		print '<div class="fichehalfleft">';
944		print '<div class="underbanner clearboth"></div>';
945
946		print '<table class="border tableforfield centpercent">';
947
948		// Track ID
949		print '<tr><td class="titlefield">'.$langs->trans("TicketTrackId").'</td><td>';
950		if (!empty($object->track_id)) {
951			if (empty($object->ref)) {
952				$object->ref = $object->id;
953				print $form->showrefnav($object, 'id', $linkback, 1, 'rowid', 'track_id');
954			} else {
955				print $object->track_id;
956			}
957		} else {
958			print $langs->trans('None');
959		}
960		print '</td></tr>';
961
962		// Subject
963		print '<tr><td>';
964		print $form->editfieldkey("Subject", 'subject', $object->subject, $object, $user->rights->ticket->write && !$user->socid, 'string');
965		print '</td><td>';
966		print $form->editfieldval("Subject", 'subject', $object->subject, $object, $user->rights->ticket->write && !$user->socid, 'string');
967		print '</td></tr>';
968
969		// Creation date
970		print '<tr><td>'.$langs->trans("DateCreation").'</td><td>';
971		print dol_print_date($object->datec, 'dayhour', 'tzuser');
972		print '<span class="opacitymedium"> - '.$langs->trans("TimeElapsedSince").': <i>'.convertSecondToTime(roundUpToNextMultiple($now - $object->datec, 60)).'</i></span>';
973		print '</td></tr>';
974
975		// Read date
976		print '<tr><td>'.$langs->trans("TicketReadOn").'</td><td>';
977		if (!empty($object->date_read)) {
978			print dol_print_date($object->date_read, 'dayhour', 'tzuser');
979			print '<span class="opacitymedium"> - '.$langs->trans("TicketTimeElapsedBeforeSince").': <i>'.convertSecondToTime(roundUpToNextMultiple($object->date_read - $object->datec, 60)).'</i>';
980			print ' / <i>'.convertSecondToTime(roundUpToNextMultiple($now - $object->date_read, 60)).'</i></span>';
981		}
982		print '</td></tr>';
983
984		// Close date
985		print '<tr><td>'.$langs->trans("TicketCloseOn").'</td><td>';
986		if (!empty($object->date_close)) {
987			print dol_print_date($object->date_close, 'dayhour', 'tzuser');
988		}
989		print '</td></tr>';
990
991		// User assigned
992		print '<tr><td>';
993		print '<table class="nobordernopadding" width="100%"><tr><td class="nowrap">';
994		print $langs->trans("AssignedTo");
995		if ($object->fk_statut < $object::STATUS_CLOSED && GETPOST('set', 'alpha') != "assign_ticket" && $user->rights->ticket->manage) {
996			print '<td class="right"><a class="editfielda" href="'.$url_page_current.'?track_id='.$object->track_id.'&action=view&set=assign_ticket">'.img_edit($langs->trans('Modify'), '').'</a></td>';
997		}
998		print '</tr></table>';
999		print '</td><td>';
1000		if ($object->fk_user_assign > 0) {
1001			$userstat->fetch($object->fk_user_assign);
1002			print $userstat->getNomUrl(-1);
1003		}
1004
1005		// Show user list to assignate one if status is "read"
1006		if (GETPOST('set', 'alpha') == "assign_ticket" && $object->fk_statut < 8 && !$user->socid && $user->rights->ticket->write) {
1007			print '<form method="post" name="ticket" enctype="multipart/form-data" action="'.$url_page_current.'">';
1008			print '<input type="hidden" name="token" value="'.newToken().'">';
1009			print '<input type="hidden" name="action" value="assign_user">';
1010			print '<input type="hidden" name="track_id" value="'.$object->track_id.'">';
1011			print '<label for="fk_user_assign">'.$langs->trans("AssignUser").'</label> ';
1012			print $form->select_dolusers($user->id, 'fk_user_assign', 1);
1013			print ' <input class="button" type="submit" name="btn_assign_user" value="'.$langs->trans("Validate").'" />';
1014			print '</form>';
1015		}
1016		print '</td></tr>';
1017
1018		// Progression
1019		print '<tr><td>';
1020		print '<table class="nobordernopadding" width="100%"><tr><td class="nowrap">';
1021		print $langs->trans('Progression').'</td><td class="left">';
1022		print '</td>';
1023		if ($action != 'progression' && $object->fk_statut < $object::STATUS_CLOSED && !$user->socid) {
1024			print '<td class="right"><a class="editfielda" href="'.$url_page_current.'?action=progression&amp;track_id='.$object->track_id.'">'.img_edit($langs->trans('Modify')).'</a></td>';
1025		}
1026		print '</tr></table>';
1027		print '</td><td colspan="5">';
1028		if ($user->rights->ticket->write && $action == 'progression') {
1029			print '<form action="'.$url_page_current.'" method="post">';
1030			print '<input type="hidden" name="token" value="'.newToken().'">';
1031			print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1032			print '<input type="hidden" name="action" value="set_progression">';
1033			print '<input type="text" class="flat" size="20" name="progress" value="'.$object->progress.'">';
1034			print ' <input type="submit" class="button" value="'.$langs->trans('Modify').'">';
1035			print '</form>';
1036		} else {
1037			print($object->progress > 0 ? $object->progress : '0').'%';
1038		}
1039		print '</td>';
1040		print '</tr>';
1041
1042		// Timing (Duration sum of linked fichinter)
1043		if ($conf->ficheinter->enabled) {
1044			$object->fetchObjectLinked();
1045			$num = count($object->linkedObjects);
1046			$timing = 0;
1047			if ($num) {
1048				foreach ($object->linkedObjects as $objecttype => $objects) {
1049					if ($objecttype = "fichinter") {
1050						foreach ($objects as $fichinter) {
1051							$timing += $fichinter->duration;
1052						}
1053					}
1054				}
1055			}
1056			print '<tr><td valign="top">';
1057
1058			print $form->textwithpicto($langs->trans("TicketDurationAuto"), $langs->trans("TicketDurationAutoInfos"), 1);
1059			print '</td><td>';
1060			print convertSecondToTime($timing, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
1061			print '</td></tr>';
1062		}
1063
1064		// Other attributes
1065		include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
1066
1067		print '</table>';
1068
1069
1070		// Fin colonne gauche et début colonne droite
1071		print '</div><div class="fichehalfright"><div class="ficheaddleft">';
1072
1073
1074		// View Original message
1075		$actionobject->viewTicketOriginalMessage($user, $action, $object);
1076
1077		// Classification of ticket
1078		print '<form method="post" name="formticketproperties" action="'.$url_page_current.'">';
1079		print '<input type="hidden" name="token" value="'.newToken().'">';
1080		print '<input type="hidden" name="action" value="change_property">';
1081		print '<input type="hidden" name="track_id" value="'.$track_id.'">';
1082
1083		print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
1084		print '<table class="noborder tableforfield centpercent margintable">';
1085		print '<tr class="liste_titre">';
1086		print '<td>';
1087		print $langs->trans('Properties');
1088		print '</td>';
1089		print '<td>';
1090		if (GETPOST('set', 'alpha') == 'properties' && $user->rights->ticket->write) {
1091			print '<input class="button" type="submit" name="btn_update_ticket_prop" value="'.$langs->trans("Modify").'" />';
1092		} else {
1093			//    Button to edit Properties
1094			if ($object->fk_statut < $object::STATUS_NEED_MORE_INFO && $user->rights->ticket->write) {
1095				print '<a class="editfielda" href="card.php?track_id='.$object->track_id.'&action=view&set=properties">'.img_edit($langs->trans('Modify')).'</a>';
1096			}
1097		}
1098		print '</td>';
1099		print '</tr>';
1100
1101		if (GETPOST('set', 'alpha') == 'properties' && $user->rights->ticket->write) {
1102			print '<tr>';
1103			// Type
1104			print '<td class="titlefield">';
1105			print $langs->trans('TicketChangeType');
1106			print '</td><td>';
1107			$formticket->selectTypesTickets($object->type_code, 'update_value_type', '', 2);
1108			print '</td>';
1109			print '</tr>';
1110			// Group
1111			print '<tr>';
1112			print '<td>';
1113			print $langs->trans('TicketChangeCategory');
1114			print '</td><td>';
1115			$formticket->selectGroupTickets($object->category_code, 'update_value_category', '', 2);
1116			print '</td>';
1117			print '</tr>';
1118			// Severity
1119			print '<tr>';
1120			print '<td>';
1121			print $langs->trans('TicketChangeSeverity');
1122			print '</td><td>';
1123			$formticket->selectSeveritiesTickets($object->severity_code, 'update_value_severity', '', 2);
1124			print '</td>';
1125			print '</tr>';
1126		} else {
1127			// Type
1128			print '<tr><td class="titlefield">'.$langs->trans("Type").'</td><td>';
1129			if (!empty($object->type_code)) {
1130				print $langs->getLabelFromKey($db, 'TicketTypeShort'.$object->type_code, 'c_ticket_type', 'code', 'label', $object->type_code);
1131			}
1132			print '</td></tr>';
1133			// Group
1134			print '<tr><td>'.$langs->trans("TicketCategory").'</td><td>';
1135			if (!empty($object->category_code)) {
1136				print $langs->getLabelFromKey($db, 'TicketCategoryShort'.$object->category_code, 'c_ticket_category', 'code', 'label', $object->category_code);
1137			}
1138			print '</td></tr>';
1139			// Severity
1140			print '<tr><td>'.$langs->trans("TicketSeverity").'</td><td>';
1141			if (!empty($object->severity_code)) {
1142				print $langs->getLabelFromKey($db, 'TicketSeverityShort'.$object->severity_code, 'c_ticket_severity', 'code', 'label', $object->severity_code);
1143			}
1144			print '</td></tr>';
1145		}
1146		print '</table>'; // End table actions
1147		print '</div>';
1148
1149		print '</form>';
1150
1151		// Display navbar with links to change ticket status
1152		print '<!-- navbar with status -->';
1153		if (!$user->socid && $user->rights->ticket->write && $object->fk_statut < $object::STATUS_CLOSED && GETPOST('set') !== 'properties') {
1154			$actionobject->viewStatusActions($object);
1155		}
1156
1157
1158		if (!empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) {
1159			print load_fiche_titre($langs->trans('Contacts'), '', 'title_companies.png');
1160
1161			print '<div class="div-table-responsive-no-min">';
1162			print '<div class="tagtable centpercent noborder allwidth">';
1163
1164			print '<div class="tagtr liste_titre">';
1165			print '<div class="tagtd">'.$langs->trans("Source").'</div>
1166			<div class="tagtd">' . $langs->trans("Company").'</div>
1167			<div class="tagtd">' . $langs->trans("Contacts").'</div>
1168			<div class="tagtd">' . $langs->trans("ContactType").'</div>
1169			<div class="tagtd">' . $langs->trans("Phone").'</div>
1170			<div class="tagtd center">' . $langs->trans("Status").'</div>';
1171			print '</div><!-- tagtr -->';
1172
1173			// Contact list
1174			$companystatic = new Societe($db);
1175			$contactstatic = new Contact($db);
1176			$userstatic = new User($db);
1177			foreach (array('internal', 'external') as $source) {
1178				$tmpobject = $object;
1179				$tab = $tmpobject->listeContact(-1, $source);
1180				$num = count($tab);
1181				$i = 0;
1182				while ($i < $num) {
1183					$var = !$var;
1184					print '<div class="tagtr '.($var ? 'pair' : 'impair').'">';
1185
1186					print '<div class="tagtd left">';
1187					if ($tab[$i]['source'] == 'internal') {
1188						echo $langs->trans("User");
1189					}
1190
1191					if ($tab[$i]['source'] == 'external') {
1192						echo $langs->trans("ThirdPartyContact");
1193					}
1194
1195					print '</div>';
1196					print '<div class="tagtd left">';
1197
1198					if ($tab[$i]['socid'] > 0) {
1199						$companystatic->fetch($tab[$i]['socid']);
1200						echo $companystatic->getNomUrl(-1);
1201					}
1202					if ($tab[$i]['socid'] < 0) {
1203						echo $conf->global->MAIN_INFO_SOCIETE_NOM;
1204					}
1205					if (!$tab[$i]['socid']) {
1206						echo '&nbsp;';
1207					}
1208					print '</div>';
1209
1210					print '<div class="tagtd">';
1211					if ($tab[$i]['source'] == 'internal') {
1212						if ($userstatic->fetch($tab[$i]['id'])) {
1213							print $userstatic->getNomUrl(-1);
1214						}
1215					}
1216					if ($tab[$i]['source'] == 'external') {
1217						if ($contactstatic->fetch($tab[$i]['id'])) {
1218							print $contactstatic->getNomUrl(-1);
1219						}
1220					}
1221					print ' </div>
1222					<div class="tagtd">' . $tab[$i]['libelle'].'</div>';
1223
1224					print '<div class="tagtd">';
1225
1226					print dol_print_phone($tab[$i]['phone'], '', '', '', 'AC_TEL').'<br>';
1227
1228					if (!empty($tab[$i]['phone_perso'])) {
1229						//print img_picto($langs->trans('PhonePerso'),'object_phoning.png','',0,0,0).' ';
1230						print '<br>'.dol_print_phone($tab[$i]['phone_perso'], '', '', '', 'AC_TEL').'<br>';
1231					}
1232					if (!empty($tab[$i]['phone_mobile'])) {
1233						//print img_picto($langs->trans('PhoneMobile'),'object_phoning.png','',0,0,0).' ';
1234						print dol_print_phone($tab[$i]['phone_mobile'], '', '', '', 'AC_TEL').'<br>';
1235					}
1236					print '</div>';
1237
1238					print '<div class="tagtd center">';
1239					if ($object->statut >= 0) {
1240						echo '<a href="contact.php?track_id='.$object->track_id.'&amp;action=swapstatut&amp;ligne='.$tab[$i]['rowid'].'">';
1241					}
1242
1243					if ($tab[$i]['source'] == 'internal') {
1244						$userstatic->id = $tab[$i]['id'];
1245						$userstatic->lastname = $tab[$i]['lastname'];
1246						$userstatic->firstname = $tab[$i]['firstname'];
1247						echo $userstatic->LibStatut($tab[$i]['statuscontact'], 3);
1248					}
1249					if ($tab[$i]['source'] == 'external') {
1250						$contactstatic->id = $tab[$i]['id'];
1251						$contactstatic->lastname = $tab[$i]['lastname'];
1252						$contactstatic->firstname = $tab[$i]['firstname'];
1253						echo $contactstatic->LibStatut($tab[$i]['statuscontact'], 3);
1254					}
1255					if ($object->statut >= 0) {
1256						echo '</a>';
1257					}
1258
1259					print '</div>';
1260
1261					print '</div><!-- tagtr -->';
1262
1263					$i++;
1264				}
1265			}
1266
1267			print '</div><!-- contact list -->';
1268			print '</div>';
1269		}
1270
1271		print '</div></div></div>';
1272		print '<div style="clear:both"></div>';
1273
1274		print dol_get_fiche_end();
1275
1276
1277		// Buttons for actions
1278		if ($action != 'presend' && $action != 'presend_addmessage' && $action != 'editline') {
1279			print '<div class="tabsAction">'."\n";
1280			$parameters = array();
1281			$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1282			if ($reshook < 0) {
1283				setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1284			}
1285
1286			if (empty($reshook)) {
1287				// Show link to add a message (if read and not closed)
1288				if ($object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage") {
1289					print '<div class="inline-block divButAction"><a class="butAction reposition" href="card.php?track_id='.$object->track_id.'&action=presend_addmessage&mode=init">'.$langs->trans('TicketAddMessage').'</a></div>';
1290				}
1291
1292				// Link to create an intervention
1293				// socid is needed otherwise fichinter ask it and forgot origin after form submit :\
1294				if (!$object->fk_soc && $user->rights->ficheinter->creer) {
1295					print '<div class="inline-block divButAction"><a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans('UnableToCreateInterIfNoSocid').'">'.$langs->trans('TicketAddIntervention').'</a></div>';
1296				}
1297				if ($object->fk_soc > 0 && $object->fk_statut < Ticket::STATUS_CLOSED && $user->rights->ficheinter->creer) {
1298					print '<div class="inline-block divButAction"><a class="butAction" href="'.dol_buildpath('/fichinter/card.php', 1).'?action=create&socid='.$object->fk_soc.'&origin=ticket_ticket&originid='.$object->id.'">'.$langs->trans('TicketAddIntervention').'</a></div>';
1299				}
1300
1301				/* This is useless. We can already modify each field individually
1302				if ($user->rights->ticket->write && $object->fk_statut < Ticket::STATUS_CLOSED) {
1303					print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?track_id='.$object->track_id.'&action=edit">'.$langs->trans('Modify').'</a></div>';
1304				}
1305				*/
1306
1307				// Close ticket if statut is read
1308				if ($object->fk_statut > 0 && $object->fk_statut < Ticket::STATUS_CLOSED && $user->rights->ticket->write) {
1309					print '<div class="inline-block divButAction"><a class="butAction" href="card.php?track_id='.$object->track_id.'&action=close">'.$langs->trans('CloseTicket').'</a></div>';
1310				}
1311
1312				// Abadon ticket if statut is read
1313				if ($object->fk_statut > 0 && $object->fk_statut < Ticket::STATUS_CLOSED && $user->rights->ticket->write) {
1314					print '<div class="inline-block divButAction"><a class="butAction" href="card.php?track_id='.$object->track_id.'&action=abandon">'.$langs->trans('AbandonTicket').'</a></div>';
1315				}
1316
1317				// Re-open ticket
1318				if (!$user->socid && ($object->fk_statut == Ticket::STATUS_CLOSED || $object->fk_statut == Ticket::STATUS_CANCELED) && !$user->socid) {
1319					print '<div class="inline-block divButAction"><a class="butAction" href="card.php?track_id='.$object->track_id.'&action=reopen">'.$langs->trans('ReOpen').'</a></div>';
1320				}
1321
1322				// Delete ticket
1323				if ($user->rights->ticket->delete && !$user->socid) {
1324					print '<div class="inline-block divButAction"><a class="butActionDelete" href="card.php?track_id='.$object->track_id.'&action=delete&token='.newToken().'">'.$langs->trans('Delete').'</a></div>';
1325				}
1326			}
1327			print '</div>'."\n";
1328		} else {
1329			//print '<br>';
1330		}
1331
1332		// Select mail models is same action as presend
1333		if (GETPOST('modelselected')) {
1334			$action = 'presend';
1335		}
1336		// Set $action to correct value for the case we used presend action to add a message
1337		if (GETPOSTISSET('actionbis') && $action == 'presend') {
1338			$action = 'presend_addmessage';
1339		}
1340
1341		// add a message
1342		if ($action == 'presend' || $action == 'presend_addmessage') {
1343			if ($object->fk_soc > 0) {
1344				$object->fetch_thirdparty();
1345			}
1346
1347			$outputlangs = $langs;
1348			$newlang = '';
1349			if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1350				$newlang = GETPOST('lang_id', 'aZ09');
1351			} elseif ($conf->global->MAIN_MULTILANGS && empty($newlang) && is_object($object->thirdparty)) {
1352				$newlang = $object->thirdparty->default_lang;
1353			}
1354			if (!empty($newlang)) {
1355				$outputlangs = new Translate("", $conf);
1356				$outputlangs->setDefaultLang($newlang);
1357			}
1358
1359			$arrayoffamiliestoexclude = array('objectamount');
1360
1361			$action = 'add_message'; // action to use to post the message
1362			$modelmail = 'ticket_send';
1363
1364			// Substitution array
1365			$morehtmlright = '';
1366			$help = "";
1367			$substitutionarray = getCommonSubstitutionArray($outputlangs, 0, $arrayoffamiliestoexclude, $object);
1368			if ($object->fk_soc > 0) {
1369				$substitutionarray['__THIRDPARTY_NAME__'] = $object->thirdparty->name;
1370			}
1371			$substitutionarray['__USER_SIGNATURE__'] = $user->signature;
1372			$substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
1373			$substitutionarray['__TICKET_REF__'] = $object->ref;
1374			$substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
1375			$substitutionarray['__TICKET_TYPE__'] = $object->type_code;
1376			$substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
1377			$substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
1378			$substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
1379			$substitutionarray['__TICKET_MESSAGE__'] = $object->message;
1380			$substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
1381			if ($object->fk_user_assign > 0) {
1382				$userstat->fetch($object->fk_user_assign);
1383				$substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
1384			}
1385
1386			if ($object->fk_user_create > 0) {
1387				$userstat->fetch($object->fk_user_create);
1388				$substitutionarray['__TICKET_USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
1389			}
1390			foreach ($substitutionarray as $key => $val) {
1391				$help .= $key.' -> '.$langs->trans($val).'<br>';
1392			}
1393			$morehtmlright .= $form->textwithpicto('<span class="opacitymedium">'.$langs->trans("TicketMessageSubstitutionReplacedByGenericValues").'</span>', $help, 1, 'helpclickable', '', 0, 3, 'helpsubstitution');
1394
1395			print '<div>';
1396
1397			print load_fiche_titre($langs->trans('TicketAddMessage'), $morehtmlright, 'messages@ticket');
1398
1399			print '<hr>';
1400
1401			$formticket = new FormTicket($db);
1402
1403			$formticket->action = $action;
1404			$formticket->track_id = $object->track_id;
1405			$formticket->ref = $object->ref;
1406			$formticket->id = $object->id;
1407
1408			$formticket->withfile = 2;
1409			$formticket->withcancel = 1;
1410			$formticket->param = array('fk_user_create' => $user->id);
1411			$formticket->param['langsmodels'] = (empty($newlang) ? $langs->defaultlang : $newlang);
1412
1413			// Tableau des parametres complementaires du post
1414			$formticket->param['models'] = $modelmail;
1415			$formticket->param['models_id'] = GETPOST('modelmailselected', 'int');
1416			//$formticket->param['socid']=$object->fk_soc;
1417			$formticket->param['returnurl'] = $_SERVER["PHP_SELF"].'?track_id='.$object->track_id;
1418
1419			$formticket->withsubstit = 1;
1420			$formticket->substit = $substitutionarray;
1421			$formticket->showMessageForm('100%');
1422			print '</div>';
1423		}
1424
1425		// Show messages on card (Note: this is a duplicate of the view Events/Agenda but on the main tab)
1426		if (!empty($conf->global->TICKET_SHOW_MESSAGES_ON_CARD)) {
1427			$param = '&id='.$object->id;
1428			if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1429				$param .= '&contextpage='.$contextpage;
1430			}
1431			if ($limit > 0 && $limit != $conf->liste_limit) {
1432				$param .= '&limit='.$limit;
1433			}
1434			if ($actioncode) {
1435				$param .= '&actioncode='.urlencode($actioncode);
1436			}
1437			if ($search_agenda_label) {
1438				$param .= '&search_agenda_label='.urlencode($search_agenda_label);
1439			}
1440
1441			$morehtmlright = '';
1442
1443			$messagingUrl = DOL_URL_ROOT.'/ticket/agenda.php?track_id='.$object->track_id;
1444			$morehtmlright .= dolGetButtonTitle($langs->trans('MessageListViewType'), '', 'fal fa-list-alt imgforviewmode', $messagingUrl, '', 1);
1445
1446			// Show link to add a message (if read and not closed)
1447			$btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage" && $action != "add_message";
1448			$url = 'card.php?track_id='.$object->track_id.'&action=presend_addmessage&mode=init';
1449			$morehtmlright .= dolGetButtonTitle($langs->trans('TicketAddMessage'), '', 'fal fa-comment-dots', $url, 'add-new-ticket-title-button', $btnstatus);
1450
1451			// Show link to add event (if read and not closed)
1452			$btnstatus = $object->fk_statut < Ticket::STATUS_CLOSED && $action != "presend" && $action != "presend_addmessage" && $action != "add_message"; ;
1453			$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);
1454			$morehtmlright .= dolGetButtonTitle($langs->trans('AddAction'), '', 'fal fa-plus-circle', $url, 'add-new-ticket-even-button', $btnstatus);
1455
1456			print_barre_liste($langs->trans("ActionsOnTicket"), 0, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', 0, -1, '', 0, $morehtmlright, '', 0, 1, 1);
1457
1458			// List of all actions
1459			$filters = array();
1460			$filters['search_agenda_label'] = $search_agenda_label;
1461			show_ticket_messaging($conf, $langs, $db, $object, null, 0, $actioncode, '', $filters, $sortfield, $sortorder);
1462		}
1463
1464		if ($action != 'presend' && $action != 'presend_addmessage' && $action != 'add_message') {
1465			print '<div class="fichecenter"><div class="fichehalfleft">';
1466			print '<a name="builddoc"></a>'; // ancre
1467
1468			// Show links to link elements
1469			$linktoelem = $form->showLinkToObjectBlock($object, null, array('ticket'));
1470			$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
1471
1472			// Show direct link to public interface
1473			print '<br><!-- Link to public interface -->'."\n";
1474			print showDirectPublicLink($object).'<br>';
1475			print '</div>';
1476
1477			if (empty($conf->global->TICKET_SHOW_MESSAGES_ON_CARD)) {
1478				print '<div class="fichehalfright"><div class="ficheaddleft">';
1479
1480				$MAXEVENT = 10;
1481
1482				$morehtmlcenter = '<div class="nowraponall">';
1483				$morehtmlcenter .= dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT.'/ticket/messaging.php?id='.$object->id);
1484				$morehtmlcenter .= ' ';
1485				$morehtmlcenter .= dolGetButtonTitle($langs->trans('FullList'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT.'/ticket/agenda.php?id='.$object->id);
1486				$morehtmlcenter .= '</div>';
1487
1488				// List of actions on element
1489				include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
1490				$formactions = new FormActions($db);
1491				$somethingshown = $formactions->showactions($object, 'ticket', $socid, 1, 'listactions', $MAXEVENT, '', $morehtmlcenter);
1492
1493				print '</div></div>';
1494			}
1495
1496			print '</div>';
1497		}
1498	}
1499}
1500
1501// End of page
1502llxFooter();
1503$db->close();
1504