dolibarr  18.0.6
html.form.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5  * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6  * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7  * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9  * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10  * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11  * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12  * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13  * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14  * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15  * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17  * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18  * Copyright (C) 2014-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
19  * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20  * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
21  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22  * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23  * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24  * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25  *
26  * This program is free software; you can redistribute it and/or modify
27  * it under the terms of the GNU General Public License as published by
28  * the Free Software Foundation; either version 3 of the License, or
29  * (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program. If not, see <https://www.gnu.org/licenses/>.
38  */
39 
53 class Form
54 {
58  public $db;
59 
63  public $error = '';
64 
68  public $errors = array();
69 
70  // Some properties used to return data by some methods
71  public $result;
72  public $num;
73 
74  // Cache arrays
75  public $cache_types_paiements = array();
76  public $cache_conditions_paiements = array();
77  public $cache_transport_mode = array();
78  public $cache_availability = array();
79  public $cache_demand_reason = array();
80  public $cache_types_fees = array();
81  public $cache_vatrates = array();
82 
83 
89  public function __construct($db)
90  {
91  $this->db = $db;
92  }
93 
110  public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
111  {
112  global $conf, $langs;
113 
114  $ret = '';
115 
116  // TODO change for compatibility
117  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) {
118  if (!empty($perm)) {
119  $tmp = explode(':', $typeofdata);
120  $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
121  if ($fieldrequired) {
122  $ret .= '<span class="fieldrequired">';
123  }
124  if ($help) {
125  $ret .= $this->textwithpicto($langs->trans($text), $help);
126  } else {
127  $ret .= $langs->trans($text);
128  }
129  if ($fieldrequired) {
130  $ret .= '</span>';
131  }
132  $ret .= '</div>' . "\n";
133  } else {
134  if ($fieldrequired) {
135  $ret .= '<span class="fieldrequired">';
136  }
137  if ($help) {
138  $ret .= $this->textwithpicto($langs->trans($text), $help);
139  } else {
140  $ret .= $langs->trans($text);
141  }
142  if ($fieldrequired) {
143  $ret .= '</span>';
144  }
145  }
146  } else {
147  if (empty($notabletag) && $perm) {
148  $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
149  }
150  if ($fieldrequired) {
151  $ret .= '<span class="fieldrequired">';
152  }
153  if ($help) {
154  $ret .= $this->textwithpicto($langs->trans($text), $help);
155  } else {
156  $ret .= $langs->trans($text);
157  }
158  if ($fieldrequired) {
159  $ret .= '</span>';
160  }
161  if (!empty($notabletag)) {
162  $ret .= ' ';
163  }
164  if (empty($notabletag) && $perm) {
165  $ret .= '</td>';
166  }
167  if (empty($notabletag) && $perm) {
168  $ret .= '<td class="right">';
169  }
170  if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
171  $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
172  }
173  if (!empty($notabletag) && $notabletag == 1) {
174  if ($text) {
175  $ret .= ' : ';
176  } else {
177  $ret .= ' ';
178  }
179  }
180  if (!empty($notabletag) && $notabletag == 3) {
181  $ret .= ' ';
182  }
183  if (empty($notabletag) && $perm) {
184  $ret .= '</td>';
185  }
186  if (empty($notabletag) && $perm) {
187  $ret .= '</tr></table>';
188  }
189  }
190 
191  return $ret;
192  }
193 
217  public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
218  {
219  global $conf, $langs;
220 
221  $ret = '';
222 
223  // Check parameters
224  if (empty($typeofdata)) {
225  return 'ErrorBadParameter typeofdata is empty';
226  }
227  // Clean paramater $typeofdata
228  if ($typeofdata == 'datetime') {
229  $typeofdata = 'dayhour';
230  }
231  $reg = array();
232  if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
233  if ($reg[1] == 'varchar') {
234  $typeofdata = 'string';
235  } elseif ($reg[1] == 'int') {
236  $typeofdata = 'numeric';
237  } else {
238  return 'ErrorBadParameter ' . $typeofdata;
239  }
240  }
241 
242  // When option to edit inline is activated
243  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
244  $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
245  } else {
246  if ($editaction == '') {
247  $editaction = GETPOST('action', 'aZ09');
248  }
249  $editmode = ($editaction == 'edit' . $htmlname);
250  if ($editmode) { // edit mode
251  $ret .= "\n";
252  $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
253  $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
254  $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
255  $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
256  if (empty($notabletag)) {
257  $ret .= '<table class="nobordernopadding centpercent">';
258  }
259  if (empty($notabletag)) {
260  $ret .= '<tr><td>';
261  }
262  if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
263  $tmp = explode(':', $typeofdata);
264  $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
265  } elseif (preg_match('/^(integer)/', $typeofdata)) {
266  $tmp = explode(':', $typeofdata);
267  $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
268  $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
269  } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
270  $tmp = explode(':', $typeofdata);
271  $valuetoshow = price2num($editvalue ? $editvalue : $value);
272  $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
273  } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
274  $tmp = explode(':', $typeofdata);
275  $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
276  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
277  $tmp = explode(':', $typeofdata);
278  $cols = (empty($tmp[2]) ? '' : $tmp[2]);
279  $morealt = '';
280  if (preg_match('/%/', $cols)) {
281  $morealt = ' style="width: ' . $cols . '"';
282  $cols = '';
283  }
284  $valuetoshow = ($editvalue ? $editvalue : $value);
285  $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
286  // textarea convert automatically entities chars into simple chars.
287  // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwig is off.
288  $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
289  $ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
290  $ret .= '</textarea>';
291  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
292  $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
293  $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
294  $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
295  $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
296  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
297  $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
298  $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
299  $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
300  $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
301  } elseif (preg_match('/^select;/', $typeofdata)) {
302  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
303  $arraylist = array();
304  foreach ($arraydata as $val) {
305  $tmp = explode(':', $val);
306  $tmpkey = str_replace('|', ':', $tmp[0]);
307  $arraylist[$tmpkey] = $tmp[1];
308  }
309  $ret .= $this->selectarray($htmlname, $arraylist, $value);
310  } elseif (preg_match('/^link/', $typeofdata)) {
311  // TODO Not yet implemented. See code for extrafields
312  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
313  $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
314  require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
315  $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? '100' : $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? 0 : $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? '20' : $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
316  $ret .= $doleditor->Create(1);
317  } elseif ($typeofdata == 'asis') {
318  $ret .= ($editvalue ? $editvalue : $value);
319  }
320  if (empty($notabletag)) {
321  $ret .= '</td>';
322  }
323 
324  // Button save-cancel
325  if (empty($notabletag)) {
326  $ret .= '<td>';
327  }
328  //else $ret.='<div class="clearboth"></div>';
329  $ret .= '<input type="submit" class="smallpaddingimp button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
330  if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
331  $ret .= '<br>' . "\n";
332  }
333  $ret .= '<input type="submit" class="smallpaddingimp button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
334  if (empty($notabletag)) {
335  $ret .= '</td>';
336  }
337 
338  if (empty($notabletag)) {
339  $ret .= '</tr></table>' . "\n";
340  }
341  $ret .= '</form>' . "\n";
342  } else { // view mode
343  if (preg_match('/^email/', $typeofdata)) {
344  $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
345  } elseif (preg_match('/^phone/', $typeofdata)) {
346  $ret .= dol_print_phone($value, '_blank', 32, 1);
347  } elseif (preg_match('/^url/', $typeofdata)) {
348  $ret .= dol_print_url($value, '_blank', 32, 1);
349  } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
350  $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
351  } elseif (preg_match('/^checkbox/', $typeofdata)) {
352  $tmp = explode(':', $typeofdata);
353  $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
354  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
355  $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($value), 1, 1, 1);
356  } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
357  $ret .= dol_string_onlythesehtmltags($value);
358  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
359  $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
360  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
361  $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
362  } elseif (preg_match('/^select;/', $typeofdata)) {
363  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
364  $arraylist = array();
365  foreach ($arraydata as $val) {
366  $tmp = explode(':', $val);
367  $arraylist[$tmp[0]] = $tmp[1];
368  }
369  $ret .= $arraylist[$value];
370  if ($htmlname == 'fk_product_type') {
371  if ($value == 0) {
372  $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
373  } else {
374  $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
375  }
376  }
377  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
378  $tmpcontent = dol_htmlentitiesbr($value);
379  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
380  $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
381  $firstline = preg_replace('/[\n\r].*/', '', $firstline);
382  $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
383  }
384  // We dont use dol_escape_htmltag to get the html formating active, but this need we must also
385  // clean data from some dangerous html
386  $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent));
387  } else {
388  if (empty($moreoptions['valuealreadyhtmlescaped'])) {
389  $ret .= dol_escape_htmltag($value);
390  } else {
391  $ret .= $value; // $value must be already html escaped.
392  }
393  }
394 
395  // Custom format if parameter $formatfunc has been provided
396  if ($formatfunc && method_exists($object, $formatfunc)) {
397  $ret = $object->$formatfunc($ret);
398  }
399  }
400  }
401  return $ret;
402  }
403 
415  public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
416  {
417  global $conf, $langs, $extralanguages;
418 
419  $result = '';
420 
421  // List of extra languages
422  $arrayoflangcode = array();
423  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
424  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
425  }
426 
427  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
428  if (!is_object($extralanguages)) {
429  include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
430  $extralanguages = new ExtraLanguages($this->db);
431  }
432  $extralanguages->fetch_name_extralanguages('societe');
433 
434  if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
435  return ''; // No extralang field to show
436  }
437 
438  $result .= '<!-- Widget for translation -->' . "\n";
439  $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
440  $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
441  $result .= $s;
442  $result .= '</div>';
443 
444  $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
445 
446  $resultforextrlang = '';
447  foreach ($arrayoflangcode as $langcode) {
448  $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
449  if (empty($valuetoshow)) {
450  $object->fetchValuesForExtraLanguages();
451  //var_dump($object->array_languages);
452  $valuetoshow = $object->array_languages[$fieldname][$langcode];
453  }
454 
455  $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
456  $resultforextrlang .= $s;
457 
458  // TODO Use the showInputField() method of ExtraLanguages object
459  if ($typeofdata == 'textarea') {
460  $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
461  $resultforextrlang .= $valuetoshow;
462  $resultforextrlang .= '</textarea>';
463  } else {
464  $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
465  }
466  }
467  $result .= $resultforextrlang;
468 
469  $result .= '</div>';
470  $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
471  }
472 
473  return $result;
474  }
475 
489  protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
490  {
491  global $conf;
492 
493  $out = '';
494 
495  // Check parameters
496  if (preg_match('/^text/', $inputType)) {
497  $value = dol_nl2br($value);
498  } elseif (preg_match('/^numeric/', $inputType)) {
499  $value = price($value);
500  } elseif ($inputType == 'day' || $inputType == 'datepicker') {
501  $value = dol_print_date($value, 'day');
502  }
503 
504  if ($condition) {
505  $element = false;
506  $table_element = false;
507  $fk_element = false;
508  $loadmethod = false;
509  $savemethod = false;
510  $ext_element = false;
511  $button_only = false;
512  $inputOption = '';
513  $rows = '';
514  $cols = '';
515 
516  if (is_object($object)) {
517  $element = $object->element;
518  $table_element = $object->table_element;
519  $fk_element = $object->id;
520  }
521 
522  if (is_object($extObject)) {
523  $ext_element = $extObject->element;
524  }
525 
526  if (preg_match('/^(string|email|numeric)/', $inputType)) {
527  $tmp = explode(':', $inputType);
528  $inputType = $tmp[0];
529  if (!empty($tmp[1])) {
530  $inputOption = $tmp[1];
531  }
532  if (!empty($tmp[2])) {
533  $savemethod = $tmp[2];
534  }
535  $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
536  } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
537  $tmp = explode(':', $inputType);
538  $inputType = $tmp[0];
539  if (!empty($tmp[1])) {
540  $inputOption = $tmp[1];
541  }
542  if (!empty($tmp[2])) {
543  $savemethod = $tmp[2];
544  }
545 
546  $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
547  } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
548  $tmp = explode(':', $inputType);
549  $inputType = $tmp[0];
550  $loadmethod = $tmp[1];
551  if (!empty($tmp[2])) {
552  $savemethod = $tmp[2];
553  }
554  if (!empty($tmp[3])) {
555  $button_only = true;
556  }
557  } elseif (preg_match('/^textarea/', $inputType)) {
558  $tmp = explode(':', $inputType);
559  $inputType = $tmp[0];
560  $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
561  $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
562  } elseif (preg_match('/^ckeditor/', $inputType)) {
563  $tmp = explode(':', $inputType);
564  $inputType = $tmp[0];
565  $toolbar = $tmp[1];
566  if (!empty($tmp[2])) {
567  $width = $tmp[2];
568  }
569  if (!empty($tmp[3])) {
570  $heigth = $tmp[3];
571  }
572  if (!empty($tmp[4])) {
573  $savemethod = $tmp[4];
574  }
575 
576  if (isModEnabled('fckeditor')) {
577  $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
578  } else {
579  $inputType = 'textarea';
580  }
581  }
582 
583  $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
584  $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
585  $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
586  $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
587  if (!empty($savemethod)) {
588  $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
589  }
590  if (!empty($ext_element)) {
591  $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
592  }
593  if (!empty($custommsg)) {
594  if (is_array($custommsg)) {
595  if (!empty($custommsg['success'])) {
596  $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
597  }
598  if (!empty($custommsg['error'])) {
599  $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
600  }
601  } else {
602  $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
603  }
604  }
605  if ($inputType == 'textarea') {
606  $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
607  $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
608  }
609  $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
610  $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
611  } else {
612  $out = $value;
613  }
614 
615  return $out;
616  }
617 
636  public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
637  {
638  if ($incbefore) {
639  $text = $incbefore . $text;
640  }
641  if (!$htmltext) {
642  return $text;
643  }
644  $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
645 
646  $tag = 'td';
647  if ($notabs == 2) {
648  $tag = 'div';
649  }
650  if ($notabs == 3) {
651  $tag = 'span';
652  }
653  // Sanitize tooltip
654  $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
655 
656  $extrastyle = '';
657  if ($direction < 0) {
658  $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
659  $extrastyle = 'padding: 0px; padding-left: 3px;';
660  }
661  if ($direction > 0) {
662  $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
663  $extrastyle = 'padding: 0px; padding-right: 3px;';
664  }
665 
666  $classfortooltip = 'classfortooltip';
667 
668  $s = '';
669  $textfordialog = '';
670 
671  if ($tooltiptrigger == '') {
672  $htmltext = str_replace('"', '&quot;', $htmltext);
673  } else {
674  $classfortooltip = 'classfortooltiponclick';
675  $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
676  }
677  if ($tooltipon == 2 || $tooltipon == 3) {
678  $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
679  if ($tooltiptrigger == '') {
680  $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on img tag to store tooltip
681  } else {
682  $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
683  }
684  } else {
685  $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag
686  }
687  if ($tooltipon == 1 || $tooltipon == 3) {
688  $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
689  if ($tooltiptrigger == '') {
690  $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribut to put on td tag to store tooltip
691  } else {
692  $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
693  }
694  } else {
695  $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribut to put on td text tag
696  }
697  if (empty($notabs)) {
698  $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
699  } elseif ($notabs == 2) {
700  $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
701  }
702  // Define value if value is before
703  if ($direction < 0) {
704  $s .= '<' . $tag . $paramfortooltipimg;
705  if ($tag == 'td') {
706  $s .= ' class="valigntop" width="14"';
707  }
708  $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
709  }
710  // Use another method to help avoid having a space in value in order to use this value with jquery
711  // Define label
712  if ((string) $text != '') {
713  $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
714  }
715  // Define value if value is after
716  if ($direction > 0) {
717  $s .= '<' . $tag . $paramfortooltipimg;
718  if ($tag == 'td') {
719  $s .= ' class="valignmiddle" width="14"';
720  }
721  $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
722  }
723  if (empty($notabs)) {
724  $s .= '</tr></table>';
725  } elseif ($notabs == 2) {
726  $s .= '</div>';
727  }
728 
729  return $s;
730  }
731 
746  public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
747  {
748  global $conf, $langs;
749 
750  //For backwards compatibility
751  if ($type == '0') {
752  $type = 'info';
753  } elseif ($type == '1') {
754  $type = 'help';
755  }
756 
757  if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
758  $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
759  }
760 
761  $alt = '';
762  if ($tooltiptrigger) {
763  $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
764  }
765 
766  // If info or help with no javascript, show only text
767  if (empty($conf->use_javascript_ajax)) {
768  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
769  return $text;
770  } else {
771  $alt = $htmltext;
772  $htmltext = '';
773  }
774  }
775 
776  // If info or help with smartphone, show only text (tooltip hover can't works)
777  if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
778  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
779  return $text;
780  }
781  }
782  // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
783  //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
784  //{
785  //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
786  //}
787 
788  $img = '';
789  if ($type == 'info') {
790  $img = img_help(0, $alt);
791  } elseif ($type == 'help') {
792  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
793  } elseif ($type == 'helpclickable') {
794  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
795  } elseif ($type == 'superadmin') {
796  $img = img_picto($alt, 'redstar');
797  } elseif ($type == 'admin') {
798  $img = img_picto($alt, 'star');
799  } elseif ($type == 'warning') {
800  $img = img_warning($alt);
801  } elseif ($type != 'none') {
802  $img = img_picto($alt, $type); // $type can be an image path
803  }
804 
805  return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
806  }
807 
818  public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
819  {
820  global $conf, $langs, $hookmanager;
821 
822  $disabled = 0;
823  $ret = '<div class="centpercent center">';
824  $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
825 
826  // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks.
827  $parameters = array();
828  $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
829  // check if there is a mass action
830  if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
831  return;
832  }
833  if (empty($reshook)) {
834  $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
835  foreach ($arrayofaction as $code => $label) {
836  $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
837  }
838  }
839  $ret .= $hookmanager->resPrint;
840 
841  $ret .= '</select>';
842 
843  if (empty($conf->dol_optimize_smallscreen)) {
844  $ret .= ajax_combobox('.' . $name . 'select');
845  }
846 
847  // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button
848  $ret .= '<input type="submit" name="confirmmassactioninvisible" style="display: none" tabindex="-1">'; // Hidden button BEFORE so it is the one used when we submit with ENTER.
849  $ret .= '<input type="submit" disabled name="confirmmassaction"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display: none"') . ' class="reposition button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">';
850  $ret .= '</div>';
851 
852  if (!empty($conf->use_javascript_ajax)) {
853  $ret .= '<!-- JS CODE TO ENABLE mass action select -->
854  <script nonce="' . getNonce() . '">
855  function initCheckForSelect(mode, name, cssclass) /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
856  {
857  atleastoneselected=0;
858  jQuery("."+cssclass).each(function( index ) {
859  /* console.log( index + ": " + $( this ).text() ); */
860  if ($(this).is(\':checked\')) atleastoneselected++;
861  });
862 
863  console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
864 
865  if (atleastoneselected || ' . $alwaysvisible . ')
866  {
867  jQuery("."+name).show();
868  ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
869  ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
870  }
871  else
872  {
873  jQuery("."+name).hide();
874  jQuery("."+name+"other").hide();
875  }
876  }
877 
878  jQuery(document).ready(function () {
879  initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
880  jQuery(".' . $cssclass . '").click(function() {
881  initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
882  });
883  jQuery(".' . $name . 'select").change(function() {
884  var massaction = $( this ).val();
885  var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
886  if (massaction == "builddoc")
887  {
888  urlform = urlform + "#show_files";
889  }
890  $( this ).closest("form").attr("action", urlform);
891  console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
892  /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
893  if ($(this).val() != \'0\')
894  {
895  jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
896  jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
897  jQuery(".' . $name . '"+massaction).show();
898  }
899  else
900  {
901  jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
902  jQuery(".' . $name . 'other").hide(); /* To disable any div open */
903  }
904  });
905  });
906  </script>
907  ';
908  }
909 
910  return $ret;
911  }
912 
913  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
914 
931  public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
932  {
933  // phpcs:enable
934  global $conf, $langs, $mysoc;
935 
936  $langs->load("dict");
937 
938  $out = '';
939  $countryArray = array();
940  $favorite = array();
941  $label = array();
942  $atleastonefavorite = 0;
943 
944  $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
945  $sql .= " FROM " . $this->db->prefix() . "c_country";
946  $sql .= " WHERE active > 0";
947  //$sql.= " ORDER BY code ASC";
948 
949  dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
950  $resql = $this->db->query($sql);
951  if ($resql) {
952  $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
953  $num = $this->db->num_rows($resql);
954  $i = 0;
955  if ($num) {
956  while ($i < $num) {
957  $obj = $this->db->fetch_object($resql);
958 
959  $countryArray[$i]['rowid'] = $obj->rowid;
960  $countryArray[$i]['code_iso'] = $obj->code_iso;
961  $countryArray[$i]['code_iso3'] = $obj->code_iso3;
962  $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country" . $obj->code_iso) != "Country" . $obj->code_iso ? $langs->transnoentitiesnoconv("Country" . $obj->code_iso) : ($obj->label != '-' ? $obj->label : ''));
963  $countryArray[$i]['favorite'] = $obj->favorite;
964  $countryArray[$i]['eec'] = $obj->eec;
965  $favorite[$i] = $obj->favorite;
966  $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
967  $i++;
968  }
969 
970  if (empty($disablefavorites)) {
971  $array1_sort_order = SORT_DESC;
972  $array2_sort_order = SORT_ASC;
973  array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
974  } else {
975  $countryArray = dol_sort_array($countryArray, 'label');
976  }
977 
978  if ($showempty) {
979  if (is_numeric($showempty)) {
980  $out .= '<option value="">&nbsp;</option>' . "\n";
981  } else {
982  $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
983  }
984  }
985 
986  if ($addspecialentries) { // Add dedicated entries for groups of countries
987  //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
988  $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
989  $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
990  if ($mysoc->isInEEC()) {
991  $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
992  }
993  $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
994  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
995  }
996 
997  foreach ($countryArray as $row) {
998  //if (empty($showempty) && empty($row['rowid'])) continue;
999  if (empty($row['rowid'])) {
1000  continue;
1001  }
1002  if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1003  continue; // exclude some countries
1004  }
1005 
1006  if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1007  $atleastonefavorite++;
1008  }
1009  if (empty($row['favorite']) && $atleastonefavorite) {
1010  $atleastonefavorite = 0;
1011  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1012  }
1013 
1014  $labeltoshow = '';
1015  if ($row['label']) {
1016  $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1017  } else {
1018  $labeltoshow .= '&nbsp;';
1019  }
1020  if ($row['code_iso']) {
1021  $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1022  if (empty($hideflags)) {
1023  $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1024  $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1025  }
1026  }
1027 
1028  if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1029  $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1030  } else {
1031  $out .= '<option value="' . ($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']) . '" data-html="' . dol_escape_htmltag($labeltoshow) . '" data-eec="' . ((int) $row['eec']) . '">';
1032  }
1033  $out .= $labeltoshow;
1034  $out .= '</option>' . "\n";
1035  }
1036  }
1037  $out .= '</select>';
1038  } else {
1039  dol_print_error($this->db);
1040  }
1041 
1042  // Make select dynamic
1043  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1044  $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1045 
1046  return $out;
1047  }
1048 
1049  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1050 
1064  public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1065  {
1066  // phpcs:enable
1067  global $conf, $langs;
1068 
1069  $langs->load("dict");
1070 
1071  $out = '';
1072  $moreattrib = '';
1073  $incotermArray = array();
1074 
1075  $sql = "SELECT rowid, code";
1076  $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1077  $sql .= " WHERE active > 0";
1078  $sql .= " ORDER BY code ASC";
1079 
1080  dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1081  $resql = $this->db->query($sql);
1082  if ($resql) {
1083  if ($conf->use_javascript_ajax && !$forcecombo) {
1084  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1085  $out .= ajax_combobox($htmlname, $events);
1086  }
1087 
1088  if (!empty($page)) {
1089  $out .= '<form method="post" action="' . $page . '">';
1090  $out .= '<input type="hidden" name="action" value="set_incoterms">';
1091  $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1092  }
1093 
1094  $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1095  $out .= '<option value="0">&nbsp;</option>';
1096  $num = $this->db->num_rows($resql);
1097  $i = 0;
1098  if ($num) {
1099  while ($i < $num) {
1100  $obj = $this->db->fetch_object($resql);
1101  $incotermArray[$i]['rowid'] = $obj->rowid;
1102  $incotermArray[$i]['code'] = $obj->code;
1103  $i++;
1104  }
1105 
1106  foreach ($incotermArray as $row) {
1107  if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1108  $out .= '<option value="' . $row['rowid'] . '" selected>';
1109  } else {
1110  $out .= '<option value="' . $row['rowid'] . '">';
1111  }
1112 
1113  if ($row['code']) {
1114  $out .= $row['code'];
1115  }
1116 
1117  $out .= '</option>';
1118  }
1119  }
1120  $out .= '</select>';
1121 
1122  if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1123  $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1124  $moreattrib .= ' autocomplete="off"';
1125  }
1126  $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1127 
1128  if (!empty($page)) {
1129  $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1130  }
1131  } else {
1132  dol_print_error($this->db);
1133  }
1134 
1135  return $out;
1136  }
1137 
1138  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1139 
1151  public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1152  {
1153  // phpcs:enable
1154  global $langs, $conf;
1155 
1156  // If product & services are enabled or both disabled.
1157  if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1158  || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1159  if (empty($hidetext)) {
1160  print $langs->trans("Type") . ': ';
1161  }
1162  print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1163  if ($showempty) {
1164  print '<option value="-1"';
1165  if ($selected == -1) {
1166  print ' selected';
1167  }
1168  print '>&nbsp;</option>';
1169  }
1170 
1171  print '<option value="0"';
1172  if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1173  print ' selected';
1174  }
1175  print '>' . $langs->trans("Product");
1176 
1177  print '<option value="1"';
1178  if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1179  print ' selected';
1180  }
1181  print '>' . $langs->trans("Service");
1182 
1183  print '</select>';
1184  print ajax_combobox('select_' . $htmlname);
1185  //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1186  }
1187  if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1188  print $langs->trans("Service");
1189  print '<input type="hidden" name="' . $htmlname . '" value="1">';
1190  }
1191  if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1192  print $langs->trans("Product");
1193  print '<input type="hidden" name="' . $htmlname . '" value="0">';
1194  }
1195  if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1196  print '<input type="hidden" name="' . $htmlname . '" value="1">'; // By default we set on service for contract. If CONTRACT_SUPPORT_PRODUCTS is set, forceall should be 1 not -1
1197  }
1198  }
1199 
1200  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1201 
1207  public function load_cache_types_fees()
1208  {
1209  // phpcs:enable
1210  global $langs;
1211 
1212  $num = count($this->cache_types_fees);
1213  if ($num > 0) {
1214  return 0; // Cache already loaded
1215  }
1216 
1217  dol_syslog(__METHOD__, LOG_DEBUG);
1218 
1219  $langs->load("trips");
1220 
1221  $sql = "SELECT c.code, c.label";
1222  $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1223  $sql .= " WHERE active > 0";
1224 
1225  $resql = $this->db->query($sql);
1226  if ($resql) {
1227  $num = $this->db->num_rows($resql);
1228  $i = 0;
1229 
1230  while ($i < $num) {
1231  $obj = $this->db->fetch_object($resql);
1232 
1233  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1234  $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1235  $this->cache_types_fees[$obj->code] = $label;
1236  $i++;
1237  }
1238 
1239  asort($this->cache_types_fees);
1240 
1241  return $num;
1242  } else {
1243  dol_print_error($this->db);
1244  return -1;
1245  }
1246  }
1247 
1248  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1249 
1258  public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1259  {
1260  // phpcs:enable
1261  global $user, $langs;
1262 
1263  dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1264 
1265  $this->load_cache_types_fees();
1266 
1267  print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1268  if ($showempty) {
1269  print '<option value="-1"';
1270  if ($selected == -1) {
1271  print ' selected';
1272  }
1273  print '>&nbsp;</option>';
1274  }
1275 
1276  foreach ($this->cache_types_fees as $key => $value) {
1277  print '<option value="' . $key . '"';
1278  if ($key == $selected) {
1279  print ' selected';
1280  }
1281  print '>';
1282  print $value;
1283  print '</option>';
1284  }
1285 
1286  print '</select>';
1287  if ($user->admin) {
1288  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1289  }
1290  }
1291 
1292 
1293  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1294 
1316  public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array(), $showcode = 0)
1317  {
1318  // phpcs:enable
1319  global $conf, $user, $langs;
1320 
1321  $out = '';
1322 
1323  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1324  if (is_null($ajaxoptions)) {
1325  $ajaxoptions = array();
1326  }
1327 
1328  require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1329 
1330  // No immediate load of all database
1331  $placeholder = '';
1332  if ($selected && empty($selected_input_value)) {
1333  require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1334  $societetmp = new Societe($this->db);
1335  $societetmp->fetch($selected);
1336  $selected_input_value = $societetmp->name;
1337  unset($societetmp);
1338  }
1339 
1340  // mode 1
1341  $urloption = 'htmlname=' . urlencode(str_replace('.', '_', $htmlname)) . '&outjson=1&filter=' . urlencode($filter) . (empty($excludeids) ? '' : '&excludeids=' . join(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode($showtype) : '') . ($showcode ? '&showcode=' . urlencode($showcode) : '');
1342 
1343  $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1344  if (empty($hidelabel)) {
1345  print $langs->trans("RefOrLabel") . ' : ';
1346  } elseif ($hidelabel > 1) {
1347  $placeholder = $langs->trans("RefOrLabel");
1348  if ($hidelabel == 2) {
1349  $out .= img_picto($langs->trans("Search"), 'search');
1350  }
1351  }
1352  $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
1353  if ($hidelabel == 3) {
1354  $out .= img_picto($langs->trans("Search"), 'search');
1355  }
1356 
1357  $out .= ajax_event($htmlname, $events);
1358 
1359  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1360  } else {
1361  // Immediate load of all database
1362  $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1363  }
1364 
1365  return $out;
1366  }
1367 
1368  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1369 
1393  public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array(), $showcode = 0)
1394  {
1395  // phpcs:enable
1396  global $conf, $user, $langs;
1397  global $hookmanager;
1398 
1399  $out = '';
1400  $num = 0;
1401  $outarray = array();
1402 
1403  if ($selected === '') {
1404  $selected = array();
1405  } elseif (!is_array($selected)) {
1406  $selected = array($selected);
1407  }
1408 
1409  // Clean $filter that may contains sql conditions so sql code
1410  if (function_exists('testSqlAndScriptInject')) {
1411  if (testSqlAndScriptInject($filter, 3) > 0) {
1412  $filter = '';
1413  return 'SQLInjectionTryDetected';
1414  }
1415  }
1416 
1417  if (preg_match('/[\‍(\‍)]/', $filter)) {
1418  // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1419  $errormsg = '';
1420  $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1421 
1422  // Redo clean $filter that may contains sql conditions so sql code
1423  if (function_exists('testSqlAndScriptInject')) {
1424  if (testSqlAndScriptInject($filter, 3) > 0) {
1425  $filter = '';
1426  return 'SQLInjectionTryDetected';
1427  }
1428  }
1429  } else {
1430  // If not, we do nothing. We already no that there is no parenthesis
1431  // TODO Disallow this case in a future.
1432  dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1433  }
1434 
1435  // We search companies
1436  $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1437  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1438  $sql .= ", s.address, s.zip, s.town";
1439  $sql .= ", dictp.code as country_code";
1440  }
1441  $sql .= " FROM " . $this->db->prefix() . "societe as s";
1442  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1443  $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1444  }
1445  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1446  $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1447  }
1448  $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1449  if (!empty($user->socid)) {
1450  $sql .= " AND s.rowid = " . ((int) $user->socid);
1451  }
1452  if ($filter) {
1453  // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1454  // if not, by testSqlAndScriptInject() only.
1455  $sql .= " AND (" . $filter . ")";
1456  }
1457  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1458  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1459  }
1460  if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1461  $sql .= " AND s.status <> 0";
1462  }
1463  if (!empty($excludeids)) {
1464  $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(join(',', $excludeids)) . ")";
1465  }
1466  // Add where from hooks
1467  $parameters = array();
1468  $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1469  $sql .= $hookmanager->resPrint;
1470  // Add criteria
1471  if ($filterkey && $filterkey != '') {
1472  $sql .= " AND (";
1473  $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1474  // For natural search
1475  $scrit = explode(' ', $filterkey);
1476  $i = 0;
1477  if (count($scrit) > 1) {
1478  $sql .= "(";
1479  }
1480  foreach ($scrit as $crit) {
1481  if ($i > 0) {
1482  $sql .= " AND ";
1483  }
1484  $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1485  $i++;
1486  }
1487  if (count($scrit) > 1) {
1488  $sql .= ")";
1489  }
1490  if (isModEnabled('barcode')) {
1491  $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1492  }
1493  $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1494  $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1495  $sql .= ")";
1496  }
1497  $sql .= $this->db->order("nom", "ASC");
1498  $sql .= $this->db->plimit($limit, 0);
1499 
1500  // Build output string
1501  dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1502  $resql = $this->db->query($sql);
1503  if ($resql) {
1504  if (!$forcecombo) {
1505  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1506  $out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1507  }
1508 
1509  // Construct $out and $outarray
1510  $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1511 
1512  $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1513  if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1514  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1515  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1516  if ($showempty && !is_numeric($showempty)) {
1517  $textifempty = $langs->trans($showempty);
1518  } else {
1519  $textifempty .= $langs->trans("All");
1520  }
1521  }
1522  if ($showempty) {
1523  $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1524  }
1525 
1526  $companytemp = new Societe($this->db);
1527 
1528  $num = $this->db->num_rows($resql);
1529  $i = 0;
1530  if ($num) {
1531  while ($i < $num) {
1532  $obj = $this->db->fetch_object($resql);
1533  $label = '';
1534  if ($showcode || !empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) {
1535  if (($obj->client) && (!empty($obj->code_client))) {
1536  $label = $obj->code_client . ' - ';
1537  }
1538  if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1539  $label .= $obj->code_fournisseur . ' - ';
1540  }
1541  $label .= ' ' . $obj->name;
1542  } else {
1543  $label = $obj->name;
1544  }
1545 
1546  if (!empty($obj->name_alias)) {
1547  $label .= ' (' . $obj->name_alias . ')';
1548  }
1549 
1550  if (!empty($conf->global->SOCIETE_SHOW_VAT_IN_LIST) && !empty($obj->tva_intra)) {
1551  $label .= ' - '.$obj->tva_intra;
1552  }
1553 
1554  $labelhtml = $label;
1555 
1556  if ($showtype) {
1557  $companytemp->id = $obj->rowid;
1558  $companytemp->client = $obj->client;
1559  $companytemp->fournisseur = $obj->fournisseur;
1560  $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1561  if ($tmptype) {
1562  $labelhtml .= ' ' . $tmptype;
1563  }
1564 
1565  if ($obj->client || $obj->fournisseur) {
1566  $label .= ' (';
1567  }
1568  if ($obj->client == 1 || $obj->client == 3) {
1569  $label .= $langs->trans("Customer");
1570  }
1571  if ($obj->client == 2 || $obj->client == 3) {
1572  $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1573  }
1574  if ($obj->fournisseur) {
1575  $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1576  }
1577  if ($obj->client || $obj->fournisseur) {
1578  $label .= ')';
1579  }
1580  }
1581 
1582  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1583  $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1584  if (!empty($obj->country_code)) {
1585  $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1586  }
1587  $label .= $s;
1588  $labelhtml .= $s;
1589  }
1590 
1591  if (empty($outputmode)) {
1592  if (in_array($obj->rowid, $selected)) {
1593  $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1594  } else {
1595  $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1596  }
1597  } else {
1598  array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1599  }
1600 
1601  $i++;
1602  if (($i % 10) == 0) {
1603  $out .= "\n";
1604  }
1605  }
1606  }
1607  $out .= '</select>' . "\n";
1608  } else {
1609  dol_print_error($this->db);
1610  }
1611 
1612  $this->result = array('nbofthirdparties' => $num);
1613 
1614  if ($outputmode) {
1615  return $outarray;
1616  }
1617  return $out;
1618  }
1619 
1620 
1621  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1622 
1633  public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1634  {
1635  // phpcs:enable
1636  global $langs, $conf;
1637 
1638  // On recherche les remises
1639  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1640  $sql .= " re.description, re.fk_facture_source";
1641  $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
1642  $sql .= " WHERE re.fk_soc = " . (int) $socid;
1643  $sql .= " AND re.entity = " . $conf->entity;
1644  if ($filter) {
1645  $sql .= " AND " . $filter;
1646  }
1647  $sql .= " ORDER BY re.description ASC";
1648 
1649  dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
1650  $resql = $this->db->query($sql);
1651  if ($resql) {
1652  print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
1653  $num = $this->db->num_rows($resql);
1654 
1655  $qualifiedlines = $num;
1656 
1657  $i = 0;
1658  if ($num) {
1659  print '<option value="0">&nbsp;</option>';
1660  while ($i < $num) {
1661  $obj = $this->db->fetch_object($resql);
1662  $desc = dol_trunc($obj->description, 40);
1663  if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
1664  $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
1665  }
1666  if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
1667  $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
1668  }
1669  if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
1670  $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
1671  }
1672  if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
1673  $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
1674  }
1675 
1676  $selectstring = '';
1677  if ($selected > 0 && $selected == $obj->rowid) {
1678  $selectstring = ' selected';
1679  }
1680 
1681  $disabled = '';
1682  if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1683  $qualifiedlines--;
1684  $disabled = ' disabled';
1685  }
1686 
1687  if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1688  $tmpfac = new Facture($this->db);
1689  if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1690  $desc = $desc . ' - ' . $tmpfac->ref;
1691  }
1692  }
1693 
1694  print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
1695  $i++;
1696  }
1697  }
1698  print '</select>';
1699  print ajax_combobox('select_' . $htmlname);
1700 
1701  return $qualifiedlines;
1702  } else {
1703  dol_print_error($this->db);
1704  return -1;
1705  }
1706  }
1707 
1708  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1709 
1730  public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1731  {
1732  // phpcs:enable
1733  print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1734  return $this->num;
1735  }
1736 
1761  public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1762  {
1763  global $conf, $langs, $hookmanager, $action;
1764 
1765  $langs->load('companies');
1766 
1767  if (empty($htmlid)) {
1768  $htmlid = $htmlname;
1769  }
1770  $num = 0;
1771 
1772  if ($selected === '') {
1773  $selected = array();
1774  } elseif (!is_array($selected)) {
1775  $selected = array($selected);
1776  }
1777  $out = '';
1778 
1779  if (!is_object($hookmanager)) {
1780  include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1781  $hookmanager = new HookManager($this->db);
1782  }
1783 
1784  // We search third parties
1785  $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town";
1786  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1787  $sql .= ", s.nom as company, s.town AS company_town";
1788  }
1789  $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1790  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1791  $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1792  }
1793  $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1794  if ($socid > 0 || $socid == -1) {
1795  $sql .= " AND sp.fk_soc = " . ((int) $socid);
1796  }
1797  if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1798  $sql .= " AND sp.statut <> 0";
1799  }
1800  // Add where from hooks
1801  $parameters = array();
1802  $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1803  $sql .= $hookmanager->resPrint;
1804  $sql .= " ORDER BY sp.lastname ASC";
1805 
1806  dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1807  $resql = $this->db->query($sql);
1808  if ($resql) {
1809  $num = $this->db->num_rows($resql);
1810 
1811  if ($htmlname != 'none' && !$options_only) {
1812  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1813  }
1814 
1815  if ($showempty && !is_numeric($showempty)) {
1816  $textforempty = $showempty;
1817  $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1818  } else {
1819  if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1820  $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1821  }
1822  if ($showempty == 2) {
1823  $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1824  }
1825  }
1826 
1827  $i = 0;
1828  if ($num) {
1829  include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1830  $contactstatic = new Contact($this->db);
1831 
1832  while ($i < $num) {
1833  $obj = $this->db->fetch_object($resql);
1834 
1835  // Set email (or phones) and town extended infos
1836  $extendedInfos = '';
1837  if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1838  $extendedInfos = array();
1839  $email = trim($obj->email);
1840  if (!empty($email)) {
1841  $extendedInfos[] = $email;
1842  } else {
1843  $phone = trim($obj->phone);
1844  $phone_perso = trim($obj->phone_perso);
1845  $phone_mobile = trim($obj->phone_mobile);
1846  if (!empty($phone)) {
1847  $extendedInfos[] = $phone;
1848  }
1849  if (!empty($phone_perso)) {
1850  $extendedInfos[] = $phone_perso;
1851  }
1852  if (!empty($phone_mobile)) {
1853  $extendedInfos[] = $phone_mobile;
1854  }
1855  }
1856  $contact_town = trim($obj->contact_town);
1857  $company_town = trim($obj->company_town);
1858  if (!empty($contact_town)) {
1859  $extendedInfos[] = $contact_town;
1860  } elseif (!empty($company_town)) {
1861  $extendedInfos[] = $company_town;
1862  }
1863  $extendedInfos = implode(' - ', $extendedInfos);
1864  if (!empty($extendedInfos)) {
1865  $extendedInfos = ' - ' . $extendedInfos;
1866  }
1867  }
1868 
1869  $contactstatic->id = $obj->rowid;
1870  $contactstatic->lastname = $obj->lastname;
1871  $contactstatic->firstname = $obj->firstname;
1872  if ($obj->statut == 1) {
1873  if ($htmlname != 'none') {
1874  $disabled = 0;
1875  if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1876  $disabled = 1;
1877  }
1878  if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1879  $disabled = 1;
1880  }
1881  if (!empty($selected) && in_array($obj->rowid, $selected)) {
1882  $out .= '<option value="' . $obj->rowid . '"';
1883  if ($disabled) {
1884  $out .= ' disabled';
1885  }
1886  $out .= ' selected>';
1887  $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1888  if ($showfunction && $obj->poste) {
1889  $out .= ' (' . $obj->poste . ')';
1890  }
1891  if (($showsoc > 0) && $obj->company) {
1892  $out .= ' - (' . $obj->company . ')';
1893  }
1894  $out .= '</option>';
1895  } else {
1896  $out .= '<option value="' . $obj->rowid . '"';
1897  if ($disabled) {
1898  $out .= ' disabled';
1899  }
1900  $out .= '>';
1901  $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1902  if ($showfunction && $obj->poste) {
1903  $out .= ' (' . $obj->poste . ')';
1904  }
1905  if (($showsoc > 0) && $obj->company) {
1906  $out .= ' - (' . $obj->company . ')';
1907  }
1908  $out .= '</option>';
1909  }
1910  } else {
1911  if (in_array($obj->rowid, $selected)) {
1912  $out .= $contactstatic->getFullName($langs) . $extendedInfos;
1913  if ($showfunction && $obj->poste) {
1914  $out .= ' (' . $obj->poste . ')';
1915  }
1916  if (($showsoc > 0) && $obj->company) {
1917  $out .= ' - (' . $obj->company . ')';
1918  }
1919  }
1920  }
1921  }
1922  $i++;
1923  }
1924  } else {
1925  $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1926  $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1927  $out .= $labeltoshow;
1928  $out .= '</option>';
1929  }
1930 
1931  $parameters = array(
1932  'socid' => $socid,
1933  'htmlname' => $htmlname,
1934  'resql' => $resql,
1935  'out' => &$out,
1936  'showfunction' => $showfunction,
1937  'showsoc' => $showsoc,
1938  );
1939 
1940  $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1941 
1942  if ($htmlname != 'none' && !$options_only) {
1943  $out .= '</select>';
1944  }
1945 
1946  if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1947  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1948  $out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1949  }
1950 
1951  $this->num = $num;
1952  return $out;
1953  } else {
1954  dol_print_error($this->db);
1955  return -1;
1956  }
1957  }
1958 
1959  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1960 
1976  public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1977  {
1978  // phpcs:enable
1979  print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1980  }
1981 
1982  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1983 
2008  public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2009  {
2010  // phpcs:enable
2011  global $conf, $user, $langs, $hookmanager;
2012  global $action;
2013 
2014  // If no preselected user defined, we take current user
2015  if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
2016  $selected = $user->id;
2017  }
2018 
2019  if ($selected === '') {
2020  $selected = array();
2021  } elseif (!is_array($selected)) {
2022  $selected = array($selected);
2023  }
2024 
2025  $excludeUsers = null;
2026  $includeUsers = null;
2027 
2028  // Exclude some users
2029  if (is_array($exclude)) {
2030  $excludeUsers = implode(",", $exclude);
2031  }
2032  // Include some uses
2033  if (is_array($include)) {
2034  $includeUsers = implode(",", $include);
2035  } elseif ($include == 'hierarchy') {
2036  // Build list includeUsers to have only hierarchy
2037  $includeUsers = implode(",", $user->getAllChildIds(0));
2038  } elseif ($include == 'hierarchyme') {
2039  // Build list includeUsers to have only hierarchy and current user
2040  $includeUsers = implode(",", $user->getAllChildIds(1));
2041  }
2042 
2043  $out = '';
2044  $outarray = array();
2045  $outarray2 = array();
2046 
2047  // Forge request to select users
2048  $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
2049  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
2050  $sql .= ", e.label";
2051  }
2052  $sql .= " FROM " . $this->db->prefix() . "user as u";
2053  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
2054  $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2055  if ($force_entity) {
2056  $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2057  } else {
2058  $sql .= " WHERE u.entity IS NOT NULL";
2059  }
2060  } else {
2061  if (isModEnabled('multicompany') && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
2062  $sql .= " LEFT JOIN " . $this->db->prefix() . "usergroup_user as ug";
2063  $sql .= " ON ug.fk_user = u.rowid";
2064  $sql .= " WHERE ug.entity = " . (int) $conf->entity;
2065  } else {
2066  $sql .= " WHERE u.entity IN (0, " . ((int) $conf->entity) . ")";
2067  }
2068  }
2069  if (!empty($user->socid)) {
2070  $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2071  }
2072  if (is_array($exclude) && $excludeUsers) {
2073  $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2074  }
2075  if ($includeUsers) {
2076  $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2077  }
2078  if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $notdisabled) {
2079  $sql .= " AND u.statut <> 0";
2080  }
2081  if (!empty($morefilter)) {
2082  $sql .= " " . $morefilter;
2083  }
2084 
2085  //Add hook to filter on user (for exemple on usergroup define in custom modules)
2086  $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2087  if (!empty($reshook)) {
2088  $sql .= $hookmanager->resPrint;
2089  }
2090 
2091  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2092  $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2093  } else {
2094  $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2095  }
2096 
2097  dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2098 
2099  $resql = $this->db->query($sql);
2100  if ($resql) {
2101  $num = $this->db->num_rows($resql);
2102  $i = 0;
2103  if ($num) {
2104  // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2105  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2106  if ($show_empty && !$multiple) {
2107  $textforempty = ' ';
2108  if (!empty($conf->use_javascript_ajax)) {
2109  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2110  }
2111  if (!is_numeric($show_empty)) {
2112  $textforempty = $show_empty;
2113  }
2114  $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2115  }
2116  if ($show_every) {
2117  $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2118  }
2119 
2120  $userstatic = new User($this->db);
2121 
2122  while ($i < $num) {
2123  $obj = $this->db->fetch_object($resql);
2124 
2125  $userstatic->id = $obj->rowid;
2126  $userstatic->lastname = $obj->lastname;
2127  $userstatic->firstname = $obj->firstname;
2128  $userstatic->photo = $obj->photo;
2129  $userstatic->statut = $obj->status;
2130  $userstatic->entity = $obj->entity;
2131  $userstatic->admin = $obj->admin;
2132 
2133  $disableline = '';
2134  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2135  $disableline = ($enableonlytext ? $enableonlytext : '1');
2136  }
2137 
2138  $labeltoshow = '';
2139  $labeltoshowhtml = '';
2140 
2141  // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2142  $fullNameMode = 0;
2143  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2144  $fullNameMode = 1; //Firstname+lastname
2145  }
2146  $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2147  $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2148  if (empty($obj->firstname) && empty($obj->lastname)) {
2149  $labeltoshow .= $obj->login;
2150  $labeltoshowhtml .= $obj->login;
2151  }
2152 
2153  // Complete name with a more info string like: ' (info1 - info2 - ...)'
2154  $moreinfo = '';
2155  $moreinfohtml = '';
2156  if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2157  $moreinfo .= ($moreinfo ? ' - ' : ' (');
2158  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2159  $moreinfo .= $obj->login;
2160  $moreinfohtml .= $obj->login;
2161  }
2162  if ($showstatus >= 0) {
2163  if ($obj->status == 1 && $showstatus == 1) {
2164  $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2165  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2166  }
2167  if ($obj->status == 0 && $showstatus == 1) {
2168  $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2169  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2170  }
2171  }
2172  if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2173  if (!$obj->entity) {
2174  $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2175  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2176  } else {
2177  if ($obj->entity != $conf->entity) {
2178  $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2179  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2180  }
2181  }
2182  }
2183  $moreinfo .= ($moreinfo ? ')' : '');
2184  $moreinfohtml .= ($moreinfohtml ? ')</span>' : '');
2185  if ($disableline && $disableline != '1') {
2186  // Add text from $enableonlytext parameter
2187  $moreinfo .= ' - ' . $disableline;
2188  $moreinfohtml .= ' - ' . $disableline;
2189  }
2190  $labeltoshow .= $moreinfo;
2191  $labeltoshowhtml .= $moreinfohtml;
2192 
2193  $out .= '<option value="' . $obj->rowid . '"';
2194  if ($disableline) {
2195  $out .= ' disabled';
2196  }
2197  if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2198  $out .= ' selected';
2199  }
2200  $out .= ' data-html="';
2201  $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2202  if ($showstatus >= 0 && $obj->status == 0) {
2203  $outhtml .= '<strike class="opacitymediumxxx">';
2204  }
2205  $outhtml .= $labeltoshowhtml;
2206  if ($showstatus >= 0 && $obj->status == 0) {
2207  $outhtml .= '</strike>';
2208  }
2209  $out .= dol_escape_htmltag($outhtml);
2210  $out .= '">';
2211  $out .= $labeltoshow;
2212  $out .= '</option>';
2213 
2214  $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2215  $outarray2[$userstatic->id] = array(
2216  'id'=>$userstatic->id,
2217  'label'=>$labeltoshow,
2218  'labelhtml'=>$labeltoshowhtml,
2219  'color'=>'',
2220  'picto'=>''
2221  );
2222 
2223  $i++;
2224  }
2225  } else {
2226  $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2227  $out .= '<option value="">' . $langs->trans("None") . '</option>';
2228  }
2229  $out .= '</select>';
2230 
2231  if ($num && !$forcecombo) {
2232  // Enhance with select2
2233  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2234  $out .= ajax_combobox($htmlname);
2235  }
2236  } else {
2237  dol_print_error($this->db);
2238  }
2239 
2240  if ($outputmode == 2) {
2241  return $outarray2;
2242  } elseif ($outputmode) {
2243  return $outarray;
2244  }
2245 
2246  return $out;
2247  }
2248 
2249 
2250  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2251 
2274  public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
2275  {
2276  // phpcs:enable
2277  global $conf, $user, $langs;
2278 
2279  $userstatic = new User($this->db);
2280  $out = '';
2281 
2282 
2283  $assignedtouser = array();
2284  if (!empty($_SESSION['assignedtouser'])) {
2285  $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2286  }
2287  $nbassignetouser = count($assignedtouser);
2288 
2289  //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2290  if ($nbassignetouser) {
2291  $out .= '<ul class="attendees">';
2292  }
2293  $i = 0;
2294  $ownerid = 0;
2295  foreach ($assignedtouser as $key => $value) {
2296  if ($value['id'] == $ownerid) {
2297  continue;
2298  }
2299 
2300  $out .= '<li>';
2301  $userstatic->fetch($value['id']);
2302  $out .= $userstatic->getNomUrl(-1);
2303  if ($i == 0) {
2304  $ownerid = $value['id'];
2305  $out .= ' (' . $langs->trans("Owner") . ')';
2306  }
2307  if ($nbassignetouser > 1 && $action != 'view') {
2308  $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $userstatic->id . '" class="removedassigned reposition" id="removedassigned_' . $userstatic->id . '" name="removedassigned_' . $userstatic->id . '">';
2309  }
2310  // Show my availability
2311  if ($showproperties) {
2312  if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2313  $out .= '<div class="myavailability inline-block">';
2314  $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparency" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofuserid[$ownerid]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2315  $out .= '</div>';
2316  }
2317  }
2318  //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2319  //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2320 
2321  $out .= '</li>';
2322  $i++;
2323  }
2324  if ($nbassignetouser) {
2325  $out .= '</ul>';
2326  }
2327 
2328  // Method with no ajax
2329  if ($action != 'view') {
2330  $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2331  $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2332  $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2333  $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2334  $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2335  $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2336  $out .= '});';
2337  $out .= '})</script>';
2338  $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2339  $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2340  $out .= '<br>';
2341  }
2342 
2343  return $out;
2344  }
2345 
2346 
2347  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2348 
2376  public function select_produits($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1)
2377  {
2378  // phpcs:enable
2379  global $langs, $conf;
2380 
2381  $out = '';
2382 
2383  // check parameters
2384  $price_level = (!empty($price_level) ? $price_level : 0);
2385  if (is_null($ajaxoptions)) {
2386  $ajaxoptions = array();
2387  }
2388 
2389  if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2390  if (isModEnabled("product") && !isModEnabled('service')) {
2391  $filtertype = '0';
2392  } elseif (!isModEnabled('product') && isModEnabled("service")) {
2393  $filtertype = '1';
2394  }
2395  }
2396 
2397  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2398  $placeholder = '';
2399 
2400  if ($selected && empty($selected_input_value)) {
2401  require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2402  $producttmpselect = new Product($this->db);
2403  $producttmpselect->fetch($selected);
2404  $selected_input_value = $producttmpselect->ref;
2405  unset($producttmpselect);
2406  }
2407  // handle case where product or service module is disabled + no filter specified
2408  if ($filtertype == '') {
2409  if (!isModEnabled('product')) { // when product module is disabled, show services only
2410  $filtertype = 1;
2411  } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2412  $filtertype = 0;
2413  }
2414  }
2415  // mode=1 means customers products
2416  $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=1&status=' . $status . '&status_purchase=' . $status_purchase . '&finished=' . $finished . '&hidepriceinlabel=' . $hidepriceinlabel . '&warehousestatus=' . $warehouseStatus;
2417  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2418 
2419  if (isModEnabled('variants') && is_array($selected_combinations)) {
2420  // Code to automatically insert with javascript the select of attributes under the select of product
2421  // when a parent of variant has been selected.
2422  $out .= '
2423  <!-- script to auto show attributes select tags if a variant was selected -->
2424  <script nonce="' . getNonce() . '">
2425  // auto show attributes fields
2426  selected = ' . json_encode($selected_combinations) . ';
2427  combvalues = {};
2428 
2429  jQuery(document).ready(function () {
2430 
2431  jQuery("input[name=\'prod_entry_mode\']").change(function () {
2432  if (jQuery(this).val() == \'free\') {
2433  jQuery(\'div#attributes_box\').empty();
2434  }
2435  });
2436 
2437  jQuery("input#' . $htmlname . '").change(function () {
2438 
2439  if (!jQuery(this).val()) {
2440  jQuery(\'div#attributes_box\').empty();
2441  return;
2442  }
2443 
2444  console.log("A change has started. We get variants fields to inject html select");
2445 
2446  jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2447  id: jQuery(this).val()
2448  }, function (data) {
2449  jQuery(\'div#attributes_box\').empty();
2450 
2451  jQuery.each(data, function (key, val) {
2452 
2453  combvalues[val.id] = val.values;
2454 
2455  var span = jQuery(document.createElement(\'div\')).css({
2456  \'display\': \'table-row\'
2457  });
2458 
2459  span.append(
2460  jQuery(document.createElement(\'div\')).text(val.label).css({
2461  \'font-weight\': \'bold\',
2462  \'display\': \'table-cell\'
2463  })
2464  );
2465 
2466  var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2467  \'margin-left\': \'15px\',
2468  \'white-space\': \'pre\'
2469  }).append(
2470  jQuery(document.createElement(\'option\')).val(\'\')
2471  );
2472 
2473  jQuery.each(combvalues[val.id], function (key, val) {
2474  var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2475 
2476  if (selected[val.fk_product_attribute] == val.id) {
2477  tag.attr(\'selected\', \'selected\');
2478  }
2479 
2480  html.append(tag);
2481  });
2482 
2483  span.append(html);
2484  jQuery(\'div#attributes_box\').append(span);
2485  });
2486  })
2487  });
2488 
2489  ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2490  });
2491  </script>
2492  ';
2493  }
2494 
2495  if (empty($hidelabel)) {
2496  $out .= $langs->trans("RefOrLabel") . ' : ';
2497  } elseif ($hidelabel > 1) {
2498  $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2499  if ($hidelabel == 2) {
2500  $out .= img_picto($langs->trans("Search"), 'search');
2501  }
2502  }
2503  $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
2504  if ($hidelabel == 3) {
2505  $out .= img_picto($langs->trans("Search"), 'search');
2506  }
2507  } else {
2508  $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2509  }
2510 
2511  if (empty($nooutput)) {
2512  print $out;
2513  } else {
2514  return $out;
2515  }
2516  }
2517 
2518  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2519 
2535  public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2536  {
2537  // phpcs:enable
2538  global $conf, $user, $langs, $db;
2539 
2540  require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2541 
2542  $error = 0;
2543  $out = '';
2544 
2545  if (!$forcecombo) {
2546  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2547  $events = array();
2548  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2549  }
2550 
2551  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2552 
2553  $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2554  $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2555  $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2556  if (!empty($status)) $sql .= ' AND status = ' . (int) $status;
2557  if (!empty($type)) $sql .= ' AND bomtype = ' . (int) $type;
2558  if (!empty($TProducts)) $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2559  if (!empty($limit)) $sql .= ' LIMIT ' . (int) $limit;
2560  $resql = $db->query($sql);
2561  if ($resql) {
2562  if ($showempty) {
2563  $out .= '<option value="-1"';
2564  if (empty($selected)) $out .= ' selected';
2565  $out .= '>&nbsp;</option>';
2566  }
2567  while ($obj = $db->fetch_object($resql)) {
2568  $product = new Product($db);
2569  $res = $product->fetch($obj->fk_product);
2570  $out .= '<option value="' . $obj->rowid . '"';
2571  if ($obj->rowid == $selected) $out .= 'selected';
2572  $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2573  }
2574  } else {
2575  $error++;
2576  dol_print_error($db);
2577  }
2578  $out .= '</select>';
2579  if (empty($nooutput)) {
2580  print $out;
2581  } else {
2582  return $out;
2583  }
2584  }
2585 
2586  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2587 
2613  public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1)
2614  {
2615  // phpcs:enable
2616  global $langs, $conf;
2617  global $hookmanager;
2618 
2619  $out = '';
2620  $outarray = array();
2621 
2622  // Units
2623  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2624  $langs->load('other');
2625  }
2626 
2627  $warehouseStatusArray = array();
2628  if (!empty($warehouseStatus)) {
2629  require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2630  if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2631  $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2632  }
2633  if (preg_match('/warehouseopen/', $warehouseStatus)) {
2634  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2635  }
2636  if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2637  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2638  }
2639  }
2640 
2641  $selectFields = " p.rowid, p.ref, p.label, p.description, p.barcode, p.fk_country, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.default_vat_code, p.duration, p.fk_price_expression";
2642  if (count($warehouseStatusArray)) {
2643  $selectFieldsGrouped = ", sum(" . $this->db->ifsql("e.statut IS NULL", "0", "ps.reel") . ") as stock"; // e.statut is null if there is no record in stock
2644  } else {
2645  $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2646  }
2647 
2648  $sql = "SELECT ";
2649 
2650  // Add select from hooks
2651  $parameters = array();
2652  $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2653  if (empty($reshook)) {
2654  $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2655  } else {
2656  $sql .= $hookmanager->resPrint;
2657  }
2658 
2659  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2660  //Product category
2661  $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2662  FROM " . $this->db->prefix() . "categorie_product
2663  WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2664  LIMIT 1
2665  ) AS categorie_product_id ";
2666  }
2667 
2668  //Price by customer
2669  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2670  $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2671  $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref';
2672  $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2673  }
2674  // Units
2675  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2676  $sql .= ", u.label as unit_long, u.short_label as unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units";
2677  $selectFields .= ', unit_long, unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units';
2678  }
2679 
2680  // Multilang : we add translation
2681  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2682  $sql .= ", pl.label as label_translated";
2683  $sql .= ", pl.description as description_translated";
2684  $selectFields .= ", label_translated";
2685  $selectFields .= ", description_translated";
2686  }
2687  // Price by quantity
2688  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2689  $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2690  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2691  $sql .= " AND price_level = " . ((int) $price_level);
2692  }
2693  $sql .= " ORDER BY date_price";
2694  $sql .= " DESC LIMIT 1) as price_rowid";
2695  $sql .= ", (SELECT pp.price_by_qty FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable
2696  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2697  $sql .= " AND price_level = " . ((int) $price_level);
2698  }
2699  $sql .= " ORDER BY date_price";
2700  $sql .= " DESC LIMIT 1) as price_by_qty";
2701  $selectFields .= ", price_rowid, price_by_qty";
2702  }
2703 
2704  $sql .= " FROM ".$this->db->prefix()."product as p";
2705  // Add from (left join) from hooks
2706  $parameters = array();
2707  $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2708  $sql .= $hookmanager->resPrint;
2709 
2710  if (count($warehouseStatusArray)) {
2711  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2712  $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2713  $sql .= ' AND e.statut IN (' . $this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))) . ')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0.
2714  }
2715 
2716  // include search in supplier ref
2717  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2718  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2719  }
2720 
2721  //Price by customer
2722  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2723  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
2724  }
2725  // Units
2726  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2727  $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
2728  }
2729  // Multilang : we add translation
2730  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2731  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
2732  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2733  require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
2734  $soc = new Societe($this->db);
2735  $result = $soc->fetch($socid);
2736  if ($result > 0 && !empty($soc->default_lang)) {
2737  $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
2738  } else {
2739  $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
2740  }
2741  } else {
2742  $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
2743  }
2744  }
2745 
2746  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2747  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2748  }
2749 
2750  $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
2751 
2752  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2753  $sql .= " AND pac.rowid IS NULL";
2754  }
2755 
2756  if ($finished == 0) {
2757  $sql .= " AND p.finished = " . ((int) $finished);
2758  } elseif ($finished == 1) {
2759  $sql .= " AND p.finished = ".((int) $finished);
2760  }
2761  if ($status >= 0) {
2762  $sql .= " AND p.tosell = ".((int) $status);
2763  }
2764  if ($status_purchase >= 0) {
2765  $sql .= " AND p.tobuy = " . ((int) $status_purchase);
2766  }
2767  // Filter by product type
2768  if (strval($filtertype) != '') {
2769  $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
2770  } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
2771  $sql .= " AND p.fk_product_type = 1";
2772  } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2773  $sql .= " AND p.fk_product_type = 0";
2774  }
2775  // Add where from hooks
2776  $parameters = array();
2777  $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2778  $sql .= $hookmanager->resPrint;
2779  // Add criteria on ref/label
2780  if ($filterkey != '') {
2781  $sql .= ' AND (';
2782  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2783  // For natural search
2784  $scrit = explode(' ', $filterkey);
2785  $i = 0;
2786  if (count($scrit) > 1) {
2787  $sql .= "(";
2788  }
2789  foreach ($scrit as $crit) {
2790  if ($i > 0) {
2791  $sql .= " AND ";
2792  }
2793  $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2794  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2795  $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2796  }
2797  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2798  $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2799  }
2800  if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2801  $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2802  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2803  $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2804  }
2805  }
2806  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2807  $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
2808  }
2809  $sql .= ")";
2810  $i++;
2811  }
2812  if (count($scrit) > 1) {
2813  $sql .= ")";
2814  }
2815  if (isModEnabled('barcode')) {
2816  $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
2817  }
2818  $sql .= ')';
2819  }
2820  if (count($warehouseStatusArray)) {
2821  $sql .= " GROUP BY " . $selectFields;
2822  }
2823 
2824  //Sort by category
2825  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2826  $sql .= " ORDER BY categorie_product_id ";
2827  //ASC OR DESC order
2828  ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2829  } else {
2830  $sql .= $this->db->order("p.ref");
2831  }
2832 
2833  $sql .= $this->db->plimit($limit, 0);
2834 
2835  // Build output string
2836  dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
2837  $result = $this->db->query($sql);
2838  if ($result) {
2839  require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2840  require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
2841  require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
2842 
2843  $num = $this->db->num_rows($result);
2844 
2845  $events = null;
2846 
2847  if (!$forcecombo) {
2848  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2849  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2850  }
2851 
2852  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2853 
2854  $textifempty = '';
2855  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2856  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2857  if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2858  if ($showempty && !is_numeric($showempty)) {
2859  $textifempty = $langs->trans($showempty);
2860  } else {
2861  $textifempty .= $langs->trans("All");
2862  }
2863  } else {
2864  if ($showempty && !is_numeric($showempty)) {
2865  $textifempty = $langs->trans($showempty);
2866  }
2867  }
2868  if ($showempty) {
2869  $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
2870  }
2871 
2872  $i = 0;
2873  while ($num && $i < $num) {
2874  $opt = '';
2875  $optJson = array();
2876  $objp = $this->db->fetch_object($result);
2877 
2878  if ((!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product
2879  $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2880  $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
2881  $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
2882  $sql .= " ORDER BY quantity ASC";
2883 
2884  dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
2885  $result2 = $this->db->query($sql);
2886  if ($result2) {
2887  $nb_prices = $this->db->num_rows($result2);
2888  $j = 0;
2889  while ($nb_prices && $j < $nb_prices) {
2890  $objp2 = $this->db->fetch_object($result2);
2891 
2892  $objp->price_by_qty_rowid = $objp2->rowid;
2893  $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2894  $objp->price_by_qty_quantity = $objp2->quantity;
2895  $objp->price_by_qty_unitprice = $objp2->unitprice;
2896  $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2897  // For backward compatibility
2898  $objp->quantity = $objp2->quantity;
2899  $objp->price = $objp2->price;
2900  $objp->unitprice = $objp2->unitprice;
2901  $objp->remise_percent = $objp2->remise_percent;
2902 
2903  //$objp->tva_tx is not overwritten by $objp2 value
2904  //$objp->default_vat_code is not overwritten by $objp2 value
2905 
2906  $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2907 
2908  $j++;
2909 
2910  // Add new entry
2911  // "key" value of json key array is used by jQuery automatically as selected value
2912  // "label" value of json key array is used by jQuery automatically as text for combo box
2913  $out .= $opt;
2914  array_push($outarray, $optJson);
2915  }
2916  }
2917  } else {
2918  if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
2919  $price_product = new Product($this->db);
2920  $price_product->fetch($objp->rowid, '', '', 1);
2921 
2922  require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
2923  $priceparser = new PriceParser($this->db);
2924  $price_result = $priceparser->parseProduct($price_product);
2925  if ($price_result >= 0) {
2926  $objp->price = $price_result;
2927  $objp->unitprice = $price_result;
2928  //Calculate the VAT
2929  $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2930  $objp->price_ttc = price2num($objp->price_ttc, 'MU');
2931  }
2932  }
2933 
2934  $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2935  // Add new entry
2936  // "key" value of json key array is used by jQuery automatically as selected value
2937  // "label" value of json key array is used by jQuery automatically as text for combo box
2938  $out .= $opt;
2939  array_push($outarray, $optJson);
2940  }
2941 
2942  $i++;
2943  }
2944 
2945  $out .= '</select>';
2946 
2947  $this->db->free($result);
2948 
2949  if (empty($outputmode)) {
2950  return $out;
2951  }
2952 
2953  return $outarray;
2954  } else {
2955  dol_print_error($this->db);
2956  }
2957 
2958  return '';
2959  }
2960 
2976  protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2977  {
2978  global $langs, $conf, $user;
2979  global $hookmanager;
2980 
2981  $outkey = '';
2982  $outval = '';
2983  $outref = '';
2984  $outlabel = '';
2985  $outlabel_translated = '';
2986  $outdesc = '';
2987  $outdesc_translated = '';
2988  $outbarcode = '';
2989  $outorigin = '';
2990  $outtype = '';
2991  $outprice_ht = '';
2992  $outprice_ttc = '';
2993  $outpricebasetype = '';
2994  $outtva_tx = '';
2995  $outdefault_vat_code = '';
2996  $outqty = 1;
2997  $outdiscount = 0;
2998 
2999  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3000 
3001  $label = $objp->label;
3002  if (!empty($objp->label_translated)) {
3003  $label = $objp->label_translated;
3004  }
3005  if (!empty($filterkey) && $filterkey != '') {
3006  $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3007  }
3008 
3009  $outkey = $objp->rowid;
3010  $outref = $objp->ref;
3011  $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3012  $outlabel = $objp->label;
3013  $outdesc = $objp->description;
3014  if (getDolGlobalInt('MAIN_MULTILANGS')) {
3015  $outlabel_translated = $objp->label_translated;
3016  $outdesc_translated = $objp->description_translated;
3017  }
3018  $outbarcode = $objp->barcode;
3019  $outorigin = $objp->fk_country;
3020  $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3021 
3022  $outtype = $objp->fk_product_type;
3023  $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3024  $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3025 
3026  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3027  require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3028  }
3029 
3030  // Units
3031  $outvalUnits = '';
3032  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3033  if (!empty($objp->unit_short)) {
3034  $outvalUnits .= ' - ' . $objp->unit_short;
3035  }
3036  }
3037  if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
3038  if (!empty($objp->weight) && $objp->weight_units !== null) {
3039  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3040  $outvalUnits .= ' - ' . $unitToShow;
3041  }
3042  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3043  $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3044  $outvalUnits .= ' - ' . $unitToShow;
3045  }
3046  if (!empty($objp->surface) && $objp->surface_units !== null) {
3047  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3048  $outvalUnits .= ' - ' . $unitToShow;
3049  }
3050  if (!empty($objp->volume) && $objp->volume_units !== null) {
3051  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3052  $outvalUnits .= ' - ' . $unitToShow;
3053  }
3054  }
3055  if ($outdurationvalue && $outdurationunit) {
3056  $da = array(
3057  'h' => $langs->trans('Hour'),
3058  'd' => $langs->trans('Day'),
3059  'w' => $langs->trans('Week'),
3060  'm' => $langs->trans('Month'),
3061  'y' => $langs->trans('Year')
3062  );
3063  if (isset($da[$outdurationunit])) {
3064  $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3065  }
3066  }
3067 
3068  $opt = '<option value="' . $objp->rowid . '"';
3069  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3070  if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3071  $opt .= ' pbq="' . $objp->price_by_qty_rowid . '" data-pbq="' . $objp->price_by_qty_rowid . '" data-pbqup="' . $objp->price_by_qty_unitprice . '" data-pbqbase="' . $objp->price_by_qty_price_base_type . '" data-pbqqty="' . $objp->price_by_qty_quantity . '" data-pbqpercent="' . $objp->price_by_qty_remise_percent . '"';
3072  }
3073  if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3074  if (!empty($user->rights->stock->lire)) {
3075  if ($objp->stock > 0) {
3076  $opt .= ' class="product_line_stock_ok"';
3077  } elseif ($objp->stock <= 0) {
3078  $opt .= ' class="product_line_stock_too_low"';
3079  }
3080  }
3081  }
3082  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
3083  $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3084  $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3085  }
3086  $opt .= '>';
3087  $opt .= $objp->ref;
3088  if (!empty($objp->custref)) {
3089  $opt .= ' (' . $objp->custref . ')';
3090  }
3091  if ($outbarcode) {
3092  $opt .= ' (' . $outbarcode . ')';
3093  }
3094  $opt .= ' - ' . dol_trunc($label, $maxlengtharticle);
3095  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3096  $opt .= ' (' . getCountry($outorigin, 1) . ')';
3097  }
3098 
3099  $objRef = $objp->ref;
3100  if (!empty($objp->custref)) {
3101  $objRef .= ' (' . $objp->custref . ')';
3102  }
3103  if (!empty($filterkey) && $filterkey != '') {
3104  $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3105  }
3106  $outval .= $objRef;
3107  if ($outbarcode) {
3108  $outval .= ' (' . $outbarcode . ')';
3109  }
3110  $outval .= ' - ' . dol_trunc($label, $maxlengtharticle);
3111  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3112  $outval .= ' (' . getCountry($outorigin, 1) . ')';
3113  }
3114 
3115  // Units
3116  $opt .= $outvalUnits;
3117  $outval .= $outvalUnits;
3118 
3119  $found = 0;
3120 
3121  // Multiprice
3122  // If we need a particular price level (from 1 to n)
3123  if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
3124  $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3125  $sql .= " FROM " . $this->db->prefix() . "product_price";
3126  $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3127  $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3128  $sql .= " AND price_level = " . ((int) $price_level);
3129  $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3130  $sql .= " LIMIT 1";
3131 
3132  dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3133  $result2 = $this->db->query($sql);
3134  if ($result2) {
3135  $objp2 = $this->db->fetch_object($result2);
3136  if ($objp2) {
3137  $found = 1;
3138  if ($objp2->price_base_type == 'HT') {
3139  $opt .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3140  $outval .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3141  } else {
3142  $opt .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3143  $outval .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3144  }
3145  $outprice_ht = price($objp2->price);
3146  $outprice_ttc = price($objp2->price_ttc);
3147  $outpricebasetype = $objp2->price_base_type;
3148  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
3149  $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3150  $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3151  } else {
3152  $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3153  $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3154  }
3155  }
3156  } else {
3157  dol_print_error($this->db);
3158  }
3159  }
3160 
3161  // Price by quantity
3162  if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
3163  $found = 1;
3164  $outqty = $objp->quantity;
3165  $outdiscount = $objp->remise_percent;
3166  if ($objp->quantity == 1) {
3167  $opt .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3168  $outval .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3169  $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3170  $outval .= $langs->transnoentities("Unit");
3171  } else {
3172  $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3173  $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3174  $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3175  $outval .= $langs->transnoentities("Units");
3176  }
3177 
3178  $outprice_ht = price($objp->unitprice);
3179  $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3180  $outpricebasetype = $objp->price_base_type;
3181  $outtva_tx = $objp->tva_tx; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3182  $outdefault_vat_code = $objp->default_vat_code; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3183  }
3184  if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3185  $opt .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3186  $outval .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3187  }
3188  if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3189  $opt .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3190  $outval .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3191  }
3192 
3193  // Price by customer
3194  if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
3195  if (!empty($objp->idprodcustprice)) {
3196  $found = 1;
3197 
3198  if ($objp->custprice_base_type == 'HT') {
3199  $opt .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3200  $outval .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3201  } else {
3202  $opt .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3203  $outval .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3204  }
3205 
3206  $outprice_ht = price($objp->custprice);
3207  $outprice_ttc = price($objp->custprice_ttc);
3208  $outpricebasetype = $objp->custprice_base_type;
3209  $outtva_tx = $objp->custtva_tx;
3210  $outdefault_vat_code = $objp->custdefault_vat_code;
3211  }
3212  }
3213 
3214  // If level no defined or multiprice not found, we used the default price
3215  if (empty($hidepriceinlabel) && !$found) {
3216  if ($objp->price_base_type == 'HT') {
3217  $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3218  $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3219  } else {
3220  $opt .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3221  $outval .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3222  }
3223  $outprice_ht = price($objp->price);
3224  $outprice_ttc = price($objp->price_ttc);
3225  $outpricebasetype = $objp->price_base_type;
3226  $outtva_tx = $objp->tva_tx;
3227  $outdefault_vat_code = $objp->default_vat_code;
3228  }
3229 
3230  if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3231  if (!empty($user->rights->stock->lire)) {
3232  $opt .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3233 
3234  if ($objp->stock > 0) {
3235  $outval .= ' - <span class="product_line_stock_ok">';
3236  } elseif ($objp->stock <= 0) {
3237  $outval .= ' - <span class="product_line_stock_too_low">';
3238  }
3239  $outval .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3240  $outval .= '</span>';
3241  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3242  $langs->load("stocks");
3243 
3244  $tmpproduct = new Product($this->db);
3245  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3246  $tmpproduct->load_virtual_stock();
3247  $virtualstock = $tmpproduct->stock_theorique;
3248 
3249  $opt .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3250 
3251  $outval .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3252  if ($virtualstock > 0) {
3253  $outval .= '<span class="product_line_stock_ok">';
3254  } elseif ($virtualstock <= 0) {
3255  $outval .= '<span class="product_line_stock_too_low">';
3256  }
3257  $outval .= $virtualstock;
3258  $outval .= '</span>';
3259 
3260  unset($tmpproduct);
3261  }
3262  }
3263  }
3264 
3265  $parameters = array('objp'=>$objp);
3266  $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3267  if (empty($reshook)) {
3268  $opt .= $hookmanager->resPrint;
3269  } else {
3270  $opt = $hookmanager->resPrint;
3271  }
3272 
3273  $opt .= "</option>\n";
3274  $optJson = array(
3275  'key' => $outkey,
3276  'value' => $outref,
3277  'label' => $outval,
3278  'label2' => $outlabel,
3279  'desc' => $outdesc,
3280  'type' => $outtype,
3281  'price_ht' => price2num($outprice_ht),
3282  'price_ttc' => price2num($outprice_ttc),
3283  'price_ht_locale' => price(price2num($outprice_ht)),
3284  'price_ttc_locale' => price(price2num($outprice_ttc)),
3285  'pricebasetype' => $outpricebasetype,
3286  'tva_tx' => $outtva_tx,
3287  'default_vat_code' => $outdefault_vat_code,
3288  'qty' => $outqty,
3289  'discount' => $outdiscount,
3290  'duration_value' => $outdurationvalue,
3291  'duration_unit' => $outdurationunit,
3292  'pbq' => $outpbq,
3293  'labeltrans' => $outlabel_translated,
3294  'desctrans' => $outdesc_translated,
3295  'ref_customer' => $outrefcust
3296  );
3297  }
3298 
3299  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3300 
3316  public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3317  {
3318  // phpcs:enable
3319  global $langs, $conf;
3320  global $price_level, $status, $finished;
3321 
3322  if (!isset($status)) {
3323  $status = 1;
3324  }
3325 
3326  $selected_input_value = '';
3327  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
3328  if ($selected > 0) {
3329  require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3330  $producttmpselect = new Product($this->db);
3331  $producttmpselect->fetch($selected);
3332  $selected_input_value = $producttmpselect->ref;
3333  unset($producttmpselect);
3334  }
3335 
3336  // mode=2 means suppliers products
3337  $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3338  print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3339 
3340  print ($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="minwidth300" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3341  } else {
3342  print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3343  }
3344  }
3345 
3346  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3347 
3366  public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0, $placeholder = '')
3367  {
3368  // phpcs:enable
3369  global $langs, $conf, $user;
3370  global $hookmanager;
3371 
3372  $out = '';
3373  $outarray = array();
3374 
3375  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3376 
3377  $langs->load('stocks');
3378  // Units
3379  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3380  $langs->load('other');
3381  }
3382 
3383  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock, p.tva_tx as tva_tx_sale, p.default_vat_code as default_vat_code_sale,";
3384  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
3385  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name,";
3386  $sql .= " pfp.supplier_reputation";
3387  // if we use supplier description of the products
3388  if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3389  $sql .= ", pfp.desc_fourn as description";
3390  } else {
3391  $sql .= ", p.description";
3392  }
3393  // Units
3394  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3395  $sql .= ", u.label as unit_long, u.short_label as unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units";
3396  }
3397  if (isModEnabled('barcode')) {
3398  $sql .= ", pfp.barcode";
3399  }
3400  $sql .= " FROM " . $this->db->prefix() . "product as p";
3401  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3402  if ($socid > 0) {
3403  $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3404  }
3405  $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3406  // Units
3407  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3408  $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3409  }
3410  $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3411  if ($statut != -1) {
3412  $sql .= " AND p.tobuy = " . ((int) $statut);
3413  }
3414  if (strval($filtertype) != '') {
3415  $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3416  }
3417  if (!empty($filtre)) {
3418  $sql .= " " . $filtre;
3419  }
3420  // Add where from hooks
3421  $parameters = array();
3422  $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3423  $sql .= $hookmanager->resPrint;
3424  // Add criteria on ref/label
3425  if ($filterkey != '') {
3426  $sql .= ' AND (';
3427  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3428  // For natural search
3429  $scrit = explode(' ', $filterkey);
3430  $i = 0;
3431  if (count($scrit) > 1) {
3432  $sql .= "(";
3433  }
3434  foreach ($scrit as $crit) {
3435  if ($i > 0) {
3436  $sql .= " AND ";
3437  }
3438  $sql .= "(pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3439  if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3440  $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3441  }
3442  $sql .= ")";
3443  $i++;
3444  }
3445  if (count($scrit) > 1) {
3446  $sql .= ")";
3447  }
3448  if (isModEnabled('barcode')) {
3449  $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3450  $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3451  }
3452  $sql .= ')';
3453  }
3454  $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3455  $sql .= $this->db->plimit($limit, 0);
3456 
3457  // Build output string
3458 
3459  dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3460  $result = $this->db->query($sql);
3461  if ($result) {
3462  require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3463  require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3464 
3465  $num = $this->db->num_rows($result);
3466 
3467  //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3468  $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3469  if (!$selected) {
3470  $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3471  } else {
3472  $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3473  }
3474 
3475  $i = 0;
3476  while ($i < $num) {
3477  $objp = $this->db->fetch_object($result);
3478 
3479  if (is_null($objp->idprodfournprice)) {
3480  // There is no supplier price found, we will use the vat rate for sale
3481  $objp->tva_tx = $objp->tva_tx_sale;
3482  $objp->default_vat_code = $objp->default_vat_code_sale;
3483  }
3484 
3485  $outkey = $objp->idprodfournprice; // id in table of price
3486  if (!$outkey && $alsoproductwithnosupplierprice) {
3487  $outkey = 'idprod_' . $objp->rowid; // id of product
3488  }
3489 
3490  $outref = $objp->ref;
3491  $outbarcode = $objp->barcode;
3492  $outqty = 1;
3493  $outdiscount = 0;
3494  $outtype = $objp->fk_product_type;
3495  $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3496  $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3497 
3498  // Units
3499  $outvalUnits = '';
3500  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3501  if (!empty($objp->unit_short)) {
3502  $outvalUnits .= ' - ' . $objp->unit_short;
3503  }
3504  if (!empty($objp->weight) && $objp->weight_units !== null) {
3505  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3506  $outvalUnits .= ' - ' . $unitToShow;
3507  }
3508  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3509  $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3510  $outvalUnits .= ' - ' . $unitToShow;
3511  }
3512  if (!empty($objp->surface) && $objp->surface_units !== null) {
3513  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3514  $outvalUnits .= ' - ' . $unitToShow;
3515  }
3516  if (!empty($objp->volume) && $objp->volume_units !== null) {
3517  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3518  $outvalUnits .= ' - ' . $unitToShow;
3519  }
3520  if ($outdurationvalue && $outdurationunit) {
3521  $da = array(
3522  'h' => $langs->trans('Hour'),
3523  'd' => $langs->trans('Day'),
3524  'w' => $langs->trans('Week'),
3525  'm' => $langs->trans('Month'),
3526  'y' => $langs->trans('Year')
3527  );
3528  if (isset($da[$outdurationunit])) {
3529  $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3530  }
3531  }
3532  }
3533 
3534  $objRef = $objp->ref;
3535  if ($filterkey && $filterkey != '') {
3536  $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3537  }
3538  $objRefFourn = $objp->ref_fourn;
3539  if ($filterkey && $filterkey != '') {
3540  $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3541  }
3542  $label = $objp->label;
3543  if ($filterkey && $filterkey != '') {
3544  $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3545  }
3546 
3547  $optlabel = $objp->ref;
3548  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3549  $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3550  }
3551  if (isModEnabled('barcode') && !empty($objp->barcode)) {
3552  $optlabel .= ' (' . $outbarcode . ')';
3553  }
3554  $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3555 
3556  $outvallabel = $objRef;
3557  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3558  $outvallabel .= ' (' . $objRefFourn . ')';
3559  }
3560  if (isModEnabled('barcode') && !empty($objp->barcode)) {
3561  $outvallabel .= ' (' . $outbarcode . ')';
3562  }
3563  $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3564 
3565  // Units
3566  $optlabel .= $outvalUnits;
3567  $outvallabel .= $outvalUnits;
3568 
3569  if (!empty($objp->idprodfournprice)) {
3570  $outqty = $objp->quantity;
3571  $outdiscount = $objp->remise_percent;
3572  if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3573  $prod_supplier = new ProductFournisseur($this->db);
3574  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3575  $prod_supplier->id = $objp->fk_product;
3576  $prod_supplier->fourn_qty = $objp->quantity;
3577  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3578  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3579 
3580  require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3581  $priceparser = new PriceParser($this->db);
3582  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3583  if ($price_result >= 0) {
3584  $objp->fprice = $price_result;
3585  if ($objp->quantity >= 1) {
3586  $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3587  }
3588  }
3589  }
3590  if ($objp->quantity == 1) {
3591  $optlabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3592  $outvallabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3593  $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3594  $outvallabel .= $langs->transnoentities("Unit");
3595  } else {
3596  $optlabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3597  $outvallabel .= ' - ' . price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3598  $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3599  $outvallabel .= ' ' . $langs->transnoentities("Units");
3600  }
3601 
3602  if ($objp->quantity > 1) {
3603  $optlabel .= " (" . price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3604  $outvallabel .= " (" . price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3605  }
3606  if ($objp->remise_percent >= 1) {
3607  $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3608  $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3609  }
3610  if ($objp->duration) {
3611  $optlabel .= " - " . $objp->duration;
3612  $outvallabel .= " - " . $objp->duration;
3613  }
3614  if (!$socid) {
3615  $optlabel .= " - " . dol_trunc($objp->name, 8);
3616  $outvallabel .= " - " . dol_trunc($objp->name, 8);
3617  }
3618  if ($objp->supplier_reputation) {
3619  //TODO dictionary
3620  $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3621 
3622  $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3623  $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3624  }
3625  } else {
3626  if (empty($alsoproductwithnosupplierprice)) { // No supplier price defined for couple product/supplier
3627  $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3628  $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3629  } else // No supplier price defined for product, even on other suppliers
3630  {
3631  $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3632  $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3633  }
3634  }
3635 
3636  if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3637  $novirtualstock = ($showstockinlist == 2);
3638 
3639  if (!empty($user->rights->stock->lire)) {
3640  $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3641 
3642  if ($objp->stock > 0) {
3643  $optlabel .= ' - <span class="product_line_stock_ok">';
3644  } elseif ($objp->stock <= 0) {
3645  $optlabel .= ' - <span class="product_line_stock_too_low">';
3646  }
3647  $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3648  $optlabel .= '</span>';
3649  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3650  $langs->load("stocks");
3651 
3652  $tmpproduct = new Product($this->db);
3653  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3654  $tmpproduct->load_virtual_stock();
3655  $virtualstock = $tmpproduct->stock_theorique;
3656 
3657  $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3658 
3659  $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3660  if ($virtualstock > 0) {
3661  $optlabel .= '<span class="product_line_stock_ok">';
3662  } elseif ($virtualstock <= 0) {
3663  $optlabel .= '<span class="product_line_stock_too_low">';
3664  }
3665  $optlabel .= $virtualstock;
3666  $optlabel .= '</span>';
3667 
3668  unset($tmpproduct);
3669  }
3670  }
3671  }
3672 
3673  $optstart = '<option value="' . $outkey . '"';
3674  if ($selected && $selected == $objp->idprodfournprice) {
3675  $optstart .= ' selected';
3676  }
3677  if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3678  $optstart .= ' disabled';
3679  }
3680 
3681  if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3682  $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
3683  $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
3684  $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
3685  $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
3686  $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
3687  $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
3688  $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
3689  $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
3690  $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
3691  $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
3692  }
3693  $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
3694 
3695  $outarrayentry = array(
3696  'key' => $outkey,
3697  'value' => $outref,
3698  'label' => $outvallabel,
3699  'qty' => $outqty,
3700  'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3701  'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3702  'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3703  'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
3704  'tva_tx' => price2num($objp->tva_tx),
3705  'default_vat_code' => $objp->default_vat_code,
3706  'discount' => $outdiscount,
3707  'type' => $outtype,
3708  'duration_value' => $outdurationvalue,
3709  'duration_unit' => $outdurationunit,
3710  'disabled' => (empty($objp->idprodfournprice) ? true : false),
3711  'description' => $objp->description
3712  );
3713 
3714  $parameters = array(
3715  'objp' => &$objp,
3716  'optstart' => &$optstart,
3717  'optlabel' => &$optlabel,
3718  'outvallabel' => &$outvallabel,
3719  'outarrayentry' => &$outarrayentry
3720  );
3721  $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
3722 
3723 
3724  // Add new entry
3725  // "key" value of json key array is used by jQuery automatically as selected value. Example: 'type' = product or service, 'price_ht' = unit price without tax
3726  // "label" value of json key array is used by jQuery automatically as text for combo box
3727  $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
3728  array_push(
3729  $outarray,
3730  array('key' => $outkey,
3731  'value' => $outref,
3732  'label' => $outvallabel,
3733  'qty' => $outqty,
3734  'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3735  'price_qty_ht_locale' => price($objp->fprice),
3736  'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3737  'price_unit_ht_locale' => price($objp->unitprice),
3738  'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3739  'tva_tx_formated' => price($objp->tva_tx),
3740  'tva_tx' => price2num($objp->tva_tx),
3741  'default_vat_code' => $objp->default_vat_code,
3742  'discount' => $outdiscount,
3743  'type' => $outtype,
3744  'duration_value' => $outdurationvalue,
3745  'duration_unit' => $outdurationunit,
3746  'disabled' => (empty($objp->idprodfournprice) ? true : false),
3747  'description' => $objp->description
3748  )
3749  );
3750  // Exemple of var_dump $outarray
3751  // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3752  // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3753  // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3754  //}
3755  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3756  //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3757  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3758 
3759  $i++;
3760  }
3761  $out .= '</select>';
3762 
3763  $this->db->free($result);
3764 
3765  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3766  $out .= ajax_combobox($htmlname);
3767  } else {
3768  dol_print_error($this->db);
3769  }
3770 
3771  if (empty($outputmode)) {
3772  return $out;
3773  }
3774  return $outarray;
3775  }
3776 
3777  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3778 
3787  public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3788  {
3789  // phpcs:enable
3790  global $langs, $conf;
3791 
3792  $langs->load('stocks');
3793 
3794  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3795  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3796  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3797  $sql .= " FROM " . $this->db->prefix() . "product as p";
3798  $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3799  $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3800  $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
3801  $sql .= " AND p.tobuy = 1";
3802  $sql .= " AND s.fournisseur = 1";
3803  $sql .= " AND p.rowid = " . ((int) $productid);
3804  if (empty($conf->global->PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED)) {
3805  $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3806  } else {
3807  $sql .= " ORDER BY pfp.unitprice ASC";
3808  }
3809 
3810  dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
3811  $result = $this->db->query($sql);
3812 
3813  if ($result) {
3814  $num = $this->db->num_rows($result);
3815 
3816  $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
3817 
3818  if (!$num) {
3819  $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
3820  } else {
3821  require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3822  $form .= '<option value="0">&nbsp;</option>';
3823 
3824  $i = 0;
3825  while ($i < $num) {
3826  $objp = $this->db->fetch_object($result);
3827 
3828  $opt = '<option value="' . $objp->idprodfournprice . '"';
3829  //if there is only one supplier, preselect it
3830  if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && !empty($conf->global->PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED))) {
3831  $opt .= ' selected';
3832  }
3833  $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
3834 
3835  if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3836  $prod_supplier = new ProductFournisseur($this->db);
3837  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3838  $prod_supplier->id = $productid;
3839  $prod_supplier->fourn_qty = $objp->quantity;
3840  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3841  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3842 
3843  require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3844  $priceparser = new PriceParser($this->db);
3845  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3846  if ($price_result >= 0) {
3847  $objp->fprice = $price_result;
3848  if ($objp->quantity >= 1) {
3849  $objp->unitprice = $objp->fprice / $objp->quantity;
3850  }
3851  }
3852  }
3853  if ($objp->quantity == 1) {
3854  $opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3855  }
3856 
3857  $opt .= $objp->quantity . ' ';
3858 
3859  if ($objp->quantity == 1) {
3860  $opt .= $langs->trans("Unit");
3861  } else {
3862  $opt .= $langs->trans("Units");
3863  }
3864  if ($objp->quantity > 1) {
3865  $opt .= " - ";
3866  $opt .= price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit");
3867  }
3868  if ($objp->duration) {
3869  $opt .= " - " . $objp->duration;
3870  }
3871  $opt .= "</option>\n";
3872 
3873  $form .= $opt;
3874  $i++;
3875  }
3876  }
3877 
3878  $form .= '</select>';
3879  $this->db->free($result);
3880  return $form;
3881  } else {
3882  dol_print_error($this->db);
3883  return '';
3884  }
3885  }
3886 
3887  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3888 
3898  public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3899  {
3900  // phpcs:enable
3901  // looking for users
3902  $sql = "SELECT a.rowid, a.label";
3903  $sql .= " FROM " . $this->db->prefix() . "societe_address as a";
3904  $sql .= " WHERE a.fk_soc = " . ((int) $socid);
3905  $sql .= " ORDER BY a.label ASC";
3906 
3907  dol_syslog(get_class($this) . "::select_address", LOG_DEBUG);
3908  $resql = $this->db->query($sql);
3909  if ($resql) {
3910  print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
3911  if ($showempty) {
3912  print '<option value="0">&nbsp;</option>';
3913  }
3914  $num = $this->db->num_rows($resql);
3915  $i = 0;
3916  if ($num) {
3917  while ($i < $num) {
3918  $obj = $this->db->fetch_object($resql);
3919 
3920  if ($selected && $selected == $obj->rowid) {
3921  print '<option value="' . $obj->rowid . '" selected>' . $obj->label . '</option>';
3922  } else {
3923  print '<option value="' . $obj->rowid . '">' . $obj->label . '</option>';
3924  }
3925  $i++;
3926  }
3927  }
3928  print '</select>';
3929  return $num;
3930  } else {
3931  dol_print_error($this->db);
3932  return -1;
3933  }
3934  }
3935 
3936  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3937 
3944  {
3945  // phpcs:enable
3946  global $langs;
3947 
3948  $num = count($this->cache_conditions_paiements);
3949  if ($num > 0) {
3950  return 0; // Cache already loaded
3951  }
3952 
3953  dol_syslog(__METHOD__, LOG_DEBUG);
3954 
3955  $sql = "SELECT rowid, code, libelle as label, deposit_percent";
3956  $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
3957  $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
3958  $sql .= " AND active > 0";
3959  $sql .= " ORDER BY sortorder";
3960 
3961  $resql = $this->db->query($sql);
3962  if ($resql) {
3963  $num = $this->db->num_rows($resql);
3964  $i = 0;
3965  while ($i < $num) {
3966  $obj = $this->db->fetch_object($resql);
3967 
3968  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3969  $label = ($langs->trans("PaymentConditionShort" . $obj->code) != ("PaymentConditionShort" . $obj->code) ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
3970  $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3971  $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3972  $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
3973  $i++;
3974  }
3975 
3976  //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
3977 
3978  return $num;
3979  } else {
3980  dol_print_error($this->db);
3981  return -1;
3982  }
3983  }
3984 
3985  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3986 
3992  public function load_cache_availability()
3993  {
3994  // phpcs:enable
3995  global $langs;
3996 
3997  $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
3998  if ($num > 0) {
3999  return 0; // Cache already loaded
4000  }
4001 
4002  dol_syslog(__METHOD__, LOG_DEBUG);
4003 
4004  $langs->load('propal');
4005 
4006  $sql = "SELECT rowid, code, label, position";
4007  $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4008  $sql .= " WHERE active > 0";
4009 
4010  $resql = $this->db->query($sql);
4011  if ($resql) {
4012  $num = $this->db->num_rows($resql);
4013  $i = 0;
4014  while ($i < $num) {
4015  $obj = $this->db->fetch_object($resql);
4016 
4017  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4018  $label = ($langs->trans("AvailabilityType" . $obj->code) != ("AvailabilityType" . $obj->code) ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4019  $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4020  $this->cache_availability[$obj->rowid]['label'] = $label;
4021  $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4022  $i++;
4023  }
4024 
4025  $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4026 
4027  return $num;
4028  } else {
4029  dol_print_error($this->db);
4030  return -1;
4031  }
4032  }
4033 
4044  public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4045  {
4046  global $langs, $user;
4047 
4048  $this->load_cache_availability();
4049 
4050  dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4051 
4052  print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4053  if ($addempty) {
4054  print '<option value="0">&nbsp;</option>';
4055  }
4056  foreach ($this->cache_availability as $id => $arrayavailability) {
4057  if ($selected == $id) {
4058  print '<option value="' . $id . '" selected>';
4059  } else {
4060  print '<option value="' . $id . '">';
4061  }
4062  print dol_escape_htmltag($arrayavailability['label']);
4063  print '</option>';
4064  }
4065  print '</select>';
4066  if ($user->admin) {
4067  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4068  }
4069  print ajax_combobox($htmlname);
4070  }
4071 
4077  public function loadCacheInputReason()
4078  {
4079  global $langs;
4080 
4081  $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4082  if ($num > 0) {
4083  return 0; // Cache already loaded
4084  }
4085 
4086  $sql = "SELECT rowid, code, label";
4087  $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4088  $sql .= " WHERE active > 0";
4089 
4090  $resql = $this->db->query($sql);
4091  if ($resql) {
4092  $num = $this->db->num_rows($resql);
4093  $i = 0;
4094  $tmparray = array();
4095  while ($i < $num) {
4096  $obj = $this->db->fetch_object($resql);
4097 
4098  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4099  $label = ($obj->label != '-' ? $obj->label : '');
4100  if ($langs->trans("DemandReasonType" . $obj->code) != ("DemandReasonType" . $obj->code)) {
4101  $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4102  }
4103  if ($langs->trans($obj->code) != $obj->code) {
4104  $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4105  }
4106 
4107  $tmparray[$obj->rowid]['id'] = $obj->rowid;
4108  $tmparray[$obj->rowid]['code'] = $obj->code;
4109  $tmparray[$obj->rowid]['label'] = $label;
4110  $i++;
4111  }
4112 
4113  $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4114 
4115  unset($tmparray);
4116  return $num;
4117  } else {
4118  dol_print_error($this->db);
4119  return -1;
4120  }
4121  }
4122 
4135  public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4136  {
4137  global $langs, $user;
4138 
4139  $this->loadCacheInputReason();
4140 
4141  print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4142  if ($addempty) {
4143  print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4144  }
4145  foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4146  if ($arraydemandreason['code'] == $exclude) {
4147  continue;
4148  }
4149 
4150  if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4151  print '<option value="' . $arraydemandreason['id'] . '" selected>';
4152  } else {
4153  print '<option value="' . $arraydemandreason['id'] . '">';
4154  }
4155  $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4156  print $langs->trans($label);
4157  print '</option>';
4158  }
4159  print '</select>';
4160  if ($user->admin && empty($notooltip)) {
4161  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4162  }
4163  print ajax_combobox('select_' . $htmlname);
4164  }
4165 
4166  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4167 
4173  public function load_cache_types_paiements()
4174  {
4175  // phpcs:enable
4176  global $langs;
4177 
4178  $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4179  if ($num > 0) {
4180  return $num; // Cache already loaded
4181  }
4182 
4183  dol_syslog(__METHOD__, LOG_DEBUG);
4184 
4185  $this->cache_types_paiements = array();
4186 
4187  $sql = "SELECT id, code, libelle as label, type, active";
4188  $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4189  $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4190 
4191  $resql = $this->db->query($sql);
4192  if ($resql) {
4193  $num = $this->db->num_rows($resql);
4194  $i = 0;
4195  while ($i < $num) {
4196  $obj = $this->db->fetch_object($resql);
4197 
4198  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4199  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != ("PaymentTypeShort" . $obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4200  $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4201  $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4202  $this->cache_types_paiements[$obj->id]['label'] = $label;
4203  $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4204  $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4205  $i++;
4206  }
4207 
4208  $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4209 
4210  return $num;
4211  } else {
4212  dol_print_error($this->db);
4213  return -1;
4214  }
4215  }
4216 
4217 
4218  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4219 
4237  public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4238  {
4239  // phpcs:enable
4240  print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4241  }
4242 
4243 
4260  public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4261  {
4262  global $langs, $user, $conf;
4263 
4264  $out = '';
4265  dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4266 
4268 
4269  // Set default value if not already set by caller
4270  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
4271  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4272  }
4273 
4274  $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4275  if ($addempty) {
4276  $out .= '<option value="0">&nbsp;</option>';
4277  }
4278 
4279  $selectedDepositPercent = null;
4280 
4281  foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4282  if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4283  continue;
4284  }
4285 
4286  if ($selected == $id) {
4287  $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4288  $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4289  } else {
4290  $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4291  }
4292  $label = $arrayconditions['label'];
4293 
4294  if (!empty($arrayconditions['deposit_percent'])) {
4295  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4296  }
4297 
4298  $out .= $label;
4299  $out .= '</option>';
4300  }
4301  $out .= '</select>';
4302  if ($user->admin && empty($noinfoadmin)) {
4303  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4304  }
4305  $out .= ajax_combobox($htmlname);
4306 
4307  if ($deposit_percent >= 0) {
4308  $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4309  $out .= $langs->trans('DepositPercent') . ' : ';
4310  $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4311  $out .= '</span>';
4312  $out .= '
4313  <script nonce="' . getNonce() . '">
4314  $(document).ready(function () {
4315  $("#' . $htmlname . '").change(function () {
4316  let $selected = $(this).find("option:selected");
4317  let depositPercent = $selected.attr("data-deposit_percent");
4318 
4319  if (depositPercent.length > 0) {
4320  $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4321  } else {
4322  $("#' . $htmlname . '_deposit_percent_container").hide();
4323  }
4324 
4325  return true;
4326  });
4327  });
4328  </script>';
4329  }
4330 
4331  return $out;
4332  }
4333 
4334 
4335  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4336 
4353  public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4354  {
4355  // phpcs:enable
4356  global $langs, $user, $conf;
4357 
4358  $out = '';
4359 
4360  dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4361 
4362  $filterarray = array();
4363  if ($filtertype == 'CRDT') {
4364  $filterarray = array(0, 2, 3);
4365  } elseif ($filtertype == 'DBIT') {
4366  $filterarray = array(1, 2, 3);
4367  } elseif ($filtertype != '' && $filtertype != '-1') {
4368  $filterarray = explode(',', $filtertype);
4369  }
4370 
4371  $this->load_cache_types_paiements();
4372 
4373  // Set default value if not already set by caller
4374  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
4375  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4376  }
4377 
4378  $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4379  if ($empty) {
4380  $out .= '<option value="">&nbsp;</option>';
4381  }
4382  foreach ($this->cache_types_paiements as $id => $arraytypes) {
4383  // If not good status
4384  if ($active >= 0 && $arraytypes['active'] != $active) {
4385  continue;
4386  }
4387 
4388  // On passe si on a demande de filtrer sur des modes de paiments particuliers
4389  if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4390  continue;
4391  }
4392 
4393  // We discard empty line if showempty is on because an empty line has already been output.
4394  if ($empty && empty($arraytypes['code'])) {
4395  continue;
4396  }
4397 
4398  if ($format == 0) {
4399  $out .= '<option value="' . $id . '"';
4400  } elseif ($format == 1) {
4401  $out .= '<option value="' . $arraytypes['code'] . '"';
4402  } elseif ($format == 2) {
4403  $out .= '<option value="' . $arraytypes['code'] . '"';
4404  } elseif ($format == 3) {
4405  $out .= '<option value="' . $id . '"';
4406  }
4407  // Print attribute selected or not
4408  if ($format == 1 || $format == 2) {
4409  if ($selected == $arraytypes['code']) {
4410  $out .= ' selected';
4411  }
4412  } else {
4413  if ($selected == $id) {
4414  $out .= ' selected';
4415  }
4416  }
4417  $out .= '>';
4418  $value = '';
4419  if ($format == 0) {
4420  $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4421  } elseif ($format == 1) {
4422  $value = $arraytypes['code'];
4423  } elseif ($format == 2) {
4424  $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4425  } elseif ($format == 3) {
4426  $value = $arraytypes['code'];
4427  }
4428  $out .= $value ? $value : '&nbsp;';
4429  $out .= '</option>';
4430  }
4431  $out .= '</select>';
4432  if ($user->admin && !$noadmininfo) {
4433  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4434  }
4435  $out .= ajax_combobox('select' . $htmlname);
4436 
4437  if (empty($nooutput)) {
4438  print $out;
4439  } else {
4440  return $out;
4441  }
4442  }
4443 
4444 
4453  public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4454  {
4455  global $langs;
4456 
4457  $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4458  $options = array(
4459  'HT' => $langs->trans("HT"),
4460  'TTC' => $langs->trans("TTC")
4461  );
4462  foreach ($options as $id => $value) {
4463  if ($selected == $id) {
4464  $return .= '<option value="' . $id . '" selected>' . $value;
4465  } else {
4466  $return .= '<option value="' . $id . '">' . $value;
4467  }
4468  $return .= '</option>';
4469  }
4470  $return .= '</select>';
4471  if ($addjscombo) {
4472  $return .= ajax_combobox('select_' . $htmlname);
4473  }
4474 
4475  return $return;
4476  }
4477 
4478  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4479 
4485  public function load_cache_transport_mode()
4486  {
4487  // phpcs:enable
4488  global $langs;
4489 
4490  $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4491  if ($num > 0) {
4492  return $num; // Cache already loaded
4493  }
4494 
4495  dol_syslog(__METHOD__, LOG_DEBUG);
4496 
4497  $this->cache_transport_mode = array();
4498 
4499  $sql = "SELECT rowid, code, label, active";
4500  $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4501  $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4502 
4503  $resql = $this->db->query($sql);
4504  if ($resql) {
4505  $num = $this->db->num_rows($resql);
4506  $i = 0;
4507  while ($i < $num) {
4508  $obj = $this->db->fetch_object($resql);
4509 
4510  // If traduction exist, we use it else we take the default label
4511  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != ("PaymentTypeShort" . $obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4512  $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4513  $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4514  $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4515  $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4516  $i++;
4517  }
4518 
4519  $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4520 
4521  return $num;
4522  } else {
4523  dol_print_error($this->db);
4524  return -1;
4525  }
4526  }
4527 
4541  public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4542  {
4543  global $langs, $user;
4544 
4545  dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4546 
4547  $this->load_cache_transport_mode();
4548 
4549  print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4550  if ($empty) {
4551  print '<option value="">&nbsp;</option>';
4552  }
4553  foreach ($this->cache_transport_mode as $id => $arraytypes) {
4554  // If not good status
4555  if ($active >= 0 && $arraytypes['active'] != $active) {
4556  continue;
4557  }
4558 
4559  // We discard empty line if showempty is on because an empty line has already been output.
4560  if ($empty && empty($arraytypes['code'])) {
4561  continue;
4562  }
4563 
4564  if ($format == 0) {
4565  print '<option value="' . $id . '"';
4566  } elseif ($format == 1) {
4567  print '<option value="' . $arraytypes['code'] . '"';
4568  } elseif ($format == 2) {
4569  print '<option value="' . $arraytypes['code'] . '"';
4570  } elseif ($format == 3) {
4571  print '<option value="' . $id . '"';
4572  }
4573  // If text is selected, we compare with code, else with id
4574  if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4575  print ' selected';
4576  } elseif ($selected == $id) {
4577  print ' selected';
4578  }
4579  print '>';
4580  $value = '';
4581  if ($format == 0) {
4582  $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4583  } elseif ($format == 1) {
4584  $value = $arraytypes['code'];
4585  } elseif ($format == 2) {
4586  $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4587  } elseif ($format == 3) {
4588  $value = $arraytypes['code'];
4589  }
4590  print $value ? $value : '&nbsp;';
4591  print '</option>';
4592  }
4593  print '</select>';
4594  if ($user->admin && !$noadmininfo) {
4595  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4596  }
4597  }
4598 
4611  public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4612  {
4613  global $langs, $conf, $user;
4614 
4615  $langs->load("admin");
4616  $langs->load("deliveries");
4617 
4618  $sql = "SELECT rowid, code, libelle as label";
4619  $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4620  $sql .= " WHERE active > 0";
4621  if ($filtre) {
4622  $sql .= " AND " . $filtre;
4623  }
4624  $sql .= " ORDER BY libelle ASC";
4625 
4626  dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4627  $result = $this->db->query($sql);
4628  if ($result) {
4629  $num = $this->db->num_rows($result);
4630  $i = 0;
4631  if ($num) {
4632  print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4633  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4634  print '<option value="-1">&nbsp;</option>';
4635  }
4636  while ($i < $num) {
4637  $obj = $this->db->fetch_object($result);
4638  if ($selected == $obj->rowid) {
4639  print '<option value="' . $obj->rowid . '" selected>';
4640  } else {
4641  print '<option value="' . $obj->rowid . '">';
4642  }
4643  print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4644  print '</option>';
4645  $i++;
4646  }
4647  print "</select>";
4648  if ($user->admin && empty($noinfoadmin)) {
4649  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4650  }
4651 
4652  print ajax_combobox('select' . $htmlname);
4653  } else {
4654  print $langs->trans("NoShippingMethodDefined");
4655  }
4656  } else {
4657  dol_print_error($this->db);
4658  }
4659  }
4660 
4670  public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4671  {
4672  global $langs;
4673 
4674  $langs->load("deliveries");
4675 
4676  if ($htmlname != "none") {
4677  print '<form method="POST" action="' . $page . '">';
4678  print '<input type="hidden" name="action" value="setshippingmethod">';
4679  print '<input type="hidden" name="token" value="' . newToken() . '">';
4680  $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4681  print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4682  print '</form>';
4683  } else {
4684  if ($selected) {
4685  $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4686  print $langs->trans("SendingMethod" . strtoupper($code));
4687  } else {
4688  print "&nbsp;";
4689  }
4690  }
4691  }
4692 
4701  public function selectSituationInvoices($selected = '', $socid = 0)
4702  {
4703  global $langs;
4704 
4705  $langs->load('bills');
4706 
4707  $opt = '<option value="" selected></option>';
4708  $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4709  $sql .= ' FROM ' . $this->db->prefix() . 'facture';
4710  $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
4711  $sql .= ' AND situation_counter >= 1';
4712  $sql .= ' AND fk_soc = ' . (int) $socid;
4713  $sql .= ' AND type <> 2';
4714  $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4715  $resql = $this->db->query($sql);
4716 
4717  if ($resql && $this->db->num_rows($resql) > 0) {
4718  // Last seen cycle
4719  $ref = 0;
4720  while ($obj = $this->db->fetch_object($resql)) {
4721  //Same cycle ?
4722  if ($obj->situation_cycle_ref != $ref) {
4723  // Just seen this cycle
4724  $ref = $obj->situation_cycle_ref;
4725  //not final ?
4726  if ($obj->situation_final != 1) {
4727  //Not prov?
4728  if (substr($obj->ref, 1, 4) != 'PROV') {
4729  if ($selected == $obj->rowid) {
4730  $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
4731  } else {
4732  $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
4733  }
4734  }
4735  }
4736  }
4737  }
4738  } else {
4739  dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
4740  }
4741  if ($opt == '<option value ="" selected></option>') {
4742  $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
4743  }
4744  return $opt;
4745  }
4746 
4756  public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4757  {
4758  global $langs;
4759 
4760  $langs->load('products');
4761 
4762  $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
4763 
4764  $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
4765  $sql .= ' WHERE active > 0';
4766  if (!empty($unit_type)) {
4767  $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
4768  }
4769  $sql .= " ORDER BY sortorder";
4770 
4771  $resql = $this->db->query($sql);
4772  if ($resql && $this->db->num_rows($resql) > 0) {
4773  if ($showempty) {
4774  $return .= '<option value="none"></option>';
4775  }
4776 
4777  while ($res = $this->db->fetch_object($resql)) {
4778  $unitLabel = $res->label;
4779  if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
4780  $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
4781  }
4782 
4783  if ($selected == $res->rowid) {
4784  $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
4785  } else {
4786  $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
4787  }
4788  }
4789  $return .= '</select>';
4790  }
4791  return $return;
4792  }
4793 
4794  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4795 
4810  public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4811  {
4812  // phpcs:enable
4813  global $langs, $conf;
4814 
4815  $out = '';
4816 
4817  $langs->load("admin");
4818  $num = 0;
4819 
4820  $sql = "SELECT rowid, label, bank, clos as status, currency_code";
4821  $sql .= " FROM " . $this->db->prefix() . "bank_account";
4822  $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
4823  if ($status != 2) {
4824  $sql .= " AND clos = " . (int) $status;
4825  }
4826  if ($filtre) {
4827  $sql .= " AND " . $filtre;
4828  }
4829  $sql .= " ORDER BY label";
4830 
4831  dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
4832  $result = $this->db->query($sql);
4833  if ($result) {
4834  $num = $this->db->num_rows($result);
4835  $i = 0;
4836  if ($num) {
4837  $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4838  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4839  $out .= '<option value="-1">&nbsp;</option>';
4840  }
4841 
4842  while ($i < $num) {
4843  $obj = $this->db->fetch_object($result);
4844  if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4845  $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
4846  } else {
4847  $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
4848  }
4849  $out .= trim($obj->label);
4850  if ($showcurrency) {
4851  $out .= ' (' . $obj->currency_code . ')';
4852  }
4853  if ($status == 2 && $obj->status == 1) {
4854  $out .= ' (' . $langs->trans("Closed") . ')';
4855  }
4856  $out .= '</option>';
4857  $i++;
4858  }
4859  $out .= "</select>";
4860  $out .= ajax_combobox('select' . $htmlname);
4861  } else {
4862  if ($status == 0) {
4863  $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
4864  } else {
4865  $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
4866  }
4867  }
4868  } else {
4869  dol_print_error($this->db);
4870  }
4871 
4872  // Output or return
4873  if (empty($nooutput)) {
4874  print $out;
4875  } else {
4876  return $out;
4877  }
4878 
4879  return $num;
4880  }
4881 
4893  public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4894  {
4895  global $langs, $conf;
4896 
4897  $langs->load("admin");
4898  $num = 0;
4899 
4900  $sql = "SELECT rowid, name, fk_country, status, entity";
4901  $sql .= " FROM " . $this->db->prefix() . "establishment";
4902  $sql .= " WHERE 1=1";
4903  if ($status != 2) {
4904  $sql .= " AND status = " . (int) $status;
4905  }
4906  if ($filtre) {
4907  $sql .= " AND " . $filtre;
4908  }
4909  $sql .= " ORDER BY name";
4910 
4911  dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
4912  $result = $this->db->query($sql);
4913  if ($result) {
4914  $num = $this->db->num_rows($result);
4915  $i = 0;
4916  if ($num) {
4917  print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4918  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4919  print '<option value="-1">&nbsp;</option>';
4920  }
4921 
4922  while ($i < $num) {
4923  $obj = $this->db->fetch_object($result);
4924  if ($selected == $obj->rowid) {
4925  print '<option value="' . $obj->rowid . '" selected>';
4926  } else {
4927  print '<option value="' . $obj->rowid . '">';
4928  }
4929  print trim($obj->name);
4930  if ($status == 2 && $obj->status == 1) {
4931  print ' (' . $langs->trans("Closed") . ')';
4932  }
4933  print '</option>';
4934  $i++;
4935  }
4936  print "</select>";
4937  } else {
4938  if ($status == 0) {
4939  print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
4940  } else {
4941  print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
4942  }
4943  }
4944 
4945  return $num;
4946  } else {
4947  dol_print_error($this->db);
4948  return -1;
4949  }
4950  }
4951 
4961  public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4962  {
4963  global $langs;
4964  if ($htmlname != "none") {
4965  print '<form method="POST" action="' . $page . '">';
4966  print '<input type="hidden" name="action" value="setbankaccount">';
4967  print '<input type="hidden" name="token" value="' . newToken() . '">';
4968  print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4969  $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4970  if ($nbaccountfound > 0) {
4971  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
4972  }
4973  print '</form>';
4974  } else {
4975  $langs->load('banks');
4976 
4977  if ($selected) {
4978  require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
4979  $bankstatic = new Account($this->db);
4980  $result = $bankstatic->fetch($selected);
4981  if ($result) {
4982  print $bankstatic->getNomUrl(1);
4983  }
4984  } else {
4985  print "&nbsp;";
4986  }
4987  }
4988  }
4989 
4990  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4991 
5010  public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
5011  {
5012  // phpcs:enable
5013  global $conf, $langs;
5014  $langs->load("categories");
5015 
5016  include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5017 
5018  // For backward compatibility
5019  if (is_numeric($type)) {
5020  dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5021  }
5022 
5023  if ($type === Categorie::TYPE_BANK_LINE) {
5024  // TODO Move this into common category feature
5025  $cate_arbo = array();
5026  $sql = "SELECT c.label, c.rowid";
5027  $sql .= " FROM " . $this->db->prefix() . "bank_categ as c";
5028  $sql .= " WHERE entity = " . $conf->entity;
5029  $sql .= " ORDER BY c.label";
5030  $result = $this->db->query($sql);
5031  if ($result) {
5032  $num = $this->db->num_rows($result);
5033  $i = 0;
5034  while ($i < $num) {
5035  $objp = $this->db->fetch_object($result);
5036  if ($objp) {
5037  $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5038  }
5039  $i++;
5040  }
5041  $this->db->free($result);
5042  } else {
5043  dol_print_error($this->db);
5044  }
5045  } else {
5046  $cat = new Categorie($this->db);
5047  $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
5048  }
5049 
5050  $outarray = array();
5051 
5052  $output = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5053  if (is_array($cate_arbo)) {
5054  if (!count($cate_arbo)) {
5055  $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5056  } else {
5057  $output .= '<option value="-1">&nbsp;</option>';
5058  foreach ($cate_arbo as $key => $value) {
5059  if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5060  $add = 'selected ';
5061  } else {
5062  $add = '';
5063  }
5064  $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5065  $output .= ' data-html="' . dol_escape_htmltag(img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"') . dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle')) . '"';
5066  $output .= '>';
5067  $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5068  $output .= '</option>';
5069 
5070  $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5071  }
5072  }
5073  }
5074  $output .= '</select>';
5075  $output .= "\n";
5076 
5077  if ($outputmode == 2) {
5078  return $cate_arbo;
5079  } elseif ($outputmode) {
5080  return $outarray;
5081  }
5082  return $output;
5083  }
5084 
5085  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5086 
5103  public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5104  {
5105  // phpcs:enable
5106  dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5107  print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5108  }
5109 
5137  public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5138  {
5139  global $langs, $conf;
5140 
5141  $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5142  $formconfirm = '';
5143  $inputok = array();
5144  $inputko = array();
5145 
5146  // Clean parameters
5147  $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5148  if ($conf->browser->layout == 'phone') {
5149  $width = '95%';
5150  }
5151 
5152  // Set height automatically if not defined
5153  if (empty($height)) {
5154  $height = 220;
5155  if (is_array($formquestion) && count($formquestion) > 2) {
5156  $height += ((count($formquestion) - 2) * 24);
5157  }
5158  }
5159 
5160  if (is_array($formquestion) && !empty($formquestion)) {
5161  // First add hidden fields and value
5162  foreach ($formquestion as $key => $input) {
5163  if (is_array($input) && !empty($input)) {
5164  if ($input['type'] == 'hidden') {
5165  $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5166  $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5167 
5168  $more .= '<input type="hidden" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '" value="' . dol_escape_htmltag($input['value']) . '" class="' . $morecss . '"' . $moreattr . '>' . "\n";
5169  }
5170  }
5171  }
5172 
5173  // Now add questions
5174  $moreonecolumn = '';
5175  $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5176  foreach ($formquestion as $key => $input) {
5177  if (is_array($input) && !empty($input)) {
5178  $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5179  $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5180  $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5181 
5182  if ($input['type'] == 'text') {
5183  $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div><div class="tagtd"><input type="text" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
5184  } elseif ($input['type'] == 'password') {
5185  $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div><div class="tagtd"><input type="password" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
5186  } elseif ($input['type'] == 'textarea') {
5187  /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5188  $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5189  $more .= $input['value'];
5190  $more .= '</textarea>';
5191  $more .= '</div></div>'."\n";*/
5192  $moreonecolumn .= '<div class="margintoponly">';
5193  $moreonecolumn .= $input['label'] . '<br>';
5194  $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5195  $moreonecolumn .= $input['value'];
5196  $moreonecolumn .= '</textarea>';
5197  $moreonecolumn .= '</div>';
5198  } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5199  if (empty($morecss)) {
5200  $morecss = 'minwidth100';
5201  }
5202 
5203  $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5204  $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5205  $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5206  $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5207  $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5208  $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5209  $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5210 
5211  $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5212  if (!empty($input['label'])) {
5213  $more .= $input['label'] . '</div><div class="tagtd left">';
5214  }
5215  if ($input['type'] == 'select') {
5216  $more .= $this->selectarray($input['name'], $input['values'], isset($input['default']) ? $input['default'] : '-1', $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
5217  } else {
5218  $more .= $this->multiselectarray($input['name'], $input['values'], is_array($input['default']) ? $input['default'] : [$input['default']], $key_in_label, $value_as_key, $morecss, $translate, $maxlen, $moreattr);
5219  }
5220  $more .= '</div></div>' . "\n";
5221  } elseif ($input['type'] == 'checkbox') {
5222  $more .= '<div class="tagtr">';
5223  $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5224  $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5225  if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5226  $more .= ' checked';
5227  }
5228  if (is_bool($input['value']) && $input['value']) {
5229  $more .= ' checked';
5230  }
5231  if (isset($input['disabled'])) {
5232  $more .= ' disabled';
5233  }
5234  $more .= ' /></div>';
5235  $more .= '</div>' . "\n";
5236  } elseif ($input['type'] == 'radio') {
5237  $i = 0;
5238  foreach ($input['values'] as $selkey => $selval) {
5239  $more .= '<div class="tagtr">';
5240  if (isset($input['label'])) {
5241  if ($i == 0) {
5242  $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5243  } else {
5244  $more .= '<div clas="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5245  }
5246  }
5247  $more .= '<div class="tagtd' . ($i == 0 ? ' tdtop' : '') . '"><input type="radio" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name'] . $selkey) . '" name="' . dol_escape_htmltag($input['name']) . '" value="' . $selkey . '"' . $moreattr;
5248  if (!empty($input['disabled'])) {
5249  $more .= ' disabled';
5250  }
5251  if (isset($input['default']) && $input['default'] === $selkey) {
5252  $more .= ' checked="checked"';
5253  }
5254  $more .= ' /> ';
5255  $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5256  $more .= '</div></div>' . "\n";
5257  $i++;
5258  }
5259  } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5260  $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5261  $more .= '<div class="tagtd">';
5262  $addnowlink = (empty($input['datenow']) ? 0 : 1);
5263  $h = $m = 0;
5264  if ($input['type'] == 'datetime') {
5265  $h = isset($input['hours']) ? $input['hours'] : 1;
5266  $m = isset($input['minutes']) ? $input['minutes'] : 1;
5267  }
5268  $more .= $this->selectDate($input['value'], $input['name'], $h, $m, 0, '', 1, $addnowlink);
5269  $more .= '</div></div>'."\n";
5270  $formquestion[] = array('name'=>$input['name'].'day');
5271  $formquestion[] = array('name'=>$input['name'].'month');
5272  $formquestion[] = array('name'=>$input['name'].'year');
5273  $formquestion[] = array('name'=>$input['name'].'hour');
5274  $formquestion[] = array('name'=>$input['name'].'min');
5275  } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5276  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5277  if (!empty($input['label'])) {
5278  $more .= $input['label'] . '</div><div class="tagtd">';
5279  }
5280  $more .= $input['value'];
5281  $more .= '</div></div>' . "\n";
5282  } elseif ($input['type'] == 'onecolumn') {
5283  $moreonecolumn .= '<div class="margintoponly">';
5284  $moreonecolumn .= $input['value'];
5285  $moreonecolumn .= '</div>' . "\n";
5286  } elseif ($input['type'] == 'hidden') {
5287  // Do nothing more, already added by a previous loop
5288  } elseif ($input['type'] == 'separator') {
5289  $more .= '<br>';
5290  } else {
5291  $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5292  }
5293  }
5294  }
5295  $more .= '</div>' . "\n";
5296  $more .= $moreonecolumn;
5297  }
5298 
5299  // JQUERY method dialog is broken with smartphone, we use standard HTML.
5300  // Note: When using dol_use_jmobile or no js, you must also check code for button use a GET url with action=xxx and check that you also output the confirm code when action=xxx
5301  // See page product/card.php for example
5302  if (!empty($conf->dol_use_jmobile)) {
5303  $useajax = 0;
5304  }
5305  if (empty($conf->use_javascript_ajax)) {
5306  $useajax = 0;
5307  }
5308 
5309  if ($useajax) {
5310  $autoOpen = true;
5311  $dialogconfirm = 'dialog-confirm';
5312  $button = '';
5313  if (!is_numeric($useajax)) {
5314  $button = $useajax;
5315  $useajax = 1;
5316  $autoOpen = false;
5317  $dialogconfirm .= '-' . $button;
5318  }
5319  $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5320  $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5321 
5322  // Add input fields into list of fields to read during submit (inputok and inputko)
5323  if (is_array($formquestion)) {
5324  foreach ($formquestion as $key => $input) {
5325  //print "xx ".$key." rr ".is_array($input)."<br>\n";
5326  // Add name of fields to propagate with the GET when submitting the form with button OK.
5327  if (is_array($input) && isset($input['name'])) {
5328  if (strpos($input['name'], ',') > 0) {
5329  $inputok = array_merge($inputok, explode(',', $input['name']));
5330  } else {
5331  array_push($inputok, $input['name']);
5332  }
5333  }
5334  // Add name of fields to propagate with the GET when submitting the form with button KO.
5335  if (isset($input['inputko']) && $input['inputko'] == 1) {
5336  array_push($inputko, $input['name']);
5337  }
5338  }
5339  }
5340 
5341  // Show JQuery confirm box.
5342  $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5343  if (is_array($formquestion) && !empty($formquestion['text'])) {
5344  $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5345  }
5346  if (!empty($more)) {
5347  $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5348  }
5349  $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help('', '') . ' ' . $question . '</div>' : '');
5350  $formconfirm .= '</div>' . "\n";
5351 
5352  $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5353  $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5354  $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5355  $formconfirm .= 'jQuery(document).ready(function() {
5356  $(function() {
5357  $( "#' . $dialogconfirm . '" ).dialog(
5358  {
5359  autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5360  if ($newselectedchoice == 'no') {
5361  $formconfirm .= '
5362  open: function() {
5363  $(this).parent().find("button.ui-button:eq(2)").focus();
5364  },';
5365  }
5366 
5367  $jsforcursor = '';
5368  if ($useajax == 1) {
5369  $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5370  $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5371  }
5372 
5373  $postconfirmas = 'GET';
5374 
5375  $formconfirm .= '
5376  resizable: false,
5377  height: "' . $height . '",
5378  width: "' . $width . '",
5379  modal: true,
5380  closeOnEscape: false,
5381  buttons: {
5382  "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5383  var options = "token=' . urlencode(newToken()) . '";
5384  var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5385  var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5386  var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5387 
5388  if (inputok.length > 0) {
5389  $.each(inputok, function(i, inputname) {
5390  var more = "";
5391  var inputvalue;
5392  if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5393  inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5394  } else {
5395  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5396  inputvalue = $("#" + inputname + more).val();
5397  }
5398  if (typeof inputvalue == "undefined") { inputvalue=""; }
5399  console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5400  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5401  });
5402  }
5403  var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5404  if (pageyes.length > 0) {';
5405  if ($postconfirmas == 'GET') {
5406  $formconfirm .= 'location.href = urljump;';
5407  } else {
5408  $formconfirm .= $jsforcursor;
5409  $formconfirm .= 'var post = $.post(
5410  pageyes,
5411  options,
5412  function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5413  );';
5414  }
5415  $formconfirm .= '
5416  console.log("after post ok");
5417  }
5418  $(this).dialog("close");
5419  },
5420  "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5421  var options = "token=' . urlencode(newToken()) . '";
5422  var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5423  var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5424  var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5425  if (inputko.length > 0) {
5426  $.each(inputko, function(i, inputname) {
5427  var more = "";
5428  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5429  var inputvalue = $("#" + inputname + more).val();
5430  if (typeof inputvalue == "undefined") { inputvalue=""; }
5431  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5432  });
5433  }
5434  var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5435  //alert(urljump);
5436  if (pageno.length > 0) {';
5437  if ($postconfirmas == 'GET') {
5438  $formconfirm .= 'location.href = urljump;';
5439  } else {
5440  $formconfirm .= $jsforcursor;
5441  $formconfirm .= 'var post = $.post(
5442  pageno,
5443  options,
5444  function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5445  );';
5446  }
5447  $formconfirm .= '
5448  console.log("after post ko");
5449  }
5450  $(this).dialog("close");
5451  }
5452  }
5453  }
5454  );
5455 
5456  var button = "' . $button . '";
5457  if (button.length > 0) {
5458  $( "#" + button ).click(function() {
5459  $("#' . $dialogconfirm . '").dialog("open");
5460  });
5461  }
5462  });
5463  });
5464  </script>';
5465  $formconfirm .= "<!-- end ajax formconfirm -->\n";
5466  } else {
5467  $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5468 
5469  if (empty($disableformtag)) {
5470  $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5471  }
5472 
5473  $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5474  $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5475 
5476  $formconfirm .= '<table class="valid centpercent">' . "\n";
5477 
5478  // Line title
5479  $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5480  $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5481  $formconfirm .= '</td></tr>' . "\n";
5482 
5483  // Line text
5484  if (is_array($formquestion) && !empty($formquestion['text'])) {
5485  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5486  }
5487 
5488  // Line form fields
5489  if ($more) {
5490  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5491  $formconfirm .= $more;
5492  $formconfirm .= '</td></tr>' . "\n";
5493  }
5494 
5495  // Line with question
5496  $formconfirm .= '<tr class="valid">';
5497  $formconfirm .= '<td class="valid">' . $question . '</td>';
5498  $formconfirm .= '<td class="valid center">';
5499  $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5500  $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5501  $formconfirm .= '</td>';
5502  $formconfirm .= '</tr>' . "\n";
5503 
5504  $formconfirm .= '</table>' . "\n";
5505 
5506  if (empty($disableformtag)) {
5507  $formconfirm .= "</form>\n";
5508  }
5509  $formconfirm .= '<br>';
5510 
5511  if (!empty($conf->use_javascript_ajax)) {
5512  $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5513  $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5514  $formconfirm .= '
5515  $(document).ready(function () {
5516  $(".confirmvalidatebutton").on("click", function() {
5517  console.log("We click on button");
5518  $(this).attr("disabled", "disabled");
5519  setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5520  //console.log($(this).closest("form"));
5521  $(this).closest("form").submit();
5522  });
5523  });
5524  ';
5525  $formconfirm .= '</script>' . "\n";
5526  }
5527 
5528  $formconfirm .= "<!-- end formconfirm -->\n";
5529  }
5530 
5531  return $formconfirm;
5532  }
5533 
5534 
5535  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5536 
5552  public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5553  {
5554  // phpcs:enable
5555  global $langs;
5556 
5557  require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5558  require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5559 
5560  $out = '';
5561 
5562  $formproject = new FormProjets($this->db);
5563 
5564  $langs->load("project");
5565  if ($htmlname != "none") {
5566  $out .= '<form method="post" action="' . $page . '">';
5567  $out .= '<input type="hidden" name="action" value="classin">';
5568  $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5569  $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5570  $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5571  $out .= '</form>';
5572  } else {
5573  $out .= '<span class="project_head_block">';
5574  if ($selected) {
5575  $projet = new Project($this->db);
5576  $projet->fetch($selected);
5577  $out .= $projet->getNomUrl(0, '', 1);
5578  } else {
5579  $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5580  }
5581  $out .= '</span>';
5582  }
5583 
5584  if (empty($nooutput)) {
5585  print $out;
5586  return '';
5587  }
5588  return $out;
5589  }
5590 
5591  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5592 
5608  public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5609  {
5610  // phpcs:enable
5611  global $langs;
5612 
5613  $out = '';
5614 
5615  if ($htmlname != "none") {
5616  $out .= '<form method="POST" action="' . $page . '">';
5617  $out .= '<input type="hidden" name="action" value="setconditions">';
5618  $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5619  if ($type) {
5620  $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5621  }
5622  $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5623  $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5624  $out .= '</form>';
5625  } else {
5626  if ($selected) {
5628  if (isset($this->cache_conditions_paiements[$selected])) {
5629  $label = $this->cache_conditions_paiements[$selected]['label'];
5630 
5631  if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5632  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5633  }
5634 
5635  $out .= $label;
5636  } else {
5637  $langs->load('errors');
5638  $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5639  }
5640  } else {
5641  $out .= '&nbsp;';
5642  }
5643  }
5644 
5645  if (empty($nooutput)) {
5646  print $out;
5647  return '';
5648  }
5649  return $out;
5650  }
5651 
5652  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5653 
5663  public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5664  {
5665  // phpcs:enable
5666  global $langs;
5667  if ($htmlname != "none") {
5668  print '<form method="post" action="' . $page . '">';
5669  print '<input type="hidden" name="action" value="setavailability">';
5670  print '<input type="hidden" name="token" value="' . newToken() . '">';
5671  $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5672  print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5673  print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5674  print '</form>';
5675  } else {
5676  if ($selected) {
5677  $this->load_cache_availability();
5678  print $this->cache_availability[$selected]['label'];
5679  } else {
5680  print "&nbsp;";
5681  }
5682  }
5683  }
5684 
5695  public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5696  {
5697  global $langs;
5698  if ($htmlname != "none") {
5699  print '<form method="post" action="' . $page . '">';
5700  print '<input type="hidden" name="action" value="setdemandreason">';
5701  print '<input type="hidden" name="token" value="' . newToken() . '">';
5702  $this->selectInputReason($selected, $htmlname, -1, $addempty);
5703  print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5704  print '</form>';
5705  } else {
5706  if ($selected) {
5707  $this->loadCacheInputReason();
5708  foreach ($this->cache_demand_reason as $key => $val) {
5709  if ($val['id'] == $selected) {
5710  print $val['label'];
5711  break;
5712  }
5713  }
5714  } else {
5715  print "&nbsp;";
5716  }
5717  }
5718  }
5719 
5720  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5721 
5735  public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
5736  {
5737  // phpcs:enable
5738  global $langs;
5739 
5740  $ret = '';
5741 
5742  if ($htmlname != "none") {
5743  $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
5744  $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
5745  $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
5746  if ($type) {
5747  $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5748  }
5749  $ret .= '<table class="nobordernopadding">';
5750  $ret .= '<tr><td>';
5751  $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
5752  $ret .= '</td>';
5753  $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
5754  $ret .= '</tr></table></form>';
5755  } else {
5756  if ($displayhour) {
5757  $ret .= dol_print_date($selected, 'dayhour');
5758  } else {
5759  $ret .= dol_print_date($selected, 'day');
5760  }
5761  }
5762 
5763  if (empty($nooutput)) {
5764  print $ret;
5765  }
5766  return $ret;
5767  }
5768 
5769 
5770  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5771 
5782  public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
5783  {
5784  // phpcs:enable
5785  global $langs;
5786 
5787  if ($htmlname != "none") {
5788  print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
5789  print '<input type="hidden" name="action" value="set' . $htmlname . '">';
5790  print '<input type="hidden" name="token" value="' . newToken() . '">';
5791  print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5792  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5793  print '</form>';
5794  } else {
5795  if ($selected) {
5796  require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
5797  $theuser = new User($this->db);
5798  $theuser->fetch($selected);
5799  print $theuser->getNomUrl(1);
5800  } else {
5801  print "&nbsp;";
5802  }
5803  }
5804  }
5805 
5806 
5807  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5808 
5822  public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
5823  {
5824  // phpcs:enable
5825  global $langs;
5826 
5827  $out = '';
5828  if ($htmlname != "none") {
5829  $out .= '<form method="POST" action="' . $page . '">';
5830  $out .= '<input type="hidden" name="action" value="setmode">';
5831  $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5832  if ($type) {
5833  $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5834  }
5835  $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
5836  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5837  $out .= '</form>';
5838  } else {
5839  if ($selected) {
5840  $this->load_cache_types_paiements();
5841  $out .= $this->cache_types_paiements[$selected]['label'];
5842  } else {
5843  $out .= "&nbsp;";
5844  }
5845  }
5846 
5847  if ($nooutput) {
5848  return $out;
5849  } else {
5850  print $out;
5851  }
5852  return '';
5853  }
5854 
5865  public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5866  {
5867  global $langs;
5868  if ($htmlname != "none") {
5869  print '<form method="POST" action="' . $page . '">';
5870  print '<input type="hidden" name="action" value="settransportmode">';
5871  print '<input type="hidden" name="token" value="' . newToken() . '">';
5872  $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5873  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5874  print '</form>';
5875  } else {
5876  if ($selected) {
5877  $this->load_cache_transport_mode();
5878  print $this->cache_transport_mode[$selected]['label'];
5879  } else {
5880  print "&nbsp;";
5881  }
5882  }
5883  }
5884 
5885  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5886 
5895  public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5896  {
5897  // phpcs:enable
5898  global $langs;
5899  if ($htmlname != "none") {
5900  print '<form method="POST" action="' . $page . '">';
5901  print '<input type="hidden" name="action" value="setmulticurrencycode">';
5902  print '<input type="hidden" name="token" value="' . newToken() . '">';
5903  print $this->selectMultiCurrency($selected, $htmlname, 0);
5904  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5905  print '</form>';
5906  } else {
5907  dol_include_once('/core/lib/company.lib.php');
5908  print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5909  }
5910  }
5911 
5912  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5913 
5923  public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5924  {
5925  // phpcs:enable
5926  global $langs, $mysoc, $conf;
5927 
5928  if ($htmlname != "none") {
5929  print '<form method="POST" action="' . $page . '">';
5930  print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5931  print '<input type="hidden" name="token" value="' . newToken() . '">';
5932  print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
5933  print '<select name="calculation_mode">';
5934  print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
5935  print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
5936  print '</select> ';
5937  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5938  print '</form>';
5939  } else {
5940  if (!empty($rate)) {
5941  print price($rate, 1, $langs, 0, 0);
5942  if ($currency && $rate != 1) {
5943  print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
5944  }
5945  } else {
5946  print 1;
5947  }
5948  }
5949  }
5950 
5951 
5952  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5953 
5969  public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5970  {
5971  // phpcs:enable
5972  global $conf, $langs;
5973  if ($htmlname != "none") {
5974  print '<form method="post" action="' . $page . '">';
5975  print '<input type="hidden" name="action" value="setabsolutediscount">';
5976  print '<input type="hidden" name="token" value="' . newToken() . '">';
5977  print '<div class="inline-block">';
5978  if (!empty($discount_type)) {
5979  if (!empty($conf->global->FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS)) {
5980  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5981  $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5982  } else {
5983  $translationKey = 'HasCreditNoteFromSupplier';
5984  }
5985  } else {
5986  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5987  $translationKey = 'HasAbsoluteDiscountFromSupplier';
5988  } else {
5989  $translationKey = 'HasCreditNoteFromSupplier';
5990  }
5991  }
5992  } else {
5993  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5994  if (!$filter || $filter == "fk_facture_source IS NULL") {
5995  $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
5996  } else {
5997  $translationKey = 'CompanyHasCreditNote';
5998  }
5999  } else {
6000  if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6001  $translationKey = 'CompanyHasAbsoluteDiscount';
6002  } else {
6003  $translationKey = 'CompanyHasCreditNote';
6004  }
6005  }
6006  }
6007  print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6008  if (empty($hidelist)) {
6009  print ' ';
6010  }
6011  print '</div>';
6012  if (empty($hidelist)) {
6013  print '<div class="inline-block" style="padding-right: 10px">';
6014  $newfilter = 'discount_type=' . intval($discount_type);
6015  if (!empty($discount_type)) {
6016  $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6017  } else {
6018  $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6019  }
6020  if ($filter) {
6021  $newfilter .= ' AND (' . $filter . ')';
6022  }
6023  // output the combo of discounts
6024  $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
6025  if ($nbqualifiedlines > 0) {
6026  print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6027  if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6028  print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6029  }
6030  if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6031  print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6032  }
6033 
6034  print '>';
6035  }
6036  print '</div>';
6037  }
6038  if ($more) {
6039  print '<div class="inline-block">';
6040  print $more;
6041  print '</div>';
6042  }
6043  print '</form>';
6044  } else {
6045  if ($selected) {
6046  print $selected;
6047  } else {
6048  print "0";
6049  }
6050  }
6051  }
6052 
6053 
6054  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6055 
6065  public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6066  {
6067  // phpcs:enable
6068  global $langs, $conf;
6069 
6070  if ($htmlname != "none") {
6071  print '<form method="post" action="' . $page . '">';
6072  print '<input type="hidden" name="action" value="set_contact">';
6073  print '<input type="hidden" name="token" value="' . newToken() . '">';
6074  print '<table class="nobordernopadding">';
6075  print '<tr><td>';
6076  print $this->selectcontacts($societe->id, $selected, $htmlname);
6077  $num = $this->num;
6078  if ($num == 0) {
6079  $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6080  print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&amp;action=create&amp;backtoreferer=1">' . $addcontact . '</a>';
6081  }
6082  print '</td>';
6083  print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6084  print '</tr></table></form>';
6085  } else {
6086  if ($selected) {
6087  require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6088  $contact = new Contact($this->db);
6089  $contact->fetch($selected);
6090  print $contact->getFullName($langs);
6091  } else {
6092  print "&nbsp;";
6093  }
6094  }
6095  }
6096 
6097  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6098 
6115  public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6116  {
6117  // phpcs:enable
6118  global $langs;
6119 
6120  $out = '';
6121  if ($htmlname != "none") {
6122  $out .= '<form method="post" action="' . $page . '">';
6123  $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6124  $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6125  $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6126  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6127  $out .= '</form>';
6128  } else {
6129  if ($selected) {
6130  require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6131  $soc = new Societe($this->db);
6132  $soc->fetch($selected);
6133  $out .= $soc->getNomUrl(0, '');
6134  } else {
6135  $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6136  }
6137  }
6138 
6139  if ($nooutput) {
6140  return $out;
6141  } else {
6142  print $out;
6143  }
6144 
6145  return '';
6146  }
6147 
6148  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6149 
6158  public function select_currency($selected = '', $htmlname = 'currency_id')
6159  {
6160  // phpcs:enable
6161  print $this->selectCurrency($selected, $htmlname);
6162  }
6163 
6173  public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6174  {
6175  global $conf, $langs, $user;
6176 
6177  $langs->loadCacheCurrencies('');
6178 
6179  $out = '';
6180 
6181  if ($selected == 'euro' || $selected == 'euros') {
6182  $selected = 'EUR'; // Pour compatibilite
6183  }
6184 
6185  $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6186  if ($useempty) {
6187  $out .= '<option value="-1" selected></option>';
6188  }
6189  foreach ($langs->cache_currencies as $code_iso => $currency) {
6190  $labeltoshow = $currency['label'];
6191  if ($mode == 1) {
6192  $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6193  } else {
6194  $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6195  }
6196 
6197  if ($selected && $selected == $code_iso) {
6198  $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6199  } else {
6200  $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6201  }
6202  $out .= $labeltoshow;
6203  $out .= '</option>';
6204  }
6205  $out .= '</select>';
6206  if ($user->admin) {
6207  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6208  }
6209 
6210  // Make select dynamic
6211  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6212  $out .= ajax_combobox($htmlname);
6213 
6214  return $out;
6215  }
6216 
6229  public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6230  {
6231  global $conf, $langs;
6232 
6233  $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6234 
6235  $TCurrency = array();
6236 
6237  $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6238  $sql .= " WHERE entity IN ('" . getEntity('mutlicurrency') . "')";
6239  if ($filter) {
6240  $sql .= " AND " . $filter;
6241  }
6242  $resql = $this->db->query($sql);
6243  if ($resql) {
6244  while ($obj = $this->db->fetch_object($resql)) {
6245  $TCurrency[$obj->code] = $obj->code;
6246  }
6247  }
6248 
6249  $out = '';
6250  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6251  if ($useempty) {
6252  $out .= '<option value="">&nbsp;</option>';
6253  }
6254  // If company current currency not in table, we add it into list. Should always be available.
6255  if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6256  $TCurrency[$conf->currency] = $conf->currency;
6257  }
6258  if (count($TCurrency) > 0) {
6259  foreach ($langs->cache_currencies as $code_iso => $currency) {
6260  if (isset($TCurrency[$code_iso])) {
6261  if (!empty($selected) && $selected == $code_iso) {
6262  $out .= '<option value="' . $code_iso . '" selected="selected">';
6263  } else {
6264  $out .= '<option value="' . $code_iso . '">';
6265  }
6266 
6267  $out .= $currency['label'];
6268  $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6269  $out .= '</option>';
6270  }
6271  }
6272  }
6273 
6274  $out .= '</select>';
6275 
6276  // Make select dynamic
6277  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6278  $out .= ajax_combobox($htmlname);
6279 
6280  return $out;
6281  }
6282 
6283  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6284 
6291  public function load_cache_vatrates($country_code)
6292  {
6293  // phpcs:enable
6294  global $langs, $user;
6295 
6296  $num = count($this->cache_vatrates);
6297  if ($num > 0) {
6298  return $num; // Cache already loaded
6299  }
6300 
6301  dol_syslog(__METHOD__, LOG_DEBUG);
6302 
6303  $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6304  $sql .= " FROM " . $this->db->prefix() . "c_tva as t, " . $this->db->prefix() . "c_country as c";
6305  $sql .= " WHERE t.fk_pays = c.rowid";
6306  $sql .= " AND t.active > 0";
6307  $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6308  $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6309 
6310  $resql = $this->db->query($sql);
6311  if ($resql) {
6312  $num = $this->db->num_rows($resql);
6313  if ($num) {
6314  for ($i = 0; $i < $num; $i++) {
6315  $obj = $this->db->fetch_object($resql);
6316  $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
6317  $this->cache_vatrates[$i]['code'] = $obj->code;
6318  $this->cache_vatrates[$i]['txtva'] = $obj->taux;
6319  $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
6320  $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
6321  $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
6322  $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
6323  $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
6324 
6325  $this->cache_vatrates[$i]['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6326  $this->cache_vatrates[$i]['labelallrates'] = $obj->taux . '/' . ($obj->localtax1 ? $obj->localtax1 : '0') . '/' . ($obj->localtax2 ? $obj->localtax2 : '0') . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6327  $positiverates = '';
6328  if ($obj->taux) {
6329  $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6330  }
6331  if ($obj->localtax1) {
6332  $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6333  }
6334  if ($obj->localtax2) {
6335  $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6336  }
6337  if (empty($positiverates)) {
6338  $positiverates = '0';
6339  }
6340  $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6341  }
6342 
6343  return $num;
6344  } else {
6345  $this->error = '<span class="error">';
6346  $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6347  $reg = array();
6348  if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6349  $langs->load("errors");
6350  $new_country_code = $reg[1];
6351  $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
6352  $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6353  }
6354  $this->error .= '</span>';
6355  return -1;
6356  }
6357  } else {
6358  $this->error = '<span class="error">' . $this->db->error() . '</span>';
6359  return -2;
6360  }
6361  }
6362 
6363  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6364 
6386  public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
6387  {
6388  // phpcs:enable
6389  global $langs, $conf, $mysoc;
6390 
6391  $langs->load('errors');
6392 
6393  $return = '';
6394 
6395  // Define defaultnpr, defaultttx and defaultcode
6396  $defaultnpr = ($info_bits & 0x01);
6397  $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6398  $defaulttx = str_replace('*', '', $selectedrate);
6399  $defaultcode = '';
6400  $reg = array();
6401  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6402  $defaultcode = $reg[1];
6403  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6404  }
6405  //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6406 
6407  // Check parameters
6408  if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6409  if ($societe_vendeuse->id == $mysoc->id) {
6410  $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6411  } else {
6412  $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6413  }
6414  return $return;
6415  }
6416 
6417  //var_dump($societe_acheteuse);
6418  //print "name=$name, selectedrate=$selectedrate, seller=".$societe_vendeuse->country_code." buyer=".$societe_acheteuse->country_code." buyer is company=".$societe_acheteuse->isACompany()." idprod=$idprod, info_bits=$info_bits type=$type";
6419  //exit;
6420 
6421  // Define list of countries to use to search VAT rates to show
6422  // First we defined code_country to use to find list
6423  if (is_object($societe_vendeuse)) {
6424  $code_country = "'" . $societe_vendeuse->country_code . "'";
6425  } else {
6426  $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6427  }
6428  if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) { // If option to have vat for end customer for services is on
6429  require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6430  if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
6431  // We also add the buyer country code
6432  if (is_numeric($type)) {
6433  if ($type == 1) { // We know product is a service
6434  $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6435  }
6436  } elseif (!$idprod) { // We don't know type of product
6437  $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6438  } else {
6439  $prodstatic = new Product($this->db);
6440  $prodstatic->fetch($idprod);
6441  if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6442  $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6443  }
6444  }
6445  }
6446  }
6447 
6448  // Now we get list
6449  $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6450 
6451  if ($num > 0) {
6452  // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6453  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6454  $tmpthirdparty = new Societe($this->db);
6455 
6456  $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6457  $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6458 
6459  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6460  $defaultcode = $reg[1];
6461  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6462  }
6463  if (empty($defaulttx)) {
6464  $defaultnpr = 0;
6465  }
6466  }
6467 
6468  // If we fails to find a default vat rate, we take the last one in list
6469  // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6470  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6471  if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6472  // We take the last one found in list
6473  $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
6474  } else {
6475  // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6476  $defaulttx = '';
6477  if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6478  $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6479  }
6480  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6481  $defaultcode = $reg[1];
6482  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6483  }
6484  }
6485  }
6486 
6487  // Disabled if seller is not subject to VAT
6488  $disabled = false;
6489  $title = '';
6490  if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6491  // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6492  // of using supplier invoices (this is a very bad idea !)
6493  if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
6494  $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
6495  $disabled = true;
6496  }
6497  }
6498 
6499  if (!$options_only) {
6500  $return .= '<select class="flat minwidth50imp maxwidth100" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
6501  }
6502 
6503  $selectedfound = false;
6504  foreach ($this->cache_vatrates as $rate) {
6505  // Keep only 0 if seller is not subject to VAT
6506  if ($disabled && $rate['txtva'] != 0) {
6507  continue;
6508  }
6509 
6510  // Define key to use into select list
6511  $key = $rate['txtva'];
6512  $key .= $rate['nprtva'] ? '*' : '';
6513  if ($mode > 0 && $rate['code']) {
6514  $key .= ' (' . $rate['code'] . ')';
6515  }
6516  if ($mode < 0) {
6517  $key = $rate['rowid'];
6518  }
6519 
6520  $return .= '<option value="' . $key . '"';
6521  if (!$selectedfound) {
6522  if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6523  if ($defaultcode == $rate['code']) {
6524  $return .= ' selected';
6525  $selectedfound = true;
6526  }
6527  } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6528  $return .= ' selected';
6529  $selectedfound = true;
6530  }
6531  }
6532  $return .= '>';
6533 
6534  // Show label of VAT
6535  if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
6536  // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6537  $return .= $rate['labelpositiverates'];
6538  } else {
6539  // Simple label
6540  $return .= vatrate($rate['label']);
6541  }
6542 
6543  //$return.=($rate['code']?' '.$rate['code']:'');
6544  $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6545 
6546  $return .= '</option>';
6547  }
6548 
6549  if (!$options_only) {
6550  $return .= '</select>';
6551  //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
6552  }
6553  } else {
6554  $return .= $this->error;
6555  }
6556 
6557  $this->num = $num;
6558  return $return;
6559  }
6560 
6561 
6562  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6563 
6588  public function select_date($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $nooutput = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '')
6589  {
6590  // phpcs:enable
6591  $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6592  if (!empty($nooutput)) {
6593  return $retstring;
6594  }
6595  print $retstring;
6596 
6597  return '';
6598  }
6599 
6615  public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6616  {
6617  global $langs;
6618 
6619  $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6620  if ($forcenewline) {
6621  $ret .= '<br>';
6622  }
6623  $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6624  return $ret;
6625  }
6626 
6654  public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '', $placeholder = '', $gm = 'auto')
6655  {
6656  global $conf, $langs;
6657 
6658  if ($gm === 'auto') {
6659  $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6660  }
6661 
6662  $retstring = '';
6663 
6664  if ($prefix == '') {
6665  $prefix = 're';
6666  }
6667  if ($h == '') {
6668  $h = 0;
6669  }
6670  if ($m == '') {
6671  $m = 0;
6672  }
6673  $emptydate = 0;
6674  $emptyhours = 0;
6675  if ($stepminutes <= 0 || $stepminutes > 30) {
6676  $stepminutes = 1;
6677  }
6678  if ($empty == 1) {
6679  $emptydate = 1;
6680  $emptyhours = 1;
6681  }
6682  if ($empty == 2) {
6683  $emptydate = 0;
6684  $emptyhours = 1;
6685  }
6686  $orig_set_time = $set_time;
6687 
6688  if ($set_time === '' && $emptydate == 0) {
6689  include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
6690  if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6691  $set_time = dol_now($gm);
6692  } else {
6693  $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6694  }
6695  }
6696 
6697  // Analysis of the pre-selection date
6698  $reg = array();
6699  $shour = '';
6700  $smin = '';
6701  $ssec = '';
6702  if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
6703  // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6704  $syear = (!empty($reg[1]) ? $reg[1] : '');
6705  $smonth = (!empty($reg[2]) ? $reg[2] : '');
6706  $sday = (!empty($reg[3]) ? $reg[3] : '');
6707  $shour = (!empty($reg[4]) ? $reg[4] : '');
6708  $smin = (!empty($reg[5]) ? $reg[5] : '');
6709  } elseif (strval($set_time) != '' && $set_time != -1) {
6710  // set_time est un timestamps (0 possible)
6711  $syear = dol_print_date($set_time, "%Y", $gm);
6712  $smonth = dol_print_date($set_time, "%m", $gm);
6713  $sday = dol_print_date($set_time, "%d", $gm);
6714  if ($orig_set_time != '') {
6715  $shour = dol_print_date($set_time, "%H", $gm);
6716  $smin = dol_print_date($set_time, "%M", $gm);
6717  $ssec = dol_print_date($set_time, "%S", $gm);
6718  }
6719  } else {
6720  // Date est '' ou vaut -1
6721  $syear = '';
6722  $smonth = '';
6723  $sday = '';
6724  $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6725  $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6726  $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6727  }
6728  if ($h == 3) {
6729  $shour = '';
6730  }
6731  if ($m == 3) {
6732  $smin = '';
6733  }
6734 
6735  $nowgmt = dol_now('gmt');
6736  //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6737 
6738  // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6739  $usecalendar = 'combo';
6740  if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6741  $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6742  }
6743 
6744  if ($d) {
6745  // Show date with popup
6746  if ($usecalendar != 'combo') {
6747  $formated_date = '';
6748  //print "e".$set_time." t ".$conf->format_date_short;
6749  if (strval($set_time) != '' && $set_time != -1) {
6750  //$formated_date=dol_print_date($set_time,$conf->format_date_short);
6751  $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6752  }
6753 
6754  // Calendrier popup version eldy
6755  if ($usecalendar == "eldy") {
6756  // Input area to enter date manually
6757  $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate" maxlength="11" value="' . $formated_date . '"';
6758  $retstring .= ($disabled ? ' disabled' : '');
6759  $retstring .= ' onChange="dpChangeDay(\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6760  $retstring .= '>';
6761 
6762  // Icon calendar
6763  $retstringbuttom = '';
6764  if (!$disabled) {
6765  $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
6766  $base = DOL_URL_ROOT . '/core/';
6767  $retstringbuttom .= ' onClick="showDP(\'' . $base . '\',\'' . $prefix . '\',\'' . $langs->trans("FormatDateShortJavaInput") . '\',\'' . $langs->defaultlang . '\');"';
6768  $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
6769  } else {
6770  $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
6771  }
6772  $retstring = $retstringbuttom . $retstring;
6773 
6774  $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
6775  $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
6776  $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
6777  } elseif ($usecalendar == 'jquery') {
6778  if (!$disabled) {
6779  // Output javascript for datepicker
6780  $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (date('Y') - 100));
6781  $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (date('Y') + 100));
6782 
6783  $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
6784  $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
6785  dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
6786  autoclose: true,
6787  todayHighlight: true,
6788  yearRange: '" . $minYear . ":" . $maxYear . "',";
6789  if (!empty($conf->dol_use_jmobile)) {
6790  $retstring .= "
6791  beforeShow: function (input, datePicker) {
6792  input.disabled = true;
6793  },
6794  onClose: function (dateText, datePicker) {
6795  this.disabled = false;
6796  },
6797  ";
6798  }
6799  // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6800  if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6801  $retstring .= "
6802  showOn: 'button', /* both has problem with autocompletion */
6803  buttonImage: '" . DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png',
6804  buttonImageOnly: true";
6805  }
6806  $retstring .= "
6807  }) });";
6808  $retstring .= "</script>";
6809  }
6810 
6811  // Zone de saisie manuelle de la date
6812  $retstring .= '<div class="nowraponall inline-block divfordateinput">';
6813  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6814  $retstring .= ($disabled ? ' disabled' : '');
6815  $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
6816  $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6817  $retstring .= '>';
6818 
6819  // Icone calendrier
6820  if (!$disabled) {
6821  /* Not required. Managed by option buttonImage of jquery
6822  $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6823  $retstring.='<script nonce="'.getNonce().'" type="text/javascript">';
6824  $retstring.="jQuery(document).ready(function() {";
6825  $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
6826  $retstring.=" jQuery('#".$prefix."').focus();";
6827  $retstring.=' });';
6828  $retstring.='});';
6829  $retstring.="</script>";*/
6830  } else {
6831  $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
6832  $retsring = $retstringbutton . $retstring;
6833  }
6834 
6835  $retstring .= '</div>';
6836  $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
6837  $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
6838  $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
6839  } else {
6840  $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6841  }
6842  } else {
6843  // Show date with combo selects
6844  // Day
6845  $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
6846 
6847  if ($emptydate || $set_time == -1) {
6848  $retstring .= '<option value="0" selected>&nbsp;</option>';
6849  }
6850 
6851  for ($day = 1; $day <= 31; $day++) {
6852  $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
6853  }
6854 
6855  $retstring .= "</select>";
6856 
6857  $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
6858  if ($emptydate || $set_time == -1) {
6859  $retstring .= '<option value="0" selected>&nbsp;</option>';
6860  }
6861 
6862  // Month
6863  for ($month = 1; $month <= 12; $month++) {
6864  $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
6865  $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6866  $retstring .= "</option>";
6867  }
6868  $retstring .= "</select>";
6869 
6870  // Year
6871  if ($emptydate || $set_time == -1) {
6872  $retstring .= '<input' . ($disabled ? ' disabled' : '') . ' placeholder="' . dol_escape_htmltag($langs->trans("Year")) . '" class="flat maxwidth50imp valignmiddle" type="number" min="0" max="3000" maxlength="4" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">';
6873  } else {
6874  $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
6875 
6876  for ($year = $syear - 10; $year < $syear + 10; $year++) {
6877  $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
6878  }
6879  $retstring .= "</select>\n";
6880  }
6881  }
6882  }
6883 
6884  if ($d && $h) {
6885  $retstring .= ($h == 2 ? '<br>' : ' ');
6886  $retstring .= '<span class="nowraponall">';
6887  }
6888 
6889  if ($h) {
6890  $hourstart = 0;
6891  $hourend = 24;
6892  if ($openinghours != '') {
6893  $openinghours = explode(',', $openinghours);
6894  $hourstart = $openinghours[0];
6895  $hourend = $openinghours[1];
6896  if ($hourend < $hourstart) {
6897  $hourend = $hourstart;
6898  }
6899  }
6900  // Show hour
6901  $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
6902  if ($emptyhours) {
6903  $retstring .= '<option value="-1">&nbsp;</option>';
6904  }
6905  for ($hour = $hourstart; $hour < $hourend; $hour++) {
6906  if (strlen($hour) < 2) {
6907  $hour = "0" . $hour;
6908  }
6909  $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
6910  //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6911  $retstring .= '</option>';
6912  }
6913  $retstring .= '</select>';
6914  //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6915  if ($m) {
6916  $retstring .= ":";
6917  }
6918  }
6919 
6920  if ($m) {
6921  // Show minutes
6922  $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
6923  if ($emptyhours) {
6924  $retstring .= '<option value="-1">&nbsp;</option>';
6925  }
6926  for ($min = 0; $min < 60; $min += $stepminutes) {
6927  if (strlen($min) < 2) {
6928  $min = "0" . $min;
6929  }
6930  $retstring .= '<option value="' . $min . '"' . (($min == $smin) ? ' selected' : '') . '>' . $min . (empty($conf->dol_optimize_smallscreen) ? '' : '') . '</option>';
6931  }
6932  $retstring .= '</select>';
6933 
6934  $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
6935  }
6936 
6937  if ($d && $h) {
6938  $retstring .= '</span>';
6939  }
6940 
6941  // Add a "Now" link
6942  if (!empty($conf->use_javascript_ajax) && $addnowlink) {
6943  // Script which will be inserted in the onClick of the "Now" link
6944  $reset_scripts = "";
6945  if ($addnowlink == 2) { // local computer time
6946  // pad add leading 0 on numbers
6947  $reset_scripts .= "Number.prototype.pad = function(size) {
6948  var s = String(this);
6949  while (s.length < (size || 2)) {s = '0' + s;}
6950  return s;
6951  };
6952  var d = new Date();";
6953  }
6954 
6955  // Generate the date part, depending on the use or not of the javascript calendar
6956  if ($addnowlink == 1) { // server time expressed in user time setup
6957  $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
6958  $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
6959  $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
6960  $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
6961  } elseif ($addnowlink == 2) {
6962  /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6963  * This break application for foreign languages.
6964  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6965  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6966  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6967  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6968  */
6969  $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
6970  $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
6971  $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
6972  $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
6973  }
6974  /*if ($usecalendar == "eldy")
6975  {
6976  $base=DOL_URL_ROOT.'/core/';
6977  $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6978  }
6979  else
6980  {
6981  $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6982  $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6983  $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6984  }*/
6985  // Update the hour part
6986  if ($h) {
6987  if ($fullday) {
6988  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6989  }
6990  //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
6991  if ($addnowlink == 1) {
6992  $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
6993  $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
6994  } elseif ($addnowlink == 2) {
6995  $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
6996  $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
6997  }
6998 
6999  if ($fullday) {
7000  $reset_scripts .= ' } ';
7001  }
7002  }
7003  // Update the minute part
7004  if ($m) {
7005  if ($fullday) {
7006  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7007  }
7008  //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7009  if ($addnowlink == 1) {
7010  $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7011  $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7012  } elseif ($addnowlink == 2) {
7013  $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7014  $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7015  }
7016  if ($fullday) {
7017  $reset_scripts .= ' } ';
7018  }
7019  }
7020  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7021  if ($reset_scripts && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7022  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7023  $retstring .= $langs->trans("Now");
7024  $retstring .= '</button> ';
7025  }
7026  }
7027 
7028  // Add a "Plus one hour" link
7029  if ($conf->use_javascript_ajax && $addplusone) {
7030  // Script which will be inserted in the onClick of the "Add plusone" link
7031  $reset_scripts = "";
7032 
7033  // Generate the date part, depending on the use or not of the javascript calendar
7034  $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7035  $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7036  $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7037  $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7038  // Update the hour part
7039  if ($h) {
7040  if ($fullday) {
7041  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7042  }
7043  $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7044  if ($fullday) {
7045  $reset_scripts .= ' } ';
7046  }
7047  }
7048  // Update the minute part
7049  if ($m) {
7050  if ($fullday) {
7051  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7052  }
7053  $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7054  if ($fullday) {
7055  $reset_scripts .= ' } ';
7056  }
7057  }
7058  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7059  if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7060  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7061  $retstring .= $langs->trans("DateStartPlusOne");
7062  $retstring .= '</button> ';
7063  }
7064  }
7065 
7066  // Add a link to set data
7067  if ($conf->use_javascript_ajax && !empty($adddateof)) {
7068  if (!is_array($adddateof)) {
7069  $arrayofdateof = array(array('adddateof'=>$adddateof, 'labeladddateof'=>$labeladddateof));
7070  } else {
7071  $arrayofdateof = $adddateof;
7072  }
7073  foreach ($arrayofdateof as $valuedateof) {
7074  $tmpadddateof = $valuedateof['adddateof'] != '' ? $valuedateof['adddateof'] : 0;
7075  $tmplabeladddateof = $valuedateof['labeladddateof'];
7076  $tmparray = dol_getdate($tmpadddateof);
7077  if (empty($tmplabeladddateof)) {
7078  $tmplabeladddateof = $langs->trans("DateInvoice");
7079  }
7080  $reset_scripts = 'console.log(\'Click on now link\'); ';
7081  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7082  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7083  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7084  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7085  $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7086  }
7087  }
7088 
7089  return $retstring;
7090  }
7091 
7100  public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7101  {
7102  global $langs;
7103 
7104  $TDurationTypes = array(
7105  'y' => $langs->trans('Years'),
7106  'm' => $langs->trans('Month'),
7107  'w' => $langs->trans('Weeks'),
7108  'd' => $langs->trans('Days'),
7109  'h' => $langs->trans('Hours'),
7110  'i' => $langs->trans('Minutes')
7111  );
7112 
7113  // Removed undesired duration types
7114  foreach ($excludetypes as $value) {
7115  unset($TDurationTypes[$value]);
7116  }
7117 
7118  $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7119  foreach ($TDurationTypes as $key => $typeduration) {
7120  $retstring .= '<option value="' . $key . '"';
7121  if ($key == $selected) {
7122  $retstring .= " selected";
7123  }
7124  $retstring .= ">" . $typeduration . "</option>";
7125  }
7126  $retstring .= "</select>";
7127 
7128  $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7129 
7130  return $retstring;
7131  }
7132 
7133  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7134 
7148  public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7149  {
7150  // phpcs:enable
7151  global $langs;
7152 
7153  $retstring = '<span class="nowraponall">';
7154 
7155  $hourSelected = '';
7156  $minSelected = '';
7157 
7158  // Hours
7159  if ($iSecond != '') {
7160  require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7161 
7162  $hourSelected = convertSecondToTime($iSecond, 'allhour');
7163  $minSelected = convertSecondToTime($iSecond, 'min');
7164  }
7165 
7166  if ($typehour == 'select') {
7167  $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7168  for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7169  $retstring .= '<option value="' . $hour . '"';
7170  if (is_numeric($hourSelected) && $hourSelected == $hour) {
7171  $retstring .= " selected";
7172  }
7173  $retstring .= ">" . $hour . "</option>";
7174  }
7175  $retstring .= "</select>";
7176  } elseif ($typehour == 'text' || $typehour == 'textselect') {
7177  $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7178  } else {
7179  return 'BadValueForParameterTypeHour';
7180  }
7181 
7182  if ($typehour != 'text') {
7183  $retstring .= ' ' . $langs->trans('HourShort');
7184  } else {
7185  $retstring .= '<span class="">:</span>';
7186  }
7187 
7188  // Minutes
7189  if ($minunderhours) {
7190  $retstring .= '<br>';
7191  } else {
7192  if ($typehour != 'text') {
7193  $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7194  }
7195  }
7196 
7197  if ($typehour == 'select' || $typehour == 'textselect') {
7198  $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7199  for ($min = 0; $min <= 55; $min = $min + 5) {
7200  $retstring .= '<option value="' . $min . '"';
7201  if (is_numeric($minSelected) && $minSelected == $min) {
7202  $retstring .= ' selected';
7203  }
7204  $retstring .= '>' . $min . '</option>';
7205  }
7206  $retstring .= "</select>";
7207  } elseif ($typehour == 'text') {
7208  $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7209  }
7210 
7211  if ($typehour != 'text') {
7212  $retstring .= ' ' . $langs->trans('MinuteShort');
7213  }
7214 
7215  $retstring .= "</span>";
7216 
7217  if (!empty($nooutput)) {
7218  return $retstring;
7219  }
7220 
7221  print $retstring;
7222 
7223  return '';
7224  }
7225 
7245  public function selectTickets($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7246  {
7247  global $langs, $conf;
7248 
7249  $out = '';
7250 
7251  // check parameters
7252  if (is_null($ajaxoptions)) $ajaxoptions = array();
7253 
7254  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7255  $placeholder = '';
7256 
7257  if ($selected && empty($selected_input_value)) {
7258  require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7259  $tickettmpselect = new Ticket($this->db);
7260  $tickettmpselect->fetch($selected);
7261  $selected_input_value = $tickettmpselect->ref;
7262  unset($tickettmpselect);
7263  }
7264 
7265  $urloption = '';
7266  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7267 
7268  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel") . ' : ';
7269  elseif ($hidelabel > 1) {
7270  $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7271  if ($hidelabel == 2) {
7272  $out .= img_picto($langs->trans("Search"), 'search');
7273  }
7274  }
7275  $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
7276  if ($hidelabel == 3) {
7277  $out .= img_picto($langs->trans("Search"), 'search');
7278  }
7279  } else {
7280  $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7281  }
7282 
7283  if (empty($nooutput)) {
7284  print $out;
7285  } else {
7286  return $out;
7287  }
7288  return '';
7289  }
7290 
7291 
7308  public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7309  {
7310  global $langs, $conf;
7311 
7312  $out = '';
7313  $outarray = array();
7314 
7315  $selectFields = " p.rowid, p.ref, p.message";
7316 
7317  $sql = "SELECT ";
7318  $sql .= $selectFields;
7319  $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7320  $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7321 
7322  // Add criteria on ref/label
7323  if ($filterkey != '') {
7324  $sql .= ' AND (';
7325  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7326  // For natural search
7327  $scrit = explode(' ', $filterkey);
7328  $i = 0;
7329  if (count($scrit) > 1) $sql .= "(";
7330  foreach ($scrit as $crit) {
7331  if ($i > 0) $sql .= " AND ";
7332  $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7333  $sql .= ")";
7334  $i++;
7335  }
7336  if (count($scrit) > 1) $sql .= ")";
7337  $sql .= ')';
7338  }
7339 
7340  $sql .= $this->db->plimit($limit, 0);
7341 
7342  // Build output string
7343  dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7344  $result = $this->db->query($sql);
7345  if ($result) {
7346  require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7347  require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7348 
7349  $num = $this->db->num_rows($result);
7350 
7351  $events = null;
7352 
7353  if (!$forcecombo) {
7354  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7355  $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7356  }
7357 
7358  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7359 
7360  $textifempty = '';
7361  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7362  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7363  if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7364  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7365  else $textifempty .= $langs->trans("All");
7366  } else {
7367  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7368  }
7369  if ($showempty) $out .= '<option value="0" selected>' . $textifempty . '</option>';
7370 
7371  $i = 0;
7372  while ($num && $i < $num) {
7373  $opt = '';
7374  $optJson = array();
7375  $objp = $this->db->fetch_object($result);
7376 
7377  $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7378  // Add new entry
7379  // "key" value of json key array is used by jQuery automatically as selected value
7380  // "label" value of json key array is used by jQuery automatically as text for combo box
7381  $out .= $opt;
7382  array_push($outarray, $optJson);
7383 
7384  $i++;
7385  }
7386 
7387  $out .= '</select>';
7388 
7389  $this->db->free($result);
7390 
7391  if (empty($outputmode)) {
7392  return $out;
7393  }
7394  return $outarray;
7395  } else {
7396  dol_print_error($this->db);
7397  }
7398 
7399  return array();
7400  }
7401 
7413  protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7414  {
7415  $outkey = '';
7416  $outref = '';
7417  $outtype = '';
7418 
7419  $outkey = $objp->rowid;
7420  $outref = $objp->ref;
7421  $outtype = $objp->fk_product_type;
7422 
7423  $opt = '<option value="' . $objp->rowid . '"';
7424  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7425  $opt .= '>';
7426  $opt .= $objp->ref;
7427  $objRef = $objp->ref;
7428  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7429 
7430  $opt .= "</option>\n";
7431  $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7432  }
7433 
7453  public function selectProjects($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7454  {
7455  global $langs, $conf;
7456 
7457  $out = '';
7458 
7459  // check parameters
7460  if (is_null($ajaxoptions)) $ajaxoptions = array();
7461 
7462  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7463  $placeholder = '';
7464 
7465  if ($selected && empty($selected_input_value)) {
7466  require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7467  $projecttmpselect = new Project($this->db);
7468  $projecttmpselect->fetch($selected);
7469  $selected_input_value = $projecttmpselect->ref;
7470  unset($projecttmpselect);
7471  }
7472 
7473  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7474 
7475  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel") . ' : ';
7476  elseif ($hidelabel > 1) {
7477  $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7478  if ($hidelabel == 2) {
7479  $out .= img_picto($langs->trans("Search"), 'search');
7480  }
7481  }
7482  $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
7483  if ($hidelabel == 3) {
7484  $out .= img_picto($langs->trans("Search"), 'search');
7485  }
7486  } else {
7487  $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7488  }
7489 
7490  if (empty($nooutput)) {
7491  print $out;
7492  } else {
7493  return $out;
7494  }
7495  return '';
7496  }
7497 
7514  public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7515  {
7516  global $langs, $conf;
7517 
7518  $out = '';
7519  $outarray = array();
7520 
7521  $selectFields = " p.rowid, p.ref";
7522 
7523  $sql = "SELECT ";
7524  $sql .= $selectFields;
7525  $sql .= " FROM " . $this->db->prefix() . "projet as p";
7526  $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
7527 
7528  // Add criteria on ref/label
7529  if ($filterkey != '') {
7530  $sql .= ' AND (';
7531  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7532  // For natural search
7533  $scrit = explode(' ', $filterkey);
7534  $i = 0;
7535  if (count($scrit) > 1) $sql .= "(";
7536  foreach ($scrit as $crit) {
7537  if ($i > 0) $sql .= " AND ";
7538  $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7539  $sql .= "";
7540  $i++;
7541  }
7542  if (count($scrit) > 1) $sql .= ")";
7543  $sql .= ')';
7544  }
7545 
7546  $sql .= $this->db->plimit($limit, 0);
7547 
7548  // Build output string
7549  dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
7550  $result = $this->db->query($sql);
7551  if ($result) {
7552  require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
7553  require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
7554 
7555  $num = $this->db->num_rows($result);
7556 
7557  $events = null;
7558 
7559  if (!$forcecombo) {
7560  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7561  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7562  }
7563 
7564  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7565 
7566  $textifempty = '';
7567  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7568  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7569  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7570  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7571  else $textifempty .= $langs->trans("All");
7572  } else {
7573  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7574  }
7575  if ($showempty) $out .= '<option value="0" selected>' . $textifempty . '</option>';
7576 
7577  $i = 0;
7578  while ($num && $i < $num) {
7579  $opt = '';
7580  $optJson = array();
7581  $objp = $this->db->fetch_object($result);
7582 
7583  $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7584  // Add new entry
7585  // "key" value of json key array is used by jQuery automatically as selected value
7586  // "label" value of json key array is used by jQuery automatically as text for combo box
7587  $out .= $opt;
7588  array_push($outarray, $optJson);
7589 
7590  $i++;
7591  }
7592 
7593  $out .= '</select>';
7594 
7595  $this->db->free($result);
7596 
7597  if (empty($outputmode)) {
7598  return $out;
7599  }
7600  return $outarray;
7601  } else {
7602  dol_print_error($this->db);
7603  }
7604 
7605  return array();
7606  }
7607 
7619  protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7620  {
7621  $outkey = '';
7622  $outref = '';
7623  $outtype = '';
7624 
7625  $label = $objp->label;
7626 
7627  $outkey = $objp->rowid;
7628  $outref = $objp->ref;
7629  $outlabel = $objp->label;
7630  $outtype = $objp->fk_product_type;
7631 
7632  $opt = '<option value="' . $objp->rowid . '"';
7633  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7634  $opt .= '>';
7635  $opt .= $objp->ref;
7636  $objRef = $objp->ref;
7637  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
7638 
7639  $opt .= "</option>\n";
7640  $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
7641  }
7642 
7643 
7663  public function selectMembers($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7664  {
7665  global $langs, $conf;
7666 
7667  $out = '';
7668 
7669  // check parameters
7670  if (is_null($ajaxoptions)) $ajaxoptions = array();
7671 
7672  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7673  $placeholder = '';
7674  $urloption = '';
7675 
7676  if ($selected && empty($selected_input_value)) {
7677  require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
7678  $adherenttmpselect = new Adherent($this->db);
7679  $adherenttmpselect->fetch($selected);
7680  $selected_input_value = $adherenttmpselect->ref;
7681  unset($adherenttmpselect);
7682  }
7683 
7684  $urloption = '';
7685 
7686  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7687 
7688  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel") . ' : ';
7689  elseif ($hidelabel > 1) {
7690  $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7691  if ($hidelabel == 2) {
7692  $out .= img_picto($langs->trans("Search"), 'search');
7693  }
7694  }
7695  $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '') . ' />';
7696  if ($hidelabel == 3) {
7697  $out .= img_picto($langs->trans("Search"), 'search');
7698  }
7699  } else {
7700  $filterkey = '';
7701 
7702  $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
7703  }
7704 
7705  if (empty($nooutput)) {
7706  print $out;
7707  } else {
7708  return $out;
7709  }
7710  return '';
7711  }
7712 
7729  public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7730  {
7731  global $langs, $conf;
7732 
7733  $out = '';
7734  $outarray = array();
7735 
7736  $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
7737 
7738  $sql = "SELECT ";
7739  $sql .= $selectFields;
7740  $sql .= " FROM " . $this->db->prefix() . "adherent as p";
7741  $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
7742 
7743  // Add criteria on ref/label
7744  if ($filterkey != '') {
7745  $sql .= ' AND (';
7746  $prefix = empty($conf->global->MEMBER_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7747  // For natural search
7748  $scrit = explode(' ', $filterkey);
7749  $i = 0;
7750  if (count($scrit) > 1) $sql .= "(";
7751  foreach ($scrit as $crit) {
7752  if ($i > 0) $sql .= " AND ";
7753  $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7754  $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
7755  $i++;
7756  }
7757  if (count($scrit) > 1) $sql .= ")";
7758  $sql .= ')';
7759  }
7760  if ($status != -1) {
7761  $sql .= ' AND statut = ' . ((int) $status);
7762  }
7763  $sql .= $this->db->plimit($limit, 0);
7764 
7765  // Build output string
7766  dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
7767  $result = $this->db->query($sql);
7768  if ($result) {
7769  require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
7770  require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
7771 
7772  $num = $this->db->num_rows($result);
7773 
7774  $events = null;
7775 
7776  if (!$forcecombo) {
7777  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7778  $out .= ajax_combobox($htmlname, $events, !empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT) ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
7779  }
7780 
7781  $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7782 
7783  $textifempty = '';
7784  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7785  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7786  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7787  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7788  else $textifempty .= $langs->trans("All");
7789  } else {
7790  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7791  }
7792  if ($showempty) {
7793  $out .= '<option value="-1" selected>' . $textifempty . '</option>';
7794  }
7795 
7796  $i = 0;
7797  while ($num && $i < $num) {
7798  $opt = '';
7799  $optJson = array();
7800  $objp = $this->db->fetch_object($result);
7801 
7802  $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
7803 
7804  // Add new entry
7805  // "key" value of json key array is used by jQuery automatically as selected value
7806  // "label" value of json key array is used by jQuery automatically as text for combo box
7807  $out .= $opt;
7808  array_push($outarray, $optJson);
7809 
7810  $i++;
7811  }
7812 
7813  $out .= '</select>';
7814 
7815  $this->db->free($result);
7816 
7817  if (empty($outputmode)) {
7818  return $out;
7819  }
7820  return $outarray;
7821  } else {
7822  dol_print_error($this->db);
7823  }
7824 
7825  return array();
7826  }
7827 
7839  protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7840  {
7841  $outkey = '';
7842  $outlabel = '';
7843  $outtype = '';
7844 
7845  $outkey = $objp->rowid;
7846  $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
7847  $outtype = $objp->fk_adherent_type;
7848 
7849  $opt = '<option value="' . $objp->rowid . '"';
7850  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7851  $opt .= '>';
7852  if (!empty($filterkey) && $filterkey != '') {
7853  $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
7854  }
7855  $opt .= $outlabel;
7856  $opt .= "</option>\n";
7857 
7858  $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
7859  }
7860 
7880  public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
7881  {
7882  global $conf, $user;
7883 
7884  $objecttmp = null;
7885 
7886  // Example of value for $objectdec:
7887  // Bom:bom/class/bom.class.php:0:t.status=1
7888  // Bom:bom/class/bom.class.php:0:t.status=1:ref
7889  // Bom:bom/class/bom.class.php:0:(t.status:=:1):ref
7890  $InfoFieldList = explode(":", $objectdesc, 4);
7891  $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
7892  $reg = array();
7893  if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
7894  $InfoFieldList[4] = $reg[1]; // take the sort field
7895  }
7896  $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
7897 
7898  $classname = $InfoFieldList[0];
7899  $classpath = $InfoFieldList[1];
7900  $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
7901  $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
7902  $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
7903 
7904  if (!empty($classpath)) {
7905  dol_include_once($classpath);
7906 
7907  if ($classname && class_exists($classname)) {
7908  $objecttmp = new $classname($this->db);
7909 
7910  // Make some replacement
7911  $sharedentities = getEntity(strtolower($classname));
7912  $filter = str_replace(
7913  array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
7914  array($conf->entity, $sharedentities, $user->id),
7915  $filter
7916  );
7917  }
7918  }
7919  if (!is_object($objecttmp)) {
7920  dol_syslog('Error bad setup of type for field ' . join(',', $InfoFieldList), LOG_WARNING);
7921  return 'Error bad setup of type for field ' . join(',', $InfoFieldList);
7922  }
7923 
7924  //var_dump($filter);
7925  $prefixforautocompletemode = $objecttmp->element;
7926  if ($prefixforautocompletemode == 'societe') {
7927  $prefixforautocompletemode = 'company';
7928  }
7929  if ($prefixforautocompletemode == 'product') {
7930  $prefixforautocompletemode = 'produit';
7931  }
7932  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7933 
7934  dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
7935  $out = '';
7936  if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
7937  // No immediate load of all database
7938  $placeholder = '';
7939  if ($preselectedvalue && empty($selected_input_value)) {
7940  $objecttmp->fetch($preselectedvalue);
7941  $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
7942  //unset($objecttmp);
7943  }
7944 
7945  $objectdesc = $classname . ':' . $classpath . ':' . $addcreatebuttonornot . ':' . $filter;
7946  $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
7947 
7948  // No immediate load of all database
7949  $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdesc) . '&filter=' . urlencode($filter) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
7950  // Activate the auto complete using ajax call.
7951  $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
7952  $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
7953  $out .= '<input type="text" class="' . $morecss . '"' . ($disabled ? ' disabled="disabled"' : '') . ' name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' />';
7954  } else {
7955  // Immediate load of table record.
7956  $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
7957  }
7958 
7959  return $out;
7960  }
7961 
7962 
7983  public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
7984  {
7985  global $conf, $langs, $user, $hookmanager;
7986 
7987  //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
7988 
7989  $prefixforautocompletemode = $objecttmp->element;
7990  if ($prefixforautocompletemode == 'societe') {
7991  $prefixforautocompletemode = 'company';
7992  }
7993  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7994 
7995  if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
7996  $tmpfieldstoshow = '';
7997  foreach ($objecttmp->fields as $key => $val) {
7998  if (!dol_eval($val['enabled'], 1, 1, '1')) {
7999  continue;
8000  }
8001  if (!empty($val['showoncombobox'])) {
8002  $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8003  }
8004  }
8005  if ($tmpfieldstoshow) {
8006  $fieldstoshow = $tmpfieldstoshow;
8007  }
8008  } else {
8009  // For backward compatibility
8010  $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8011  }
8012 
8013  if (empty($fieldstoshow)) {
8014  if (isset($objecttmp->fields['ref'])) {
8015  $fieldstoshow = 't.ref';
8016  } else {
8017  $langs->load("errors");
8018  $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8019  return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8020  }
8021  }
8022 
8023  $out = '';
8024  $outarray = array();
8025  $tmparray = array();
8026 
8027  $num = 0;
8028 
8029  // Search data
8030  $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $objecttmp->table_element . " as t";
8031  if (isset($objecttmp->ismultientitymanaged)) {
8032  if (!is_numeric($objecttmp->ismultientitymanaged)) {
8033  $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8034  $sql .= " INNER JOIN " . $this->db->prefix() . $tmparray[1] . " as parenttable ON parenttable.rowid = t." . $tmparray[0];
8035  }
8036  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8037  if (empty($user->rights->societe->client->voir) && !$user->socid) {
8038  $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8039  }
8040  }
8041  }
8042 
8043  // Add where from hooks
8044  $parameters = array(
8045  'object' => $objecttmp,
8046  'htmlname' => $htmlname,
8047  'filter' => $filter,
8048  'searchkey' => $searchkey
8049  );
8050 
8051  $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8052  if (!empty($hookmanager->resPrint)) {
8053  $sql .= $hookmanager->resPrint;
8054  } else {
8055  $sql .= " WHERE 1=1";
8056  if (isset($objecttmp->ismultientitymanaged)) {
8057  if ($objecttmp->ismultientitymanaged == 1) {
8058  $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8059  }
8060  if (!is_numeric($objecttmp->ismultientitymanaged)) {
8061  $sql .= " AND parenttable.entity = t." . $tmparray[0];
8062  }
8063  if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8064  if ($objecttmp->element == 'societe') {
8065  $sql .= " AND t.rowid = " . ((int) $user->socid);
8066  } else {
8067  $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8068  }
8069  }
8070  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8071  if (empty($user->rights->societe->client->voir) && !$user->socid) {
8072  $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8073  }
8074  }
8075  }
8076  if ($searchkey != '') {
8077  $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
8078  }
8079 
8080  if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8081  $errormessage = '';
8082  $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8083  if ($errormessage) {
8084  return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8085  }
8086  }
8087  }
8088  $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8089  //$sql.=$this->db->plimit($limit, 0);
8090  //print $sql;
8091 
8092  // Build output string
8093  $resql = $this->db->query($sql);
8094  if ($resql) {
8095  // Construct $out and $outarray
8096  $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8097 
8098  // Warning: Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'. Seems it is no more true with selec2 v4
8099  $textifempty = '&nbsp;';
8100 
8101  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8102  if (!empty($conf->global->$confkeyforautocompletemode)) {
8103  if ($showempty && !is_numeric($showempty)) {
8104  $textifempty = $langs->trans($showempty);
8105  } else {
8106  $textifempty .= $langs->trans("All");
8107  }
8108  }
8109  if ($showempty) {
8110  $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8111  }
8112 
8113  $num = $this->db->num_rows($resql);
8114  $i = 0;
8115  if ($num) {
8116  while ($i < $num) {
8117  $obj = $this->db->fetch_object($resql);
8118  $label = '';
8119  $labelhtml = '';
8120  $tmparray = explode(',', $fieldstoshow);
8121  $oldvalueforshowoncombobox = 0;
8122  foreach ($tmparray as $key => $val) {
8123  $val = preg_replace('/t\./', '', $val);
8124  $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8125  $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8126  $label .= $obj->$val;
8127  $labelhtml .= $obj->$val;
8128 
8129  $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8130  }
8131  if (empty($outputmode)) {
8132  if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8133  $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8134  } else {
8135  $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8136  }
8137  } else {
8138  array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8139  }
8140 
8141  $i++;
8142  if (($i % 10) == 0) {
8143  $out .= "\n";
8144  }
8145  }
8146  }
8147 
8148  $out .= '</select>' . "\n";
8149 
8150  if (!$forcecombo) {
8151  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8152  $out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
8153  }
8154  } else {
8155  dol_print_error($this->db);
8156  }
8157 
8158  $this->result = array('nbofelement' => $num);
8159 
8160  if ($outputmode) {
8161  return $outarray;
8162  }
8163  return $out;
8164  }
8165 
8166 
8190  public static function selectarray($htmlname, $array, $id = '', $show_empty = 0, $key_in_label = 0, $value_as_key = 0, $moreparam = '', $translate = 0, $maxlen = 0, $disabled = 0, $sort = '', $morecss = 'minwidth75', $addjscombo = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
8191  {
8192  global $conf, $langs;
8193 
8194  // Do we want a multiselect ?
8195  //$jsbeautify = 0;
8196  //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8197  $jsbeautify = 1;
8198 
8199  if ($value_as_key) {
8200  $array = array_combine($array, $array);
8201  }
8202 
8203  $out = '';
8204 
8205  if ($addjscombo < 0) {
8206  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8207  $addjscombo = 1;
8208  } else {
8209  $addjscombo = 0;
8210  }
8211  }
8212 
8213  $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8214  $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8215  $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8216  $out .= '>';
8217 
8218  if ($show_empty) {
8219  $textforempty = ' ';
8220  if (!empty($conf->use_javascript_ajax)) {
8221  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8222  }
8223  if (!is_numeric($show_empty)) {
8224  $textforempty = $show_empty;
8225  }
8226  $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8227  }
8228 
8229  if (is_array($array)) {
8230  // Translate
8231  if ($translate) {
8232  foreach ($array as $key => $value) {
8233  if (!is_array($value)) {
8234  $array[$key] = $langs->trans($value);
8235  } else {
8236  $array[$key]['label'] = $langs->trans($value['label']);
8237  }
8238  }
8239  }
8240 
8241  // Sort
8242  if ($sort == 'ASC') {
8243  asort($array);
8244  } elseif ($sort == 'DESC') {
8245  arsort($array);
8246  }
8247 
8248  foreach ($array as $key => $tmpvalue) {
8249  if (is_array($tmpvalue)) {
8250  $value = $tmpvalue['label'];
8251  $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8252  $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8253  } else {
8254  $value = $tmpvalue;
8255  $disabled = '';
8256  $style = '';
8257  }
8258  if (!empty($disablebademail)) {
8259  if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8260  || ($disablebademail == 2 && preg_match('/---/', $value))) {
8261  $disabled = ' disabled';
8262  $style = ' class="warning"';
8263  }
8264  }
8265 
8266  if ($key_in_label) {
8267  if (empty($nohtmlescape)) {
8268  $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8269  } else {
8270  $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8271  }
8272  } else {
8273  if (empty($nohtmlescape)) {
8274  $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8275  } else {
8276  $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8277  }
8278  if ($value == '' || $value == '-') {
8279  $selectOptionValue = '&nbsp;';
8280  }
8281  }
8282 
8283  $out .= '<option value="' . $key . '"';
8284  $out .= $style . $disabled;
8285  if (is_array($id)) {
8286  if (in_array($key, $id) && !$disabled) {
8287  $out .= ' selected'; // To preselect a value
8288  }
8289  } else {
8290  $id = (string) $id; // if $id = 0, then $id = '0'
8291  if ($id != '' && ($id == $key || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8292  $out .= ' selected'; // To preselect a value
8293  }
8294  }
8295  if ($nohtmlescape) {
8296  $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
8297  }
8298  if (is_array($tmpvalue)) {
8299  foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8300  if (preg_match('/^data-/', $keyforvalue)) {
8301  $out .= ' '.$keyforvalue.'="'.dol_escape_htmltag($valueforvalue).'"';
8302  }
8303  }
8304  }
8305  $out .= '>';
8306  //var_dump($selectOptionValue);
8307  $out .= $selectOptionValue;
8308  $out .= "</option>\n";
8309  }
8310  }
8311 
8312  $out .= "</select>";
8313 
8314  // Add code for jquery to use multiselect
8315  if ($addjscombo && $jsbeautify) {
8316  // Enhance with select2
8317  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8318  $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
8319  }
8320 
8321  return $out;
8322  }
8323 
8324 
8343  public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8344  {
8345  global $conf, $langs;
8346  global $delayedhtmlcontent; // Will be used later outside of this function
8347 
8348  // TODO Use an internal dolibarr component instead of select2
8349  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8350  return '';
8351  }
8352 
8353  $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
8354 
8355  $outdelayed = '';
8356  if (!empty($conf->use_javascript_ajax)) {
8357  $tmpplugin = 'select2';
8358  $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8359  <script nonce="' . getNonce() . '">
8360  $(document).ready(function () {
8361 
8362  ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
8363 
8364  $(".' . $htmlname . '").select2({
8365  ajax: {
8366  dir: "ltr",
8367  url: "' . $url . '",
8368  dataType: \'json\',
8369  delay: 250,
8370  data: function (params) {
8371  return {
8372  q: params.term, // search term
8373  page: params.page
8374  }
8375  },
8376  processResults: function (data) {
8377  // parse the results into the format expected by Select2.
8378  // since we are using custom formatting functions we do not need to alter the remote JSON data
8379  //console.log(data);
8380  saveRemoteData = data;
8381  /* format json result for select2 */
8382  result = []
8383  $.each( data, function( key, value ) {
8384  result.push({id: key, text: value.text});
8385  });
8386  //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8387  //console.log(result);
8388  return {results: result, more: false}
8389  },
8390  cache: true
8391  },
8392  language: select2arrayoflanguage,
8393  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8394  placeholder: "' . dol_escape_js($placeholder) . '",
8395  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8396  minimumInputLength: ' . ((int) $minimumInputLength) . ',
8397  formatResult: function (result, container, query, escapeMarkup) {
8398  return escapeMarkup(result.text);
8399  },
8400  });
8401 
8402  ' . ($callurlonselect ? '
8403  /* Code to execute a GET when we select a value */
8404  $(".' . $htmlname . '").change(function() {
8405  var selected = $(".' . $htmlname . '").val();
8406  console.log("We select in selectArrayAjax the entry "+selected)
8407  $(".' . $htmlname . '").val(""); /* reset visible combo value */
8408  $.each( saveRemoteData, function( key, value ) {
8409  if (key == selected)
8410  {
8411  console.log("selectArrayAjax - Do a redirect to "+value.url)
8412  location.assign(value.url);
8413  }
8414  });
8415  });' : '') . '
8416 
8417  });
8418  </script>';
8419  }
8420 
8421  if ($acceptdelayedhtml) {
8422  $delayedhtmlcontent .= $outdelayed;
8423  } else {
8424  $out .= $outdelayed;
8425  }
8426  return $out;
8427  }
8428 
8448  public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
8449  {
8450  global $conf, $langs;
8451  global $delayedhtmlcontent; // Will be used later outside of this function
8452 
8453  // TODO Use an internal dolibarr component instead of select2
8454  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8455  return '';
8456  }
8457 
8458  $out = '<select type="text"'.($textfortitle? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
8459 
8460  $formattedarrayresult = array();
8461 
8462  foreach ($array as $key => $value) {
8463  $o = new stdClass();
8464  $o->id = $key;
8465  $o->text = $value['text'];
8466  $o->url = $value['url'];
8467  $formattedarrayresult[] = $o;
8468  }
8469 
8470  $outdelayed = '';
8471  if (!empty($conf->use_javascript_ajax)) {
8472  $tmpplugin = 'select2';
8473  $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
8474  <script nonce="' . getNonce() . '">
8475  $(document).ready(function () {
8476  var data = ' . json_encode($formattedarrayresult) . ';
8477 
8478  ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
8479 
8480  $(".' . $htmlname . '").select2({
8481  data: data,
8482  language: select2arrayoflanguage,
8483  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8484  placeholder: "' . dol_escape_js($placeholder) . '",
8485  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8486  minimumInputLength: ' . $minimumInputLength . ',
8487  formatResult: function (result, container, query, escapeMarkup) {
8488  return escapeMarkup(result.text);
8489  },
8490  matcher: function (params, data) {
8491 
8492  if(! data.id) return null;';
8493 
8494  if ($callurlonselect) {
8495  // We forge the url with 'sall='
8496  $outdelayed .= '
8497 
8498  var urlBase = data.url;
8499  var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8500  /* console.log("params.term="+params.term); */
8501  /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8502  saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8503  }
8504 
8505  if (!$disableFiltering) {
8506  $outdelayed .= '
8507 
8508  if(data.text.match(new RegExp(params.term))) {
8509  return data;
8510  }
8511 
8512  return null;';
8513  } else {
8514  $outdelayed .= '
8515 
8516  return data;';
8517  }
8518 
8519  $outdelayed .= '
8520  }
8521  });
8522 
8523  ' . ($callurlonselect ? '
8524  /* Code to execute a GET when we select a value */
8525  $(".' . $htmlname . '").change(function() {
8526  var selected = $(".' . $htmlname . '").val();
8527  console.log("We select "+selected)
8528 
8529  $(".' . $htmlname . '").val(""); /* reset visible combo value */
8530  $.each( saveRemoteData, function( key, value ) {
8531  if (key == selected)
8532  {
8533  console.log("selectArrayFilter - Do a redirect to "+value.url)
8534  location.assign(value.url);
8535  }
8536  });
8537  });' : '') . '
8538 
8539  });
8540  </script>';
8541  }
8542 
8543  if ($acceptdelayedhtml) {
8544  $delayedhtmlcontent .= $outdelayed;
8545  } else {
8546  $out .= $outdelayed;
8547  }
8548  return $out;
8549  }
8550 
8569  public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $elemtype = '', $placeholder = '', $addjscombo = -1)
8570  {
8571  global $conf, $langs;
8572 
8573  $out = '';
8574 
8575  if ($addjscombo < 0) {
8576  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8577  $addjscombo = 1;
8578  } else {
8579  $addjscombo = 0;
8580  }
8581  }
8582 
8583  $useenhancedmultiselect = 0;
8584  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8585  $useenhancedmultiselect = 1;
8586  }
8587 
8588  // Output select component
8589  $out .= '<select id="' . $htmlname . '" class="multiselect' . ($useenhancedmultiselect ? ' multiselectononeline' : '') . ($morecss ? ' ' . $morecss : '') . '" multiple name="' . $htmlname . '[]"' . ($moreattrib ? ' ' . $moreattrib : '') . ($width ? ' style="width: ' . (preg_match('/%/', $width) ? $width : $width . 'px') . '"' : '') . '>' . "\n";
8590  if (is_array($array) && !empty($array)) {
8591  if ($value_as_key) {
8592  $array = array_combine($array, $array);
8593  }
8594 
8595  if (!empty($array)) {
8596  foreach ($array as $key => $value) {
8597  $tmpkey = $key;
8598  $tmpvalue = $value;
8599  $tmpcolor = '';
8600  $tmppicto = '';
8601  $tmplabelhtml = '';
8602  if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
8603  $tmpkey = $value['id'];
8604  $tmpvalue = $value['label'];
8605  $tmpcolor = $value['color'];
8606  $tmppicto = $value['picto'];
8607  $tmplabelhtml = !empty($value['labelhtml']) ? $value['labelhtml'] : '';
8608  }
8609  $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
8610  $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
8611 
8612  $out .= '<option value="' . $tmpkey . '"';
8613  if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
8614  $out .= ' selected';
8615  }
8616  if (!empty($tmplabelhtml)) {
8617  $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
8618  } else {
8619  $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
8620  $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
8621  }
8622  $out .= '>';
8623  $out .= dol_htmlentitiesbr($newval);
8624  $out .= '</option>' . "\n";
8625  }
8626  }
8627  }
8628  $out .= '</select>' . "\n";
8629 
8630  // Add code for jquery to use multiselect
8631  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8632  $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
8633  $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
8634  if ($addjscombo == 1) {
8635  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
8636  $out .= 'function formatResult(record, container) {' . "\n";
8637  // If property html set, we decode html entities and use this.
8638  // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
8639  $out .= ' if ($(record.element).attr("data-html") != undefined) { return htmlEntityDecodeJs($(record.element).attr("data-html")); }'."\n";
8640  $out .= ' return record.text;';
8641  $out .= '}' . "\n";
8642  $out .= 'function formatSelection(record) {' . "\n";
8643  if ($elemtype == 'category') {
8644  $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
8645  } else {
8646  $out .= 'return record.text;';
8647  }
8648  $out .= '}' . "\n";
8649  $out .= '$(document).ready(function () {
8650  $(\'#' . $htmlname . '\').' . $tmpplugin . '({';
8651  if ($placeholder) {
8652  $out .= '
8653  placeholder: {
8654  id: \'-1\',
8655  text: \'' . dol_escape_js($placeholder) . '\'
8656  },';
8657  }
8658  $out .= ' dir: \'ltr\',
8659  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
8660  dropdownCssClass: \'' . $morecss . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect) */
8661  // Specify format function for dropdown item
8662  formatResult: formatResult,
8663  templateResult: formatResult, /* For 4.0 */
8664  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8665  // Specify format function for selected item
8666  formatSelection: formatSelection,
8667  templateSelection: formatSelection /* For 4.0 */
8668  });
8669 
8670  /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
8671  the size only if component is not hidden by default on load */
8672  $(\'#' . $htmlname . ' + .select2\').addClass(\'' . $morecss . '\');
8673  });' . "\n";
8674  } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
8675  // Add other js lib
8676  // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
8677  // ...
8678  $out .= 'console.log(\'addjscombo=2 for htmlname=' . $htmlname . '\');';
8679  $out .= '$(document).ready(function () {
8680  $(\'#' . $htmlname . '\').multiSelect({
8681  containerHTML: \'<div class="multi-select-container">\',
8682  menuHTML: \'<div class="multi-select-menu">\',
8683  buttonHTML: \'<span class="multi-select-button ' . $morecss . '">\',
8684  menuItemHTML: \'<label class="multi-select-menuitem">\',
8685  activeClass: \'multi-select-container--open\',
8686  noneText: \'' . $placeholder . '\'
8687  });
8688  })';
8689  }
8690  $out .= '</script>';
8691  }
8692 
8693  return $out;
8694  }
8695 
8696 
8707  public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
8708  {
8709  global $conf, $langs, $user, $extrafields;
8710 
8711  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8712  return '';
8713  }
8714  if (empty($array)) {
8715  return '';
8716  }
8717 
8718  $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
8719 
8720  if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
8721  $tmparray = explode(',', $user->conf->$tmpvar);
8722  foreach ($array as $key => $val) {
8723  //var_dump($key);
8724  //var_dump($tmparray);
8725  if (in_array($key, $tmparray)) {
8726  $array[$key]['checked'] = 1;
8727  } else {
8728  $array[$key]['checked'] = 0;
8729  }
8730  }
8731  } else { // There is no list of fields already customized for user
8732  foreach ($array as $key => $val) {
8733  if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
8734  $array[$key]['checked'] = 0;
8735  }
8736  }
8737  }
8738 
8739  $listoffieldsforselection = '';
8740  $listcheckedstring = '';
8741 
8742  foreach ($array as $key => $val) {
8743  // var_dump($val);
8744  // var_dump(array_key_exists('enabled', $val));
8745  // var_dump(!$val['enabled']);
8746  if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
8747  unset($array[$key]); // We don't want this field
8748  continue;
8749  }
8750  if (!empty($val['type']) && $val['type'] == 'separate') {
8751  // Field remains in array but we don't add it into $listoffieldsforselection
8752  //$listoffieldsforselection .= '<li>-----</li>';
8753  continue;
8754  }
8755  if ($val['label']) {
8756  if (!empty($val['langfile']) && is_object($langs)) {
8757  $langs->load($val['langfile']);
8758  }
8759 
8760  // Note: $val['checked'] <> 0 means we must show the field into the combo list
8761  $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/><label for="checkbox' . $key . '">' . dol_escape_htmltag($langs->trans($val['label'])) . '</label></li>';
8762  $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
8763  }
8764  }
8765 
8766  $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
8767 
8768  <dl class="dropdown">
8769  <dt>
8770  <a href="#' . $htmlname . '">
8771  ' . img_picto('', 'list') . '
8772  </a>
8773  <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
8774  </dt>
8775  <dd class="dropdowndd">
8776  <div class="multiselectcheckbox'.$htmlname.'">
8777  <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
8778  <li><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
8779  '.$listoffieldsforselection.'
8780  </ul>
8781  </div>
8782  </dd>
8783  </dl>
8784 
8785  <script nonce="' . getNonce() . '" type="text/javascript">
8786  jQuery(document).ready(function () {
8787  $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
8788  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
8789 
8790  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
8791 
8792  var title = $(this).val() + ",";
8793  if ($(this).is(\':checked\')) {
8794  $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
8795  }
8796  else {
8797  $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
8798  }
8799  // Now, we submit page
8800  //$(this).parents(\'form:first\').submit();
8801  });
8802  $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
8803  var value = $(this).val().toLowerCase();
8804  $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
8805  $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
8806  });
8807  });
8808 
8809 
8810  });
8811  </script>
8812 
8813  ';
8814  return $out;
8815  }
8816 
8826  public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
8827  {
8828  include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
8829 
8830  $cat = new Categorie($this->db);
8831  $categories = $cat->containing($id, $type);
8832 
8833  if ($rendermode == 1) {
8834  $toprint = array();
8835  foreach ($categories as $c) {
8836  $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
8837  foreach ($ways as $way) {
8838  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
8839  }
8840  }
8841  return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
8842  }
8843 
8844  if ($rendermode == 0) {
8845  $arrayselected = array();
8846  $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
8847  foreach ($categories as $c) {
8848  $arrayselected[] = $c->id;
8849  }
8850 
8851  return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
8852  }
8853 
8854  return 'ErrorBadValueForParameterRenderMode'; // Should not happened
8855  }
8856 
8866  public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false, $title = 'RelatedObjects')
8867  {
8868  global $conf, $langs, $hookmanager;
8869  global $bc, $action;
8870 
8871  $object->fetchObjectLinked();
8872 
8873  // Bypass the default method
8874  $hookmanager->initHooks(array('commonobject'));
8875  $parameters = array(
8876  'morehtmlright' => $morehtmlright,
8877  'compatibleImportElementsList' => &$compatibleImportElementsList,
8878  );
8879  $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8880 
8881  $nbofdifferenttypes = count($object->linkedObjects);
8882 
8883  if (empty($reshook)) {
8884  print '<!-- showLinkedObjectBlock -->';
8885  print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
8886 
8887 
8888  print '<div class="div-table-responsive-no-min">';
8889  print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
8890 
8891  print '<tr class="liste_titre">';
8892  print '<td>' . $langs->trans("Type") . '</td>';
8893  print '<td>' . $langs->trans("Ref") . '</td>';
8894  print '<td class="center"></td>';
8895  print '<td class="center">' . $langs->trans("Date") . '</td>';
8896  print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
8897  print '<td class="right">' . $langs->trans("Status") . '</td>';
8898  print '<td></td>';
8899  print '</tr>';
8900 
8901  $nboftypesoutput = 0;
8902 
8903  foreach ($object->linkedObjects as $objecttype => $objects) {
8904  $tplpath = $element = $subelement = $objecttype;
8905 
8906  // to display inport button on tpl
8907  $showImportButton = false;
8908  if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
8909  $showImportButton = true;
8910  }
8911 
8912  $regs = array();
8913  if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
8914  $element = $regs[1];
8915  $subelement = $regs[2];
8916  $tplpath = $element . '/' . $subelement;
8917  }
8918  $tplname = 'linkedobjectblock';
8919 
8920  // To work with non standard path
8921  if ($objecttype == 'facture') {
8922  $tplpath = 'compta/' . $element;
8923  if (!isModEnabled('facture')) {
8924  continue; // Do not show if module disabled
8925  }
8926  } elseif ($objecttype == 'facturerec') {
8927  $tplpath = 'compta/facture';
8928  $tplname = 'linkedobjectblockForRec';
8929  if (!isModEnabled('facture')) {
8930  continue; // Do not show if module disabled
8931  }
8932  } elseif ($objecttype == 'propal') {
8933  $tplpath = 'comm/' . $element;
8934  if (!isModEnabled('propal')) {
8935  continue; // Do not show if module disabled
8936  }
8937  } elseif ($objecttype == 'supplier_proposal') {
8938  if (!isModEnabled('supplier_proposal')) {
8939  continue; // Do not show if module disabled
8940  }
8941  } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
8942  $tplpath = 'expedition';
8943  if (!isModEnabled('expedition')) {
8944  continue; // Do not show if module disabled
8945  }
8946  } elseif ($objecttype == 'reception') {
8947  $tplpath = 'reception';
8948  if (!isModEnabled('reception')) {
8949  continue; // Do not show if module disabled
8950  }
8951  } elseif ($objecttype == 'delivery') {
8952  $tplpath = 'delivery';
8953  if (!isModEnabled('expedition')) {
8954  continue; // Do not show if module disabled
8955  }
8956  } elseif ($objecttype == 'ficheinter') {
8957  $tplpath = 'fichinter';
8958  if (!isModEnabled('ficheinter')) {
8959  continue; // Do not show if module disabled
8960  }
8961  } elseif ($objecttype == 'invoice_supplier') {
8962  $tplpath = 'fourn/facture';
8963  } elseif ($objecttype == 'order_supplier') {
8964  $tplpath = 'fourn/commande';
8965  } elseif ($objecttype == 'expensereport') {
8966  $tplpath = 'expensereport';
8967  } elseif ($objecttype == 'subscription') {
8968  $tplpath = 'adherents';
8969  } elseif ($objecttype == 'conferenceorbooth') {
8970  $tplpath = 'eventorganization';
8971  } elseif ($objecttype == 'conferenceorboothattendee') {
8972  $tplpath = 'eventorganization';
8973  } elseif ($objecttype == 'mo') {
8974  $tplpath = 'mrp';
8975  if (!isModEnabled('mrp')) {
8976  continue; // Do not show if module disabled
8977  }
8978  }
8979 
8980  global $linkedObjectBlock;
8981  $linkedObjectBlock = $objects;
8982 
8983  // Output template part (modules that overwrite templates must declare this into descriptor)
8984  $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
8985  foreach ($dirtpls as $reldir) {
8986  if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
8987  global $noMoreLinkedObjectBlockAfter;
8988  $noMoreLinkedObjectBlockAfter = 1;
8989  }
8990 
8991  $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
8992  if ($res) {
8993  $nboftypesoutput++;
8994  break;
8995  }
8996  }
8997  }
8998 
8999  if (!$nboftypesoutput) {
9000  print '<tr><td class="impair" colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9001  }
9002 
9003  print '</table>';
9004 
9005  if (!empty($compatibleImportElementsList)) {
9006  $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9007  }
9008 
9009  print '</div>';
9010  }
9011 
9012  return $nbofdifferenttypes;
9013  }
9014 
9023  public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
9024  {
9025  global $conf, $langs, $hookmanager;
9026  global $action;
9027 
9028  $linktoelem = '';
9029  $linktoelemlist = '';
9030  $listofidcompanytoscan = '';
9031 
9032  if (!is_object($object->thirdparty)) {
9033  $object->fetch_thirdparty();
9034  }
9035 
9036  $possiblelinks = array();
9037  if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9038  $listofidcompanytoscan = $object->thirdparty->id;
9039  if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
9040  $listofidcompanytoscan .= ',' . $object->thirdparty->parent;
9041  }
9042  if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
9043  include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9044  $tmpproject = new Project($this->db);
9045  $tmpproject->fetch($object->fk_project);
9046  if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9047  $listofidcompanytoscan .= ',' . $tmpproject->socid;
9048  }
9049  unset($tmpproject);
9050  }
9051 
9052  $possiblelinks = array(
9053  'propal' => array(
9054  'enabled' => isModEnabled('propal'),
9055  'perms' => 1,
9056  'label' => 'LinkToProposal',
9057  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('propal') . ')'),
9058  'shipping' => array(
9059  'enabled' => isModEnabled('expedition'),
9060  'perms' => 1,
9061  'label' => 'LinkToExpedition',
9062  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "expedition as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('shipping') . ')'),
9063  'order' => array(
9064  'enabled' => isModEnabled('commande'),
9065  'perms' => 1,
9066  'label' => 'LinkToOrder',
9067  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('commande') . ')'),
9068  'invoice' => array(
9069  'enabled' => isModEnabled('facture'),
9070  'perms' => 1,
9071  'label' => 'LinkToInvoice',
9072  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'),
9073  'invoice_template' => array(
9074  'enabled' => isModEnabled('facture'),
9075  'perms' => 1,
9076  'label' => 'LinkToTemplateInvoice',
9077  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('invoice') . ')'),
9078  'contrat' => array(
9079  'enabled' => isModEnabled('contrat'),
9080  'perms' => 1,
9081  'label' => 'LinkToContract',
9082  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, SUM(td.total_ht) as total_ht
9083  FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "contrat as t, " . $this->db->prefix() . "contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('contract') . ') GROUP BY s.rowid, s.nom, s.client, t.rowid, t.ref, t.ref_customer, t.ref_supplier'
9084  ),
9085  'fichinter' => array(
9086  'enabled' => isModEnabled('ficheinter'),
9087  'perms' => 1,
9088  'label' => 'LinkToIntervention',
9089  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('intervention') . ')'),
9090  'supplier_proposal' => array(
9091  'enabled' => (isModEnabled('supplier_proposal') ? $conf->supplier_proposal->enabled : 0),
9092  'perms' => 1,
9093  'label' => 'LinkToSupplierProposal',
9094  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('supplier_proposal') . ')'),
9095  'order_supplier' => array(
9096  'enabled' => (isModEnabled("supplier_order") ? $conf->supplier_order->enabled : 0),
9097  'perms' => 1,
9098  'label' => 'LinkToSupplierOrder',
9099  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('commande_fournisseur') . ')'),
9100  'invoice_supplier' => array(
9101  'enabled' => (isModEnabled("supplier_invoice") ? $conf->supplier_invoice->enabled : 0),
9102  'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9103  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('facture_fourn') . ')'),
9104  'ticket' => array(
9105  'enabled' => isModEnabled('ticket'),
9106  'perms' => 1,
9107  'label' => 'LinkToTicket',
9108  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('ticket') . ')'),
9109  'mo' => array(
9110  'enabled' => isModEnabled('mrp'),
9111  'perms' => 1,
9112  'label' => 'LinkToMo',
9113  'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM " . $this->db->prefix() . "societe as s INNER JOIN " . $this->db->prefix() . "mrp_mo as t ON t.fk_soc = s.rowid WHERE t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('mo') . ')')
9114  );
9115  }
9116 
9117  if ($object->table_element == 'commande_fournisseur') {
9118  $possiblelinks['mo']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix().'mrp_mo as t ON t.fk_soc = s.rowid WHERE t.entity IN ('.getEntity('mo').')';
9119  } elseif ($object->table_element == 'mrp_mo') {
9120  $possiblelinks['order_supplier']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix().'commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.entity IN ('.getEntity('commande_fournisseur').')';
9121  }
9122 
9123  if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9124  // Can complete the possiblelink array
9125  $hookmanager->initHooks(array('commonobject'));
9126  $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9127  $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9128  }
9129 
9130  if (empty($reshook)) {
9131  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9132  $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9133  }
9134  } elseif ($reshook > 0) {
9135  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9136  $possiblelinks = $hookmanager->resArray;
9137  }
9138  }
9139 
9140  foreach ($possiblelinks as $key => $possiblelink) {
9141  $num = 0;
9142 
9143  if (empty($possiblelink['enabled'])) {
9144  continue;
9145  }
9146 
9147  if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9148  print '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9149 
9150  if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
9151  print '<br>'."\n";
9152  print '<!-- form to add a link from anywhere -->'."\n";
9153  print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9154  print '<input type="hidden" name="id" value="' . $object->id . '">';
9155  print '<input type="hidden" name="action" value="addlinkbyref">';
9156  print '<input type="hidden" name="token" value="' . newToken() . '">';
9157  print '<input type="hidden" name="addlink" value="' . $key . '">';
9158  print '<table class="noborder">';
9159  print '<tr>';
9160  //print '<td>' . $langs->trans("Ref") . '</td>';
9161  print '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9162  print '<input type="submit" class="button small valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9163  print '<input type="submit" class="button small" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9164  print '</tr>';
9165  print '</table>';
9166  print '</form>';
9167  }
9168 
9169  $sql = $possiblelink['sql'];
9170 
9171  $resqllist = $this->db->query($sql);
9172  if ($resqllist) {
9173  $num = $this->db->num_rows($resqllist);
9174  $i = 0;
9175 
9176  print '<br>';
9177  print '<!-- form to add a link from object to same thirdparty -->'."\n";
9178  print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9179  print '<input type="hidden" name="action" value="addlink">';
9180  print '<input type="hidden" name="token" value="' . newToken() . '">';
9181  print '<input type="hidden" name="id" value="' . $object->id . '">';
9182  print '<input type="hidden" name="addlink" value="' . $key . '">';
9183  print '<table class="noborder">';
9184  print '<tr class="liste_titre">';
9185  print '<td class="nowrap"></td>';
9186  print '<td class="center">' . $langs->trans("Ref") . '</td>';
9187  print '<td class="left">' . $langs->trans("RefCustomer") . '</td>';
9188  print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9189  print '<td class="left">' . $langs->trans("Company") . '</td>';
9190  print '</tr>';
9191  while ($i < $num) {
9192  $objp = $this->db->fetch_object($resqllist);
9193 
9194  print '<tr class="oddeven">';
9195  print '<td class="left">';
9196  print '<input type="radio" name="idtolinkto" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9197  print '</td>';
9198  print '<td class="center"><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9199  print '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9200  print '<td class="right">';
9201  if ($possiblelink['label'] == 'LinkToContract') {
9202  $form = new Form($this->db);
9203  print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9204  }
9205  print '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9206  print '</td>';
9207  print '<td>' . $objp->name . '</td>';
9208  print '</tr>';
9209  $i++;
9210  }
9211  print '</table>';
9212  print '<div class="center">';
9213  if ($num) {
9214  print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly small" value="' . $langs->trans('ToLink') . '">';
9215  }
9216  if (empty($conf->use_javascript_ajax)) {
9217  print '<input type="submit" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9218  } else {
9219  print '<input type="submit" onclick="jQuery(\'#' . $key . 'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly small" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9220  }
9221  print '</form>';
9222  $this->db->free($resqllist);
9223  } else {
9224  dol_print_error($this->db);
9225  }
9226  print '</div>';
9227 
9228  //$linktoelem.=($linktoelem?' &nbsp; ':'');
9229  if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
9230  $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
9231  // } else $linktoelem.=$langs->trans($possiblelink['label']);
9232  } else {
9233  $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
9234  }
9235  }
9236  }
9237 
9238  if ($linktoelemlist) {
9239  $linktoelem = '
9240  <dl class="dropdown" id="linktoobjectname">
9241  ';
9242  if (!empty($conf->use_javascript_ajax)) {
9243  $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
9244  }
9245  $linktoelem .= '<dd>
9246  <div class="multiselectlinkto">
9247  <ul class="ulselectedfields">' . $linktoelemlist . '
9248  </ul>
9249  </div>
9250  </dd>
9251  </dl>';
9252  } else {
9253  $linktoelem = '';
9254  }
9255 
9256  if (!empty($conf->use_javascript_ajax)) {
9257  print '<!-- Add js to show linkto box -->
9258  <script nonce="' . getNonce() . '">
9259  jQuery(document).ready(function() {
9260  jQuery(".linkto").click(function() {
9261  console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9262  jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9263  });
9264  });
9265  </script>
9266  ';
9267  }
9268 
9269  return $linktoelem;
9270  }
9271 
9286  public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '', $labelyes = 'Yes', $labelno = 'No')
9287  {
9288  global $langs;
9289 
9290  $yes = "yes";
9291  $no = "no";
9292  if ($option) {
9293  $yes = "1";
9294  $no = "0";
9295  }
9296 
9297  $disabled = ($disabled ? ' disabled' : '');
9298 
9299  $resultyesno = '<select class="flat width75' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
9300  if ($useempty) {
9301  $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9302  }
9303  if (("$value" == 'yes') || ($value == 1)) {
9304  $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
9305  $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
9306  } else {
9307  $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9308  $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
9309  $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
9310  }
9311  $resultyesno .= '</select>' . "\n";
9312 
9313  if ($addjscombo) {
9314  $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9315  }
9316 
9317  return $resultyesno;
9318  }
9319 
9320  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9321 
9331  public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9332  {
9333  // phpcs:enable
9334  $sql = "SELECT rowid, label";
9335  $sql .= " FROM " . $this->db->prefix() . "export_model";
9336  $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
9337  $sql .= " ORDER BY rowid";
9338  $result = $this->db->query($sql);
9339  if ($result) {
9340  print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
9341  if ($useempty) {
9342  print '<option value="-1">&nbsp;</option>';
9343  }
9344 
9345  $num = $this->db->num_rows($result);
9346  $i = 0;
9347  while ($i < $num) {
9348  $obj = $this->db->fetch_object($result);
9349  if ($selected == $obj->rowid) {
9350  print '<option value="' . $obj->rowid . '" selected>';
9351  } else {
9352  print '<option value="' . $obj->rowid . '">';
9353  }
9354  print $obj->label;
9355  print '</option>';
9356  $i++;
9357  }
9358  print "</select>";
9359  } else {
9360  dol_print_error($this->db);
9361  }
9362  }
9363 
9382  public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9383  {
9384  global $conf, $langs, $hookmanager, $extralanguages;
9385 
9386  $ret = '';
9387  if (empty($fieldid)) {
9388  $fieldid = 'rowid';
9389  }
9390  if (empty($fieldref)) {
9391  $fieldref = 'ref';
9392  }
9393 
9394  // Preparing gender's display if there is one
9395  $addgendertxt = '';
9396  if (property_exists($object, 'gender') && !empty($object->gender)) {
9397  $addgendertxt = ' ';
9398  switch ($object->gender) {
9399  case 'man':
9400  $addgendertxt .= '<i class="fas fa-mars"></i>';
9401  break;
9402  case 'woman':
9403  $addgendertxt .= '<i class="fas fa-venus"></i>';
9404  break;
9405  case 'other':
9406  $addgendertxt .= '<i class="fas fa-transgender"></i>';
9407  break;
9408  }
9409  }
9410 
9411  // Add where from hooks
9412  if (is_object($hookmanager)) {
9413  $parameters = array('showrefnav' => true);
9414  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9415  $object->next_prev_filter .= $hookmanager->resPrint;
9416  }
9417  $previous_ref = $next_ref = '';
9418  if ($shownav) {
9419  //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9420  $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9421 
9422  $navurl = $_SERVER["PHP_SELF"];
9423  // Special case for project/task page
9424  if ($paramid == 'project_ref') {
9425  if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9426  $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9427  $paramid = 'ref';
9428  }
9429  }
9430 
9431  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9432  // accesskey is for Mac: CTRL + key for all browsers
9433  $stringforfirstkey = $langs->trans("KeyboardShortcut");
9434  if ($conf->browser->name == 'chrome') {
9435  $stringforfirstkey .= ' ALT +';
9436  } elseif ($conf->browser->name == 'firefox') {
9437  $stringforfirstkey .= ' ALT + SHIFT +';
9438  } else {
9439  $stringforfirstkey .= ' CTL +';
9440  }
9441 
9442  $previous_ref = $object->ref_previous ? '<a accesskey="p" title="' . $stringforfirstkey . ' p" class="classfortooltip" href="' . $navurl . '?' . $paramid . '=' . urlencode($object->ref_previous) . $moreparam . '"><i class="fa fa-chevron-left"></i></a>' : '<span class="inactive"><i class="fa fa-chevron-left opacitymedium"></i></span>';
9443  $next_ref = $object->ref_next ? '<a accesskey="n" title="' . $stringforfirstkey . ' n" class="classfortooltip" href="' . $navurl . '?' . $paramid . '=' . urlencode($object->ref_next) . $moreparam . '"><i class="fa fa-chevron-right"></i></a>' : '<span class="inactive"><i class="fa fa-chevron-right opacitymedium"></i></span>';
9444  }
9445 
9446  //print "xx".$previous_ref."x".$next_ref;
9447  $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9448 
9449  // Right part of banner
9450  if ($morehtmlright) {
9451  $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
9452  }
9453 
9454  if ($previous_ref || $next_ref || $morehtml) {
9455  $ret .= '<div class="pagination paginationref"><ul class="right">';
9456  }
9457  if ($morehtml) {
9458  $ret .= '<li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
9459  }
9460  if ($shownav && ($previous_ref || $next_ref)) {
9461  $ret .= '<li class="pagination">' . $previous_ref . '</li>';
9462  $ret .= '<li class="pagination">' . $next_ref . '</li>';
9463  }
9464  if ($previous_ref || $next_ref || $morehtml) {
9465  $ret .= '</ul></div>';
9466  }
9467 
9468  // Status
9469  $parameters = array();
9470  $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9471  if (empty($reshook)) {
9472  $morehtmlstatus .= $hookmanager->resPrint;
9473  } else {
9474  $morehtmlstatus = $hookmanager->resPrint;
9475  }
9476  if ($morehtmlstatus) {
9477  $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
9478  }
9479 
9480  $parameters = array();
9481  $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9482  if (empty($reshook)) {
9483  $morehtmlref .= $hookmanager->resPrint;
9484  } elseif ($reshook > 0) {
9485  $morehtmlref = $hookmanager->resPrint;
9486  }
9487 
9488  // Left part of banner
9489  if ($morehtmlleft) {
9490  if ($conf->browser->layout == 'phone') {
9491  $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
9492  } else {
9493  $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
9494  }
9495  }
9496 
9497  //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9498  $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
9499 
9500  // For thirdparty, contact, user, member, the ref is the id, so we show something else
9501  if ($object->element == 'societe') {
9502  $ret .= dol_htmlentities($object->name);
9503 
9504  // List of extra languages
9505  $arrayoflangcode = array();
9506  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
9507  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
9508  }
9509 
9510  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9511  if (!is_object($extralanguages)) {
9512  include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
9513  $extralanguages = new ExtraLanguages($this->db);
9514  }
9515  $extralanguages->fetch_name_extralanguages('societe');
9516 
9517  if (!empty($extralanguages->attributes['societe']['name'])) {
9518  $object->fetchValuesForExtraLanguages();
9519 
9520  $htmltext = '';
9521  // If there is extra languages
9522  foreach ($arrayoflangcode as $extralangcode) {
9523  $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9524  if ($object->array_languages['name'][$extralangcode]) {
9525  $htmltext .= $object->array_languages['name'][$extralangcode];
9526  } else {
9527  $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
9528  }
9529  }
9530  $ret .= '<!-- Show translations of name -->' . "\n";
9531  $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
9532  }
9533  }
9534  } elseif ($object->element == 'member') {
9535  $ret .= $object->ref . '<br>';
9536  $fullname = $object->getFullName($langs);
9537  if ($object->morphy == 'mor' && $object->societe) {
9538  $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
9539  } else {
9540  $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
9541  }
9542  } elseif (in_array($object->element, array('contact', 'user'))) {
9543  $ret .= dol_htmlentities($object->getFullName($langs)) . $addgendertxt;
9544  } elseif ($object->element == 'usergroup') {
9545  $ret .= dol_htmlentities($object->name);
9546  } elseif (in_array($object->element, array('action', 'agenda'))) {
9547  $ret .= $object->ref . '<br>' . $object->label;
9548  } elseif (in_array($object->element, array('adherent_type'))) {
9549  $ret .= $object->label;
9550  } elseif ($object->element == 'ecm_directories') {
9551  $ret .= '';
9552  } elseif ($fieldref != 'none') {
9553  $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
9554  }
9555  if ($morehtmlref) {
9556  // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9557  if (substr($morehtmlref, 0, 4) != '<div') {
9558  $ret .= ' ';
9559  }
9560 
9561  $ret .= $morehtmlref;
9562  }
9563 
9564  $ret .= '</div>';
9565 
9566  $ret .= '</div><!-- End banner content -->';
9567 
9568  return $ret;
9569  }
9570 
9571 
9580  public function showbarcode(&$object, $width = 100, $morecss = '')
9581  {
9582  global $conf;
9583 
9584  //Check if barcode is filled in the card
9585  if (empty($object->barcode)) {
9586  return '';
9587  }
9588 
9589  // Complete object if not complete
9590  if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
9591  $result = $object->fetch_barcode();
9592  //Check if fetch_barcode() failed
9593  if ($result < 1) {
9594  return '<!-- ErrorFetchBarcode -->';
9595  }
9596  }
9597 
9598  // Barcode image
9599  $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
9600  $out = '<!-- url barcode = ' . $url . ' -->';
9601  $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
9602 
9603  return $out;
9604  }
9605 
9622  public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
9623  {
9624  global $conf, $langs;
9625 
9626  $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
9627  $id = (!empty($object->id) ? $object->id : $object->rowid);
9628 
9629  $ret = '';
9630  $dir = '';
9631  $file = '';
9632  $originalfile = '';
9633  $altfile = '';
9634  $email = '';
9635  $capture = '';
9636  if ($modulepart == 'societe') {
9637  $dir = $conf->societe->multidir_output[$entity];
9638  if (!empty($object->logo)) {
9639  if (dolIsAllowedForPreview($object->logo)) {
9640  if ((string) $imagesize == 'mini') {
9641  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
9642  } elseif ((string) $imagesize == 'small') {
9643  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
9644  } else {
9645  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
9646  }
9647  $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
9648  }
9649  }
9650  $email = $object->email;
9651  } elseif ($modulepart == 'contact') {
9652  $dir = $conf->societe->multidir_output[$entity] . '/contact';
9653  if (!empty($object->photo)) {
9654  if (dolIsAllowedForPreview($object->photo)) {
9655  if ((string) $imagesize == 'mini') {
9656  $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9657  } elseif ((string) $imagesize == 'small') {
9658  $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9659  } else {
9660  $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
9661  }
9662  $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
9663  }
9664  }
9665  $email = $object->email;
9666  $capture = 'user';
9667  } elseif ($modulepart == 'userphoto') {
9668  $dir = $conf->user->dir_output;
9669  if (!empty($object->photo)) {
9670  if (dolIsAllowedForPreview($object->photo)) {
9671  if ((string) $imagesize == 'mini') {
9672  $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9673  } elseif ((string) $imagesize == 'small') {
9674  $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9675  } else {
9676  $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
9677  }
9678  $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
9679  }
9680  }
9681  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9682  $altfile = $object->id . ".jpg"; // For backward compatibility
9683  }
9684  $email = $object->email;
9685  $capture = 'user';
9686  } elseif ($modulepart == 'memberphoto') {
9687  $dir = $conf->adherent->dir_output;
9688  if (!empty($object->photo)) {
9689  if (dolIsAllowedForPreview($object->photo)) {
9690  if ((string) $imagesize == 'mini') {
9691  $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9692  } elseif ((string) $imagesize == 'small') {
9693  $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9694  } else {
9695  $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
9696  }
9697  $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
9698  }
9699  }
9700  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9701  $altfile = $object->id . ".jpg"; // For backward compatibility
9702  }
9703  $email = $object->email;
9704  $capture = 'user';
9705  } else {
9706  // Generic case to show photos
9707  $dir = $conf->$modulepart->dir_output;
9708  if (!empty($object->photo)) {
9709  if (dolIsAllowedForPreview($object->photo)) {
9710  if ((string) $imagesize == 'mini') {
9711  $file = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
9712  } elseif ((string) $imagesize == 'small') {
9713  $file = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . getImageFileNameForSize($object->photo, '_small');
9714  } else {
9715  $file = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . $object->photo;
9716  }
9717  $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart) . 'photos/' . $object->photo;
9718  }
9719  }
9720  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9721  $altfile = $object->id . ".jpg"; // For backward compatibility
9722  }
9723  $email = $object->email;
9724  }
9725 
9726  if ($forcecapture) {
9727  $capture = $forcecapture;
9728  }
9729 
9730  if ($dir) {
9731  if ($file && file_exists($dir . "/" . $file)) {
9732  if ($addlinktofullsize) {
9733  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
9734  if ($urladvanced) {
9735  $ret .= '<a href="' . $urladvanced . '">';
9736  } else {
9737  $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
9738  }
9739  }
9740  $ret .= '<img alt="Photo" class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . ' photologo' . (preg_replace('/[^a-z]/i', '_', $file)) . '" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($file) . '&cache=' . $cache . '">';
9741  if ($addlinktofullsize) {
9742  $ret .= '</a>';
9743  }
9744  } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
9745  if ($addlinktofullsize) {
9746  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
9747  if ($urladvanced) {
9748  $ret .= '<a href="' . $urladvanced . '">';
9749  } else {
9750  $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
9751  }
9752  }
9753  $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="Photo alt" id="photologo' . (preg_replace('/[^a-z]/i', '_', $file)) . '" class="' . $cssclass . '" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($altfile) . '&cache=' . $cache . '">';
9754  if ($addlinktofullsize) {
9755  $ret .= '</a>';
9756  }
9757  } else {
9758  $nophoto = '/public/theme/common/nophoto.png';
9759  $defaultimg = 'identicon'; // For gravatar
9760  if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
9761  if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor')) !== false) {
9762  $nophoto = 'company';
9763  } else {
9764  $nophoto = '/public/theme/common/user_anonymous.png';
9765  if (!empty($object->gender) && $object->gender == 'man') {
9766  $nophoto = '/public/theme/common/user_man.png';
9767  }
9768  if (!empty($object->gender) && $object->gender == 'woman') {
9769  $nophoto = '/public/theme/common/user_woman.png';
9770  }
9771  }
9772  }
9773 
9774  if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
9775  // see https://gravatar.com/site/implement/images/php/
9776  $ret .= '<!-- Put link to gravatar -->';
9777  $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" title="' . $email . ' Gravatar avatar" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) . '?s=' . $width . '&d=' . $defaultimg . '">'; // gravatar need md5 hash
9778  } else {
9779  if ($nophoto == 'company') {
9780  $ret .= '<div class="divforspanimg photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
9781  $ret .= '<div class="difforspanimgright"></div>';
9782  } else {
9783  $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
9784  }
9785  }
9786  }
9787 
9788  if ($caneditfield) {
9789  if ($object->photo) {
9790  $ret .= "<br>\n";
9791  }
9792  $ret .= '<table class="nobordernopadding centpercent">';
9793  if ($object->photo) {
9794  $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
9795  }
9796  $ret .= '<tr><td class="tdoverflow">';
9797  $maxfilesizearray = getMaxFileSizeArray();
9798  $maxmin = $maxfilesizearray['maxmin'];
9799  if ($maxmin > 0) {
9800  $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
9801  }
9802  $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
9803  $ret .= '</td></tr>';
9804  $ret .= '</table>';
9805  }
9806  }
9807 
9808  return $ret;
9809  }
9810 
9811  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9812 
9829  public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
9830  {
9831  // phpcs:enable
9832  global $conf, $user, $langs;
9833 
9834  // Permettre l'exclusion de groupes
9835  $excludeGroups = null;
9836  if (is_array($exclude)) {
9837  $excludeGroups = implode(",", $exclude);
9838  }
9839  // Permettre l'inclusion de groupes
9840  $includeGroups = null;
9841  if (is_array($include)) {
9842  $includeGroups = implode(",", $include);
9843  }
9844 
9845  if (!is_array($selected)) {
9846  $selected = array($selected);
9847  }
9848 
9849  $out = '';
9850 
9851  // On recherche les groupes
9852  $sql = "SELECT ug.rowid, ug.nom as name";
9853  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9854  $sql .= ", e.label";
9855  }
9856  $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
9857  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9858  $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
9859  if ($force_entity) {
9860  $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
9861  } else {
9862  $sql .= " WHERE ug.entity IS NOT NULL";
9863  }
9864  } else {
9865  $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
9866  }
9867  if (is_array($exclude) && $excludeGroups) {
9868  $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
9869  }
9870  if (is_array($include) && $includeGroups) {
9871  $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
9872  }
9873  $sql .= " ORDER BY ug.nom ASC";
9874 
9875  dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
9876  $resql = $this->db->query($sql);
9877  if ($resql) {
9878  // Enhance with select2
9879  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9880 
9881  $out .= '<select class="flat minwidth200' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
9882 
9883  $num = $this->db->num_rows($resql);
9884  $i = 0;
9885  if ($num) {
9886  if ($show_empty && !$multiple) {
9887  $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
9888  }
9889 
9890  while ($i < $num) {
9891  $obj = $this->db->fetch_object($resql);
9892  $disableline = 0;
9893  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
9894  $disableline = 1;
9895  }
9896 
9897  $label = $obj->name;
9898  $labelhtml = $obj->name;
9899  if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
9900  $label .= " (" . $obj->label . ")";
9901  $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
9902  }
9903 
9904  $out .= '<option value="' . $obj->rowid . '"';
9905  if ($disableline) {
9906  $out .= ' disabled';
9907  }
9908  if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid) || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
9909  $out .= ' selected';
9910  }
9911  $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
9912  $out .= '>';
9913 
9914  $out .= $label;
9915 
9916  $out .= '</option>';
9917  $i++;
9918  }
9919  } else {
9920  if ($show_empty) {
9921  $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
9922  }
9923  $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
9924  }
9925  $out .= '</select>';
9926 
9927  $out .= ajax_combobox($htmlname);
9928  } else {
9929  dol_print_error($this->db);
9930  }
9931 
9932  return $out;
9933  }
9934 
9935 
9942  public function showFilterButtons($pos = '')
9943  {
9944  $out = '<div class="nowraponall">';
9945  if ($pos == 'left') {
9946  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9947  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9948  } else {
9949  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9950  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9951  }
9952  $out .= '</div>';
9953 
9954  return $out;
9955  }
9956 
9965  public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9966  {
9967  global $conf, $langs;
9968 
9969  $out = '';
9970 
9971  if (!empty($conf->use_javascript_ajax)) {
9972  $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
9973  }
9974  $out .= '<script nonce="' . getNonce() . '">
9975  $(document).ready(function() {
9976  $("#' . $cssclass . 's").click(function() {
9977  if($(this).is(\':checked\')){
9978  console.log("We check all ' . $cssclass . ' and trigger the change method");
9979  $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
9980  }
9981  else
9982  {
9983  console.log("We uncheck all");
9984  $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
9985  }' . "\n";
9986  if ($calljsfunction) {
9987  $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
9988  }
9989  $out .= ' });
9990  $(".' . $cssclass . '").change(function() {
9991  $(this).closest("tr").toggleClass("highlight", this.checked);
9992  });
9993  });
9994  </script>';
9995 
9996  return $out;
9997  }
9998 
10008  public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10009  {
10010  $out = $this->showFilterButtons();
10011  if ($addcheckuncheckall) {
10012  $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10013  }
10014  return $out;
10015  }
10016 
10030  public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10031  {
10032  global $langs, $user;
10033 
10034  $out = '';
10035  $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10036  $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10037  if (!empty($excludeid)) {
10038  $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10039  }
10040  $sql .= " ORDER BY label";
10041 
10042  $resql = $this->db->query($sql);
10043  if ($resql) {
10044  $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10045  if ($useempty) {
10046  $out .= '<option value="0">&nbsp;</option>';
10047  }
10048 
10049  while ($obj = $this->db->fetch_object($resql)) {
10050  $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10051  }
10052  $out .= '</select>';
10053  $out .= ajax_combobox('select_' . $htmlname);
10054 
10055  if (!empty($htmlname) && $user->admin && $info_admin) {
10056  $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10057  }
10058 
10059  if (!empty($target)) {
10060  $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10061  $resql = $this->db->query($sql);
10062  if ($resql) {
10063  if ($this->db->num_rows($resql) > 0) {
10064  $obj = $this->db->fetch_object($resql);
10065  $out .= '<script nonce="' . getNonce() . '">
10066  $(function() {
10067  $("select[name=' . $target . ']").on("change", function() {
10068  var current_val = $(this).val();
10069  if (current_val == ' . $obj->id . ') {';
10070  if (!empty($default_selected) || !empty($selected)) {
10071  $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10072  }
10073 
10074  $out .= '
10075  $("select[name=' . $htmlname . ']").change();
10076  }
10077  });
10078 
10079  $("select[name=' . $htmlname . ']").change(function() {
10080 
10081  if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10082  // get price of kilometer to fill the unit price
10083  $.ajax({
10084  method: "POST",
10085  dataType: "json",
10086  data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10087  url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . join('&', $params)) . '",
10088  }).done(function( data, textStatus, jqXHR ) {
10089  console.log(data);
10090  if (typeof data.up != "undefined") {
10091  $("input[name=value_unit]").val(data.up);
10092  $("select[name=' . $htmlname . ']").attr("title", data.title);
10093  } else {
10094  $("input[name=value_unit]").val("");
10095  $("select[name=' . $htmlname . ']").attr("title", "");
10096  }
10097  });
10098  }
10099  });
10100  });
10101  </script>';
10102  }
10103  }
10104  }
10105  } else {
10106  dol_print_error($this->db);
10107  }
10108 
10109  return $out;
10110  }
10111 
10120  public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10121  {
10122  global $conf, $langs;
10123 
10124  $out = '';
10125  $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10126  $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10127 
10128  $resql = $this->db->query($sql);
10129  if ($resql) {
10130  $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10131  if ($useempty) {
10132  $out .= '<option value="0"></option>';
10133  }
10134 
10135  while ($obj = $this->db->fetch_object($resql)) {
10136  $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10137  }
10138  $out .= '</select>';
10139  } else {
10140  dol_print_error($this->db);
10141  }
10142 
10143  return $out;
10144  }
10145 
10156  public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10157  {
10158  global $langs;
10159 
10160  $out = '';
10161  $sql = "SELECT id, code, label FROM " . $this->db->prefix() . "c_type_fees";
10162  $sql .= " WHERE active = 1";
10163 
10164  $resql = $this->db->query($sql);
10165  if ($resql) {
10166  $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10167  if ($useempty) {
10168  $out .= '<option value="0"></option>';
10169  }
10170  if ($allchoice) {
10171  $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10172  }
10173 
10174  $field = 'code';
10175  if ($useid) {
10176  $field = 'id';
10177  }
10178 
10179  while ($obj = $this->db->fetch_object($resql)) {
10180  $key = $langs->trans($obj->code);
10181  $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10182  }
10183  $out .= '</select>';
10184  } else {
10185  dol_print_error($this->db);
10186  }
10187 
10188  return $out;
10189  }
10190 
10209  public function selectInvoice($socid = -1, $selected = '', $htmlname = 'invoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500', $projectsListId = '', $showproject = 'all', $usertofilter = null)
10210  {
10211  global $user, $conf, $langs;
10212 
10213  require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
10214 
10215  if (is_null($usertofilter)) {
10216  $usertofilter = $user;
10217  }
10218 
10219  $out = '';
10220 
10221  $hideunselectables = false;
10222  if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
10223  $hideunselectables = true;
10224  }
10225 
10226  if (empty($projectsListId)) {
10227  if (empty($usertofilter->rights->projet->all->lire)) {
10228  $projectstatic = new Project($this->db);
10229  $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10230  }
10231  }
10232 
10233  // Search all projects
10234  $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10235  p.title, p.fk_soc, p.fk_statut, p.public,";
10236  $sql .= ' s.nom as name';
10237  $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
10238  $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
10239  $sql .= ' ' . $this->db->prefix() . 'facture as f';
10240  $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
10241  $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10242  //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10243  //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10244  //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10245  $sql .= " ORDER BY p.ref, f.ref ASC";
10246 
10247  $resql = $this->db->query($sql);
10248  if ($resql) {
10249  // Use select2 selector
10250  if (!empty($conf->use_javascript_ajax)) {
10251  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10252  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10253  $out .= $comboenhancement;
10254  $morecss = 'minwidth200imp maxwidth500';
10255  }
10256 
10257  if (empty($option_only)) {
10258  $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10259  }
10260  if (!empty($show_empty)) {
10261  $out .= '<option value="0" class="optiongrey">';
10262  if (!is_numeric($show_empty)) {
10263  $out .= $show_empty;
10264  } else {
10265  $out .= '&nbsp;';
10266  }
10267  $out .= '</option>';
10268  }
10269  $num = $this->db->num_rows($resql);
10270  $i = 0;
10271  if ($num) {
10272  while ($i < $num) {
10273  $obj = $this->db->fetch_object($resql);
10274  // If we ask to filter on a company and user has no permission to see all companies and project is linked to another company, we hide project.
10275  if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
10276  // Do nothing
10277  } else {
10278  if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10279  $i++;
10280  continue;
10281  }
10282 
10283  $labeltoshow = '';
10284 
10285  if ($showproject == 'all') {
10286  $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10287  if ($obj->name) {
10288  $labeltoshow .= ' - ' . $obj->name; // Soc name
10289  }
10290 
10291  $disabled = 0;
10292  if ($obj->fk_statut == Project::STATUS_DRAFT) {
10293  $disabled = 1;
10294  $labeltoshow .= ' - ' . $langs->trans("Draft");
10295  } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10296  if ($discard_closed == 2) {
10297  $disabled = 1;
10298  }
10299  $labeltoshow .= ' - ' . $langs->trans("Closed");
10300  } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10301  $disabled = 1;
10302  $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
10303  }
10304  }
10305 
10306  if (!empty($selected) && $selected == $obj->rowid) {
10307  $out .= '<option value="' . $obj->rowid . '" selected';
10308  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10309  $out .= '>' . $labeltoshow . '</option>';
10310  } else {
10311  if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10312  $resultat = '';
10313  } else {
10314  $resultat = '<option value="' . $obj->rowid . '"';
10315  if ($disabled) {
10316  $resultat .= ' disabled';
10317  }
10318  //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10319  //else $labeltoshow.=' ('.$langs->trans("Private").')';
10320  $resultat .= '>';
10321  $resultat .= $labeltoshow;
10322  $resultat .= '</option>';
10323  }
10324  $out .= $resultat;
10325  }
10326  }
10327  $i++;
10328  }
10329  }
10330  if (empty($option_only)) {
10331  $out .= '</select>';
10332  }
10333 
10334  $this->db->free($resql);
10335 
10336  return $out;
10337  } else {
10338  dol_print_error($this->db);
10339  return '';
10340  }
10341  }
10342 
10356  public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
10357  {
10358  global $user, $conf, $langs;
10359 
10360  $out = '';
10361 
10362  dol_syslog('FactureRec::fetch', LOG_DEBUG);
10363 
10364  $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10365  //$sql.= ', el.fk_source';
10366  $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10367  $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10368  $sql .= " ORDER BY f.titre ASC";
10369 
10370  $resql = $this->db->query($sql);
10371  if ($resql) {
10372  // Use select2 selector
10373  if (!empty($conf->use_javascript_ajax)) {
10374  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10375  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10376  $out .= $comboenhancement;
10377  $morecss = 'minwidth200imp maxwidth500';
10378  }
10379 
10380  if (empty($option_only)) {
10381  $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10382  }
10383  if (!empty($show_empty)) {
10384  $out .= '<option value="0" class="optiongrey">';
10385  if (!is_numeric($show_empty)) {
10386  $out .= $show_empty;
10387  } else {
10388  $out .= '&nbsp;';
10389  }
10390  $out .= '</option>';
10391  }
10392  $num = $this->db->num_rows($resql);
10393  if ($num) {
10394  while ($obj = $this->db->fetch_object($resql)) {
10395  $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10396 
10397  $disabled = 0;
10398  if (!empty($obj->suspended)) {
10399  $disabled = 1;
10400  $labeltoshow .= ' - ' . $langs->trans("Closed");
10401  }
10402 
10403 
10404  if (!empty($selected) && $selected == $obj->rowid) {
10405  $out .= '<option value="' . $obj->rowid . '" selected';
10406  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10407  $out .= '>' . $labeltoshow . '</option>';
10408  } else {
10409  if ($disabled && ($selected != $obj->rowid)) {
10410  $resultat = '';
10411  } else {
10412  $resultat = '<option value="' . $obj->rowid . '"';
10413  if ($disabled) {
10414  $resultat .= ' disabled';
10415  }
10416  $resultat .= '>';
10417  $resultat .= $labeltoshow;
10418  $resultat .= '</option>';
10419  }
10420  $out .= $resultat;
10421  }
10422  }
10423  }
10424  if (empty($option_only)) {
10425  $out .= '</select>';
10426  }
10427 
10428  print $out;
10429 
10430  $this->db->free($resql);
10431  return $num;
10432  } else {
10433  $this->errors[] = $this->db->lasterror;
10434  return -1;
10435  }
10436  }
10437 
10447  public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10448  {
10449  global $langs;
10450 
10451  if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10452  $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
10453  }
10454 
10455  $ret = '';
10456 
10457  $ret .= '<div class="divadvancedsearchfieldcomp inline-block">';
10458  $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10459  $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
10460  $ret .= '</a>';
10461 
10462  $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10463 
10464  // Show select fields as tags.
10465  $ret .= '<div name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10466 
10467  if ($search_component_params_hidden) {
10468  // Split the criteria on each AND
10469  //var_dump($search_component_params_hidden);
10470 
10471  $nbofchars = dol_strlen($search_component_params_hidden);
10472  $arrayofandtags = array();
10473  $i = 0; $s = '';
10474  $countparenthesis = 0;
10475  while ($i < $nbofchars) {
10476  $char = dol_substr($search_component_params_hidden, $i, 1);
10477 
10478  if ($char == '(') {
10479  $countparenthesis++;
10480  } elseif ($char == ')') {
10481  $countparenthesis--;
10482  }
10483 
10484  if ($countparenthesis == 0) {
10485  $char2 = dol_substr($search_component_params_hidden, $i+1, 1);
10486  $char3 = dol_substr($search_component_params_hidden, $i+2, 1);
10487  if ($char == 'A' && $char2 == 'N' && $char3 == 'D') {
10488  // We found a AND
10489  $arrayofandtags[] = trim($s);
10490  $s = '';
10491  $i+=2;
10492  } else {
10493  $s .= $char;
10494  }
10495  } else {
10496  $s .= $char;
10497  }
10498  $i++;
10499  }
10500  if ($s) {
10501  $arrayofandtags[] = trim($s);
10502  }
10503 
10504  // Show each AND part
10505  foreach ($arrayofandtags as $tmpkey => $tmpval) {
10506  $errormessage = '';
10507  $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
10508  if ($errormessage) {
10509  $this->error = 'ERROR in parsing search string: '.$errormessage;
10510  }
10511  // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
10512  include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
10513  $searchtags = removeGlobalParenthesis($searchtags);
10514 
10515  $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey+1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
10516  $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey+1).'">x</span> ';
10517  $ret .= dol_escape_htmltag($searchtags);
10518  $ret .= '</span>';
10519  }
10520  }
10521 
10522  //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10523 
10524  //$ret .= search_component_params
10525  //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10526  //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10527 
10528  $show_search_component_params_hidden = 1;
10529  if ($show_search_component_params_hidden) {
10530  $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10531  }
10532  $ret .= "<!-- We store the full Universal Search String into this field. For example: (t.ref:like:'SO-%') AND ((t.ref:like:'CO-%') OR (t.ref:like:'AA%')) -->";
10533  $ret .= '<input type="hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
10534  // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
10535 
10536  // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
10537  foreach ($arrayofcriterias as $criterias) {
10538  foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
10539  if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10540  continue;
10541  }
10542  if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10543  continue;
10544  }
10545  if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10546  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
10547  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
10548  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
10549  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
10550  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
10551  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
10552  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
10553  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
10554  } else {
10555  $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
10556  }
10557  }
10558  }
10559 
10560  $ret .= '</div>';
10561 
10562  $ret .= "<!-- Field to enter a generic filter string: t.ref:like:'SO-%', t.date_creation:<:'20160101', t.date_creation:<:'2016-01-01 12:30:00', t.nature:is:NULL, t.field2:isnot:NULL -->\n";
10563  $ret .= '<input type="text" placeholder="' . $langs->trans("Search") . '" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10564 
10565  $ret .= '</div>';
10566  $ret .= '</div>';
10567 
10568  $ret .= '<script>
10569  jQuery(".tagsearchdelete").click(function() {
10570  var filterid = $(this).parents().data("ufilterid");
10571  console.log("We click to delete a criteria nb "+filterid);
10572  // TODO Update the search_component_params_hidden with all data-ufilter except the one delete and post page
10573 
10574  });
10575  </script>
10576  ';
10577 
10578 
10579  return $ret;
10580  }
10581 
10591  public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
10592  {
10593  global $langs, $user;
10594 
10595  $retstring = '';
10596 
10597  $TModels = array();
10598 
10599  include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
10600  $formmail = new FormMail($this->db);
10601  $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
10602 
10603  if ($default) {
10604  $TModels[0] = $langs->trans('DefaultMailModel');
10605  }
10606  if ($result > 0) {
10607  foreach ($formmail->lines_model as $model) {
10608  $TModels[$model->id] = $model->label;
10609  }
10610  }
10611 
10612  $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
10613 
10614  foreach ($TModels as $id_model => $label_model) {
10615  $retstring .= '<option value="' . $id_model . '"';
10616  $retstring .= ">" . $label_model . "</option>";
10617  }
10618 
10619  $retstring .= "</select>";
10620 
10621  if ($addjscombo) {
10622  $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
10623  }
10624 
10625  return $retstring;
10626  }
10627 
10639  public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = 0, $morecss = '', $dol_openinpopup = '')
10640  {
10641  global $langs;
10642 
10643  $buttons = array();
10644 
10645  $save = array(
10646  'name' => 'save',
10647  'label_key' => $save_label,
10648  );
10649 
10650  if ($save_label == 'Create' || $save_label == 'Add') {
10651  $save['name'] = 'add';
10652  } elseif ($save_label == 'Modify') {
10653  $save['name'] = 'edit';
10654  }
10655 
10656  $cancel = array(
10657  'name' => 'cancel',
10658  'label_key' => 'Cancel',
10659  );
10660 
10661  !empty($save_label) ? $buttons[] = $save : '';
10662 
10663  if (!empty($morebuttons)) {
10664  $buttons[] = $morebuttons;
10665  }
10666 
10667  !empty($cancel_label) ? $buttons[] = $cancel : '';
10668 
10669  $retstring = $withoutdiv ? '' : '<div class="center">';
10670 
10671  foreach ($buttons as $button) {
10672  $addclass = empty($button['addclass']) ? '' : $button['addclass'];
10673  $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
10674  }
10675  $retstring .= $withoutdiv ? '' : '</div>';
10676 
10677  if ($dol_openinpopup) {
10678  $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . $dol_openinpopup . ' context, so we enable the close of dialog on cancel -->' . "\n";
10679  $retstring .= '<script nonce="' . getNonce() . '">';
10680  $retstring .= 'jQuery(".button-cancel").click(function(e) {
10681  e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . $dol_openinpopup . '\');
10682  window.parent.jQuery(\'#idfordialog' . $dol_openinpopup . '\').dialog(\'close\');
10683  });';
10684  $retstring .= '</script>';
10685  }
10686 
10687  return $retstring;
10688  }
10689 }
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition: ajax.lib.php:47
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:449
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition: ajax.lib.php:297
ajax_event($htmlname, $events)
Add event management script.
Definition: ajax.lib.php:550
Class to manage bank accounts.
Class to manage categories.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0)
selectModelMail
showFilterButtons($pos='')
Return HTML to show the search and clear seach button.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
load_cache_vatrates($country_code)
Load into the cache vat rates of a country.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_address($selected, $socid, $htmlname='address_id', $showempty=0)
Return list of delivery address.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
select_contacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $showsoc=0, $forcecombo=0, $events=array(), $options_only=false, $moreparam='', $htmlid='')
Return list of all contacts (for a third party or all)
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
selectcontacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=false, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0)
Return HTML code of the SELECT of list of all contacts (for a third party or all).
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear seach button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0')
Return the HTML select list of users.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_dolgroups($selected='', $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity='0', $multiple=false, $morecss='')
Return select list of groups.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto')
Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
form_users($page, $selected='', $htmlname='userid', $exclude='', $include='')
Show a select form to choose a user.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=0, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=false, $title='RelatedObjects')
Show linked object block.
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
print list of payment modes.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier='')
Return list of suppliers prices for a product.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array())
Show block with links to link to other objects.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $markafterid=0, $outputmode=0, $include=0, $morecss='')
Return list of categories having choosed type.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array())
Return select list of users.
form_confirm($page, $title, $question, $action, $formquestion='', $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_produits_list($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1)
Return list of products for a customer.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='')
Output the component to make advanced search criteries.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
select_produits($selected='', $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1)
Return list of products for customer in Ajax if Ajax activated or go to select_produits_list.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse='', $societe_acheteuse='', $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0)
Output an HTML select vat rate.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0, $disabled=0, $selected_input_value='')
Generic method to select a component from a combo list.
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday='', $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Class to manage building of HTML components.
Class to manage hooks.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php:48
currency_name($code_iso, $withcode='', $outputlangs=null)
Return label of currency or code+label.
getCountry($searchkey, $withcode='', $dbtouse=0, $outputlangs='', $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition: date.lib.php:83
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
$formconfirm
if ($action == 'delbookkeepingyear') {
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:89
table tableforfield button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
Definition: style.css.php:853
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:123
getMaxFileSizeArray()
Return the max allowed for file upload.
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...