html.formticket.class.php 69 KB

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