html.formticket.class.php 57 KB

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