html.formticket.class.php 67 KB

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