card.php 63 KB

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