card.php 66 KB

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