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