html.formticket.class.php 70 KB

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