html.formticket.class.php 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  1. <?php
  2. /* Copyright (C) 2013-2015 Jean-François FERRY <hello@librethic.io>
  3. * Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr>
  4. * Copyright (C) 2019-2022 Frédéric France <frederic.france@netlogic.fr>
  5. * Copyright (C) 2021 Juanjo Menent <jmenent@2byte.es>
  6. * Copyright (C) 2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
  7. * Copyright (C) 2023 Charlene Benke <charlene.r@patas-monkey.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * \file htdocs/core/class/html.formticket.class.php
  24. * \ingroup ticket
  25. * \brief File of class to generate the form for creating a new ticket.
  26. */
  27. require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
  28. require_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
  29. require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
  30. if (!class_exists('FormCompany')) {
  31. include DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
  32. }
  33. /**
  34. * Class to generate the form for creating a new ticket.
  35. * Usage: $formticket = new FormTicket($db)
  36. * $formticket->proprietes = 1 or string or array of values
  37. * $formticket->show_form() shows the form
  38. *
  39. * @package Ticket
  40. */
  41. class FormTicket
  42. {
  43. /**
  44. * @var DoliDB Database handler.
  45. */
  46. public $db;
  47. /**
  48. * @var string A hash value of the ticket. Duplicate of ref but for public purposes.
  49. */
  50. public $track_id;
  51. /**
  52. * @var string Email $trackid. Used also for the $keytoavoidconflict to name session vars to upload files.
  53. */
  54. public $trackid;
  55. /**
  56. * @var int ID
  57. */
  58. public $fk_user_create;
  59. public $message;
  60. public $topic_title;
  61. public $action;
  62. public $withtopic;
  63. public $withemail;
  64. /**
  65. * @var int $withsubstit Show substitution array
  66. */
  67. public $withsubstit;
  68. public $withfile;
  69. public $withfilereadonly;
  70. public $backtopage;
  71. public $ispublic; // to show information or not into public form
  72. public $withtitletopic;
  73. public $withtopicreadonly;
  74. public $withreadid;
  75. public $withcompany; // to show company drop-down list
  76. public $withfromsocid;
  77. public $withfromcontactid;
  78. public $withnotifytiersatcreate;
  79. public $withusercreate; // to show name of creating user in form
  80. public $withcreatereadonly;
  81. /**
  82. * @var int withextrafields
  83. */
  84. public $withextrafields;
  85. public $withref; // to show ref field
  86. public $withcancel;
  87. public $type_code;
  88. public $category_code;
  89. public $severity_code;
  90. /**
  91. *
  92. * @var array $substit Substitutions
  93. */
  94. public $substit = array();
  95. public $param = array();
  96. /**
  97. * @var string Error code (or message)
  98. */
  99. public $error;
  100. public $errors = array();
  101. /**
  102. * Constructor
  103. *
  104. * @param DoliDB $db Database handler
  105. */
  106. public function __construct($db)
  107. {
  108. global $conf;
  109. $this->db = $db;
  110. $this->action = 'add';
  111. $this->withcompany = isModEnabled("societe");
  112. $this->withfromsocid = 0;
  113. $this->withfromcontactid = 0;
  114. $this->withreadid=0;
  115. //$this->withtitletopic='';
  116. $this->withnotifytiersatcreate = 0;
  117. $this->withusercreate = 1;
  118. $this->withcreatereadonly = 1;
  119. $this->withemail = 0;
  120. $this->withref = 0;
  121. $this->withextrafields = 0; // to show extrafields or not
  122. //$this->withtopicreadonly=0;
  123. }
  124. /**
  125. * Show the form to input ticket
  126. *
  127. * @param int $withdolfichehead With dol_get_fiche_head() and dol_get_fiche_end()
  128. * @param string $mode Mode ('create' or 'edit')
  129. * @param int $public 1=If we show the form for the public interface
  130. * @param Contact|null $with_contact [=NULL] Contact to link to this ticket if it exists
  131. * @param string $action [=''] Action in card
  132. * @return void
  133. */
  134. public function showForm($withdolfichehead = 0, $mode = 'edit', $public = 0, Contact $with_contact = null, $action = '')
  135. {
  136. global $conf, $langs, $user, $hookmanager;
  137. // Load translation files required by the page
  138. $langs->loadLangs(array('other', 'mails', 'ticket'));
  139. $form = new Form($this->db);
  140. $formcompany = new FormCompany($this->db);
  141. $ticketstatic = new Ticket($this->db);
  142. $soc = new Societe($this->db);
  143. if (!empty($this->withfromsocid) && $this->withfromsocid > 0) {
  144. $soc->fetch($this->withfromsocid);
  145. }
  146. $ticketstat = new Ticket($this->db);
  147. $extrafields = new ExtraFields($this->db);
  148. $extrafields->fetch_name_optionals_label($ticketstat->table_element);
  149. print "\n<!-- Begin form TICKET -->\n";
  150. if ($withdolfichehead) {
  151. print dol_get_fiche_head(null, 'card', '', 0, '');
  152. }
  153. print '<form method="POST" '.($withdolfichehead ? '' : 'style="margin-bottom: 30px;" ').'name="ticket" id="form_create_ticket" enctype="multipart/form-data" action="'.(!empty($this->param["returnurl"]) ? $this->param["returnurl"] : $_SERVER['PHP_SELF']).'">';
  154. print '<input type="hidden" name="token" value="'.newToken().'">';
  155. print '<input type="hidden" name="action" value="'.$this->action.'">';
  156. print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
  157. foreach ($this->param as $key => $value) {
  158. print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
  159. }
  160. print '<input type="hidden" name="fk_user_create" value="'.$this->fk_user_create.'">';
  161. print '<table class="border centpercent">';
  162. if ($this->withref) {
  163. // Ref
  164. $defaultref = $ticketstat->getDefaultRef();
  165. print '<tr><td class="titlefieldcreate"><span class="fieldrequired">'.$langs->trans("Ref").'</span></td><td>';
  166. print '<input type="text" name="ref" value="'.dol_escape_htmltag(GETPOST("ref", 'alpha') ? GETPOST("ref", 'alpha') : $defaultref).'">';
  167. print '</td></tr>';
  168. }
  169. // TITLE
  170. $email = GETPOSTISSET('email') ? GETPOST('email', 'alphanohtml') : '';
  171. if ($this->withemail) {
  172. print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">'.$langs->trans("Email").'</span></label></td><td>';
  173. print '<input class="text minwidth200" id="email" name="email" value="'.$email.'" autofocus>';
  174. print '</td></tr>';
  175. if ($with_contact) {
  176. // contact search and result
  177. $html_contact_search = '';
  178. $html_contact_search .= '<tr id="contact_search_line">';
  179. $html_contact_search .= '<td class="titlefield">';
  180. $html_contact_search .= '<label for="contact"><span class="fieldrequired">' . $langs->trans('Contact') . '</span></label>';
  181. $html_contact_search .= '<input type="hidden" id="contact_id" name="contact_id" value="" />';
  182. $html_contact_search .= '</td>';
  183. $html_contact_search .= '<td id="contact_search_result"></td>';
  184. $html_contact_search .= '</tr>';
  185. print $html_contact_search;
  186. // contact lastname
  187. $html_contact_lastname = '';
  188. $html_contact_lastname .= '<tr id="contact_lastname_line" class="contact_field"><td class="titlefield"><label for="contact_lastname"><span class="fieldrequired">' . $langs->trans('Lastname') . '</span></label></td><td>';
  189. $html_contact_lastname .= '<input type="text" id="contact_lastname" name="contact_lastname" value="' . dol_escape_htmltag(GETPOSTISSET('contact_lastname') ? GETPOST('contact_lastname', 'alphanohtml') : '') . '" />';
  190. $html_contact_lastname .= '</td></tr>';
  191. print $html_contact_lastname;
  192. // contact firstname
  193. $html_contact_firstname = '';
  194. $html_contact_firstname .= '<tr id="contact_firstname_line" class="contact_field"><td class="titlefield"><label for="contact_firstname"><span class="fieldrequired">' . $langs->trans('Firstname') . '</span></label></td><td>';
  195. $html_contact_firstname .= '<input type="text" id="contact_firstname" name="contact_firstname" value="' . dol_escape_htmltag(GETPOSTISSET('contact_firstname') ? GETPOST('contact_firstname', 'alphanohtml') : '') . '" />';
  196. $html_contact_firstname .= '</td></tr>';
  197. print $html_contact_firstname;
  198. // company name
  199. $html_company_name = '';
  200. $html_company_name .= '<tr id="contact_company_name_line" class="contact_field"><td><label for="company_name"><span>' . $langs->trans('Company') . '</span></label></td><td>';
  201. $html_company_name .= '<input type="text" id="company_name" name="company_name" value="' . dol_escape_htmltag(GETPOSTISSET('company_name') ? GETPOST('company_name', 'alphanohtml') : '') . '" />';
  202. $html_company_name .= '</td></tr>';
  203. print $html_company_name;
  204. // contact phone
  205. $html_contact_phone = '';
  206. $html_contact_phone .= '<tr id="contact_phone_line" class="contact_field"><td><label for="contact_phone"><span>' . $langs->trans('Phone') . '</span></label></td><td>';
  207. $html_contact_phone .= '<input type="text" id="contact_phone" name="contact_phone" value="' . dol_escape_htmltag(GETPOSTISSET('contact_phone') ? GETPOST('contact_phone', 'alphanohtml') : '') . '" />';
  208. $html_contact_phone .= '</td></tr>';
  209. print $html_contact_phone;
  210. // search contact form email
  211. $langs->load('errors');
  212. print '<script nonce="'.getNonce().'" type="text/javascript">
  213. jQuery(document).ready(function() {
  214. var contact = jQuery.parseJSON("'.dol_escape_js(json_encode($with_contact), 2).'");
  215. jQuery("#contact_search_line").hide();
  216. if (contact) {
  217. if (contact.id > 0) {
  218. jQuery("#contact_search_line").show();
  219. jQuery("#contact_id").val(contact.id);
  220. jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
  221. jQuery(".contact_field").hide();
  222. } else {
  223. jQuery(".contact_field").show();
  224. }
  225. }
  226. jQuery("#email").change(function() {
  227. jQuery("#contact_search_line").show();
  228. jQuery("#contact_search_result").html("'.dol_escape_js($langs->trans('Select2SearchInProgress')).'");
  229. jQuery("#contact_id").val("");
  230. jQuery("#contact_lastname").val("");
  231. jQuery("#contact_firstname").val("");
  232. jQuery("#company_name").val("");
  233. jQuery("#contact_phone").val("");
  234. jQuery.getJSON(
  235. "'.dol_escape_js(dol_buildpath('/public/ticket/ajax/ajax.php', 1)).'",
  236. {
  237. action: "getContacts",
  238. email: jQuery("#email").val()
  239. },
  240. function(response) {
  241. if (response.error) {
  242. jQuery("#contact_search_result").html("<span class=\"error\">"+response.error+"</span>");
  243. } else {
  244. var contact_list = response.contacts;
  245. if (contact_list.length == 1) {
  246. var contact = contact_list[0];
  247. jQuery("#contact_id").val(contact.id);
  248. jQuery("#contact_search_result").html(contact.firstname+" "+contact.lastname);
  249. jQuery(".contact_field").hide();
  250. } else if (contact_list.length <= 0) {
  251. jQuery("#contact_search_line").hide();
  252. jQuery(".contact_field").show();
  253. }
  254. }
  255. }
  256. ).fail(function(jqxhr, textStatus, error) {
  257. var error_msg = "'.dol_escape_js($langs->trans('ErrorAjaxRequestFailed')).'"+" ["+textStatus+"] : "+error;
  258. jQuery("#contact_search_result").html("<span class=\"error\">"+error_msg+"</span>");
  259. });
  260. });
  261. });
  262. </script>';
  263. }
  264. }
  265. // If ticket created from another object
  266. $subelement = '';
  267. if (isset($this->param['origin']) && $this->param['originid'] > 0) {
  268. // Parse element/subelement (ex: project_task)
  269. $element = $subelement = $this->param['origin'];
  270. $regs = array();
  271. if (preg_match('/^([^_]+)_([^_]+)/i', $this->param['origin'], $regs)) {
  272. $element = $regs[1];
  273. $subelement = $regs[2];
  274. }
  275. dol_include_once('/'.$element.'/class/'.$subelement.'.class.php');
  276. $classname = ucfirst($subelement);
  277. $objectsrc = new $classname($this->db);
  278. $objectsrc->fetch(GETPOST('originid', 'int'));
  279. if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
  280. $objectsrc->fetch_lines();
  281. }
  282. $objectsrc->fetch_thirdparty();
  283. $newclassname = $classname;
  284. print '<tr><td>'.$langs->trans($newclassname).'</td><td colspan="2"><input name="'.$subelement.'id" value="'.GETPOST('originid').'" type="hidden" />'.$objectsrc->getNomUrl(1).'</td></tr>';
  285. }
  286. // Type of Ticket
  287. print '<tr><td class="titlefield"><span class="fieldrequired"><label for="selecttype_code">'.$langs->trans("TicketTypeRequest").'</span></label></td><td>';
  288. $this->selectTypesTickets((GETPOST('type_code', 'alpha') ? GETPOST('type_code', 'alpha') : $this->type_code), 'type_code', '', 2, 1, 0, 0, 'minwidth200');
  289. print '</td></tr>';
  290. // Group => Category
  291. print '<tr><td><span class="fieldrequired"><label for="selectcategory_code">'.$langs->trans("TicketCategory").'</span></label></td><td>';
  292. $filter = '';
  293. if ($public) {
  294. $filter = 'public=1';
  295. }
  296. $selected = (GETPOST('category_code') ? GETPOST('category_code') : $this->category_code);
  297. $this->selectGroupTickets($selected, 'category_code', $filter, 2, 1, 0, 0, 'minwidth200');
  298. print '</td></tr>';
  299. // Severity => Priority
  300. print '<tr><td><span class="fieldrequired"><label for="selectseverity_code">'.$langs->trans("TicketSeverity").'</span></label></td><td>';
  301. $this->selectSeveritiesTickets((GETPOST('severity_code') ? GETPOST('severity_code') : $this->severity_code), 'severity_code', '', 2, 1);
  302. print '</td></tr>';
  303. if (!empty($conf->knowledgemanagement->enabled)) {
  304. // KM Articles
  305. print '<tr id="KWwithajax" class="hidden"><td></td></tr>';
  306. print '<!-- Script to manage change of ticket group -->
  307. <script nonce="'.getNonce().'">
  308. jQuery(document).ready(function() {
  309. function groupticketchange() {
  310. console.log("We called groupticketchange, so we try to load list KM linked to event");
  311. $("#KWwithajax").html("");
  312. idgroupticket = $("#selectcategory_code").val();
  313. console.log("We have selected id="+idgroupticket);
  314. if (idgroupticket != "") {
  315. $.ajax({ url: \''.DOL_URL_ROOT.'/core/ajax/fetchKnowledgeRecord.php\',
  316. data: { action: \'getKnowledgeRecord\', idticketgroup: idgroupticket, token: \''.newToken().'\', lang:\''.$langs->defaultlang.'\', public:'.($public).' },
  317. type: \'GET\',
  318. success: function(response) {
  319. var urllist = \'\';
  320. console.log("We received response "+response);
  321. if (typeof response == "object") {
  322. console.log("response is already type object, no need to parse it");
  323. } else {
  324. console.log("response is type "+(typeof response));
  325. response = JSON.parse(response);
  326. }
  327. for (key in response) {
  328. answer = response[key].answer;
  329. urllist += \'<li><a href="#" title="\'+response[key].title+\'" class="button_KMpopup" data-html="\'+answer+\'">\' +response[key].title+\'</a></li>\';
  330. }
  331. if (urllist != "") {
  332. $("#KWwithajax").html(\'<td>'.$langs->trans("KMFoundForTicketGroup").'</td><td><ul>\'+urllist+\'</ul></td>\');
  333. $("#KWwithajax").show();
  334. $(".button_KMpopup").on("click",function(){
  335. console.log("Open popup with jQuery(...).dialog() with KM article")
  336. var $dialog = $("<div></div>").html($(this).attr("data-html"))
  337. .dialog({
  338. autoOpen: false,
  339. modal: true,
  340. height: (window.innerHeight - 150),
  341. width: "80%",
  342. title: $(this).attr("title"),
  343. });
  344. $dialog.dialog("open");
  345. console.log($dialog);
  346. })
  347. }
  348. },
  349. error : function(output) {
  350. console.error("Error on Fetch of KM articles");
  351. },
  352. });
  353. }
  354. };
  355. $("#selectcategory_code").on("change",function() { groupticketchange(); });
  356. if ($("#selectcategory_code").val() != "") {
  357. groupticketchange();
  358. }
  359. });
  360. </script>'."\n";
  361. }
  362. // Subject
  363. if ($this->withtitletopic) {
  364. print '<tr><td><label for="subject"><span class="fieldrequired">'.$langs->trans("Subject").'</span></label></td><td>';
  365. // Answer to a ticket : display of the thread title in readonly
  366. if ($this->withtopicreadonly) {
  367. print $langs->trans('SubjectAnswerToTicket').' '.$this->topic_title;
  368. } else {
  369. if (isset($this->withreadid) && $this->withreadid > 0) {
  370. $subject = $langs->trans('SubjectAnswerToTicket').' '.$this->withreadid.' : '.$this->topic_title;
  371. } else {
  372. $subject = GETPOST('subject', 'alpha');
  373. }
  374. print '<input class="text minwidth500" id="subject" name="subject" value="'.$subject.'"'.(empty($this->withemail) ? ' autofocus' : '').' />';
  375. }
  376. print '</td></tr>';
  377. }
  378. // MESSAGE
  379. $msg = GETPOSTISSET('message') ? GETPOST('message', 'restricthtml') : '';
  380. print '<tr><td><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span></label></td><td>';
  381. // If public form, display more information
  382. $toolbarname = 'dolibarr_notes';
  383. if ($this->ispublic) {
  384. $toolbarname = 'dolibarr_details';
  385. print '<div class="warning hideonsmartphone">'.(getDolGlobalString("TICKET_PUBLIC_TEXT_HELP_MESSAGE", $langs->trans('TicketPublicPleaseBeAccuratelyDescribe'))).'</div>';
  386. }
  387. include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  388. $uselocalbrowser = true;
  389. $doleditor = new DolEditor('message', $msg, '100%', 230, $toolbarname, 'In', true, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_8, '90%');
  390. $doleditor->Create();
  391. print '</td></tr>';
  392. if ($public && getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA_TICKET')) {
  393. require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
  394. print '<tr><td class="titlefield"><label for="email"><span class="fieldrequired">'.$langs->trans("SecurityCode").'</span></label></td><td>';
  395. print '<span class="span-icon-security inline-block">';
  396. print '<input id="securitycode" placeholder="'.$langs->trans("SecurityCode").'" class="flat input-icon-security width125" type="text" maxlength="5" name="code" tabindex="3" />';
  397. print '</span>';
  398. print '<span class="nowrap inline-block">';
  399. print '<img class="inline-block valignmiddle" src="'.DOL_URL_ROOT.'/core/antispamimage.php" border="0" width="80" height="32" id="img_securitycode" />';
  400. print '<a class="inline-block valignmiddle" href="" tabindex="4" data-role="button">'.img_picto($langs->trans("Refresh"), 'refresh', 'id="captcha_refresh_img"').'</a>';
  401. print '</span>';
  402. print '</td></tr>';
  403. }
  404. // Categories
  405. if (isModEnabled('categorie')) {
  406. include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  407. $cate_arbo = $form->select_all_categories(Categorie::TYPE_TICKET, '', 'parent', 64, 0, 1);
  408. if (count($cate_arbo)) {
  409. // Categories
  410. print '<tr><td class="wordbreak">'.$langs->trans("Categories").'</td><td>';
  411. print img_picto('', 'category', 'class="pictofixedwidth"').$form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, 'quatrevingtpercent widthcentpercentminusx', 0, 0);
  412. print "</td></tr>";
  413. }
  414. }
  415. // Attached files
  416. if (!empty($this->withfile)) {
  417. // Define list of attached files
  418. $listofpaths = array();
  419. $listofnames = array();
  420. $listofmimes = array();
  421. if (!empty($_SESSION["listofpaths"])) {
  422. $listofpaths = explode(';', $_SESSION["listofpaths"]);
  423. }
  424. if (!empty($_SESSION["listofnames"])) {
  425. $listofnames = explode(';', $_SESSION["listofnames"]);
  426. }
  427. if (!empty($_SESSION["listofmimes"])) {
  428. $listofmimes = explode(';', $_SESSION["listofmimes"]);
  429. }
  430. $out = '<tr>';
  431. $out .= '<td>'.$langs->trans("MailFile").'</td>';
  432. $out .= '<td>';
  433. // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
  434. $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
  435. $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
  436. $out .= 'jQuery(document).ready(function () {';
  437. $out .= ' jQuery(".removedfile").click(function() {';
  438. $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
  439. $out .= ' });';
  440. $out .= '})';
  441. $out .= '</script>'."\n";
  442. if (count($listofpaths)) {
  443. foreach ($listofpaths as $key => $val) {
  444. $out .= '<div id="attachfile_'.$key.'">';
  445. $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
  446. if (!$this->withfilereadonly) {
  447. $out .= ' <input type="image" style="border: 0px;" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/delete.png" value="'.($key + 1).'" class="removedfile" id="removedfile_'.$key.'" name="removedfile_'.$key.'" />';
  448. }
  449. $out .= '<br></div>';
  450. }
  451. } else {
  452. $out .= $langs->trans("NoAttachedFiles").'<br>';
  453. }
  454. if ($this->withfile == 2) { // Can add other files
  455. $maxfilesizearray = getMaxFileSizeArray();
  456. $maxmin = $maxfilesizearray['maxmin'];
  457. if ($maxmin > 0) {
  458. $out .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
  459. }
  460. $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
  461. $out .= ' ';
  462. $out .= '<input type="submit" class="button smallpaddingimp reposition" id="addfile" name="addfile" value="'.$langs->trans("MailingAddFile").'" />';
  463. }
  464. $out .= "</td></tr>\n";
  465. print $out;
  466. }
  467. // User of creation
  468. if ($this->withusercreate > 0 && $this->fk_user_create) {
  469. print '<tr><td class="titlefield">'.$langs->trans("CreatedBy").'</td><td>';
  470. $langs->load("users");
  471. $fuser = new User($this->db);
  472. if ($this->withcreatereadonly) {
  473. if ($res = $fuser->fetch($this->fk_user_create)) {
  474. print $fuser->getNomUrl(1);
  475. }
  476. }
  477. print ' &nbsp; ';
  478. print "</td></tr>\n";
  479. }
  480. // Customer or supplier
  481. if ($this->withcompany) {
  482. // altairis: force company and contact id for external user
  483. if (empty($user->socid)) {
  484. // Company
  485. print '<tr><td class="titlefield">'.$langs->trans("ThirdParty").'</td><td>';
  486. $events = array();
  487. $events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
  488. print img_picto('', 'company', 'class="paddingright"');
  489. print $form->select_company($this->withfromsocid, 'socid', '', 1, 1, '', $events, 0, 'minwidth200');
  490. print '</td></tr>';
  491. if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
  492. $htmlname = 'socid';
  493. print '<script nonce="'.getNonce().'" type="text/javascript">
  494. $(document).ready(function () {
  495. jQuery("#'.$htmlname.'").change(function () {
  496. var obj = '.json_encode($events).';
  497. $.each(obj, function(key,values) {
  498. if (values.method.length) {
  499. runJsCodeForEvent'.$htmlname.'(values);
  500. }
  501. });
  502. });
  503. function runJsCodeForEvent'.$htmlname.'(obj) {
  504. console.log("Run runJsCodeForEvent'.$htmlname.'");
  505. var id = $("#'.$htmlname.'").val();
  506. var method = obj.method;
  507. var url = obj.url;
  508. var htmlname = obj.htmlname;
  509. var showempty = obj.showempty;
  510. $.getJSON(url,
  511. {
  512. action: method,
  513. id: id,
  514. htmlname: htmlname,
  515. showempty: showempty
  516. },
  517. function(response) {
  518. $.each(obj.params, function(key,action) {
  519. if (key.length) {
  520. var num = response.num;
  521. if (num > 0) {
  522. $("#" + key).removeAttr(action);
  523. } else {
  524. $("#" + key).attr(action, action);
  525. }
  526. }
  527. });
  528. $("select#" + htmlname).html(response.value);
  529. if (response.num) {
  530. var selecthtml_str = response.value;
  531. var selecthtml_dom=$.parseHTML(selecthtml_str);
  532. if (typeof(selecthtml_dom[0][0]) !== \'undefined\') {
  533. $("#inputautocomplete"+htmlname).val(selecthtml_dom[0][0].innerHTML);
  534. }
  535. } else {
  536. $("#inputautocomplete"+htmlname).val("");
  537. }
  538. $("select#" + htmlname).change(); /* Trigger event change */
  539. }
  540. );
  541. }
  542. });
  543. </script>';
  544. }
  545. // Contact and type
  546. print '<tr><td>'.$langs->trans("Contact").'</td><td>';
  547. // If no socid, set to -1 to avoid full contacts list
  548. $selectedCompany = ($this->withfromsocid > 0) ? $this->withfromsocid : -1;
  549. print img_picto('', 'contact', 'class="paddingright"');
  550. print $form->selectcontacts($selectedCompany, $this->withfromcontactid, 'contactid', 3, '', '', 0, 'minwidth200');
  551. print ' ';
  552. $formcompany->selectTypeContact($ticketstatic, '', 'type', 'external', '', 0, 'maginleftonly');
  553. print '</td></tr>';
  554. } else {
  555. print '<tr><td class="titlefield"><input type="hidden" name="socid" value="'.$user->socid.'"/></td>';
  556. print '<td><input type="hidden" name="contactid" value="'.$user->contact_id.'"/></td>';
  557. print '<td><input type="hidden" name="type" value="Z"/></td></tr>';
  558. }
  559. // Notify thirdparty at creation
  560. if (empty($this->ispublic)) {
  561. print '<tr><td><label for="notify_tiers_at_create">'.$langs->trans("TicketNotifyTiersAtCreation").'</label></td><td>';
  562. print '<input type="checkbox" id="notify_tiers_at_create" name="notify_tiers_at_create"'.($this->withnotifytiersatcreate ? ' checked="checked"' : '').'>';
  563. print '</td></tr>';
  564. }
  565. // User assigned
  566. print '<tr><td>';
  567. print $langs->trans("AssignedTo");
  568. print '</td><td>';
  569. print img_picto('', 'user', 'class="pictofixedwidth"');
  570. print $form->select_dolusers(GETPOST('fk_user_assign', 'int'), 'fk_user_assign', 1);
  571. print '</td>';
  572. print '</tr>';
  573. }
  574. if ($subelement != 'project') {
  575. if (isModEnabled('project') && !$this->ispublic) {
  576. $formproject = new FormProjets($this->db);
  577. print '<tr><td><label for="project"><span class="">'.$langs->trans("Project").'</span></label></td><td>';
  578. print img_picto('', 'project').$formproject->select_projects(-1, GETPOST('projectid', 'int'), 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
  579. print '</td></tr>';
  580. }
  581. }
  582. if ($subelement != 'contract') {
  583. if (isModEnabled('contract') && !$this->ispublic) {
  584. $formcontract = new FormContract($this->db);
  585. print '<tr><td><label for="contract"><span class="">'.$langs->trans("Contract").'</span></label></td><td>';
  586. print img_picto('', 'contract');
  587. print $formcontract->select_contract(-1, GETPOST('contactid', 'int'), 'contractid', 0, 1, 1);
  588. print '</td></tr>';
  589. }
  590. }
  591. // Other attributes
  592. $parameters = array();
  593. $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $ticketstat, $action); // Note that $action and $object may have been modified by hook
  594. if (empty($reshook)) {
  595. print $ticketstat->showOptionals($extrafields, 'create');
  596. }
  597. print '</table>';
  598. if ($withdolfichehead) {
  599. print dol_get_fiche_end();
  600. }
  601. print '<br><br>';
  602. print $form->buttonsSaveCancel(((isset($this->withreadid) && $this->withreadid > 0) ? "SendResponse" : "CreateTicket"), ($this->withcancel ? "Cancel" : ""));
  603. /*
  604. print '<div class="center">';
  605. print '<input type="submit" class="button" name="add" value="'.$langs->trans(($this->withreadid > 0 ? "SendResponse" : "CreateTicket")).'" />';
  606. if ($this->withcancel) {
  607. print " &nbsp; &nbsp; &nbsp;";
  608. print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
  609. }
  610. print '</div>';
  611. */
  612. print '<input type="hidden" name="page_y">'."\n";
  613. print "</form>\n";
  614. print "<!-- End form TICKET -->\n";
  615. }
  616. /**
  617. * Return html list of tickets type
  618. *
  619. * @param string|array $selected Id of preselected field or array of Ids
  620. * @param string $htmlname Nom de la zone select
  621. * @param string $filtertype To filter on field type in llx_c_ticket_type (array('code'=>xx,'label'=>zz))
  622. * @param int $format 0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code
  623. * @param int $empty 1=peut etre vide, 0 sinon
  624. * @param int $noadmininfo 0=Add admin info, 1=Disable admin info
  625. * @param int $maxlength Max length of label
  626. * @param string $morecss More CSS
  627. * @param int $multiselect Is multiselect ?
  628. * @return void
  629. */
  630. public function selectTypesTickets($selected = '', $htmlname = 'tickettype', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $multiselect = 0)
  631. {
  632. global $langs, $user;
  633. $selected = is_array($selected) ? $selected : (!empty($selected) ? explode(',', $selected) : array());
  634. $ticketstat = new Ticket($this->db);
  635. dol_syslog(get_class($this) . "::select_types_tickets " . implode(';', $selected) . ", " . $htmlname . ", " . $filtertype . ", " . $format . ", " . $multiselect, LOG_DEBUG);
  636. $filterarray = array();
  637. if ($filtertype != '' && $filtertype != '-1') {
  638. $filterarray = explode(',', $filtertype);
  639. }
  640. $ticketstat->loadCacheTypesTickets();
  641. print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.($multiselect ? '[]' : '').'"'.($multiselect ? ' multiple' : '').'>';
  642. if ($empty) {
  643. print '<option value="">&nbsp;</option>';
  644. }
  645. if (is_array($ticketstat->cache_types_tickets) && count($ticketstat->cache_types_tickets)) {
  646. foreach ($ticketstat->cache_types_tickets as $id => $arraytypes) {
  647. // On passe si on a demande de filtrer sur des modes de paiments particuliers
  648. if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
  649. continue;
  650. }
  651. // If 'showempty' is enabled we discard empty line because an empty line has already been output.
  652. if ($empty && empty($arraytypes['code'])) {
  653. continue;
  654. }
  655. if ($format == 0) {
  656. print '<option value="'.$id.'"';
  657. }
  658. if ($format == 1) {
  659. print '<option value="'.$arraytypes['code'].'"';
  660. }
  661. if ($format == 2) {
  662. print '<option value="'.$arraytypes['code'].'"';
  663. }
  664. if ($format == 3) {
  665. print '<option value="'.$id.'"';
  666. }
  667. // If text is selected, we compare with code, otherwise with id
  668. if (in_array($arraytypes['code'], $selected)) {
  669. print ' selected="selected"';
  670. } elseif (in_array($id, $selected)) {
  671. print ' selected="selected"';
  672. } elseif ($arraytypes['use_default'] == "1" && !$selected && !$empty) {
  673. print ' selected="selected"';
  674. }
  675. print '>';
  676. $value = '&nbsp;';
  677. if ($format == 0) {
  678. $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
  679. } elseif ($format == 1) {
  680. $value = $arraytypes['code'];
  681. } elseif ($format == 2) {
  682. $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
  683. } elseif ($format == 3) {
  684. $value = $arraytypes['code'];
  685. }
  686. print $value ? $value : '&nbsp;';
  687. print '</option>';
  688. }
  689. }
  690. print '</select>';
  691. if (isset($user->admin) && $user->admin && !$noadmininfo) {
  692. print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
  693. }
  694. print ajax_combobox('select'.$htmlname);
  695. }
  696. /**
  697. * Return html list of ticket anaytic codes
  698. *
  699. * @param string $selected Id pre-selected category
  700. * @param string $htmlname Name of select component
  701. * @param string $filtertype To filter on some properties in llx_c_ticket_category ('public = 1'). This parameter must not come from input of users.
  702. * @param int $format 0 = id+label, 1 = code+code, 2 = code+label, 3 = id+code
  703. * @param int $empty 1 = can be empty, 0 = or not
  704. * @param int $noadmininfo 0 = ddd admin info, 1 = disable admin info
  705. * @param int $maxlength Max length of label
  706. * @param string $morecss More CSS
  707. * @param int $use_multilevel If > 0 create a multilevel select which use $htmlname example: $use_multilevel = 1 permit to have 2 select boxes.
  708. * @param Translate $outputlangs Output language
  709. * @return string|void String of HTML component
  710. */
  711. public function selectGroupTickets($selected = '', $htmlname = 'ticketcategory', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '', $use_multilevel = 0, $outputlangs = null)
  712. {
  713. global $conf, $langs, $user;
  714. dol_syslog(get_class($this)."::selectCategoryTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
  715. if (is_null($outputlangs) || !is_object($outputlangs)) {
  716. $outputlangs = $langs;
  717. }
  718. $outputlangs->load("ticket");
  719. $publicgroups = ($filtertype == 'public=1' || $filtertype == '(public:=:1)');
  720. $ticketstat = new Ticket($this->db);
  721. $ticketstat->loadCacheCategoriesTickets($publicgroups ? 1 : -1); // get list of active ticket groups
  722. if ($use_multilevel <= 0) {
  723. print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
  724. if ($empty) {
  725. print '<option value="">&nbsp;</option>';
  726. }
  727. if (is_array($ticketstat->cache_category_tickets) && count($ticketstat->cache_category_tickets)) {
  728. foreach ($ticketstat->cache_category_tickets as $id => $arraycategories) {
  729. // Exclude some record
  730. if ($publicgroups) {
  731. if (empty($arraycategories['public'])) {
  732. continue;
  733. }
  734. }
  735. // We discard empty line if showempty is on because an empty line has already been output.
  736. if ($empty && empty($arraycategories['code'])) {
  737. continue;
  738. }
  739. $label = ($arraycategories['label'] != '-' ? $arraycategories['label'] : '');
  740. if ($outputlangs->trans("TicketCategoryShort".$arraycategories['code']) != "TicketCategoryShort".$arraycategories['code']) {
  741. $label = $outputlangs->trans("TicketCategoryShort".$arraycategories['code']);
  742. } elseif ($outputlangs->trans($arraycategories['code']) != $arraycategories['code']) {
  743. $label = $outputlangs->trans($arraycategories['code']);
  744. }
  745. if ($format == 0) {
  746. print '<option value="'.$id.'"';
  747. }
  748. if ($format == 1) {
  749. print '<option value="'.$arraycategories['code'].'"';
  750. }
  751. if ($format == 2) {
  752. print '<option value="'.$arraycategories['code'].'"';
  753. }
  754. if ($format == 3) {
  755. print '<option value="'.$id.'"';
  756. }
  757. // If selected is text, we compare with code, otherwise with id
  758. if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arraycategories['code']) {
  759. print ' selected="selected"';
  760. } elseif (isset($selected) && $selected == $id) {
  761. print ' selected="selected"';
  762. } elseif ($arraycategories['use_default'] == "1" && !$selected && !$empty) {
  763. print ' selected="selected"';
  764. } elseif (count($ticketstat->cache_category_tickets) == 1) {
  765. print ' selected="selected"';
  766. }
  767. print '>';
  768. $value = '';
  769. if ($format == 0) {
  770. $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
  771. }
  772. if ($format == 1) {
  773. $value = $arraycategories['code'];
  774. }
  775. if ($format == 2) {
  776. $value = ($maxlength ? dol_trunc($label, $maxlength) : $label);
  777. }
  778. if ($format == 3) {
  779. $value = $arraycategories['code'];
  780. }
  781. print $value ? $value : '&nbsp;';
  782. print '</option>';
  783. }
  784. }
  785. print '</select>';
  786. if (isset($user->admin) && $user->admin && !$noadmininfo) {
  787. print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
  788. }
  789. print ajax_combobox('select'.$htmlname);
  790. } elseif ($htmlname != '') {
  791. $selectedgroups = array();
  792. $groupvalue = "";
  793. $groupticket=GETPOST($htmlname, 'aZ09');
  794. $child_id=GETPOST($htmlname.'_child_id', 'aZ09') ? GETPOST($htmlname.'_child_id', 'aZ09') : 0;
  795. if (!empty($groupticket)) {
  796. $tmpgroupticket = $groupticket;
  797. $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code";
  798. $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc WHERE ctc.code = '".$this->db->escape($tmpgroupticket)."'";
  799. $resql = $this->db->query($sql);
  800. if ($resql) {
  801. $obj = $this->db->fetch_object($resql);
  802. $selectedgroups[] = $obj->code;
  803. while ($obj->fk_parent > 0) {
  804. $sql = "SELECT ctc.rowid, ctc.fk_parent, ctc.code FROM ".$this->db->prefix()."c_ticket_category as ctc WHERE ctc.rowid ='".$this->db->escape($obj->fk_parent)."'";
  805. $resql = $this->db->query($sql);
  806. if ($resql) {
  807. $obj = $this->db->fetch_object($resql);
  808. $selectedgroups[] = $obj->code;
  809. }
  810. }
  811. }
  812. }
  813. $arrayidused = array();
  814. $arrayidusedconcat = array();
  815. $arraycodenotparent = array();
  816. $arraycodenotparent[] = "";
  817. $stringtoprint = '<span class="supportemailfield bold">'.$langs->trans("GroupOfTicket").'</span> ';
  818. $stringtoprint .= '<select id ="'.$htmlname.'" class="minwidth500" child_id="0">';
  819. $stringtoprint .= '<option value="">&nbsp;</option>';
  820. $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ";
  821. $sql .= $this->db->ifsql("ctc.rowid NOT IN (SELECT ctcfather.rowid FROM llx_c_ticket_category as ctcfather JOIN llx_c_ticket_category as ctcjoin ON ctcfather.rowid = ctcjoin.fk_parent)", "'NOTPARENT'", "'PARENT'")." as isparent";
  822. $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
  823. $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
  824. if ($filtertype == 'public=1') {
  825. $sql .= " AND ctc.public = 1";
  826. }
  827. $sql .= " AND ctc.fk_parent = 0";
  828. $sql .= $this->db->order('ctc.pos', 'ASC');
  829. $resql = $this->db->query($sql);
  830. if ($resql) {
  831. $num_rows_level0 = $this->db->num_rows($resql);
  832. $i = 0;
  833. while ($i < $num_rows_level0) {
  834. $obj = $this->db->fetch_object($resql);
  835. if ($obj) {
  836. $label = ($obj->label != '-' ? $obj->label : '');
  837. if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
  838. $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
  839. } elseif ($outputlangs->trans($obj->code) != $obj->code) {
  840. $label = $outputlangs->trans($obj->code);
  841. }
  842. $grouprowid = $obj->rowid;
  843. $groupvalue = $obj->code;
  844. $grouplabel = $label;
  845. $isparent = $obj->isparent;
  846. if (is_array($selectedgroups)) {
  847. $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
  848. } else {
  849. $iselected = $groupticket == $obj->code ? 'selected' : '';
  850. }
  851. $stringtoprint .= '<option '.$iselected.' class="'.$htmlname.dol_escape_htmltag($grouprowid).'" value="'.dol_escape_htmltag($groupvalue).'" data-html="'.dol_escape_htmltag($grouplabel).'">'.dol_escape_htmltag($grouplabel).'</option>';
  852. if ($isparent == 'NOTPARENT') {
  853. $arraycodenotparent[] = $groupvalue;
  854. }
  855. $arrayidused[] = $grouprowid;
  856. $arrayidusedconcat[] = $grouprowid;
  857. }
  858. $i++;
  859. }
  860. } else {
  861. dol_print_error($this->db);
  862. }
  863. if (count($arrayidused) == 1) {
  864. return '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'" value="'.dol_escape_htmltag($groupvalue).'">';
  865. } else {
  866. $stringtoprint .= '<input type="hidden" name="'.$htmlname.'" id="'.$htmlname.'_select" class="maxwidth500 minwidth400">';
  867. $stringtoprint .= '<input type="hidden" name="'.$htmlname.'_child_id" id="'.$htmlname.'_select_child_id" class="maxwidth500 minwidth400">';
  868. }
  869. $stringtoprint .= '</select>&nbsp;';
  870. $levelid = 1; // The first combobox
  871. while ($levelid <= $use_multilevel) { // Loop to take the child of the combo
  872. $tabscript = array();
  873. $stringtoprint .= '<select id ="'.$htmlname.'_child_'.$levelid.'" class="maxwidth500 minwidth400 groupticketchild" child_id="'.$levelid.'">';
  874. $stringtoprint .= '<option value="">&nbsp;</option>';
  875. $sql = "SELECT ctc.rowid, ctc.code, ctc.label, ctc.fk_parent, ctc.public, ctcjoin.code as codefather";
  876. $sql .= " FROM ".$this->db->prefix()."c_ticket_category as ctc";
  877. $sql .= " JOIN ".$this->db->prefix()."c_ticket_category as ctcjoin ON ctc.fk_parent = ctcjoin.rowid";
  878. $sql .= " WHERE ctc.active > 0 AND ctc.entity = ".((int) $conf->entity);
  879. $sql .= " AND ctc.rowid NOT IN (".$this->db->sanitize(join(',', $arrayidusedconcat)).")";
  880. if ($filtertype == 'public=1') {
  881. $sql .= " AND ctc.public = 1";
  882. }
  883. // Add a test to take only record that are direct child
  884. if (!empty($arrayidused)) {
  885. $sql .= " AND ctc.fk_parent IN ( ";
  886. foreach ($arrayidused as $idused) {
  887. $sql .= $idused.", ";
  888. }
  889. $sql = substr($sql, 0, -2);
  890. $sql .= ")";
  891. }
  892. $sql .= $this->db->order('ctc.pos', 'ASC');
  893. $resql = $this->db->query($sql);
  894. if ($resql) {
  895. $num_rows = $this->db->num_rows($resql);
  896. $i = 0;
  897. $arrayidused=array();
  898. while ($i < $num_rows) {
  899. $obj = $this->db->fetch_object($resql);
  900. if ($obj) {
  901. $label = ($obj->label != '-' ? $obj->label : '');
  902. if ($outputlangs->trans("TicketCategoryShort".$obj->code) != "TicketCategoryShort".$obj->code) {
  903. $label = $outputlangs->trans("TicketCategoryShort".$obj->code);
  904. } elseif ($outputlangs->trans($obj->code) != $obj->code) {
  905. $label = $outputlangs->trans($obj->code);
  906. }
  907. $grouprowid = $obj->rowid;
  908. $groupvalue = $obj->code;
  909. $grouplabel = $label;
  910. $isparent = $obj->isparent;
  911. $fatherid = $obj->fk_parent;
  912. $arrayidused[] = $grouprowid;
  913. $arrayidusedconcat[] = $grouprowid;
  914. $groupcodefather = $obj->codefather;
  915. if ($isparent == 'NOTPARENT') {
  916. $arraycodenotparent[] = $groupvalue;
  917. }
  918. if (is_array($selectedgroups)) {
  919. $iselected = in_array($obj->code, $selectedgroups) ? 'selected' : '';
  920. } else {
  921. $iselected = $groupticket == $obj->code ? 'selected' : '';
  922. }
  923. $stringtoprint .= '<option '.$iselected.' class="'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'" value="'.dol_escape_htmltag($groupvalue).'" data-html="'.dol_escape_htmltag($grouplabel).'">'.dol_escape_htmltag($grouplabel).'</option>';
  924. if (empty($tabscript[$groupcodefather])) {
  925. $tabscript[$groupcodefather] = 'if ($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid-1) : '').'").val() == "'.dol_escape_js($groupcodefather).'"){
  926. $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").show()
  927. console.log("We show childs tickets of '.$groupcodefather.' group ticket")
  928. }else{
  929. $(".'.$htmlname.'_'.dol_escape_htmltag($fatherid).'_child_'.$levelid.'").hide()
  930. console.log("We hide childs tickets of '.$groupcodefather.' group ticket")
  931. }';
  932. }
  933. }
  934. $i++;
  935. }
  936. } else {
  937. dol_print_error($this->db);
  938. }
  939. $stringtoprint .='</select>';
  940. $stringtoprint .='<script nonce="'.getNonce().'">';
  941. $stringtoprint .='arraynotparents = '.json_encode($arraycodenotparent).';'; // when the last visible combo list is number x, this is the array of group
  942. $stringtoprint .='if (arraynotparents.includes($("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid-1) : '').'").val())){
  943. console.log("'.$htmlname.'_child_'.$levelid.'")
  944. if($("#'.$htmlname.'_child_'.$levelid.'").val() == "" && ($("#'.$htmlname.'_child_'.$levelid.'").attr("child_id")>'.$child_id.')){
  945. $("#'.$htmlname.'_child_'.$levelid.'").hide();
  946. console.log("We hide '.$htmlname.'_child_'.$levelid.' input")
  947. }
  948. if(arraynotparents.includes("'.$groupticket.'") && '.$child_id.' == 0){
  949. $("#ticketcategory_select_child_id").val($("#'.$htmlname.'").attr("child_id"))
  950. $("#ticketcategory_select").val($("#'.$htmlname.'").val()) ;
  951. console.log("We choose '.$htmlname.' input and reload hidden input");
  952. }
  953. }
  954. $("#'.$htmlname.($levelid > 1 ? '_child_'.($levelid-1) : '').'").change(function() {
  955. child_id = $("#'.$htmlname.($levelid > 1 ? '_child_'.$levelid : '').'").attr("child_id");
  956. /* Change of value to select this value*/
  957. if (arraynotparents.includes($(this).val()) || $(this).attr("child_id") == '.$use_multilevel.') {
  958. $("#ticketcategory_select").val($(this).val());
  959. $("#ticketcategory_select_child_id").val($(this).attr("child_id")) ;
  960. console.log("We choose to select "+ $(this).val());
  961. }else{
  962. if ($("#'.$htmlname.'_child_'.$levelid.' option").length <= 1) {
  963. $("#ticketcategory_select").val($(this).val());
  964. $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
  965. console.log("We choose to select "+ $(this).val() + " and next combo has no item, so we keep this selection");
  966. } else {
  967. console.log("We choose to select "+ $(this).val() + " but next combo has some item, so we clean selected item");
  968. $("#ticketcategory_select").val("");
  969. $("#ticketcategory_select_child_id").val("");
  970. }
  971. }
  972. console.log("We select a new value into combo child_id="+child_id);
  973. // Hide all selected box that are child of the one modified
  974. $(".groupticketchild").each(function(){
  975. if ($(this).attr("child_id") > child_id) {
  976. console.log("hide child_id="+$(this).attr("child_id"));
  977. $(this).val("");
  978. $(this).hide();
  979. }
  980. })
  981. // Now we enable the next combo
  982. $("#'.$htmlname.'_child_'.$levelid.'").val("");
  983. if (!arraynotparents.includes($(this).val()) && $("#'.$htmlname.'_child_'.$levelid.' option").length > 1) {
  984. console.log($("#'.$htmlname.'_child_'.$levelid.' option").length);
  985. $("#'.$htmlname.'_child_'.$levelid.'").show()
  986. } else {
  987. $("#'.$htmlname.'_child_'.$levelid.'").hide()
  988. }
  989. ';
  990. $levelid++;
  991. foreach ($tabscript as $script) {
  992. $stringtoprint .= $script;
  993. }
  994. $stringtoprint .='})';
  995. $stringtoprint .='</script>';
  996. }
  997. $stringtoprint .='<script nonce="'.getNonce().'">';
  998. $stringtoprint .='$("#'.$htmlname.'_child_'.$use_multilevel.'").change(function() {
  999. $("#ticketcategory_select").val($(this).val());
  1000. $("#ticketcategory_select_child_id").val($(this).attr("child_id"));
  1001. console.log($("#ticketcategory_select").val());
  1002. })';
  1003. $stringtoprint .='</script>';
  1004. $stringtoprint .= ajax_combobox($htmlname);
  1005. return $stringtoprint;
  1006. }
  1007. }
  1008. /**
  1009. * Return html list of ticket severitys (priorities)
  1010. *
  1011. * @param string $selected Id severity pre-selected
  1012. * @param string $htmlname Name of the select area
  1013. * @param string $filtertype To filter on field type in llx_c_ticket_severity (array('code'=>xx,'label'=>zz))
  1014. * @param int $format 0 = id+label, 1 = code+code, 2 = code+label, 3 = id+code
  1015. * @param int $empty 1 = can be empty, 0 = or not
  1016. * @param int $noadmininfo 0 = add admin info, 1 = disable admin info
  1017. * @param int $maxlength Max length of label
  1018. * @param string $morecss More CSS
  1019. * @return void
  1020. */
  1021. public function selectSeveritiesTickets($selected = '', $htmlname = 'ticketseverity', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $morecss = '')
  1022. {
  1023. global $langs, $user;
  1024. $ticketstat = new Ticket($this->db);
  1025. dol_syslog(get_class($this)."::selectSeveritiesTickets ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
  1026. $filterarray = array();
  1027. if ($filtertype != '' && $filtertype != '-1') {
  1028. $filterarray = explode(',', $filtertype);
  1029. }
  1030. $ticketstat->loadCacheSeveritiesTickets();
  1031. print '<select id="select'.$htmlname.'" class="flat minwidth100'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
  1032. if ($empty) {
  1033. print '<option value="">&nbsp;</option>';
  1034. }
  1035. if (is_array($ticketstat->cache_severity_tickets) && count($ticketstat->cache_severity_tickets)) {
  1036. foreach ($ticketstat->cache_severity_tickets as $id => $arrayseverities) {
  1037. // On passe si on a demande de filtrer sur des modes de paiments particuliers
  1038. if (count($filterarray) && !in_array($arrayseverities['type'], $filterarray)) {
  1039. continue;
  1040. }
  1041. // We discard empty line if showempty is on because an empty line has already been output.
  1042. if ($empty && empty($arrayseverities['code'])) {
  1043. continue;
  1044. }
  1045. if ($format == 0) {
  1046. print '<option value="'.$id.'"';
  1047. }
  1048. if ($format == 1) {
  1049. print '<option value="'.$arrayseverities['code'].'"';
  1050. }
  1051. if ($format == 2) {
  1052. print '<option value="'.$arrayseverities['code'].'"';
  1053. }
  1054. if ($format == 3) {
  1055. print '<option value="'.$id.'"';
  1056. }
  1057. // If text is selected, we compare with code, otherwise with id
  1058. if (isset($selected) && preg_match('/[a-z]/i', $selected) && $selected == $arrayseverities['code']) {
  1059. print ' selected="selected"';
  1060. } elseif (isset($selected) && $selected == $id) {
  1061. print ' selected="selected"';
  1062. } elseif ($arrayseverities['use_default'] == "1" && !$selected && !$empty) {
  1063. print ' selected="selected"';
  1064. }
  1065. print '>';
  1066. $value = '';
  1067. if ($format == 0) {
  1068. $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
  1069. }
  1070. if ($format == 1) {
  1071. $value = $arrayseverities['code'];
  1072. }
  1073. if ($format == 2) {
  1074. $value = ($maxlength ? dol_trunc($arrayseverities['label'], $maxlength) : $arrayseverities['label']);
  1075. }
  1076. if ($format == 3) {
  1077. $value = $arrayseverities['code'];
  1078. }
  1079. print $value ? $value : '&nbsp;';
  1080. print '</option>';
  1081. }
  1082. }
  1083. print '</select>';
  1084. if (isset($user->admin) && $user->admin && !$noadmininfo) {
  1085. print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
  1086. }
  1087. print ajax_combobox('select'.$htmlname);
  1088. }
  1089. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
  1090. /**
  1091. * Clear list of attached files in send mail form (also stored in session)
  1092. *
  1093. * @return void
  1094. */
  1095. public function clear_attached_files()
  1096. {
  1097. // phpcs:enable
  1098. global $conf, $user;
  1099. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  1100. // Set tmp user directory
  1101. $vardir = $conf->user->dir_output."/".$user->id;
  1102. $upload_dir = $vardir.'/temp/'; // TODO Add $keytoavoidconflict in upload_dir path
  1103. if (is_dir($upload_dir)) {
  1104. dol_delete_dir_recursive($upload_dir);
  1105. }
  1106. if (!empty($this->trackid)) { // TODO Always use trackid (ticXXX) instead of track_id (abcd123)
  1107. $keytoavoidconflict = '-'.$this->trackid;
  1108. } else {
  1109. $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id;
  1110. }
  1111. unset($_SESSION["listofpaths".$keytoavoidconflict]);
  1112. unset($_SESSION["listofnames".$keytoavoidconflict]);
  1113. unset($_SESSION["listofmimes".$keytoavoidconflict]);
  1114. }
  1115. /**
  1116. * Show the form to add message on ticket
  1117. *
  1118. * @param string $width Width of form
  1119. * @return void
  1120. */
  1121. public function showMessageForm($width = '40%')
  1122. {
  1123. global $conf, $langs, $user, $hookmanager, $form, $mysoc;
  1124. $formmail = new FormMail($this->db);
  1125. $addfileaction = 'addfile';
  1126. if (!is_object($form)) {
  1127. $form = new Form($this->db);
  1128. }
  1129. // Load translation files required by the page
  1130. $langs->loadLangs(array('other', 'mails', 'ticket'));
  1131. // Clear temp files. Must be done at beginning, before call of triggers
  1132. if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
  1133. $this->clear_attached_files();
  1134. }
  1135. // Define output language
  1136. $outputlangs = $langs;
  1137. $newlang = '';
  1138. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
  1139. $newlang = $this->param['langsmodels'];
  1140. }
  1141. if (!empty($newlang)) {
  1142. $outputlangs = new Translate("", $conf);
  1143. $outputlangs->setDefaultLang($newlang);
  1144. $outputlangs->load('other');
  1145. }
  1146. // Get message template for $this->param["models"] into c_email_templates
  1147. $arraydefaultmessage = -1;
  1148. if (isset($this->param['models']) && $this->param['models'] != 'none') {
  1149. $model_id = 0;
  1150. if (array_key_exists('models_id', $this->param)) {
  1151. $model_id = (int) $this->param["models_id"];
  1152. }
  1153. $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id); // If $model_id is empty, preselect the first one
  1154. }
  1155. // Define list of attached files
  1156. $listofpaths = array();
  1157. $listofnames = array();
  1158. $listofmimes = array();
  1159. if (!empty($this->trackid)) {
  1160. $keytoavoidconflict = '-'.$this->trackid;
  1161. } else {
  1162. $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
  1163. }
  1164. //var_dump($keytoavoidconflict);
  1165. if (GETPOST('mode', 'alpha') == 'init' || (GETPOST('modelselected') && GETPOST('modelmailselected', 'alpha') && GETPOST('modelmailselected', 'alpha') != '-1')) {
  1166. if (!empty($arraydefaultmessage->joinfiles) && !empty($this->param['fileinit']) && is_array($this->param['fileinit'])) {
  1167. foreach ($this->param['fileinit'] as $file) {
  1168. $formmail->add_attached_files($file, basename($file), dol_mimetype($file));
  1169. }
  1170. }
  1171. }
  1172. //var_dump($_SESSION);
  1173. //var_dump($_SESSION["listofpaths".$keytoavoidconflict]);
  1174. if (!empty($_SESSION["listofpaths".$keytoavoidconflict])) {
  1175. $listofpaths = explode(';', $_SESSION["listofpaths".$keytoavoidconflict]);
  1176. }
  1177. if (!empty($_SESSION["listofnames".$keytoavoidconflict])) {
  1178. $listofnames = explode(';', $_SESSION["listofnames".$keytoavoidconflict]);
  1179. }
  1180. if (!empty($_SESSION["listofmimes".$keytoavoidconflict])) {
  1181. $listofmimes = explode(';', $_SESSION["listofmimes".$keytoavoidconflict]);
  1182. }
  1183. // Define output language
  1184. $outputlangs = $langs;
  1185. $newlang = '';
  1186. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && isset($this->param['langsmodels'])) {
  1187. $newlang = $this->param['langsmodels'];
  1188. }
  1189. if (!empty($newlang)) {
  1190. $outputlangs = new Translate("", $conf);
  1191. $outputlangs->setDefaultLang($newlang);
  1192. $outputlangs->load('other');
  1193. }
  1194. print "\n<!-- Begin message_form TICKET -->\n";
  1195. $send_email = GETPOST('send_email', 'int') ? GETPOST('send_email', 'int') : 0;
  1196. // Example 1 : Adding jquery code
  1197. print '<script nonce="'.getNonce().'" type="text/javascript">
  1198. jQuery(document).ready(function() {
  1199. send_email=' . $send_email.';
  1200. if (send_email) {
  1201. if (!jQuery("#send_msg_email").is(":checked")) {
  1202. jQuery("#send_msg_email").prop("checked", true).trigger("change");
  1203. }
  1204. jQuery(".email_line").show();
  1205. } else {
  1206. if (!jQuery("#private_message").is(":checked")) {
  1207. jQuery("#private_message").prop("checked", true).trigger("change");
  1208. }
  1209. jQuery(".email_line").hide();
  1210. }
  1211. ';
  1212. // If constant set, allow to send private messages as email
  1213. if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
  1214. print 'jQuery("#send_msg_email").click(function() {
  1215. console.log("Click send_msg_email");
  1216. if(jQuery(this).is(":checked")) {
  1217. if (jQuery("#private_message").is(":checked")) {
  1218. jQuery("#private_message").prop("checked", false).trigger("change");
  1219. }
  1220. jQuery(".email_line").show();
  1221. }
  1222. else {
  1223. jQuery(".email_line").hide();
  1224. }
  1225. });
  1226. jQuery("#private_message").click(function() {
  1227. console.log("Click private_message");
  1228. if (jQuery(this).is(":checked")) {
  1229. if (jQuery("#send_msg_email").is(":checked")) {
  1230. jQuery("#send_msg_email").prop("checked", false).trigger("change");
  1231. }
  1232. jQuery(".email_line").hide();
  1233. }
  1234. });';
  1235. }
  1236. print '});
  1237. </script>';
  1238. print '<form method="post" name="ticket" id="ticket" enctype="multipart/form-data" action="'.$this->param["returnurl"].'">';
  1239. print '<input type="hidden" name="token" value="'.newToken().'">';
  1240. print '<input type="hidden" name="action" value="'.$this->action.'">';
  1241. print '<input type="hidden" name="actionbis" value="add_message">';
  1242. print '<input type="hidden" name="backtopage" value="'.$this->backtopage.'">';
  1243. if (!empty($this->trackid)) {
  1244. print '<input type="hidden" name="trackid" value="'.$this->trackid.'">';
  1245. } else {
  1246. print '<input type="hidden" name="trackid" value="'.(empty($this->track_id) ? '' : $this->track_id).'">';
  1247. $keytoavoidconflict = empty($this->track_id) ? '' : '-'.$this->track_id; // track_id instead of trackid
  1248. }
  1249. foreach ($this->param as $key => $value) {
  1250. print '<input type="hidden" name="'.$key.'" value="'.$value.'">';
  1251. }
  1252. // Get message template
  1253. $model_id = 0;
  1254. if (array_key_exists('models_id', $this->param)) {
  1255. $model_id = $this->param["models_id"];
  1256. $arraydefaultmessage = $formmail->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id);
  1257. }
  1258. $result = $formmail->fetchAllEMailTemplate(!empty($this->param["models"]) ? $this->param["models"] : "", $user, $outputlangs);
  1259. if ($result < 0) {
  1260. setEventMessages($this->error, $this->errors, 'errors');
  1261. }
  1262. $modelmail_array = array();
  1263. foreach ($formmail->lines_model as $line) {
  1264. $modelmail_array[$line->id] = $line->label;
  1265. }
  1266. print '<table class="border" width="'.$width.'">';
  1267. // External users can't send message email
  1268. if ($user->hasRight("ticket", "write") && !$user->socid) {
  1269. $ticketstat = new Ticket($this->db);
  1270. $res = $ticketstat->fetch('', '', $this->track_id);
  1271. print '<tr><td></td><td>';
  1272. $checkbox_selected = (GETPOST('send_email') == "1" ? ' checked' : (getDolGlobalInt('TICKETS_MESSAGE_FORCE_MAIL') ? 'checked' : ''));
  1273. print '<input type="checkbox" name="send_email" value="1" id="send_msg_email" '.$checkbox_selected.'/> ';
  1274. print '<label for="send_msg_email">'.$langs->trans('SendMessageByEmail').'</label>';
  1275. $texttooltip = $langs->trans("TicketMessageSendEmailHelp");
  1276. if (!getDolGlobalString('TICKET_SEND_PRIVATE_EMAIL')) {
  1277. $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2b");
  1278. } else {
  1279. $texttooltip .= ' '.$langs->trans("TicketMessageSendEmailHelp2a", '{s1}');
  1280. }
  1281. $texttooltip = str_replace('{s1}', $langs->trans('MarkMessageAsPrivate'), $texttooltip);
  1282. print ' '.$form->textwithpicto('', $texttooltip, 1, 'help');
  1283. print '</td></tr>';
  1284. // Private message (not visible by customer/external user)
  1285. if (!$user->socid) {
  1286. print '<tr><td></td><td>';
  1287. $checkbox_selected = (GETPOST('private_message', 'alpha') == "1" ? ' checked' : '');
  1288. print '<input type="checkbox" name="private_message" value="1" id="private_message" '.$checkbox_selected.'/> ';
  1289. print '<label for="private_message">'.$langs->trans('MarkMessageAsPrivate').'</label>';
  1290. print ' '.$form->textwithpicto('', $langs->trans("TicketMessagePrivateHelp"), 1, 'help');
  1291. print '</td></tr>';
  1292. }
  1293. // Zone to select its email template
  1294. if (count($modelmail_array) > 0) {
  1295. print '<tr class="email_line"><td></td><td colspan="2"><div style="padding: 3px 0 3px 0">'."\n";
  1296. print $langs->trans('SelectMailModel').': '.$formmail->selectarray('modelmailselected', $modelmail_array, $this->param['models_id'], 1, 0, "", "", 0, 0, 0, '', 'minwidth200');
  1297. if ($user->admin) {
  1298. print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
  1299. }
  1300. print ' &nbsp; ';
  1301. print '<input type="submit" class="button" value="'.$langs->trans('Apply').'" name="modelselected" id="modelselected">';
  1302. print '</div></td>';
  1303. }
  1304. // Subject/topic
  1305. $topic = "";
  1306. foreach ($formmail->lines_model as $line) {
  1307. if ($this->param['models_id'] == $line->id) {
  1308. $topic = $line->topic;
  1309. break;
  1310. }
  1311. }
  1312. print '<tr class="email_line"><td>'.$langs->trans('Subject').'</td>';
  1313. if (empty($topic)) {
  1314. print '<td><input type="text" class="text minwidth500" name="subject" value="['.getDolGlobalString('MAIN_INFO_SOCIETE_NOM').' - '.$langs->trans("Ticket").' '.$ticketstat->ref.'] '.$langs->trans('TicketNewMessage').'" />';
  1315. } else {
  1316. print '<td><input type="text" class="text minwidth500" name="subject" value="['.getDolGlobalString('MAIN_INFO_SOCIETE_NOM').' - '.$langs->trans("Ticket").' '.$ticketstat->ref.'] '.$topic.'" />';
  1317. }
  1318. print '</td></tr>';
  1319. // Recipients / adressed-to
  1320. print '<tr class="email_line"><td>'.$langs->trans('MailRecipients');
  1321. print ' '.$form->textwithpicto('', $langs->trans("TicketMessageRecipientsHelp"), 1, 'help');
  1322. print '</td><td>';
  1323. if ($res) {
  1324. // Retrieve email of all contacts (internal and external)
  1325. $contacts = $ticketstat->getInfosTicketInternalContact(1);
  1326. $contacts = array_merge($contacts, $ticketstat->getInfosTicketExternalContact(1));
  1327. $sendto = array();
  1328. // Build array to display recipient list
  1329. if (is_array($contacts) && count($contacts) > 0) {
  1330. foreach ($contacts as $key => $info_sendto) {
  1331. if ($info_sendto['email'] != '') {
  1332. $sendto[] = dol_escape_htmltag(trim($info_sendto['firstname']." ".$info_sendto['lastname'])." <".$info_sendto['email'].">").' <small class="opacitymedium">('.dol_escape_htmltag($info_sendto['libelle']).")</small>";
  1333. }
  1334. }
  1335. }
  1336. if ($ticketstat->origin_email && !in_array($ticketstat->origin_email, $sendto)) {
  1337. $sendto[] = dol_escape_htmltag($ticketstat->origin_email).' <small class="opacitymedium">('.$langs->trans("TicketEmailOriginIssuer").")</small>";
  1338. }
  1339. if ($ticketstat->fk_soc > 0) {
  1340. $ticketstat->socid = $ticketstat->fk_soc;
  1341. $ticketstat->fetch_thirdparty();
  1342. if (!empty($ticketstat->thirdparty->email) && !in_array($ticketstat->thirdparty->email, $sendto)) {
  1343. $sendto[] = $ticketstat->thirdparty->email.' <small class="opacitymedium">('.$langs->trans('Customer').')</small>';
  1344. }
  1345. }
  1346. if (getDolGlobalInt('TICKET_NOTIFICATION_ALSO_MAIN_ADDRESS')) {
  1347. $sendto[] = getDolGlobalString('TICKET_NOTIFICATION_EMAIL_TO').' <small class="opacitymedium">(generic email)</small>';
  1348. }
  1349. // Print recipient list
  1350. if (is_array($sendto) && count($sendto) > 0) {
  1351. print img_picto('', 'email', 'class="pictofixedwidth"');
  1352. print implode(', ', $sendto);
  1353. } else {
  1354. print '<div class="warning">'.$langs->trans('WarningNoEMailsAdded').' '.$langs->trans('TicketGoIntoContactTab').'</div>';
  1355. }
  1356. }
  1357. print '</td></tr>';
  1358. }
  1359. $uselocalbrowser = false;
  1360. // Intro
  1361. // External users can't send message email
  1362. /*
  1363. if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_INTRO)) {
  1364. $mail_intro = GETPOST('mail_intro') ? GETPOST('mail_intro') : $conf->global->TICKET_MESSAGE_MAIL_INTRO;
  1365. print '<tr class="email_line"><td><label for="mail_intro">';
  1366. print $form->textwithpicto($langs->trans("TicketMessageMailIntro"), $langs->trans("TicketMessageMailIntroHelp"), 1, 'help');
  1367. print '</label>';
  1368. print '</td><td>';
  1369. include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  1370. $doleditor = new DolEditor('mail_intro', $mail_intro, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_2, 70);
  1371. $doleditor->Create();
  1372. print '</td></tr>';
  1373. }
  1374. */
  1375. // Attached files
  1376. if (!empty($this->withfile)) {
  1377. $out = '<tr>';
  1378. $out .= '<td>'.$langs->trans("MailFile").'</td>';
  1379. $out .= '<td>';
  1380. // TODO Trick to have param removedfile containing nb of image to delete. But this does not works without javascript
  1381. $out .= '<input type="hidden" class="removedfilehidden" name="removedfile" value="">'."\n";
  1382. $out .= '<script nonce="'.getNonce().'" type="text/javascript">';
  1383. $out .= 'jQuery(document).ready(function () {';
  1384. $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
  1385. $out .= ' jQuery("#addedfile").on("change", function() {';
  1386. $out .= ' if (jQuery(this).val().length) {';
  1387. $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", false);';
  1388. $out .= ' } else {';
  1389. $out .= ' jQuery("#'.$addfileaction.'").prop("disabled", true);';
  1390. $out .= ' }';
  1391. $out .= ' });';
  1392. $out .= ' jQuery(".removedfile").click(function() {';
  1393. $out .= ' jQuery(".removedfilehidden").val(jQuery(this).val());';
  1394. $out .= ' });';
  1395. $out .= '})';
  1396. $out .= '</script>'."\n";
  1397. if (count($listofpaths)) {
  1398. foreach ($listofpaths as $key => $val) {
  1399. $out .= '<div id="attachfile_'.$key.'">';
  1400. $out .= img_mime($listofnames[$key]).' '.$listofnames[$key];
  1401. if (!$this->withfilereadonly) {
  1402. $out .= ' <input type="image" style="border: 0px;" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/delete.png" value="'.($key + 1).'" class="removedfile reposition" id="removedfile_'.$key.'" name="removedfile_'.$key.'" />';
  1403. }
  1404. $out .= '<br></div>';
  1405. }
  1406. } else {
  1407. //$out .= $langs->trans("NoAttachedFiles").'<br>';
  1408. }
  1409. if ($this->withfile == 2) { // Can add other files
  1410. $out .= '<input type="file" class="flat" id="addedfile" name="addedfile" value="'.$langs->trans("Upload").'" />';
  1411. $out .= ' ';
  1412. $out .= '<input type="submit" class="button smallpaddingimp reposition" id="'.$addfileaction.'" name="'.$addfileaction.'" value="'.$langs->trans("MailingAddFile").'" />';
  1413. }
  1414. $out .= "</td></tr>\n";
  1415. print $out;
  1416. }
  1417. // MESSAGE
  1418. $defaultmessage = "";
  1419. if (is_object($arraydefaultmessage) && $arraydefaultmessage->content) {
  1420. $defaultmessage = $arraydefaultmessage->content;
  1421. }
  1422. $defaultmessage = str_replace('\n', "\n", $defaultmessage);
  1423. // Deal with format differences between message and signature (text / HTML)
  1424. if (dol_textishtml($defaultmessage) && !dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
  1425. $this->substit['__USER_SIGNATURE__'] = dol_nl2br($this->substit['__USER_SIGNATURE__']);
  1426. } elseif (!dol_textishtml($defaultmessage) && isset($this->substit['__USER_SIGNATURE__']) && dol_textishtml($this->substit['__USER_SIGNATURE__'])) {
  1427. $defaultmessage = dol_nl2br($defaultmessage);
  1428. }
  1429. if (GETPOSTISSET("message") && !GETPOST('modelselected')) {
  1430. $defaultmessage = GETPOST('message', 'restricthtml');
  1431. } else {
  1432. $defaultmessage = make_substitutions($defaultmessage, $this->substit);
  1433. // Clean first \n and br (to avoid empty line when CONTACTCIVNAME is empty)
  1434. $defaultmessage = preg_replace("/^(<br>)+/", "", $defaultmessage);
  1435. $defaultmessage = preg_replace("/^\n+/", "", $defaultmessage);
  1436. }
  1437. print '<tr><td colspan="2"><label for="message"><span class="fieldrequired">'.$langs->trans("Message").'</span>';
  1438. if ($user->hasRight("ticket", "write") && !$user->socid) {
  1439. $texttooltip = $langs->trans("TicketMessageHelp");
  1440. if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO') || getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
  1441. $texttooltip .= '<br><br>'.$langs->trans("ForEmailMessageWillBeCompletedWith").'...';
  1442. }
  1443. if (getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO')) {
  1444. $texttooltip .= '<br><u>'.$langs->trans("TicketMessageMailIntro").'</u><br>'.getDolGlobalString('TICKET_MESSAGE_MAIL_INTRO');
  1445. }
  1446. if (getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE')) {
  1447. $texttooltip .= '<br><br><u>'.$langs->trans("TicketMessageMailFooter").'</u><br>'.getDolGlobalString('TICKET_MESSAGE_MAIL_SIGNATURE');
  1448. }
  1449. print $form->textwithpicto('', $texttooltip, 1, 'help');
  1450. }
  1451. print '</label></td></tr>';
  1452. print '<tr><td colspan="2">';
  1453. //$toolbarname = 'dolibarr_details';
  1454. $toolbarname = 'dolibarr_notes';
  1455. include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  1456. $doleditor = new DolEditor('message', $defaultmessage, '100%', 200, $toolbarname, '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_TICKET'), ROWS_5, '90%');
  1457. $doleditor->Create();
  1458. print '</td></tr>';
  1459. // Footer
  1460. // External users can't send message email
  1461. /*if ($user->rights->ticket->write && !$user->socid && !empty($conf->global->TICKET_MESSAGE_MAIL_SIGNATURE)) {
  1462. $mail_signature = GETPOST('mail_signature') ? GETPOST('mail_signature') : $conf->global->TICKET_MESSAGE_MAIL_SIGNATURE;
  1463. print '<tr class="email_line"><td><label for="mail_intro">'.$langs->trans("TicketMessageMailFooter").'</label>';
  1464. print $form->textwithpicto('', $langs->trans("TicketMessageMailFooterHelp"), 1, 'help');
  1465. print '</td><td>';
  1466. include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  1467. $doleditor = new DolEditor('mail_signature', $mail_signature, '100%', 90, 'dolibarr_details', '', false, $uselocalbrowser, getDolGlobalInt('FCKEDITOR_ENABLE_SOCIETE'), ROWS_2, 70);
  1468. $doleditor->Create();
  1469. print '</td></tr>';
  1470. }
  1471. */
  1472. print '</table>';
  1473. print '<br><center>';
  1474. print '<input type="submit" class="button" name="btn_add_message" value="'.$langs->trans("Add").'"';
  1475. // Add a javascript test to avoid to forget to submit file before sending email
  1476. if ($this->withfile == 2 && !empty($conf->use_javascript_ajax)) {
  1477. print ' onClick="if (document.ticket.addedfile.value != \'\') { alert(\''.dol_escape_js($langs->trans("FileWasNotUploaded")).'\'); return false; } else { return true; }"';
  1478. }
  1479. print ' />';
  1480. if (!empty($this->withcancel)) {
  1481. print " &nbsp; &nbsp; ";
  1482. print '<input class="button button-cancel" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
  1483. }
  1484. print "</center>\n";
  1485. print '<input type="hidden" name="page_y">'."\n";
  1486. print "</form><br>\n";
  1487. // Disable enter key if option MAIN_MAILFORM_DISABLE_ENTERKEY is set
  1488. if (getDolGlobalString('MAIN_MAILFORM_DISABLE_ENTERKEY')) {
  1489. print '<script type="text/javascript">';
  1490. print 'jQuery(document).ready(function () {';
  1491. print ' $(document).on("keypress", \'#ticket\', function (e) { /* Note this is called at every key pressed ! */
  1492. var code = e.keyCode || e.which;
  1493. if (code == 13) {
  1494. console.log("Enter was intercepted and blocked");
  1495. e.preventDefault();
  1496. return false;
  1497. }
  1498. });';
  1499. print '})';
  1500. print '</script>';
  1501. }
  1502. print "<!-- End form TICKET -->\n";
  1503. }
  1504. }