dolibarr  16.0.5
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  *
25  * This program is free software; you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation; either version 3 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program. If not, see <https://www.gnu.org/licenses/>.
37  */
38 
52 class Form
53 {
57  public $db;
58 
62  public $error = '';
63 
67  public $errors = array();
68 
69  public $num;
70 
71  // Cache arrays
72  public $cache_types_paiements = array();
73  public $cache_conditions_paiements = array();
74  public $cache_transport_mode = array();
75  public $cache_availability = array();
76  public $cache_demand_reason = array();
77  public $cache_types_fees = array();
78  public $cache_vatrates = array();
79 
80 
86  public function __construct($db)
87  {
88  $this->db = $db;
89  }
90 
107  public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
108  {
109  global $conf, $langs;
110 
111  $ret = '';
112 
113  // TODO change for compatibility
114  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) {
115  if (!empty($perm)) {
116  $tmp = explode(':', $typeofdata);
117  $ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
118  if ($fieldrequired) {
119  $ret .= '<span class="fieldrequired">';
120  }
121  if ($help) {
122  $ret .= $this->textwithpicto($langs->trans($text), $help);
123  } else {
124  $ret .= $langs->trans($text);
125  }
126  if ($fieldrequired) {
127  $ret .= '</span>';
128  }
129  $ret .= '</div>'."\n";
130  } else {
131  if ($fieldrequired) {
132  $ret .= '<span class="fieldrequired">';
133  }
134  if ($help) {
135  $ret .= $this->textwithpicto($langs->trans($text), $help);
136  } else {
137  $ret .= $langs->trans($text);
138  }
139  if ($fieldrequired) {
140  $ret .= '</span>';
141  }
142  }
143  } else {
144  if (empty($notabletag) && $perm) {
145  $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
146  }
147  if ($fieldrequired) {
148  $ret .= '<span class="fieldrequired">';
149  }
150  if ($help) {
151  $ret .= $this->textwithpicto($langs->trans($text), $help);
152  } else {
153  $ret .= $langs->trans($text);
154  }
155  if ($fieldrequired) {
156  $ret .= '</span>';
157  }
158  if (!empty($notabletag)) {
159  $ret .= ' ';
160  }
161  if (empty($notabletag) && $perm) {
162  $ret .= '</td>';
163  }
164  if (empty($notabletag) && $perm) {
165  $ret .= '<td class="right">';
166  }
167  if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) {
168  $ret .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&token='.newToken().'&'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
169  }
170  if (!empty($notabletag) && $notabletag == 1) {
171  $ret .= ' : ';
172  }
173  if (!empty($notabletag) && $notabletag == 3) {
174  $ret .= ' ';
175  }
176  if (empty($notabletag) && $perm) {
177  $ret .= '</td>';
178  }
179  if (empty($notabletag) && $perm) {
180  $ret .= '</tr></table>';
181  }
182  }
183 
184  return $ret;
185  }
186 
206  public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id', $gm = 'auto')
207  {
208  global $conf, $langs;
209 
210  $ret = '';
211 
212  // Check parameters
213  if (empty($typeofdata)) {
214  return 'ErrorBadParameter';
215  }
216 
217  // When option to edit inline is activated
218  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
219  $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
220  } else {
221  $editmode = (GETPOST('action', 'aZ09') == 'edit'.$htmlname);
222  if ($editmode) {
223  $ret .= "\n";
224  $ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">';
225  $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
226  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
227  $ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
228  if (empty($notabletag)) {
229  $ret .= '<table class="nobordernopadding centpercent">';
230  }
231  if (empty($notabletag)) {
232  $ret .= '<tr><td>';
233  }
234  if (preg_match('/^(string|safehtmlstring|email)/', $typeofdata)) {
235  $tmp = explode(':', $typeofdata);
236  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.(empty($tmp[1]) ? '' : ' size="'.$tmp[1].'"').' autofocus>';
237  } elseif (preg_match('/^(integer)/', $typeofdata)) {
238  $tmp = explode(':', $typeofdata);
239  $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
240  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.$valuetoshow.'"'.(empty($tmp[1]) ? '' : ' size="'.$tmp[1].'"').' autofocus>';
241  } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
242  $tmp = explode(':', $typeofdata);
243  $valuetoshow = price2num($editvalue ? $editvalue : $value);
244  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ? price($valuetoshow) : '').'"'.(empty($tmp[1]) ? '' : ' size="'.$tmp[1].'"').' autofocus>';
245  } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
246  $tmp = explode(':', $typeofdata);
247  $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
248  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
249  $tmp = explode(':', $typeofdata);
250  $cols = (empty($tmp[2]) ? '' : $tmp[2]);
251  $morealt = '';
252  if (preg_match('/%/', $cols)) {
253  $morealt = ' style="width: '.$cols.'"';
254  $cols = '';
255  }
256 
257  $valuetoshow = ($editvalue ? $editvalue : $value);
258  $ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.(empty($tmp[1]) ? '20' : $tmp[1]).'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'" autofocus>';
259  // textarea convert automatically entities chars into simple chars.
260  // 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.
261  $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
262  $ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
263  $ret .= '</textarea>';
264  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
265  $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0, 0, '', '', '', '', 1, '', '', $gm);
266  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
267  $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0, 0, '', '', '', '', 1, '', '', $gm);
268  } elseif (preg_match('/^select;/', $typeofdata)) {
269  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
270  $arraylist = array();
271  foreach ($arraydata as $val) {
272  $tmp = explode(':', $val);
273  $tmpkey = str_replace('|', ':', $tmp[0]);
274  $arraylist[$tmpkey] = $tmp[1];
275  }
276  $ret .= $this->selectarray($htmlname, $arraylist, $value);
277  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
278  $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
279  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
280  $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]));
281  $ret .= $doleditor->Create(1);
282  }
283  if (empty($notabletag)) {
284  $ret .= '</td>';
285  }
286 
287  // Button save-cancel
288  if (empty($notabletag)) {
289  $ret .= '<td class="left">';
290  }
291  //else $ret.='<div class="clearboth"></div>';
292  $ret .= '<input type="submit" class="smallpaddingimp button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
293  if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
294  $ret .= '<br>'."\n";
295  }
296  $ret .= '<input type="submit" class="smallpaddingimp button button-cancel'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
297  if (empty($notabletag)) {
298  $ret .= '</td>';
299  }
300 
301  if (empty($notabletag)) {
302  $ret .= '</tr></table>'."\n";
303  }
304  $ret .= '</form>'."\n";
305  } else {
306  if (preg_match('/^(email)/', $typeofdata)) {
307  $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
308  } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
309  $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
310  } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
311  $tmp = explode(':', $typeofdata);
312  $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($tmp[1] ? $tmp[1] : '') . '/>';
313  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
314  $ret .= dol_htmlentitiesbr($value);
315  } elseif (preg_match('/^safehtmlstring/', $typeofdata)) {
316  $ret .= dol_string_onlythesehtmltags($value);
317  } elseif (preg_match('/^restricthtml/', $typeofdata)) {
318  $ret .= dol_string_onlythesehtmltags($value);
319  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
320  $ret .= '<span class="valuedate">'.dol_print_date($value, 'day', $gm).'</span>';
321  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
322  $ret .= '<span class="valuedate">'.dol_print_date($value, 'dayhour', $gm).'</span>';
323  } elseif (preg_match('/^select;/', $typeofdata)) {
324  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
325  $arraylist = array();
326  foreach ($arraydata as $val) {
327  $tmp = explode(':', $val);
328  $arraylist[$tmp[0]] = $tmp[1];
329  }
330  $ret .= $arraylist[$value];
331  if ($htmlname == 'fk_product_type') {
332  if ($value == 0) {
333  $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"').$ret;
334  } else {
335  $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"').$ret;
336  }
337  }
338  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
339  $tmpcontent = dol_htmlentitiesbr($value);
340  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
341  $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
342  $firstline = preg_replace('/[\n\r].*/', '', $firstline);
343  $tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
344  }
345  // We dont use dol_escape_htmltag to get the html formating active, but this need we must also
346  // clean data from some dangerous html
347  $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent));
348  } else {
349  $ret .= dol_escape_htmltag($value);
350  }
351 
352  if ($formatfunc && method_exists($object, $formatfunc)) {
353  $ret = $object->$formatfunc($ret);
354  }
355  }
356  }
357  return $ret;
358  }
359 
371  public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
372  {
373  global $conf, $langs, $extralanguages;
374 
375  $result = '';
376 
377  // List of extra languages
378  $arrayoflangcode = array();
379  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
380  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
381  }
382 
383  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
384  if (!is_object($extralanguages)) {
385  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
386  $extralanguages = new ExtraLanguages($this->db);
387  }
388  $extralanguages->fetch_name_extralanguages('societe');
389 
390  if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
391  return ''; // No extralang field to show
392  }
393 
394  $result .= '<!-- Widget for translation -->'."\n";
395  $result .= '<div class="inline-block paddingleft image-'.$object->element.'-'.$fieldname.'">';
396  $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
397  $result .= $s;
398  $result .= '</div>';
399 
400  $result .= '<div class="inline-block hidden field-'.$object->element.'-'.$fieldname.'">';
401 
402  $resultforextrlang = '';
403  foreach ($arrayoflangcode as $langcode) {
404  $valuetoshow = GETPOSTISSET('field-'.$object->element."-".$fieldname."-".$langcode) ? GETPOST('field-'.$object->element.'-'.$fieldname."-".$langcode, $check) : '';
405  if (empty($valuetoshow)) {
406  $object->fetchValuesForExtraLanguages();
407  //var_dump($object->array_languages);
408  $valuetoshow = $object->array_languages[$fieldname][$langcode];
409  }
410 
411  $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
412  $resultforextrlang .= $s;
413 
414  // TODO Use the showInputField() method of ExtraLanguages object
415  if ($typeofdata == 'textarea') {
416  $resultforextrlang .= '<textarea name="field-'.$object->element."-".$fieldname."-".$langcode.'" id="'.$fieldname."-".$langcode.'" class="'.$morecss.'" rows="'.ROWS_2.'" wrap="soft">';
417  $resultforextrlang .= $valuetoshow;
418  $resultforextrlang .= '</textarea>';
419  } else {
420  $resultforextrlang .= '<input type="text" class="inputfieldforlang '.($morecss ? ' '.$morecss : '').'" name="field-'.$object->element.'-'.$fieldname.'-'.$langcode.'" value="'.$valuetoshow.'">';
421  }
422  }
423  $result .= $resultforextrlang;
424 
425  $result .= '</div>';
426  $result .= '<script>$(".image-'.$object->element.'-'.$fieldname.'").click(function() { console.log("Toggle lang widget"); jQuery(".field-'.$object->element.'-'.$fieldname.'").toggle(); });</script>';
427  }
428 
429  return $result;
430  }
431 
445  protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
446  {
447  global $conf;
448 
449  $out = '';
450 
451  // Check parameters
452  if (preg_match('/^text/', $inputType)) {
453  $value = dol_nl2br($value);
454  } elseif (preg_match('/^numeric/', $inputType)) {
455  $value = price($value);
456  } elseif ($inputType == 'day' || $inputType == 'datepicker') {
457  $value = dol_print_date($value, 'day');
458  }
459 
460  if ($condition) {
461  $element = false;
462  $table_element = false;
463  $fk_element = false;
464  $loadmethod = false;
465  $savemethod = false;
466  $ext_element = false;
467  $button_only = false;
468  $inputOption = '';
469  $rows = '';
470  $cols = '';
471 
472  if (is_object($object)) {
473  $element = $object->element;
474  $table_element = $object->table_element;
475  $fk_element = $object->id;
476  }
477 
478  if (is_object($extObject)) {
479  $ext_element = $extObject->element;
480  }
481 
482  if (preg_match('/^(string|email|numeric)/', $inputType)) {
483  $tmp = explode(':', $inputType);
484  $inputType = $tmp[0];
485  if (!empty($tmp[1])) {
486  $inputOption = $tmp[1];
487  }
488  if (!empty($tmp[2])) {
489  $savemethod = $tmp[2];
490  }
491  $out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
492  } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
493  $tmp = explode(':', $inputType);
494  $inputType = $tmp[0];
495  if (!empty($tmp[1])) {
496  $inputOption = $tmp[1];
497  }
498  if (!empty($tmp[2])) {
499  $savemethod = $tmp[2];
500  }
501 
502  $out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
503  } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
504  $tmp = explode(':', $inputType);
505  $inputType = $tmp[0];
506  $loadmethod = $tmp[1];
507  if (!empty($tmp[2])) {
508  $savemethod = $tmp[2];
509  }
510  if (!empty($tmp[3])) {
511  $button_only = true;
512  }
513  } elseif (preg_match('/^textarea/', $inputType)) {
514  $tmp = explode(':', $inputType);
515  $inputType = $tmp[0];
516  $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
517  $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
518  } elseif (preg_match('/^ckeditor/', $inputType)) {
519  $tmp = explode(':', $inputType);
520  $inputType = $tmp[0];
521  $toolbar = $tmp[1];
522  if (!empty($tmp[2])) {
523  $width = $tmp[2];
524  }
525  if (!empty($tmp[3])) {
526  $heigth = $tmp[3];
527  }
528  if (!empty($tmp[4])) {
529  $savemethod = $tmp[4];
530  }
531 
532  if (!empty($conf->fckeditor->enabled)) {
533  $out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
534  } else {
535  $inputType = 'textarea';
536  }
537  }
538 
539  $out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
540  $out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
541  $out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
542  $out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
543  if (!empty($savemethod)) {
544  $out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
545  }
546  if (!empty($ext_element)) {
547  $out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
548  }
549  if (!empty($custommsg)) {
550  if (is_array($custommsg)) {
551  if (!empty($custommsg['success'])) {
552  $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
553  }
554  if (!empty($custommsg['error'])) {
555  $out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
556  }
557  } else {
558  $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
559  }
560  }
561  if ($inputType == 'textarea') {
562  $out .= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n";
563  $out .= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n";
564  }
565  $out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
566  $out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n";
567  } else {
568  $out = $value;
569  }
570 
571  return $out;
572  }
573 
592  public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
593  {
594  if ($incbefore) {
595  $text = $incbefore.$text;
596  }
597  if (!$htmltext) {
598  return $text;
599  }
600  $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
601 
602  $tag = 'td';
603  if ($notabs == 2) {
604  $tag = 'div';
605  }
606  if ($notabs == 3) {
607  $tag = 'span';
608  }
609  // Sanitize tooltip
610  $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
611 
612  $extrastyle = '';
613  if ($direction < 0) {
614  $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : '');
615  $extrastyle = 'padding: 0px; padding-left: 3px !important;';
616  }
617  if ($direction > 0) {
618  $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : '');
619  $extrastyle = 'padding: 0px; padding-right: 3px !important;';
620  }
621 
622  $classfortooltip = 'classfortooltip';
623 
624  $s = '';
625  $textfordialog = '';
626 
627  if ($tooltiptrigger == '') {
628  $htmltext = str_replace('"', '&quot;', $htmltext);
629  } else {
630  $classfortooltip = 'classfortooltiponclick';
631  $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
632  }
633  if ($tooltipon == 2 || $tooltipon == 3) {
634  $paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
635  if ($tooltiptrigger == '') {
636  $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
637  } else {
638  $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
639  }
640  } else {
641  $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
642  }
643  if ($tooltipon == 1 || $tooltipon == 3) {
644  $paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
645  if ($tooltiptrigger == '') {
646  $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
647  } else {
648  $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
649  }
650  } else {
651  $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
652  }
653  if (empty($notabs)) {
654  $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
655  } elseif ($notabs == 2) {
656  $s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">';
657  }
658  // Define value if value is before
659  if ($direction < 0) {
660  $s .= '<'.$tag.$paramfortooltipimg;
661  if ($tag == 'td') {
662  $s .= ' class=valigntop" width="14"';
663  }
664  $s .= '>'.$textfordialog.$img.'</'.$tag.'>';
665  }
666  // Use another method to help avoid having a space in value in order to use this value with jquery
667  // Define label
668  if ((string) $text != '') {
669  $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
670  }
671  // Define value if value is after
672  if ($direction > 0) {
673  $s .= '<'.$tag.$paramfortooltipimg;
674  if ($tag == 'td') {
675  $s .= ' class="valignmiddle" width="14"';
676  }
677  $s .= '>'.$textfordialog.$img.'</'.$tag.'>';
678  }
679  if (empty($notabs)) {
680  $s .= '</tr></table>';
681  } elseif ($notabs == 2) {
682  $s .= '</div>';
683  }
684 
685  return $s;
686  }
687 
702  public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
703  {
704  global $conf, $langs;
705 
706  $alt = '';
707  if ($tooltiptrigger) {
708  $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
709  }
710 
711  //For backwards compatibility
712  if ($type == '0') {
713  $type = 'info';
714  } elseif ($type == '1') {
715  $type = 'help';
716  }
717 
718  // If info or help with no javascript, show only text
719  if (empty($conf->use_javascript_ajax)) {
720  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
721  return $text;
722  } else {
723  $alt = $htmltext;
724  $htmltext = '';
725  }
726  }
727 
728  // If info or help with smartphone, show only text (tooltip hover can't works)
729  if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
730  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
731  return $text;
732  }
733  }
734  // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
735  //if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
736  //{
737  //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>';
738  //}
739 
740  $img = '';
741  if ($type == 'info') {
742  $img = img_help(0, $alt);
743  } elseif ($type == 'help') {
744  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
745  } elseif ($type == 'helpclickable') {
746  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
747  } elseif ($type == 'superadmin') {
748  $img = img_picto($alt, 'redstar');
749  } elseif ($type == 'admin') {
750  $img = img_picto($alt, 'star');
751  } elseif ($type == 'warning') {
752  $img = img_warning($alt);
753  } elseif ($type != 'none') {
754  $img = img_picto($alt, $type); // $type can be an image path
755  }
756 
757  return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
758  }
759 
770  public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
771  {
772  global $conf, $langs, $hookmanager;
773 
774 
775  $disabled = 0;
776  $ret = '<div class="centpercent center">';
777  $ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>';
778 
779  // 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.
780  $parameters = array();
781  $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
782  // check if there is a mass action
783  if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
784  return;
785  }
786  if (empty($reshook)) {
787  $ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
788  foreach ($arrayofaction as $code => $label) {
789  $ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
790  }
791  }
792  $ret .= $hookmanager->resPrint;
793 
794  $ret .= '</select>';
795 
796  if (empty($conf->dol_optimize_smallscreen)) {
797  $ret .= ajax_combobox('.'.$name.'select');
798  }
799 
800  // 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
801  $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.
802  $ret .= '<input type="submit" disabled name="confirmmassaction"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display: none"').' class="button smallpaddingimp'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
803  $ret .= '</div>';
804 
805  if (!empty($conf->use_javascript_ajax)) {
806  $ret .= '<!-- JS CODE TO ENABLE mass action select -->
807  <script>
808  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 */
809  {
810  atleastoneselected=0;
811  jQuery("."+cssclass).each(function( index ) {
812  /* console.log( index + ": " + $( this ).text() ); */
813  if ($(this).is(\':checked\')) atleastoneselected++;
814  });
815 
816  console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
817 
818  if (atleastoneselected || '.$alwaysvisible.')
819  {
820  jQuery("."+name).show();
821  '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').'
822  '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').'
823  }
824  else
825  {
826  jQuery("."+name).hide();
827  jQuery("."+name+"other").hide();
828  }
829  }
830 
831  jQuery(document).ready(function () {
832  initCheckForSelect(0, "' . $name.'", "'.$cssclass.'");
833  jQuery(".' . $cssclass.'").click(function() {
834  initCheckForSelect(1, "'.$name.'", "'.$cssclass.'");
835  });
836  jQuery(".' . $name.'select").change(function() {
837  var massaction = $( this ).val();
838  var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
839  if (massaction == "builddoc")
840  {
841  urlform = urlform + "#show_files";
842  }
843  $( this ).closest("form").attr("action", urlform);
844  console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform);
845  /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
846  if ($(this).val() != \'0\')
847  {
848  jQuery(".' . $name.'confirmed").prop(\'disabled\', false);
849  jQuery(".' . $name.'other").hide(); /* To disable if another div was open */
850  jQuery(".' . $name.'"+massaction).show();
851  }
852  else
853  {
854  jQuery(".' . $name.'confirmed").prop(\'disabled\', true);
855  jQuery(".' . $name.'other").hide(); /* To disable any div open */
856  }
857  });
858  });
859  </script>
860  ';
861  }
862 
863  return $ret;
864  }
865 
866  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
883  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)
884  {
885  // phpcs:enable
886  global $conf, $langs, $mysoc;
887 
888  $langs->load("dict");
889 
890  $out = '';
891  $countryArray = array();
892  $favorite = array();
893  $label = array();
894  $atleastonefavorite = 0;
895 
896  $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
897  $sql .= " FROM ".$this->db->prefix()."c_country";
898  $sql .= " WHERE active > 0";
899  //$sql.= " ORDER BY code ASC";
900 
901  dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
902  $resql = $this->db->query($sql);
903  if ($resql) {
904  $out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
905  $num = $this->db->num_rows($resql);
906  $i = 0;
907  if ($num) {
908  while ($i < $num) {
909  $obj = $this->db->fetch_object($resql);
910 
911  $countryArray[$i]['rowid'] = $obj->rowid;
912  $countryArray[$i]['code_iso'] = $obj->code_iso;
913  $countryArray[$i]['code_iso3'] = $obj->code_iso3;
914  $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 : ''));
915  $countryArray[$i]['favorite'] = $obj->favorite;
916  $countryArray[$i]['eec'] = $obj->eec;
917  $favorite[$i] = $obj->favorite;
918  $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
919  $i++;
920  }
921 
922  if (empty($disablefavorites)) {
923  $array1_sort_order = SORT_DESC;
924  $array2_sort_order = SORT_ASC;
925  array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
926  } else {
927  $countryArray = dol_sort_array($countryArray, 'label');
928  }
929 
930  if ($showempty) {
931  if (is_numeric($showempty)) {
932  $out .= '<option value="">&nbsp;</option>'."\n";
933  } else {
934  $out .= '<option value="">'.$langs->trans($showempty).'</option>'."\n";
935  }
936  }
937 
938  if ($addspecialentries) { // Add dedicated entries for groups of countries
939  //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
940  $out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
941  $out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
942  if ($mysoc->isInEEC()) {
943  $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
944  }
945  $out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
946  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
947  }
948 
949  foreach ($countryArray as $row) {
950  //if (empty($showempty) && empty($row['rowid'])) continue;
951  if (empty($row['rowid'])) {
952  continue;
953  }
954  if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
955  continue; // exclude some countries
956  }
957 
958  if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
959  $atleastonefavorite++;
960  }
961  if (empty($row['favorite']) && $atleastonefavorite) {
962  $atleastonefavorite = 0;
963  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
964  }
965 
966  $labeltoshow = '';
967  if ($row['label']) {
968  $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
969  } else {
970  $labeltoshow .= '&nbsp;';
971  }
972  if ($row['code_iso']) {
973  $labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>';
974  if (empty($hideflags)) {
975  $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
976  $labeltoshow = $tmpflag.' '.$labeltoshow;
977  }
978  }
979 
980  if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
981  $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']).'">';
982  } else {
983  $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']).'">';
984  }
985  $out .= $labeltoshow;
986  $out .= '</option>'."\n";
987  }
988  }
989  $out .= '</select>';
990  } else {
991  dol_print_error($this->db);
992  }
993 
994  // Make select dynamic
995  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
996  $out .= ajax_combobox('select'.$htmlname, array(), 0, 0, 'resolve');
997 
998  return $out;
999  }
1000 
1001  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1015  public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1016  {
1017  // phpcs:enable
1018  global $conf, $langs;
1019 
1020  $langs->load("dict");
1021 
1022  $out = '';
1023  $moreattrib = '';
1024  $incotermArray = array();
1025 
1026  $sql = "SELECT rowid, code";
1027  $sql .= " FROM ".$this->db->prefix()."c_incoterms";
1028  $sql .= " WHERE active > 0";
1029  $sql .= " ORDER BY code ASC";
1030 
1031  dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
1032  $resql = $this->db->query($sql);
1033  if ($resql) {
1034  if ($conf->use_javascript_ajax && !$forcecombo) {
1035  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1036  $out .= ajax_combobox($htmlname, $events);
1037  }
1038 
1039  if (!empty($page)) {
1040  $out .= '<form method="post" action="'.$page.'">';
1041  $out .= '<input type="hidden" name="action" value="set_incoterms">';
1042  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
1043  }
1044 
1045  $out .= '<select id="'.$htmlname.'" class="flat selectincoterm width75" name="'.$htmlname.'" '.$htmloption.'>';
1046  $out .= '<option value="0">&nbsp;</option>';
1047  $num = $this->db->num_rows($resql);
1048  $i = 0;
1049  if ($num) {
1050  while ($i < $num) {
1051  $obj = $this->db->fetch_object($resql);
1052  $incotermArray[$i]['rowid'] = $obj->rowid;
1053  $incotermArray[$i]['code'] = $obj->code;
1054  $i++;
1055  }
1056 
1057  foreach ($incotermArray as $row) {
1058  if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1059  $out .= '<option value="'.$row['rowid'].'" selected>';
1060  } else {
1061  $out .= '<option value="'.$row['rowid'].'">';
1062  }
1063 
1064  if ($row['code']) {
1065  $out .= $row['code'];
1066  }
1067 
1068  $out .= '</option>';
1069  }
1070  }
1071  $out .= '</select>';
1072 
1073  if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1074  $out .= ajax_multiautocompleter('location_incoterms', '', DOL_URL_ROOT.'/core/ajax/locationincoterms.php')."\n";
1075  $moreattrib .= ' autocomplete="off"';
1076  }
1077  $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="'.$location_incoterms.'">'."\n";
1078 
1079  if (!empty($page)) {
1080  $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="'.$langs->trans("Modify").'"></form>';
1081  }
1082  } else {
1083  dol_print_error($this->db);
1084  }
1085 
1086  return $out;
1087  }
1088 
1089  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1101  public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1102  {
1103  // phpcs:enable
1104  global $langs, $conf;
1105 
1106  // If product & services are enabled or both disabled.
1107  if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
1108  || (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled))) {
1109  if (empty($hidetext)) {
1110  print $langs->trans("Type").': ';
1111  }
1112  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
1113  if ($showempty) {
1114  print '<option value="-1"';
1115  if ($selected == -1) {
1116  print ' selected';
1117  }
1118  print '>&nbsp;</option>';
1119  }
1120 
1121  print '<option value="0"';
1122  if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1123  print ' selected';
1124  }
1125  print '>'.$langs->trans("Product");
1126 
1127  print '<option value="1"';
1128  if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1129  print ' selected';
1130  }
1131  print '>'.$langs->trans("Service");
1132 
1133  print '</select>';
1134  print ajax_combobox('select_'.$htmlname);
1135  //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1136  }
1137  if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3) {
1138  print $langs->trans("Service");
1139  print '<input type="hidden" name="'.$htmlname.'" value="1">';
1140  }
1141  if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2) {
1142  print $langs->trans("Product");
1143  print '<input type="hidden" name="'.$htmlname.'" value="0">';
1144  }
1145  if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1146  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
1147  }
1148  }
1149 
1150  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1156  public function load_cache_types_fees()
1157  {
1158  // phpcs:enable
1159  global $langs;
1160 
1161  $num = count($this->cache_types_fees);
1162  if ($num > 0) {
1163  return 0; // Cache already loaded
1164  }
1165 
1166  dol_syslog(__METHOD__, LOG_DEBUG);
1167 
1168  $langs->load("trips");
1169 
1170  $sql = "SELECT c.code, c.label";
1171  $sql .= " FROM ".$this->db->prefix()."c_type_fees as c";
1172  $sql .= " WHERE active > 0";
1173 
1174  $resql = $this->db->query($sql);
1175  if ($resql) {
1176  $num = $this->db->num_rows($resql);
1177  $i = 0;
1178 
1179  while ($i < $num) {
1180  $obj = $this->db->fetch_object($resql);
1181 
1182  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1183  $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1184  $this->cache_types_fees[$obj->code] = $label;
1185  $i++;
1186  }
1187 
1188  asort($this->cache_types_fees);
1189 
1190  return $num;
1191  } else {
1192  dol_print_error($this->db);
1193  return -1;
1194  }
1195  }
1196 
1197  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1206  public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1207  {
1208  // phpcs:enable
1209  global $user, $langs;
1210 
1211  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1212 
1213  $this->load_cache_types_fees();
1214 
1215  print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1216  if ($showempty) {
1217  print '<option value="-1"';
1218  if ($selected == -1) {
1219  print ' selected';
1220  }
1221  print '>&nbsp;</option>';
1222  }
1223 
1224  foreach ($this->cache_types_fees as $key => $value) {
1225  print '<option value="'.$key.'"';
1226  if ($key == $selected) {
1227  print ' selected';
1228  }
1229  print '>';
1230  print $value;
1231  print '</option>';
1232  }
1233 
1234  print '</select>';
1235  if ($user->admin) {
1236  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1237  }
1238  }
1239 
1240 
1241  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1263  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)
1264  {
1265  // phpcs:enable
1266  global $conf, $user, $langs;
1267 
1268  $out = '';
1269 
1270  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1271  if (is_null($ajaxoptions)) {
1272  $ajaxoptions = array();
1273  }
1274 
1275  require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1276 
1277  // No immediate load of all database
1278  $placeholder = '';
1279  if ($selected && empty($selected_input_value)) {
1280  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1281  $societetmp = new Societe($this->db);
1282  $societetmp->fetch($selected);
1283  $selected_input_value = $societetmp->name;
1284  unset($societetmp);
1285  }
1286 
1287  // mode 1
1288  $urloption = 'htmlname='.urlencode(str_replace('.', '_', $htmlname)).'&outjson=1&filter='.urlencode($filter).(empty($excludeids) ? '' : '&excludeids='.join(',', $excludeids)).($showtype ? '&showtype='.urlencode($showtype) : '').($showcode ? '&showcode='.urlencode($showcode) : '');
1289 
1290  $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
1291  if (empty($hidelabel)) {
1292  print $langs->trans("RefOrLabel").' : ';
1293  } elseif ($hidelabel > 1) {
1294  $placeholder = $langs->trans("RefOrLabel");
1295  if ($hidelabel == 2) {
1296  $out .= img_picto($langs->trans("Search"), 'search');
1297  }
1298  }
1299  $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' : '').' />';
1300  if ($hidelabel == 3) {
1301  $out .= img_picto($langs->trans("Search"), 'search');
1302  }
1303 
1304  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1305  } else {
1306  // Immediate load of all database
1307  $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1308  }
1309 
1310  return $out;
1311  }
1312 
1313  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1335  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)
1336  {
1337  // phpcs:enable
1338  global $conf, $user, $langs;
1339  global $hookmanager;
1340 
1341  $out = '';
1342  $num = 0;
1343  $outarray = array();
1344 
1345  if ($selected === '') {
1346  $selected = array();
1347  } elseif (!is_array($selected)) {
1348  $selected = array($selected);
1349  }
1350 
1351  // Clean $filter that may contains sql conditions so sql code
1352  if (function_exists('testSqlAndScriptInject')) {
1353  if (testSqlAndScriptInject($filter, 3) > 0) {
1354  $filter = '';
1355  }
1356  }
1357 
1358  // We search companies
1359  $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1360  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1361  $sql .= ", s.address, s.zip, s.town";
1362  $sql .= ", dictp.code as country_code";
1363  }
1364  $sql .= " FROM ".$this->db->prefix()."societe as s";
1365  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1366  $sql .= " LEFT JOIN ".$this->db->prefix()."c_country as dictp ON dictp.rowid = s.fk_pays";
1367  }
1368  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1369  $sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
1370  }
1371  $sql .= " WHERE s.entity IN (".getEntity('societe').")";
1372  if (!empty($user->socid)) {
1373  $sql .= " AND s.rowid = ".((int) $user->socid);
1374  }
1375  if ($filter) {
1376  $sql .= " AND (".$filter.")";
1377  }
1378  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1379  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
1380  }
1381  if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1382  $sql .= " AND s.status <> 0";
1383  }
1384  if (!empty($excludeids)) {
1385  $sql .= " AND s.rowid NOT IN (".$this->db->sanitize(join(',', $excludeids)).")";
1386  }
1387  // Add where from hooks
1388  $parameters = array();
1389  $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1390  $sql .= $hookmanager->resPrint;
1391  // Add criteria
1392  if ($filterkey && $filterkey != '') {
1393  $sql .= " AND (";
1394  $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1395  // For natural search
1396  $scrit = explode(' ', $filterkey);
1397  $i = 0;
1398  if (count($scrit) > 1) {
1399  $sql .= "(";
1400  }
1401  foreach ($scrit as $crit) {
1402  if ($i > 0) {
1403  $sql .= " AND ";
1404  }
1405  $sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1406  $i++;
1407  }
1408  if (count($scrit) > 1) {
1409  $sql .= ")";
1410  }
1411  if (!empty($conf->barcode->enabled)) {
1412  $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1413  }
1414  $sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1415  $sql .= " OR s.name_alias LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.tva_intra LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1416  $sql .= ")";
1417  }
1418  $sql .= $this->db->order("nom", "ASC");
1419  $sql .= $this->db->plimit($limit, 0);
1420 
1421  // Build output string
1422  dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1423  $resql = $this->db->query($sql);
1424  if ($resql) {
1425  if (!$forcecombo) {
1426  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1427  $out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1428  }
1429 
1430  // Construct $out and $outarray
1431  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1432 
1433  $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1434  if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1435  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1436  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1437  if ($showempty && !is_numeric($showempty)) {
1438  $textifempty = $langs->trans($showempty);
1439  } else {
1440  $textifempty .= $langs->trans("All");
1441  }
1442  }
1443  if ($showempty) {
1444  $out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.($textifempty ? $textifempty : '&nbsp;').'</span>').'">'.$textifempty.'</option>'."\n";
1445  }
1446 
1447  $companytemp = new Societe($this->db);
1448 
1449  $num = $this->db->num_rows($resql);
1450  $i = 0;
1451  if ($num) {
1452  while ($i < $num) {
1453  $obj = $this->db->fetch_object($resql);
1454  $label = '';
1455  if ($showcode || !empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) {
1456  if (($obj->client) && (!empty($obj->code_client))) {
1457  $label = $obj->code_client.' - ';
1458  }
1459  if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1460  $label .= $obj->code_fournisseur.' - ';
1461  }
1462  $label .= ' '.$obj->name;
1463  } else {
1464  $label = $obj->name;
1465  }
1466 
1467  if (!empty($obj->name_alias)) {
1468  $label .= ' ('.$obj->name_alias.')';
1469  }
1470 
1471  if (!empty($conf->global->SOCIETE_SHOW_VAT_IN_LIST) && !empty($obj->tva_intra)) {
1472  $label .= ' - '.$obj->tva_intra.'';
1473  }
1474 
1475  $labelhtml = $label;
1476 
1477  if ($showtype) {
1478  $companytemp->id = $obj->rowid;
1479  $companytemp->client = $obj->client;
1480  $companytemp->fournisseur = $obj->fournisseur;
1481  $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1482  if ($tmptype) {
1483  $labelhtml .= ' '.$tmptype;
1484  }
1485 
1486  if ($obj->client || $obj->fournisseur) {
1487  $label .= ' (';
1488  }
1489  if ($obj->client == 1 || $obj->client == 3) {
1490  $label .= $langs->trans("Customer");
1491  }
1492  if ($obj->client == 2 || $obj->client == 3) {
1493  $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1494  }
1495  if ($obj->fournisseur) {
1496  $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1497  }
1498  if ($obj->client || $obj->fournisseur) {
1499  $label .= ')';
1500  }
1501  }
1502 
1503  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1504  $s = ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : '');
1505  if (!empty($obj->country_code)) {
1506  $s .= ', '.$langs->trans('Country'.$obj->country_code);
1507  }
1508  $label .= $s;
1509  $labelhtml .= $s;
1510  }
1511 
1512  if (empty($outputmode)) {
1513  if (in_array($obj->rowid, $selected)) {
1514  $out .= '<option value="'.$obj->rowid.'" selected data-html="'.dol_escape_htmltag($labelhtml).'">'.$label.'</option>';
1515  } else {
1516  $out .= '<option value="'.$obj->rowid.'" data-html="'.dol_escape_htmltag($labelhtml).'">'.$label.'</option>';
1517  }
1518  } else {
1519  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label, 'labelhtml'=>$labelhtml));
1520  }
1521 
1522  $i++;
1523  if (($i % 10) == 0) {
1524  $out .= "\n";
1525  }
1526  }
1527  }
1528  $out .= '</select>'."\n";
1529  } else {
1530  dol_print_error($this->db);
1531  }
1532 
1533  $this->result = array('nbofthirdparties'=>$num);
1534 
1535  if ($outputmode) {
1536  return $outarray;
1537  }
1538  return $out;
1539  }
1540 
1541 
1542  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1553  public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1554  {
1555  // phpcs:enable
1556  global $langs, $conf;
1557 
1558  // On recherche les remises
1559  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1560  $sql .= " re.description, re.fk_facture_source";
1561  $sql .= " FROM ".$this->db->prefix()."societe_remise_except as re";
1562  $sql .= " WHERE re.fk_soc = ".(int) $socid;
1563  $sql .= " AND re.entity = ".$conf->entity;
1564  if ($filter) {
1565  $sql .= " AND ".$filter;
1566  }
1567  $sql .= " ORDER BY re.description ASC";
1568 
1569  dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1570  $resql = $this->db->query($sql);
1571  if ($resql) {
1572  print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1573  $num = $this->db->num_rows($resql);
1574 
1575  $qualifiedlines = $num;
1576 
1577  $i = 0;
1578  if ($num) {
1579  print '<option value="0">&nbsp;</option>';
1580  while ($i < $num) {
1581  $obj = $this->db->fetch_object($resql);
1582  $desc = dol_trunc($obj->description, 40);
1583  if (preg_match('/\(CREDIT_NOTE\)/', $desc)) {
1584  $desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1585  }
1586  if (preg_match('/\(DEPOSIT\)/', $desc)) {
1587  $desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1588  }
1589  if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) {
1590  $desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1591  }
1592  if (preg_match('/\(EXCESS PAID\)/', $desc)) {
1593  $desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1594  }
1595 
1596  $selectstring = '';
1597  if ($selected > 0 && $selected == $obj->rowid) {
1598  $selectstring = ' selected';
1599  }
1600 
1601  $disabled = '';
1602  if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1603  $qualifiedlines--;
1604  $disabled = ' disabled';
1605  }
1606 
1607  if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1608  $tmpfac = new Facture($this->db);
1609  if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1610  $desc = $desc.' - '.$tmpfac->ref;
1611  }
1612  }
1613 
1614  print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1615  $i++;
1616  }
1617  }
1618  print '</select>';
1619  print ajax_combobox('select_'.$htmlname);
1620 
1621  return $qualifiedlines;
1622  } else {
1623  dol_print_error($this->db);
1624  return -1;
1625  }
1626  }
1627 
1628  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1649  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 = '')
1650  {
1651  // phpcs:enable
1652  print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1653  return $this->num;
1654  }
1655 
1680  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)
1681  {
1682  global $conf, $langs, $hookmanager, $action;
1683 
1684  $langs->load('companies');
1685 
1686  if (empty($htmlid)) {
1687  $htmlid = $htmlname;
1688  }
1689  $num = 0;
1690 
1691  if ($selected === '') {
1692  $selected = array();
1693  } elseif (!is_array($selected)) {
1694  $selected = array($selected);
1695  }
1696  $out = '';
1697 
1698  if (!is_object($hookmanager)) {
1699  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1700  $hookmanager = new HookManager($this->db);
1701  }
1702 
1703  // We search third parties
1704  $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";
1705  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1706  $sql .= ", s.nom as company, s.town AS company_town";
1707  }
1708  $sql .= " FROM ".$this->db->prefix()."socpeople as sp";
1709  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1710  $sql .= " LEFT OUTER JOIN ".$this->db->prefix()."societe as s ON s.rowid=sp.fk_soc";
1711  }
1712  $sql .= " WHERE sp.entity IN (".getEntity('contact').")";
1713  if ($socid > 0 || $socid == -1) {
1714  $sql .= " AND sp.fk_soc = ".((int) $socid);
1715  }
1716  if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1717  $sql .= " AND sp.statut <> 0";
1718  }
1719  // Add where from hooks
1720  $parameters = array();
1721  $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1722  $sql .= $hookmanager->resPrint;
1723  $sql .= " ORDER BY sp.lastname ASC";
1724 
1725  dol_syslog(get_class($this)."::selectcontacts", LOG_DEBUG);
1726  $resql = $this->db->query($sql);
1727  if ($resql) {
1728  $num = $this->db->num_rows($resql);
1729 
1730  if ($htmlname != 'none' && !$options_only) {
1731  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1732  }
1733 
1734  if ($showempty && ! is_numeric($showempty)) {
1735  $textforempty = $showempty;
1736  $out .= '<option class="optiongrey" value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>'.$textforempty.'</option>';
1737  } else {
1738  if (($showempty == 1 || ($showempty == 3 && $num > 1)) && ! $multiple) {
1739  $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1740  }
1741  if ($showempty == 2) {
1742  $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1743  }
1744  }
1745 
1746  $i = 0;
1747  if ($num) {
1748  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1749  $contactstatic = new Contact($this->db);
1750 
1751  while ($i < $num) {
1752  $obj = $this->db->fetch_object($resql);
1753 
1754  // Set email (or phones) and town extended infos
1755  $extendedInfos = '';
1756  if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1757  $extendedInfos = array();
1758  $email = trim($obj->email);
1759  if (!empty($email)) {
1760  $extendedInfos[] = $email;
1761  } else {
1762  $phone = trim($obj->phone);
1763  $phone_perso = trim($obj->phone_perso);
1764  $phone_mobile = trim($obj->phone_mobile);
1765  if (!empty($phone)) {
1766  $extendedInfos[] = $phone;
1767  }
1768  if (!empty($phone_perso)) {
1769  $extendedInfos[] = $phone_perso;
1770  }
1771  if (!empty($phone_mobile)) {
1772  $extendedInfos[] = $phone_mobile;
1773  }
1774  }
1775  $contact_town = trim($obj->contact_town);
1776  $company_town = trim($obj->company_town);
1777  if (!empty($contact_town)) {
1778  $extendedInfos[] = $contact_town;
1779  } elseif (!empty($company_town)) {
1780  $extendedInfos[] = $company_town;
1781  }
1782  $extendedInfos = implode(' - ', $extendedInfos);
1783  if (!empty($extendedInfos)) {
1784  $extendedInfos = ' - '.$extendedInfos;
1785  }
1786  }
1787 
1788  $contactstatic->id = $obj->rowid;
1789  $contactstatic->lastname = $obj->lastname;
1790  $contactstatic->firstname = $obj->firstname;
1791  if ($obj->statut == 1) {
1792  if ($htmlname != 'none') {
1793  $disabled = 0;
1794  if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1795  $disabled = 1;
1796  }
1797  if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1798  $disabled = 1;
1799  }
1800  if (!empty($selected) && in_array($obj->rowid, $selected)) {
1801  $out .= '<option value="'.$obj->rowid.'"';
1802  if ($disabled) {
1803  $out .= ' disabled';
1804  }
1805  $out .= ' selected>';
1806  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1807  if ($showfunction && $obj->poste) {
1808  $out .= ' ('.$obj->poste.')';
1809  }
1810  if (($showsoc > 0) && $obj->company) {
1811  $out .= ' - ('.$obj->company.')';
1812  }
1813  $out .= '</option>';
1814  } else {
1815  $out .= '<option value="'.$obj->rowid.'"';
1816  if ($disabled) {
1817  $out .= ' disabled';
1818  }
1819  $out .= '>';
1820  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1821  if ($showfunction && $obj->poste) {
1822  $out .= ' ('.$obj->poste.')';
1823  }
1824  if (($showsoc > 0) && $obj->company) {
1825  $out .= ' - ('.$obj->company.')';
1826  }
1827  $out .= '</option>';
1828  }
1829  } else {
1830  if (in_array($obj->rowid, $selected)) {
1831  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1832  if ($showfunction && $obj->poste) {
1833  $out .= ' ('.$obj->poste.')';
1834  }
1835  if (($showsoc > 0) && $obj->company) {
1836  $out .= ' - ('.$obj->company.')';
1837  }
1838  }
1839  }
1840  }
1841  $i++;
1842  }
1843  } else {
1844  $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1845  $out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">';
1846  $out .= $labeltoshow;
1847  $out .= '</option>';
1848  }
1849 
1850  $parameters = array(
1851  'socid'=>$socid,
1852  'htmlname'=>$htmlname,
1853  'resql'=>$resql,
1854  'out'=>&$out,
1855  'showfunction'=>$showfunction,
1856  'showsoc'=>$showsoc,
1857  );
1858 
1859  $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1860 
1861  if ($htmlname != 'none' && !$options_only) {
1862  $out .= '</select>';
1863  }
1864 
1865  if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1866  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1867  $out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1868  }
1869 
1870  $this->num = $num;
1871  return $out;
1872  } else {
1873  dol_print_error($this->db);
1874  return -1;
1875  }
1876  }
1877 
1878  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1894  public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1895  {
1896  // phpcs:enable
1897  print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1898  }
1899 
1900  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1925  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 = '', $noactive = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
1926  {
1927  // phpcs:enable
1928  global $conf, $user, $langs, $hookmanager;
1929  global $action;
1930 
1931  // If no preselected user defined, we take current user
1932  if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
1933  $selected = $user->id;
1934  }
1935 
1936  if ($selected === '') {
1937  $selected = array();
1938  } elseif (!is_array($selected)) {
1939  $selected = array($selected);
1940  }
1941 
1942  $excludeUsers = null;
1943  $includeUsers = null;
1944 
1945  // Permettre l'exclusion d'utilisateurs
1946  if (is_array($exclude)) {
1947  $excludeUsers = implode(",", $exclude);
1948  }
1949  // Permettre l'inclusion d'utilisateurs
1950  if (is_array($include)) {
1951  $includeUsers = implode(",", $include);
1952  } elseif ($include == 'hierarchy') {
1953  // Build list includeUsers to have only hierarchy
1954  $includeUsers = implode(",", $user->getAllChildIds(0));
1955  } elseif ($include == 'hierarchyme') {
1956  // Build list includeUsers to have only hierarchy and current user
1957  $includeUsers = implode(",", $user->getAllChildIds(1));
1958  }
1959 
1960  $out = '';
1961  $outarray = array();
1962 
1963  // Forge request to select users
1964  $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
1965  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
1966  $sql .= ", e.label";
1967  }
1968  $sql .= " FROM ".$this->db->prefix()."user as u";
1969  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
1970  $sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid = u.entity";
1971  if ($force_entity) {
1972  $sql .= " WHERE u.entity IN (0, ".$this->db->sanitize($force_entity).")";
1973  } else {
1974  $sql .= " WHERE u.entity IS NOT NULL";
1975  }
1976  } else {
1977  if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1978  $sql .= " LEFT JOIN ".$this->db->prefix()."usergroup_user as ug";
1979  $sql .= " ON ug.fk_user = u.rowid";
1980  $sql .= " WHERE ug.entity = ".$conf->entity;
1981  } else {
1982  $sql .= " WHERE u.entity IN (0, ".$conf->entity.")";
1983  }
1984  }
1985  if (!empty($user->socid)) {
1986  $sql .= " AND u.fk_soc = ".((int) $user->socid);
1987  }
1988  if (is_array($exclude) && $excludeUsers) {
1989  $sql .= " AND u.rowid NOT IN (".$this->db->sanitize($excludeUsers).")";
1990  }
1991  if ($includeUsers) {
1992  $sql .= " AND u.rowid IN (".$this->db->sanitize($includeUsers).")";
1993  }
1994  if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) {
1995  $sql .= " AND u.statut <> 0";
1996  }
1997  if (!empty($morefilter)) {
1998  $sql .= " ".$morefilter;
1999  }
2000 
2001  //Add hook to filter on user (for exemple on usergroup define in custom modules)
2002  $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2003  if (!empty($reshook)) {
2004  $sql .= $hookmanager->resPrint;
2005  }
2006 
2007  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2008  $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2009  } else {
2010  $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2011  }
2012 
2013  dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
2014 
2015  $resql = $this->db->query($sql);
2016  if ($resql) {
2017  $num = $this->db->num_rows($resql);
2018  $i = 0;
2019  if ($num) {
2020  // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2021  $out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
2022  if ($show_empty && !$multiple) {
2023  $textforempty = ' ';
2024  if (!empty($conf->use_javascript_ajax)) {
2025  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2026  }
2027  if (!is_numeric($show_empty)) {
2028  $textforempty = $show_empty;
2029  }
2030  $out .= '<option class="optiongrey" value="'.($show_empty < 0 ? $show_empty : -1).'"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
2031  }
2032  if ($show_every) {
2033  $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
2034  }
2035 
2036  $userstatic = new User($this->db);
2037 
2038  while ($i < $num) {
2039  $obj = $this->db->fetch_object($resql);
2040 
2041  $userstatic->id = $obj->rowid;
2042  $userstatic->lastname = $obj->lastname;
2043  $userstatic->firstname = $obj->firstname;
2044  $userstatic->photo = $obj->photo;
2045  $userstatic->statut = $obj->status;
2046  $userstatic->entity = $obj->entity;
2047  $userstatic->admin = $obj->admin;
2048 
2049  $disableline = '';
2050  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2051  $disableline = ($enableonlytext ? $enableonlytext : '1');
2052  }
2053 
2054  $labeltoshow = '';
2055 
2056  // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2057  $fullNameMode = 0;
2058  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2059  $fullNameMode = 1; //Firstname+lastname
2060  }
2061  $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2062  if (empty($obj->firstname) && empty($obj->lastname)) {
2063  $labeltoshow .= $obj->login;
2064  }
2065 
2066  // Complete name with more info
2067  $moreinfo = '';
2068  if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2069  $moreinfo .= ($moreinfo ? ' - ' : ' (').$obj->login;
2070  }
2071  if ($showstatus >= 0) {
2072  if ($obj->status == 1 && $showstatus == 1) {
2073  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
2074  }
2075  if ($obj->status == 0 && $showstatus == 1) {
2076  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
2077  }
2078  }
2079  if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2080  if (!$obj->entity) {
2081  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
2082  } else {
2083  if ($obj->entity != $conf->entity) {
2084  $moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2085  }
2086  }
2087  }
2088  $moreinfo .= ($moreinfo ? ')' : '');
2089  if ($disableline && $disableline != '1') {
2090  $moreinfo .= ' - '.$disableline; // This is text from $enableonlytext parameter
2091  }
2092  $labeltoshow .= $moreinfo;
2093 
2094  $out .= '<option value="'.$obj->rowid.'"';
2095  if ($disableline) {
2096  $out .= ' disabled';
2097  }
2098  if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2099  $out .= ' selected';
2100  }
2101  $out .= ' data-html="';
2102  $outhtml = '';
2103  // if (!empty($obj->photo)) {
2104  $outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
2105  // }
2106  if ($showstatus >= 0 && $obj->status == 0) {
2107  $outhtml .= '<strike class="opacitymediumxxx">';
2108  }
2109  $outhtml .= $labeltoshow;
2110  if ($showstatus >= 0 && $obj->status == 0) {
2111  $outhtml .= '</strike>';
2112  }
2113  $out .= dol_escape_htmltag($outhtml);
2114  $out .= '">';
2115  $out .= $labeltoshow;
2116  $out .= '</option>';
2117 
2118  $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
2119 
2120  $i++;
2121  }
2122  } else {
2123  $out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
2124  $out .= '<option value="">'.$langs->trans("None").'</option>';
2125  }
2126  $out .= '</select>';
2127 
2128  if ($num && !$forcecombo) {
2129  // Enhance with select2
2130  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2131  $out .= ajax_combobox($htmlname);
2132  }
2133  } else {
2134  dol_print_error($this->db);
2135  }
2136 
2137  if ($outputmode) {
2138  return $outarray;
2139  }
2140 
2141  return $out;
2142  }
2143 
2144 
2145  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2168  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())
2169  {
2170  // phpcs:enable
2171  global $conf, $user, $langs;
2172 
2173  $userstatic = new User($this->db);
2174  $out = '';
2175 
2176 
2177  $assignedtouser = array();
2178  if (!empty($_SESSION['assignedtouser'])) {
2179  $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2180  }
2181  $nbassignetouser = count($assignedtouser);
2182 
2183  //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2184  if ($nbassignetouser) {
2185  $out .= '<ul class="attendees">';
2186  }
2187  $i = 0;
2188  $ownerid = 0;
2189  foreach ($assignedtouser as $key => $value) {
2190  if ($value['id'] == $ownerid) {
2191  continue;
2192  }
2193 
2194  $out .= '<li>';
2195  $userstatic->fetch($value['id']);
2196  $out .= $userstatic->getNomUrl(-1);
2197  if ($i == 0) {
2198  $ownerid = $value['id'];
2199  $out .= ' ('.$langs->trans("Owner").')';
2200  }
2201  if ($nbassignetouser > 1 && $action != 'view') {
2202  $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.'">';
2203  }
2204  // Show my availability
2205  if ($showproperties) {
2206  if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2207  $out .= '<div class="myavailability inline-block">';
2208  $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>';
2209  $out .= '</div>';
2210  }
2211  }
2212  //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2213  //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2214 
2215  $out .= '</li>';
2216  $i++;
2217  }
2218  if ($nbassignetouser) {
2219  $out .= '</ul>';
2220  }
2221 
2222  // Method with no ajax
2223  if ($action != 'view') {
2224  $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2225  $out .= '<script type="text/javascript">jQuery(document).ready(function () {';
2226  $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2227  $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2228  $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }';
2229  $out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }';
2230  $out .= '});';
2231  $out .= '})</script>';
2232  $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2233  $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
2234  $out .= '<br>';
2235  }
2236 
2237  return $out;
2238  }
2239 
2240 
2241  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2269  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)
2270  {
2271  // phpcs:enable
2272  global $langs, $conf;
2273 
2274  $out = '';
2275 
2276  // check parameters
2277  $price_level = (!empty($price_level) ? $price_level : 0);
2278  if (is_null($ajaxoptions)) {
2279  $ajaxoptions = array();
2280  }
2281 
2282  if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
2283  if (!empty($conf->product->enabled) && empty($conf->service->enabled)) {
2284  $filtertype = '0';
2285  } elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) {
2286  $filtertype = '1';
2287  }
2288  }
2289 
2290  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2291  $placeholder = '';
2292 
2293  if ($selected && empty($selected_input_value)) {
2294  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2295  $producttmpselect = new Product($this->db);
2296  $producttmpselect->fetch($selected);
2297  $selected_input_value = $producttmpselect->ref;
2298  unset($producttmpselect);
2299  }
2300  // handle case where product or service module is disabled + no filter specified
2301  if ($filtertype == '') {
2302  if (empty($conf->product->enabled)) { // when product module is disabled, show services only
2303  $filtertype = 1;
2304  } elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2305  $filtertype = 0;
2306  }
2307  }
2308  // mode=1 means customers products
2309  $urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&status_purchase='.$status_purchase.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
2310  //Price by customer
2311  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2312  $urloption .= '&socid='.$socid;
2313  }
2314  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2315 
2316  if (!empty($conf->variants->enabled) && is_array($selected_combinations)) {
2317  // Code to automatically insert with javascript the select of attributes under the select of product
2318  // when a parent of variant has been selected.
2319  $out .= '
2320  <!-- script to auto show attributes select tags if a variant was selected -->
2321  <script>
2322  // auto show attributes fields
2323  selected = '.json_encode($selected_combinations).';
2324  combvalues = {};
2325 
2326  jQuery(document).ready(function () {
2327 
2328  jQuery("input[name=\'prod_entry_mode\']").change(function () {
2329  if (jQuery(this).val() == \'free\') {
2330  jQuery(\'div#attributes_box\').empty();
2331  }
2332  });
2333 
2334  jQuery("input#'.$htmlname.'").change(function () {
2335 
2336  if (!jQuery(this).val()) {
2337  jQuery(\'div#attributes_box\').empty();
2338  return;
2339  }
2340 
2341  console.log("A change has started. We get variants fields to inject html select");
2342 
2343  jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
2344  id: jQuery(this).val()
2345  }, function (data) {
2346  jQuery(\'div#attributes_box\').empty();
2347 
2348  jQuery.each(data, function (key, val) {
2349 
2350  combvalues[val.id] = val.values;
2351 
2352  var span = jQuery(document.createElement(\'div\')).css({
2353  \'display\': \'table-row\'
2354  });
2355 
2356  span.append(
2357  jQuery(document.createElement(\'div\')).text(val.label).css({
2358  \'font-weight\': \'bold\',
2359  \'display\': \'table-cell\'
2360  })
2361  );
2362 
2363  var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2364  \'margin-left\': \'15px\',
2365  \'white-space\': \'pre\'
2366  }).append(
2367  jQuery(document.createElement(\'option\')).val(\'\')
2368  );
2369 
2370  jQuery.each(combvalues[val.id], function (key, val) {
2371  var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2372 
2373  if (selected[val.fk_product_attribute] == val.id) {
2374  tag.attr(\'selected\', \'selected\');
2375  }
2376 
2377  html.append(tag);
2378  });
2379 
2380  span.append(html);
2381  jQuery(\'div#attributes_box\').append(span);
2382  });
2383  })
2384  });
2385 
2386  '.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2387  });
2388  </script>
2389  ';
2390  }
2391 
2392  if (empty($hidelabel)) {
2393  $out .= $langs->trans("RefOrLabel").' : ';
2394  } elseif ($hidelabel > 1) {
2395  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2396  if ($hidelabel == 2) {
2397  $out .= img_picto($langs->trans("Search"), 'search');
2398  }
2399  }
2400  $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' : '').' />';
2401  if ($hidelabel == 3) {
2402  $out .= img_picto($langs->trans("Search"), 'search');
2403  }
2404  } else {
2405  $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2406  }
2407 
2408  if (empty($nooutput)) {
2409  print $out;
2410  } else {
2411  return $out;
2412  }
2413  }
2414 
2415  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2416 
2432  public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2433  {
2434  // phpcs:enable
2435  global $conf, $user, $langs, $db;
2436 
2437  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2438 
2439  $error = 0;
2440  $out = '';
2441 
2442  if (!$forcecombo) {
2443  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2444  $events = array();
2445  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2446  }
2447 
2448  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2449 
2450  $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2451  $sql.= ' FROM '.MAIN_DB_PREFIX.'bom_bom as b';
2452  $sql.= ' WHERE b.entity IN ('.getEntity('bom').')';
2453  if (!empty($status)) $sql.= ' AND status = '. (int) $status;
2454  if (!empty($type)) $sql.= ' AND bomtype = '. (int) $type;
2455  if (!empty($TProducts)) $sql .= ' AND fk_product IN ('.$this->db->sanitize(implode(',', $TProducts)).')';
2456  if (!empty($limit)) $sql.= ' LIMIT '. (int) $limit;
2457  $resql = $db->query($sql);
2458  if ($resql) {
2459  if ($showempty) {
2460  $out .= '<option value="-1"';
2461  if (empty($selected)) $out .= ' selected';
2462  $out .= '>&nbsp;</option>';
2463  }
2464  while ($obj = $db->fetch_object($resql)) {
2465  $product = new Product($db);
2466  $res = $product->fetch($obj->fk_product);
2467  $out .= '<option value="'.$obj->rowid.'"';
2468  if ($obj->rowid == $selected) $out .= 'selected';
2469  $out .= '>'.$obj->ref.' - '.$product->label .' - '. $obj->label.'</option>';
2470  }
2471  } else {
2472  $error++;
2473  dol_print_error($db);
2474  }
2475  if (empty($nooutput)) {
2476  print $out;
2477  } else {
2478  return $out;
2479  }
2480  }
2481 
2482  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2508  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)
2509  {
2510  // phpcs:enable
2511  global $langs, $conf;
2512  global $hookmanager;
2513 
2514  $out = '';
2515  $outarray = array();
2516 
2517  // Units
2518  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2519  $langs->load('other');
2520  }
2521 
2522  $warehouseStatusArray = array();
2523  if (!empty($warehouseStatus)) {
2524  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2525  if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2526  $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2527  }
2528  if (preg_match('/warehouseopen/', $warehouseStatus)) {
2529  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2530  }
2531  if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2532  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2533  }
2534  }
2535 
2536  $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";
2537  if (count($warehouseStatusArray)) {
2538  $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
2539  } else {
2540  $selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2541  }
2542 
2543  $sql = "SELECT ";
2544  $sql .= $selectFields.$selectFieldsGrouped;
2545 
2546  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2547  //Product category
2548  $sql .= ", (SELECT ".$this->db->prefix()."categorie_product.fk_categorie
2549  FROM ".$this->db->prefix()."categorie_product
2550  WHERE ".$this->db->prefix()."categorie_product.fk_product=p.rowid
2551  LIMIT 1
2552  ) AS categorie_product_id ";
2553  }
2554 
2555  //Price by customer
2556  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2557  $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2558  $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';
2559  $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2560  }
2561  // Units
2562  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2563  $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";
2564  $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';
2565  }
2566 
2567  // Multilang : we add translation
2568  if (!empty($conf->global->MAIN_MULTILANGS)) {
2569  $sql .= ", pl.label as label_translated";
2570  $sql .= ", pl.description as description_translated";
2571  $selectFields .= ", label_translated";
2572  $selectFields .= ", description_translated";
2573  }
2574  // Price by quantity
2575  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2576  $sql .= ", (SELECT pp.rowid FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid";
2577  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2578  $sql .= " AND price_level = ".((int) $price_level);
2579  }
2580  $sql .= " ORDER BY date_price";
2581  $sql .= " DESC LIMIT 1) as price_rowid";
2582  $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
2583  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2584  $sql .= " AND price_level = ".((int) $price_level);
2585  }
2586  $sql .= " ORDER BY date_price";
2587  $sql .= " DESC LIMIT 1) as price_by_qty";
2588  $selectFields .= ", price_rowid, price_by_qty";
2589  }
2590  $sql .= " FROM ".$this->db->prefix()."product as p";
2591  if (count($warehouseStatusArray)) {
2592  $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_product = p.rowid";
2593  $sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2594  $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.
2595  }
2596 
2597  // include search in supplier ref
2598  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2599  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2600  }
2601 
2602  //Price by customer
2603  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2604  $sql .= " LEFT JOIN ".$this->db->prefix()."product_customer_price as pcp ON pcp.fk_soc=".((int) $socid)." AND pcp.fk_product=p.rowid";
2605  }
2606  // Units
2607  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2608  $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
2609  }
2610  // Multilang : we add translation
2611  if (!empty($conf->global->MAIN_MULTILANGS)) {
2612  $sql .= " LEFT JOIN ".$this->db->prefix()."product_lang as pl ON pl.fk_product = p.rowid ";
2613  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2614  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
2615  $soc = new Societe($this->db);
2616  $result = $soc->fetch($socid);
2617  if ($result > 0 && !empty($soc->default_lang)) {
2618  $sql .= " AND pl.lang = '".$this->db->escape($soc->default_lang)."'";
2619  } else {
2620  $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2621  }
2622  } else {
2623  $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2624  }
2625  }
2626 
2627  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2628  $sql .= " LEFT JOIN ".$this->db->prefix()."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2629  }
2630 
2631  $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2632 
2633  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2634  $sql .= " AND pac.rowid IS NULL";
2635  }
2636 
2637  if ($finished == 0) {
2638  $sql .= " AND p.finished = ".((int) $finished);
2639  } elseif ($finished == 1) {
2640  $sql .= " AND p.finished = ".((int) $finished);
2641  }
2642  if ($status >= 0) {
2643  $sql .= " AND p.tosell = ".((int) $status);
2644  }
2645  if ($status_purchase >= 0) {
2646  $sql .= " AND p.tobuy = ".((int) $status_purchase);
2647  }
2648  // Filter by product type
2649  if (strval($filtertype) != '') {
2650  $sql .= " AND p.fk_product_type = ".((int) $filtertype);
2651  } elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only
2652  $sql .= " AND p.fk_product_type = 1";
2653  } elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2654  $sql .= " AND p.fk_product_type = 0";
2655  }
2656  // Add where from hooks
2657  $parameters = array();
2658  $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2659  $sql .= $hookmanager->resPrint;
2660  // Add criteria on ref/label
2661  if ($filterkey != '') {
2662  $sql .= ' AND (';
2663  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2664  // For natural search
2665  $scrit = explode(' ', $filterkey);
2666  $i = 0;
2667  if (count($scrit) > 1) {
2668  $sql .= "(";
2669  }
2670  foreach ($scrit as $crit) {
2671  if ($i > 0) {
2672  $sql .= " AND ";
2673  }
2674  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2675  if (!empty($conf->global->MAIN_MULTILANGS)) {
2676  $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2677  }
2678  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && ! empty($socid)) {
2679  $sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'";
2680  }
2681  if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2682  $sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2683  if (!empty($conf->global->MAIN_MULTILANGS)) {
2684  $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2685  }
2686  }
2687  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2688  $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2689  }
2690  $sql .= ")";
2691  $i++;
2692  }
2693  if (count($scrit) > 1) {
2694  $sql .= ")";
2695  }
2696  if (!empty($conf->barcode->enabled)) {
2697  $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2698  }
2699  $sql .= ')';
2700  }
2701  if (count($warehouseStatusArray)) {
2702  $sql .= " GROUP BY ".$selectFields;
2703  }
2704 
2705  //Sort by category
2706  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2707  $sql .= " ORDER BY categorie_product_id ";
2708  //ASC OR DESC order
2709  ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2710  } else {
2711  $sql .= $this->db->order("p.ref");
2712  }
2713 
2714  $sql .= $this->db->plimit($limit, 0);
2715 
2716  // Build output string
2717  dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2718  $result = $this->db->query($sql);
2719  if ($result) {
2720  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2721  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2722  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2723 
2724  $num = $this->db->num_rows($result);
2725 
2726  $events = null;
2727 
2728  if (!$forcecombo) {
2729  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2730  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2731  }
2732 
2733  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2734 
2735  $textifempty = '';
2736  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2737  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2738  if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2739  if ($showempty && !is_numeric($showempty)) {
2740  $textifempty = $langs->trans($showempty);
2741  } else {
2742  $textifempty .= $langs->trans("All");
2743  }
2744  } else {
2745  if ($showempty && !is_numeric($showempty)) {
2746  $textifempty = $langs->trans($showempty);
2747  }
2748  }
2749  if ($showempty) {
2750  $out .= '<option value="-1" selected>'.($textifempty ? $textifempty : '&nbsp;').'</option>';
2751  }
2752 
2753  $i = 0;
2754  while ($num && $i < $num) {
2755  $opt = '';
2756  $optJson = array();
2757  $objp = $this->db->fetch_object($result);
2758 
2759  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
2760  $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2761  $sql .= " FROM ".$this->db->prefix()."product_price_by_qty";
2762  $sql .= " WHERE fk_product_price = ".((int) $objp->price_rowid);
2763  $sql .= " ORDER BY quantity ASC";
2764 
2765  dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2766  $result2 = $this->db->query($sql);
2767  if ($result2) {
2768  $nb_prices = $this->db->num_rows($result2);
2769  $j = 0;
2770  while ($nb_prices && $j < $nb_prices) {
2771  $objp2 = $this->db->fetch_object($result2);
2772 
2773  $objp->price_by_qty_rowid = $objp2->rowid;
2774  $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2775  $objp->price_by_qty_quantity = $objp2->quantity;
2776  $objp->price_by_qty_unitprice = $objp2->unitprice;
2777  $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2778  // For backward compatibility
2779  $objp->quantity = $objp2->quantity;
2780  $objp->price = $objp2->price;
2781  $objp->unitprice = $objp2->unitprice;
2782  $objp->remise_percent = $objp2->remise_percent;
2783 
2784  //$objp->tva_tx is not overwritten by $objp2 value
2785  //$objp->default_vat_code is not overwritten by $objp2 value
2786 
2787  $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2788 
2789  $j++;
2790 
2791  // Add new entry
2792  // "key" value of json key array is used by jQuery automatically as selected value
2793  // "label" value of json key array is used by jQuery automatically as text for combo box
2794  $out .= $opt;
2795  array_push($outarray, $optJson);
2796  }
2797  }
2798  } else {
2799  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2800  $price_product = new Product($this->db);
2801  $price_product->fetch($objp->rowid, '', '', 1);
2802  $priceparser = new PriceParser($this->db);
2803  $price_result = $priceparser->parseProduct($price_product);
2804  if ($price_result >= 0) {
2805  $objp->price = $price_result;
2806  $objp->unitprice = $price_result;
2807  //Calculate the VAT
2808  $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2809  $objp->price_ttc = price2num($objp->price_ttc, 'MU');
2810  }
2811  }
2812 
2813  $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2814  // Add new entry
2815  // "key" value of json key array is used by jQuery automatically as selected value
2816  // "label" value of json key array is used by jQuery automatically as text for combo box
2817  $out .= $opt;
2818  array_push($outarray, $optJson);
2819  }
2820 
2821  $i++;
2822  }
2823 
2824  $out .= '</select>';
2825 
2826  $this->db->free($result);
2827 
2828  if (empty($outputmode)) {
2829  return $out;
2830  }
2831  return $outarray;
2832  } else {
2833  dol_print_error($this->db);
2834  }
2835  }
2836 
2852  protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2853  {
2854  global $langs, $conf, $user;
2855 
2856  $outkey = '';
2857  $outval = '';
2858  $outref = '';
2859  $outlabel = '';
2860  $outlabel_translated = '';
2861  $outdesc = '';
2862  $outdesc_translated = '';
2863  $outbarcode = '';
2864  $outorigin = '';
2865  $outtype = '';
2866  $outprice_ht = '';
2867  $outprice_ttc = '';
2868  $outpricebasetype = '';
2869  $outtva_tx = '';
2870  $outdefault_vat_code = '';
2871  $outqty = 1;
2872  $outdiscount = 0;
2873 
2874  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2875 
2876  $label = $objp->label;
2877  if (!empty($objp->label_translated)) {
2878  $label = $objp->label_translated;
2879  }
2880  if (!empty($filterkey) && $filterkey != '') {
2881  $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2882  }
2883 
2884  $outkey = $objp->rowid;
2885  $outref = $objp->ref;
2886  $outrefcust = empty($objp->custref) ? '' : $objp->custref;
2887  $outlabel = $objp->label;
2888  $outdesc = $objp->description;
2889  if (!empty($conf->global->MAIN_MULTILANGS)) {
2890  $outlabel_translated = $objp->label_translated;
2891  $outdesc_translated = $objp->description_translated;
2892  }
2893  $outbarcode = $objp->barcode;
2894  $outorigin = $objp->fk_country;
2895  $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
2896 
2897  $outtype = $objp->fk_product_type;
2898  $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2899  $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2900 
2901  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2902  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
2903  }
2904 
2905  // Units
2906  $outvalUnits = '';
2907  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2908  if (!empty($objp->unit_short)) {
2909  $outvalUnits .= ' - '.$objp->unit_short;
2910  }
2911  }
2912  if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2913  if (!empty($objp->weight) && $objp->weight_units !== null) {
2914  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2915  $outvalUnits .= ' - '.$unitToShow;
2916  }
2917  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2918  $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2919  $outvalUnits .= ' - '.$unitToShow;
2920  }
2921  if (!empty($objp->surface) && $objp->surface_units !== null) {
2922  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2923  $outvalUnits .= ' - '.$unitToShow;
2924  }
2925  if (!empty($objp->volume) && $objp->volume_units !== null) {
2926  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2927  $outvalUnits .= ' - '.$unitToShow;
2928  }
2929  }
2930  if ($outdurationvalue && $outdurationunit) {
2931  $da = array(
2932  'h' => $langs->trans('Hour'),
2933  'd' => $langs->trans('Day'),
2934  'w' => $langs->trans('Week'),
2935  'm' => $langs->trans('Month'),
2936  'y' => $langs->trans('Year')
2937  );
2938  if (isset($da[$outdurationunit])) {
2939  $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2940  }
2941  }
2942 
2943  $opt = '<option value="'.$objp->rowid.'"';
2944  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
2945  if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
2946  $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.'"';
2947  }
2948  if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
2949  if (!empty($user->rights->stock->lire)) {
2950  if ($objp->stock > 0) {
2951  $opt .= ' class="product_line_stock_ok"';
2952  } elseif ($objp->stock <= 0) {
2953  $opt .= ' class="product_line_stock_too_low"';
2954  }
2955  }
2956  }
2957  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2958  $opt .= ' data-labeltrans="'.$outlabel_translated.'"';
2959  $opt .= ' data-desctrans="'.dol_escape_htmltag($outdesc_translated).'"';
2960  }
2961  $opt .= '>';
2962  $opt .= $objp->ref;
2963  if (! empty($objp->custref)) {
2964  $opt.= ' (' . $objp->custref . ')';
2965  }
2966  if ($outbarcode) {
2967  $opt .= ' ('.$outbarcode.')';
2968  }
2969  $opt .= ' - '.dol_trunc($label, $maxlengtharticle);
2970  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2971  $opt .= ' ('.getCountry($outorigin, 1).')';
2972  }
2973 
2974  $objRef = $objp->ref;
2975  if (! empty($objp->custref)) {
2976  $objRef .= ' (' . $objp->custref . ')';
2977  }
2978  if (!empty($filterkey) && $filterkey != '') {
2979  $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2980  }
2981  $outval .= $objRef;
2982  if ($outbarcode) {
2983  $outval .= ' ('.$outbarcode.')';
2984  }
2985  $outval .= ' - '.dol_trunc($label, $maxlengtharticle);
2986  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2987  $outval .= ' ('.getCountry($outorigin, 1).')';
2988  }
2989 
2990  // Units
2991  $opt .= $outvalUnits;
2992  $outval .= $outvalUnits;
2993 
2994  $found = 0;
2995 
2996  // Multiprice
2997  // If we need a particular price level (from 1 to n)
2998  if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
2999  $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3000  $sql .= " FROM ".$this->db->prefix()."product_price";
3001  $sql .= " WHERE fk_product = ".((int) $objp->rowid);
3002  $sql .= " AND entity IN (".getEntity('productprice').")";
3003  $sql .= " AND price_level = ".((int) $price_level);
3004  $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3005  $sql .= " LIMIT 1";
3006 
3007  dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
3008  $result2 = $this->db->query($sql);
3009  if ($result2) {
3010  $objp2 = $this->db->fetch_object($result2);
3011  if ($objp2) {
3012  $found = 1;
3013  if ($objp2->price_base_type == 'HT') {
3014  $opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3015  $outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3016  } else {
3017  $opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3018  $outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3019  }
3020  $outprice_ht = price($objp2->price);
3021  $outprice_ttc = price($objp2->price_ttc);
3022  $outpricebasetype = $objp2->price_base_type;
3023  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
3024  $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3025  $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3026  } else {
3027  $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3028  $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3029  }
3030  }
3031  } else {
3032  dol_print_error($this->db);
3033  }
3034  }
3035 
3036  // Price by quantity
3037  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))) {
3038  $found = 1;
3039  $outqty = $objp->quantity;
3040  $outdiscount = $objp->remise_percent;
3041  if ($objp->quantity == 1) {
3042  $opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
3043  $outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
3044  $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3045  $outval .= $langs->transnoentities("Unit");
3046  } else {
3047  $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
3048  $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
3049  $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3050  $outval .= $langs->transnoentities("Units");
3051  }
3052 
3053  $outprice_ht = price($objp->unitprice);
3054  $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3055  $outpricebasetype = $objp->price_base_type;
3056  $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
3057  $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
3058  }
3059  if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3060  $opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
3061  $outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
3062  }
3063  if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3064  $opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3065  $outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3066  }
3067 
3068  // Price by customer
3069  if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
3070  if (!empty($objp->idprodcustprice)) {
3071  $found = 1;
3072 
3073  if ($objp->custprice_base_type == 'HT') {
3074  $opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3075  $outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3076  } else {
3077  $opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3078  $outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3079  }
3080 
3081  $outprice_ht = price($objp->custprice);
3082  $outprice_ttc = price($objp->custprice_ttc);
3083  $outpricebasetype = $objp->custprice_base_type;
3084  $outtva_tx = $objp->custtva_tx;
3085  $outdefault_vat_code = $objp->custdefault_vat_code;
3086  }
3087  }
3088 
3089  // If level no defined or multiprice not found, we used the default price
3090  if (empty($hidepriceinlabel) && !$found) {
3091  if ($objp->price_base_type == 'HT') {
3092  $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3093  $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3094  } else {
3095  $opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3096  $outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3097  }
3098  $outprice_ht = price($objp->price);
3099  $outprice_ttc = price($objp->price_ttc);
3100  $outpricebasetype = $objp->price_base_type;
3101  $outtva_tx = $objp->tva_tx;
3102  $outdefault_vat_code = $objp->default_vat_code;
3103  }
3104 
3105  if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3106  if (!empty($user->rights->stock->lire)) {
3107  $opt .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3108 
3109  if ($objp->stock > 0) {
3110  $outval .= ' - <span class="product_line_stock_ok">';
3111  } elseif ($objp->stock <= 0) {
3112  $outval .= ' - <span class="product_line_stock_too_low">';
3113  }
3114  $outval .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS'));
3115  $outval .= '</span>';
3116  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3117  $langs->load("stocks");
3118 
3119  $tmpproduct = new Product($this->db);
3120  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3121  $tmpproduct->load_virtual_stock();
3122  $virtualstock = $tmpproduct->stock_theorique;
3123 
3124  $opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3125 
3126  $outval .= ' - '.$langs->transnoentities("VirtualStock").':';
3127  if ($virtualstock > 0) {
3128  $outval .= '<span class="product_line_stock_ok">';
3129  } elseif ($virtualstock <= 0) {
3130  $outval .= '<span class="product_line_stock_too_low">';
3131  }
3132  $outval .= $virtualstock;
3133  $outval .= '</span>';
3134 
3135  unset($tmpproduct);
3136  }
3137  }
3138  }
3139 
3140  $opt .= "</option>\n";
3141  $optJson = array(
3142  'key'=>$outkey,
3143  'value'=>$outref,
3144  'label'=>$outval,
3145  'label2'=>$outlabel,
3146  'desc'=>$outdesc,
3147  'type'=>$outtype,
3148  'price_ht'=>price2num($outprice_ht),
3149  'price_ttc'=>price2num($outprice_ttc),
3150  'price_ht_locale'=>price(price2num($outprice_ht)),
3151  'price_ttc_locale'=>price(price2num($outprice_ttc)),
3152  'pricebasetype'=>$outpricebasetype,
3153  'tva_tx'=>$outtva_tx,
3154  'default_vat_code'=>$outdefault_vat_code,
3155  'qty'=>$outqty,
3156  'discount'=>$outdiscount,
3157  'duration_value'=>$outdurationvalue,
3158  'duration_unit'=>$outdurationunit,
3159  'pbq'=>$outpbq,
3160  'labeltrans'=>$outlabel_translated,
3161  'desctrans'=>$outdesc_translated,
3162  'ref_customer'=>$outrefcust
3163  );
3164  }
3165 
3166  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3182  public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3183  {
3184  // phpcs:enable
3185  global $langs, $conf;
3186  global $price_level, $status, $finished;
3187 
3188  if (!isset($status)) {
3189  $status = 1;
3190  }
3191 
3192  $selected_input_value = '';
3193  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
3194  if ($selected > 0) {
3195  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
3196  $producttmpselect = new Product($this->db);
3197  $producttmpselect->fetch($selected);
3198  $selected_input_value = $producttmpselect->ref;
3199  unset($producttmpselect);
3200  }
3201 
3202  // mode=2 means suppliers products
3203  $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
3204  print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3205  print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" class="minwidth300" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.$placeholder.'"' : '').'>';
3206  } else {
3207  print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3208  }
3209  }
3210 
3211  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3230  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 = '')
3231  {
3232  // phpcs:enable
3233  global $langs, $conf, $user;
3234  global $hookmanager;
3235 
3236  $out = '';
3237  $outarray = array();
3238 
3239  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3240 
3241  $langs->load('stocks');
3242  // Units
3243  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3244  $langs->load('other');
3245  }
3246 
3247  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock,";
3248  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
3249  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name,";
3250  $sql .= " pfp.supplier_reputation";
3251  // if we use supplier description of the products
3252  if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3253  $sql .= ", pfp.desc_fourn as description";
3254  } else {
3255  $sql .= ", p.description";
3256  }
3257  // Units
3258  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3259  $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";
3260  }
3261  if (!empty($conf->barcode->enabled)) {
3262  $sql .= ", pfp.barcode";
3263  }
3264  $sql .= " FROM ".$this->db->prefix()."product as p";
3265  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )";
3266  if ($socid > 0) {
3267  $sql .= " AND pfp.fk_soc = ".((int) $socid);
3268  }
3269  $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid";
3270  // Units
3271  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3272  $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
3273  }
3274  $sql .= " WHERE p.entity IN (".getEntity('product').")";
3275  if ($statut != -1) {
3276  $sql .= " AND p.tobuy = ".((int) $statut);
3277  }
3278  if (strval($filtertype) != '') {
3279  $sql .= " AND p.fk_product_type = ".((int) $filtertype);
3280  }
3281  if (!empty($filtre)) {
3282  $sql .= " ".$filtre;
3283  }
3284  // Add where from hooks
3285  $parameters = array();
3286  $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3287  $sql .= $hookmanager->resPrint;
3288  // Add criteria on ref/label
3289  if ($filterkey != '') {
3290  $sql .= ' AND (';
3291  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3292  // For natural search
3293  $scrit = explode(' ', $filterkey);
3294  $i = 0;
3295  if (count($scrit) > 1) {
3296  $sql .= "(";
3297  }
3298  foreach ($scrit as $crit) {
3299  if ($i > 0) {
3300  $sql .= " AND ";
3301  }
3302  $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)."%'";
3303  if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3304  $sql .= " OR pfp.desc_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
3305  }
3306  $sql .= ")";
3307  $i++;
3308  }
3309  if (count($scrit) > 1) {
3310  $sql .= ")";
3311  }
3312  if (!empty($conf->barcode->enabled)) {
3313  $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3314  $sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3315  }
3316  $sql .= ')';
3317  }
3318  $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3319  $sql .= $this->db->plimit($limit, 0);
3320 
3321  // Build output string
3322 
3323  dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
3324  $result = $this->db->query($sql);
3325  if ($result) {
3326  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3327  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
3328 
3329  $num = $this->db->num_rows($result);
3330 
3331  //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3332  $out .= '<select class="flat '.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
3333  if (!$selected) {
3334  $out .= '<option value="-1" selected>'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3335  } else {
3336  $out .= '<option value="-1">'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3337  }
3338 
3339  $i = 0;
3340  while ($i < $num) {
3341  $objp = $this->db->fetch_object($result);
3342 
3343  $outkey = $objp->idprodfournprice; // id in table of price
3344  if (!$outkey && $alsoproductwithnosupplierprice) {
3345  $outkey = 'idprod_'.$objp->rowid; // id of product
3346  }
3347 
3348  $outref = $objp->ref;
3349  $outval = '';
3350  $outbarcode = $objp->barcode;
3351  $outqty = 1;
3352  $outdiscount = 0;
3353  $outtype = $objp->fk_product_type;
3354  $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3355  $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
3356 
3357  // Units
3358  $outvalUnits = '';
3359  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3360  if (!empty($objp->unit_short)) {
3361  $outvalUnits .= ' - '.$objp->unit_short;
3362  }
3363  if (!empty($objp->weight) && $objp->weight_units !== null) {
3364  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3365  $outvalUnits .= ' - '.$unitToShow;
3366  }
3367  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3368  $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
3369  $outvalUnits .= ' - '.$unitToShow;
3370  }
3371  if (!empty($objp->surface) && $objp->surface_units !== null) {
3372  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3373  $outvalUnits .= ' - '.$unitToShow;
3374  }
3375  if (!empty($objp->volume) && $objp->volume_units !== null) {
3376  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3377  $outvalUnits .= ' - '.$unitToShow;
3378  }
3379  if ($outdurationvalue && $outdurationunit) {
3380  $da = array(
3381  'h' => $langs->trans('Hour'),
3382  'd' => $langs->trans('Day'),
3383  'w' => $langs->trans('Week'),
3384  'm' => $langs->trans('Month'),
3385  'y' => $langs->trans('Year')
3386  );
3387  if (isset($da[$outdurationunit])) {
3388  $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
3389  }
3390  }
3391  }
3392 
3393  $objRef = $objp->ref;
3394  if ($filterkey && $filterkey != '') {
3395  $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
3396  }
3397  $objRefFourn = $objp->ref_fourn;
3398  if ($filterkey && $filterkey != '') {
3399  $objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1);
3400  }
3401  $label = $objp->label;
3402  if ($filterkey && $filterkey != '') {
3403  $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
3404  }
3405 
3406  $optlabel = $objp->ref;
3407  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3408  $optlabel .= ' <span class="opacitymedium">('.$objp->ref_fourn.')</span>';
3409  }
3410  if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
3411  $optlabel .= ' ('.$outbarcode.')';
3412  }
3413  $optlabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3414 
3415  $outvallabel = $objRef;
3416  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3417  $outvallabel .= ' ('.$objRefFourn.')';
3418  }
3419  if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
3420  $outvallabel .= ' ('.$outbarcode.')';
3421  }
3422  $outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3423 
3424  // Units
3425  $optlabel .= $outvalUnits;
3426  $outvallabel .= $outvalUnits;
3427 
3428  if (!empty($objp->idprodfournprice)) {
3429  $outqty = $objp->quantity;
3430  $outdiscount = $objp->remise_percent;
3431  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3432  $prod_supplier = new ProductFournisseur($this->db);
3433  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3434  $prod_supplier->id = $objp->fk_product;
3435  $prod_supplier->fourn_qty = $objp->quantity;
3436  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3437  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3438  $priceparser = new PriceParser($this->db);
3439  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3440  if ($price_result >= 0) {
3441  $objp->fprice = $price_result;
3442  if ($objp->quantity >= 1) {
3443  $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3444  }
3445  }
3446  }
3447  if ($objp->quantity == 1) {
3448  $optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3449  $outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
3450  $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3451  $outvallabel .= $langs->transnoentities("Unit");
3452  } else {
3453  $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;
3454  $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;
3455  $optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3456  $outvallabel .= ' '.$langs->transnoentities("Units");
3457  }
3458 
3459  if ($objp->quantity > 1) {
3460  $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
3461  $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
3462  }
3463  if ($objp->remise_percent >= 1) {
3464  $optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3465  $outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3466  }
3467  if ($objp->duration) {
3468  $optlabel .= " - ".$objp->duration;
3469  $outvallabel .= " - ".$objp->duration;
3470  }
3471  if (!$socid) {
3472  $optlabel .= " - ".dol_trunc($objp->name, 8);
3473  $outvallabel .= " - ".dol_trunc($objp->name, 8);
3474  }
3475  if ($objp->supplier_reputation) {
3476  //TODO dictionary
3477  $reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
3478 
3479  $optlabel .= " - ".$reputations[$objp->supplier_reputation];
3480  $outvallabel .= " - ".$reputations[$objp->supplier_reputation];
3481  }
3482  } else {
3483  if (empty($alsoproductwithnosupplierprice)) { // No supplier price defined for couple product/supplier
3484  $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3485  $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3486  } else // No supplier price defined for product, even on other suppliers
3487  {
3488  $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3489  $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3490  }
3491  }
3492 
3493  if (!empty($conf->stock->enabled) && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3494  $novirtualstock = ($showstockinlist == 2);
3495 
3496  if (!empty($user->rights->stock->lire)) {
3497  $outvallabel .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3498 
3499  if ($objp->stock > 0) {
3500  $optlabel .= ' - <span class="product_line_stock_ok">';
3501  } elseif ($objp->stock <= 0) {
3502  $optlabel .= ' - <span class="product_line_stock_too_low">';
3503  }
3504  $optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS'));
3505  $optlabel .= '</span>';
3506  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3507  $langs->load("stocks");
3508 
3509  $tmpproduct = new Product($this->db);
3510  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3511  $tmpproduct->load_virtual_stock();
3512  $virtualstock = $tmpproduct->stock_theorique;
3513 
3514  $outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3515 
3516  $optlabel .= ' - '.$langs->transnoentities("VirtualStock").':';
3517  if ($virtualstock > 0) {
3518  $optlabel .= '<span class="product_line_stock_ok">';
3519  } elseif ($virtualstock <= 0) {
3520  $optlabel .= '<span class="product_line_stock_too_low">';
3521  }
3522  $optlabel .= $virtualstock;
3523  $optlabel .= '</span>';
3524 
3525  unset($tmpproduct);
3526  }
3527  }
3528  }
3529 
3530  $opt = '<option value="'.$outkey.'"';
3531  if ($selected && $selected == $objp->idprodfournprice) {
3532  $opt .= ' selected';
3533  }
3534  if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3535  $opt .= ' disabled';
3536  }
3537  if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3538  $opt .= ' data-product-id="'.dol_escape_htmltag($objp->rowid).'"';
3539  $opt .= ' data-price-id="'.dol_escape_htmltag($objp->idprodfournprice).'"';
3540  $opt .= ' data-qty="'.dol_escape_htmltag($objp->quantity).'"';
3541  $opt .= ' data-up="'.dol_escape_htmltag($objp->unitprice).'"';
3542  $opt .= ' data-up-locale="'.dol_escape_htmltag(price($objp->unitprice)).'"';
3543  $opt .= ' data-discount="'.dol_escape_htmltag($outdiscount).'"';
3544  $opt .= ' data-tvatx="'.dol_escape_htmltag($objp->tva_tx).'"';
3545  }
3546  $opt .= ' data-description="'.dol_escape_htmltag($objp->description, 0, 1).'"';
3547  $opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"';
3548  $opt .= '>';
3549 
3550  $opt .= $optlabel;
3551  $outval .= $outvallabel;
3552 
3553  $opt .= "</option>\n";
3554 
3555  // Add new entry
3556  // "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
3557  // "label" value of json key array is used by jQuery automatically as text for combo box
3558  $out .= $opt;
3559  array_push(
3560  $outarray,
3561  array('key'=>$outkey,
3562  'value'=>$outref,
3563  'label'=>$outval,
3564  'qty'=>$outqty,
3565  'price_qty_ht'=>price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3566  'price_unit_ht'=>price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3567  'price_ht'=>price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3568  'price_qty_ht_locale'=>price($objp->fprice),
3569  'price_unit_ht_locale'=>price($objp->unitprice),
3570  'tva_tx'=>$objp->tva_tx,
3571  'default_vat_code'=>$objp->default_vat_code,
3572  'discount'=>$outdiscount,
3573  'type'=>$outtype,
3574  'duration_value'=>$outdurationvalue,
3575  'duration_unit'=>$outdurationunit,
3576  'disabled'=>(empty($objp->idprodfournprice) ? true : false),
3577  'description'=>$objp->description
3578  )
3579  );
3580  // Exemple of var_dump $outarray
3581  // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3582  // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3583  // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3584  //}
3585  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3586  //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3587  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3588 
3589  $i++;
3590  }
3591  $out .= '</select>';
3592 
3593  $this->db->free($result);
3594 
3595  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3596  $out .= ajax_combobox($htmlname);
3597 
3598  if (empty($outputmode)) {
3599  return $out;
3600  }
3601  return $outarray;
3602  } else {
3603  dol_print_error($this->db);
3604  }
3605  }
3606 
3607  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3616  public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3617  {
3618  // phpcs:enable
3619  global $langs, $conf;
3620 
3621  $langs->load('stocks');
3622 
3623  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3624  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3625  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3626  $sql .= " FROM ".$this->db->prefix()."product as p";
3627  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3628  $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid";
3629  $sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3630  $sql .= " AND p.tobuy = 1";
3631  $sql .= " AND s.fournisseur = 1";
3632  $sql .= " AND p.rowid = ".((int) $productid);
3633  $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3634 
3635  dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3636  $result = $this->db->query($sql);
3637 
3638  if ($result) {
3639  $num = $this->db->num_rows($result);
3640 
3641  $form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3642 
3643  if (!$num) {
3644  $form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3645  } else {
3646  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3647  $form .= '<option value="0">&nbsp;</option>';
3648 
3649  $i = 0;
3650  while ($i < $num) {
3651  $objp = $this->db->fetch_object($result);
3652 
3653  $opt = '<option value="'.$objp->idprodfournprice.'"';
3654  //if there is only one supplier, preselect it
3655  if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
3656  $opt .= ' selected';
3657  }
3658  $opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3659 
3660  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3661  $prod_supplier = new ProductFournisseur($this->db);
3662  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3663  $prod_supplier->id = $productid;
3664  $prod_supplier->fourn_qty = $objp->quantity;
3665  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3666  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3667  $priceparser = new PriceParser($this->db);
3668  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3669  if ($price_result >= 0) {
3670  $objp->fprice = $price_result;
3671  if ($objp->quantity >= 1) {
3672  $objp->unitprice = $objp->fprice / $objp->quantity;
3673  }
3674  }
3675  }
3676  if ($objp->quantity == 1) {
3677  $opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3678  }
3679 
3680  $opt .= $objp->quantity.' ';
3681 
3682  if ($objp->quantity == 1) {
3683  $opt .= $langs->trans("Unit");
3684  } else {
3685  $opt .= $langs->trans("Units");
3686  }
3687  if ($objp->quantity > 1) {
3688  $opt .= " - ";
3689  $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");
3690  }
3691  if ($objp->duration) {
3692  $opt .= " - ".$objp->duration;
3693  }
3694  $opt .= "</option>\n";
3695 
3696  $form .= $opt;
3697  $i++;
3698  }
3699  }
3700 
3701  $form .= '</select>';
3702  $this->db->free($result);
3703  return $form;
3704  } else {
3705  dol_print_error($this->db);
3706  }
3707  }
3708 
3709  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3719  public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3720  {
3721  // phpcs:enable
3722  // looking for users
3723  $sql = "SELECT a.rowid, a.label";
3724  $sql .= " FROM ".$this->db->prefix()."societe_address as a";
3725  $sql .= " WHERE a.fk_soc = ".((int) $socid);
3726  $sql .= " ORDER BY a.label ASC";
3727 
3728  dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3729  $resql = $this->db->query($sql);
3730  if ($resql) {
3731  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3732  if ($showempty) {
3733  print '<option value="0">&nbsp;</option>';
3734  }
3735  $num = $this->db->num_rows($resql);
3736  $i = 0;
3737  if ($num) {
3738  while ($i < $num) {
3739  $obj = $this->db->fetch_object($resql);
3740 
3741  if ($selected && $selected == $obj->rowid) {
3742  print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3743  } else {
3744  print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3745  }
3746  $i++;
3747  }
3748  }
3749  print '</select>';
3750  return $num;
3751  } else {
3752  dol_print_error($this->db);
3753  }
3754  }
3755 
3756  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3763  {
3764  // phpcs:enable
3765  global $langs;
3766 
3767  $num = count($this->cache_conditions_paiements);
3768  if ($num > 0) {
3769  return 0; // Cache already loaded
3770  }
3771 
3772  dol_syslog(__METHOD__, LOG_DEBUG);
3773 
3774  $sql = "SELECT rowid, code, libelle as label, deposit_percent";
3775  $sql .= " FROM ".$this->db->prefix().'c_payment_term';
3776  $sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3777  $sql .= " AND active > 0";
3778  $sql .= " ORDER BY sortorder";
3779 
3780  $resql = $this->db->query($sql);
3781  if ($resql) {
3782  $num = $this->db->num_rows($resql);
3783  $i = 0;
3784  while ($i < $num) {
3785  $obj = $this->db->fetch_object($resql);
3786 
3787  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3788  $label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3789  $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3790  $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3791  $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
3792  $i++;
3793  }
3794 
3795  //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
3796 
3797  return $num;
3798  } else {
3799  dol_print_error($this->db);
3800  return -1;
3801  }
3802  }
3803 
3804  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3810  public function load_cache_availability()
3811  {
3812  // phpcs:enable
3813  global $langs;
3814 
3815  $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
3816  if ($num > 0) {
3817  return 0; // Cache already loaded
3818  }
3819 
3820  dol_syslog(__METHOD__, LOG_DEBUG);
3821 
3822  $langs->load('propal');
3823 
3824  $sql = "SELECT rowid, code, label, position";
3825  $sql .= " FROM ".$this->db->prefix().'c_availability';
3826  $sql .= " WHERE active > 0";
3827 
3828  $resql = $this->db->query($sql);
3829  if ($resql) {
3830  $num = $this->db->num_rows($resql);
3831  $i = 0;
3832  while ($i < $num) {
3833  $obj = $this->db->fetch_object($resql);
3834 
3835  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3836  $label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3837  $this->cache_availability[$obj->rowid]['code'] = $obj->code;
3838  $this->cache_availability[$obj->rowid]['label'] = $label;
3839  $this->cache_availability[$obj->rowid]['position'] = $obj->position;
3840  $i++;
3841  }
3842 
3843  $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
3844 
3845  return $num;
3846  } else {
3847  dol_print_error($this->db);
3848  return -1;
3849  }
3850  }
3851 
3862  public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
3863  {
3864  global $langs, $user;
3865 
3866  $this->load_cache_availability();
3867 
3868  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3869 
3870  print '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3871  if ($addempty) {
3872  print '<option value="0">&nbsp;</option>';
3873  }
3874  foreach ($this->cache_availability as $id => $arrayavailability) {
3875  if ($selected == $id) {
3876  print '<option value="'.$id.'" selected>';
3877  } else {
3878  print '<option value="'.$id.'">';
3879  }
3880  print dol_escape_htmltag($arrayavailability['label']);
3881  print '</option>';
3882  }
3883  print '</select>';
3884  if ($user->admin) {
3885  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3886  }
3887  print ajax_combobox($htmlname);
3888  }
3889 
3895  public function loadCacheInputReason()
3896  {
3897  global $langs;
3898 
3899  $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
3900  if ($num > 0) {
3901  return 0; // Cache already loaded
3902  }
3903 
3904  $sql = "SELECT rowid, code, label";
3905  $sql .= " FROM ".$this->db->prefix().'c_input_reason';
3906  $sql .= " WHERE active > 0";
3907 
3908  $resql = $this->db->query($sql);
3909  if ($resql) {
3910  $num = $this->db->num_rows($resql);
3911  $i = 0;
3912  $tmparray = array();
3913  while ($i < $num) {
3914  $obj = $this->db->fetch_object($resql);
3915 
3916  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3917  $label = ($obj->label != '-' ? $obj->label : '');
3918  if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) {
3919  $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3920  }
3921  if ($langs->trans($obj->code) != $obj->code) {
3922  $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3923  }
3924 
3925  $tmparray[$obj->rowid]['id'] = $obj->rowid;
3926  $tmparray[$obj->rowid]['code'] = $obj->code;
3927  $tmparray[$obj->rowid]['label'] = $label;
3928  $i++;
3929  }
3930 
3931  $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3932 
3933  unset($tmparray);
3934  return $num;
3935  } else {
3936  dol_print_error($this->db);
3937  return -1;
3938  }
3939  }
3940 
3953  public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
3954  {
3955  global $langs, $user;
3956 
3957  $this->loadCacheInputReason();
3958 
3959  print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3960  if ($addempty) {
3961  print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
3962  }
3963  foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
3964  if ($arraydemandreason['code'] == $exclude) {
3965  continue;
3966  }
3967 
3968  if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
3969  print '<option value="'.$arraydemandreason['id'].'" selected>';
3970  } else {
3971  print '<option value="'.$arraydemandreason['id'].'">';
3972  }
3973  $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3974  print $langs->trans($label);
3975  print '</option>';
3976  }
3977  print '</select>';
3978  if ($user->admin && empty($notooltip)) {
3979  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3980  }
3981  print ajax_combobox('select_'.$htmlname);
3982  }
3983 
3984  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3990  public function load_cache_types_paiements()
3991  {
3992  // phpcs:enable
3993  global $langs;
3994 
3995  $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
3996  if ($num > 0) {
3997  return $num; // Cache already loaded
3998  }
3999 
4000  dol_syslog(__METHOD__, LOG_DEBUG);
4001 
4002  $this->cache_types_paiements = array();
4003 
4004  $sql = "SELECT id, code, libelle as label, type, active";
4005  $sql .= " FROM ".$this->db->prefix()."c_paiement";
4006  $sql .= " WHERE entity IN (".getEntity('c_paiement').")";
4007 
4008  $resql = $this->db->query($sql);
4009  if ($resql) {
4010  $num = $this->db->num_rows($resql);
4011  $i = 0;
4012  while ($i < $num) {
4013  $obj = $this->db->fetch_object($resql);
4014 
4015  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4016  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4017  $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4018  $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4019  $this->cache_types_paiements[$obj->id]['label'] = $label;
4020  $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4021  $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4022  $i++;
4023  }
4024 
4025  $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4026 
4027  return $num;
4028  } else {
4029  dol_print_error($this->db);
4030  return -1;
4031  }
4032  }
4033 
4034 
4035  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4052  public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4053  {
4054  // phpcs:enable
4055  print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4056  }
4057 
4058 
4075  public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4076  {
4077  global $langs, $user, $conf;
4078 
4079  $out = '';
4080  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
4081 
4083 
4084  // Set default value if not already set by caller
4085  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
4086  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4087  }
4088 
4089  $out.= '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4090  if ($addempty) {
4091  $out.= '<option value="0">&nbsp;</option>';
4092  }
4093 
4094  $selectedDepositPercent = null;
4095 
4096  foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4097  if ($filtertype <= 0 && ! empty($arrayconditions['deposit_percent'])) {
4098  continue;
4099  }
4100 
4101  if ($selected == $id) {
4102  $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4103  $out .= '<option value="'.$id.'" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4104  } else {
4105  $out .= '<option value="'.$id.'" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4106  }
4107  $label = $arrayconditions['label'];
4108 
4109  if (! empty($arrayconditions['deposit_percent'])) {
4110  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4111  }
4112 
4113  $out.= $label;
4114  $out.= '</option>';
4115  }
4116  $out.= '</select>';
4117  if ($user->admin && empty($noinfoadmin)) {
4118  $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4119  }
4120  $out.= ajax_combobox($htmlname);
4121 
4122  if ($deposit_percent >= 0) {
4123  $out .= ' <span id="'.$htmlname.'_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4124  $out .= $langs->trans('DepositPercent') . ' : ';
4125  $out .= '<input id="'.$htmlname.'_deposit_percent" name="'.$htmlname.'_deposit_percent" class="maxwidth50" value="' . strval($deposit_percent) . '" />';
4126  $out .= '</span>';
4127  $out .= '
4128  <script>
4129  $(document).ready(function () {
4130  $("#' . $htmlname . '").change(function () {
4131  let $selected = $(this).find("option:selected");
4132  let depositPercent = $selected.attr("data-deposit_percent");
4133 
4134  if (depositPercent.length > 0) {
4135  $("#'.$htmlname.'_deposit_percent_container").show().find("#'.$htmlname.'_deposit_percent").val(depositPercent);
4136  } else {
4137  $("#'.$htmlname.'_deposit_percent_container").hide();
4138  }
4139 
4140  return true;
4141  });
4142  });
4143  </script>';
4144  }
4145 
4146  return $out;
4147  }
4148 
4149 
4150  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4167  public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4168  {
4169  // phpcs:enable
4170  global $langs, $user, $conf;
4171 
4172  $out = '';
4173 
4174  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
4175 
4176  $filterarray = array();
4177  if ($filtertype == 'CRDT') {
4178  $filterarray = array(0, 2, 3);
4179  } elseif ($filtertype == 'DBIT') {
4180  $filterarray = array(1, 2, 3);
4181  } elseif ($filtertype != '' && $filtertype != '-1') {
4182  $filterarray = explode(',', $filtertype);
4183  }
4184 
4185  $this->load_cache_types_paiements();
4186 
4187  // Set default value if not already set by caller
4188  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
4189  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4190  }
4191 
4192  $out .= '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4193  if ($empty) {
4194  $out .= '<option value="">&nbsp;</option>';
4195  }
4196  foreach ($this->cache_types_paiements as $id => $arraytypes) {
4197  // If not good status
4198  if ($active >= 0 && $arraytypes['active'] != $active) {
4199  continue;
4200  }
4201 
4202  // On passe si on a demande de filtrer sur des modes de paiments particuliers
4203  if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4204  continue;
4205  }
4206 
4207  // We discard empty line if showempty is on because an empty line has already been output.
4208  if ($empty && empty($arraytypes['code'])) {
4209  continue;
4210  }
4211 
4212  if ($format == 0) {
4213  $out .= '<option value="'.$id.'"';
4214  } elseif ($format == 1) {
4215  $out .= '<option value="'.$arraytypes['code'].'"';
4216  } elseif ($format == 2) {
4217  $out .= '<option value="'.$arraytypes['code'].'"';
4218  } elseif ($format == 3) {
4219  $out .= '<option value="'.$id.'"';
4220  }
4221  // Print attribute selected or not
4222  if ($format == 1 || $format == 2) {
4223  if ($selected == $arraytypes['code']) {
4224  $out .= ' selected';
4225  }
4226  } else {
4227  if ($selected == $id) {
4228  $out .= ' selected';
4229  }
4230  }
4231  $out .= '>';
4232  $value = '';
4233  if ($format == 0) {
4234  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4235  } elseif ($format == 1) {
4236  $value = $arraytypes['code'];
4237  } elseif ($format == 2) {
4238  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4239  } elseif ($format == 3) {
4240  $value = $arraytypes['code'];
4241  }
4242  $out .= $value ? $value : '&nbsp;';
4243  $out .= '</option>';
4244  }
4245  $out .= '</select>';
4246  if ($user->admin && !$noadmininfo) {
4247  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4248  }
4249  $out .= ajax_combobox('select'.$htmlname);
4250 
4251  if (empty($nooutput)) {
4252  print $out;
4253  } else {
4254  return $out;
4255  }
4256  }
4257 
4258 
4267  public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4268  {
4269  global $langs;
4270 
4271  $return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4272  $options = array(
4273  'HT'=>$langs->trans("HT"),
4274  'TTC'=>$langs->trans("TTC")
4275  );
4276  foreach ($options as $id => $value) {
4277  if ($selected == $id) {
4278  $return .= '<option value="'.$id.'" selected>'.$value;
4279  } else {
4280  $return .= '<option value="'.$id.'">'.$value;
4281  }
4282  $return .= '</option>';
4283  }
4284  $return .= '</select>';
4285  if ($addjscombo) {
4286  $return .= ajax_combobox('select_'.$htmlname);
4287  }
4288 
4289  return $return;
4290  }
4291 
4292  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4298  public function load_cache_transport_mode()
4299  {
4300  // phpcs:enable
4301  global $langs;
4302 
4303  $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4304  if ($num > 0) {
4305  return $num; // Cache already loaded
4306  }
4307 
4308  dol_syslog(__METHOD__, LOG_DEBUG);
4309 
4310  $this->cache_transport_mode = array();
4311 
4312  $sql = "SELECT rowid, code, label, active";
4313  $sql .= " FROM ".$this->db->prefix()."c_transport_mode";
4314  $sql .= " WHERE entity IN (".getEntity('c_transport_mode').")";
4315 
4316  $resql = $this->db->query($sql);
4317  if ($resql) {
4318  $num = $this->db->num_rows($resql);
4319  $i = 0;
4320  while ($i < $num) {
4321  $obj = $this->db->fetch_object($resql);
4322 
4323  // If traduction exist, we use it else we take the default label
4324  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4325  $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4326  $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4327  $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4328  $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4329  $i++;
4330  }
4331 
4332  $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4333 
4334  return $num;
4335  } else {
4336  dol_print_error($this->db);
4337  return -1;
4338  }
4339  }
4340 
4354  public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4355  {
4356  global $langs, $user;
4357 
4358  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
4359 
4360  $this->load_cache_transport_mode();
4361 
4362  print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4363  if ($empty) {
4364  print '<option value="">&nbsp;</option>';
4365  }
4366  foreach ($this->cache_transport_mode as $id => $arraytypes) {
4367  // If not good status
4368  if ($active >= 0 && $arraytypes['active'] != $active) {
4369  continue;
4370  }
4371 
4372  // We discard empty line if showempty is on because an empty line has already been output.
4373  if ($empty && empty($arraytypes['code'])) {
4374  continue;
4375  }
4376 
4377  if ($format == 0) {
4378  print '<option value="'.$id.'"';
4379  } elseif ($format == 1) {
4380  print '<option value="'.$arraytypes['code'].'"';
4381  } elseif ($format == 2) {
4382  print '<option value="'.$arraytypes['code'].'"';
4383  } elseif ($format == 3) {
4384  print '<option value="'.$id.'"';
4385  }
4386  // If text is selected, we compare with code, else with id
4387  if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4388  print ' selected';
4389  } elseif ($selected == $id) {
4390  print ' selected';
4391  }
4392  print '>';
4393  $value = '';
4394  if ($format == 0) {
4395  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4396  } elseif ($format == 1) {
4397  $value = $arraytypes['code'];
4398  } elseif ($format == 2) {
4399  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4400  } elseif ($format == 3) {
4401  $value = $arraytypes['code'];
4402  }
4403  print $value ? $value : '&nbsp;';
4404  print '</option>';
4405  }
4406  print '</select>';
4407  if ($user->admin && !$noadmininfo) {
4408  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4409  }
4410  }
4411 
4424  public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4425  {
4426  global $langs, $conf, $user;
4427 
4428  $langs->load("admin");
4429  $langs->load("deliveries");
4430 
4431  $sql = "SELECT rowid, code, libelle as label";
4432  $sql .= " FROM ".$this->db->prefix()."c_shipment_mode";
4433  $sql .= " WHERE active > 0";
4434  if ($filtre) {
4435  $sql .= " AND ".$filtre;
4436  }
4437  $sql .= " ORDER BY libelle ASC";
4438 
4439  dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
4440  $result = $this->db->query($sql);
4441  if ($result) {
4442  $num = $this->db->num_rows($result);
4443  $i = 0;
4444  if ($num) {
4445  print '<select id="select'.$htmlname.'" class="flat selectshippingmethod'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4446  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4447  print '<option value="-1">&nbsp;</option>';
4448  }
4449  while ($i < $num) {
4450  $obj = $this->db->fetch_object($result);
4451  if ($selected == $obj->rowid) {
4452  print '<option value="'.$obj->rowid.'" selected>';
4453  } else {
4454  print '<option value="'.$obj->rowid.'">';
4455  }
4456  print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
4457  print '</option>';
4458  $i++;
4459  }
4460  print "</select>";
4461  if ($user->admin && empty($noinfoadmin)) {
4462  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4463  }
4464 
4465  print ajax_combobox('select'.$htmlname);
4466  } else {
4467  print $langs->trans("NoShippingMethodDefined");
4468  }
4469  } else {
4470  dol_print_error($this->db);
4471  }
4472  }
4473 
4483  public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4484  {
4485  global $langs;
4486 
4487  $langs->load("deliveries");
4488 
4489  if ($htmlname != "none") {
4490  print '<form method="POST" action="'.$page.'">';
4491  print '<input type="hidden" name="action" value="setshippingmethod">';
4492  print '<input type="hidden" name="token" value="'.newToken().'">';
4493  $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4494  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4495  print '</form>';
4496  } else {
4497  if ($selected) {
4498  $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4499  print $langs->trans("SendingMethod".strtoupper($code));
4500  } else {
4501  print "&nbsp;";
4502  }
4503  }
4504  }
4505 
4514  public function selectSituationInvoices($selected = '', $socid = 0)
4515  {
4516  global $langs;
4517 
4518  $langs->load('bills');
4519 
4520  $opt = '<option value="" selected></option>';
4521  $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4522  $sql .= ' FROM '.$this->db->prefix().'facture';
4523  $sql .= ' WHERE entity IN ('.getEntity('invoice').')';
4524  $sql .= ' AND situation_counter >= 1';
4525  $sql .= ' AND fk_soc = '.(int) $socid;
4526  $sql .= ' AND type <> 2';
4527  $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4528  $resql = $this->db->query($sql);
4529 
4530  if ($resql && $this->db->num_rows($resql) > 0) {
4531  // Last seen cycle
4532  $ref = 0;
4533  while ($obj = $this->db->fetch_object($resql)) {
4534  //Same cycle ?
4535  if ($obj->situation_cycle_ref != $ref) {
4536  // Just seen this cycle
4537  $ref = $obj->situation_cycle_ref;
4538  //not final ?
4539  if ($obj->situation_final != 1) {
4540  //Not prov?
4541  if (substr($obj->ref, 1, 4) != 'PROV') {
4542  if ($selected == $obj->rowid) {
4543  $opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
4544  } else {
4545  $opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
4546  }
4547  }
4548  }
4549  }
4550  }
4551  } else {
4552  dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
4553  }
4554  if ($opt == '<option value ="" selected></option>') {
4555  $opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
4556  }
4557  return $opt;
4558  }
4559 
4569  public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4570  {
4571  global $langs;
4572 
4573  $langs->load('products');
4574 
4575  $return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
4576 
4577  $sql = "SELECT rowid, label, code FROM ".$this->db->prefix()."c_units";
4578  $sql .= ' WHERE active > 0';
4579  if (!empty($unit_type)) {
4580  $sql .= " AND unit_type = '".$this->db->escape($unit_type)."'";
4581  }
4582  $sql .= " ORDER BY sortorder";
4583 
4584  $resql = $this->db->query($sql);
4585  if ($resql && $this->db->num_rows($resql) > 0) {
4586  if ($showempty) {
4587  $return .= '<option value="none"></option>';
4588  }
4589 
4590  while ($res = $this->db->fetch_object($resql)) {
4591  $unitLabel = $res->label;
4592  if (!empty($langs->tab_translate['unit'.$res->code])) { // check if Translation is available before
4593  $unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
4594  }
4595 
4596  if ($selected == $res->rowid) {
4597  $return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
4598  } else {
4599  $return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
4600  }
4601  }
4602  $return .= '</select>';
4603  }
4604  return $return;
4605  }
4606 
4607  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4622  public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4623  {
4624  // phpcs:enable
4625  global $langs, $conf;
4626 
4627  $out = '';
4628 
4629  $langs->load("admin");
4630  $num = 0;
4631 
4632  $sql = "SELECT rowid, label, bank, clos as status, currency_code";
4633  $sql .= " FROM ".$this->db->prefix()."bank_account";
4634  $sql .= " WHERE entity IN (".getEntity('bank_account').")";
4635  if ($status != 2) {
4636  $sql .= " AND clos = ".(int) $status;
4637  }
4638  if ($filtre) {
4639  $sql .= " AND ".$filtre;
4640  }
4641  $sql .= " ORDER BY label";
4642 
4643  dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
4644  $result = $this->db->query($sql);
4645  if ($result) {
4646  $num = $this->db->num_rows($result);
4647  $i = 0;
4648  if ($num) {
4649  $out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4650  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4651  $out .= '<option value="-1">&nbsp;</option>';
4652  }
4653 
4654  while ($i < $num) {
4655  $obj = $this->db->fetch_object($result);
4656  if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4657  $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'" selected>';
4658  } else {
4659  $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'">';
4660  }
4661  $out .= trim($obj->label);
4662  if ($showcurrency) {
4663  $out .= ' ('.$obj->currency_code.')';
4664  }
4665  if ($status == 2 && $obj->status == 1) {
4666  $out .= ' ('.$langs->trans("Closed").')';
4667  }
4668  $out .= '</option>';
4669  $i++;
4670  }
4671  $out .= "</select>";
4672  $out .= ajax_combobox('select'.$htmlname);
4673  } else {
4674  if ($status == 0) {
4675  $out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
4676  } else {
4677  $out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
4678  }
4679  }
4680  } else {
4681  dol_print_error($this->db);
4682  }
4683 
4684  // Output or return
4685  if (empty($nooutput)) {
4686  print $out;
4687  } else {
4688  return $out;
4689  }
4690 
4691  return $num;
4692  }
4693 
4705  public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4706  {
4707  global $langs, $conf;
4708 
4709  $langs->load("admin");
4710  $num = 0;
4711 
4712  $sql = "SELECT rowid, name, fk_country, status, entity";
4713  $sql .= " FROM ".$this->db->prefix()."establishment";
4714  $sql .= " WHERE 1=1";
4715  if ($status != 2) {
4716  $sql .= " AND status = ".(int) $status;
4717  }
4718  if ($filtre) {
4719  $sql .= " AND ".$filtre;
4720  }
4721  $sql .= " ORDER BY name";
4722 
4723  dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
4724  $result = $this->db->query($sql);
4725  if ($result) {
4726  $num = $this->db->num_rows($result);
4727  $i = 0;
4728  if ($num) {
4729  print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4730  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4731  print '<option value="-1">&nbsp;</option>';
4732  }
4733 
4734  while ($i < $num) {
4735  $obj = $this->db->fetch_object($result);
4736  if ($selected == $obj->rowid) {
4737  print '<option value="'.$obj->rowid.'" selected>';
4738  } else {
4739  print '<option value="'.$obj->rowid.'">';
4740  }
4741  print trim($obj->name);
4742  if ($status == 2 && $obj->status == 1) {
4743  print ' ('.$langs->trans("Closed").')';
4744  }
4745  print '</option>';
4746  $i++;
4747  }
4748  print "</select>";
4749  } else {
4750  if ($status == 0) {
4751  print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
4752  } else {
4753  print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
4754  }
4755  }
4756  } else {
4757  dol_print_error($this->db);
4758  }
4759  }
4760 
4770  public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4771  {
4772  global $langs;
4773  if ($htmlname != "none") {
4774  print '<form method="POST" action="'.$page.'">';
4775  print '<input type="hidden" name="action" value="setbankaccount">';
4776  print '<input type="hidden" name="token" value="'.newToken().'">';
4777  print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4778  $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4779  if ($nbaccountfound > 0) {
4780  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4781  }
4782  print '</form>';
4783  } else {
4784  $langs->load('banks');
4785 
4786  if ($selected) {
4787  require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
4788  $bankstatic = new Account($this->db);
4789  $result = $bankstatic->fetch($selected);
4790  if ($result) {
4791  print $bankstatic->getNomUrl(1);
4792  }
4793  } else {
4794  print "&nbsp;";
4795  }
4796  }
4797  }
4798 
4799  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4818  public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4819  {
4820  // phpcs:enable
4821  global $conf, $langs;
4822  $langs->load("categories");
4823 
4824  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4825 
4826  // For backward compatibility
4827  if (is_numeric($type)) {
4828  dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4829  }
4830 
4831  if ($type === Categorie::TYPE_BANK_LINE) {
4832  // TODO Move this into common category feature
4833  $cate_arbo = array();
4834  $sql = "SELECT c.label, c.rowid";
4835  $sql .= " FROM ".$this->db->prefix()."bank_categ as c";
4836  $sql .= " WHERE entity = ".$conf->entity;
4837  $sql .= " ORDER BY c.label";
4838  $result = $this->db->query($sql);
4839  if ($result) {
4840  $num = $this->db->num_rows($result);
4841  $i = 0;
4842  while ($i < $num) {
4843  $objp = $this->db->fetch_object($result);
4844  if ($objp) {
4845  $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
4846  }
4847  $i++;
4848  }
4849  $this->db->free($result);
4850  } else {
4851  dol_print_error($this->db);
4852  }
4853  } else {
4854  $cat = new Categorie($this->db);
4855  $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4856  }
4857 
4858  $output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4859  $outarray = array();
4860  if (is_array($cate_arbo)) {
4861  if (!count($cate_arbo)) {
4862  $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4863  } else {
4864  $output .= '<option value="-1">&nbsp;</option>';
4865  foreach ($cate_arbo as $key => $value) {
4866  if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
4867  $add = 'selected ';
4868  } else {
4869  $add = '';
4870  }
4871  $output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>';
4872 
4873  $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4874  }
4875  }
4876  }
4877  $output .= '</select>';
4878  $output .= "\n";
4879 
4880  if ($outputmode) {
4881  return $outarray;
4882  }
4883  return $output;
4884  }
4885 
4886  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4903  public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4904  {
4905  // phpcs:enable
4906  dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4907  print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4908  }
4909 
4936  public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
4937  {
4938  global $langs, $conf;
4939 
4940  $more = '<!-- formconfirm before calling page='.dol_escape_htmltag($page).' -->';
4941  $formconfirm = '';
4942  $inputok = array();
4943  $inputko = array();
4944 
4945  // Clean parameters
4946  $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
4947  if ($conf->browser->layout == 'phone') {
4948  $width = '95%';
4949  }
4950 
4951  // Set height automatically if not defined
4952  if (empty($height)) {
4953  $height = 220;
4954  if (is_array($formquestion) && count($formquestion) > 2) {
4955  $height += ((count($formquestion) - 2) * 24);
4956  }
4957  }
4958 
4959  if (is_array($formquestion) && !empty($formquestion)) {
4960  // First add hidden fields and value
4961  foreach ($formquestion as $key => $input) {
4962  if (is_array($input) && !empty($input)) {
4963  if ($input['type'] == 'hidden') {
4964  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4965  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4966 
4967  $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";
4968  }
4969  }
4970  }
4971 
4972  // Now add questions
4973  $moreonecolumn = '';
4974  $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
4975  foreach ($formquestion as $key => $input) {
4976  if (is_array($input) && !empty($input)) {
4977  $size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : ''); // deprecated. Use morecss instead.
4978  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4979  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4980 
4981  if ($input['type'] == 'text') {
4982  $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="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4983  } elseif ($input['type'] == 'password') {
4984  $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="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4985  } elseif ($input['type'] == 'textarea') {
4986  /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
4987  $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
4988  $more .= $input['value'];
4989  $more .= '</textarea>';
4990  $more .= '</div></div>'."\n";*/
4991  $moreonecolumn .= '<div class="margintoponly">';
4992  $moreonecolumn .= $input['label'].'<br>';
4993  $moreonecolumn .= '<textarea name="'.dol_escape_htmltag($input['name']).'" id="'.dol_escape_htmltag($input['name']).'" class="'.$morecss.'"'.$moreattr.'>';
4994  $moreonecolumn .= $input['value'];
4995  $moreonecolumn .= '</textarea>';
4996  $moreonecolumn .= '</div>';
4997  } elseif ($input['type'] == 'select') {
4998  if (empty($morecss)) {
4999  $morecss = 'minwidth100';
5000  }
5001 
5002  $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5003  $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5004  $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5005  $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5006  $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5007  $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5008  $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5009 
5010  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5011  if (!empty($input['label'])) {
5012  $more .= $input['label'].'</div><div class="tagtd left">';
5013  }
5014  $more .= $this->selectarray($input['name'], $input['values'], isset($input['default'])?$input['default']:'', $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
5015  $more .= '</div></div>'."\n";
5016  } elseif ($input['type'] == 'checkbox') {
5017  $more .= '<div class="tagtr">';
5018  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
5019  $more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$moreattr;
5020  if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5021  $more .= ' checked';
5022  }
5023  if (is_bool($input['value']) && $input['value']) {
5024  $more .= ' checked';
5025  }
5026  if (isset($input['disabled'])) {
5027  $more .= ' disabled';
5028  }
5029  $more .= ' /></div>';
5030  $more .= '</div>'."\n";
5031  } elseif ($input['type'] == 'radio') {
5032  $i = 0;
5033  foreach ($input['values'] as $selkey => $selval) {
5034  $more .= '<div class="tagtr">';
5035  if ($i == 0) {
5036  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
5037  } else {
5038  $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
5039  }
5040  $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;
5041  if (!empty($input['disabled'])) {
5042  $more .= ' disabled';
5043  }
5044  if (isset($input['default']) && $input['default'] === $selkey) {
5045  $more .= ' checked="checked"';
5046  }
5047  $more .= ' /> ';
5048  $more .= '<label for="'.dol_escape_htmltag($input['name'].$selkey).'" class="valignmiddle">'.$selval.'</label>';
5049  $more .= '</div></div>'."\n";
5050  $i++;
5051  }
5052  } elseif ($input['type'] == 'date') {
5053  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
5054  $more .= '<div class="tagtd">';
5055  $addnowlink = (empty($input['datenow']) ? 0 : 1);
5056  $more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, $addnowlink);
5057  $more .= '</div></div>'."\n";
5058  $formquestion[] = array('name'=>$input['name'].'day');
5059  $formquestion[] = array('name'=>$input['name'].'month');
5060  $formquestion[] = array('name'=>$input['name'].'year');
5061  $formquestion[] = array('name'=>$input['name'].'hour');
5062  $formquestion[] = array('name'=>$input['name'].'min');
5063  } elseif ($input['type'] == 'other') {
5064  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5065  if (!empty($input['label'])) {
5066  $more .= $input['label'].'</div><div class="tagtd">';
5067  }
5068  $more .= $input['value'];
5069  $more .= '</div></div>'."\n";
5070  } elseif ($input['type'] == 'onecolumn') {
5071  $moreonecolumn .= '<div class="margintoponly">';
5072  $moreonecolumn .= $input['value'];
5073  $moreonecolumn .= '</div>'."\n";
5074  } elseif ($input['type'] == 'hidden') {
5075  // Do nothing more, already added by a previous loop
5076  } elseif ($input['type'] == 'separator') {
5077  $more .= '<br>';
5078  } else {
5079  $more .= 'Error type '.$input['type'].' for the confirm box is not a supported type';
5080  }
5081  }
5082  }
5083  $more .= '</div>'."\n";
5084  $more .= $moreonecolumn;
5085  }
5086 
5087  // JQUERY method dialog is broken with smartphone, we use standard HTML.
5088  // 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
5089  // See page product/card.php for example
5090  if (!empty($conf->dol_use_jmobile)) {
5091  $useajax = 0;
5092  }
5093  if (empty($conf->use_javascript_ajax)) {
5094  $useajax = 0;
5095  }
5096 
5097  if ($useajax) {
5098  $autoOpen = true;
5099  $dialogconfirm = 'dialog-confirm';
5100  $button = '';
5101  if (!is_numeric($useajax)) {
5102  $button = $useajax;
5103  $useajax = 1;
5104  $autoOpen = false;
5105  $dialogconfirm .= '-'.$button;
5106  }
5107  $pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.urlencode($action).'&confirm=yes';
5108  $pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.urlencode($action).'&confirm=no' : '');
5109 
5110  // Add input fields into list of fields to read during submit (inputok and inputko)
5111  if (is_array($formquestion)) {
5112  foreach ($formquestion as $key => $input) {
5113  //print "xx ".$key." rr ".is_array($input)."<br>\n";
5114  // Add name of fields to propagate with the GET when submitting the form with button OK.
5115  if (is_array($input) && isset($input['name'])) {
5116  if (strpos($input['name'], ',') > 0) {
5117  $inputok = array_merge($inputok, explode(',', $input['name']));
5118  } else {
5119  array_push($inputok, $input['name']);
5120  }
5121  }
5122  // Add name of fields to propagate with the GET when submitting the form with button KO.
5123  if (isset($input['inputko']) && $input['inputko'] == 1) {
5124  array_push($inputko, $input['name']);
5125  }
5126  }
5127  }
5128 
5129  // Show JQuery confirm box.
5130  $formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
5131  if (is_array($formquestion) && !empty($formquestion['text'])) {
5132  $formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
5133  }
5134  if (!empty($more)) {
5135  $formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
5136  }
5137  $formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
5138  $formconfirm .= '</div>'."\n";
5139 
5140  $formconfirm .= "\n<!-- begin code of popup for formconfirm page=".$page." -->\n";
5141  $formconfirm .= '<script type="text/javascript">'."\n";
5142  $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5143  $formconfirm .= 'jQuery(document).ready(function() {
5144  $(function() {
5145  $( "#'.$dialogconfirm.'" ).dialog(
5146  {
5147  autoOpen: '.($autoOpen ? "true" : "false").',';
5148  if ($newselectedchoice == 'no') {
5149  $formconfirm .= '
5150  open: function() {
5151  $(this).parent().find("button.ui-button:eq(2)").focus();
5152  },';
5153  }
5154 
5155  $jsforcursor = '';
5156  if (empty($useajax)) {
5157  $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor'."\n";
5158  $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");'."\n";
5159  }
5160 
5161  $formconfirm .= '
5162  resizable: false,
5163  height: "'.$height.'",
5164  width: "'.$width.'",
5165  modal: true,
5166  closeOnEscape: false,
5167  buttons: {
5168  "'.dol_escape_js($langs->transnoentities($labelbuttonyes)).'": function() {
5169  var options = "&token='.urlencode(newToken()).'";
5170  var inputok = '.json_encode($inputok).'; /* List of fields into form */
5171  var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
5172 
5173  if (inputok.length > 0) {
5174  $.each(inputok, function(i, inputname) {
5175  var more = "";
5176  var inputvalue;
5177  if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5178  inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5179  } else {
5180  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5181  inputvalue = $("#" + inputname + more).val();
5182  }
5183  if (typeof inputvalue == "undefined") { inputvalue=""; }
5184  console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5185  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5186  });
5187  }
5188  var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
5189  if (pageyes.length > 0) {
5190  '.$jsforcursor.'
5191  location.href = urljump;
5192  console.log("after location.href");
5193  }
5194  $(this).dialog("close");
5195  },
5196  "'.dol_escape_js($langs->transnoentities($labelbuttonno)).'": function() {
5197  var options = "&token='.urlencode(newToken()).'";
5198  var inputko = '.json_encode($inputko).'; /* List of fields into form */
5199  var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
5200  if (inputko.length > 0) {
5201  $.each(inputko, function(i, inputname) {
5202  var more = "";
5203  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5204  var inputvalue = $("#" + inputname + more).val();
5205  if (typeof inputvalue == "undefined") { inputvalue=""; }
5206  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5207  });
5208  }
5209  var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
5210  //alert(urljump);
5211  if (pageno.length > 0) {
5212  '.$jsforcursor.'
5213  location.href = urljump;
5214  console.log("after location.href");
5215  }
5216  $(this).dialog("close");
5217  }
5218  }
5219  }
5220  );
5221 
5222  var button = "'.$button.'";
5223  if (button.length > 0) {
5224  $( "#" + button ).click(function() {
5225  $("#'.$dialogconfirm.'").dialog("open");
5226  });
5227  }
5228  });
5229  });
5230  </script>';
5231  $formconfirm .= "<!-- end ajax formconfirm -->\n";
5232  } else {
5233  $formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n";
5234 
5235  if (empty($disableformtag)) {
5236  $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
5237  }
5238 
5239  $formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
5240  $formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
5241 
5242  $formconfirm .= '<table class="valid centpercent">'."\n";
5243 
5244  // Line title
5245  $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5246  $formconfirm .= img_picto('', 'recent').' '.$title;
5247  $formconfirm .= '</td></tr>'."\n";
5248 
5249  // Line text
5250  if (is_array($formquestion) && !empty($formquestion['text'])) {
5251  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
5252  }
5253 
5254  // Line form fields
5255  if ($more) {
5256  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'."\n";
5257  $formconfirm .= $more;
5258  $formconfirm .= '</td></tr>'."\n";
5259  }
5260 
5261  // Line with question
5262  $formconfirm .= '<tr class="valid">';
5263  $formconfirm .= '<td class="valid">'.$question.'</td>';
5264  $formconfirm .= '<td class="valid center">';
5265  $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5266  $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="'.$langs->trans("Validate").'">';
5267  $formconfirm .= '</td>';
5268  $formconfirm .= '</tr>'."\n";
5269 
5270  $formconfirm .= '</table>'."\n";
5271 
5272  if (empty($disableformtag)) {
5273  $formconfirm .= "</form>\n";
5274  }
5275  $formconfirm .= '<br>';
5276 
5277  if (!empty($conf->use_javascript_ajax)) {
5278  $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5279  $formconfirm .= '<script type="text/javascript">'."\n";
5280  $formconfirm .= '
5281  $(document).ready(function () {
5282  $(".confirmvalidatebutton").on("click", function() {
5283  console.log("We click on button");
5284  $(this).attr("disabled", "disabled");
5285  setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5286  //console.log($(this).closest("form"));
5287  $(this).closest("form").submit();
5288  });
5289  });
5290  ';
5291  $formconfirm .= '</script>'."\n";
5292  }
5293 
5294  $formconfirm .= "<!-- end formconfirm -->\n";
5295  }
5296 
5297  return $formconfirm;
5298  }
5299 
5300 
5301  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5315  public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0)
5316  {
5317  // phpcs:enable
5318  global $langs;
5319 
5320  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
5321  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
5322 
5323  $out = '';
5324 
5325  $formproject = new FormProjets($this->db);
5326 
5327  $langs->load("project");
5328  if ($htmlname != "none") {
5329  $out .= "\n";
5330  $out .= '<form method="post" action="'.$page.'">';
5331  $out .= '<input type="hidden" name="action" value="classin">';
5332  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5333  $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
5334  $out .= '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5335  $out .= '</form>';
5336  } else {
5337  $out .= '<span class="project_head_block">';
5338  if ($selected) {
5339  $projet = new Project($this->db);
5340  $projet->fetch($selected);
5341  $out .= $projet->getNomUrl(1, '', 1);
5342  } else {
5343  $out .= "&nbsp;";
5344  }
5345  $out .= '</span>';
5346  }
5347 
5348  if (empty($nooutput)) {
5349  print $out;
5350  return '';
5351  }
5352  return $out;
5353  }
5354 
5355  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5370  public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1)
5371  {
5372  // phpcs:enable
5373  global $langs;
5374  if ($htmlname != "none") {
5375  print '<form method="POST" action="'.$page.'">';
5376  print '<input type="hidden" name="action" value="setconditions">';
5377  print '<input type="hidden" name="token" value="'.newToken().'">';
5378  if ($type) {
5379  print '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5380  }
5381  $this->select_conditions_paiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5382  print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
5383  print '</form>';
5384  } else {
5385  if ($selected) {
5387  if (isset($this->cache_conditions_paiements[$selected])) {
5388  $label = $this->cache_conditions_paiements[$selected]['label'];
5389 
5390  if (! empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5391  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5392  }
5393 
5394  print $label;
5395  } else {
5396  $langs->load('errors');
5397  print $langs->trans('ErrorNotInDictionaryPaymentConditions');
5398  }
5399  } else {
5400  print "&nbsp;";
5401  }
5402  }
5403  }
5404 
5405  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5415  public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5416  {
5417  // phpcs:enable
5418  global $langs;
5419  if ($htmlname != "none") {
5420  print '<form method="post" action="'.$page.'">';
5421  print '<input type="hidden" name="action" value="setavailability">';
5422  print '<input type="hidden" name="token" value="'.newToken().'">';
5423  $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5424  print '<input type="submit" name="modify" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5425  print '<input type="submit" name="cancel" class="button smallpaddingimp" value="'.$langs->trans("Cancel").'">';
5426  print '</form>';
5427  } else {
5428  if ($selected) {
5429  $this->load_cache_availability();
5430  print $this->cache_availability[$selected]['label'];
5431  } else {
5432  print "&nbsp;";
5433  }
5434  }
5435  }
5436 
5447  public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5448  {
5449  global $langs;
5450  if ($htmlname != "none") {
5451  print '<form method="post" action="'.$page.'">';
5452  print '<input type="hidden" name="action" value="setdemandreason">';
5453  print '<input type="hidden" name="token" value="'.newToken().'">';
5454  $this->selectInputReason($selected, $htmlname, -1, $addempty);
5455  print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5456  print '</form>';
5457  } else {
5458  if ($selected) {
5459  $this->loadCacheInputReason();
5460  foreach ($this->cache_demand_reason as $key => $val) {
5461  if ($val['id'] == $selected) {
5462  print $val['label'];
5463  break;
5464  }
5465  }
5466  } else {
5467  print "&nbsp;";
5468  }
5469  }
5470  }
5471 
5472  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5486  public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
5487  {
5488  // phpcs:enable
5489  global $langs;
5490 
5491  $ret = '';
5492 
5493  if ($htmlname != "none") {
5494  $ret .= '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5495  $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
5496  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
5497  if ($type) {
5498  $ret .= '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5499  }
5500  $ret .= '<table class="nobordernopadding">';
5501  $ret .= '<tr><td>';
5502  $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
5503  $ret .= '</td>';
5504  $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5505  $ret .= '</tr></table></form>';
5506  } else {
5507  if ($displayhour) {
5508  $ret .= dol_print_date($selected, 'dayhour');
5509  } else {
5510  $ret .= dol_print_date($selected, 'day');
5511  }
5512  }
5513 
5514  if (empty($nooutput)) {
5515  print $ret;
5516  }
5517  return $ret;
5518  }
5519 
5520 
5521  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5532  public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
5533  {
5534  // phpcs:enable
5535  global $langs;
5536 
5537  if ($htmlname != "none") {
5538  print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5539  print '<input type="hidden" name="action" value="set'.$htmlname.'">';
5540  print '<input type="hidden" name="token" value="'.newToken().'">';
5541  print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5542  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5543  print '</form>';
5544  } else {
5545  if ($selected) {
5546  require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
5547  $theuser = new User($this->db);
5548  $theuser->fetch($selected);
5549  print $theuser->getNomUrl(1);
5550  } else {
5551  print "&nbsp;";
5552  }
5553  }
5554  }
5555 
5556 
5557  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5570  public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '')
5571  {
5572  // phpcs:enable
5573  global $langs;
5574  if ($htmlname != "none") {
5575  print '<form method="POST" action="'.$page.'">';
5576  print '<input type="hidden" name="action" value="setmode">';
5577  print '<input type="hidden" name="token" value="'.newToken().'">';
5578  if ($type) {
5579  print '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5580  }
5581  print $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
5582  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5583  print '</form>';
5584  } else {
5585  if ($selected) {
5586  $this->load_cache_types_paiements();
5587  print $this->cache_types_paiements[$selected]['label'];
5588  } else {
5589  print "&nbsp;";
5590  }
5591  }
5592  }
5593 
5604  public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5605  {
5606  global $langs;
5607  if ($htmlname != "none") {
5608  print '<form method="POST" action="'.$page.'">';
5609  print '<input type="hidden" name="action" value="settransportmode">';
5610  print '<input type="hidden" name="token" value="'.newToken().'">';
5611  $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5612  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5613  print '</form>';
5614  } else {
5615  if ($selected) {
5616  $this->load_cache_transport_mode();
5617  print $this->cache_transport_mode[$selected]['label'];
5618  } else {
5619  print "&nbsp;";
5620  }
5621  }
5622  }
5623 
5624  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5633  public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5634  {
5635  // phpcs:enable
5636  global $langs;
5637  if ($htmlname != "none") {
5638  print '<form method="POST" action="'.$page.'">';
5639  print '<input type="hidden" name="action" value="setmulticurrencycode">';
5640  print '<input type="hidden" name="token" value="'.newToken().'">';
5641  print $this->selectMultiCurrency($selected, $htmlname, 0);
5642  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5643  print '</form>';
5644  } else {
5645  dol_include_once('/core/lib/company.lib.php');
5646  print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5647  }
5648  }
5649 
5650  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5660  public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5661  {
5662  // phpcs:enable
5663  global $langs, $mysoc, $conf;
5664 
5665  if ($htmlname != "none") {
5666  print '<form method="POST" action="'.$page.'">';
5667  print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5668  print '<input type="hidden" name="token" value="'.newToken().'">';
5669  print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> ';
5670  print '<select name="calculation_mode">';
5671  print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>';
5672  print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>';
5673  print '</select> ';
5674  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5675  print '</form>';
5676  } else {
5677  if (!empty($rate)) {
5678  print price($rate, 1, $langs, 1, 0);
5679  if ($currency && $rate != 1) {
5680  print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
5681  }
5682  } else {
5683  print 1;
5684  }
5685  }
5686  }
5687 
5688 
5689  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5705  public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5706  {
5707  // phpcs:enable
5708  global $conf, $langs;
5709  if ($htmlname != "none") {
5710  print '<form method="post" action="'.$page.'">';
5711  print '<input type="hidden" name="action" value="setabsolutediscount">';
5712  print '<input type="hidden" name="token" value="'.newToken().'">';
5713  print '<div class="inline-block">';
5714  if (!empty($discount_type)) {
5715  if (!empty($conf->global->FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS)) {
5716  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5717  $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5718  } else {
5719  $translationKey = 'HasCreditNoteFromSupplier';
5720  }
5721  } else {
5722  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5723  $translationKey = 'HasAbsoluteDiscountFromSupplier';
5724  } else {
5725  $translationKey = 'HasCreditNoteFromSupplier';
5726  }
5727  }
5728  } else {
5729  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5730  if (!$filter || $filter == "fk_facture_source IS NULL") {
5731  $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
5732  } else {
5733  $translationKey = 'CompanyHasCreditNote';
5734  }
5735  } else {
5736  if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5737  $translationKey = 'CompanyHasAbsoluteDiscount';
5738  } else {
5739  $translationKey = 'CompanyHasCreditNote';
5740  }
5741  }
5742  }
5743  print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
5744  if (empty($hidelist)) {
5745  print ' ';
5746  }
5747  print '</div>';
5748  if (empty($hidelist)) {
5749  print '<div class="inline-block" style="padding-right: 10px">';
5750  $newfilter = 'discount_type='.intval($discount_type);
5751  if (!empty($discount_type)) {
5752  $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
5753  } else {
5754  $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
5755  }
5756  if ($filter) {
5757  $newfilter .= ' AND ('.$filter.')';
5758  }
5759  // output the combo of discounts
5760  $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
5761  if ($nbqualifiedlines > 0) {
5762  print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
5763  if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5764  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5765  }
5766  if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5767  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5768  }
5769 
5770  print '>';
5771  }
5772  print '</div>';
5773  }
5774  if ($more) {
5775  print '<div class="inline-block">';
5776  print $more;
5777  print '</div>';
5778  }
5779  print '</form>';
5780  } else {
5781  if ($selected) {
5782  print $selected;
5783  } else {
5784  print "0";
5785  }
5786  }
5787  }
5788 
5789 
5790  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5800  public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
5801  {
5802  // phpcs:enable
5803  global $langs, $conf;
5804 
5805  if ($htmlname != "none") {
5806  print '<form method="post" action="'.$page.'">';
5807  print '<input type="hidden" name="action" value="set_contact">';
5808  print '<input type="hidden" name="token" value="'.newToken().'">';
5809  print '<table class="nobordernopadding">';
5810  print '<tr><td>';
5811  print $this->selectcontacts($societe->id, $selected, $htmlname);
5812  $num = $this->num;
5813  if ($num == 0) {
5814  $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
5815  print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
5816  }
5817  print '</td>';
5818  print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5819  print '</tr></table></form>';
5820  } else {
5821  if ($selected) {
5822  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
5823  $contact = new Contact($this->db);
5824  $contact->fetch($selected);
5825  print $contact->getFullName($langs);
5826  } else {
5827  print "&nbsp;";
5828  }
5829  }
5830  }
5831 
5832  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5848  public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array())
5849  {
5850  // phpcs:enable
5851  global $langs;
5852 
5853  $out = '';
5854  if ($htmlname != "none") {
5855  $out .= '<form method="post" action="'.$page.'">';
5856  $out .= '<input type="hidden" name="action" value="set_thirdparty">';
5857  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5858  $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
5859  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5860  $out .= '</form>';
5861  } else {
5862  if ($selected) {
5863  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
5864  $soc = new Societe($this->db);
5865  $soc->fetch($selected);
5866  $out .= $soc->getNomUrl($langs);
5867  } else {
5868  $out .= "&nbsp;";
5869  }
5870  }
5871 
5872  if ($nooutput) {
5873  return $out;
5874  } else {
5875  print $out;
5876  }
5877  }
5878 
5879  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5888  public function select_currency($selected = '', $htmlname = 'currency_id')
5889  {
5890  // phpcs:enable
5891  print $this->selectCurrency($selected, $htmlname);
5892  }
5893 
5903  public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
5904  {
5905  global $conf, $langs, $user;
5906 
5907  $langs->loadCacheCurrencies('');
5908 
5909  $out = '';
5910 
5911  if ($selected == 'euro' || $selected == 'euros') {
5912  $selected = 'EUR'; // Pour compatibilite
5913  }
5914 
5915  $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
5916  if ($useempty) {
5917  $out .= '<option value="-1" selected></option>';
5918  }
5919  foreach ($langs->cache_currencies as $code_iso => $currency) {
5920  $labeltoshow = $currency['label'];
5921  if ($mode == 1) {
5922  $labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>';
5923  } else {
5924  $labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>';
5925  }
5926 
5927  if ($selected && $selected == $code_iso) {
5928  $out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
5929  } else {
5930  $out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
5931  }
5932  $out .= $labeltoshow;
5933  $out .= '</option>';
5934  }
5935  $out .= '</select>';
5936  if ($user->admin) {
5937  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5938  }
5939 
5940  // Make select dynamic
5941  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5942  $out .= ajax_combobox($htmlname);
5943 
5944  return $out;
5945  }
5946 
5959  public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
5960  {
5961  global $conf, $langs;
5962 
5963  $langs->loadCacheCurrencies(''); // Load ->cache_currencies
5964 
5965  $TCurrency = array();
5966 
5967  $sql = "SELECT code FROM ".$this->db->prefix()."multicurrency";
5968  $sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
5969  if ($filter) {
5970  $sql .= " AND ".$filter;
5971  }
5972  $resql = $this->db->query($sql);
5973  if ($resql) {
5974  while ($obj = $this->db->fetch_object($resql)) {
5975  $TCurrency[$obj->code] = $obj->code;
5976  }
5977  }
5978 
5979  $out = '';
5980  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
5981  if ($useempty) {
5982  $out .= '<option value="">&nbsp;</option>';
5983  }
5984  // If company current currency not in table, we add it into list. Should always be available.
5985  if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
5986  $TCurrency[$conf->currency] = $conf->currency;
5987  }
5988  if (count($TCurrency) > 0) {
5989  foreach ($langs->cache_currencies as $code_iso => $currency) {
5990  if (isset($TCurrency[$code_iso])) {
5991  if (!empty($selected) && $selected == $code_iso) {
5992  $out .= '<option value="'.$code_iso.'" selected="selected">';
5993  } else {
5994  $out .= '<option value="'.$code_iso.'">';
5995  }
5996 
5997  $out .= $currency['label'];
5998  $out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5999  $out .= '</option>';
6000  }
6001  }
6002  }
6003 
6004  $out .= '</select>';
6005 
6006  // Make select dynamic
6007  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6008  $out .= ajax_combobox($htmlname);
6009 
6010  return $out;
6011  }
6012 
6013  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6020  public function load_cache_vatrates($country_code)
6021  {
6022  // phpcs:enable
6023  global $langs;
6024 
6025  $num = count($this->cache_vatrates);
6026  if ($num > 0) {
6027  return $num; // Cache already loaded
6028  }
6029 
6030  dol_syslog(__METHOD__, LOG_DEBUG);
6031 
6032  $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6033  $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6034  $sql .= " WHERE t.fk_pays = c.rowid";
6035  $sql .= " AND t.active > 0";
6036  $sql .= " AND c.code IN (".$this->db->sanitize($country_code, 1).")";
6037  $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6038 
6039  $resql = $this->db->query($sql);
6040  if ($resql) {
6041  $num = $this->db->num_rows($resql);
6042  if ($num) {
6043  for ($i = 0; $i < $num; $i++) {
6044  $obj = $this->db->fetch_object($resql);
6045  $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
6046  $this->cache_vatrates[$i]['code'] = $obj->code;
6047  $this->cache_vatrates[$i]['txtva'] = $obj->taux;
6048  $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
6049  $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
6050  $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
6051  $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
6052  $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
6053 
6054  $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
6055  $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
6056  $positiverates = '';
6057  if ($obj->taux) {
6058  $positiverates .= ($positiverates ? '/' : '').$obj->taux;
6059  }
6060  if ($obj->localtax1) {
6061  $positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
6062  }
6063  if ($obj->localtax2) {
6064  $positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
6065  }
6066  if (empty($positiverates)) {
6067  $positiverates = '0';
6068  }
6069  $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
6070  }
6071 
6072  return $num;
6073  } else {
6074  $this->error = '<span class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</span>';
6075  return -1;
6076  }
6077  } else {
6078  $this->error = '<span class="error">'.$this->db->error().'</span>';
6079  return -2;
6080  }
6081  }
6082 
6083  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6105  public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
6106  {
6107  // phpcs:enable
6108  global $langs, $conf, $mysoc;
6109 
6110  $langs->load('errors');
6111 
6112  $return = '';
6113 
6114  // Define defaultnpr, defaultttx and defaultcode
6115  $defaultnpr = ($info_bits & 0x01);
6116  $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6117  $defaulttx = str_replace('*', '', $selectedrate);
6118  $defaultcode = '';
6119  $reg = array();
6120  if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
6121  $defaultcode = $reg[1];
6122  $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
6123  }
6124  //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6125 
6126  // Check parameters
6127  if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6128  if ($societe_vendeuse->id == $mysoc->id) {
6129  $return .= '<span class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</span>';
6130  } else {
6131  $return .= '<span class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</span>';
6132  }
6133  return $return;
6134  }
6135 
6136  //var_dump($societe_acheteuse);
6137  //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";
6138  //exit;
6139 
6140  // Define list of countries to use to search VAT rates to show
6141  // First we defined code_country to use to find list
6142  if (is_object($societe_vendeuse)) {
6143  $code_country = "'".$societe_vendeuse->country_code."'";
6144  } else {
6145  $code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
6146  }
6147  if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) { // If option to have vat for end customer for services is on
6148  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6149  if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
6150  // We also add the buyer
6151  if (is_numeric($type)) {
6152  if ($type == 1) { // We know product is a service
6153  $code_country .= ",'".$societe_acheteuse->country_code."'";
6154  }
6155  } elseif (!$idprod) { // We don't know type of product
6156  $code_country .= ",'".$societe_acheteuse->country_code."'";
6157  } else {
6158  $prodstatic = new Product($this->db);
6159  $prodstatic->fetch($idprod);
6160  if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6161  $code_country .= ",'".$societe_acheteuse->country_code."'";
6162  }
6163  }
6164  }
6165  }
6166 
6167  // Now we get list
6168  $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6169 
6170  if ($num > 0) {
6171  // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6172  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6173  $tmpthirdparty = new Societe($this->db);
6174  $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6175  $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6176  if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
6177  $defaultcode = $reg[1];
6178  $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
6179  }
6180  if (empty($defaulttx)) {
6181  $defaultnpr = 0;
6182  }
6183  }
6184 
6185  // Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
6186  // Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
6187  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6188  if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6189  $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
6190  } else {
6191  $defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
6192  }
6193  }
6194 
6195  // Disabled if seller is not subject to VAT
6196  $disabled = false;
6197  $title = '';
6198  if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6199  // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6200  // of using supplier invoices (this is a very bad idea !)
6201  if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
6202  $title = ' title="'.$langs->trans('VATIsNotUsed').'"';
6203  $disabled = true;
6204  }
6205  }
6206 
6207  if (!$options_only) {
6208  $return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
6209  }
6210 
6211  $selectedfound = false;
6212  foreach ($this->cache_vatrates as $rate) {
6213  // Keep only 0 if seller is not subject to VAT
6214  if ($disabled && $rate['txtva'] != 0) {
6215  continue;
6216  }
6217 
6218  // Define key to use into select list
6219  $key = $rate['txtva'];
6220  $key .= $rate['nprtva'] ? '*' : '';
6221  if ($mode > 0 && $rate['code']) {
6222  $key .= ' ('.$rate['code'].')';
6223  }
6224  if ($mode < 0) {
6225  $key = $rate['rowid'];
6226  }
6227 
6228  $return .= '<option value="'.$key.'"';
6229  if (!$selectedfound) {
6230  if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6231  if ($defaultcode == $rate['code']) {
6232  $return .= ' selected';
6233  $selectedfound = true;
6234  }
6235  } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6236  $return .= ' selected';
6237  $selectedfound = true;
6238  }
6239  }
6240  $return .= '>';
6241  //if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
6242  if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
6243  $return .= $rate['labelpositiverates'];
6244  } else {
6245  $return .= vatrate($rate['label']);
6246  }
6247  //$return.=($rate['code']?' '.$rate['code']:'');
6248  $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6249 
6250  $return .= '</option>';
6251  }
6252 
6253  if (!$options_only) {
6254  $return .= '</select>';
6255  }
6256  } else {
6257  $return .= $this->error;
6258  }
6259 
6260  $this->num = $num;
6261  return $return;
6262  }
6263 
6264 
6265  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6290  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 = '')
6291  {
6292  // phpcs:enable
6293  $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6294  if (!empty($nooutput)) {
6295  return $retstring;
6296  }
6297  print $retstring;
6298  return;
6299  }
6300 
6316  public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6317  {
6318  global $langs;
6319 
6320  $ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6321  if ($forcenewline) {
6322  $ret .= '<br>';
6323  }
6324  $ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6325  return $ret;
6326  }
6327 
6355  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')
6356  {
6357  global $conf, $langs;
6358 
6359  if ($gm === 'auto') {
6360  $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6361  }
6362 
6363  $retstring = '';
6364 
6365  if ($prefix == '') {
6366  $prefix = 're';
6367  }
6368  if ($h == '') {
6369  $h = 0;
6370  }
6371  if ($m == '') {
6372  $m = 0;
6373  }
6374  $emptydate = 0;
6375  $emptyhours = 0;
6376  if ($stepminutes <= 0 || $stepminutes > 30) {
6377  $stepminutes = 1;
6378  }
6379  if ($empty == 1) {
6380  $emptydate = 1;
6381  $emptyhours = 1;
6382  }
6383  if ($empty == 2) {
6384  $emptydate = 0;
6385  $emptyhours = 1;
6386  }
6387  $orig_set_time = $set_time;
6388 
6389  if ($set_time === '' && $emptydate == 0) {
6390  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6391  if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6392  $set_time = dol_now($gm);
6393  } else {
6394  $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6395  }
6396  }
6397 
6398  // Analysis of the pre-selection date
6399  $reg = array();
6400  $shour = '';
6401  $smin = '';
6402  $ssec = '';
6403  if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
6404  // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6405  $syear = (!empty($reg[1]) ? $reg[1] : '');
6406  $smonth = (!empty($reg[2]) ? $reg[2] : '');
6407  $sday = (!empty($reg[3]) ? $reg[3] : '');
6408  $shour = (!empty($reg[4]) ? $reg[4] : '');
6409  $smin = (!empty($reg[5]) ? $reg[5] : '');
6410  } elseif (strval($set_time) != '' && $set_time != -1) {
6411  // set_time est un timestamps (0 possible)
6412  $syear = dol_print_date($set_time, "%Y", $gm);
6413  $smonth = dol_print_date($set_time, "%m", $gm);
6414  $sday = dol_print_date($set_time, "%d", $gm);
6415  if ($orig_set_time != '') {
6416  $shour = dol_print_date($set_time, "%H", $gm);
6417  $smin = dol_print_date($set_time, "%M", $gm);
6418  $ssec = dol_print_date($set_time, "%S", $gm);
6419  }
6420  } else {
6421  // Date est '' ou vaut -1
6422  $syear = '';
6423  $smonth = '';
6424  $sday = '';
6425  $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6426  $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6427  $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6428  }
6429  if ($h == 3) {
6430  $shour = '';
6431  }
6432  if ($m == 3) {
6433  $smin = '';
6434  }
6435 
6436  $nowgmt = dol_now('gmt');
6437  //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6438 
6439  // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6440  $usecalendar = 'combo';
6441  if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6442  $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6443  }
6444 
6445  if ($d) {
6446  // Show date with popup
6447  if ($usecalendar != 'combo') {
6448  $formated_date = '';
6449  //print "e".$set_time." t ".$conf->format_date_short;
6450  if (strval($set_time) != '' && $set_time != -1) {
6451  //$formated_date=dol_print_date($set_time,$conf->format_date_short);
6452  $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6453  }
6454 
6455  // Calendrier popup version eldy
6456  if ($usecalendar == "eldy") {
6457  // Input area to enter date manually
6458  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6459  $retstring .= ($disabled ? ' disabled' : '');
6460  $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6461  $retstring .= '>';
6462 
6463  // Icon calendar
6464  $retstringbuttom = '';
6465  if (!$disabled) {
6466  $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
6467  $base = DOL_URL_ROOT.'/core/';
6468  $retstringbuttom .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
6469  $retstringbuttom .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
6470  } else {
6471  $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6472  }
6473  $retstring = $retstringbuttom.$retstring;
6474 
6475  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
6476  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6477  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
6478  } elseif ($usecalendar == 'jquery') {
6479  if (!$disabled) {
6480  // Output javascript for datepicker
6481  $minYear = getDolGlobalString('MIN_YEAR_SELECT_DATE', date('Y') - 100);
6482  $maxYear = getDolGlobalString('MAX_YEAR_SELECT_DATE', date('Y') + 100);
6483 
6484  $retstring .= "<script type='text/javascript'>";
6485  $retstring .= "$(function(){ $('#".$prefix."').datepicker({
6486  dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
6487  autoclose: true,
6488  todayHighlight: true,
6489  yearRange: '".$minYear.":".$maxYear."',";
6490  if (!empty($conf->dol_use_jmobile)) {
6491  $retstring .= "
6492  beforeShow: function (input, datePicker) {
6493  input.disabled = true;
6494  },
6495  onClose: function (dateText, datePicker) {
6496  this.disabled = false;
6497  },
6498  ";
6499  }
6500  // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6501  if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6502  $retstring .= "
6503  showOn: 'button', /* both has problem with autocompletion */
6504  buttonImage: '".DOL_URL_ROOT."/theme/".dol_escape_js($conf->theme)."/img/object_calendarday.png',
6505  buttonImageOnly: true";
6506  }
6507  $retstring .= "
6508  }) });";
6509  $retstring .= "</script>";
6510  }
6511 
6512  // Zone de saisie manuelle de la date
6513  $retstring .= '<div class="nowrap inline-block divfordateinput">';
6514  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6515  $retstring .= ($disabled ? ' disabled' : '');
6516  $retstring .= ($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '');
6517  $retstring .= ' onChange="dpChangeDay(\''.dol_escape_js($prefix).'\',\''.dol_escape_js($langs->trans("FormatDateShortJavaInput")).'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6518  $retstring .= '>';
6519 
6520  // Icone calendrier
6521  if (!$disabled) {
6522  /* Not required. Managed by option buttonImage of jquery
6523  $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6524  $retstring.="<script type='text/javascript'>";
6525  $retstring.="jQuery(document).ready(function() {";
6526  $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
6527  $retstring.=" jQuery('#".$prefix."').focus();";
6528  $retstring.=' });';
6529  $retstring.='});';
6530  $retstring.="</script>";*/
6531  } else {
6532  $retstringbutton = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6533  $retsring = $retstringbutton.$retstring;
6534  }
6535 
6536  $retstring .= '</div>';
6537  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
6538  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6539  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
6540  } else {
6541  $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6542  }
6543  } else {
6544  // Show date with combo selects
6545  // Day
6546  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
6547 
6548  if ($emptydate || $set_time == -1) {
6549  $retstring .= '<option value="0" selected>&nbsp;</option>';
6550  }
6551 
6552  for ($day = 1; $day <= 31; $day++) {
6553  $retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
6554  }
6555 
6556  $retstring .= "</select>";
6557 
6558  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
6559  if ($emptydate || $set_time == -1) {
6560  $retstring .= '<option value="0" selected>&nbsp;</option>';
6561  }
6562 
6563  // Month
6564  for ($month = 1; $month <= 12; $month++) {
6565  $retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
6566  $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6567  $retstring .= "</option>";
6568  }
6569  $retstring .= "</select>";
6570 
6571  // Year
6572  if ($emptydate || $set_time == -1) {
6573  $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.'">';
6574  } else {
6575  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
6576 
6577  for ($year = $syear - 10; $year < $syear + 10; $year++) {
6578  $retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
6579  }
6580  $retstring .= "</select>\n";
6581  }
6582  }
6583  }
6584 
6585  if ($d && $h) {
6586  $retstring .= ($h == 2 ? '<br>' : ' ');
6587  $retstring .= '<span class="nowraponall">';
6588  }
6589 
6590  if ($h) {
6591  $hourstart = 0;
6592  $hourend = 24;
6593  if ($openinghours != '') {
6594  $openinghours = explode(',', $openinghours);
6595  $hourstart = $openinghours[0];
6596  $hourend = $openinghours[1];
6597  if ($hourend < $hourstart) {
6598  $hourend = $hourstart;
6599  }
6600  }
6601  // Show hour
6602  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
6603  if ($emptyhours) {
6604  $retstring .= '<option value="-1">&nbsp;</option>';
6605  }
6606  for ($hour = $hourstart; $hour < $hourend; $hour++) {
6607  if (strlen($hour) < 2) {
6608  $hour = "0".$hour;
6609  }
6610  $retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour;
6611  //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6612  $retstring .= '</option>';
6613  }
6614  $retstring .= '</select>';
6615  //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6616  if ($m) {
6617  $retstring .= ":";
6618  }
6619  }
6620 
6621  if ($m) {
6622  // Show minutes
6623  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
6624  if ($emptyhours) {
6625  $retstring .= '<option value="-1">&nbsp;</option>';
6626  }
6627  for ($min = 0; $min < 60; $min += $stepminutes) {
6628  if (strlen($min) < 2) {
6629  $min = "0".$min;
6630  }
6631  $retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
6632  }
6633  $retstring .= '</select>';
6634 
6635  $retstring .= '<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
6636  }
6637 
6638  if ($d && $h) {
6639  $retstring .= '</span>';
6640  }
6641 
6642  // Add a "Now" link
6643  if ($conf->use_javascript_ajax && $addnowlink) {
6644  // Script which will be inserted in the onClick of the "Now" link
6645  $reset_scripts = "";
6646  if ($addnowlink == 2) { // local computer time
6647  // pad add leading 0 on numbers
6648  $reset_scripts .= "Number.prototype.pad = function(size) {
6649  var s = String(this);
6650  while (s.length < (size || 2)) {s = '0' + s;}
6651  return s;
6652  };
6653  var d = new Date();";
6654  }
6655 
6656  // Generate the date part, depending on the use or not of the javascript calendar
6657  if ($addnowlink == 1) { // server time expressed in user time setup
6658  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6659  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6660  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6661  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6662  } elseif ($addnowlink == 2) {
6663  /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6664  * This break application for foreign languages.
6665  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6666  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6667  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6668  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6669  */
6670  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6671  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6672  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6673  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6674  }
6675  /*if ($usecalendar == "eldy")
6676  {
6677  $base=DOL_URL_ROOT.'/core/';
6678  $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6679  }
6680  else
6681  {
6682  $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6683  $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6684  $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6685  }*/
6686  // Update the hour part
6687  if ($h) {
6688  if ($fullday) {
6689  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6690  }
6691  //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
6692  if ($addnowlink == 1) {
6693  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6694  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6695  } elseif ($addnowlink == 2) {
6696  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
6697  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6698  }
6699 
6700  if ($fullday) {
6701  $reset_scripts .= ' } ';
6702  }
6703  }
6704  // Update the minute part
6705  if ($m) {
6706  if ($fullday) {
6707  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6708  }
6709  //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
6710  if ($addnowlink == 1) {
6711  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6712  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6713  } elseif ($addnowlink == 2) {
6714  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
6715  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6716  }
6717  if ($fullday) {
6718  $reset_scripts .= ' } ';
6719  }
6720  }
6721  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6722  if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6723  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
6724  $retstring .= $langs->trans("Now");
6725  $retstring .= '</button> ';
6726  }
6727  }
6728 
6729  // Add a "Plus one hour" link
6730  if ($conf->use_javascript_ajax && $addplusone) {
6731  // Script which will be inserted in the onClick of the "Add plusone" link
6732  $reset_scripts = "";
6733 
6734  // Generate the date part, depending on the use or not of the javascript calendar
6735  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');';
6736  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6737  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6738  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6739  // Update the hour part
6740  if ($h) {
6741  if ($fullday) {
6742  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6743  }
6744  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6745  if ($fullday) {
6746  $reset_scripts .= ' } ';
6747  }
6748  }
6749  // Update the minute part
6750  if ($m) {
6751  if ($fullday) {
6752  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6753  }
6754  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6755  if ($fullday) {
6756  $reset_scripts .= ' } ';
6757  }
6758  }
6759  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6760  if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6761  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
6762  $retstring .= $langs->trans("DateStartPlusOne");
6763  $retstring .= '</button> ';
6764  }
6765  }
6766 
6767  // Add a link to set data
6768  if ($conf->use_javascript_ajax && $adddateof) {
6769  $tmparray = dol_getdate($adddateof);
6770  if (empty($labeladddateof)) {
6771  $labeladddateof = $langs->trans("DateInvoice");
6772  }
6773  $reset_scripts = 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($adddateof, 'dayinputnoreduce').'\');';
6774  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
6775  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
6776  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
6777  $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$labeladddateof.'</a>';
6778  }
6779 
6780  return $retstring;
6781  }
6782 
6791  public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
6792  {
6793  global $langs;
6794 
6795  $TDurationTypes = array(
6796  'y'=>$langs->trans('Years'),
6797  'm'=>$langs->trans('Month'),
6798  'w'=>$langs->trans('Weeks'),
6799  'd'=>$langs->trans('Days'),
6800  'h'=>$langs->trans('Hours'),
6801  'i'=>$langs->trans('Minutes')
6802  );
6803 
6804  // Removed undesired duration types
6805  foreach ($excludetypes as $value) {
6806  unset($TDurationTypes[$value]);
6807  }
6808 
6809  $retstring = '<select class="flat minwidth75 maxwidth100" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
6810  foreach ($TDurationTypes as $key => $typeduration) {
6811  $retstring .= '<option value="'.$key.'"';
6812  if ($key == $selected) {
6813  $retstring .= " selected";
6814  }
6815  $retstring .= ">".$typeduration."</option>";
6816  }
6817  $retstring .= "</select>";
6818 
6819  $retstring .= ajax_combobox('select_'.$prefix.'type_duration');
6820 
6821  return $retstring;
6822  }
6823 
6824  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6838  public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
6839  {
6840  // phpcs:enable
6841  global $langs;
6842 
6843  $retstring = '<span class="nowraponall">';
6844 
6845  $hourSelected = 0;
6846  $minSelected = 0;
6847 
6848  // Hours
6849  if ($iSecond != '') {
6850  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6851 
6852  $hourSelected = convertSecondToTime($iSecond, 'allhour');
6853  $minSelected = convertSecondToTime($iSecond, 'min');
6854  }
6855 
6856  if ($typehour == 'select') {
6857  $retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
6858  for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
6859  $retstring .= '<option value="'.$hour.'"';
6860  if ($hourSelected == $hour) {
6861  $retstring .= " selected";
6862  }
6863  $retstring .= ">".$hour."</option>";
6864  }
6865  $retstring .= "</select>";
6866  } elseif ($typehour == 'text' || $typehour == 'textselect') {
6867  $retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
6868  } else {
6869  return 'BadValueForParameterTypeHour';
6870  }
6871 
6872  if ($typehour != 'text') {
6873  $retstring .= ' '.$langs->trans('HourShort');
6874  } else {
6875  $retstring .= '<span class="">:</span>';
6876  }
6877 
6878  // Minutes
6879  if ($minunderhours) {
6880  $retstring .= '<br>';
6881  } else {
6882  $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
6883  }
6884 
6885  if ($typehour == 'select' || $typehour == 'textselect') {
6886  $retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
6887  for ($min = 0; $min <= 55; $min = $min + 5) {
6888  $retstring .= '<option value="'.$min.'"';
6889  if ($minSelected == $min) {
6890  $retstring .= ' selected';
6891  }
6892  $retstring .= '>'.$min.'</option>';
6893  }
6894  $retstring .= "</select>";
6895  } elseif ($typehour == 'text') {
6896  $retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
6897  }
6898 
6899  if ($typehour != 'text') {
6900  $retstring .= ' '.$langs->trans('MinuteShort');
6901  }
6902 
6903  $retstring.="</span>";
6904 
6905  if (!empty($nooutput)) {
6906  return $retstring;
6907  }
6908 
6909  print $retstring;
6910  return;
6911  }
6912 
6932  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)
6933  {
6934  global $langs, $conf;
6935 
6936  $out = '';
6937 
6938  // check parameters
6939  if (is_null($ajaxoptions)) $ajaxoptions = array();
6940 
6941  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
6942  $placeholder = '';
6943 
6944  if ($selected && empty($selected_input_value)) {
6945  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
6946  $tickettmpselect = new Ticket($this->db);
6947  $tickettmpselect->fetch($selected);
6948  $selected_input_value = $tickettmpselect->ref;
6949  unset($tickettmpselect);
6950  }
6951 
6952  $urloption = '';
6953  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
6954 
6955  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
6956  elseif ($hidelabel > 1) {
6957  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
6958  if ($hidelabel == 2) {
6959  $out .= img_picto($langs->trans("Search"), 'search');
6960  }
6961  }
6962  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
6963  if ($hidelabel == 3) {
6964  $out .= img_picto($langs->trans("Search"), 'search');
6965  }
6966  } else {
6967  $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
6968  }
6969 
6970  if (empty($nooutput)) print $out;
6971  else return $out;
6972  }
6973 
6974 
6991  public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
6992  {
6993  global $langs, $conf;
6994 
6995  $out = '';
6996  $outarray = array();
6997 
6998  $selectFields = " p.rowid, p.ref, p.message";
6999 
7000  $sql = "SELECT ";
7001  $sql .= $selectFields;
7002  $sql .= " FROM ".$this->db->prefix()."ticket as p";
7003  $sql .= ' WHERE p.entity IN ('.getEntity('ticket').')';
7004 
7005  // Add criteria on ref/label
7006  if ($filterkey != '') {
7007  $sql .= ' AND (';
7008  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7009  // For natural search
7010  $scrit = explode(' ', $filterkey);
7011  $i = 0;
7012  if (count($scrit) > 1) $sql .= "(";
7013  foreach ($scrit as $crit) {
7014  if ($i > 0) $sql .= " AND ";
7015  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.subject LIKE '".$this->db->escape($prefix.$crit)."%'";
7016  $sql .= ")";
7017  $i++;
7018  }
7019  if (count($scrit) > 1) $sql .= ")";
7020  $sql .= ')';
7021  }
7022 
7023  $sql .= $this->db->plimit($limit, 0);
7024 
7025  // Build output string
7026  dol_syslog(get_class($this)."::selectTicketsList search tickets", LOG_DEBUG);
7027  $result = $this->db->query($sql);
7028  if ($result) {
7029  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
7030  require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
7031 
7032  $num = $this->db->num_rows($result);
7033 
7034  $events = null;
7035 
7036  if (!$forcecombo) {
7037  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7038  $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7039  }
7040 
7041  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7042 
7043  $textifempty = '';
7044  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7045  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7046  if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7047  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7048  else $textifempty .= $langs->trans("All");
7049  } else {
7050  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7051  }
7052  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7053 
7054  $i = 0;
7055  while ($num && $i < $num) {
7056  $opt = '';
7057  $optJson = array();
7058  $objp = $this->db->fetch_object($result);
7059 
7060  $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7061  // Add new entry
7062  // "key" value of json key array is used by jQuery automatically as selected value
7063  // "label" value of json key array is used by jQuery automatically as text for combo box
7064  $out .= $opt;
7065  array_push($outarray, $optJson);
7066 
7067  $i++;
7068  }
7069 
7070  $out .= '</select>';
7071 
7072  $this->db->free($result);
7073 
7074  if (empty($outputmode)) return $out;
7075  return $outarray;
7076  } else {
7077  dol_print_error($this->db);
7078  }
7079  }
7080 
7092  protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7093  {
7094  $outkey = '';
7095  $outref = '';
7096  $outtype = '';
7097 
7098  $outkey = $objp->rowid;
7099  $outref = $objp->ref;
7100  $outtype = $objp->fk_product_type;
7101 
7102  $opt = '<option value="'.$objp->rowid.'"';
7103  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7104  $opt .= '>';
7105  $opt .= $objp->ref;
7106  $objRef = $objp->ref;
7107  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7108 
7109  $opt .= "</option>\n";
7110  $optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7111  }
7112 
7132  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)
7133  {
7134  global $langs, $conf;
7135 
7136  $out = '';
7137 
7138  // check parameters
7139  if (is_null($ajaxoptions)) $ajaxoptions = array();
7140 
7141  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7142  $placeholder = '';
7143 
7144  if ($selected && empty($selected_input_value)) {
7145  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7146  $projecttmpselect = new Project($this->db);
7147  $projecttmpselect->fetch($selected);
7148  $selected_input_value = $projecttmpselect->ref;
7149  unset($projecttmpselect);
7150  }
7151 
7152  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7153 
7154  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7155  elseif ($hidelabel > 1) {
7156  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7157  if ($hidelabel == 2) {
7158  $out .= img_picto($langs->trans("Search"), 'search');
7159  }
7160  }
7161  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7162  if ($hidelabel == 3) {
7163  $out .= img_picto($langs->trans("Search"), 'search');
7164  }
7165  } else {
7166  $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7167  }
7168 
7169  if (empty($nooutput)) print $out;
7170  else return $out;
7171  }
7172 
7189  public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7190  {
7191  global $langs, $conf;
7192 
7193  $out = '';
7194  $outarray = array();
7195 
7196  $selectFields = " p.rowid, p.ref";
7197 
7198  $sql = "SELECT ";
7199  $sql .= $selectFields;
7200  $sql .= " FROM ".$this->db->prefix()."projet as p";
7201  $sql .= ' WHERE p.entity IN ('.getEntity('project').')';
7202 
7203  // Add criteria on ref/label
7204  if ($filterkey != '') {
7205  $sql .= ' AND (';
7206  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7207  // For natural search
7208  $scrit = explode(' ', $filterkey);
7209  $i = 0;
7210  if (count($scrit) > 1) $sql .= "(";
7211  foreach ($scrit as $crit) {
7212  if ($i > 0) $sql .= " AND ";
7213  $sql .= "p.ref LIKE '".$this->db->escape($prefix.$crit)."%'";
7214  $sql .= "";
7215  $i++;
7216  }
7217  if (count($scrit) > 1) $sql .= ")";
7218  $sql .= ')';
7219  }
7220 
7221  $sql .= $this->db->plimit($limit, 0);
7222 
7223  // Build output string
7224  dol_syslog(get_class($this)."::selectProjectsList search projects", LOG_DEBUG);
7225  $result = $this->db->query($sql);
7226  if ($result) {
7227  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7228  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
7229 
7230  $num = $this->db->num_rows($result);
7231 
7232  $events = null;
7233 
7234  if (!$forcecombo) {
7235  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7236  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7237  }
7238 
7239  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7240 
7241  $textifempty = '';
7242  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7243  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7244  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7245  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7246  else $textifempty .= $langs->trans("All");
7247  } else {
7248  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7249  }
7250  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7251 
7252  $i = 0;
7253  while ($num && $i < $num) {
7254  $opt = '';
7255  $optJson = array();
7256  $objp = $this->db->fetch_object($result);
7257 
7258  $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7259  // Add new entry
7260  // "key" value of json key array is used by jQuery automatically as selected value
7261  // "label" value of json key array is used by jQuery automatically as text for combo box
7262  $out .= $opt;
7263  array_push($outarray, $optJson);
7264 
7265  $i++;
7266  }
7267 
7268  $out .= '</select>';
7269 
7270  $this->db->free($result);
7271 
7272  if (empty($outputmode)) return $out;
7273  return $outarray;
7274  } else {
7275  dol_print_error($this->db);
7276  }
7277  }
7278 
7290  protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7291  {
7292  $outkey = '';
7293  $outval = '';
7294  $outref = '';
7295  $outlabel = '';
7296  $outtype = '';
7297 
7298  $label = $objp->label;
7299 
7300  $outkey = $objp->rowid;
7301  $outref = $objp->ref;
7302  $outlabel = $objp->label;
7303  $outtype = $objp->fk_product_type;
7304 
7305  $opt = '<option value="'.$objp->rowid.'"';
7306  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7307  $opt .= '>';
7308  $opt .= $objp->ref;
7309  $objRef = $objp->ref;
7310  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7311  $outval .= $objRef;
7312 
7313  $opt .= "</option>\n";
7314  $optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7315  }
7316 
7317 
7337  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)
7338  {
7339  global $langs, $conf;
7340 
7341  $out = '';
7342 
7343  // check parameters
7344  if (is_null($ajaxoptions)) $ajaxoptions = array();
7345 
7346  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7347  $placeholder = '';
7348  $urloption = '';
7349 
7350  if ($selected && empty($selected_input_value)) {
7351  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7352  $adherenttmpselect = new Adherent($this->db);
7353  $adherenttmpselect->fetch($selected);
7354  $selected_input_value = $adherenttmpselect->ref;
7355  unset($adherenttmpselect);
7356  }
7357 
7358  $urloption = '';
7359 
7360  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7361 
7362  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7363  elseif ($hidelabel > 1) {
7364  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7365  if ($hidelabel == 2) {
7366  $out .= img_picto($langs->trans("Search"), 'search');
7367  }
7368  }
7369  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7370  if ($hidelabel == 3) {
7371  $out .= img_picto($langs->trans("Search"), 'search');
7372  }
7373  } else {
7374  $filterkey = '';
7375 
7376  $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
7377  }
7378 
7379  if (empty($nooutput)) print $out;
7380  else return $out;
7381  }
7382 
7399  public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7400  {
7401  global $langs, $conf;
7402 
7403  $out = '';
7404  $outarray = array();
7405 
7406  $selectFields = " p.rowid, p.ref, p.firstname, p.lastname";
7407 
7408  $sql = "SELECT ";
7409  $sql .= $selectFields;
7410  $sql .= " FROM ".$this->db->prefix()."adherent as p";
7411  $sql .= ' WHERE p.entity IN ('.getEntity('adherent').')';
7412 
7413  // Add criteria on ref/label
7414  if ($filterkey != '') {
7415  $sql .= ' AND (';
7416  $prefix = empty($conf->global->MEMBER_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7417  // For natural search
7418  $scrit = explode(' ', $filterkey);
7419  $i = 0;
7420  if (count($scrit) > 1) $sql .= "(";
7421  foreach ($scrit as $crit) {
7422  if ($i > 0) $sql .= " AND ";
7423  $sql .= "(p.firstname LIKE '".$this->db->escape($prefix.$crit)."%'";
7424  $sql .= " OR p.lastname LIKE '".$this->db->escape($prefix.$crit)."%')";
7425  $i++;
7426  }
7427  if (count($scrit) > 1) $sql .= ")";
7428  $sql .= ')';
7429  }
7430  if ($status != -1) {
7431  $sql .= ' AND statut = '.((int) $status);
7432  }
7433  $sql .= $this->db->plimit($limit, 0);
7434 
7435  // Build output string
7436  dol_syslog(get_class($this)."::selectMembersList search adherents", LOG_DEBUG);
7437  $result = $this->db->query($sql);
7438  if ($result) {
7439  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7440  require_once DOL_DOCUMENT_ROOT.'/core/lib/member.lib.php';
7441 
7442  $num = $this->db->num_rows($result);
7443 
7444  $events = null;
7445 
7446  if (!$forcecombo) {
7447  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7448  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7449  }
7450 
7451  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7452 
7453  $textifempty = '';
7454  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7455  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7456  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7457  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7458  else $textifempty .= $langs->trans("All");
7459  } else {
7460  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7461  }
7462  if ($showempty) {
7463  $out .= '<option value="-1" selected>'.$textifempty.'</option>';
7464  }
7465 
7466  $i = 0;
7467  while ($num && $i < $num) {
7468  $opt = '';
7469  $optJson = array();
7470  $objp = $this->db->fetch_object($result);
7471 
7472  $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
7473 
7474  // Add new entry
7475  // "key" value of json key array is used by jQuery automatically as selected value
7476  // "label" value of json key array is used by jQuery automatically as text for combo box
7477  $out .= $opt;
7478  array_push($outarray, $optJson);
7479 
7480  $i++;
7481  }
7482 
7483  $out .= '</select>';
7484 
7485  $this->db->free($result);
7486 
7487  if (empty($outputmode)) return $out;
7488  return $outarray;
7489  } else {
7490  dol_print_error($this->db);
7491  }
7492  }
7493 
7505  protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7506  {
7507  $outkey = '';
7508  $outlabel = '';
7509  $outtype = '';
7510 
7511  $outkey = $objp->rowid;
7512  $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
7513  $outtype = $objp->fk_adherent_type;
7514 
7515  $opt = '<option value="'.$objp->rowid.'"';
7516  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7517  $opt .= '>';
7518  if (!empty($filterkey) && $filterkey != '') {
7519  $outlabel = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $outlabel, 1);
7520  }
7521  $opt .= $outlabel;
7522  $opt .= "</option>\n";
7523 
7524  $optJson = array('key'=>$outkey, 'value'=>$outlabel, 'type'=>$outtype);
7525  }
7526 
7546  public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
7547  {
7548  global $conf, $user;
7549 
7550  $objecttmp = null;
7551 
7552  // Example of value for $objectdec:
7553  // Bom:bom/class/bom.class.php:0:t.status=1
7554  // Bom:bom/class/bom.class.php:0:t.status=1:ref
7555  // Bom:bom/class/bom.class.php:0:(t.status:=:1):ref
7556  $InfoFieldList = explode(":", $objectdesc, 4);
7557  $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
7558  $reg = array();
7559  if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
7560  $InfoFieldList[4] = $reg[1]; // take the sort field
7561  }
7562  $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
7563 
7564  $classname = $InfoFieldList[0];
7565  $classpath = $InfoFieldList[1];
7566  $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
7567  $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
7568  $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
7569 
7570  if (!empty($classpath)) {
7571  dol_include_once($classpath);
7572 
7573  if ($classname && class_exists($classname)) {
7574  $objecttmp = new $classname($this->db);
7575  // Make some replacement
7576  $sharedentities = getEntity(strtolower($classname));
7577  $objecttmp->filter = str_replace(
7578  array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
7579  array($conf->entity, $sharedentities, $user->id),
7580  $filter
7581  );
7582  }
7583  }
7584  if (!is_object($objecttmp)) {
7585  dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
7586  return 'Error bad setup of type for field '.join(',', $InfoFieldList);
7587  }
7588 
7589  //var_dump($objecttmp->filter);
7590  $prefixforautocompletemode = $objecttmp->element;
7591  if ($prefixforautocompletemode == 'societe') {
7592  $prefixforautocompletemode = 'company';
7593  }
7594  if ($prefixforautocompletemode == 'product') {
7595  $prefixforautocompletemode = 'produit';
7596  }
7597  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7598 
7599  dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG);
7600  $out = '';
7601  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo) {
7602  // No immediate load of all database
7603  $placeholder = '';
7604  if ($preselectedvalue && empty($selected_input_value)) {
7605  $objecttmp->fetch($preselectedvalue);
7606  $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
7607  //unset($objecttmp);
7608  }
7609 
7610  $objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
7611  $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
7612 
7613  // No immediate load of all database
7614  $urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&objectdesc='.urlencode($objectdesc).'&filter='.urlencode($objecttmp->filter).($sortfield ? '&sortfield='.urlencode($sortfield) : '');
7615  // Activate the auto complete using ajax call.
7616  $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
7617  $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
7618  $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).'"' : '') .' />';
7619  } else {
7620  // Immediate load of table record. Note: filter is inside $objecttmp->filter
7621  $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield);
7622  }
7623 
7624  return $out;
7625  }
7626 
7633  protected static function forgeCriteriaCallback($matches)
7634  {
7635  global $db;
7636 
7637  //dol_syslog("Convert matches ".$matches[1]);
7638  if (empty($matches[1])) {
7639  return '';
7640  }
7641  $tmp = explode(':', $matches[1]);
7642  if (count($tmp) < 3) {
7643  return '';
7644  }
7645 
7646  $tmpescaped = $tmp[2];
7647  $regbis = array();
7648  if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
7649  $tmpescaped = "'".$db->escape($regbis[1])."'";
7650  } else {
7651  $tmpescaped = $db->escape($tmpescaped);
7652  }
7653  return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
7654  }
7655 
7676  public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
7677  {
7678  global $conf, $langs, $user, $hookmanager;
7679 
7680  //print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled";
7681 
7682  $prefixforautocompletemode = $objecttmp->element;
7683  if ($prefixforautocompletemode == 'societe') {
7684  $prefixforautocompletemode = 'company';
7685  }
7686  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7687 
7688  if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
7689  $tmpfieldstoshow = '';
7690  foreach ($objecttmp->fields as $key => $val) {
7691  if (!dol_eval($val['enabled'], 1, 1, '1')) {
7692  continue;
7693  }
7694  if (!empty($val['showoncombobox'])) {
7695  $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
7696  }
7697  }
7698  if ($tmpfieldstoshow) {
7699  $fieldstoshow = $tmpfieldstoshow;
7700  }
7701  } else {
7702  // For backward compatibility
7703  $objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
7704  }
7705 
7706  if (empty($fieldstoshow)) {
7707  if (isset($objecttmp->fields['ref'])) {
7708  $fieldstoshow = 't.ref';
7709  } else {
7710  $langs->load("errors");
7711  $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
7712  return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
7713  }
7714  }
7715 
7716  $out = '';
7717  $outarray = array();
7718  $tmparray = array();
7719 
7720  $num = 0;
7721 
7722  // Search data
7723  $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".$this->db->prefix().$objecttmp->table_element." as t";
7724  if (isset($objecttmp->ismultientitymanaged)) {
7725  if (!is_numeric($objecttmp->ismultientitymanaged)) {
7726  $tmparray = explode('@', $objecttmp->ismultientitymanaged);
7727  $sql .= " INNER JOIN ".$this->db->prefix().$tmparray[1]." as parenttable ON parenttable.rowid = t.".$tmparray[0];
7728  }
7729  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7730  if (empty($user->rights->societe->client->voir) && !$user->socid) {
7731  $sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
7732  }
7733  }
7734  }
7735 
7736  // Add where from hooks
7737  $parameters = array(
7738  'object' => $objecttmp,
7739  'htmlname' => $htmlname,
7740  'filter' => $filter,
7741  'searchkey' => $searchkey
7742  );
7743 
7744  $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
7745  if (!empty($hookmanager->resPrint)) {
7746  $sql .= $hookmanager->resPrint;
7747  } else {
7748  $sql .= " WHERE 1=1";
7749  if (isset($objecttmp->ismultientitymanaged)) {
7750  if ($objecttmp->ismultientitymanaged == 1) {
7751  $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
7752  }
7753  if (!is_numeric($objecttmp->ismultientitymanaged)) {
7754  $sql .= " AND parenttable.entity = t.".$tmparray[0];
7755  }
7756  if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
7757  if ($objecttmp->element == 'societe') {
7758  $sql .= " AND t.rowid = ".((int) $user->socid);
7759  } else {
7760  $sql .= " AND t.fk_soc = ".((int) $user->socid);
7761  }
7762  }
7763  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7764  if (empty($user->rights->societe->client->voir) && !$user->socid) {
7765  $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
7766  }
7767  }
7768  }
7769  if ($searchkey != '') {
7770  $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
7771  }
7772  if ($objecttmp->filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
7773  /*if (! DolibarrApi::_checkFilters($objecttmp->filter))
7774  {
7775  throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter);
7776  }*/
7777  $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
7778  $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")";
7779  }
7780  }
7781  $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
7782  //$sql.=$this->db->plimit($limit, 0);
7783  //print $sql;
7784 
7785  // Build output string
7786  $resql = $this->db->query($sql);
7787  if ($resql) {
7788  // Construct $out and $outarray
7789  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
7790 
7791  // 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
7792  $textifempty = '&nbsp;';
7793 
7794  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7795  if (!empty($conf->global->$confkeyforautocompletemode)) {
7796  if ($showempty && !is_numeric($showempty)) {
7797  $textifempty = $langs->trans($showempty);
7798  } else {
7799  $textifempty .= $langs->trans("All");
7800  }
7801  }
7802  if ($showempty) {
7803  $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
7804  }
7805 
7806  $num = $this->db->num_rows($resql);
7807  $i = 0;
7808  if ($num) {
7809  while ($i < $num) {
7810  $obj = $this->db->fetch_object($resql);
7811  $label = '';
7812  $tmparray = explode(',', $fieldstoshow);
7813  $oldvalueforshowoncombobox = 0;
7814  foreach ($tmparray as $key => $val) {
7815  $val = preg_replace('/t\./', '', $val);
7816  $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
7817  $label .= $obj->$val;
7818  $oldvalueforshowoncombobox = !empty($objecttmp->fields[$val]['showoncombobox']) ? $objecttmp->fields[$val]['showoncombobox'] : 0;
7819  }
7820  if (empty($outputmode)) {
7821  if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
7822  $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
7823  } else {
7824  $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
7825  }
7826  } else {
7827  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
7828  }
7829 
7830  $i++;
7831  if (($i % 10) == 0) {
7832  $out .= "\n";
7833  }
7834  }
7835  }
7836 
7837  $out .= '</select>'."\n";
7838 
7839  if (!$forcecombo) {
7840  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7841  $out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
7842  }
7843  } else {
7844  dol_print_error($this->db);
7845  }
7846 
7847  $this->result = array('nbofelement'=>$num);
7848 
7849  if ($outputmode) {
7850  return $outarray;
7851  }
7852  return $out;
7853  }
7854 
7855 
7879  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 = '', $addjscombo = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
7880  {
7881  global $conf, $langs;
7882 
7883  // Do we want a multiselect ?
7884  //$jsbeautify = 0;
7885  //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
7886  $jsbeautify = 1;
7887 
7888  if ($value_as_key) {
7889  $array = array_combine($array, $array);
7890  }
7891 
7892  $out = '';
7893 
7894  if ($addjscombo < 0) {
7895  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7896  $addjscombo = 1;
7897  } else {
7898  $addjscombo = 0;
7899  }
7900  }
7901 
7902  $out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
7903  $out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
7904  $out .= '>';
7905 
7906  if ($show_empty) {
7907  $textforempty = ' ';
7908  if (!empty($conf->use_javascript_ajax)) {
7909  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
7910  }
7911  if (!is_numeric($show_empty)) {
7912  $textforempty = $show_empty;
7913  }
7914  $out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
7915  }
7916 
7917  if (is_array($array)) {
7918  // Translate
7919  if ($translate) {
7920  foreach ($array as $key => $value) {
7921  if (!is_array($value)) {
7922  $array[$key] = $langs->trans($value);
7923  } else {
7924  $array[$key]['label'] = $langs->trans($value['label']);
7925  }
7926  }
7927  }
7928 
7929  // Sort
7930  if ($sort == 'ASC') {
7931  asort($array);
7932  } elseif ($sort == 'DESC') {
7933  arsort($array);
7934  }
7935 
7936  foreach ($array as $key => $tmpvalue) {
7937  if (is_array($tmpvalue)) {
7938  $value = $tmpvalue['label'];
7939  $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
7940  $style = empty($tmpvalue['css']) ? '' : ' class="'.$tmpvalue['css'].'"';
7941  } else {
7942  $value = $tmpvalue;
7943  $disabled = '';
7944  $style = '';
7945  }
7946  if (!empty($disablebademail)) {
7947  if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
7948  || ($disablebademail == 2 && preg_match('/---/', $value))) {
7949  $disabled = ' disabled';
7950  $style = ' class="warning"';
7951  }
7952  }
7953 
7954  if ($key_in_label) {
7955  if (empty($nohtmlescape)) {
7956  $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
7957  } else {
7958  $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
7959  }
7960  } else {
7961  if (empty($nohtmlescape)) {
7962  $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
7963  } else {
7964  $selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value;
7965  }
7966  if ($value == '' || $value == '-') {
7967  $selectOptionValue = '&nbsp;';
7968  }
7969  }
7970 
7971  $out .= '<option value="'.$key.'"';
7972  $out .= $style.$disabled;
7973  if (is_array($id)) {
7974  if (in_array($key, $id) && !$disabled) {
7975  $out .= ' selected'; // To preselect a value
7976  }
7977  } else {
7978  $id = (string) $id; // if $id = 0, then $id = '0'
7979  if ($id != '' && ($id == $key || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
7980  $out .= ' selected'; // To preselect a value
7981  }
7982  }
7983  if ($nohtmlescape) {
7984  $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
7985  }
7986  if (is_array($tmpvalue)) {
7987  foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
7988  if (preg_match('/^data-/', $keyforvalue)) {
7989  $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
7990  }
7991  }
7992  }
7993  $out .= '>';
7994  //var_dump($selectOptionValue);
7995  $out .= $selectOptionValue;
7996  $out .= "</option>\n";
7997  }
7998  }
7999 
8000  $out .= "</select>";
8001 
8002  // Add code for jquery to use multiselect
8003  if ($addjscombo && $jsbeautify) {
8004  // Enhance with select2
8005  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
8006  $out .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', $show_empty < 0 ? (string) $show_empty : '-1');
8007  }
8008 
8009  return $out;
8010  }
8011 
8012 
8031  public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8032  {
8033  global $conf, $langs;
8034  global $delayedhtmlcontent; // Will be used later outside of this function
8035 
8036  // TODO Use an internal dolibarr component instead of select2
8037  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8038  return '';
8039  }
8040 
8041  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
8042 
8043  $outdelayed = '';
8044  if (!empty($conf->use_javascript_ajax)) {
8045  $tmpplugin = 'select2';
8046  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8047  <script>
8048  $(document).ready(function () {
8049 
8050  '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
8051 
8052  $(".'.$htmlname.'").select2({
8053  ajax: {
8054  dir: "ltr",
8055  url: "'.$url.'",
8056  dataType: \'json\',
8057  delay: 250,
8058  data: function (params) {
8059  return {
8060  q: params.term, // search term
8061  page: params.page
8062  };
8063  },
8064  processResults: function (data) {
8065  // parse the results into the format expected by Select2.
8066  // since we are using custom formatting functions we do not need to alter the remote JSON data
8067  //console.log(data);
8068  saveRemoteData = data;
8069  /* format json result for select2 */
8070  result = []
8071  $.each( data, function( key, value ) {
8072  result.push({id: key, text: value.text});
8073  });
8074  //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8075  //console.log(result);
8076  return {results: result, more: false}
8077  },
8078  cache: true
8079  },
8080  language: select2arrayoflanguage,
8081  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8082  placeholder: "'.dol_escape_js($placeholder).'",
8083  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8084  minimumInputLength: '.$minimumInputLength.',
8085  formatResult: function(result, container, query, escapeMarkup) {
8086  return escapeMarkup(result.text);
8087  },
8088  });
8089 
8090  '.($callurlonselect ? '
8091  /* Code to execute a GET when we select a value */
8092  $(".'.$htmlname.'").change(function() {
8093  var selected = $(".'.$htmlname.'").val();
8094  console.log("We select in selectArrayAjax the entry "+selected)
8095  $(".'.$htmlname.'").val(""); /* reset visible combo value */
8096  $.each( saveRemoteData, function( key, value ) {
8097  if (key == selected)
8098  {
8099  console.log("selectArrayAjax - Do a redirect to "+value.url)
8100  location.assign(value.url);
8101  }
8102  });
8103  });' : '').'
8104 
8105  });
8106  </script>';
8107  }
8108 
8109  if ($acceptdelayedhtml) {
8110  $delayedhtmlcontent .= $outdelayed;
8111  } else {
8112  $out .= $outdelayed;
8113  }
8114  return $out;
8115  }
8116 
8135  public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8136  {
8137  global $conf, $langs;
8138  global $delayedhtmlcontent; // Will be used later outside of this function
8139 
8140  // TODO Use an internal dolibarr component instead of select2
8141  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8142  return '';
8143  }
8144 
8145  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
8146 
8147  $formattedarrayresult = array();
8148 
8149  foreach ($array as $key => $value) {
8150  $o = new stdClass();
8151  $o->id = $key;
8152  $o->text = $value['text'];
8153  $o->url = $value['url'];
8154  $formattedarrayresult[] = $o;
8155  }
8156 
8157  $outdelayed = '';
8158  if (!empty($conf->use_javascript_ajax)) {
8159  $tmpplugin = 'select2';
8160  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8161  <script>
8162  $(document).ready(function () {
8163  var data = '.json_encode($formattedarrayresult).';
8164 
8165  '.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
8166 
8167  $(".'.$htmlname.'").select2({
8168  data: data,
8169  language: select2arrayoflanguage,
8170  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8171  placeholder: "'.dol_escape_js($placeholder).'",
8172  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8173  minimumInputLength: '.$minimumInputLength.',
8174  formatResult: function(result, container, query, escapeMarkup) {
8175  return escapeMarkup(result.text);
8176  },
8177  matcher: function (params, data) {
8178 
8179  if(! data.id) return null;';
8180 
8181  if ($callurlonselect) {
8182  // We forge the url with 'sall='
8183  $outdelayed .= '
8184 
8185  var urlBase = data.url;
8186  var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8187  /* console.log("params.term="+params.term); */
8188  /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8189  saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8190  }
8191 
8192  if (!$disableFiltering) {
8193  $outdelayed .= '
8194 
8195  if(data.text.match(new RegExp(params.term))) {
8196  return data;
8197  }
8198 
8199  return null;';
8200  } else {
8201  $outdelayed .= '
8202 
8203  return data;';
8204  }
8205 
8206  $outdelayed .= '
8207  }
8208  });
8209 
8210  '.($callurlonselect ? '
8211  /* Code to execute a GET when we select a value */
8212  $(".'.$htmlname.'").change(function() {
8213  var selected = $(".'.$htmlname.'").val();
8214  console.log("We select "+selected)
8215 
8216  $(".'.$htmlname.'").val(""); /* reset visible combo value */
8217  $.each( saveRemoteData, function( key, value ) {
8218  if (key == selected)
8219  {
8220  console.log("selectArrayFilter - Do a redirect to "+value.url)
8221  location.assign(value.url);
8222  }
8223  });
8224  });' : '').'
8225 
8226  });
8227  </script>';
8228  }
8229 
8230  if ($acceptdelayedhtml) {
8231  $delayedhtmlcontent .= $outdelayed;
8232  } else {
8233  $out .= $outdelayed;
8234  }
8235  return $out;
8236  }
8237 
8256  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)
8257  {
8258  global $conf, $langs;
8259 
8260  $out = '';
8261 
8262  if ($addjscombo < 0) {
8263  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8264  $addjscombo = 1;
8265  } else {
8266  $addjscombo = 0;
8267  }
8268  }
8269 
8270  // Try also magic suggest
8271  $out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
8272  if (is_array($array) && !empty($array)) {
8273  if ($value_as_key) {
8274  $array = array_combine($array, $array);
8275  }
8276 
8277  if (!empty($array)) {
8278  foreach ($array as $key => $value) {
8279  $newval = ($translate ? $langs->trans($value) : $value);
8280  $newval = ($key_in_label ? $key.' - '.$newval : $newval);
8281 
8282  $out .= '<option value="'.$key.'"';
8283  if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != '')) {
8284  $out .= ' selected';
8285  }
8286  $out .= ' data-html="'.dol_escape_htmltag($newval).'"';
8287  $out .= '>';
8288  $out .= dol_htmlentitiesbr($newval);
8289  $out .= '</option>'."\n";
8290  }
8291  }
8292  }
8293  $out .= '</select>'."\n";
8294 
8295  // Add code for jquery to use multiselect
8296  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8297  $out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->';
8298  $out .= "\n".'<script>'."\n";
8299  if ($addjscombo == 1) {
8300  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
8301  $out .= 'function formatResult(record, container) {'."\n";
8302  $out .= ' if ($(record.element).attr("data-html") != undefined) return htmlEntityDecodeJs($(record.element).attr("data-html")); // If property html set, we decode html entities and use this'."\n";
8303  $out .= ' return record.text;';
8304  $out .= '};'."\n";
8305  $out .= 'function formatSelection(record) {'."\n";
8306  if ($elemtype == 'category') {
8307  $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
8308  } else {
8309  $out .= 'return record.text;';
8310  }
8311  $out .= '};'."\n";
8312  $out .= '$(document).ready(function () {
8313  $(\'#'.$htmlname.'\').'.$tmpplugin.'({';
8314  if ($placeholder) {
8315  $out .= '
8316  placeholder: {
8317  id: \'-1\',
8318  text: \''.dol_escape_js($placeholder).'\'
8319  },';
8320  }
8321  $out .= ' dir: \'ltr\',
8322  // Specify format function for dropdown item
8323  formatResult: formatResult,
8324  templateResult: formatResult, /* For 4.0 */
8325  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8326  // Specify format function for selected item
8327  formatSelection: formatSelection,
8328  templateSelection: formatSelection /* For 4.0 */
8329  });
8330 
8331  /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
8332  the size only if component is not hidden by default on load */
8333  $(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\');
8334  });'."\n";
8335  } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
8336  // Add other js lib
8337  // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
8338  // ...
8339  $out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
8340  $out .= '$(document).ready(function () {
8341  $(\'#'.$htmlname.'\').multiSelect({
8342  containerHTML: \'<div class="multi-select-container">\',
8343  menuHTML: \'<div class="multi-select-menu">\',
8344  buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
8345  menuItemHTML: \'<label class="multi-select-menuitem">\',
8346  activeClass: \'multi-select-container--open\',
8347  noneText: \''.$placeholder.'\'
8348  });
8349  })';
8350  }
8351  $out .= '</script>';
8352  }
8353 
8354  return $out;
8355  }
8356 
8357 
8368  public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
8369  {
8370  global $conf, $langs, $user, $extrafields;
8371 
8372  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8373  return '';
8374  }
8375 
8376  $tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved selected fields to show
8377 
8378  if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
8379  $tmparray = explode(',', $user->conf->$tmpvar);
8380  foreach ($array as $key => $val) {
8381  //var_dump($key);
8382  //var_dump($tmparray);
8383  if (in_array($key, $tmparray)) {
8384  $array[$key]['checked'] = 1;
8385  } else {
8386  $array[$key]['checked'] = 0;
8387  }
8388  }
8389  } else { // There is no list of fields already customized for user
8390  foreach ($array as $key => $val) {
8391  if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
8392  $array[$key]['checked'] = 0;
8393  }
8394  }
8395  }
8396 
8397  $listoffieldsforselection = '';
8398  $listcheckedstring = '';
8399 
8400  foreach ($array as $key => $val) {
8401  // var_dump($val);
8402  // var_dump(array_key_exists('enabled', $val));
8403  // var_dump(!$val['enabled']);
8404  if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
8405  unset($array[$key]); // We don't want this field
8406  continue;
8407  }
8408  if (!empty($val['type']) && $val['type'] == 'separate') {
8409  // Field remains in array but we don't add it into $listoffieldsforselection
8410  //$listoffieldsforselection .= '<li>-----</li>';
8411  continue;
8412  }
8413  if ($val['label']) {
8414  if (!empty($val['langfile']) && is_object($langs)) {
8415  $langs->load($val['langfile']);
8416  }
8417 
8418  // Note: $val['checked'] <> 0 means we must show the field into the combo list
8419  $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>';
8420  $listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
8421  }
8422  }
8423 
8424  $out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
8425 
8426  <dl class="dropdown">
8427  <dt>
8428  <a href="#'.$htmlname.'">
8429  '.img_picto('', 'list').'
8430  </a>
8431  <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
8432  </dt>
8433  <dd class="dropdowndd">
8434  <div class="multiselectcheckbox'.$htmlname.'">
8435  <ul class="ul'.$htmlname.' '.$htmlname.$pos.'">
8436  '.$listoffieldsforselection.'
8437  </ul>
8438  </div>
8439  </dd>
8440  </dl>
8441 
8442  <script type="text/javascript">
8443  jQuery(document).ready(function () {
8444  $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
8445  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
8446 
8447  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
8448 
8449  var title = $(this).val() + ",";
8450  if ($(this).is(\':checked\')) {
8451  $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
8452  }
8453  else {
8454  $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
8455  }
8456  // Now, we submit page
8457  //$(this).parents(\'form:first\').submit();
8458  });
8459 
8460 
8461  });
8462  </script>
8463 
8464  ';
8465  return $out;
8466  }
8467 
8477  public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
8478  {
8479  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
8480 
8481  $cat = new Categorie($this->db);
8482  $categories = $cat->containing($id, $type);
8483 
8484  if ($rendermode == 1) {
8485  $toprint = array();
8486  foreach ($categories as $c) {
8487  $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
8488  foreach ($ways as $way) {
8489  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>';
8490  }
8491  }
8492  return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
8493  }
8494 
8495  if ($rendermode == 0) {
8496  $arrayselected = array();
8497  $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
8498  foreach ($categories as $c) {
8499  $arrayselected[] = $c->id;
8500  }
8501 
8502  return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
8503  }
8504 
8505  return 'ErrorBadValueForParameterRenderMode'; // Should not happened
8506  }
8507 
8517  public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false, $title = 'RelatedObjects')
8518  {
8519  global $conf, $langs, $hookmanager;
8520  global $bc, $action;
8521 
8522  $object->fetchObjectLinked();
8523 
8524  // Bypass the default method
8525  $hookmanager->initHooks(array('commonobject'));
8526  $parameters = array(
8527  'morehtmlright' => $morehtmlright,
8528  'compatibleImportElementsList' => &$compatibleImportElementsList,
8529  );
8530  $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8531 
8532  if (empty($reshook)) {
8533  $nbofdifferenttypes = count($object->linkedObjects);
8534 
8535  print '<!-- showLinkedObjectBlock -->';
8536  print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
8537 
8538 
8539  print '<div class="div-table-responsive-no-min">';
8540  print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'" data-elementid="'.$object->id.'" >';
8541 
8542  print '<tr class="liste_titre">';
8543  print '<td>'.$langs->trans("Type").'</td>';
8544  print '<td>'.$langs->trans("Ref").'</td>';
8545  print '<td class="center"></td>';
8546  print '<td class="center">'.$langs->trans("Date").'</td>';
8547  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8548  print '<td class="right">'.$langs->trans("Status").'</td>';
8549  print '<td></td>';
8550  print '</tr>';
8551 
8552  $nboftypesoutput = 0;
8553 
8554  foreach ($object->linkedObjects as $objecttype => $objects) {
8555  $tplpath = $element = $subelement = $objecttype;
8556 
8557  // to display inport button on tpl
8558  $showImportButton = false;
8559  if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
8560  $showImportButton = true;
8561  }
8562 
8563  $regs = array();
8564  if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
8565  $element = $regs[1];
8566  $subelement = $regs[2];
8567  $tplpath = $element.'/'.$subelement;
8568  }
8569  $tplname = 'linkedobjectblock';
8570 
8571  // To work with non standard path
8572  if ($objecttype == 'facture') {
8573  $tplpath = 'compta/'.$element;
8574  if (!isModEnabled('facture')) {
8575  continue; // Do not show if module disabled
8576  }
8577  } elseif ($objecttype == 'facturerec') {
8578  $tplpath = 'compta/facture';
8579  $tplname = 'linkedobjectblockForRec';
8580  if (!isModEnabled('facture')) {
8581  continue; // Do not show if module disabled
8582  }
8583  } elseif ($objecttype == 'propal') {
8584  $tplpath = 'comm/'.$element;
8585  if (empty($conf->propal->enabled)) {
8586  continue; // Do not show if module disabled
8587  }
8588  } elseif ($objecttype == 'supplier_proposal') {
8589  if (empty($conf->supplier_proposal->enabled)) {
8590  continue; // Do not show if module disabled
8591  }
8592  } elseif ($objecttype == 'shipping' || $objecttype == 'shipment') {
8593  $tplpath = 'expedition';
8594  if (empty($conf->expedition->enabled)) {
8595  continue; // Do not show if module disabled
8596  }
8597  } elseif ($objecttype == 'reception') {
8598  $tplpath = 'reception';
8599  if (empty($conf->reception->enabled)) {
8600  continue; // Do not show if module disabled
8601  }
8602  } elseif ($objecttype == 'delivery') {
8603  $tplpath = 'delivery';
8604  if (empty($conf->expedition->enabled)) {
8605  continue; // Do not show if module disabled
8606  }
8607  } elseif ($objecttype == 'ficheinter') {
8608  $tplpath = 'fichinter';
8609  if (empty($conf->ficheinter->enabled)) {
8610  continue; // Do not show if module disabled
8611  }
8612  } elseif ($objecttype == 'invoice_supplier') {
8613  $tplpath = 'fourn/facture';
8614  } elseif ($objecttype == 'order_supplier') {
8615  $tplpath = 'fourn/commande';
8616  } elseif ($objecttype == 'expensereport') {
8617  $tplpath = 'expensereport';
8618  } elseif ($objecttype == 'subscription') {
8619  $tplpath = 'adherents';
8620  } elseif ($objecttype == 'conferenceorbooth') {
8621  $tplpath = 'eventorganization';
8622  } elseif ($objecttype == 'conferenceorboothattendee') {
8623  $tplpath = 'eventorganization';
8624  } elseif ($objecttype == 'mo') {
8625  $tplpath = 'mrp';
8626  if (empty($conf->mrp->enabled)) {
8627  continue; // Do not show if module disabled
8628  }
8629  }
8630 
8631  global $linkedObjectBlock;
8632  $linkedObjectBlock = $objects;
8633 
8634  // Output template part (modules that overwrite templates must declare this into descriptor)
8635  $dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
8636  foreach ($dirtpls as $reldir) {
8637  if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
8638  global $noMoreLinkedObjectBlockAfter;
8639  $noMoreLinkedObjectBlockAfter = 1;
8640  }
8641 
8642  $res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
8643  if ($res) {
8644  $nboftypesoutput++;
8645  break;
8646  }
8647  }
8648  }
8649 
8650  if (!$nboftypesoutput) {
8651  print '<tr><td class="impair" colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
8652  }
8653 
8654  print '</table>';
8655 
8656  if (!empty($compatibleImportElementsList)) {
8657  $res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
8658  }
8659 
8660 
8661  print '</div>';
8662 
8663  return $nbofdifferenttypes;
8664  }
8665  }
8666 
8675  public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
8676  {
8677  global $conf, $langs, $hookmanager;
8678  global $action;
8679 
8680  $linktoelem = '';
8681  $linktoelemlist = '';
8682  $listofidcompanytoscan = '';
8683 
8684  if (!is_object($object->thirdparty)) {
8685  $object->fetch_thirdparty();
8686  }
8687 
8688  $possiblelinks = array();
8689  if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
8690  $listofidcompanytoscan = $object->thirdparty->id;
8691  if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
8692  $listofidcompanytoscan .= ','.$object->thirdparty->parent;
8693  }
8694  if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
8695  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
8696  $tmpproject = new Project($this->db);
8697  $tmpproject->fetch($object->fk_project);
8698  if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
8699  $listofidcompanytoscan .= ','.$tmpproject->socid;
8700  }
8701  unset($tmpproject);
8702  }
8703 
8704  $possiblelinks = array(
8705  'propal'=>array(
8706  'enabled'=>(!empty($conf->propal->enabled) ? $conf->propal->enabled : 0),
8707  'perms'=>1,
8708  'label'=>'LinkToProposal',
8709  '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').')'),
8710  'order'=>array(
8711  'enabled'=>(!empty($conf->commande->enabled) ? $conf->commande->enabled : 0),
8712  'perms'=>1,
8713  'label'=>'LinkToOrder',
8714  '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').')'),
8715  'invoice'=>array(
8716  'enabled'=>isModEnabled('facture'),
8717  'perms'=>1,
8718  'label'=>'LinkToInvoice',
8719  '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').')'),
8720  'invoice_template'=>array(
8721  'enabled'=>isModEnabled('facture'),
8722  'perms'=>1,
8723  'label'=>'LinkToTemplateInvoice',
8724  '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').')'),
8725  'contrat'=>array(
8726  'enabled'=>(!empty($conf->contrat->enabled) ? $conf->contrat->enabled : 0),
8727  'perms'=>1,
8728  'label'=>'LinkToContract',
8729  '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
8730  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'
8731  ),
8732  'fichinter'=>array(
8733  'enabled'=>(!empty($conf->ficheinter->enabled) ? $conf->ficheinter->enabled : 0),
8734  'perms'=>1,
8735  'label'=>'LinkToIntervention',
8736  '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').')'),
8737  'supplier_proposal'=>array(
8738  'enabled'=>(!empty($conf->supplier_proposal->enabled) ? $conf->supplier_proposal->enabled : 0),
8739  'perms'=>1,
8740  'label'=>'LinkToSupplierProposal',
8741  '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').')'),
8742  'order_supplier'=>array(
8743  'enabled'=>(!empty($conf->supplier_order->enabled) ? $conf->supplier_order->enabled : 0),
8744  'perms'=>1,
8745  'label'=>'LinkToSupplierOrder',
8746  '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').')'),
8747  'invoice_supplier'=>array(
8748  'enabled'=>(!empty($conf->supplier_invoice->enabled) ? $conf->supplier_invoice->enabled : 0),
8749  'perms'=>1, 'label'=>'LinkToSupplierInvoice',
8750  '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').')'),
8751  'ticket'=>array(
8752  'enabled'=>(!empty($conf->ticket->enabled) ? $conf->ticket->enabled : 0),
8753  'perms'=>1,
8754  'label'=>'LinkToTicket',
8755  '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').')'),
8756  'mo'=>array(
8757  'enabled'=>(!empty($conf->mrp->enabled) ? $conf->mrp->enabled : 0),
8758  'perms'=>1,
8759  'label'=>'LinkToMo',
8760  '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').')')
8761  );
8762  }
8763 
8764  if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
8765  // Can complete the possiblelink array
8766  $hookmanager->initHooks(array('commonobject'));
8767  $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
8768  $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8769  }
8770 
8771  if (empty($reshook)) {
8772  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8773  $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
8774  }
8775  } elseif ($reshook > 0) {
8776  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8777  $possiblelinks = $hookmanager->resArray;
8778  }
8779  }
8780 
8781  foreach ($possiblelinks as $key => $possiblelink) {
8782  $num = 0;
8783 
8784  if (empty($possiblelink['enabled'])) {
8785  continue;
8786  }
8787 
8788  if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
8789  print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
8790 
8791  if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8792  print '<br><form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
8793  print '<input type="hidden" name="id" value="' . $object->id . '">';
8794  print '<input type="hidden" name="action" value="addlinkbyref">';
8795  print '<input type="hidden" name="token" value="'.newToken().'">';
8796  print '<input type="hidden" name="addlink" value="' . $key . '">';
8797  print '<table class="noborder">';
8798  print '<tr>';
8799  print '<td>' . $langs->trans("Ref") . '</td>';
8800  print '<td><input type="text" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;<input type="submit" class="button valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;<input type="submit" class="button" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
8801  print '</tr>';
8802  print '</table>';
8803  print '</form>';
8804  }
8805 
8806  $sql = $possiblelink['sql'];
8807 
8808  $resqllist = $this->db->query($sql);
8809  if ($resqllist) {
8810  $num = $this->db->num_rows($resqllist);
8811  $i = 0;
8812 
8813  print '<br>';
8814  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
8815  print '<input type="hidden" name="action" value="addlink">';
8816  print '<input type="hidden" name="token" value="'.newToken().'">';
8817  print '<input type="hidden" name="id" value="'.$object->id.'">';
8818  print '<input type="hidden" name="addlink" value="'.$key.'">';
8819  print '<table class="noborder">';
8820  print '<tr class="liste_titre">';
8821  print '<td class="nowrap"></td>';
8822  print '<td class="center">'.$langs->trans("Ref").'</td>';
8823  print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
8824  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8825  print '<td class="left">'.$langs->trans("Company").'</td>';
8826  print '</tr>';
8827  while ($i < $num) {
8828  $objp = $this->db->fetch_object($resqllist);
8829 
8830  print '<tr class="oddeven">';
8831  print '<td class="left">';
8832  print '<input type="radio" name="idtolinkto" id="'.$key.'_'.$objp->rowid.'" value="'.$objp->rowid.'">';
8833  print '</td>';
8834  print '<td class="center"><label for="'.$key.'_'.$objp->rowid.'">'.$objp->ref.'</label></td>';
8835  print '<td>'.(!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')).'</td>';
8836  print '<td class="right">';
8837  if ($possiblelink['label'] == 'LinkToContract') {
8838  $form = new Form($this->db);
8839  print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' ';
8840  }
8841  print '<span class="amount">'.price($objp->total_ht).'</span>';
8842  print '</td>';
8843  print '<td>'.$objp->name.'</td>';
8844  print '</tr>';
8845  $i++;
8846  }
8847  print '</table>';
8848  print '<div class="center">';
8849  print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly" value="'.$langs->trans('ToLink').'">';
8850  if (empty($conf->use_javascript_ajax)) {
8851  print '<input type="submit" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
8852  } else {
8853  print '<input type="submit"; onclick="javascript:jQuery(\'#'.$key.'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
8854  }
8855  print '</form>';
8856  $this->db->free($resqllist);
8857  } else {
8858  dol_print_error($this->db);
8859  }
8860  print '</div>';
8861 
8862  //$linktoelem.=($linktoelem?' &nbsp; ':'');
8863  if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8864  $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
8865  // } else $linktoelem.=$langs->trans($possiblelink['label']);
8866  } else {
8867  $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
8868  }
8869  }
8870  }
8871 
8872  if ($linktoelemlist) {
8873  $linktoelem = '
8874  <dl class="dropdown" id="linktoobjectname">
8875  ';
8876  if (!empty($conf->use_javascript_ajax)) {
8877  $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>'.$langs->trans("LinkTo").'...</a></dt>';
8878  }
8879  $linktoelem .= '<dd>
8880  <div class="multiselectlinkto">
8881  <ul class="ulselectedfields">'.$linktoelemlist.'
8882  </ul>
8883  </div>
8884  </dd>
8885  </dl>';
8886  } else {
8887  $linktoelem = '';
8888  }
8889 
8890  if (!empty($conf->use_javascript_ajax)) {
8891  print '<!-- Add js to show linkto box -->
8892  <script>
8893  jQuery(document).ready(function() {
8894  jQuery(".linkto").click(function() {
8895  console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
8896  jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
8897  });
8898  });
8899  </script>
8900  ';
8901  }
8902 
8903  return $linktoelem;
8904  }
8905 
8920  public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '', $labelyes = 'Yes', $labelno = 'No')
8921  {
8922  global $langs;
8923 
8924  $yes = "yes";
8925  $no = "no";
8926  if ($option) {
8927  $yes = "1";
8928  $no = "0";
8929  }
8930 
8931 
8932  $disabled = ($disabled ? ' disabled' : '');
8933 
8934  $resultyesno = '<select class="flat width75'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
8935  if ($useempty) {
8936  $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
8937  }
8938  if (("$value" == 'yes') || ($value == 1)) {
8939  $resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans($labelyes).'</option>'."\n";
8940  $resultyesno .= '<option value="'.$no.'">'.$langs->trans($labelno).'</option>'."\n";
8941  } else {
8942  $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
8943  $resultyesno .= '<option value="'.$yes.'">'.$langs->trans($labelyes).'</option>'."\n";
8944  $resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans($labelno).'</option>'."\n";
8945  }
8946  $resultyesno .= '</select>'."\n";
8947 
8948  if ($addjscombo) {
8949  $resultyesno .= ajax_combobox($htmlname);
8950  }
8951 
8952  return $resultyesno;
8953  }
8954 
8955  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8965  public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
8966  {
8967  // phpcs:enable
8968  $sql = "SELECT rowid, label";
8969  $sql .= " FROM ".$this->db->prefix()."export_model";
8970  $sql .= " WHERE type = '".$this->db->escape($type)."'";
8971  $sql .= " ORDER BY rowid";
8972  $result = $this->db->query($sql);
8973  if ($result) {
8974  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
8975  if ($useempty) {
8976  print '<option value="-1">&nbsp;</option>';
8977  }
8978 
8979  $num = $this->db->num_rows($result);
8980  $i = 0;
8981  while ($i < $num) {
8982  $obj = $this->db->fetch_object($result);
8983  if ($selected == $obj->rowid) {
8984  print '<option value="'.$obj->rowid.'" selected>';
8985  } else {
8986  print '<option value="'.$obj->rowid.'">';
8987  }
8988  print $obj->label;
8989  print '</option>';
8990  $i++;
8991  }
8992  print "</select>";
8993  } else {
8994  dol_print_error($this->db);
8995  }
8996  }
8997 
9016  public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9017  {
9018  global $conf, $langs, $hookmanager, $extralanguages;
9019 
9020  $ret = '';
9021  if (empty($fieldid)) {
9022  $fieldid = 'rowid';
9023  }
9024  if (empty($fieldref)) {
9025  $fieldref = 'ref';
9026  }
9027 
9028  // Preparing gender's display if there is one
9029  $addgendertxt = '';
9030  if (property_exists($object, 'gender') && !empty($object->gender)) {
9031  $addgendertxt = ' ';
9032  switch ($object->gender) {
9033  case 'man':
9034  $addgendertxt .= '<i class="fas fa-mars"></i>';
9035  break;
9036  case 'woman':
9037  $addgendertxt .= '<i class="fas fa-venus"></i>';
9038  break;
9039  case 'other':
9040  $addgendertxt .= '<i class="fas fa-transgender"></i>';
9041  break;
9042  }
9043  }
9044 
9045  /*
9046  $addadmin = '';
9047  if (property_exists($object, 'admin')) {
9048  if (!empty($conf->multicompany->enabled) && !empty($object->admin) && empty($object->entity)) {
9049  $addadmin .= img_picto($langs->trans("SuperAdministratorDesc"), "redstar", 'class="paddingleft"');
9050  } elseif (!empty($object->admin)) {
9051  $addadmin .= img_picto($langs->trans("AdministratorDesc"), "star", 'class="paddingleft"');
9052  }
9053  }*/
9054 
9055  // Add where from hooks
9056  if (is_object($hookmanager)) {
9057  $parameters = array('showrefnav' => true);
9058  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9059  $object->next_prev_filter .= $hookmanager->resPrint;
9060  }
9061  $previous_ref = $next_ref = '';
9062  if ($shownav) {
9063  //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9064  $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9065 
9066  $navurl = $_SERVER["PHP_SELF"];
9067  // Special case for project/task page
9068  if ($paramid == 'project_ref') {
9069  if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9070  $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9071  $paramid = 'ref';
9072  }
9073  }
9074 
9075  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9076  // accesskey is for Mac: CTRL + key for all browsers
9077  $stringforfirstkey = $langs->trans("KeyboardShortcut");
9078  if ($conf->browser->name == 'chrome') {
9079  $stringforfirstkey .= ' ALT +';
9080  } elseif ($conf->browser->name == 'firefox') {
9081  $stringforfirstkey .= ' ALT + SHIFT +';
9082  } else {
9083  $stringforfirstkey .= ' CTL +';
9084  }
9085 
9086  $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>';
9087  $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>';
9088  }
9089 
9090  //print "xx".$previous_ref."x".$next_ref;
9091  $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9092 
9093  // Right part of banner
9094  if ($morehtmlright) {
9095  $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
9096  }
9097 
9098  if ($previous_ref || $next_ref || $morehtml) {
9099  $ret .= '<div class="pagination paginationref"><ul class="right">';
9100  }
9101  if ($morehtml) {
9102  $ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>';
9103  }
9104  if ($shownav && ($previous_ref || $next_ref)) {
9105  $ret .= '<li class="pagination">'.$previous_ref.'</li>';
9106  $ret .= '<li class="pagination">'.$next_ref.'</li>';
9107  }
9108  if ($previous_ref || $next_ref || $morehtml) {
9109  $ret .= '</ul></div>';
9110  }
9111 
9112  $parameters = array();
9113  $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9114  if (empty($reshook)) {
9115  $morehtmlstatus .= $hookmanager->resPrint;
9116  } else {
9117  $morehtmlstatus = $hookmanager->resPrint;
9118  }
9119  if ($morehtmlstatus) {
9120  $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
9121  }
9122 
9123  $parameters = array();
9124  $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9125  if (empty($reshook)) {
9126  $morehtmlref .= $hookmanager->resPrint;
9127  } elseif ($reshook > 0) {
9128  $morehtmlref = $hookmanager->resPrint;
9129  }
9130 
9131  // Left part of banner
9132  if ($morehtmlleft) {
9133  if ($conf->browser->layout == 'phone') {
9134  $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
9135  } else {
9136  $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
9137  }
9138  }
9139 
9140  //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9141  $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
9142 
9143  // For thirdparty, contact, user, member, the ref is the id, so we show something else
9144  if ($object->element == 'societe') {
9145  $ret .= dol_htmlentities($object->name);
9146 
9147  // List of extra languages
9148  $arrayoflangcode = array();
9149  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
9150  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
9151  }
9152 
9153  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9154  if (!is_object($extralanguages)) {
9155  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
9156  $extralanguages = new ExtraLanguages($this->db);
9157  }
9158  $extralanguages->fetch_name_extralanguages('societe');
9159 
9160  if (!empty($extralanguages->attributes['societe']['name'])) {
9161  $object->fetchValuesForExtraLanguages();
9162 
9163  $htmltext = '';
9164  // If there is extra languages
9165  foreach ($arrayoflangcode as $extralangcode) {
9166  $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9167  if ($object->array_languages['name'][$extralangcode]) {
9168  $htmltext .= $object->array_languages['name'][$extralangcode];
9169  } else {
9170  $htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
9171  }
9172  }
9173  $ret .= '<!-- Show translations of name -->'."\n";
9174  $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
9175  }
9176  }
9177  } elseif ($object->element == 'member') {
9178  $ret .= $object->ref.'<br>';
9179  $fullname = $object->getFullName($langs);
9180  if ($object->morphy == 'mor' && $object->societe) {
9181  $ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).$addgendertxt.')' : '');
9182  } else {
9183  $ret .= dol_htmlentities($fullname).$addgendertxt.((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
9184  }
9185  } elseif (in_array($object->element, array('contact', 'user', 'usergroup'))) {
9186  $ret .= dol_htmlentities($object->getFullName($langs)).$addgendertxt;
9187  } elseif (in_array($object->element, array('action', 'agenda'))) {
9188  $ret .= $object->ref.'<br>'.$object->label;
9189  } elseif (in_array($object->element, array('adherent_type'))) {
9190  $ret .= $object->label;
9191  } elseif ($object->element == 'ecm_directories') {
9192  $ret .= '';
9193  } elseif ($fieldref != 'none') {
9194  $ret .= dol_htmlentities($object->$fieldref);
9195  }
9196 
9197  if ($morehtmlref) {
9198  // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9199  if (substr($morehtmlref, 0, 4) != '<div') {
9200  $ret .= ' ';
9201  }
9202 
9203  $ret .= $morehtmlref;
9204  }
9205 
9206  $ret .= '</div>';
9207 
9208  $ret .= '</div><!-- End banner content -->';
9209 
9210  return $ret;
9211  }
9212 
9213 
9222  public function showbarcode(&$object, $width = 100, $morecss = '')
9223  {
9224  global $conf;
9225 
9226  //Check if barcode is filled in the card
9227  if (empty($object->barcode)) {
9228  return '';
9229  }
9230 
9231  // Complete object if not complete
9232  if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
9233  $result = $object->fetch_barcode();
9234  //Check if fetch_barcode() failed
9235  if ($result < 1) {
9236  return '<!-- ErrorFetchBarcode -->';
9237  }
9238  }
9239 
9240  // Barcode image
9241  $url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
9242  $out = '<!-- url barcode = '.$url.' -->';
9243  $out .= '<img src="'.$url.'"'.($morecss ? ' class="'.$morecss.'"' : '').'>';
9244  return $out;
9245  }
9246 
9263  public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
9264  {
9265  global $conf, $langs;
9266 
9267  $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
9268  $id = (!empty($object->id) ? $object->id : $object->rowid);
9269 
9270  $ret = '';
9271  $dir = '';
9272  $file = '';
9273  $originalfile = '';
9274  $altfile = '';
9275  $email = '';
9276  $capture = '';
9277  if ($modulepart == 'societe') {
9278  $dir = $conf->societe->multidir_output[$entity];
9279  if (!empty($object->logo)) {
9280  if (dolIsAllowedForPreview($object->logo)) {
9281  if ((string) $imagesize == 'mini') {
9282  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
9283  } elseif ((string) $imagesize == 'small') {
9284  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small');
9285  } else {
9286  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9287  }
9288  $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9289  }
9290  }
9291  $email = $object->email;
9292  } elseif ($modulepart == 'contact') {
9293  $dir = $conf->societe->multidir_output[$entity].'/contact';
9294  if (!empty($object->photo)) {
9295  if (dolIsAllowedForPreview($object->photo)) {
9296  if ((string) $imagesize == 'mini') {
9297  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9298  } elseif ((string) $imagesize == 'small') {
9299  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small');
9300  } else {
9301  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9302  }
9303  $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9304  }
9305  }
9306  $email = $object->email;
9307  $capture = 'user';
9308  } elseif ($modulepart == 'userphoto') {
9309  $dir = $conf->user->dir_output;
9310  if (!empty($object->photo)) {
9311  if (dolIsAllowedForPreview($object->photo)) {
9312  if ((string) $imagesize == 'mini') {
9313  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9314  } elseif ((string) $imagesize == 'small') {
9315  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_small');
9316  } else {
9317  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9318  }
9319  $originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9320  }
9321  }
9322  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9323  $altfile = $object->id.".jpg"; // For backward compatibility
9324  }
9325  $email = $object->email;
9326  $capture = 'user';
9327  } elseif ($modulepart == 'memberphoto') {
9328  $dir = $conf->adherent->dir_output;
9329  if (!empty($object->photo)) {
9330  if (dolIsAllowedForPreview($object->photo)) {
9331  if ((string) $imagesize == 'mini') {
9332  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9333  } elseif ((string) $imagesize == 'small') {
9334  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
9335  } else {
9336  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9337  }
9338  $originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9339  }
9340  }
9341  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9342  $altfile = $object->id.".jpg"; // For backward compatibility
9343  }
9344  $email = $object->email;
9345  $capture = 'user';
9346  } else {
9347  // Generic case to show photos
9348  $dir = $conf->$modulepart->dir_output;
9349  if (!empty($object->photo)) {
9350  if (dolIsAllowedForPreview($object->photo)) {
9351  if ((string) $imagesize == 'mini') {
9352  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
9353  } elseif ((string) $imagesize == 'small') {
9354  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
9355  } else {
9356  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9357  }
9358  $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9359  }
9360  }
9361  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9362  $altfile = $object->id.".jpg"; // For backward compatibility
9363  }
9364  $email = $object->email;
9365  }
9366 
9367  if ($forcecapture) {
9368  $capture = $forcecapture;
9369  }
9370 
9371  if ($dir) {
9372  if ($file && file_exists($dir."/".$file)) {
9373  if ($addlinktofullsize) {
9374  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9375  if ($urladvanced) {
9376  $ret .= '<a href="'.$urladvanced.'">';
9377  } else {
9378  $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9379  }
9380  }
9381  $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.'">';
9382  if ($addlinktofullsize) {
9383  $ret .= '</a>';
9384  }
9385  } elseif ($altfile && file_exists($dir."/".$altfile)) {
9386  if ($addlinktofullsize) {
9387  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9388  if ($urladvanced) {
9389  $ret .= '<a href="'.$urladvanced.'">';
9390  } else {
9391  $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9392  }
9393  }
9394  $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.'">';
9395  if ($addlinktofullsize) {
9396  $ret .= '</a>';
9397  }
9398  } else {
9399  $nophoto = '/public/theme/common/nophoto.png';
9400  $defaultimg = 'identicon'; // For gravatar
9401  if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
9402  if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor')) !== false) {
9403  $nophoto = 'company';
9404  } else {
9405  $nophoto = '/public/theme/common/user_anonymous.png';
9406  if (!empty($object->gender) && $object->gender == 'man') {
9407  $nophoto = '/public/theme/common/user_man.png';
9408  }
9409  if (!empty($object->gender) && $object->gender == 'woman') {
9410  $nophoto = '/public/theme/common/user_woman.png';
9411  }
9412  }
9413  }
9414 
9415  if (!empty($conf->gravatar->enabled) && $email && empty($noexternsourceoverwrite)) {
9416  // see https://gravatar.com/site/implement/images/php/
9417  $ret .= '<!-- Put link to gravatar -->';
9418  $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
9419  } else {
9420  if ($nophoto == 'company') {
9421  $ret .= '<div class="divforspanimg photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').'>'.img_picto('', 'company').'</div>';
9422  $ret .= '<div class="difforspanimgright"></div>';
9423  } else {
9424  $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
9425  }
9426  }
9427  }
9428 
9429  if ($caneditfield) {
9430  if ($object->photo) {
9431  $ret .= "<br>\n";
9432  }
9433  $ret .= '<table class="nobordernopadding centpercent">';
9434  if ($object->photo) {
9435  $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">'.$langs->trans("Delete").'</label><br><br></td></tr>';
9436  }
9437  $ret .= '<tr><td class="tdoverflow">';
9438  $maxfilesizearray = getMaxFileSizeArray();
9439  $maxmin = $maxfilesizearray['maxmin'];
9440  if ($maxmin > 0) {
9441  $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
9442  }
9443  $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'>';
9444  $ret .= '</td></tr>';
9445  $ret .= '</table>';
9446  }
9447  } else {
9448  dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
9449  }
9450 
9451  return $ret;
9452  }
9453 
9454  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9471  public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
9472  {
9473  // phpcs:enable
9474  global $conf, $user, $langs;
9475 
9476  // Permettre l'exclusion de groupes
9477  $excludeGroups = null;
9478  if (is_array($exclude)) {
9479  $excludeGroups = implode(",", $exclude);
9480  }
9481  // Permettre l'inclusion de groupes
9482  $includeGroups = null;
9483  if (is_array($include)) {
9484  $includeGroups = implode(",", $include);
9485  }
9486 
9487  if (!is_array($selected)) {
9488  $selected = array($selected);
9489  }
9490 
9491  $out = '';
9492 
9493  // On recherche les groupes
9494  $sql = "SELECT ug.rowid, ug.nom as name";
9495  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
9496  $sql .= ", e.label";
9497  }
9498  $sql .= " FROM ".$this->db->prefix()."usergroup as ug ";
9499  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
9500  $sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid=ug.entity";
9501  if ($force_entity) {
9502  $sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
9503  } else {
9504  $sql .= " WHERE ug.entity IS NOT NULL";
9505  }
9506  } else {
9507  $sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
9508  }
9509  if (is_array($exclude) && $excludeGroups) {
9510  $sql .= " AND ug.rowid NOT IN (".$this->db->sanitize($excludeGroups).")";
9511  }
9512  if (is_array($include) && $includeGroups) {
9513  $sql .= " AND ug.rowid IN (".$this->db->sanitize($includeGroups).")";
9514  }
9515  $sql .= " ORDER BY ug.nom ASC";
9516 
9517  dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
9518  $resql = $this->db->query($sql);
9519  if ($resql) {
9520  // Enhance with select2
9521  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9522 
9523  $out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
9524 
9525  $num = $this->db->num_rows($resql);
9526  $i = 0;
9527  if ($num) {
9528  if ($show_empty && !$multiple) {
9529  $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
9530  }
9531 
9532  while ($i < $num) {
9533  $obj = $this->db->fetch_object($resql);
9534  $disableline = 0;
9535  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
9536  $disableline = 1;
9537  }
9538 
9539  $out .= '<option value="'.$obj->rowid.'"';
9540  if ($disableline) {
9541  $out .= ' disabled';
9542  }
9543  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))) {
9544  $out .= ' selected';
9545  }
9546  $out .= '>';
9547 
9548  $out .= $obj->name;
9549  if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
9550  $out .= " (".$obj->label.")";
9551  }
9552 
9553  $out .= '</option>';
9554  $i++;
9555  }
9556  } else {
9557  if ($show_empty) {
9558  $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
9559  }
9560  $out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
9561  }
9562  $out .= '</select>';
9563 
9564  $out .= ajax_combobox($htmlname);
9565  } else {
9566  dol_print_error($this->db);
9567  }
9568 
9569  return $out;
9570  }
9571 
9572 
9579  public function showFilterButtons($pos = '')
9580  {
9581  $out = '<div class="nowraponall">';
9582  if ($pos == 'left') {
9583  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9584  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9585  } else {
9586  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9587  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9588  }
9589  $out .= '</div>';
9590 
9591  return $out;
9592  }
9593 
9602  public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9603  {
9604  global $conf, $langs;
9605 
9606  $out = '';
9607 
9608  if (!empty($conf->use_javascript_ajax)) {
9609  $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
9610  }
9611  $out .= '<script>
9612  $(document).ready(function() {
9613  $("#' . $cssclass.'s").click(function() {
9614  if($(this).is(\':checked\')){
9615  console.log("We check all '.$cssclass.' and trigger the change method");
9616  $(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
9617  }
9618  else
9619  {
9620  console.log("We uncheck all");
9621  $(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
9622  }'."\n";
9623  if ($calljsfunction) {
9624  $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
9625  }
9626  $out .= ' });
9627  $(".' . $cssclass.'").change(function() {
9628  $(this).closest("tr").toggleClass("highlight", this.checked);
9629  });
9630  });
9631  </script>';
9632 
9633  return $out;
9634  }
9635 
9645  public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9646  {
9647  $out = $this->showFilterButtons();
9648  if ($addcheckuncheckall) {
9649  $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
9650  }
9651  return $out;
9652  }
9653 
9667  public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
9668  {
9669  global $langs, $user;
9670 
9671  $out = '';
9672  $sql = "SELECT rowid, label FROM ".$this->db->prefix()."c_exp_tax_cat WHERE active = 1";
9673  $sql .= " AND entity IN (0,".getEntity('exp_tax_cat').")";
9674  if (!empty($excludeid)) {
9675  $sql .= " AND rowid NOT IN (".$this->db->sanitize(implode(',', $excludeid)).")";
9676  }
9677  $sql .= " ORDER BY label";
9678 
9679  $resql = $this->db->query($sql);
9680  if ($resql) {
9681  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
9682  if ($useempty) {
9683  $out .= '<option value="0">&nbsp;</option>';
9684  }
9685 
9686  while ($obj = $this->db->fetch_object($resql)) {
9687  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
9688  }
9689  $out .= '</select>';
9690  $out .= ajax_combobox('select_'.$htmlname);
9691 
9692  if (!empty($htmlname) && $user->admin && $info_admin) {
9693  $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
9694  }
9695 
9696  if (!empty($target)) {
9697  $sql = "SELECT c.id FROM ".$this->db->prefix()."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
9698  $resql = $this->db->query($sql);
9699  if ($resql) {
9700  if ($this->db->num_rows($resql) > 0) {
9701  $obj = $this->db->fetch_object($resql);
9702  $out .= '<script>
9703  $(function() {
9704  $("select[name='.$target.']").on("change", function() {
9705  var current_val = $(this).val();
9706  if (current_val == '.$obj->id.') {';
9707  if (!empty($default_selected) || !empty($selected)) {
9708  $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
9709  }
9710 
9711  $out .= '
9712  $("select[name='.$htmlname.']").change();
9713  }
9714  });
9715 
9716  $("select[name='.$htmlname.']").change(function() {
9717 
9718  if ($("select[name='.$target.']").val() == '.$obj->id.') {
9719  // get price of kilometer to fill the unit price
9720  $.ajax({
9721  method: "POST",
9722  dataType: "json",
9723  data: { fk_c_exp_tax_cat: $(this).val(), token: \''.currentToken().'\' },
9724  url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php?'.$params).'",
9725  }).done(function( data, textStatus, jqXHR ) {
9726  console.log(data);
9727  if (typeof data.up != "undefined") {
9728  $("input[name=value_unit]").val(data.up);
9729  $("select[name='.$htmlname.']").attr("title", data.title);
9730  } else {
9731  $("input[name=value_unit]").val("");
9732  $("select[name='.$htmlname.']").attr("title", "");
9733  }
9734  });
9735  }
9736  });
9737  });
9738  </script>';
9739  }
9740  }
9741  }
9742  } else {
9743  dol_print_error($this->db);
9744  }
9745 
9746  return $out;
9747  }
9748 
9757  public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
9758  {
9759  global $conf, $langs;
9760 
9761  $out = '';
9762  $sql = "SELECT rowid, range_ik FROM ".$this->db->prefix()."c_exp_tax_range";
9763  $sql .= " WHERE entity = ".$conf->entity." AND active = 1";
9764 
9765  $resql = $this->db->query($sql);
9766  if ($resql) {
9767  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9768  if ($useempty) {
9769  $out .= '<option value="0"></option>';
9770  }
9771 
9772  while ($obj = $this->db->fetch_object($resql)) {
9773  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
9774  }
9775  $out .= '</select>';
9776  } else {
9777  dol_print_error($this->db);
9778  }
9779 
9780  return $out;
9781  }
9782 
9793  public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
9794  {
9795  global $langs;
9796 
9797  $out = '';
9798  $sql = "SELECT id, code, label FROM ".$this->db->prefix()."c_type_fees";
9799  $sql .= " WHERE active = 1";
9800 
9801  $resql = $this->db->query($sql);
9802  if ($resql) {
9803  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9804  if ($useempty) {
9805  $out .= '<option value="0"></option>';
9806  }
9807  if ($allchoice) {
9808  $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
9809  }
9810 
9811  $field = 'code';
9812  if ($useid) {
9813  $field = 'id';
9814  }
9815 
9816  while ($obj = $this->db->fetch_object($resql)) {
9817  $key = $langs->trans($obj->code);
9818  $out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
9819  }
9820  $out .= '</select>';
9821  } else {
9822  dol_print_error($this->db);
9823  }
9824 
9825  return $out;
9826  }
9827 
9846  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)
9847  {
9848  global $user, $conf, $langs;
9849 
9850  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
9851 
9852  if (is_null($usertofilter)) {
9853  $usertofilter = $user;
9854  }
9855 
9856  $out = '';
9857 
9858  $hideunselectables = false;
9859  if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
9860  $hideunselectables = true;
9861  }
9862 
9863  if (empty($projectsListId)) {
9864  if (empty($usertofilter->rights->projet->all->lire)) {
9865  $projectstatic = new Project($this->db);
9866  $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
9867  }
9868  }
9869 
9870  // Search all projects
9871  $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
9872  p.title, p.fk_soc, p.fk_statut, p.public,";
9873  $sql .= ' s.nom as name';
9874  $sql .= ' FROM '.$this->db->prefix().'projet as p';
9875  $sql .= ' LEFT JOIN '.$this->db->prefix().'societe as s ON s.rowid = p.fk_soc,';
9876  $sql .= ' '.$this->db->prefix().'facture as f';
9877  $sql .= " WHERE p.entity IN (".getEntity('project').")";
9878  $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
9879  //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
9880  //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
9881  //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
9882  $sql .= " ORDER BY p.ref, f.ref ASC";
9883 
9884  $resql = $this->db->query($sql);
9885  if ($resql) {
9886  // Use select2 selector
9887  if (!empty($conf->use_javascript_ajax)) {
9888  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9889  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
9890  $out .= $comboenhancement;
9891  $morecss = 'minwidth200imp maxwidth500';
9892  }
9893 
9894  if (empty($option_only)) {
9895  $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
9896  }
9897  if (!empty($show_empty)) {
9898  $out .= '<option value="0" class="optiongrey">';
9899  if (!is_numeric($show_empty)) {
9900  $out .= $show_empty;
9901  } else {
9902  $out .= '&nbsp;';
9903  }
9904  $out .= '</option>';
9905  }
9906  $num = $this->db->num_rows($resql);
9907  $i = 0;
9908  if ($num) {
9909  while ($i < $num) {
9910  $obj = $this->db->fetch_object($resql);
9911  // 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.
9912  if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
9913  // Do nothing
9914  } else {
9915  if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
9916  $i++;
9917  continue;
9918  }
9919 
9920  $labeltoshow = '';
9921 
9922  if ($showproject == 'all') {
9923  $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
9924  if ($obj->name) {
9925  $labeltoshow .= ' - '.$obj->name; // Soc name
9926  }
9927 
9928  $disabled = 0;
9929  if ($obj->fk_statut == Project::STATUS_DRAFT) {
9930  $disabled = 1;
9931  $labeltoshow .= ' - '.$langs->trans("Draft");
9932  } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
9933  if ($discard_closed == 2) {
9934  $disabled = 1;
9935  }
9936  $labeltoshow .= ' - '.$langs->trans("Closed");
9937  } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
9938  $disabled = 1;
9939  $labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
9940  }
9941  }
9942 
9943  if (!empty($selected) && $selected == $obj->rowid) {
9944  $out .= '<option value="'.$obj->rowid.'" selected';
9945  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
9946  $out .= '>'.$labeltoshow.'</option>';
9947  } else {
9948  if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
9949  $resultat = '';
9950  } else {
9951  $resultat = '<option value="'.$obj->rowid.'"';
9952  if ($disabled) {
9953  $resultat .= ' disabled';
9954  }
9955  //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
9956  //else $labeltoshow.=' ('.$langs->trans("Private").')';
9957  $resultat .= '>';
9958  $resultat .= $labeltoshow;
9959  $resultat .= '</option>';
9960  }
9961  $out .= $resultat;
9962  }
9963  }
9964  $i++;
9965  }
9966  }
9967  if (empty($option_only)) {
9968  $out .= '</select>';
9969  }
9970 
9971  print $out;
9972 
9973  $this->db->free($resql);
9974  return $num;
9975  } else {
9976  dol_print_error($this->db);
9977  return -1;
9978  }
9979  }
9980 
9994  public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
9995  {
9996  global $user, $conf, $langs;
9997 
9998  $out = '';
9999 
10000  dol_syslog('FactureRec::fetch', LOG_DEBUG);
10001 
10002  $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10003  //$sql.= ', el.fk_source';
10004  $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10005  $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10006  $sql .= " ORDER BY f.titre ASC";
10007 
10008  $resql = $this->db->query($sql);
10009  if ($resql) {
10010  // Use select2 selector
10011  if (!empty($conf->use_javascript_ajax)) {
10012  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10013  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10014  $out .= $comboenhancement;
10015  $morecss = 'minwidth200imp maxwidth500';
10016  }
10017 
10018  if (empty($option_only)) {
10019  $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10020  }
10021  if (!empty($show_empty)) {
10022  $out .= '<option value="0" class="optiongrey">';
10023  if (!is_numeric($show_empty)) {
10024  $out .= $show_empty;
10025  } else {
10026  $out .= '&nbsp;';
10027  }
10028  $out .= '</option>';
10029  }
10030  $num = $this->db->num_rows($resql);
10031  if ($num) {
10032  while ($obj = $this->db->fetch_object($resql)) {
10033  $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10034 
10035  $disabled = 0;
10036  if (!empty($obj->suspended)) {
10037  $disabled = 1;
10038  $labeltoshow .= ' - ' . $langs->trans("Closed");
10039  }
10040 
10041 
10042  if (!empty($selected) && $selected == $obj->rowid) {
10043  $out .= '<option value="' . $obj->rowid . '" selected';
10044  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10045  $out .= '>' . $labeltoshow . '</option>';
10046  } else {
10047  if ($disabled && ($selected != $obj->rowid)) {
10048  $resultat = '';
10049  } else {
10050  $resultat = '<option value="' . $obj->rowid . '"';
10051  if ($disabled) {
10052  $resultat .= ' disabled';
10053  }
10054  $resultat .= '>';
10055  $resultat .= $labeltoshow;
10056  $resultat .= '</option>';
10057  }
10058  $out .= $resultat;
10059  }
10060  }
10061  }
10062  if (empty($option_only)) {
10063  $out .= '</select>';
10064  }
10065 
10066  print $out;
10067 
10068  $this->db->free($resql);
10069  return $num;
10070  } else {
10071  $this->errors[]=$this->db->lasterror;
10072  return -1;
10073  }
10074  }
10075 
10085  public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10086  {
10087  global $langs;
10088 
10089  $ret = '';
10090 
10091  $ret .= '<div class="divadvancedsearchfieldcomp inline-block">';
10092  //$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
10093  $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10094  $ret .= '<span class="fas fa-filter linkobject boxfilter pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("Filters")).'" id="idsubimgproductdistribution"></span>';
10095  //$ret .= $langs->trans("Filters");
10096  $ret .= '</a>';
10097 
10098  $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10099 
10100  // Show select fields as tags.
10101  $ret .= '<div name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10102 
10103  if ($search_component_params_hidden) {
10104  if (!preg_match('/^\(.*\)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10105  $search_component_params_hidden .= '('.$search_component_params_hidden.')';
10106  }
10107  $errormessage = '';
10108  if (!dolCheckFilters($search_component_params_hidden, $errormessage)) {
10109  print 'ERROR in parsing search string';
10110  }
10111  $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
10112  //var_dump($search_component_params_hidden);
10113  $htmltags = preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $search_component_params_hidden);
10114  //var_dump($htmltags);
10115  $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch"><span class="tagsearchdelete select2-selection__choice__remove">x</span> '.$htmltags.'</span>';
10116  }
10117 
10118  //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10119 
10120  //$ret .= search_component_params
10121  //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10122  //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10123 
10124  $show_search_component_params_hidden = 1;
10125  if ($show_search_component_params_hidden) {
10126  $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10127  }
10128  $ret .= "<!-- We store the full search string into this field. For example: (t.ref:like:'SO-%') and ((t.ref:like:'CO-%') or (t.ref:like:'AA%')) -->";
10129  $ret .= '<input type="hidden" name="search_component_params_hidden" value="'.dol_escape_htmltag($search_component_params_hidden).'">';
10130  // For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
10131  foreach ($arrayofcriterias as $criterias) {
10132  foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
10133  if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10134  continue;
10135  }
10136  if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10137  continue;
10138  }
10139  if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10140  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
10141  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
10142  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
10143  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
10144  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
10145  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
10146  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
10147  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
10148  } else {
10149  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
10150  }
10151  }
10152  }
10153 
10154  $ret .= '</div>';
10155 
10156  $ret .= "<!-- Syntax of 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";
10157  $ret .= '<input type="text" placeholder="'.$langs->trans("Search").'" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10158 
10159  $ret .= '</div>';
10160  $ret .= '</div>';
10161 
10162  return $ret;
10163  }
10164 
10174  public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
10175  {
10176  global $langs, $user;
10177 
10178  $retstring = '';
10179 
10180  $TModels = array();
10181 
10182  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
10183  $formmail = new FormMail($this->db);
10184  $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
10185 
10186  if ($default) {
10187  $TModels[0] = $langs->trans('DefaultMailModel');
10188  }
10189  if ($result > 0) {
10190  foreach ($formmail->lines_model as $model) {
10191  $TModels[$model->id] = $model->label;
10192  }
10193  }
10194 
10195  $retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
10196 
10197  foreach ($TModels as $id_model => $label_model) {
10198  $retstring .= '<option value="'.$id_model.'"';
10199  $retstring .= ">".$label_model."</option>";
10200  }
10201 
10202  $retstring .= "</select>";
10203 
10204  if ($addjscombo) {
10205  $retstring .= ajax_combobox('select_'.$prefix.'model_mail');
10206  }
10207 
10208  return $retstring;
10209  }
10210 
10222  public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = 0, $morecss = '', $dol_openinpopup = '')
10223  {
10224  global $langs;
10225 
10226  $buttons = array();
10227 
10228  $save = array(
10229  'name' => 'save',
10230  'label_key' => $save_label,
10231  );
10232 
10233  if ($save_label == 'Create' || $save_label == 'Add' ) {
10234  $save['name'] = 'add';
10235  } elseif ($save_label == 'Modify') {
10236  $save['name'] = 'edit';
10237  }
10238 
10239  $cancel = array(
10240  'name' => 'cancel',
10241  'label_key' => 'Cancel',
10242  );
10243 
10244  !empty($save_label) ? $buttons[] = $save : '';
10245 
10246  if (!empty($morebuttons)) {
10247  $buttons[] = $morebuttons;
10248  }
10249 
10250  !empty($cancel_label) ? $buttons[] = $cancel : '';
10251 
10252  $retstring = $withoutdiv ? '': '<div class="center">';
10253 
10254  foreach ($buttons as $button) {
10255  $addclass = empty($button['addclass']) ? '' : $button['addclass'];
10256  $retstring .= '<input type="submit" class="button button-'.$button['name'].($morecss ? ' '.$morecss : '').' '.$addclass.'" name="'.$button['name'].'" value="'.dol_escape_htmltag($langs->trans($button['label_key'])).'">';
10257  }
10258  $retstring .= $withoutdiv ? '': '</div>';
10259 
10260  if ($dol_openinpopup) {
10261  $retstring .= '<!-- buttons are shown into a $dol_openinpopup='.$dol_openinpopup.' context, so we enable the close of dialog on cancel -->'."\n";
10262  $retstring .= '<script>';
10263  $retstring .= 'jQuery(".button-cancel").click(function(e) {
10264  e.preventDefault(); console.log(\'We click on cancel in iframe popup '.$dol_openinpopup.'\');
10265  window.parent.jQuery(\'#idfordialog'.$dol_openinpopup.'\').dialog(\'close\');
10266  });';
10267  $retstring .= '</script>';
10268  }
10269 
10270  return $retstring;
10271  }
10272 }
Form\form_modes_reglement
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='')
Show form with payment mode.
Definition: html.form.class.php:5570
Form\selectMultiCurrency
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
Definition: html.form.class.php:5959
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:48
Form\showLinkedObjectBlock
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=false, $title='RelatedObjects')
Show linked object block.
Definition: html.form.class.php:8517
ajax_combobox
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:438
db
$conf db
API class for accounts.
Definition: inc.php:41
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
Definition: functions.lib.php:1468
Form\showrefnav
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...
Definition: html.form.class.php:9016
Form\form_conditions_reglement
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1)
Show a form to select payment conditions.
Definition: html.form.class.php:5370
dol_trunc
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.
Definition: functions.lib.php:3805
ajax_autocompleter
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
Form\formSelectShippingMethod
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
Definition: html.form.class.php:4483
Form\formSelectTransportMode
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
Definition: html.form.class.php:5604
Project
Class to manage projects.
Definition: project.class.php:35
Form\select_dolgroups
select_dolgroups($selected='', $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity='0', $multiple=false, $morecss='')
Return select list of groups.
Definition: html.form.class.php:9471
Form\select_comptes
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
Definition: html.form.class.php:4622
Form\select_dolusers_forevent
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.
Definition: html.form.class.php:2168
Form\load_cache_conditions_paiements
load_cache_conditions_paiements()
Load into cache list of payment terms.
Definition: html.form.class.php:3762
Form\searchComponent
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='')
Output the component to make advanced search criteries.
Definition: html.form.class.php:10085
ProductFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.product.class.php:41
Form\__construct
__construct($db)
Constructor.
Definition: html.form.class.php:86
Form\showbarcode
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
Definition: html.form.class.php:9222
Form\select_incoterms
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
Definition: html.form.class.php:1015
Form\load_cache_availability
load_cache_availability()
Load int a cache property th elist of possible delivery delays.
Definition: html.form.class.php:3810
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
dol_nl2br
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
Definition: functions.lib.php:6963
Form\selectEstablishments
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
Definition: html.form.class.php:4705
Form\select_dolusers
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='', $noactive=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
Definition: html.form.class.php:1925
Form\selectSituationInvoices
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
Definition: html.form.class.php:4514
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4844
Form\selectyesno
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.
Definition: html.form.class.php:8920
dol_sort_array
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...
Definition: functions.lib.php:8385
Entrepot\STATUS_OPEN_INTERNAL
const STATUS_OPEN_INTERNAL
Warehouse open and operations for stock transfers/corrections allowed (not for customer shipping and ...
Definition: entrepot.class.php:161
img_help
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
Definition: functions.lib.php:4481
Form\select_remises
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
Definition: html.form.class.php:1553
dolCheckFilters
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter is valid and will pass the preg_replace_callback() to replace Gener...
Definition: functions.lib.php:11142
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1033
Form\selectForForms
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.
Definition: html.form.class.php:7546
img_warning
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
Definition: functions.lib.php:4521
ExtraLanguages
Class to manage standard extra languages.
Definition: extralanguages.class.php:28
Form\selectShippingMethod
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
Definition: html.form.class.php:4424
ajax_multiautocompleter
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:287
Form\showCheckAddButtons
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
Definition: html.form.class.php:9602
FormProjets
Class to manage building of HTML components.
Definition: html.formprojet.class.php:30
picto_from_langcode
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
Definition: functions.lib.php:8742
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:142
Form\formInputReason
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
Definition: html.form.class.php:5447
Form\selectPriceBaseType
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
Definition: html.form.class.php:4267
Form\select_country
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.
Definition: html.form.class.php:883
Form\selectDateToDate
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...
Definition: html.form.class.php:6316
Form\select_thirdparty_list
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.
Definition: html.form.class.php:1335
name
$conf db name
Definition: repair.php:122
Form\load_cache_types_fees
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
Definition: html.form.class.php:1156
Categorie
Class to manage categories.
Definition: categorie.class.php:47
Form\selectExpenseCategories
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.
Definition: html.form.class.php:9667
Facture
Class to manage invoices.
Definition: facture.class.php:60
img_edit
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
Definition: functions.lib.php:4389
Form\select_date
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...
Definition: html.form.class.php:6290
Form\form_multicurrency_code
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
Definition: html.form.class.php:5633
Form\form_confirm
form_confirm($page, $title, $question, $action, $formquestion='', $selectedchoice="", $useajax=0, $height=170, $width=500)
Show a confirmation HTML form or AJAX popup.
Definition: html.form.class.php:4903
Form\selectCurrency
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
Definition: html.form.class.php:5903
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
measuringUnitString
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
Definition: product.lib.php:619
Form\selectModelMail
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0)
selectModelMail
Definition: html.form.class.php:10174
Form\selectInvoiceRec
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.
Definition: html.form.class.php:9994
Form\form_date
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
Definition: html.form.class.php:5486
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
Form\editfieldval
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=0, $formatfunc='', $paramid='id', $gm='auto')
Output value of a field for an editable field.
Definition: html.form.class.php:206
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:3880
Form\formconfirm
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
Show a confirmation HTML form or AJAX popup.
Definition: html.form.class.php:4936
Form\form_remise_dispo
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.
Definition: html.form.class.php:5705
Form\form_multicurrency_rate
form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
Definition: html.form.class.php:5660
Form\select_export_model
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
Definition: html.form.class.php:8965
Entrepot\STATUS_OPEN_ALL
const STATUS_OPEN_ALL
Warehouse open and operations for customer shipping, supplier dispatch, internal stock transfers/corr...
Definition: entrepot.class.php:156
Form\buttonsSaveCancel
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=0, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
Definition: html.form.class.php:10222
PriceParser
Class to parse product price expressions.
Definition: price_parser.class.php:33
Form\select_currency
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
Definition: html.form.class.php:5888
Form\select_conditions_paiements
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
print list of payment modes.
Definition: html.form.class.php:4052
Form\select_type_of_lines
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...
Definition: html.form.class.php:1101
getMaxFileSizeArray
getMaxFileSizeArray()
Return the max allowed for file upload.
Definition: security.lib.php:993
get_exdir
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
Definition: functions.lib.php:6549
$formconfirm
$formconfirm
if ($action == 'delbookkeepingyear') {
Definition: listbyaccount.php:576
Form\select_bom
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.
Definition: html.form.class.php:2432
dol_escape_js
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
Definition: functions.lib.php:1423
Form\select_types_paiements
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...
Definition: html.form.class.php:4167
get_default_npr
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
Definition: functions.lib.php:6405
Form\selectUnits
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
Definition: html.form.class.php:4569
getEntity
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Definition: functions.lib.php:148
Form\editInPlace
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
Definition: html.form.class.php:445
code
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...
Definition: sync_members_ldap2dolibarr.php:60
Form\widgetForTranslation
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
Definition: html.form.class.php:371
currency_name
currency_name($code_iso, $withcode='', $outputlangs=null)
Return label of currency or code+label.
Definition: company.lib.php:639
dol_string_unaccent
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
Definition: functions.lib.php:1309
getAdvancedPreviewUrl
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
Definition: functions.lib.php:9646
Form\form_thirdparty
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array())
Output html select to select thirdparty.
Definition: html.form.class.php:5848
Form\textwithtooltip
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.
Definition: html.form.class.php:592
getServerTimeZoneInt
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition: date.lib.php:83
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
Form\constructProductListOption
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
Definition: html.form.class.php:2852
Contact
Class to manage contact/addresses.
Definition: contact.class.php:40
dol_string_neverthesehtmltags
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
Definition: functions.lib.php:6882
Form\select_produits_list
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.
Definition: html.form.class.php:2508
Form\textwithpicto
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.
Definition: html.form.class.php:702
Form\selectTicketsList
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
Definition: html.form.class.php:6991
Form\form_users
form_users($page, $selected='', $htmlname='userid', $exclude='', $include='')
Show a select form to choose a user.
Definition: html.form.class.php:5532
Form\select_users
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0')
Return the HTML select list of users.
Definition: html.form.class.php:1894
Form\selectMassAction
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
Definition: html.form.class.php:770
Form\select_all_categories
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $markafterid=0, $outputmode=0, $include=0, $morecss='')
Return list of categories having choosed type.
Definition: html.form.class.php:4818
getDolGlobalString
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:80
get_default_tva
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...
Definition: functions.lib.php:6304
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3747
info_admin
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
Definition: functions.lib.php:4800
Form\multiselectarray
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.
Definition: html.form.class.php:8256
newToken
newToken()
Return the value of token currently saved into session with name 'newtoken'.
Definition: functions.lib.php:10878
Form\loadCacheInputReason
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
Definition: html.form.class.php:3895
Form\getSelectConditionsPaiements
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
Definition: html.form.class.php:4075
Form\select_product_fourn_price
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier='')
Return list of suppliers prices for a product.
Definition: html.form.class.php:3616
Form\selectTransportMode
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
Definition: html.form.class.php:4354
Form\select_produits
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.
Definition: html.form.class.php:2269
Form\form_availability
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
Definition: html.form.class.php:5415
User
Class to manage Dolibarr users.
Definition: user.class.php:44
GETPOSTISSET
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
Definition: functions.lib.php:386
Form\showFilterAndCheckAddButtons
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear seach button.
Definition: html.form.class.php:9645
Form\select_company
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.
Definition: html.form.class.php:1263
Form\load_cache_types_paiements
load_cache_types_paiements()
Charge dans cache la liste des types de paiements possibles.
Definition: html.form.class.php:3990
Entrepot\STATUS_CLOSED
const STATUS_CLOSED
Warehouse closed, inactive.
Definition: entrepot.class.php:151
Product
Class to manage products or services.
Definition: product.class.php:46
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:52
testSqlAndScriptInject
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:87
Form\select_type_fees
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
Definition: html.form.class.php:1206
Form\selectarray
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='', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
Definition: html.form.class.php:7879
dol_print_email
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
Definition: functions.lib.php:2960
Form\formSelectAccount
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
Definition: html.form.class.php:4770
dol_htmlentitiesbr
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...
Definition: functions.lib.php:6991
Form\selectAvailabilityDelay
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Retourne la liste des types de delais de livraison possibles.
Definition: html.form.class.php:3862
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
Form\load_cache_transport_mode
load_cache_transport_mode()
Load in cache list of transport mode.
Definition: html.form.class.php:4298
Form\form_project
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0)
Show a form to select a project.
Definition: html.form.class.php:5315
getImageFileNameForSize
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
Definition: functions.lib.php:9595
price
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.
Definition: functions.lib.php:5541
dolIsAllowedForPreview
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
Definition: functions.lib.php:9706
Product\TYPE_SERVICE
const TYPE_SERVICE
Service.
Definition: product.class.php:504
Form\load_tva
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.
Definition: html.form.class.php:6105
Form\showphoto
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
Definition: html.form.class.php:9263
Form\selectDate
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...
Definition: html.form.class.php:6355
Product\TYPE_PRODUCT
const TYPE_PRODUCT
Regular product.
Definition: product.class.php:500
Form\editfieldkey
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
Definition: html.form.class.php:107
FormMail
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Definition: html.formmail.class.php:38
Form\selectMembersList
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
Definition: html.form.class.php:7399
Form\selectInputReason
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...
Definition: html.form.class.php:3953
Form\select_address
select_address($selected, $socid, $htmlname='address_id', $showempty=0)
Return list of delivery address.
Definition: html.form.class.php:3719
currentToken
currentToken()
Return the value of token currently saved into session with name 'token'.
Definition: functions.lib.php:10889
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:93
showDimensionInBestUnit
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
Definition: functions.lib.php:5788
Form\form_contacts
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
Definition: html.form.class.php:5800
Form\load_cache_vatrates
load_cache_vatrates($country_code)
Load into the cache vat rates of a country.
Definition: html.form.class.php:6020
type
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
dol_string_onlythesehtmltags
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0)
Clean a string to keep only desirable HTML tags.
Definition: functions.lib.php:6760
Form\showFilterButtons
showFilterButtons($pos='')
Return HTML to show the search and clear seach button.
Definition: html.form.class.php:9579
Form\select_contacts
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)
Definition: html.form.class.php:1649
Form\select_produits_fournisseurs
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...
Definition: html.form.class.php:3182
DolEditor
Class to manage a WYSIWYG editor.
Definition: doleditor.class.php:30
Account
Class to manage bank accounts.
Definition: account.class.php:38
Form\selectProjectsList
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
Definition: html.form.class.php:7189
HookManager
Class to manage hooks.
Definition: hookmanager.class.php:30
dol_htmlentities
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
Definition: functions.lib.php:7075
Form\selectcontacts
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).
Definition: html.form.class.php:1680
vatrate
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.
Definition: functions.lib.php:5492
isInEEC
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
Definition: company.lib.php:753
Form\select_produits_fournisseurs_list
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.
Definition: html.form.class.php:3230
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25