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