dolibarr  13.0.2
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-2019 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 Alexandre Spangaro <aspangaro@open-dsi.fr>
19  * Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es>
20  * Copyright (C) 2018-2019 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  {
116  if (!empty($perm))
117  {
118  $tmp = explode(':', $typeofdata);
119  $ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
120  if ($fieldrequired) $ret .= '<span class="fieldrequired">';
121  if ($help) {
122  $ret .= $this->textwithpicto($langs->trans($text), $help);
123  } else {
124  $ret .= $langs->trans($text);
125  }
126  if ($fieldrequired) $ret .= '</span>';
127  $ret .= '</div>'."\n";
128  } else {
129  if ($fieldrequired) $ret .= '<span class="fieldrequired">';
130  if ($help) {
131  $ret .= $this->textwithpicto($langs->trans($text), $help);
132  } else {
133  $ret .= $langs->trans($text);
134  }
135  if ($fieldrequired) $ret .= '</span>';
136  }
137  } else {
138  if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
139  if ($fieldrequired) $ret .= '<span class="fieldrequired">';
140  if ($help) {
141  $ret .= $this->textwithpicto($langs->trans($text), $help);
142  } else {
143  $ret .= $langs->trans($text);
144  }
145  if ($fieldrequired) $ret .= '</span>';
146  if (!empty($notabletag)) $ret .= ' ';
147  if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</td>';
148  if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<td class="right">';
149  if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&amp;'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
150  if (!empty($notabletag) && $notabletag == 1) $ret .= ' : ';
151  if (!empty($notabletag) && $notabletag == 3) $ret .= ' ';
152  if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</td>';
153  if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</tr></table>';
154  }
155 
156  return $ret;
157  }
158 
177  public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id')
178  {
179  global $conf, $langs, $db;
180 
181  $ret = '';
182 
183  // Check parameters
184  if (empty($typeofdata)) return 'ErrorBadParameter';
185 
186  // When option to edit inline is activated
187  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|datehourpicker/', $typeofdata)) // TODO add jquery timepicker and support select
188  {
189  $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
190  } else {
191  $editmode = (GETPOST('action', 'aZ09') == 'edit'.$htmlname);
192  if ($editmode)
193  {
194  $ret .= "\n";
195  $ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">';
196  $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
197  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
198  $ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
199  if (empty($notabletag)) $ret .= '<table class="nobordernopadding centpercent" cellpadding="0" cellspacing="0">';
200  if (empty($notabletag)) $ret .= '<tr><td>';
201  if (preg_match('/^(string|safehtmlstring|email)/', $typeofdata))
202  {
203  $tmp = explode(':', $typeofdata);
204  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>';
205  } elseif (preg_match('/^(numeric|amount)/', $typeofdata))
206  {
207  $tmp = explode(':', $typeofdata);
208  $valuetoshow = price2num($editvalue ? $editvalue : $value);
209  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ?price($valuetoshow) : '').'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>';
210  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) // if wysiwyg is enabled $typeofdata = 'ckeditor'
211  {
212  $tmp = explode(':', $typeofdata);
213  $cols = $tmp[2];
214  $morealt = '';
215  if (preg_match('/%/', $cols))
216  {
217  $morealt = ' style="width: '.$cols.'"';
218  $cols = '';
219  }
220 
221  $valuetoshow = ($editvalue ? $editvalue : $value);
222  $ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1] ? $tmp[1] : '20').'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'" autofocus>';
223  // textarea convert automatically entities chars into simple chars.
224  // 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.
225  $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
226  $ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
227  $ret .= '</textarea>';
228  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker')
229  {
230  $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0);
231  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker')
232  {
233  $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0);
234  } elseif (preg_match('/^select;/', $typeofdata))
235  {
236  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
237  $arraylist = array();
238  foreach ($arraydata as $val)
239  {
240  $tmp = explode(':', $val);
241  $tmpkey = str_replace('|', ':', $tmp[0]);
242  $arraylist[$tmpkey] = $tmp[1];
243  }
244  $ret .= $this->selectarray($htmlname, $arraylist, $value);
245  } elseif (preg_match('/^ckeditor/', $typeofdata))
246  {
247  $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
248  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
249  $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), ($tmp[2] ? $tmp[2] : ''), ($tmp[3] ? $tmp[3] : '100'), ($tmp[1] ? $tmp[1] : 'dolibarr_notes'), 'In', ($tmp[5] ? $tmp[5] : 0), (isset($tmp[8]) ? ($tmp[8] ?true:false) : true), true, ($tmp[6] ? $tmp[6] : '20'), ($tmp[7] ? $tmp[7] : '100'));
250  $ret .= $doleditor->Create(1);
251  }
252  if (empty($notabletag)) $ret .= '</td>';
253 
254  if (empty($notabletag)) $ret .= '<td class="left">';
255  //else $ret.='<div class="clearboth"></div>';
256  $ret .= '<input type="submit" class="smallpaddingimp button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
257  if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) $ret .= '<br>'."\n";
258  $ret .= '<input type="submit" class="smallpaddingimp button button-cancel'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
259  if (empty($notabletag)) $ret .= '</td>';
260 
261  if (empty($notabletag)) $ret .= '</tr></table>'."\n";
262  $ret .= '</form>'."\n";
263  } else {
264  if (preg_match('/^(email)/', $typeofdata)) $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
265  elseif (preg_match('/^(amount|numeric)/', $typeofdata)) $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
266  elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) $ret .= dol_htmlentitiesbr($value);
267  elseif (preg_match('/^safehtmlstring/', $typeofdata)) $ret .= dol_string_onlythesehtmltags($value);
268  elseif (preg_match('/^restricthtml/', $typeofdata)) $ret .= dol_string_onlythesehtmltags($value);
269  elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret .= '<span class="valuedate">'.dol_print_date($value, 'day').'</span>';
270  elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret .= '<span class="valuedate">'.dol_print_date($value, 'dayhour').'</span>';
271  elseif (preg_match('/^select;/', $typeofdata))
272  {
273  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
274  $arraylist = array();
275  foreach ($arraydata as $val)
276  {
277  $tmp = explode(':', $val);
278  $arraylist[$tmp[0]] = $tmp[1];
279  }
280  $ret .= $arraylist[$value];
281  } elseif (preg_match('/^ckeditor/', $typeofdata))
282  {
283  $tmpcontent = dol_htmlentitiesbr($value);
284  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB))
285  {
286  $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
287  $firstline = preg_replace('/[\n\r].*/', '', $firstline);
288  $tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
289  }
290  // We dont use dol_escape_htmltag to get the html formating active, but this need we must also
291  // clean data from some dangerous html
292  $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent));
293  } else {
294  $ret .= dol_escape_htmltag($value);
295  }
296 
297  if ($formatfunc && method_exists($object, $formatfunc))
298  {
299  $ret = $object->$formatfunc($ret);
300  }
301  }
302  }
303  return $ret;
304  }
305 
317  public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
318  {
319  global $conf, $langs, $extralanguages;
320 
321  $result = '';
322 
323  // List of extra languages
324  $arrayoflangcode = array();
325  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
326 
327  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
328  if (!is_object($extralanguages)) {
329  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
330  $extralanguages = new ExtraLanguages($this->db);
331  }
332  $extralanguages->fetch_name_extralanguages('societe');
333 
334  if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
335  return ''; // No extralang field to show
336  }
337 
338  $result .= '<!-- Widget for translation -->'."\n";
339  $result .= '<div class="inline-block paddingleft image-'.$object->element.'-'.$fieldname.'">';
340  $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
341  $result .= $s;
342  $result .= '</div>';
343 
344  $result .= '<div class="inline-block hidden field-'.$object->element.'-'.$fieldname.'">';
345 
346  $resultforextrlang = '';
347  foreach ($arrayoflangcode as $langcode)
348  {
349  $valuetoshow = GETPOSTISSET('field-'.$object->element."-".$fieldname."-".$langcode) ? GETPOST('field-'.$object->element.'-'.$fieldname."-".$langcode, $check) : '';
350  if (empty($valuetoshow)) {
351  $object->fetchValuesForExtraLanguages();
352  //var_dump($object->array_languages);
353  $valuetoshow = $object->array_languages[$fieldname][$langcode];
354  }
355 
356  $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
357  $resultforextrlang .= $s;
358 
359  // TODO Use the showInputField() method of ExtraLanguages object
360  if ($typeofdata == 'textarea') {
361  $resultforextrlang .= '<textarea name="field-'.$object->element."-".$fieldname."-".$langcode.'" id="'.$fieldname."-".$langcode.'" class="'.$morecss.'" rows="'.ROWS_2.'" wrap="soft">';
362  $resultforextrlang .= $valuetoshow;
363  $resultforextrlang .= '</textarea>';
364  } else {
365  $resultforextrlang .= '<input type="text" class="inputfieldforlang '.($morecss ? ' '.$morecss : '').'" name="field-'.$object->element.'-'.$fieldname.'-'.$langcode.'" value="'.$valuetoshow.'">';
366  }
367  }
368  $result .= $resultforextrlang;
369 
370  $result .= '</div>';
371  $result .= '<script>$(".image-'.$object->element.'-'.$fieldname.'").click(function() { console.log("Toggle lang widget"); jQuery(".field-'.$object->element.'-'.$fieldname.'").toggle(); });</script>';
372  }
373 
374  return $result;
375  }
376 
390  protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
391  {
392  global $conf;
393 
394  $out = '';
395 
396  // Check parameters
397  if (preg_match('/^text/', $inputType)) $value = dol_nl2br($value);
398  elseif (preg_match('/^numeric/', $inputType)) $value = price($value);
399  elseif ($inputType == 'day' || $inputType == 'datepicker') $value = dol_print_date($value, 'day');
400 
401  if ($condition)
402  {
403  $element = false;
404  $table_element = false;
405  $fk_element = false;
406  $loadmethod = false;
407  $savemethod = false;
408  $ext_element = false;
409  $button_only = false;
410  $inputOption = '';
411 
412  if (is_object($object))
413  {
414  $element = $object->element;
415  $table_element = $object->table_element;
416  $fk_element = $object->id;
417  }
418 
419  if (is_object($extObject))
420  {
421  $ext_element = $extObject->element;
422  }
423 
424  if (preg_match('/^(string|email|numeric)/', $inputType))
425  {
426  $tmp = explode(':', $inputType);
427  $inputType = $tmp[0];
428  if (!empty($tmp[1])) $inputOption = $tmp[1];
429  if (!empty($tmp[2])) $savemethod = $tmp[2];
430  $out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
431  } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType)))
432  {
433  $tmp = explode(':', $inputType);
434  $inputType = $tmp[0];
435  if (!empty($tmp[1])) $inputOption = $tmp[1];
436  if (!empty($tmp[2])) $savemethod = $tmp[2];
437 
438  $out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
439  } elseif (preg_match('/^(select|autocomplete)/', $inputType))
440  {
441  $tmp = explode(':', $inputType);
442  $inputType = $tmp[0]; $loadmethod = $tmp[1];
443  if (!empty($tmp[2])) $savemethod = $tmp[2];
444  if (!empty($tmp[3])) $button_only = true;
445  } elseif (preg_match('/^textarea/', $inputType))
446  {
447  $tmp = explode(':', $inputType);
448  $inputType = $tmp[0];
449  $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
450  $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
451  } elseif (preg_match('/^ckeditor/', $inputType))
452  {
453  $tmp = explode(':', $inputType);
454  $inputType = $tmp[0]; $toolbar = $tmp[1];
455  if (!empty($tmp[2])) $width = $tmp[2];
456  if (!empty($tmp[3])) $heigth = $tmp[3];
457  if (!empty($tmp[4])) $savemethod = $tmp[4];
458 
459  if (!empty($conf->fckeditor->enabled))
460  {
461  $out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
462  } else {
463  $inputType = 'textarea';
464  }
465  }
466 
467  $out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
468  $out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
469  $out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
470  $out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
471  if (!empty($savemethod)) $out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
472  if (!empty($ext_element)) $out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
473  if (!empty($custommsg))
474  {
475  if (is_array($custommsg))
476  {
477  if (!empty($custommsg['success']))
478  $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
479  if (!empty($custommsg['error']))
480  $out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
481  } else $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
482  }
483  if ($inputType == 'textarea') {
484  $out .= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n";
485  $out .= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n";
486  }
487  $out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
488  $out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n";
489  } else {
490  $out = $value;
491  }
492 
493  return $out;
494  }
495 
514  public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
515  {
516  if ($incbefore) $text = $incbefore.$text;
517  if (!$htmltext) return $text;
518 
519  $tag = 'td';
520  if ($notabs == 2) $tag = 'div';
521  if ($notabs == 3) $tag = 'span';
522  // Sanitize tooltip
523  $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
524 
525  $extrastyle = '';
526  if ($direction < 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-left: 3px !important;'; }
527  if ($direction > 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-right: 3px !important;'; }
528 
529  $classfortooltip = 'classfortooltip';
530 
531  $s = ''; $textfordialog = '';
532 
533  if ($tooltiptrigger == '')
534  {
535  $htmltext = str_replace('"', '&quot;', $htmltext);
536  } else {
537  $classfortooltip = 'classfortooltiponclick';
538  $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
539  }
540  if ($tooltipon == 2 || $tooltipon == 3)
541  {
542  $paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
543  if ($tooltiptrigger == '') $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
544  else $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
545  } else $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
546  if ($tooltipon == 1 || $tooltipon == 3)
547  {
548  $paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
549  if ($tooltiptrigger == '') $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
550  else $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
551  } else $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
552  if (empty($notabs)) $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
553  elseif ($notabs == 2) $s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">';
554  // Define value if value is before
555  if ($direction < 0) {
556  $s .= '<'.$tag.$paramfortooltipimg;
557  if ($tag == 'td') {
558  $s .= ' class=valigntop" width="14"';
559  }
560  $s .= '>'.$textfordialog.$img.'</'.$tag.'>';
561  }
562  // Use another method to help avoid having a space in value in order to use this value with jquery
563  // Define label
564  if ((string) $text != '') $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
565  // Define value if value is after
566  if ($direction > 0) {
567  $s .= '<'.$tag.$paramfortooltipimg;
568  if ($tag == 'td') $s .= ' class="valignmiddle" width="14"';
569  $s .= '>'.$textfordialog.$img.'</'.$tag.'>';
570  }
571  if (empty($notabs)) $s .= '</tr></table>';
572  elseif ($notabs == 2) $s .= '</div>';
573 
574  return $s;
575  }
576 
591  public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
592  {
593  global $conf, $langs;
594 
595  $alt = '';
596  if ($tooltiptrigger) $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
597 
598  //For backwards compatibility
599  if ($type == '0') $type = 'info';
600  elseif ($type == '1') $type = 'help';
601 
602  // If info or help with no javascript, show only text
603  if (empty($conf->use_javascript_ajax))
604  {
605  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') return $text;
606  else {
607  $alt = $htmltext;
608  $htmltext = '';
609  }
610  }
611 
612  // If info or help with smartphone, show only text (tooltip hover can't works)
613  if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger))
614  {
615  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') return $text;
616  }
617  // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
618  //if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
619  //{
620  //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>';
621  //}
622 
623  $img = '';
624  if ($type == 'info') $img = img_help(0, $alt);
625  elseif ($type == 'help') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
626  elseif ($type == 'helpclickable') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
627  elseif ($type == 'superadmin') $img = img_picto($alt, 'redstar');
628  elseif ($type == 'admin') $img = img_picto($alt, 'star');
629  elseif ($type == 'warning') $img = img_warning($alt);
630  elseif ($type != 'none') $img = img_picto($alt, $type); // $type can be an image path
631 
632  return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
633  }
634 
645  public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
646  {
647  global $conf, $langs, $hookmanager;
648 
649 
650  $disabled = 0;
651  $ret = '<div class="centpercent center">';
652  $ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>';
653 
654  // 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.
655  $parameters = array();
656  $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
657  // check if there is a mass action
658  if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) return;
659  if (empty($reshook))
660  {
661  $ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
662  foreach ($arrayofaction as $code => $label)
663  {
664  $ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
665  }
666  }
667  $ret .= $hookmanager->resPrint;
668 
669  $ret .= '</select>';
670 
671  if (empty($conf->dol_optimize_smallscreen)) $ret .= ajax_combobox('.'.$name.'select');
672 
673  // 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
674  $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.
675  $ret .= '<input type="submit" disabled name="confirmmassaction" class="button'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
676  $ret .= '</div>';
677 
678  if (!empty($conf->use_javascript_ajax))
679  {
680  $ret .= '<!-- JS CODE TO ENABLE mass action select -->
681  <script>
682  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 */
683  {
684  atleastoneselected=0;
685  jQuery("."+cssclass).each(function( index ) {
686  /* console.log( index + ": " + $( this ).text() ); */
687  if ($(this).is(\':checked\')) atleastoneselected++;
688  });
689 
690  console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
691 
692  if (atleastoneselected || '.$alwaysvisible.')
693  {
694  jQuery("."+name).show();
695  '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').'
696  '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').'
697  }
698  else
699  {
700  jQuery("."+name).hide();
701  jQuery("."+name+"other").hide();
702  }
703  }
704 
705  jQuery(document).ready(function () {
706  initCheckForSelect(0, "' . $name.'", "'.$cssclass.'");
707  jQuery(".' . $cssclass.'").click(function() {
708  initCheckForSelect(1, "'.$name.'", "'.$cssclass.'");
709  });
710  jQuery(".' . $name.'select").change(function() {
711  var massaction = $( this ).val();
712  var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
713  if (massaction == "builddoc")
714  {
715  urlform = urlform + "#show_files";
716  }
717  $( this ).closest("form").attr("action", urlform);
718  console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform);
719  /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
720  if ($(this).val() != \'0\')
721  {
722  jQuery(".' . $name.'confirmed").prop(\'disabled\', false);
723  jQuery(".' . $name.'other").hide(); /* To disable if another div was open */
724  jQuery(".' . $name.'"+massaction).show();
725  }
726  else
727  {
728  jQuery(".' . $name.'confirmed").prop(\'disabled\', true);
729  jQuery(".' . $name.'other").hide(); /* To disable any div open */
730  }
731  });
732  });
733  </script>
734  ';
735  }
736 
737  return $ret;
738  }
739 
740  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
756  public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array())
757  {
758  // phpcs:enable
759  global $conf, $langs, $mysoc;
760 
761  $langs->load("dict");
762 
763  $out = '';
764  $countryArray = array();
765  $favorite = array();
766  $label = array();
767  $atleastonefavorite = 0;
768 
769  $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
770  $sql .= " FROM ".MAIN_DB_PREFIX."c_country";
771  $sql .= " WHERE active > 0";
772  //$sql.= " ORDER BY code ASC";
773 
774  dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
775  $resql = $this->db->query($sql);
776  if ($resql)
777  {
778  $out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
779  $num = $this->db->num_rows($resql);
780  $i = 0;
781  if ($num)
782  {
783  while ($i < $num)
784  {
785  $obj = $this->db->fetch_object($resql);
786 
787  $countryArray[$i]['rowid'] = $obj->rowid;
788  $countryArray[$i]['code_iso'] = $obj->code_iso;
789  $countryArray[$i]['code_iso3'] = $obj->code_iso3;
790  $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 : ''));
791  $countryArray[$i]['favorite'] = $obj->favorite;
792  $favorite[$i] = $obj->favorite;
793  $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
794  $i++;
795  }
796 
797  if (empty($disablefavorites)) array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
798  else $countryArray = dol_sort_array($countryArray, 'label');
799 
800  if ($showempty)
801  {
802  $out .= '<option value="">&nbsp;</option>'."\n";
803  }
804 
805  if ($addspecialentries) // Add dedicated entries for groups of countries
806  {
807  //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
808  $out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
809  $out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
810  if ($mysoc->isInEEC()) $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
811  $out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
812  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
813  }
814 
815  foreach ($countryArray as $row)
816  {
817  //if (empty($showempty) && empty($row['rowid'])) continue;
818  if (empty($row['rowid'])) continue;
819  if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) continue; // exclude some countries
820 
821  if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) $atleastonefavorite++;
822  if (empty($row['favorite']) && $atleastonefavorite)
823  {
824  $atleastonefavorite = 0;
825  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
826  }
827 
828  $labeltoshow = '';
829  if ($row['label']) $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
830  else $labeltoshow .= '&nbsp;';
831  if ($row['code_iso']) {
832  $labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>';
833  $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium marginrightonly"');
834  $labeltoshow = $tmpflag.' '.$labeltoshow;
835  }
836 
837  if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
838  $out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
839  } else {
840  $out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
841  }
842  $out .= $labeltoshow;
843  $out .= '</option>';
844  }
845  }
846  $out .= '</select>';
847  } else {
848  dol_print_error($this->db);
849  }
850 
851  // Make select dynamic
852  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
853  $out .= ajax_combobox('select'.$htmlname);
854 
855  return $out;
856  }
857 
858  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
871  public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array())
872  {
873  // phpcs:enable
874  global $conf, $langs;
875 
876  $langs->load("dict");
877 
878  $out = '';
879  $incotermArray = array();
880 
881  $sql = "SELECT rowid, code";
882  $sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms";
883  $sql .= " WHERE active > 0";
884  $sql .= " ORDER BY code ASC";
885 
886  dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
887  $resql = $this->db->query($sql);
888  if ($resql)
889  {
890  if ($conf->use_javascript_ajax && !$forcecombo)
891  {
892  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
893  $out .= ajax_combobox($htmlname, $events);
894  }
895 
896  if (!empty($page))
897  {
898  $out .= '<form method="post" action="'.$page.'">';
899  $out .= '<input type="hidden" name="action" value="set_incoterms">';
900  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
901  }
902 
903  $out .= '<select id="'.$htmlname.'" class="flat selectincoterm minwidth100imp noenlargeonsmartphone" name="'.$htmlname.'" '.$htmloption.'>';
904  $out .= '<option value="0">&nbsp;</option>';
905  $num = $this->db->num_rows($resql);
906  $i = 0;
907  if ($num)
908  {
909  $foundselected = false;
910 
911  while ($i < $num)
912  {
913  $obj = $this->db->fetch_object($resql);
914  $incotermArray[$i]['rowid'] = $obj->rowid;
915  $incotermArray[$i]['code'] = $obj->code;
916  $i++;
917  }
918 
919  foreach ($incotermArray as $row)
920  {
921  if ($selected && ($selected == $row['rowid'] || $selected == $row['code']))
922  {
923  $out .= '<option value="'.$row['rowid'].'" selected>';
924  } else {
925  $out .= '<option value="'.$row['rowid'].'">';
926  }
927 
928  if ($row['code']) $out .= $row['code'];
929 
930  $out .= '</option>';
931  }
932  }
933  $out .= '</select>';
934 
935  $out .= '<input id="location_incoterms" class="maxwidth100onsmartphone" name="location_incoterms" value="'.$location_incoterms.'">';
936 
937  if (!empty($page))
938  {
939  $out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'"></form>';
940  }
941  } else {
942  dol_print_error($this->db);
943  }
944 
945  return $out;
946  }
947 
948  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
960  public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
961  {
962  // phpcs:enable
963  global $db, $langs, $user, $conf;
964 
965  // If product & services are enabled or both disabled.
966  if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
967  || (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled)))
968  {
969  if (empty($hidetext)) print $langs->trans("Type").': ';
970  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
971  if ($showempty)
972  {
973  print '<option value="-1"';
974  if ($selected == -1) print ' selected';
975  print '>&nbsp;</option>';
976  }
977 
978  print '<option value="0"';
979  if (0 == $selected) print ' selected';
980  print '>'.$langs->trans("Product");
981 
982  print '<option value="1"';
983  if (1 == $selected) print ' selected';
984  print '>'.$langs->trans("Service");
985 
986  print '</select>';
987  //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
988  }
989  if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3)
990  {
991  print $langs->trans("Service");
992  print '<input type="hidden" name="'.$htmlname.'" value="1">';
993  }
994  if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2)
995  {
996  print $langs->trans("Product");
997  print '<input type="hidden" name="'.$htmlname.'" value="0">';
998  }
999  if ($forceall < 0) // This should happened only for contracts when both predefined product and service are disabled.
1000  {
1001  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
1002  }
1003  }
1004 
1005  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1011  public function load_cache_types_fees()
1012  {
1013  // phpcs:enable
1014  global $langs;
1015 
1016  $num = count($this->cache_types_fees);
1017  if ($num > 0) return 0; // Cache already loaded
1018 
1019  dol_syslog(__METHOD__, LOG_DEBUG);
1020 
1021  $langs->load("trips");
1022 
1023  $sql = "SELECT c.code, c.label";
1024  $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
1025  $sql .= " WHERE active > 0";
1026 
1027  $resql = $this->db->query($sql);
1028  if ($resql)
1029  {
1030  $num = $this->db->num_rows($resql);
1031  $i = 0;
1032 
1033  while ($i < $num)
1034  {
1035  $obj = $this->db->fetch_object($resql);
1036 
1037  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1038  $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1039  $this->cache_types_fees[$obj->code] = $label;
1040  $i++;
1041  }
1042 
1043  asort($this->cache_types_fees);
1044 
1045  return $num;
1046  } else {
1047  dol_print_error($this->db);
1048  return -1;
1049  }
1050  }
1051 
1052  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1061  public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1062  {
1063  // phpcs:enable
1064  global $user, $langs;
1065 
1066  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1067 
1068  $this->load_cache_types_fees();
1069 
1070  print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1071  if ($showempty)
1072  {
1073  print '<option value="-1"';
1074  if ($selected == -1) print ' selected';
1075  print '>&nbsp;</option>';
1076  }
1077 
1078  foreach ($this->cache_types_fees as $key => $value)
1079  {
1080  print '<option value="'.$key.'"';
1081  if ($key == $selected) print ' selected';
1082  print '>';
1083  print $value;
1084  print '</option>';
1085  }
1086 
1087  print '</select>';
1088  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1089  }
1090 
1091 
1092  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1112  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)
1113  {
1114  // phpcs:enable
1115  global $conf, $user, $langs;
1116 
1117  $out = '';
1118 
1119  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo)
1120  {
1121  // No immediate load of all database
1122  $placeholder = '';
1123  if ($selected && empty($selected_input_value))
1124  {
1125  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1126  $societetmp = new Societe($this->db);
1127  $societetmp->fetch($selected);
1128  $selected_input_value = $societetmp->name;
1129  unset($societetmp);
1130  }
1131  // mode 1
1132  $urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).($showtype ? '&showtype='.urlencode($showtype) : '');
1133  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1134  $out .= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
1135  if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1136  elseif ($hidelabel > 1) {
1137  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
1138  if ($hidelabel == 2) {
1139  $out .= img_picto($langs->trans("Search"), 'search');
1140  }
1141  }
1142  $out .= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1143  if ($hidelabel == 3) {
1144  $out .= img_picto($langs->trans("Search"), 'search');
1145  }
1146  } else {
1147  // Immediate load of all database
1148  $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple);
1149  }
1150 
1151  return $out;
1152  }
1153 
1154  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1174  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)
1175  {
1176  // phpcs:enable
1177  global $conf, $user, $langs;
1178 
1179  $out = '';
1180  $num = 0;
1181  $outarray = array();
1182 
1183  if ($selected === '') $selected = array();
1184  elseif (!is_array($selected)) $selected = array($selected);
1185 
1186  // Clean $filter that may contains sql conditions so sql code
1187  if (function_exists('testSqlAndScriptInject')) {
1188  if (testSqlAndScriptInject($filter, 3) > 0) {
1189  $filter = '';
1190  }
1191  }
1192 
1193  // We search companies
1194  $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1195  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1196  $sql .= ", s.address, s.zip, s.town";
1197  $sql .= ", dictp.code as country_code";
1198  }
1199  $sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
1200  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1201  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid = s.fk_pays";
1202  }
1203  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1204  $sql .= " WHERE s.entity IN (".getEntity('societe').")";
1205  if (!empty($user->socid)) $sql .= " AND s.rowid = ".$user->socid;
1206  if ($filter) $sql .= " AND (".$filter.")";
1207  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
1208  if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND s.status <> 0";
1209  // Add criteria
1210  if ($filterkey && $filterkey != '')
1211  {
1212  $sql .= " AND (";
1213  $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1214  // For natural search
1215  $scrit = explode(' ', $filterkey);
1216  $i = 0;
1217  if (count($scrit) > 1) $sql .= "(";
1218  foreach ($scrit as $crit) {
1219  if ($i > 0) $sql .= " AND ";
1220  $sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1221  $i++;
1222  }
1223  if (count($scrit) > 1) $sql .= ")";
1224  if (!empty($conf->barcode->enabled))
1225  {
1226  $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1227  }
1228  $sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1229  $sql .= ")";
1230  }
1231  $sql .= $this->db->order("nom", "ASC");
1232  $sql .= $this->db->plimit($limit, 0);
1233 
1234  // Build output string
1235  dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1236  $resql = $this->db->query($sql);
1237  if ($resql)
1238  {
1239  if (!$forcecombo)
1240  {
1241  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1242  $out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
1243  }
1244 
1245  // Construct $out and $outarray
1246  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1247 
1248  $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1249  if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT))
1250  {
1251  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1252  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1253  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
1254  else $textifempty .= $langs->trans("All");
1255  }
1256  if ($showempty) $out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.$textifempty.'</span>').'">'.$textifempty.'</option>'."\n";
1257 
1258  $num = $this->db->num_rows($resql);
1259  $i = 0;
1260  if ($num)
1261  {
1262  while ($i < $num)
1263  {
1264  $obj = $this->db->fetch_object($resql);
1265  $label = '';
1266  if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1267  if (($obj->client) && (!empty($obj->code_client))) {
1268  $label = $obj->code_client.' - ';
1269  }
1270  if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1271  $label .= $obj->code_fournisseur.' - ';
1272  }
1273  $label .= ' '.$obj->name;
1274  } else {
1275  $label = $obj->name;
1276  }
1277 
1278  if (!empty($obj->name_alias)) {
1279  $label .= ' ('.$obj->name_alias.')';
1280  }
1281 
1282  if ($showtype)
1283  {
1284  if ($obj->client || $obj->fournisseur) $label .= ' (';
1285  if ($obj->client == 1 || $obj->client == 3) $label .= $langs->trans("Customer");
1286  if ($obj->client == 2 || $obj->client == 3) $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1287  if ($obj->fournisseur) $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1288  if ($obj->client || $obj->fournisseur) $label .= ')';
1289  }
1290 
1291  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1292  $label .= ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : '');
1293  if (!empty($obj->country_code)) {
1294  $label .= ', '.$langs->trans('Country'.$obj->country_code);
1295  }
1296  }
1297 
1298  if (empty($outputmode))
1299  {
1300  if (in_array($obj->rowid, $selected))
1301  {
1302  $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1303  } else {
1304  $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1305  }
1306  } else {
1307  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1308  }
1309 
1310  $i++;
1311  if (($i % 10) == 0) $out .= "\n";
1312  }
1313  }
1314  $out .= '</select>'."\n";
1315  } else {
1316  dol_print_error($this->db);
1317  }
1318 
1319  $this->result = array('nbofthirdparties'=>$num);
1320 
1321  if ($outputmode) return $outarray;
1322  return $out;
1323  }
1324 
1325 
1326  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1337  public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1338  {
1339  // phpcs:enable
1340  global $langs, $conf;
1341 
1342  // On recherche les remises
1343  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1344  $sql .= " re.description, re.fk_facture_source";
1345  $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
1346  $sql .= " WHERE re.fk_soc = ".(int) $socid;
1347  $sql .= " AND re.entity = ".$conf->entity;
1348  if ($filter) $sql .= " AND ".$filter;
1349  $sql .= " ORDER BY re.description ASC";
1350 
1351  dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1352  $resql = $this->db->query($sql);
1353  if ($resql)
1354  {
1355  print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1356  $num = $this->db->num_rows($resql);
1357 
1358  $qualifiedlines = $num;
1359 
1360  $i = 0;
1361  if ($num)
1362  {
1363  print '<option value="0">&nbsp;</option>';
1364  while ($i < $num)
1365  {
1366  $obj = $this->db->fetch_object($resql);
1367  $desc = dol_trunc($obj->description, 40);
1368  if (preg_match('/\(CREDIT_NOTE\)/', $desc)) $desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1369  if (preg_match('/\(DEPOSIT\)/', $desc)) $desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1370  if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) $desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1371  if (preg_match('/\(EXCESS PAID\)/', $desc)) $desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1372 
1373  $selectstring = '';
1374  if ($selected > 0 && $selected == $obj->rowid) $selectstring = ' selected';
1375 
1376  $disabled = '';
1377  if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue)
1378  {
1379  $qualifiedlines--;
1380  $disabled = ' disabled';
1381  }
1382 
1383  if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source))
1384  {
1385  $tmpfac = new Facture($this->db);
1386  if ($tmpfac->fetch($obj->fk_facture_source) > 0) $desc = $desc.' - '.$tmpfac->ref;
1387  }
1388 
1389  print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1390  $i++;
1391  }
1392  }
1393  print '</select>';
1394  return $qualifiedlines;
1395  } else {
1396  dol_print_error($this->db);
1397  return -1;
1398  }
1399  }
1400 
1401  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1422  public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1423  {
1424  // phpcs:enable
1425  print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1426  return $this->num;
1427  }
1428 
1453  public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1454  {
1455  global $conf, $langs, $hookmanager, $action;
1456 
1457  $langs->load('companies');
1458 
1459  if (empty($htmlid)) $htmlid = $htmlname;
1460  $num = 0;
1461 
1462  if ($selected === '') $selected = array();
1463  elseif (!is_array($selected)) $selected = array($selected);
1464  $out = '';
1465 
1466  if (!is_object($hookmanager))
1467  {
1468  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1469  $hookmanager = new HookManager($this->db);
1470  }
1471 
1472  // We search third parties
1473  $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";
1474  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) $sql .= ", s.nom as company, s.town AS company_town";
1475  $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as sp";
1476  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=sp.fk_soc";
1477  $sql .= " WHERE sp.entity IN (".getEntity('socpeople').")";
1478  if ($socid > 0 || $socid == -1) $sql .= " AND sp.fk_soc=".$socid;
1479  if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND sp.statut <> 0";
1480  $sql .= " ORDER BY sp.lastname ASC";
1481 
1482  dol_syslog(get_class($this)."::select_contacts", LOG_DEBUG);
1483  $resql = $this->db->query($sql);
1484  if ($resql)
1485  {
1486  $num = $this->db->num_rows($resql);
1487 
1488  if ($conf->use_javascript_ajax && !$forcecombo && !$options_only)
1489  {
1490  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1491  $out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
1492  }
1493 
1494  if ($htmlname != 'none' && !$options_only) {
1495  $out .= '<select class="flat'.($moreclass ? ' '.$moreclass : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1496  }
1497 
1498  if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1499  if ($showempty == 2) $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1500 
1501  $i = 0;
1502  if ($num)
1503  {
1504  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1505  $contactstatic = new Contact($this->db);
1506 
1507  while ($i < $num)
1508  {
1509  $obj = $this->db->fetch_object($resql);
1510 
1511  // Set email (or phones) and town extended infos
1512  $extendedInfos = '';
1513  if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1514  $extendedInfos = array();
1515  $email = trim($obj->email);
1516  if (!empty($email)) $extendedInfos[] = $email;
1517  else {
1518  $phone = trim($obj->phone);
1519  $phone_perso = trim($obj->phone_perso);
1520  $phone_mobile = trim($obj->phone_mobile);
1521  if (!empty($phone)) $extendedInfos[] = $phone;
1522  if (!empty($phone_perso)) $extendedInfos[] = $phone_perso;
1523  if (!empty($phone_mobile)) $extendedInfos[] = $phone_mobile;
1524  }
1525  $contact_town = trim($obj->contact_town);
1526  $company_town = trim($obj->company_town);
1527  if (!empty($contact_town)) $extendedInfos[] = $contact_town;
1528  elseif (!empty($company_town)) $extendedInfos[] = $company_town;
1529  $extendedInfos = implode(' - ', $extendedInfos);
1530  if (!empty($extendedInfos)) $extendedInfos = ' - '.$extendedInfos;
1531  }
1532 
1533  $contactstatic->id = $obj->rowid;
1534  $contactstatic->lastname = $obj->lastname;
1535  $contactstatic->firstname = $obj->firstname;
1536  if ($obj->statut == 1) {
1537  if ($htmlname != 'none')
1538  {
1539  $disabled = 0;
1540  if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) $disabled = 1;
1541  if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) $disabled = 1;
1542  if (!empty($selected) && in_array($obj->rowid, $selected))
1543  {
1544  $out .= '<option value="'.$obj->rowid.'"';
1545  if ($disabled) $out .= ' disabled';
1546  $out .= ' selected>';
1547  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1548  if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1549  if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1550  $out .= '</option>';
1551  } else {
1552  $out .= '<option value="'.$obj->rowid.'"';
1553  if ($disabled) $out .= ' disabled';
1554  $out .= '>';
1555  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1556  if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1557  if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1558  $out .= '</option>';
1559  }
1560  } else {
1561  if (in_array($obj->rowid, $selected))
1562  {
1563  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1564  if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1565  if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1566  }
1567  }
1568  }
1569  $i++;
1570  }
1571  } else {
1572  $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1573  $out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">';
1574  $out .= $labeltoshow;
1575  $out .= '</option>';
1576  }
1577 
1578  $parameters = array(
1579  'socid'=>$socid,
1580  'htmlname'=>$htmlname,
1581  'resql'=>$resql,
1582  'out'=>&$out,
1583  'showfunction'=>$showfunction,
1584  'showsoc'=>$showsoc,
1585  );
1586 
1587  $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1588 
1589  if ($htmlname != 'none' && !$options_only)
1590  {
1591  $out .= '</select>';
1592  }
1593 
1594  $this->num = $num;
1595  return $out;
1596  } else {
1597  dol_print_error($this->db);
1598  return -1;
1599  }
1600  }
1601 
1602  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1618  public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1619  {
1620  // phpcs:enable
1621  print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1622  }
1623 
1624  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1648  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)
1649  {
1650  // phpcs:enable
1651  global $conf, $user, $langs, $hookmanager;
1652 
1653  // If no preselected user defined, we take current user
1654  if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) $selected = $user->id;
1655 
1656  if ($selected === '') $selected = array();
1657  elseif (!is_array($selected)) $selected = array($selected);
1658 
1659  $excludeUsers = null;
1660  $includeUsers = null;
1661 
1662  // Permettre l'exclusion d'utilisateurs
1663  if (is_array($exclude)) $excludeUsers = implode(",", $exclude);
1664  // Permettre l'inclusion d'utilisateurs
1665  if (is_array($include)) $includeUsers = implode(",", $include);
1666  elseif ($include == 'hierarchy')
1667  {
1668  // Build list includeUsers to have only hierarchy
1669  $includeUsers = implode(",", $user->getAllChildIds(0));
1670  } elseif ($include == 'hierarchyme')
1671  {
1672  // Build list includeUsers to have only hierarchy and current user
1673  $includeUsers = implode(",", $user->getAllChildIds(1));
1674  }
1675 
1676  $out = '';
1677  $outarray = array();
1678 
1679  // Forge request to select users
1680  $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
1681  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
1682  {
1683  $sql .= ", e.label";
1684  }
1685  $sql .= " FROM ".MAIN_DB_PREFIX."user as u";
1686  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
1687  {
1688  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=u.entity";
1689  if ($force_entity) $sql .= " WHERE u.entity IN (0,".$force_entity.")";
1690  else $sql .= " WHERE u.entity IS NOT NULL";
1691  } else {
1692  if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
1693  {
1694  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
1695  $sql .= " ON ug.fk_user = u.rowid";
1696  $sql .= " WHERE ug.entity = ".$conf->entity;
1697  } else {
1698  $sql .= " WHERE u.entity IN (0,".$conf->entity.")";
1699  }
1700  }
1701  if (!empty($user->socid)) $sql .= " AND u.fk_soc = ".$user->socid;
1702  if (is_array($exclude) && $excludeUsers) $sql .= " AND u.rowid NOT IN (".$excludeUsers.")";
1703  if ($includeUsers) $sql .= " AND u.rowid IN (".$includeUsers.")";
1704  if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) $sql .= " AND u.statut <> 0";
1705  if (!empty($morefilter)) $sql .= " ".$morefilter;
1706 
1707  //Add hook to filter on user (for exemple on usergroup define in custom modules)
1708  $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
1709  if (!empty($reshook)) $sql .= $hookmanager->resPrint;
1710 
1711  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1712  {
1713  $sql .= " ORDER BY u.firstname ASC";
1714  } else {
1715  $sql .= " ORDER BY u.lastname ASC";
1716  }
1717 
1718  dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1719  $resql = $this->db->query($sql);
1720  if ($resql)
1721  {
1722  $num = $this->db->num_rows($resql);
1723  $i = 0;
1724  if ($num)
1725  {
1726  // Enhance with select2
1727  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1728  $out .= ajax_combobox($htmlname);
1729 
1730  // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1731  $out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
1732  if ($show_empty && !$multiple) $out .= '<option value="-1"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>&nbsp;</option>'."\n";
1733  if ($show_every) $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
1734 
1735  $userstatic = new User($this->db);
1736 
1737  while ($i < $num)
1738  {
1739  $obj = $this->db->fetch_object($resql);
1740 
1741  $userstatic->id = $obj->rowid;
1742  $userstatic->lastname = $obj->lastname;
1743  $userstatic->firstname = $obj->firstname;
1744  $userstatic->photo = $obj->photo;
1745  $userstatic->statut = $obj->status;
1746  $userstatic->entity = $obj->entity;
1747  $userstatic->admin = $obj->admin;
1748 
1749  $disableline = '';
1750  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) $disableline = ($enableonlytext ? $enableonlytext : '1');
1751 
1752  $labeltoshow = '';
1753 
1754  // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
1755  $fullNameMode = 0;
1756  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))
1757  {
1758  $fullNameMode = 1; //Firstname+lastname
1759  }
1760  $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1761  if (empty($obj->firstname) && empty($obj->lastname)) $labeltoshow .= $obj->login;
1762 
1763  // Complete name with more info
1764  $moreinfo = '';
1765  if (!empty($conf->global->MAIN_SHOW_LOGIN))
1766  {
1767  $moreinfo .= ($moreinfo ? ' - ' : ' (').$obj->login;
1768  }
1769  if ($showstatus >= 0)
1770  {
1771  if ($obj->status == 1 && $showstatus == 1)
1772  {
1773  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
1774  }
1775  if ($obj->status == 0 && $showstatus == 1)
1776  {
1777  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
1778  }
1779  }
1780  if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity)
1781  {
1782  if (!$obj->entity)
1783  {
1784  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
1785  } else {
1786  $moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
1787  }
1788  }
1789  $moreinfo .= ($moreinfo ? ')' : '');
1790  if ($disableline && $disableline != '1')
1791  {
1792  $moreinfo .= ' - '.$disableline; // This is text from $enableonlytext parameter
1793  }
1794  $labeltoshow .= $moreinfo;
1795 
1796  $out .= '<option value="'.$obj->rowid.'"';
1797  if ($disableline) $out .= ' disabled';
1798  if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
1799  $out .= ' selected';
1800  }
1801  $out .= ' data-html="';
1802  $outhtml = '';
1803  if (!empty($obj->photo))
1804  {
1805  $outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
1806  }
1807  if ($showstatus >= 0 && $obj->status == 0) $outhtml .= '<strike class="opacitymediumxxx">';
1808  $outhtml .= $labeltoshow;
1809  if ($showstatus >= 0 && $obj->status == 0) $outhtml .= '</strike>';
1810  $out .= dol_escape_htmltag($outhtml);
1811  $out .= '">';
1812  $out .= $labeltoshow;
1813  $out .= '</option>';
1814 
1815  $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
1816 
1817  $i++;
1818  }
1819  } else {
1820  $out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
1821  $out .= '<option value="">'.$langs->trans("None").'</option>';
1822  }
1823  $out .= '</select>';
1824  } else {
1825  dol_print_error($this->db);
1826  }
1827 
1828  if ($outputmode) return $outarray;
1829  return $out;
1830  }
1831 
1832 
1833  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1856  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())
1857  {
1858  // phpcs:enable
1859  global $conf, $user, $langs;
1860 
1861  $userstatic = new User($this->db);
1862  $out = '';
1863 
1864 
1865  $assignedtouser = array();
1866  if (!empty($_SESSION['assignedtouser']))
1867  {
1868  $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
1869  }
1870  $nbassignetouser = count($assignedtouser);
1871 
1872  //if ($nbassignetouser && $action != 'view') $out .= '<br>';
1873  if ($nbassignetouser) $out .= '<ul class="attendees">';
1874  $i = 0; $ownerid = 0;
1875  foreach ($assignedtouser as $key => $value)
1876  {
1877  if ($value['id'] == $ownerid) continue;
1878 
1879  $out .= '<li>';
1880  $userstatic->fetch($value['id']);
1881  $out .= $userstatic->getNomUrl(-1);
1882  if ($i == 0) { $ownerid = $value['id']; $out .= ' ('.$langs->trans("Owner").')'; }
1883  if ($nbassignetouser > 1 && $action != 'view')
1884  {
1885  $out .= ' <input type="image" style="border: 0px;" src="'.img_picto($langs->trans("Remove"), 'delete', '', 0, 1).'" value="'.$userstatic->id.'" class="removedassigned" id="removedassigned_'.$userstatic->id.'" name="removedassigned_'.$userstatic->id.'">';
1886  }
1887  // Show my availability
1888  if ($showproperties)
1889  {
1890  if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid)))
1891  {
1892  $out .= '<div class="myavailability inline-block">';
1893  $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>';
1894  $out .= '</div>';
1895  }
1896  }
1897  //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
1898  //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
1899 
1900  $out .= '</li>';
1901  $i++;
1902  }
1903  if ($nbassignetouser) $out .= '</ul>';
1904 
1905  // Method with no ajax
1906  if ($action != 'view')
1907  {
1908  $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
1909  $out .= '<script type="text/javascript" language="javascript">jQuery(document).ready(function () {';
1910  $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
1911  $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
1912  $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }';
1913  $out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }';
1914  $out .= '});';
1915  $out .= '})</script>';
1916  $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
1917  $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
1918  $out .= '<br>';
1919  }
1920 
1921  return $out;
1922  }
1923 
1924 
1925  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1952  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)
1953  {
1954  // phpcs:enable
1955  global $langs, $conf;
1956 
1957  $out = '';
1958 
1959  // check parameters
1960  $price_level = (!empty($price_level) ? $price_level : 0);
1961  if (is_null($ajaxoptions)) $ajaxoptions = array();
1962 
1963  if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
1964  if (!empty($conf->product->enabled) && empty($conf->service->enabled)) {
1965  $filtertype = '0';
1966  } elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) {
1967  $filtertype = '1';
1968  }
1969  }
1970 
1971  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
1972  {
1973  $placeholder = '';
1974 
1975  if ($selected && empty($selected_input_value))
1976  {
1977  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1978  $producttmpselect = new Product($this->db);
1979  $producttmpselect->fetch($selected);
1980  $selected_input_value = $producttmpselect->ref;
1981  unset($producttmpselect);
1982  }
1983  // handle case where product or service module is disabled + no filter specified
1984  if ($filtertype == '')
1985  {
1986  if (empty($conf->product->enabled)) { // when product module is disabled, show services only
1987  $filtertype = 1;
1988  } elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
1989  $filtertype = 0;
1990  }
1991  }
1992  // mode=1 means customers products
1993  $urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
1994  //Price by customer
1995  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
1996  $urloption .= '&socid='.$socid;
1997  }
1998  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
1999 
2000  if (!empty($conf->variants->enabled) && is_array($selected_combinations)) {
2001  // Code to automatically insert with javascript the select of attributes under the select of product
2002  // when a parent of variant has been selected.
2003  $out .= '
2004  <!-- script to auto show attributes select tags if a variant was selected -->
2005  <script>
2006  // auto show attributes fields
2007  selected = '.json_encode($selected_combinations).';
2008  combvalues = {};
2009 
2010  jQuery(document).ready(function () {
2011 
2012  jQuery("input[name=\'prod_entry_mode\']").change(function () {
2013  if (jQuery(this).val() == \'free\') {
2014  jQuery(\'div#attributes_box\').empty();
2015  }
2016  });
2017 
2018  jQuery("input#'.$htmlname.'").change(function () {
2019 
2020  if (!jQuery(this).val()) {
2021  jQuery(\'div#attributes_box\').empty();
2022  return;
2023  }
2024 
2025  console.log("A change has started. We get variants fields to inject html select");
2026 
2027  jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
2028  id: jQuery(this).val()
2029  }, function (data) {
2030  jQuery(\'div#attributes_box\').empty();
2031 
2032  jQuery.each(data, function (key, val) {
2033 
2034  combvalues[val.id] = val.values;
2035 
2036  var span = jQuery(document.createElement(\'div\')).css({
2037  \'display\': \'table-row\'
2038  });
2039 
2040  span.append(
2041  jQuery(document.createElement(\'div\')).text(val.label).css({
2042  \'font-weight\': \'bold\',
2043  \'display\': \'table-cell\'
2044  })
2045  );
2046 
2047  var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2048  \'margin-left\': \'15px\',
2049  \'white-space\': \'pre\'
2050  }).append(
2051  jQuery(document.createElement(\'option\')).val(\'\')
2052  );
2053 
2054  jQuery.each(combvalues[val.id], function (key, val) {
2055  var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2056 
2057  if (selected[val.fk_product_attribute] == val.id) {
2058  tag.attr(\'selected\', \'selected\');
2059  }
2060 
2061  html.append(tag);
2062  });
2063 
2064  span.append(html);
2065  jQuery(\'div#attributes_box\').append(span);
2066  });
2067  })
2068  });
2069 
2070  '.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2071  });
2072  </script>
2073  ';
2074  }
2075 
2076  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
2077  elseif ($hidelabel > 1) {
2078  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2079  if ($hidelabel == 2) {
2080  $out .= img_picto($langs->trans("Search"), 'search');
2081  }
2082  }
2083  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
2084  if ($hidelabel == 3) {
2085  $out .= img_picto($langs->trans("Search"), 'search');
2086  }
2087  } else {
2088  $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
2089  }
2090 
2091  if (empty($nooutput)) print $out;
2092  else return $out;
2093  }
2094 
2095  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2120  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 = '')
2121  {
2122  // phpcs:enable
2123  global $langs, $conf, $user, $db;
2124 
2125  $out = '';
2126  $outarray = array();
2127 
2128  // Units
2129  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2130  $langs->load('other');
2131  }
2132 
2133  $warehouseStatusArray = array();
2134  if (!empty($warehouseStatus))
2135  {
2136  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2137  if (preg_match('/warehouseclosed/', $warehouseStatus))
2138  {
2139  $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2140  }
2141  if (preg_match('/warehouseopen/', $warehouseStatus))
2142  {
2143  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2144  }
2145  if (preg_match('/warehouseinternal/', $warehouseStatus))
2146  {
2147  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2148  }
2149  }
2150 
2151  $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.duration, p.fk_price_expression";
2152  if (count($warehouseStatusArray))
2153  {
2154  $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
2155  } else {
2156  $selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2157  }
2158 
2159  $sql = "SELECT ";
2160  $sql .= $selectFields.$selectFieldsGrouped;
2161 
2162  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2163  {
2164  //Product category
2165  $sql .= ", (SELECT ".MAIN_DB_PREFIX."categorie_product.fk_categorie
2166  FROM ".MAIN_DB_PREFIX."categorie_product
2167  WHERE ".MAIN_DB_PREFIX."categorie_product.fk_product=p.rowid
2168  LIMIT 1
2169  ) AS categorie_product_id ";
2170  }
2171 
2172  //Price by customer
2173  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid))
2174  {
2175  $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2176  $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx';
2177  $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx";
2178  }
2179  // Units
2180  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2181  $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";
2182  $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';
2183  }
2184 
2185  // Multilang : we add translation
2186  if (!empty($conf->global->MAIN_MULTILANGS))
2187  {
2188  $sql .= ", pl.label as label_translated";
2189  $selectFields .= ", label_translated";
2190  }
2191  // Price by quantity
2192  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
2193  {
2194  $sql .= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
2195  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql .= " AND price_level=".$price_level;
2196  $sql .= " ORDER BY date_price";
2197  $sql .= " DESC LIMIT 1) as price_rowid";
2198  $sql .= ", (SELECT pp.price_by_qty FROM ".MAIN_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
2199  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql .= " AND price_level=".$price_level;
2200  $sql .= " ORDER BY date_price";
2201  $sql .= " DESC LIMIT 1) as price_by_qty";
2202  $selectFields .= ", price_rowid, price_by_qty";
2203  }
2204  $sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2205  if (count($warehouseStatusArray))
2206  {
2207  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
2208  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2209  $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.
2210  }
2211 
2212  // include search in supplier ref
2213  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
2214  {
2215  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2216  }
2217 
2218  //Price by customer
2219  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2220  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".$socid." AND pcp.fk_product=p.rowid";
2221  }
2222  // Units
2223  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2224  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2225  }
2226  // Multilang : we add translation
2227  if (!empty($conf->global->MAIN_MULTILANGS))
2228  {
2229  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='".$this->db->escape($langs->getDefaultLang())."'";
2230  }
2231 
2232  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2233  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2234  }
2235 
2236  $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2237 
2238  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2239  $sql .= " AND pac.rowid IS NULL";
2240  }
2241 
2242  if ($finished == 0)
2243  {
2244  $sql .= " AND p.finished = ".$finished;
2245  } elseif ($finished == 1)
2246  {
2247  $sql .= " AND p.finished = ".$finished;
2248  if ($status >= 0) $sql .= " AND p.tosell = ".$status;
2249  } elseif ($status >= 0)
2250  {
2251  $sql .= " AND p.tosell = ".$status;
2252  }
2253  // Filter by product type
2254  if (strval($filtertype) != '') $sql .= " AND p.fk_product_type = ".$filtertype;
2255  elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only
2256  $sql .= " AND p.fk_product_type = 1";
2257  } elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2258  $sql .= " AND p.fk_product_type = 0";
2259  }
2260  // Add criteria on ref/label
2261  if ($filterkey != '')
2262  {
2263  $sql .= ' AND (';
2264  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2265  // For natural search
2266  $scrit = explode(' ', $filterkey);
2267  $i = 0;
2268  if (count($scrit) > 1) $sql .= "(";
2269  foreach ($scrit as $crit)
2270  {
2271  if ($i > 0) $sql .= " AND ";
2272  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2273  if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2274  if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION))
2275  {
2276  $sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2277  if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2278  }
2279  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2280  $sql .= ")";
2281  $i++;
2282  }
2283  if (count($scrit) > 1) $sql .= ")";
2284  if (!empty($conf->barcode->enabled)) $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2285  $sql .= ')';
2286  }
2287  if (count($warehouseStatusArray))
2288  {
2289  $sql .= ' GROUP BY'.$selectFields;
2290  }
2291 
2292  //Sort by category
2293  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2294  {
2295  $sql .= " ORDER BY categorie_product_id ";
2296  //ASC OR DESC order
2297  ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2298  } else {
2299  $sql .= $this->db->order("p.ref");
2300  }
2301 
2302  $sql .= $this->db->plimit($limit, 0);
2303 
2304  // Build output string
2305  dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2306  $result = $this->db->query($sql);
2307  if ($result)
2308  {
2309  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2310  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2311  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2312 
2313  $num = $this->db->num_rows($result);
2314 
2315  $events = null;
2316 
2317  if (!$forcecombo)
2318  {
2319  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2320  $out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT);
2321  }
2322 
2323  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2324 
2325  $textifempty = '';
2326  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2327  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2328  if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2329  {
2330  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
2331  else $textifempty .= $langs->trans("All");
2332  } else {
2333  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
2334  }
2335  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
2336 
2337  $i = 0;
2338  while ($num && $i < $num)
2339  {
2340  $opt = '';
2341  $optJson = array();
2342  $objp = $this->db->fetch_object($result);
2343 
2344  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)
2345  { // Price by quantity will return many prices for the same product
2346  $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2347  $sql .= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
2348  $sql .= " WHERE fk_product_price=".$objp->price_rowid;
2349  $sql .= " ORDER BY quantity ASC";
2350 
2351  dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2352  $result2 = $this->db->query($sql);
2353  if ($result2)
2354  {
2355  $nb_prices = $this->db->num_rows($result2);
2356  $j = 0;
2357  while ($nb_prices && $j < $nb_prices) {
2358  $objp2 = $this->db->fetch_object($result2);
2359 
2360  $objp->price_by_qty_rowid = $objp2->rowid;
2361  $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2362  $objp->price_by_qty_quantity = $objp2->quantity;
2363  $objp->price_by_qty_unitprice = $objp2->unitprice;
2364  $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2365  // For backward compatibility
2366  $objp->quantity = $objp2->quantity;
2367  $objp->price = $objp2->price;
2368  $objp->unitprice = $objp2->unitprice;
2369  $objp->remise_percent = $objp2->remise_percent;
2370  $objp->remise = $objp2->remise;
2371 
2372  $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2373 
2374  $j++;
2375 
2376  // Add new entry
2377  // "key" value of json key array is used by jQuery automatically as selected value
2378  // "label" value of json key array is used by jQuery automatically as text for combo box
2379  $out .= $opt;
2380  array_push($outarray, $optJson);
2381  }
2382  }
2383  } else {
2384  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2385  $price_product = new Product($this->db);
2386  $price_product->fetch($objp->rowid, '', '', 1);
2387  $priceparser = new PriceParser($this->db);
2388  $price_result = $priceparser->parseProduct($price_product);
2389  if ($price_result >= 0) {
2390  $objp->price = $price_result;
2391  $objp->unitprice = $price_result;
2392  //Calculate the VAT
2393  $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2394  $objp->price_ttc = price2num($objp->price_ttc, 'MU');
2395  }
2396  }
2397 
2398  $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2399  // Add new entry
2400  // "key" value of json key array is used by jQuery automatically as selected value
2401  // "label" value of json key array is used by jQuery automatically as text for combo box
2402  $out .= $opt;
2403  array_push($outarray, $optJson);
2404  }
2405 
2406  $i++;
2407  }
2408 
2409  $out .= '</select>';
2410 
2411  $this->db->free($result);
2412 
2413  if (empty($outputmode)) return $out;
2414  return $outarray;
2415  } else {
2416  dol_print_error($db);
2417  }
2418  }
2419 
2434  protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2435  {
2436  global $langs, $conf, $user, $db;
2437 
2438  $outkey = '';
2439  $outval = '';
2440  $outref = '';
2441  $outlabel = '';
2442  $outdesc = '';
2443  $outbarcode = '';
2444  $outorigin = '';
2445  $outtype = '';
2446  $outprice_ht = '';
2447  $outprice_ttc = '';
2448  $outpricebasetype = '';
2449  $outtva_tx = '';
2450  $outqty = 1;
2451  $outdiscount = 0;
2452 
2453  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2454 
2455  $label = $objp->label;
2456  if (!empty($objp->label_translated)) $label = $objp->label_translated;
2457  if (!empty($filterkey) && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2458 
2459  $outkey = $objp->rowid;
2460  $outref = $objp->ref;
2461  $outlabel = $objp->label;
2462  $outdesc = $objp->description;
2463  $outbarcode = $objp->barcode;
2464  $outorigin = $objp->fk_country;
2465  $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
2466 
2467  $outtype = $objp->fk_product_type;
2468  $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2469  $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2470 
2471  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
2472 
2473  // Units
2474  $outvalUnits = '';
2475  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2476  if (!empty($objp->unit_short)) {
2477  $outvalUnits .= ' - '.$objp->unit_short;
2478  }
2479  }
2480  if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2481  if (!empty($objp->weight) && $objp->weight_units !== null) {
2482  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2483  $outvalUnits .= ' - '.$unitToShow;
2484  }
2485  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2486  $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2487  $outvalUnits .= ' - '.$unitToShow;
2488  }
2489  if (!empty($objp->surface) && $objp->surface_units !== null) {
2490  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2491  $outvalUnits .= ' - '.$unitToShow;
2492  }
2493  if (!empty($objp->volume) && $objp->volume_units !== null) {
2494  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2495  $outvalUnits .= ' - '.$unitToShow;
2496  }
2497  }
2498  if ($outdurationvalue && $outdurationunit) {
2499  $da = array(
2500  'h' => $langs->trans('Hour'),
2501  'd' => $langs->trans('Day'),
2502  'w' => $langs->trans('Week'),
2503  'm' => $langs->trans('Month'),
2504  'y' => $langs->trans('Year')
2505  );
2506  if (isset($da[$outdurationunit])) {
2507  $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2508  }
2509  }
2510 
2511  $opt = '<option value="'.$objp->rowid.'"';
2512  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
2513  if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)
2514  {
2515  $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.'"';
2516  }
2517  if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2518  {
2519  if (!empty($user->rights->stock->lire)) {
2520  if ($objp->stock > 0) $opt .= ' class="product_line_stock_ok"';
2521  elseif ($objp->stock <= 0) $opt .= ' class="product_line_stock_too_low"';
2522  }
2523  }
2524  $opt .= '>';
2525  $opt .= $objp->ref;
2526  if ($outbarcode) $opt .= ' ('.$outbarcode.')';
2527  $opt .= ' - '.dol_trunc($label, $maxlengtharticle);
2528  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) $opt .= ' ('.getCountry($outorigin, 1).')';
2529 
2530  $objRef = $objp->ref;
2531  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2532  $outval .= $objRef;
2533  if ($outbarcode) $outval .= ' ('.$outbarcode.')';
2534  $outval .= ' - '.dol_trunc($label, $maxlengtharticle);
2535  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) $outval .= ' ('.getCountry($outorigin, 1).')';
2536 
2537  // Units
2538  $opt .= $outvalUnits;
2539  $outval .= $outvalUnits;
2540 
2541  $found = 0;
2542 
2543  // Multiprice
2544  // If we need a particular price level (from 1 to 6)
2545  if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)))
2546  {
2547  $sql = "SELECT price, price_ttc, price_base_type, tva_tx";
2548  $sql .= " FROM ".MAIN_DB_PREFIX."product_price";
2549  $sql .= " WHERE fk_product = ".((int) $objp->rowid);
2550  $sql .= " AND entity IN (".getEntity('productprice').")";
2551  $sql .= " AND price_level = ".((int) $price_level);
2552  $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2553  $sql .= " LIMIT 1";
2554 
2555  dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
2556  $result2 = $this->db->query($sql);
2557  if ($result2)
2558  {
2559  $objp2 = $this->db->fetch_object($result2);
2560  if ($objp2)
2561  {
2562  $found = 1;
2563  if ($objp2->price_base_type == 'HT')
2564  {
2565  $opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2566  $outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2567  } else {
2568  $opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2569  $outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2570  }
2571  $outprice_ht = price($objp2->price);
2572  $outprice_ttc = price($objp2->price_ttc);
2573  $outpricebasetype = $objp2->price_base_type;
2574  $outtva_tx = $objp2->tva_tx;
2575  }
2576  } else {
2577  dol_print_error($this->db);
2578  }
2579  }
2580 
2581  // Price by quantity
2582  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)))
2583  {
2584  $found = 1;
2585  $outqty = $objp->quantity;
2586  $outdiscount = $objp->remise_percent;
2587  if ($objp->quantity == 1)
2588  {
2589  $opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
2590  $outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
2591  $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2592  $outval .= $langs->transnoentities("Unit");
2593  } else {
2594  $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2595  $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2596  $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2597  $outval .= $langs->transnoentities("Units");
2598  }
2599 
2600  $outprice_ht = price($objp->unitprice);
2601  $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
2602  $outpricebasetype = $objp->price_base_type;
2603  $outtva_tx = $objp->tva_tx;
2604  }
2605  if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1)
2606  {
2607  $opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2608  $outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2609  }
2610  if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1)
2611  {
2612  $opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2613  $outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2614  }
2615 
2616  // Price by customer
2617  if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES))
2618  {
2619  if (!empty($objp->idprodcustprice))
2620  {
2621  $found = 1;
2622 
2623  if ($objp->custprice_base_type == 'HT')
2624  {
2625  $opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2626  $outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2627  } else {
2628  $opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2629  $outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2630  }
2631 
2632  $outprice_ht = price($objp->custprice);
2633  $outprice_ttc = price($objp->custprice_ttc);
2634  $outpricebasetype = $objp->custprice_base_type;
2635  $outtva_tx = $objp->custtva_tx;
2636  }
2637  }
2638 
2639  // If level no defined or multiprice not found, we used the default price
2640  if (empty($hidepriceinlabel) && !$found)
2641  {
2642  if ($objp->price_base_type == 'HT')
2643  {
2644  $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2645  $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2646  } else {
2647  $opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2648  $outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2649  }
2650  $outprice_ht = price($objp->price);
2651  $outprice_ttc = price($objp->price_ttc);
2652  $outpricebasetype = $objp->price_base_type;
2653  $outtva_tx = $objp->tva_tx;
2654  }
2655 
2656  if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2657  {
2658  if (!empty($user->rights->stock->lire)) {
2659  $opt .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
2660 
2661  if ($objp->stock > 0) {
2662  $outval .= ' - <span class="product_line_stock_ok">';
2663  } elseif ($objp->stock <= 0) {
2664  $outval .= ' - <span class="product_line_stock_too_low">';
2665  }
2666  $outval .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS'));
2667  $outval .= '</span>';
2668  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) // Warning, this option may slow down combo list generation
2669  {
2670  $langs->load("stocks");
2671 
2672  $tmpproduct = new Product($this->db);
2673  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
2674  $tmpproduct->load_virtual_stock();
2675  $virtualstock = $tmpproduct->stock_theorique;
2676 
2677  $opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
2678 
2679  $outval .= ' - '.$langs->transnoentities("VirtualStock").':';
2680  if ($virtualstock > 0) {
2681  $outval .= '<span class="product_line_stock_ok">';
2682  } elseif ($virtualstock <= 0) {
2683  $outval .= '<span class="product_line_stock_too_low">';
2684  }
2685  $outval .= $virtualstock;
2686  $outval .= '</span>';
2687 
2688  unset($tmpproduct);
2689  }
2690  }
2691  }
2692 
2693  $opt .= "</option>\n";
2694  $optJson = array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>price2num($outprice_ht), 'price_ttc'=>price2num($outprice_ttc), 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit, 'pbq'=>$outpbq);
2695  }
2696 
2697  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2712  public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '')
2713  {
2714  // phpcs:enable
2715  global $langs, $conf;
2716  global $price_level, $status, $finished;
2717 
2718  $selected_input_value = '';
2719  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2720  {
2721  if ($selected > 0)
2722  {
2723  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2724  $producttmpselect = new Product($this->db);
2725  $producttmpselect->fetch($selected);
2726  $selected_input_value = $producttmpselect->ref;
2727  unset($producttmpselect);
2728  }
2729 
2730  // mode=2 means suppliers products
2731  $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
2732  print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
2733  print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" size="20" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'">';
2734  } else {
2735  print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', -1, 0, 0, $alsoproductwithnosupplierprice, $morecss);
2736  }
2737  }
2738 
2739  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2757  public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0)
2758  {
2759  // phpcs:enable
2760  global $langs, $conf, $db, $user;
2761 
2762  $out = '';
2763  $outarray = array();
2764 
2765  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2766 
2767  $langs->load('stocks');
2768  // Units
2769  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2770  $langs->load('other');
2771  }
2772 
2773  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock,";
2774  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
2775  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,";
2776  $sql .= " pfp.supplier_reputation";
2777  // Units
2778  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2779  $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";
2780  }
2781  if (!empty($conf->barcode->enabled)) $sql .= ", pfp.barcode";
2782  $sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2783  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )";
2784  if ($socid) $sql .= " AND pfp.fk_soc = ".$socid;
2785  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2786  // Units
2787  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2788  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2789  }
2790  $sql .= " WHERE p.entity IN (".getEntity('product').")";
2791  $sql .= " AND p.tobuy = 1";
2792  if (strval($filtertype) != '') $sql .= " AND p.fk_product_type=".$this->db->escape($filtertype);
2793  if (!empty($filtre)) $sql .= " ".$filtre;
2794  // Add criteria on ref/label
2795  if ($filterkey != '')
2796  {
2797  $sql .= ' AND (';
2798  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2799  // For natural search
2800  $scrit = explode(' ', $filterkey);
2801  $i = 0;
2802  if (count($scrit) > 1) $sql .= "(";
2803  foreach ($scrit as $crit)
2804  {
2805  if ($i > 0) $sql .= " AND ";
2806  $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)."%')";
2807  $i++;
2808  }
2809  if (count($scrit) > 1) $sql .= ")";
2810  if (!empty($conf->barcode->enabled)) {
2811  $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2812  $sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2813  }
2814  $sql .= ')';
2815  }
2816  $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
2817  $sql .= $this->db->plimit($limit, 0);
2818 
2819  // Build output string
2820 
2821  dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
2822  $result = $this->db->query($sql);
2823  if ($result)
2824  {
2825  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2826  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2827 
2828  $num = $this->db->num_rows($result);
2829 
2830  //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
2831  $out .= '<select class="flat maxwidthonsmartphone'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
2832  if (!$selected) $out .= '<option value="0" selected>&nbsp;</option>';
2833  else $out .= '<option value="0">&nbsp;</option>';
2834 
2835  $i = 0;
2836  while ($i < $num)
2837  {
2838  $objp = $this->db->fetch_object($result);
2839 
2840  $outkey = $objp->idprodfournprice; // id in table of price
2841  if (!$outkey && $alsoproductwithnosupplierprice) $outkey = 'idprod_'.$objp->rowid; // id of product
2842 
2843  $outref = $objp->ref;
2844  $outval = '';
2845  $outbarcode = $objp->barcode;
2846  $outqty = 1;
2847  $outdiscount = 0;
2848  $outtype = $objp->fk_product_type;
2849  $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2850  $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2851 
2852  // Units
2853  $outvalUnits = '';
2854  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2855  if (!empty($objp->unit_short)) {
2856  $outvalUnits .= ' - '.$objp->unit_short;
2857  }
2858  if (!empty($objp->weight) && $objp->weight_units !== null) {
2859  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2860  $outvalUnits .= ' - '.$unitToShow;
2861  }
2862  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2863  $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2864  $outvalUnits .= ' - '.$unitToShow;
2865  }
2866  if (!empty($objp->surface) && $objp->surface_units !== null) {
2867  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2868  $outvalUnits .= ' - '.$unitToShow;
2869  }
2870  if (!empty($objp->volume) && $objp->volume_units !== null) {
2871  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2872  $outvalUnits .= ' - '.$unitToShow;
2873  }
2874  if ($outdurationvalue && $outdurationunit) {
2875  $da = array(
2876  'h' => $langs->trans('Hour'),
2877  'd' => $langs->trans('Day'),
2878  'w' => $langs->trans('Week'),
2879  'm' => $langs->trans('Month'),
2880  'y' => $langs->trans('Year')
2881  );
2882  if (isset($da[$outdurationunit])) {
2883  $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2884  }
2885  }
2886  }
2887 
2888  $objRef = $objp->ref;
2889  if ($filterkey && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2890  $objRefFourn = $objp->ref_fourn;
2891  if ($filterkey && $filterkey != '') $objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1);
2892  $label = $objp->label;
2893  if ($filterkey && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2894 
2895  $optlabel = $objp->ref;
2896  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
2897  $optlabel .= ' <span class=\'opacitymedium\'>('.$objp->ref_fourn.')</span>';
2898  }
2899  if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
2900  $optlabel .= ' ('.$outbarcode.')';
2901  }
2902  $optlabel .= ' - '.dol_trunc($label, $maxlengtharticle);
2903 
2904  $outvallabel = $objRef;
2905  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
2906  $outvallabel .= ' ('.$objRefFourn.')';
2907  }
2908  if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
2909  $outvallabel .= ' ('.$outbarcode.')';
2910  }
2911  $outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle);
2912 
2913  // Units
2914  $optlabel .= $outvalUnits;
2915  $outvallabel .= $outvalUnits;
2916 
2917  if (!empty($objp->idprodfournprice))
2918  {
2919  $outqty = $objp->quantity;
2920  $outdiscount = $objp->remise_percent;
2921  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2922  $prod_supplier = new ProductFournisseur($this->db);
2923  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2924  $prod_supplier->id = $objp->fk_product;
2925  $prod_supplier->fourn_qty = $objp->quantity;
2926  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
2927  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2928  $priceparser = new PriceParser($this->db);
2929  $price_result = $priceparser->parseProductSupplier($prod_supplier);
2930  if ($price_result >= 0) {
2931  $objp->fprice = $price_result;
2932  if ($objp->quantity >= 1)
2933  {
2934  $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
2935  }
2936  }
2937  }
2938  if ($objp->quantity == 1)
2939  {
2940  $optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
2941  $outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
2942  $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2943  $outvallabel .= $langs->transnoentities("Unit");
2944  } else {
2945  $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;
2946  $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;
2947  $optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2948  $outvallabel .= ' '.$langs->transnoentities("Units");
2949  }
2950 
2951  if ($objp->quantity > 1)
2952  {
2953  $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
2954  $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
2955  }
2956  if ($objp->remise_percent >= 1)
2957  {
2958  $optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2959  $outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2960  }
2961  if ($objp->duration)
2962  {
2963  $optlabel .= " - ".$objp->duration;
2964  $outvallabel .= " - ".$objp->duration;
2965  }
2966  if (!$socid)
2967  {
2968  $optlabel .= " - ".dol_trunc($objp->name, 8);
2969  $outvallabel .= " - ".dol_trunc($objp->name, 8);
2970  }
2971  if ($objp->supplier_reputation)
2972  {
2973  //TODO dictionary
2974  $reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
2975 
2976  $optlabel .= " - ".$reputations[$objp->supplier_reputation];
2977  $outvallabel .= " - ".$reputations[$objp->supplier_reputation];
2978  }
2979  } else {
2980  if (empty($alsoproductwithnosupplierprice)) // No supplier price defined for couple product/supplier
2981  {
2982  $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
2983  $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
2984  } else // No supplier price defined for product, even on other suppliers
2985  {
2986  $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
2987  $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
2988  }
2989  }
2990 
2991  if (!empty($conf->stock->enabled) && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2992  {
2993  $novirtualstock = ($showstockinlist == 2);
2994 
2995  if (!empty($user->rights->stock->lire)) {
2996  $outvallabel .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
2997 
2998  if ($objp->stock > 0) {
2999  $optlabel .= ' - <span class="product_line_stock_ok">';
3000  } elseif ($objp->stock <= 0) {
3001  $optlabel .= ' - <span class="product_line_stock_too_low">';
3002  }
3003  $optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS'));
3004  $optlabel .= '</span>';
3005  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) // Warning, this option may slow down combo list generation
3006  {
3007  $langs->load("stocks");
3008 
3009  $tmpproduct = new Product($this->db);
3010  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3011  $tmpproduct->load_virtual_stock();
3012  $virtualstock = $tmpproduct->stock_theorique;
3013 
3014  $outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3015 
3016  $optlabel .= ' - '.$langs->transnoentities("VirtualStock").':';
3017  if ($virtualstock > 0) {
3018  $optlabel .= '<span class="product_line_stock_ok">';
3019  } elseif ($virtualstock <= 0) {
3020  $optlabel .= '<span class="product_line_stock_too_low">';
3021  }
3022  $optlabel .= $virtualstock;
3023  $optlabel .= '</span>';
3024 
3025  unset($tmpproduct);
3026  }
3027  }
3028  }
3029 
3030  $opt = '<option value="'.$outkey.'"';
3031  if ($selected && $selected == $objp->idprodfournprice) $opt .= ' selected';
3032  if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) $opt .= ' disabled';
3033  if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0)
3034  {
3035  $opt .= ' pbq="'.$objp->idprodfournprice.'" data-pbq="'.$objp->idprodfournprice.'" data-pbqqty="'.$objp->quantity.'" data-pbqup="'.$objp->unitprice.'" data-pbqpercent="'.$objp->remise_percent.'"';
3036  }
3037  $opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"';
3038  $opt .= '>';
3039 
3040  $opt .= $optlabel;
3041  $outval .= $outvallabel;
3042 
3043  $opt .= "</option>\n";
3044 
3045 
3046  // Add new entry
3047  // "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
3048  // "label" value of json key array is used by jQuery automatically as text for combo box
3049  $out .= $opt;
3050  array_push($outarray, array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'qty'=>$outqty, 'price_ht'=>price2num($objp->unitprice, 'MT'), 'up'=>price2num($objp->unitprice, 'MT'), 'discount'=>$outdiscount, 'type'=>$outtype, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit, 'disabled'=>(empty($objp->idprodfournprice) ?true:false)));
3051  // Exemple of var_dump $outarray
3052  // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3053  // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3054  // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3055  //}
3056  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3057  //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3058  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3059 
3060  $i++;
3061  }
3062  $out .= '</select>';
3063 
3064  $this->db->free($result);
3065 
3066  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3067  $out .= ajax_combobox($htmlname);
3068 
3069  if (empty($outputmode)) return $out;
3070  return $outarray;
3071  } else {
3072  dol_print_error($this->db);
3073  }
3074  }
3075 
3076  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3085  public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3086  {
3087  // phpcs:enable
3088  global $langs, $conf;
3089 
3090  $langs->load('stocks');
3091 
3092  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3093  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3094  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3095  $sql .= " FROM ".MAIN_DB_PREFIX."product as p";
3096  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3097  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
3098  $sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3099  $sql .= " AND p.tobuy = 1";
3100  $sql .= " AND s.fournisseur = 1";
3101  $sql .= " AND p.rowid = ".$productid;
3102  $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3103 
3104  dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3105  $result = $this->db->query($sql);
3106 
3107  if ($result)
3108  {
3109  $num = $this->db->num_rows($result);
3110 
3111  $form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3112 
3113  if (!$num)
3114  {
3115  $form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3116  } else {
3117  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3118  $form .= '<option value="0">&nbsp;</option>';
3119 
3120  $i = 0;
3121  while ($i < $num)
3122  {
3123  $objp = $this->db->fetch_object($result);
3124 
3125  $opt = '<option value="'.$objp->idprodfournprice.'"';
3126  //if there is only one supplier, preselect it
3127  if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
3128  $opt .= ' selected';
3129  }
3130  $opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3131 
3132  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3133  $prod_supplier = new ProductFournisseur($this->db);
3134  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3135  $prod_supplier->id = $productid;
3136  $prod_supplier->fourn_qty = $objp->quantity;
3137  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3138  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3139  $priceparser = new PriceParser($this->db);
3140  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3141  if ($price_result >= 0) {
3142  $objp->fprice = $price_result;
3143  if ($objp->quantity >= 1)
3144  {
3145  $objp->unitprice = $objp->fprice / $objp->quantity;
3146  }
3147  }
3148  }
3149  if ($objp->quantity == 1)
3150  {
3151  $opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3152  }
3153 
3154  $opt .= $objp->quantity.' ';
3155 
3156  if ($objp->quantity == 1)
3157  {
3158  $opt .= $langs->trans("Unit");
3159  } else {
3160  $opt .= $langs->trans("Units");
3161  }
3162  if ($objp->quantity > 1)
3163  {
3164  $opt .= " - ";
3165  $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");
3166  }
3167  if ($objp->duration) $opt .= " - ".$objp->duration;
3168  $opt .= "</option>\n";
3169 
3170  $form .= $opt;
3171  $i++;
3172  }
3173  }
3174 
3175  $form .= '</select>';
3176  $this->db->free($result);
3177  return $form;
3178  } else {
3179  dol_print_error($this->db);
3180  }
3181  }
3182 
3183  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3193  public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3194  {
3195  // phpcs:enable
3196  // looking for users
3197  $sql = "SELECT a.rowid, a.label";
3198  $sql .= " FROM ".MAIN_DB_PREFIX."societe_address as a";
3199  $sql .= " WHERE a.fk_soc = ".$socid;
3200  $sql .= " ORDER BY a.label ASC";
3201 
3202  dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3203  $resql = $this->db->query($sql);
3204  if ($resql)
3205  {
3206  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3207  if ($showempty) print '<option value="0">&nbsp;</option>';
3208  $num = $this->db->num_rows($resql);
3209  $i = 0;
3210  if ($num)
3211  {
3212  while ($i < $num)
3213  {
3214  $obj = $this->db->fetch_object($resql);
3215 
3216  if ($selected && $selected == $obj->rowid)
3217  {
3218  print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3219  } else {
3220  print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3221  }
3222  $i++;
3223  }
3224  }
3225  print '</select>';
3226  return $num;
3227  } else {
3228  dol_print_error($this->db);
3229  }
3230  }
3231 
3232 
3233  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3240  {
3241  // phpcs:enable
3242  global $langs;
3243 
3244  $num = count($this->cache_conditions_paiements);
3245  if ($num > 0) return 0; // Cache already loaded
3246 
3247  dol_syslog(__METHOD__, LOG_DEBUG);
3248 
3249  $sql = "SELECT rowid, code, libelle as label";
3250  $sql .= " FROM ".MAIN_DB_PREFIX.'c_payment_term';
3251  $sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3252  $sql .= " AND active > 0";
3253  $sql .= " ORDER BY sortorder";
3254 
3255  $resql = $this->db->query($sql);
3256  if ($resql)
3257  {
3258  $num = $this->db->num_rows($resql);
3259  $i = 0;
3260  while ($i < $num)
3261  {
3262  $obj = $this->db->fetch_object($resql);
3263 
3264  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3265  $label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3266  $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3267  $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3268  $i++;
3269  }
3270 
3271  //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
3272 
3273  return $num;
3274  } else {
3275  dol_print_error($this->db);
3276  return -1;
3277  }
3278  }
3279 
3280  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3286  public function load_cache_availability()
3287  {
3288  // phpcs:enable
3289  global $langs;
3290 
3291  $num = count($this->cache_availability);
3292  if ($num > 0) return 0; // Cache already loaded
3293 
3294  dol_syslog(__METHOD__, LOG_DEBUG);
3295 
3296  $langs->load('propal');
3297 
3298  $sql = "SELECT rowid, code, label";
3299  $sql .= " FROM ".MAIN_DB_PREFIX.'c_availability';
3300  $sql .= " WHERE active > 0";
3301 
3302  $resql = $this->db->query($sql);
3303  if ($resql)
3304  {
3305  $num = $this->db->num_rows($resql);
3306  $i = 0;
3307  while ($i < $num)
3308  {
3309  $obj = $this->db->fetch_object($resql);
3310 
3311  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3312  $label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3313  $this->cache_availability[$obj->rowid]['code'] = $obj->code;
3314  $this->cache_availability[$obj->rowid]['label'] = $label;
3315  $i++;
3316  }
3317 
3318  $this->cache_availability = dol_sort_array($this->cache_availability, 'label', 'asc', 0, 0, 1);
3319 
3320  return $num;
3321  } else {
3322  dol_print_error($this->db);
3323  return -1;
3324  }
3325  }
3326 
3336  public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0)
3337  {
3338  global $langs, $user;
3339 
3340  $this->load_cache_availability();
3341 
3342  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3343 
3344  print '<select id="'.$htmlname.'" class="flat" name="'.$htmlname.'">';
3345  if ($addempty) print '<option value="0">&nbsp;</option>';
3346  foreach ($this->cache_availability as $id => $arrayavailability)
3347  {
3348  if ($selected == $id)
3349  {
3350  print '<option value="'.$id.'" selected>';
3351  } else {
3352  print '<option value="'.$id.'">';
3353  }
3354  print $arrayavailability['label'];
3355  print '</option>';
3356  }
3357  print '</select>';
3358  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3359  print ajax_combobox($htmlname);
3360  }
3361 
3367  public function loadCacheInputReason()
3368  {
3369  global $langs;
3370 
3371  $num = count($this->cache_demand_reason);
3372  if ($num > 0) return 0; // Cache already loaded
3373 
3374  $sql = "SELECT rowid, code, label";
3375  $sql .= " FROM ".MAIN_DB_PREFIX.'c_input_reason';
3376  $sql .= " WHERE active > 0";
3377 
3378  $resql = $this->db->query($sql);
3379  if ($resql)
3380  {
3381  $num = $this->db->num_rows($resql);
3382  $i = 0;
3383  $tmparray = array();
3384  while ($i < $num)
3385  {
3386  $obj = $this->db->fetch_object($resql);
3387 
3388  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3389  $label = ($obj->label != '-' ? $obj->label : '');
3390  if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3391  if ($langs->trans($obj->code) != $obj->code) $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3392 
3393  $tmparray[$obj->rowid]['id'] = $obj->rowid;
3394  $tmparray[$obj->rowid]['code'] = $obj->code;
3395  $tmparray[$obj->rowid]['label'] = $label;
3396  $i++;
3397  }
3398 
3399  $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3400 
3401  unset($tmparray);
3402  return $num;
3403  } else {
3404  dol_print_error($this->db);
3405  return -1;
3406  }
3407  }
3408 
3419  public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0)
3420  {
3421  global $langs, $user;
3422 
3423  $this->loadCacheInputReason();
3424 
3425  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3426  if ($addempty) print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
3427  foreach ($this->cache_demand_reason as $id => $arraydemandreason)
3428  {
3429  if ($arraydemandreason['code'] == $exclude) continue;
3430 
3431  if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code']))
3432  {
3433  print '<option value="'.$arraydemandreason['id'].'" selected>';
3434  } else {
3435  print '<option value="'.$arraydemandreason['id'].'">';
3436  }
3437  $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3438  print $langs->trans($label);
3439  print '</option>';
3440  }
3441  print '</select>';
3442  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3443  print ajax_combobox('select_'.$htmlname);
3444  }
3445 
3446  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3452  public function load_cache_types_paiements()
3453  {
3454  // phpcs:enable
3455  global $langs;
3456 
3457  $num = count($this->cache_types_paiements);
3458  if ($num > 0) return $num; // Cache already loaded
3459 
3460  dol_syslog(__METHOD__, LOG_DEBUG);
3461 
3462  $this->cache_types_paiements = array();
3463 
3464  $sql = "SELECT id, code, libelle as label, type, active";
3465  $sql .= " FROM ".MAIN_DB_PREFIX."c_paiement";
3466  $sql .= " WHERE entity IN (".getEntity('c_paiement').")";
3467  //if ($active >= 0) $sql.= " AND active = ".$active;
3468 
3469  $resql = $this->db->query($sql);
3470  if ($resql)
3471  {
3472  $num = $this->db->num_rows($resql);
3473  $i = 0;
3474  while ($i < $num)
3475  {
3476  $obj = $this->db->fetch_object($resql);
3477 
3478  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3479  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3480  $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
3481  $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
3482  $this->cache_types_paiements[$obj->id]['label'] = $label;
3483  $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
3484  $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
3485  $i++;
3486  }
3487 
3488  $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3489 
3490  return $num;
3491  } else {
3492  dol_print_error($this->db);
3493  return -1;
3494  }
3495  }
3496 
3497 
3498  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3512  public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
3513  {
3514  // phpcs:enable
3515  global $langs, $user, $conf;
3516 
3517  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3518 
3520 
3521  // Set default value if not already set by caller
3522  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
3523 
3524  print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3525  if ($addempty) print '<option value="0">&nbsp;</option>';
3526  foreach ($this->cache_conditions_paiements as $id => $arrayconditions)
3527  {
3528  if ($selected == $id)
3529  {
3530  print '<option value="'.$id.'" selected>';
3531  } else {
3532  print '<option value="'.$id.'">';
3533  }
3534  print $arrayconditions['label'];
3535  print '</option>';
3536  }
3537  print '</select>';
3538  if ($user->admin && empty($noinfoadmin)) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3539  print ajax_combobox($htmlname);
3540  }
3541 
3542 
3543  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3559  public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
3560  {
3561  // phpcs:enable
3562  global $langs, $user, $conf;
3563 
3564  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
3565 
3566  $filterarray = array();
3567  if ($filtertype == 'CRDT') $filterarray = array(0, 2, 3);
3568  elseif ($filtertype == 'DBIT') $filterarray = array(1, 2, 3);
3569  elseif ($filtertype != '' && $filtertype != '-1') $filterarray = explode(',', $filtertype);
3570 
3571  $this->load_cache_types_paiements();
3572 
3573  // Set default value if not already set by caller
3574  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
3575 
3576  print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3577  if ($empty) print '<option value="">&nbsp;</option>';
3578  foreach ($this->cache_types_paiements as $id => $arraytypes)
3579  {
3580  // If not good status
3581  if ($active >= 0 && $arraytypes['active'] != $active) continue;
3582 
3583  // On passe si on a demande de filtrer sur des modes de paiments particuliers
3584  if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) continue;
3585 
3586  // We discard empty line if showempty is on because an empty line has already been output.
3587  if ($empty && empty($arraytypes['code'])) continue;
3588 
3589  if ($format == 0) print '<option value="'.$id.'"';
3590  elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3591  elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3592  elseif ($format == 3) print '<option value="'.$id.'"';
3593  // Print attribute selected or not
3594  if ($format == 1 || $format == 2) {
3595  if ($selected == $arraytypes['code']) print ' selected';
3596  } else {
3597  if ($selected == $id) print ' selected';
3598  }
3599  print '>';
3600  if ($format == 0) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3601  elseif ($format == 1) $value = $arraytypes['code'];
3602  elseif ($format == 2) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3603  elseif ($format == 3) $value = $arraytypes['code'];
3604  print $value ? $value : '&nbsp;';
3605  print '</option>';
3606  }
3607  print '</select>';
3608  if ($user->admin && !$noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3609  print ajax_combobox('select'.$htmlname);
3610  }
3611 
3612 
3621  public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
3622  {
3623  global $langs;
3624 
3625  $return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3626  $options = array(
3627  'HT'=>$langs->trans("HT"),
3628  'TTC'=>$langs->trans("TTC")
3629  );
3630  foreach ($options as $id => $value)
3631  {
3632  if ($selected == $id)
3633  {
3634  $return .= '<option value="'.$id.'" selected>'.$value;
3635  } else {
3636  $return .= '<option value="'.$id.'">'.$value;
3637  }
3638  $return .= '</option>';
3639  }
3640  $return .= '</select>';
3641  if ($addjscombo) $return .= ajax_combobox('select_'.$htmlname);
3642 
3643  return $return;
3644  }
3645 
3646  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3652  public function load_cache_transport_mode()
3653  {
3654  // phpcs:enable
3655  global $langs;
3656 
3657  $num = count($this->cache_transport_mode);
3658  if ($num > 0) return $num; // Cache already loaded
3659 
3660  dol_syslog(__METHOD__, LOG_DEBUG);
3661 
3662  $this->cache_transport_mode = array();
3663 
3664  $sql = "SELECT rowid, code, label, active";
3665  $sql .= " FROM ".MAIN_DB_PREFIX."c_transport_mode";
3666  $sql .= " WHERE entity IN (".getEntity('c_transport_mode').")";
3667  //if ($active >= 0) $sql.= " AND active = ".$active;
3668 
3669  $resql = $this->db->query($sql);
3670  if ($resql)
3671  {
3672  $num = $this->db->num_rows($resql);
3673  $i = 0;
3674  while ($i < $num)
3675  {
3676  $obj = $this->db->fetch_object($resql);
3677 
3678  // If traduction exist, we use it else we take the default label
3679  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3680  $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
3681  $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
3682  $this->cache_transport_mode[$obj->rowid]['label'] = $label;
3683  $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
3684  $i++;
3685  }
3686 
3687  $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
3688 
3689  return $num;
3690  }
3691  else {
3692  dol_print_error($this->db);
3693  return -1;
3694  }
3695  }
3696 
3710  public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
3711  {
3712  global $langs, $user;
3713 
3714  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
3715 
3716  $this->load_cache_transport_mode();
3717 
3718  print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3719  if ($empty) print '<option value="">&nbsp;</option>';
3720  foreach ($this->cache_transport_mode as $id => $arraytypes)
3721  {
3722  // If not good status
3723  if ($active >= 0 && $arraytypes['active'] != $active) continue;
3724 
3725  // We discard empty line if showempty is on because an empty line has already been output.
3726  if ($empty && empty($arraytypes['code'])) continue;
3727 
3728  if ($format == 0) print '<option value="'.$id.'"';
3729  elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3730  elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3731  elseif ($format == 3) print '<option value="'.$id.'"';
3732  // If text is selected, we compare with code, else with id
3733  if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) print ' selected';
3734  elseif ($selected == $id) print ' selected';
3735  print '>';
3736  if ($format == 0) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3737  elseif ($format == 1) $value = $arraytypes['code'];
3738  elseif ($format == 2) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3739  elseif ($format == 3) $value = $arraytypes['code'];
3740  print $value ? $value : '&nbsp;';
3741  print '</option>';
3742  }
3743  print '</select>';
3744  if ($user->admin && !$noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3745  }
3746 
3757  public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '')
3758  {
3759  global $langs, $conf, $user;
3760 
3761  $langs->load("admin");
3762  $langs->load("deliveries");
3763 
3764  $sql = "SELECT rowid, code, libelle as label";
3765  $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode";
3766  $sql .= " WHERE active > 0";
3767  if ($filtre) $sql .= " AND ".$filtre;
3768  $sql .= " ORDER BY libelle ASC";
3769 
3770  dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
3771  $result = $this->db->query($sql);
3772  if ($result) {
3773  $num = $this->db->num_rows($result);
3774  $i = 0;
3775  if ($num) {
3776  print '<select id="select'.$htmlname.'" class="flat selectshippingmethod" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3777  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
3778  print '<option value="-1">&nbsp;</option>';
3779  }
3780  while ($i < $num) {
3781  $obj = $this->db->fetch_object($result);
3782  if ($selected == $obj->rowid) {
3783  print '<option value="'.$obj->rowid.'" selected>';
3784  } else {
3785  print '<option value="'.$obj->rowid.'">';
3786  }
3787  print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
3788  print '</option>';
3789  $i++;
3790  }
3791  print "</select>";
3792  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3793 
3794  print ajax_combobox('select'.$htmlname);
3795  } else {
3796  print $langs->trans("NoShippingMethodDefined");
3797  }
3798  } else {
3799  dol_print_error($this->db);
3800  }
3801  }
3802 
3812  public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
3813  {
3814  global $langs, $db;
3815 
3816  $langs->load("deliveries");
3817 
3818  if ($htmlname != "none") {
3819  print '<form method="POST" action="'.$page.'">';
3820  print '<input type="hidden" name="action" value="setshippingmethod">';
3821  print '<input type="hidden" name="token" value="'.newToken().'">';
3822  $this->selectShippingMethod($selected, $htmlname, '', $addempty);
3823  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3824  print '</form>';
3825  } else {
3826  if ($selected) {
3827  $code = $langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code');
3828  print $langs->trans("SendingMethod".strtoupper($code));
3829  } else {
3830  print "&nbsp;";
3831  }
3832  }
3833  }
3834 
3843  public function selectSituationInvoices($selected = '', $socid = 0)
3844  {
3845  global $langs;
3846 
3847  $langs->load('bills');
3848 
3849  $opt = '<option value ="" selected></option>';
3850  $sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc';
3851  $sql .= ' FROM '.MAIN_DB_PREFIX.'facture';
3852  $sql .= ' WHERE entity IN ('.getEntity('invoice').')';
3853  $sql .= ' AND situation_counter >= 1';
3854  $sql .= ' AND fk_soc = '.(int) $socid;
3855  $sql .= ' AND type <> 2';
3856  $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
3857  $resql = $this->db->query($sql);
3858 
3859  if ($resql && $this->db->num_rows($resql) > 0) {
3860  // Last seen cycle
3861  $ref = 0;
3862  while ($obj = $this->db->fetch_object($resql)) {
3863  //Same cycle ?
3864  if ($obj->situation_cycle_ref != $ref) {
3865  // Just seen this cycle
3866  $ref = $obj->situation_cycle_ref;
3867  //not final ?
3868  if ($obj->situation_final != 1) {
3869  //Not prov?
3870  if (substr($obj->ref, 1, 4) != 'PROV') {
3871  if ($selected == $obj->rowid) {
3872  $opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
3873  } else {
3874  $opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
3875  }
3876  }
3877  }
3878  }
3879  }
3880  } else {
3881  dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
3882  }
3883  if ($opt == '<option value ="" selected></option>')
3884  {
3885  $opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
3886  }
3887  return $opt;
3888  }
3889 
3898  public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0)
3899  {
3900  global $langs;
3901 
3902  $langs->load('products');
3903 
3904  $return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
3905 
3906  $sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units';
3907  $sql .= ' WHERE active > 0';
3908 
3909  $resql = $this->db->query($sql);
3910  if ($resql && $this->db->num_rows($resql) > 0)
3911  {
3912  if ($showempty) $return .= '<option value="none"></option>';
3913 
3914  while ($res = $this->db->fetch_object($resql))
3915  {
3916  $unitLabel = $res->label;
3917  if (!empty($langs->tab_translate['unit'.$res->code])) // check if Translation is available before
3918  {
3919  $unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
3920  }
3921 
3922  if ($selected == $res->rowid)
3923  {
3924  $return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
3925  } else {
3926  $return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
3927  }
3928  }
3929  $return .= '</select>';
3930  }
3931  return $return;
3932  }
3933 
3934  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3949  public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
3950  {
3951  // phpcs:enable
3952  global $langs, $conf;
3953 
3954  $out = '';
3955 
3956  $langs->load("admin");
3957  $num = 0;
3958 
3959  $sql = "SELECT rowid, label, bank, clos as status, currency_code";
3960  $sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
3961  $sql .= " WHERE entity IN (".getEntity('bank_account').")";
3962  if ($status != 2) $sql .= " AND clos = ".(int) $status;
3963  if ($filtre) $sql .= " AND ".$filtre;
3964  $sql .= " ORDER BY label";
3965 
3966  dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
3967  $result = $this->db->query($sql);
3968  if ($result)
3969  {
3970  $num = $this->db->num_rows($result);
3971  $i = 0;
3972  if ($num)
3973  {
3974  $out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3975  if ($useempty == 1 || ($useempty == 2 && $num > 1))
3976  {
3977  $out .= '<option value="-1">&nbsp;</option>';
3978  }
3979 
3980  while ($i < $num)
3981  {
3982  $obj = $this->db->fetch_object($result);
3983  if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected)))
3984  {
3985  $out .= '<option value="'.$obj->rowid.'" selected>';
3986  } else {
3987  $out .= '<option value="'.$obj->rowid.'">';
3988  }
3989  $out .= trim($obj->label);
3990  if ($showcurrency) $out .= ' ('.$obj->currency_code.')';
3991  if ($status == 2 && $obj->status == 1) $out .= ' ('.$langs->trans("Closed").')';
3992  $out .= '</option>';
3993  $i++;
3994  }
3995  $out .= "</select>";
3996  $out .= ajax_combobox('select'.$htmlname);
3997  } else {
3998  if ($status == 0) $out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
3999  else $out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
4000  }
4001  } else {
4002  dol_print_error($this->db);
4003  }
4004 
4005  // Output or return
4006  if (empty($nooutput)) print $out;
4007  else return $out;
4008 
4009  return $num;
4010  }
4011 
4023  public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4024  {
4025  // phpcs:enable
4026  global $langs, $conf;
4027 
4028  $langs->load("admin");
4029  $num = 0;
4030 
4031  $sql = "SELECT rowid, name, fk_country, status, entity";
4032  $sql .= " FROM ".MAIN_DB_PREFIX."establishment";
4033  $sql .= " WHERE 1=1";
4034  if ($status != 2) $sql .= " AND status = ".(int) $status;
4035  if ($filtre) $sql .= " AND ".$filtre;
4036  $sql .= " ORDER BY name";
4037 
4038  dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
4039  $result = $this->db->query($sql);
4040  if ($result)
4041  {
4042  $num = $this->db->num_rows($result);
4043  $i = 0;
4044  if ($num)
4045  {
4046  print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4047  if ($useempty == 1 || ($useempty == 2 && $num > 1))
4048  {
4049  print '<option value="-1">&nbsp;</option>';
4050  }
4051 
4052  while ($i < $num)
4053  {
4054  $obj = $this->db->fetch_object($result);
4055  if ($selected == $obj->rowid)
4056  {
4057  print '<option value="'.$obj->rowid.'" selected>';
4058  } else {
4059  print '<option value="'.$obj->rowid.'">';
4060  }
4061  print trim($obj->name);
4062  if ($status == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
4063  print '</option>';
4064  $i++;
4065  }
4066  print "</select>";
4067  } else {
4068  if ($status == 0) print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
4069  else print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
4070  }
4071  } else {
4072  dol_print_error($this->db);
4073  }
4074  }
4075 
4085  public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4086  {
4087  global $langs;
4088  if ($htmlname != "none") {
4089  print '<form method="POST" action="'.$page.'">';
4090  print '<input type="hidden" name="action" value="setbankaccount">';
4091  print '<input type="hidden" name="token" value="'.newToken().'">';
4092  $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4093  if ($nbaccountfound > 0) print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4094  print '</form>';
4095  } else {
4096  $langs->load('banks');
4097 
4098  if ($selected) {
4099  require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
4100  $bankstatic = new Account($this->db);
4101  $result = $bankstatic->fetch($selected);
4102  if ($result) print $bankstatic->getNomUrl(1);
4103  } else {
4104  print "&nbsp;";
4105  }
4106  }
4107  }
4108 
4109  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4128  public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4129  {
4130  // phpcs:enable
4131  global $conf, $langs;
4132  $langs->load("categories");
4133 
4134  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4135 
4136  // For backward compatibility
4137  if (is_numeric($type))
4138  {
4139  dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4140  }
4141 
4142  if ($type === Categorie::TYPE_BANK_LINE)
4143  {
4144  // TODO Move this into common category feature
4145  $cate_arbo = array();
4146  $sql = "SELECT c.label, c.rowid";
4147  $sql .= " FROM ".MAIN_DB_PREFIX."bank_categ as c";
4148  $sql .= " WHERE entity = ".$conf->entity;
4149  $sql .= " ORDER BY c.label";
4150  $result = $this->db->query($sql);
4151  if ($result)
4152  {
4153  $num = $this->db->num_rows($result);
4154  $i = 0;
4155  while ($i < $num)
4156  {
4157  $objp = $this->db->fetch_object($result);
4158  if ($objp) $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
4159  $i++;
4160  }
4161  $this->db->free($result);
4162  } else dol_print_error($this->db);
4163  } else {
4164  $cat = new Categorie($this->db);
4165  $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4166  }
4167 
4168  $output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4169  $outarray = array();
4170  if (is_array($cate_arbo))
4171  {
4172  if (!count($cate_arbo)) $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4173  else {
4174  $output .= '<option value="-1">&nbsp;</option>';
4175  foreach ($cate_arbo as $key => $value)
4176  {
4177  if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1))
4178  {
4179  $add = 'selected ';
4180  } else {
4181  $add = '';
4182  }
4183  $output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>';
4184 
4185  $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4186  }
4187  }
4188  }
4189  $output .= '</select>';
4190  $output .= "\n";
4191 
4192  if ($outputmode) return $outarray;
4193  return $output;
4194  }
4195 
4196  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4213  public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4214  {
4215  // phpcs:enable
4216  dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4217  print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4218  }
4219 
4244  public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0)
4245  {
4246  global $langs, $conf;
4247 
4248  $more = '<!-- formconfirm for page='.dol_escape_htmltag($page).' -->';
4249  $formconfirm = '';
4250  $inputok = array();
4251  $inputko = array();
4252 
4253  // Clean parameters
4254  $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
4255  if ($conf->browser->layout == 'phone') $width = '95%';
4256 
4257  // Set height automatically if not defined
4258  if (empty($height)) {
4259  $height = 220;
4260  if (is_array($formquestion) && count($formquestion) > 2) {
4261  $height += ((count($formquestion) - 2) * 24);
4262  }
4263  }
4264 
4265  if (is_array($formquestion) && !empty($formquestion))
4266  {
4267  // First add hidden fields and value
4268  foreach ($formquestion as $key => $input)
4269  {
4270  if (is_array($input) && !empty($input))
4271  {
4272  if ($input['type'] == 'hidden')
4273  {
4274  $more .= '<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
4275  }
4276  }
4277  }
4278 
4279  // Now add questions
4280  $moreonecolumn = '';
4281  $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
4282  foreach ($formquestion as $key => $input)
4283  {
4284  if (is_array($input) && !empty($input))
4285  {
4286  $size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : '');
4287  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4288  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4289 
4290  if ($input['type'] == 'text')
4291  {
4292  $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="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4293  } elseif ($input['type'] == 'password')
4294  {
4295  $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="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4296  } elseif ($input['type'] == 'select')
4297  {
4298  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4299  if (!empty($input['label'])) $more .= $input['label'].'</div><div class="tagtd left">';
4300  $more .= $this->selectarray($input['name'], $input['values'], $input['default'], 1, 0, 0, $moreattr, 0, 0, 0, '', $morecss);
4301  $more .= '</div></div>'."\n";
4302  } elseif ($input['type'] == 'checkbox')
4303  {
4304  $more .= '<div class="tagtr">';
4305  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
4306  $more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr;
4307  if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') $more .= ' checked';
4308  if (is_bool($input['value']) && $input['value']) $more .= ' checked';
4309  if (isset($input['disabled'])) $more .= ' disabled';
4310  $more .= ' /></div>';
4311  $more .= '</div>'."\n";
4312  } elseif ($input['type'] == 'radio')
4313  {
4314  $i = 0;
4315  foreach ($input['values'] as $selkey => $selval)
4316  {
4317  $more .= '<div class="tagtr">';
4318  if ($i == 0) $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
4319  else $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
4320  $more .= '<div class="tagtd'.($i == 0 ? ' tdtop' : '').'"><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].$selkey.'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr;
4321  if ($input['disabled']) $more .= ' disabled';
4322  if (isset($input['default']) && $input['default'] === $selkey) $more .= ' checked="checked"';
4323  $more .= ' /> ';
4324  $more .= '<label for="'.$input['name'].$selkey.'">'.$selval.'</label>';
4325  $more .= '</div></div>'."\n";
4326  $i++;
4327  }
4328  } elseif ($input['type'] == 'date')
4329  {
4330  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
4331  $more .= '<div class="tagtd">';
4332  $more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, 0);
4333  $more .= '</div></div>'."\n";
4334  $formquestion[] = array('name'=>$input['name'].'day');
4335  $formquestion[] = array('name'=>$input['name'].'month');
4336  $formquestion[] = array('name'=>$input['name'].'year');
4337  $formquestion[] = array('name'=>$input['name'].'hour');
4338  $formquestion[] = array('name'=>$input['name'].'min');
4339  } elseif ($input['type'] == 'other')
4340  {
4341  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4342  if (!empty($input['label'])) $more .= $input['label'].'</div><div class="tagtd">';
4343  $more .= $input['value'];
4344  $more .= '</div></div>'."\n";
4345  } elseif ($input['type'] == 'onecolumn')
4346  {
4347  $moreonecolumn .= '<div class="margintoponly">';
4348  $moreonecolumn .= $input['value'];
4349  $moreonecolumn .= '</div>'."\n";
4350  }
4351  }
4352  }
4353  $more .= '</div>'."\n";
4354  $more .= $moreonecolumn;
4355  }
4356 
4357  // JQUI method dialog is broken with jmobile, we use standard HTML.
4358  // 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
4359  // See page product/card.php for example
4360  if (!empty($conf->dol_use_jmobile)) $useajax = 0;
4361  if (empty($conf->use_javascript_ajax)) $useajax = 0;
4362 
4363  if ($useajax)
4364  {
4365  $autoOpen = true;
4366  $dialogconfirm = 'dialog-confirm';
4367  $button = '';
4368  if (!is_numeric($useajax))
4369  {
4370  $button = $useajax;
4371  $useajax = 1;
4372  $autoOpen = false;
4373  $dialogconfirm .= '-'.$button;
4374  }
4375  $pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.$action.'&confirm=yes';
4376  $pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'confirm=no' : '');
4377  // Add input fields into list of fields to read during submit (inputok and inputko)
4378  if (is_array($formquestion))
4379  {
4380  foreach ($formquestion as $key => $input)
4381  {
4382  //print "xx ".$key." rr ".is_array($input)."<br>\n";
4383  if (is_array($input) && isset($input['name'])) array_push($inputok, $input['name']);
4384  if (isset($input['inputko']) && $input['inputko'] == 1) array_push($inputko, $input['name']);
4385  }
4386  }
4387  // Show JQuery confirm box.
4388  $formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
4389  if (is_array($formquestion) && !empty($formquestion['text'])) {
4390  $formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
4391  }
4392  if (!empty($more)) {
4393  $formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
4394  }
4395  $formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
4396  $formconfirm .= '</div>'."\n";
4397 
4398  $formconfirm .= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
4399  $formconfirm .= '<script type="text/javascript">'."\n";
4400  $formconfirm .= 'jQuery(document).ready(function() {
4401  $(function() {
4402  $( "#'.$dialogconfirm.'" ).dialog(
4403  {
4404  autoOpen: '.($autoOpen ? "true" : "false").',';
4405  if ($newselectedchoice == 'no')
4406  {
4407  $formconfirm .= '
4408  open: function() {
4409  $(this).parent().find("button.ui-button:eq(2)").focus();
4410  },';
4411  }
4412  $formconfirm .= '
4413  resizable: false,
4414  height: "'.$height.'",
4415  width: "'.$width.'",
4416  modal: true,
4417  closeOnEscape: false,
4418  buttons: {
4419  "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
4420  var options = "&token='.urlencode(newToken()).'";
4421  var inputok = '.json_encode($inputok).'; /* List of fields into form */
4422  var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
4423  if (inputok.length>0) {
4424  $.each(inputok, function(i, inputname) {
4425  var more = "";
4426  var inputvalue;
4427  if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
4428  inputvalue = $("input[name=\'" + inputname + "\']").val();
4429  } else {
4430  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4431  inputvalue = $("#" + inputname + more).val();
4432  }
4433  if (typeof inputvalue == "undefined") { inputvalue=""; }
4434  console.log("check inputname="+inputname+" inputvalue="+inputvalue);
4435  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4436  });
4437  }
4438  var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
4439  if (pageyes.length > 0) { location.href = urljump; }
4440  $(this).dialog("close");
4441  },
4442  "'.dol_escape_js($langs->transnoentities("No")).'": function() {
4443  var options = "&token='.urlencode(newToken()).'";
4444  var inputko = '.json_encode($inputko).'; /* List of fields into form */
4445  var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
4446  if (inputko.length>0) {
4447  $.each(inputko, function(i, inputname) {
4448  var more = "";
4449  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4450  var inputvalue = $("#" + inputname + more).val();
4451  if (typeof inputvalue == "undefined") { inputvalue=""; }
4452  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4453  });
4454  }
4455  var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
4456  //alert(urljump);
4457  if (pageno.length > 0) { location.href = urljump; }
4458  $(this).dialog("close");
4459  }
4460  }
4461  }
4462  );
4463 
4464  var button = "'.$button.'";
4465  if (button.length > 0) {
4466  $( "#" + button ).click(function() {
4467  $("#'.$dialogconfirm.'").dialog("open");
4468  });
4469  }
4470  });
4471  });
4472  </script>';
4473  $formconfirm .= "<!-- end ajax formconfirm -->\n";
4474  } else {
4475  $formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n";
4476 
4477  if (empty($disableformtag)) $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
4478 
4479  $formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
4480  $formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
4481 
4482  $formconfirm .= '<table class="valid centpercent">'."\n";
4483 
4484  // Line title
4485  $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="3">'.img_picto('', 'recent').' '.$title.'</td></tr>'."\n";
4486 
4487  // Line text
4488  if (is_array($formquestion) && !empty($formquestion['text'])) {
4489  $formconfirm .= '<tr class="valid"><td class="valid" colspan="3">'.$formquestion['text'].'</td></tr>'."\n";
4490  }
4491 
4492  // Line form fields
4493  if ($more)
4494  {
4495  $formconfirm .= '<tr class="valid"><td class="valid" colspan="3">'."\n";
4496  $formconfirm .= $more;
4497  $formconfirm .= '</td></tr>'."\n";
4498  }
4499 
4500  // Line with question
4501  $formconfirm .= '<tr class="valid">';
4502  $formconfirm .= '<td class="valid">'.$question.'</td>';
4503  $formconfirm .= '<td class="valid">';
4504  $formconfirm .= $this->selectyesno("confirm", $newselectedchoice);
4505  $formconfirm .= '</td>';
4506  $formconfirm .= '<td class="valid center"><input class="button valignmiddle confirmvalidatebutton" type="submit" value="'.$langs->trans("Validate").'"></td>';
4507  $formconfirm .= '</tr>'."\n";
4508 
4509  $formconfirm .= '</table>'."\n";
4510 
4511  if (empty($disableformtag)) $formconfirm .= "</form>\n";
4512  $formconfirm .= '<br>';
4513 
4514  if (empty($conf->use_javascript_ajax)) {
4515  $formconfirm .= '<!-- code to disable button to avoid double clic -->';
4516  $formconfirm .= '<script type="text/javascript">'."\n";
4517  $formconfirm .= '
4518  $(document).ready(function () {
4519  $(".confirmvalidatebutton").on("click", function() {
4520  console.log("We click on button");
4521  $(this).attr("disabled", "disabled");
4522  setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
4523  //console.log($(this).closest("form"));
4524  $(this).closest("form").submit();
4525  });
4526  });
4527  ';
4528  $formconfirm .= '</script>'."\n";
4529  }
4530 
4531  $formconfirm .= "<!-- end formconfirm -->\n";
4532  }
4533 
4534  return $formconfirm;
4535  }
4536 
4537 
4538  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4552  public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0)
4553  {
4554  // phpcs:enable
4555  global $langs;
4556 
4557  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
4558  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
4559 
4560  $out = '';
4561 
4562  $formproject = new FormProjets($this->db);
4563 
4564  $langs->load("project");
4565  if ($htmlname != "none")
4566  {
4567  $out .= "\n";
4568  $out .= '<form method="post" action="'.$page.'">';
4569  $out .= '<input type="hidden" name="action" value="classin">';
4570  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
4571  $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
4572  $out .= '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
4573  $out .= '</form>';
4574  } else {
4575  if ($selected)
4576  {
4577  $projet = new Project($this->db);
4578  $projet->fetch($selected);
4579  //print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
4580  $out .= $projet->getNomUrl(0, '', 1);
4581  } else {
4582  $out .= "&nbsp;";
4583  }
4584  }
4585 
4586  if (empty($nooutput))
4587  {
4588  print $out;
4589  return '';
4590  }
4591  return $out;
4592  }
4593 
4594  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4604  public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0)
4605  {
4606  // phpcs:enable
4607  global $langs;
4608  if ($htmlname != "none")
4609  {
4610  print '<form method="post" action="'.$page.'">';
4611  print '<input type="hidden" name="action" value="setconditions">';
4612  print '<input type="hidden" name="token" value="'.newToken().'">';
4613  $this->select_conditions_paiements($selected, $htmlname, -1, $addempty);
4614  print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
4615  print '</form>';
4616  } else {
4617  if ($selected)
4618  {
4620  print $this->cache_conditions_paiements[$selected]['label'];
4621  } else {
4622  print "&nbsp;";
4623  }
4624  }
4625  }
4626 
4627  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4637  public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
4638  {
4639  // phpcs:enable
4640  global $langs;
4641  if ($htmlname != "none")
4642  {
4643  print '<form method="post" action="'.$page.'">';
4644  print '<input type="hidden" name="action" value="setavailability">';
4645  print '<input type="hidden" name="token" value="'.newToken().'">';
4646  $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
4647  print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
4648  print '</form>';
4649  } else {
4650  if ($selected)
4651  {
4652  $this->load_cache_availability();
4653  print $this->cache_availability[$selected]['label'];
4654  } else {
4655  print "&nbsp;";
4656  }
4657  }
4658  }
4659 
4670  public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
4671  {
4672  global $langs;
4673  if ($htmlname != "none")
4674  {
4675  print '<form method="post" action="'.$page.'">';
4676  print '<input type="hidden" name="action" value="setdemandreason">';
4677  print '<input type="hidden" name="token" value="'.newToken().'">';
4678  $this->selectInputReason($selected, $htmlname, -1, $addempty);
4679  print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
4680  print '</form>';
4681  } else {
4682  if ($selected)
4683  {
4684  $this->loadCacheInputReason();
4685  foreach ($this->cache_demand_reason as $key => $val)
4686  {
4687  if ($val['id'] == $selected)
4688  {
4689  print $val['label'];
4690  break;
4691  }
4692  }
4693  } else {
4694  print "&nbsp;";
4695  }
4696  }
4697  }
4698 
4699  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4712  public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0)
4713  {
4714  // phpcs:enable
4715  global $langs;
4716 
4717  $ret = '';
4718 
4719  if ($htmlname != "none")
4720  {
4721  $ret .= '<form method="post" action="'.$page.'" name="form'.$htmlname.'">';
4722  $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
4723  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
4724  $ret .= '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4725  $ret .= '<tr><td>';
4726  $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
4727  $ret .= '</td>';
4728  $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
4729  $ret .= '</tr></table></form>';
4730  } else {
4731  if ($displayhour) $ret .= dol_print_date($selected, 'dayhour');
4732  else $ret .= dol_print_date($selected, 'day');
4733  }
4734 
4735  if (empty($nooutput)) print $ret;
4736  return $ret;
4737  }
4738 
4739 
4740  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4751  public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
4752  {
4753  // phpcs:enable
4754  global $langs;
4755 
4756  if ($htmlname != "none")
4757  {
4758  print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
4759  print '<input type="hidden" name="action" value="set'.$htmlname.'">';
4760  print '<input type="hidden" name="token" value="'.newToken().'">';
4761  print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
4762  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4763  print '</form>';
4764  } else {
4765  if ($selected)
4766  {
4767  require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
4768  $theuser = new User($this->db);
4769  $theuser->fetch($selected);
4770  print $theuser->getNomUrl(1);
4771  } else {
4772  print "&nbsp;";
4773  }
4774  }
4775  }
4776 
4777 
4778  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4790  public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0)
4791  {
4792  // phpcs:enable
4793  global $langs;
4794  if ($htmlname != "none")
4795  {
4796  print '<form method="POST" action="'.$page.'">';
4797  print '<input type="hidden" name="action" value="setmode">';
4798  print '<input type="hidden" name="token" value="'.newToken().'">';
4799  $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active);
4800  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4801  print '</form>';
4802  } else {
4803  if ($selected)
4804  {
4805  $this->load_cache_types_paiements();
4806  print $this->cache_types_paiements[$selected]['label'];
4807  } else {
4808  print "&nbsp;";
4809  }
4810  }
4811  }
4812 
4823  public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
4824  {
4825  global $langs;
4826  if ($htmlname != "none")
4827  {
4828  print '<form method="POST" action="'.$page.'">';
4829  print '<input type="hidden" name="action" value="setmode">';
4830  print '<input type="hidden" name="token" value="'.newToken().'">';
4831  $this->selectTransportMode($selected, $htmlname, 2, $addempty, 0, 0, $active);
4832  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4833  print '</form>';
4834  }
4835  else {
4836  if ($selected)
4837  {
4838  $this->load_cache_transport_mode();
4839  print $this->cache_transport_mode[$selected]['label'];
4840  } else {
4841  print "&nbsp;";
4842  }
4843  }
4844  }
4845 
4846  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4855  public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
4856  {
4857  // phpcs:enable
4858  global $langs;
4859  if ($htmlname != "none")
4860  {
4861  print '<form method="POST" action="'.$page.'">';
4862  print '<input type="hidden" name="action" value="setmulticurrencycode">';
4863  print '<input type="hidden" name="token" value="'.newToken().'">';
4864  print $this->selectMultiCurrency($selected, $htmlname, 0);
4865  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4866  print '</form>';
4867  } else {
4868  dol_include_once('/core/lib/company.lib.php');
4869  print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
4870  }
4871  }
4872 
4873  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4883  public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
4884  {
4885  // phpcs:enable
4886  global $langs, $mysoc, $conf;
4887 
4888  if ($htmlname != "none")
4889  {
4890  print '<form method="POST" action="'.$page.'">';
4891  print '<input type="hidden" name="action" value="setmulticurrencyrate">';
4892  print '<input type="hidden" name="token" value="'.newToken().'">';
4893  print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> ';
4894  print '<select name="calculation_mode">';
4895  print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>';
4896  print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>';
4897  print '</select> ';
4898  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4899  print '</form>';
4900  } else {
4901  if (!empty($rate))
4902  {
4903  print price($rate, 1, $langs, 1, 0);
4904  if ($currency && $rate != 1) print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
4905  } else {
4906  print 1;
4907  }
4908  }
4909  }
4910 
4911 
4912  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4928  public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
4929  {
4930  // phpcs:enable
4931  global $conf, $langs;
4932  if ($htmlname != "none")
4933  {
4934  print '<form method="post" action="'.$page.'">';
4935  print '<input type="hidden" name="action" value="setabsolutediscount">';
4936  print '<input type="hidden" name="token" value="'.newToken().'">';
4937  print '<div class="inline-block">';
4938  if (!empty($discount_type)) {
4939  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4940  {
4941  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
4942  else $translationKey = 'HasCreditNoteFromSupplier';
4943  } else {
4944  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") $translationKey = 'HasAbsoluteDiscountFromSupplier';
4945  else $translationKey = 'HasCreditNoteFromSupplier';
4946  }
4947  } else {
4948  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4949  {
4950  if (!$filter || $filter == "fk_facture_source IS NULL") $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
4951  else $translationKey = 'CompanyHasCreditNote';
4952  } else {
4953  if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") $translationKey = 'CompanyHasAbsoluteDiscount';
4954  else $translationKey = 'CompanyHasCreditNote';
4955  }
4956  }
4957  print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
4958  if (empty($hidelist)) print ': ';
4959  print '</div>';
4960  if (empty($hidelist))
4961  {
4962  print '<div class="inline-block" style="padding-right: 10px">';
4963  $newfilter = 'discount_type='.intval($discount_type);
4964  if (!empty($discount_type)) {
4965  $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
4966  } else {
4967  $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
4968  }
4969  if ($filter) $newfilter .= ' AND ('.$filter.')';
4970  $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
4971  if ($nbqualifiedlines > 0)
4972  {
4973  print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
4974  if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')")
4975  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4976  if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')")
4977  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4978 
4979  print '>';
4980  }
4981  print '</div>';
4982  }
4983  if ($more)
4984  {
4985  print '<div class="inline-block">';
4986  print $more;
4987  print '</div>';
4988  }
4989  print '</form>';
4990  } else {
4991  if ($selected)
4992  {
4993  print $selected;
4994  } else {
4995  print "0";
4996  }
4997  }
4998  }
4999 
5000 
5001  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5011  public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
5012  {
5013  // phpcs:enable
5014  global $langs, $conf;
5015 
5016  if ($htmlname != "none")
5017  {
5018  print '<form method="post" action="'.$page.'">';
5019  print '<input type="hidden" name="action" value="set_contact">';
5020  print '<input type="hidden" name="token" value="'.newToken().'">';
5021  print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
5022  print '<tr><td>';
5023  print $this->selectcontacts($societe->id, $selected, $htmlname);
5024  $num = $this->num;
5025  if ($num == 0)
5026  {
5027  $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
5028  print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
5029  }
5030  print '</td>';
5031  print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5032  print '</tr></table></form>';
5033  } else {
5034  if ($selected)
5035  {
5036  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
5037  $contact = new Contact($this->db);
5038  $contact->fetch($selected);
5039  print $contact->getFullName($langs);
5040  } else {
5041  print "&nbsp;";
5042  }
5043  }
5044  }
5045 
5046  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5061  public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0)
5062  {
5063  // phpcs:enable
5064  global $langs;
5065 
5066  $out = '';
5067  if ($htmlname != "none")
5068  {
5069  $out .= '<form method="post" action="'.$page.'">';
5070  $out .= '<input type="hidden" name="action" value="set_thirdparty">';
5071  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5072  $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events);
5073  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5074  $out .= '</form>';
5075  } else {
5076  if ($selected)
5077  {
5078  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
5079  $soc = new Societe($this->db);
5080  $soc->fetch($selected);
5081  $out .= $soc->getNomUrl($langs);
5082  } else {
5083  $out .= "&nbsp;";
5084  }
5085  }
5086 
5087  if ($nooutput) return $out;
5088  else print $out;
5089  }
5090 
5091  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5100  public function select_currency($selected = '', $htmlname = 'currency_id')
5101  {
5102  // phpcs:enable
5103  print $this->selectCurrency($selected, $htmlname);
5104  }
5105 
5114  public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0)
5115  {
5116  global $conf, $langs, $user;
5117 
5118  $langs->loadCacheCurrencies('');
5119 
5120  $out = '';
5121 
5122  if ($selected == 'euro' || $selected == 'euros') $selected = 'EUR'; // Pour compatibilite
5123 
5124  $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
5125  foreach ($langs->cache_currencies as $code_iso => $currency)
5126  {
5127  $labeltoshow = $currency['label'];
5128  if ($mode == 1)
5129  {
5130  $labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>';
5131  } else {
5132  $labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>';
5133  }
5134 
5135  if ($selected && $selected == $code_iso)
5136  {
5137  $out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
5138  } else {
5139  $out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
5140  }
5141  $out .= $labeltoshow;
5142  $out .= '</option>';
5143  }
5144  $out .= '</select>';
5145  if ($user->admin) $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5146 
5147  // Make select dynamic
5148  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5149  $out .= ajax_combobox($htmlname);
5150 
5151  return $out;
5152  }
5153 
5164  public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false)
5165  {
5166  global $db, $conf, $langs, $user;
5167 
5168  $langs->loadCacheCurrencies(''); // Load ->cache_currencies
5169 
5170  $TCurrency = array();
5171 
5172  $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
5173  $sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
5174  if ($filter) $sql .= " AND ".$filter;
5175  $resql = $this->db->query($sql);
5176  if ($resql)
5177  {
5178  while ($obj = $this->db->fetch_object($resql)) $TCurrency[$obj->code] = $obj->code;
5179  }
5180 
5181  $out = '';
5182  $out .= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
5183  if ($useempty) $out .= '<option value="">&nbsp;</option>';
5184  // If company current currency not in table, we add it into list. Should always be available.
5185  if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency)
5186  {
5187  $TCurrency[$conf->currency] = $conf->currency;
5188  }
5189  if (count($TCurrency) > 0)
5190  {
5191  foreach ($langs->cache_currencies as $code_iso => $currency)
5192  {
5193  if (isset($TCurrency[$code_iso]))
5194  {
5195  if (!empty($selected) && $selected == $code_iso) $out .= '<option value="'.$code_iso.'" selected="selected">';
5196  else $out .= '<option value="'.$code_iso.'">';
5197 
5198  $out .= $currency['label'];
5199  $out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5200  $out .= '</option>';
5201  }
5202  }
5203  }
5204 
5205  $out .= '</select>';
5206  // Make select dynamic
5207  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5208  $out .= ajax_combobox($htmlname);
5209 
5210  return $out;
5211  }
5212 
5213  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5220  public function load_cache_vatrates($country_code)
5221  {
5222  // phpcs:enable
5223  global $langs;
5224 
5225  $num = count($this->cache_vatrates);
5226  if ($num > 0) return $num; // Cache already loaded
5227 
5228  dol_syslog(__METHOD__, LOG_DEBUG);
5229 
5230  $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
5231  $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
5232  $sql .= " WHERE t.fk_pays = c.rowid";
5233  $sql .= " AND t.active > 0";
5234  $sql .= " AND c.code IN (".$country_code.")";
5235  $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
5236 
5237  $resql = $this->db->query($sql);
5238  if ($resql)
5239  {
5240  $num = $this->db->num_rows($resql);
5241  if ($num)
5242  {
5243  for ($i = 0; $i < $num; $i++)
5244  {
5245  $obj = $this->db->fetch_object($resql);
5246  $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
5247  $this->cache_vatrates[$i]['code'] = $obj->code;
5248  $this->cache_vatrates[$i]['txtva'] = $obj->taux;
5249  $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
5250  $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
5251  $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
5252  $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
5253  $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
5254 
5255  $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
5256  $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
5257  $positiverates = '';
5258  if ($obj->taux) $positiverates .= ($positiverates ? '/' : '').$obj->taux;
5259  if ($obj->localtax1) $positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
5260  if ($obj->localtax2) $positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
5261  if (empty($positiverates)) $positiverates = '0';
5262  $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
5263  }
5264 
5265  return $num;
5266  } else {
5267  $this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</font>';
5268  return -1;
5269  }
5270  } else {
5271  $this->error = '<font class="error">'.$this->db->error().'</font>';
5272  return -2;
5273  }
5274  }
5275 
5276  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5298  public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
5299  {
5300  // phpcs:enable
5301  global $langs, $conf, $mysoc;
5302 
5303  $langs->load('errors');
5304 
5305  $return = '';
5306 
5307  // Define defaultnpr, defaultttx and defaultcode
5308  $defaultnpr = ($info_bits & 0x01);
5309  $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
5310  $defaulttx = str_replace('*', '', $selectedrate);
5311  $defaultcode = '';
5312  if (preg_match('/\((.*)\)/', $defaulttx, $reg))
5313  {
5314  $defaultcode = $reg[1];
5315  $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5316  }
5317  //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
5318 
5319  // Check parameters
5320  if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code)
5321  {
5322  if ($societe_vendeuse->id == $mysoc->id)
5323  {
5324  $return .= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</font>';
5325  } else {
5326  $return .= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</font>';
5327  }
5328  return $return;
5329  }
5330 
5331  //var_dump($societe_acheteuse);
5332  //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";
5333  //exit;
5334 
5335  // Define list of countries to use to search VAT rates to show
5336  // First we defined code_country to use to find list
5337  if (is_object($societe_vendeuse))
5338  {
5339  $code_country = "'".$societe_vendeuse->country_code."'";
5340  } else {
5341  $code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
5342  }
5343  if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) // If option to have vat for end customer for services is on
5344  {
5345  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
5346  if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany())))
5347  {
5348  // We also add the buyer
5349  if (is_numeric($type))
5350  {
5351  if ($type == 1) // We know product is a service
5352  {
5353  $code_country .= ",'".$societe_acheteuse->country_code."'";
5354  }
5355  } elseif (!$idprod) // We don't know type of product
5356  {
5357  $code_country .= ",'".$societe_acheteuse->country_code."'";
5358  } else {
5359  $prodstatic = new Product($this->db);
5360  $prodstatic->fetch($idprod);
5361  if ($prodstatic->type == Product::TYPE_SERVICE) // We know product is a service
5362  {
5363  $code_country .= ",'".$societe_acheteuse->country_code."'";
5364  }
5365  }
5366  }
5367  }
5368 
5369  // Now we get list
5370  $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
5371 
5372  if ($num > 0)
5373  {
5374  // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
5375  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
5376  {
5377  $tmpthirdparty = new Societe($this->db);
5378  $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5379  $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5380  if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
5381  $defaultcode = $reg[1];
5382  $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5383  }
5384  if (empty($defaulttx)) $defaultnpr = 0;
5385  }
5386 
5387  // Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
5388  // Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
5389  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
5390  {
5391  if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
5392  else $defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
5393  }
5394 
5395  // Disabled if seller is not subject to VAT
5396  $disabled = false; $title = '';
5397  if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0")
5398  {
5399  // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
5400  // of using supplier invoices (this is a very bad idea !)
5401  if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT))
5402  {
5403  $title = ' title="'.$langs->trans('VATIsNotUsed').'"';
5404  $disabled = true;
5405  }
5406  }
5407 
5408  if (!$options_only) $return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
5409 
5410  $selectedfound = false;
5411  foreach ($this->cache_vatrates as $rate)
5412  {
5413  // Keep only 0 if seller is not subject to VAT
5414  if ($disabled && $rate['txtva'] != 0) continue;
5415 
5416  // Define key to use into select list
5417  $key = $rate['txtva'];
5418  $key .= $rate['nprtva'] ? '*' : '';
5419  if ($mode > 0 && $rate['code']) $key .= ' ('.$rate['code'].')';
5420  if ($mode < 0) $key = $rate['rowid'];
5421 
5422  $return .= '<option value="'.$key.'"';
5423  if (!$selectedfound)
5424  {
5425  if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
5426  {
5427  if ($defaultcode == $rate['code'])
5428  {
5429  $return .= ' selected';
5430  $selectedfound = true;
5431  }
5432  } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
5433  {
5434  $return .= ' selected';
5435  $selectedfound = true;
5436  }
5437  }
5438  $return .= '>';
5439  //if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
5440  if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES))
5441  {
5442  $return .= $rate['labelpositiverates'];
5443  } else {
5444  $return .= vatrate($rate['label']);
5445  }
5446  //$return.=($rate['code']?' '.$rate['code']:'');
5447  $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
5448 
5449  $return .= '</option>';
5450  }
5451 
5452  if (!$options_only) $return .= '</select>';
5453  } else {
5454  $return .= $this->error;
5455  }
5456 
5457  $this->num = $num;
5458  return $return;
5459  }
5460 
5461 
5462  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5487  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 = '')
5488  {
5489  // phpcs:enable
5490  $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
5491  if (!empty($nooutput)) {
5492  return $retstring;
5493  }
5494  print $retstring;
5495  return;
5496  }
5497 
5512  public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0)
5513  {
5514  global $langs;
5515 
5516  $ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
5517  $ret .= '<br>';
5518  $ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
5519  return $ret;
5520  }
5521 
5549  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')
5550  {
5551  global $conf, $langs;
5552 
5553  if ($gm === 'auto') {
5554  $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
5555  }
5556 
5557  $retstring = '';
5558 
5559  if ($prefix == '') $prefix = 're';
5560  if ($h == '') $h = 0;
5561  if ($m == '') $m = 0;
5562  $emptydate = 0;
5563  $emptyhours = 0;
5564  if ($stepminutes <= 0 || $stepminutes > 30) $stepminutes = 1;
5565  if ($empty == 1) { $emptydate = 1; $emptyhours = 1; }
5566  if ($empty == 2) { $emptydate = 0; $emptyhours = 1; }
5567  $orig_set_time = $set_time;
5568 
5569  if ($set_time === '' && $emptydate == 0)
5570  {
5571  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5572  if ($gm == 'tzuser' || $gm == 'tzuserrel') {
5573  $set_time = dol_now($gm);
5574  } else {
5575  $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
5576  }
5577  }
5578 
5579  // Analysis of the pre-selection date
5580  $reg = array();
5581  if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) // deprecated usage
5582  {
5583  // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
5584  $syear = (!empty($reg[1]) ? $reg[1] : '');
5585  $smonth = (!empty($reg[2]) ? $reg[2] : '');
5586  $sday = (!empty($reg[3]) ? $reg[3] : '');
5587  $shour = (!empty($reg[4]) ? $reg[4] : '');
5588  $smin = (!empty($reg[5]) ? $reg[5] : '');
5589  } elseif (strval($set_time) != '' && $set_time != -1)
5590  {
5591  // set_time est un timestamps (0 possible)
5592  $syear = dol_print_date($set_time, "%Y", $gm);
5593  $smonth = dol_print_date($set_time, "%m", $gm);
5594  $sday = dol_print_date($set_time, "%d", $gm);
5595  if ($orig_set_time != '')
5596  {
5597  $shour = dol_print_date($set_time, "%H", $gm);
5598  $smin = dol_print_date($set_time, "%M", $gm);
5599  $ssec = dol_print_date($set_time, "%S", $gm);
5600  } else {
5601  $shour = '';
5602  $smin = '';
5603  $ssec = '';
5604  }
5605  } else {
5606  // Date est '' ou vaut -1
5607  $syear = '';
5608  $smonth = '';
5609  $sday = '';
5610  $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
5611  $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
5612  $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
5613  }
5614  if ($h == 3) $shour = '';
5615  if ($m == 3) $smin = '';
5616 
5617  $nowgmt = dol_now('gmt');
5618  //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
5619 
5620  // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
5621  $usecalendar = 'combo';
5622  if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
5623  $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
5624  }
5625 
5626  if ($d)
5627  {
5628  // Show date with popup
5629  if ($usecalendar != 'combo')
5630  {
5631  $formated_date = '';
5632  //print "e".$set_time." t ".$conf->format_date_short;
5633  if (strval($set_time) != '' && $set_time != -1)
5634  {
5635  //$formated_date=dol_print_date($set_time,$conf->format_date_short);
5636  $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5637  }
5638 
5639  // Calendrier popup version eldy
5640  if ($usecalendar == "eldy")
5641  {
5642  // Input area to enter date manually
5643  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
5644  $retstring .= ($disabled ? ' disabled' : '');
5645  $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5646  $retstring .= '>';
5647 
5648  // Icon calendar
5649  if (!$disabled)
5650  {
5651  $retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
5652  $base = DOL_URL_ROOT.'/core/';
5653  $retstring .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
5654  $retstring .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
5655  } else $retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
5656 
5657  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
5658  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5659  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
5660  } elseif ($usecalendar == 'jquery')
5661  {
5662  if (!$disabled)
5663  {
5664  // Output javascript for datepicker
5665  $retstring .= "<script type='text/javascript'>";
5666  $retstring .= "$(function(){ $('#".$prefix."').datepicker({
5667  dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
5668  autoclose: true,
5669  todayHighlight: true,";
5670  if (!empty($conf->dol_use_jmobile))
5671  {
5672  $retstring .= "
5673  beforeShow: function (input, datePicker) {
5674  input.disabled = true;
5675  },
5676  onClose: function (dateText, datePicker) {
5677  this.disabled = false;
5678  },
5679  ";
5680  }
5681  // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
5682  if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS))
5683  {
5684  $retstring .= "
5685  showOn: 'button',
5686  buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png',
5687  buttonImageOnly: true";
5688  }
5689  $retstring .= "
5690  }) });";
5691  $retstring .= "</script>";
5692  }
5693 
5694  // Zone de saisie manuelle de la date
5695  $retstring .= '<div class="nowrap inline-block">';
5696  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
5697  $retstring .= ($disabled ? ' disabled' : '');
5698  $retstring .= ($placeholder ? ' placeholder="'.$placeholder.'"' : '');
5699  $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5700  $retstring .= '>';
5701 
5702  // Icone calendrier
5703  if (!$disabled)
5704  {
5705  /* Not required. Managed by option buttonImage of jquery
5706  $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
5707  $retstring.="<script type='text/javascript'>";
5708  $retstring.="jQuery(document).ready(function() {";
5709  $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
5710  $retstring.=" jQuery('#".$prefix."').focus();";
5711  $retstring.=' });';
5712  $retstring.='});';
5713  $retstring.="</script>";*/
5714  } else {
5715  $retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
5716  }
5717 
5718  $retstring .= '</div>';
5719  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
5720  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5721  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
5722  } else {
5723  $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
5724  }
5725  }
5726  // Show date with combo selects
5727  else {
5728  // Day
5729  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
5730 
5731  if ($emptydate || $set_time == -1)
5732  {
5733  $retstring .= '<option value="0" selected>&nbsp;</option>';
5734  }
5735 
5736  for ($day = 1; $day <= 31; $day++)
5737  {
5738  $retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
5739  }
5740 
5741  $retstring .= "</select>";
5742 
5743  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
5744  if ($emptydate || $set_time == -1)
5745  {
5746  $retstring .= '<option value="0" selected>&nbsp;</option>';
5747  }
5748 
5749  // Month
5750  for ($month = 1; $month <= 12; $month++)
5751  {
5752  $retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
5753  $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
5754  $retstring .= "</option>";
5755  }
5756  $retstring .= "</select>";
5757 
5758  // Year
5759  if ($emptydate || $set_time == -1)
5760  {
5761  $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.'">';
5762  } else {
5763  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
5764 
5765  for ($year = $syear - 10; $year < $syear + 10; $year++)
5766  {
5767  $retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
5768  }
5769  $retstring .= "</select>\n";
5770  }
5771  }
5772  }
5773 
5774  if ($d && $h) {
5775  $retstring .= ($h == 2 ? '<br>' : ' ');
5776  $retstring .= '<span class="nowraponall">';
5777  }
5778 
5779  if ($h)
5780  {
5781  $hourstart = 0;
5782  $hourend = 24;
5783  if ($openinghours != '') {
5784  $openinghours = explode(',', $openinghours);
5785  $hourstart = $openinghours[0];
5786  $hourend = $openinghours[1];
5787  if ($hourend < $hourstart) $hourend = $hourstart;
5788  }
5789  // Show hour
5790  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
5791  if ($emptyhours) $retstring .= '<option value="-1">&nbsp;</option>';
5792  for ($hour = $hourstart; $hour < $hourend; $hour++)
5793  {
5794  if (strlen($hour) < 2) $hour = "0".$hour;
5795  $retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour;
5796  //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
5797  $retstring .= '</option>';
5798  }
5799  $retstring .= '</select>';
5800  //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
5801  if ($m) $retstring .= ":";
5802  }
5803 
5804  if ($m)
5805  {
5806  // Show minutes
5807  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
5808  if ($emptyhours) $retstring .= '<option value="-1">&nbsp;</option>';
5809  for ($min = 0; $min < 60; $min += $stepminutes)
5810  {
5811  if (strlen($min) < 2) $min = "0".$min;
5812  $retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
5813  }
5814  $retstring .= '</select>';
5815 
5816  $retstring .= '<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
5817  }
5818 
5819  if ($d && $h) {
5820  $retstring .= '</span>';
5821  }
5822 
5823  // Add a "Now" link
5824  if ($conf->use_javascript_ajax && $addnowlink)
5825  {
5826  // Script which will be inserted in the onClick of the "Now" link
5827  $reset_scripts = "";
5828  if ($addnowlink == 2) { // local computer time
5829  // pad add leading 0 on numbers
5830  $reset_scripts .= "Number.prototype.pad = function(size) {
5831  var s = String(this);
5832  while (s.length < (size || 2)) {s = '0' + s;}
5833  return s;
5834  };
5835  var d = new Date();";
5836  }
5837 
5838  // Generate the date part, depending on the use or not of the javascript calendar
5839  if ($addnowlink == 1) { // server time expressed in user time setup
5840  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
5841  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
5842  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
5843  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
5844  } elseif ($addnowlink == 2) {
5845  /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
5846  * This break application for foreign languages.
5847  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
5848  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
5849  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
5850  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
5851  */
5852  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
5853  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
5854  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
5855  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
5856  }
5857  /*if ($usecalendar == "eldy")
5858  {
5859  $base=DOL_URL_ROOT.'/core/';
5860  $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
5861  }
5862  else
5863  {
5864  $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
5865  $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
5866  $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
5867  }*/
5868  // Update the hour part
5869  if ($h)
5870  {
5871  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5872  //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
5873  if ($addnowlink == 1)
5874  {
5875  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
5876  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
5877  } elseif ($addnowlink == 2)
5878  {
5879  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
5880  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
5881  }
5882 
5883  if ($fullday) $reset_scripts .= ' } ';
5884  }
5885  // Update the minute part
5886  if ($m)
5887  {
5888  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5889  //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
5890  if ($addnowlink == 1)
5891  {
5892  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
5893  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
5894  } elseif ($addnowlink == 2)
5895  {
5896  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
5897  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
5898  }
5899  if ($fullday) $reset_scripts .= ' } ';
5900  }
5901  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5902  if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5903  {
5904  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
5905  $retstring .= $langs->trans("Now");
5906  $retstring .= '</button> ';
5907  }
5908  }
5909 
5910  // Add a "Plus one hour" link
5911  if ($conf->use_javascript_ajax && $addplusone)
5912  {
5913  // Script which will be inserted in the onClick of the "Add plusone" link
5914  $reset_scripts = "";
5915 
5916  // Generate the date part, depending on the use or not of the javascript calendar
5917  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');';
5918  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
5919  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
5920  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
5921  // Update the hour part
5922  if ($h)
5923  {
5924  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5925  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
5926  if ($fullday) $reset_scripts .= ' } ';
5927  }
5928  // Update the minute part
5929  if ($m)
5930  {
5931  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5932  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
5933  if ($fullday) $reset_scripts .= ' } ';
5934  }
5935  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5936  if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5937  {
5938  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
5939  $retstring .= $langs->trans("DateStartPlusOne");
5940  $retstring .= '</button> ';
5941  }
5942  }
5943 
5944  // Add a link to set data
5945  if ($conf->use_javascript_ajax && $adddateof)
5946  {
5947  $tmparray = dol_getdate($adddateof);
5948  if (empty($labeladddateof)) $labeladddateof = $langs->trans("DateInvoice");
5949  $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="console.log(\'Click on now link\'); jQuery(\'#re\').val(\''.dol_print_date($adddateof, 'dayinputnoreduce').'\');jQuery(\'#reday\').val(\''.$tmparray['mday'].'\');jQuery(\'#remonth\').val(\''.$tmparray['mon'].'\');jQuery(\'#reyear\').val(\''.$tmparray['year'].'\');">'.$labeladddateof.'</a>';
5950  }
5951 
5952  return $retstring;
5953  }
5954 
5963  public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
5964  {
5965  global $langs;
5966 
5967  $TDurationTypes = array(
5968  'y'=>$langs->trans('Years'),
5969  'm'=>$langs->trans('Month'),
5970  'w'=>$langs->trans('Weeks'),
5971  'd'=>$langs->trans('Days'),
5972  'h'=>$langs->trans('Hours'),
5973  'i'=>$langs->trans('Minutes')
5974  );
5975 
5976  // Removed undesired duration types
5977  foreach ($excludetypes as $value) {
5978  unset($TDurationTypes[$value]);
5979  }
5980 
5981  $retstring = '<select class="flat" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
5982  foreach ($TDurationTypes as $key => $typeduration) {
5983  $retstring .= '<option value="'.$key.'"';
5984  if ($key == $selected) {
5985  $retstring .= " selected";
5986  }
5987  $retstring .= ">".$typeduration."</option>";
5988  }
5989  $retstring .= "</select>";
5990 
5991  $retstring .= ajax_combobox('select_'.$prefix.'type_duration');
5992 
5993  return $retstring;
5994  }
5995 
5996  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6010  public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
6011  {
6012  // phpcs:enable
6013  global $langs;
6014 
6015  $retstring = '';
6016 
6017  $hourSelected = 0; $minSelected = 0;
6018 
6019  // Hours
6020  if ($iSecond != '')
6021  {
6022  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6023 
6024  $hourSelected = convertSecondToTime($iSecond, 'allhour');
6025  $minSelected = convertSecondToTime($iSecond, 'min');
6026  }
6027 
6028  if ($typehour == 'select') {
6029  $retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
6030  for ($hour = 0; $hour < 25; $hour++) // For a duration, we allow 24 hours
6031  {
6032  $retstring .= '<option value="'.$hour.'"';
6033  if ($hourSelected == $hour)
6034  {
6035  $retstring .= " selected";
6036  }
6037  $retstring .= ">".$hour."</option>";
6038  }
6039  $retstring .= "</select>";
6040  } elseif ($typehour == 'text' || $typehour == 'textselect') {
6041  $retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
6042  } else {
6043  return 'BadValueForParameterTypeHour';
6044  }
6045 
6046  if ($typehour != 'text') $retstring .= ' '.$langs->trans('HourShort');
6047  else $retstring .= '<span class="hideonsmartphone">:</span>';
6048 
6049  // Minutes
6050  if ($minunderhours) $retstring .= '<br>';
6051  else $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
6052 
6053  if ($typehour == 'select' || $typehour == 'textselect')
6054  {
6055  $retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
6056  for ($min = 0; $min <= 55; $min = $min + 5)
6057  {
6058  $retstring .= '<option value="'.$min.'"';
6059  if ($minSelected == $min) $retstring .= ' selected';
6060  $retstring .= '>'.$min.'</option>';
6061  }
6062  $retstring .= "</select>";
6063  } elseif ($typehour == 'text')
6064  {
6065  $retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
6066  }
6067 
6068  if ($typehour != 'text') $retstring .= ' '.$langs->trans('MinuteShort');
6069 
6070  //$retstring.="&nbsp;";
6071 
6072  if (!empty($nooutput)) return $retstring;
6073 
6074  print $retstring;
6075  return;
6076  }
6077 
6078 
6098  public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
6099  {
6100  global $conf, $user;
6101 
6102  $objecttmp = null;
6103 
6104  $InfoFieldList = explode(":", $objectdesc);
6105  $classname = $InfoFieldList[0];
6106  $classpath = $InfoFieldList[1];
6107  $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
6108  $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
6109 
6110  if (!empty($classpath))
6111  {
6112  dol_include_once($classpath);
6113 
6114  if ($classname && class_exists($classname))
6115  {
6116  $objecttmp = new $classname($this->db);
6117  // Make some replacement
6118  $sharedentities = getEntity(strtolower($classname));
6119  $objecttmp->filter = str_replace(
6120  array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
6121  array($conf->entity, $sharedentities, $user->id),
6122  $filter);
6123  }
6124  }
6125  if (!is_object($objecttmp))
6126  {
6127  dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
6128  return 'Error bad setup of type for field '.join(',', $InfoFieldList);
6129  }
6130 
6131  //var_dump($objecttmp->filter);
6132  $prefixforautocompletemode = $objecttmp->element;
6133  if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode = 'company';
6134  if ($prefixforautocompletemode == 'product') $prefixforautocompletemode = 'produit';
6135  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
6136 
6137  dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG);
6138  $out = '';
6139  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo)
6140  {
6141  // No immediate load of all database
6142  $placeholder = '';
6143  if ($preselectedvalue && empty($selected_input_value))
6144  {
6145  $objecttmp->fetch($preselectedvalue);
6146  $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
6147  //unset($objecttmp);
6148  }
6149 
6150  $objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
6151  $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
6152 
6153  // No immediate load of all database
6154  $urloption = 'htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.'&filter='.urlencode($objecttmp->filter);
6155  // Activate the auto complete using ajax call.
6156  $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
6157  $out .= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
6158  if ($placeholder) $placeholder = ' placeholder="'.$placeholder.'"';
6159  $out .= '<input type="text" class="'.$morecss.'"'.($disabled ? ' disabled="disabled"' : '').' name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' />';
6160  } else {
6161  // Immediate load of table record. Note: filter is inside $objecttmp->filter
6162  $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled);
6163  }
6164 
6165  return $out;
6166  }
6167 
6174  protected static function forgeCriteriaCallback($matches)
6175  {
6176  global $db;
6177 
6178  //dol_syslog("Convert matches ".$matches[1]);
6179  if (empty($matches[1])) return '';
6180  $tmp = explode(':', $matches[1]);
6181  if (count($tmp) < 3) return '';
6182 
6183  $tmpescaped = $tmp[2];
6184  $regbis = array();
6185  if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis))
6186  {
6187  $tmpescaped = "'".$db->escape($regbis[1])."'";
6188  } else {
6189  $tmpescaped = $db->escape($tmpescaped);
6190  }
6191  return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
6192  }
6193 
6212  public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0)
6213  {
6214  global $conf, $langs, $user;
6215 
6216  //print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled";
6217 
6218  $prefixforautocompletemode = $objecttmp->element;
6219  if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode = 'company';
6220  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
6221 
6222  if (!empty($objecttmp->fields)) // For object that declare it, it is better to use declared fields (like societe, contact, ...)
6223  {
6224  $tmpfieldstoshow = '';
6225  foreach ($objecttmp->fields as $key => $val)
6226  {
6227  if (!dol_eval($val['enabled'], 1, 1)) continue;
6228  if ($val['showoncombobox']) $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
6229  }
6230  if ($tmpfieldstoshow) $fieldstoshow = $tmpfieldstoshow;
6231  } else {
6232  // For backward compatibility
6233  $objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
6234  }
6235 
6236  if (empty($fieldstoshow))
6237  {
6238  if (isset($objecttmp->fields['ref'])) {
6239  $fieldstoshow = 't.ref';
6240  } else {
6241  $langs->load("errors");
6242  $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
6243  return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
6244  }
6245  }
6246 
6247  $out = '';
6248  $outarray = array();
6249 
6250  $num = 0;
6251 
6252  // Search data
6253  $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX.$objecttmp->table_element." as t";
6254  if (isset($objecttmp->ismultientitymanaged) && !is_numeric($objecttmp->ismultientitymanaged)) {
6255  $tmparray = explode('@', $objecttmp->ismultientitymanaged);
6256  $sql .= ' INNER JOIN '.MAIN_DB_PREFIX.$tmparray[1].' as parenttable ON parenttable.rowid = t.'.$tmparray[0];
6257  }
6258  if ($objecttmp->ismultientitymanaged == 'fk_soc@societe')
6259  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
6260  $sql .= " WHERE 1=1";
6261  if (isset($objecttmp->ismultientitymanaged) && $objecttmp->ismultientitymanaged == 1) $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
6262  if (isset($objecttmp->ismultientitymanaged) && !is_numeric($objecttmp->ismultientitymanaged)) {
6263  $sql .= ' AND parenttable.entity = t.'.$tmparray[0];
6264  }
6265  if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
6266  if ($objecttmp->element == 'societe') $sql .= " AND t.rowid = ".$user->socid;
6267  else $sql .= " AND t.fk_soc = ".$user->socid;
6268  }
6269  if ($searchkey != '') $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
6270  if ($objecttmp->ismultientitymanaged == 'fk_soc@societe') {
6271  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
6272  }
6273  if ($objecttmp->filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
6274  /*if (! DolibarrApi::_checkFilters($objecttmp->filter))
6275  {
6276  throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter);
6277  }*/
6278  $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
6279  $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")";
6280  }
6281  $sql .= $this->db->order($fieldstoshow, "ASC");
6282  //$sql.=$this->db->plimit($limit, 0);
6283  //print $sql;
6284 
6285  // Build output string
6286  $resql = $this->db->query($sql);
6287  if ($resql)
6288  {
6289  // Construct $out and $outarray
6290  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
6291 
6292  // 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
6293  $textifempty = '&nbsp;';
6294 
6295  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
6296  if (!empty($conf->global->$confkeyforautocompletemode))
6297  {
6298  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6299  else $textifempty .= $langs->trans("All");
6300  }
6301  if ($showempty) $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
6302 
6303  $num = $this->db->num_rows($resql);
6304  $i = 0;
6305  if ($num)
6306  {
6307  while ($i < $num)
6308  {
6309  $obj = $this->db->fetch_object($resql);
6310  $label = '';
6311  $tmparray = explode(',', $fieldstoshow);
6312  foreach ($tmparray as $key => $val)
6313  {
6314  $val = preg_replace('/t\./', '', $val);
6315  $label .= (($label && $obj->$val) ? ' - ' : '').$obj->$val;
6316  }
6317  if (empty($outputmode))
6318  {
6319  if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
6320  $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
6321  } else {
6322  $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
6323  }
6324  } else {
6325  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
6326  }
6327 
6328  $i++;
6329  if (($i % 10) == 0) $out .= "\n";
6330  }
6331  }
6332 
6333  $out .= '</select>'."\n";
6334 
6335  if (!$forcecombo) {
6336  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6337  $out .= ajax_combobox($htmlname, null, $conf->global->$confkeyforautocompletemode);
6338  }
6339  } else {
6340  dol_print_error($this->db);
6341  }
6342 
6343  $this->result = array('nbofelement'=>$num);
6344 
6345  if ($outputmode) return $outarray;
6346  return $out;
6347  }
6348 
6349 
6373  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 = 0, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
6374  {
6375  global $conf, $langs;
6376 
6377  // Do we want a multiselect ?
6378  //$jsbeautify = 0;
6379  //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
6380  $jsbeautify = 1;
6381 
6382  if ($value_as_key) $array = array_combine($array, $array);
6383 
6384  $out = '';
6385 
6386  // Add code for jquery to use multiselect
6387  if ($addjscombo && $jsbeautify)
6388  {
6389  $minLengthToAutocomplete = 0;
6390  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ? (constant('REQUIRE_JQUERY_MULTISELECT') ?constant('REQUIRE_JQUERY_MULTISELECT') : 'select2') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
6391 
6392  // Enhance with select2
6393  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6394  $out .= ajax_combobox($htmlname);
6395  }
6396 
6397  $out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
6398  $out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
6399  $out .= '>';
6400 
6401  if ($show_empty)
6402  {
6403  $textforempty = ' ';
6404  if (!empty($conf->use_javascript_ajax)) $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
6405  if (!is_numeric($show_empty)) $textforempty = $show_empty;
6406  $out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
6407  }
6408 
6409  if (is_array($array))
6410  {
6411  // Translate
6412  if ($translate)
6413  {
6414  foreach ($array as $key => $value)
6415  {
6416  if (!is_array($value)) $array[$key] = $langs->trans($value);
6417  else $array[$key]['label'] = $langs->trans($value['label']);
6418  }
6419  }
6420 
6421  // Sort
6422  if ($sort == 'ASC') asort($array);
6423  elseif ($sort == 'DESC') arsort($array);
6424 
6425  foreach ($array as $key => $tmpvalue)
6426  {
6427  if (is_array($tmpvalue)) {
6428  $value = $tmpvalue['label'];
6429  $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
6430  $style = empty($tmpvalue['css']) ? ' class="'.$tmpvalue['css'].'"' : '';
6431  } else {
6432  $value = $tmpvalue;
6433  $disabled = ''; $style = '';
6434  }
6435  if (!empty($disablebademail)) {
6436  if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
6437  || ($disablebademail == 2 && preg_match('/---/', $value)))
6438  {
6439  $disabled = ' disabled';
6440  $style = ' class="warning"';
6441  }
6442  }
6443 
6444  if ($key_in_label) {
6445  if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
6446  else $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
6447  } else {
6448  if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
6449  else $selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value;
6450  if ($value == '' || $value == '-') $selectOptionValue = '&nbsp;';
6451  }
6452 
6453  $out .= '<option value="'.$key.'"';
6454  $out .= $style.$disabled;
6455  if (is_array($id)) {
6456  if (in_array($key, $id) && !$disabled) $out .= ' selected'; // To preselect a value
6457  } else {
6458  $id = (string) $id; // if $id = 0, then $id = '0'
6459  if ($id != '' && $id == $key && !$disabled) $out .= ' selected'; // To preselect a value
6460  }
6461  if ($nohtmlescape) $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
6462  if (is_array($tmpvalue))
6463  {
6464  foreach ($tmpvalue as $keyforvalue => $valueforvalue)
6465  {
6466  if (preg_match('/^data-/', $keyforvalue)) $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
6467  }
6468  }
6469  $out .= '>';
6470  //var_dump($selectOptionValue);
6471  $out .= $selectOptionValue;
6472  $out .= "</option>\n";
6473  }
6474  }
6475 
6476  $out .= "</select>";
6477  return $out;
6478  }
6479 
6480 
6499  public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
6500  {
6501  global $conf, $langs;
6502  global $delayedhtmlcontent;
6503 
6504  // TODO Use an internal dolibarr component instead of select2
6505  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) return '';
6506 
6507  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
6508 
6509  $tmpplugin = 'select2';
6510  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6511  <script>
6512  $(document).ready(function () {
6513 
6514  '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
6515 
6516  $(".'.$htmlname.'").select2({
6517  ajax: {
6518  dir: "ltr",
6519  url: "'.$url.'",
6520  dataType: \'json\',
6521  delay: 250,
6522  data: function (params) {
6523  return {
6524  q: params.term, // search term
6525  page: params.page
6526  };
6527  },
6528  processResults: function (data) {
6529  // parse the results into the format expected by Select2.
6530  // since we are using custom formatting functions we do not need to alter the remote JSON data
6531  //console.log(data);
6532  saveRemoteData = data;
6533  /* format json result for select2 */
6534  result = []
6535  $.each( data, function( key, value ) {
6536  result.push({id: key, text: value.text});
6537  });
6538  //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
6539  //console.log(result);
6540  return {results: result, more: false}
6541  },
6542  cache: true
6543  },
6544  language: select2arrayoflanguage,
6545  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
6546  placeholder: "'.dol_escape_js($placeholder).'",
6547  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
6548  minimumInputLength: '.$minimumInputLength.',
6549  formatResult: function(result, container, query, escapeMarkup) {
6550  return escapeMarkup(result.text);
6551  },
6552  });
6553 
6554  '.($callurlonselect ? '
6555  /* Code to execute a GET when we select a value */
6556  $(".'.$htmlname.'").change(function() {
6557  var selected = $(".'.$htmlname.'").val();
6558  console.log("We select in selectArrayAjax the entry "+selected)
6559  $(".'.$htmlname.'").val(""); /* reset visible combo value */
6560  $.each( saveRemoteData, function( key, value ) {
6561  if (key == selected)
6562  {
6563  console.log("selectArrayAjax - Do a redirect to "+value.url)
6564  location.assign(value.url);
6565  }
6566  });
6567  });' : '').'
6568 
6569  });
6570  </script>';
6571 
6572  if ($acceptdelayedhtml)
6573  {
6574  $delayedhtmlcontent .= $outdelayed;
6575  } else {
6576  $out .= $outdelayed;
6577  }
6578  return $out;
6579  }
6580 
6599  public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
6600  {
6601  global $conf, $langs;
6602  global $delayedhtmlcontent;
6603 
6604  // TODO Use an internal dolibarr component instead of select2
6605  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) return '';
6606 
6607  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
6608 
6609  $formattedarrayresult = array();
6610 
6611  foreach ($array as $key => $value) {
6612  $o = new stdClass();
6613  $o->id = $key;
6614  $o->text = $value['text'];
6615  $o->url = $value['url'];
6616  $formattedarrayresult[] = $o;
6617  }
6618 
6619  $tmpplugin = 'select2';
6620  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6621  <script>
6622  $(document).ready(function () {
6623  var data = '.json_encode($formattedarrayresult).';
6624 
6625  '.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
6626 
6627  $(".'.$htmlname.'").select2({
6628  data: data,
6629  language: select2arrayoflanguage,
6630  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
6631  placeholder: "'.dol_escape_js($placeholder).'",
6632  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
6633  minimumInputLength: '.$minimumInputLength.',
6634  formatResult: function(result, container, query, escapeMarkup) {
6635  return escapeMarkup(result.text);
6636  },
6637  matcher: function (params, data) {
6638 
6639  if(! data.id) return null;';
6640 
6641  if ($callurlonselect) {
6642  $outdelayed .= '
6643 
6644  var urlBase = data.url;
6645  var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
6646  /* console.log("params.term="+params.term); */
6647  /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
6648  saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
6649  }
6650 
6651  if (!$disableFiltering) {
6652  $outdelayed .= '
6653 
6654  if(data.text.match(new RegExp(params.term))) {
6655  return data;
6656  }
6657 
6658  return null;';
6659  } else {
6660  $outdelayed .= '
6661 
6662  return data;';
6663  }
6664 
6665  $outdelayed .= '
6666  }
6667  });
6668 
6669  '.($callurlonselect ? '
6670  /* Code to execute a GET when we select a value */
6671  $(".'.$htmlname.'").change(function() {
6672  var selected = $(".'.$htmlname.'").val();
6673  console.log("We select "+selected)
6674 
6675  $(".'.$htmlname.'").val(""); /* reset visible combo value */
6676  $.each( saveRemoteData, function( key, value ) {
6677  if (key == selected)
6678  {
6679  console.log("selectArrayFilter - Do a redirect to "+value.url)
6680  location.assign(value.url);
6681  }
6682  });
6683  });' : '').'
6684 
6685  });
6686  </script>';
6687 
6688  if ($acceptdelayedhtml)
6689  {
6690  $delayedhtmlcontent .= $outdelayed;
6691  } else {
6692  $out .= $outdelayed;
6693  }
6694  return $out;
6695  }
6696 
6715  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)
6716  {
6717  global $conf, $langs;
6718 
6719  $out = '';
6720 
6721  if ($addjscombo < 0) {
6722  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $addjscombo = 1;
6723  else $addjscombo = 0;
6724  }
6725 
6726  // Add code for jquery to use multiselect
6727  if (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))
6728  {
6729  $out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->
6730  <script>'."\n";
6731  if ($addjscombo == 1)
6732  {
6733  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
6734  $out .= 'function formatResult(record) {'."\n";
6735  if ($elemtype == 'category')
6736  {
6737  $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
6738  } else {
6739  $out .= 'return record.text;';
6740  }
6741  $out .= '};'."\n";
6742  $out .= 'function formatSelection(record) {'."\n";
6743  if ($elemtype == 'category')
6744  {
6745  $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
6746  } else {
6747  $out .= 'return record.text;';
6748  }
6749  $out .= '};'."\n";
6750  $out .= '$(document).ready(function () {
6751  $(\'#'.$htmlname.'\').'.$tmpplugin.'({
6752  dir: \'ltr\',
6753  // Specify format function for dropdown item
6754  formatResult: formatResult,
6755  templateResult: formatResult, /* For 4.0 */
6756  // Specify format function for selected item
6757  formatSelection: formatSelection,
6758  templateSelection: formatSelection /* For 4.0 */
6759  });
6760 
6761  /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
6762  the size only if component is not hidden by default on load */
6763  $(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\');
6764  });'."\n";
6765  } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT'))
6766  {
6767  // Add other js lib
6768  // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
6769  // ...
6770  $out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
6771  $out .= '$(document).ready(function () {
6772  $(\'#'.$htmlname.'\').multiSelect({
6773  containerHTML: \'<div class="multi-select-container">\',
6774  menuHTML: \'<div class="multi-select-menu">\',
6775  buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
6776  menuItemHTML: \'<label class="multi-select-menuitem">\',
6777  activeClass: \'multi-select-container--open\',
6778  noneText: \''.$placeholder.'\'
6779  });
6780  })';
6781  }
6782  $out .= '</script>';
6783  }
6784 
6785  // Try also magic suggest
6786  $out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
6787  if (is_array($array) && !empty($array))
6788  {
6789  if ($value_as_key) $array = array_combine($array, $array);
6790 
6791  if (!empty($array))
6792  {
6793  foreach ($array as $key => $value)
6794  {
6795  $newval = ($translate ? $langs->trans($value) : $value);
6796  $newval = ($key_in_label ? $key.' - '.$newval : $newval);
6797 
6798  $out .= '<option value="'.$key.'"';
6799  if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != ''))
6800  {
6801  $out .= ' selected';
6802  }
6803  $out .= ' data-html="'.dol_escape_htmltag($newval).'"';
6804  $out .= '>';
6805  $out .= dol_htmlentitiesbr($newval);
6806  $out .= '</option>'."\n";
6807  }
6808  }
6809  }
6810  $out .= '</select>'."\n";
6811 
6812  return $out;
6813  }
6814 
6815 
6825  public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
6826  {
6827  global $conf, $langs, $user, $extrafields;
6828 
6829  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) return '';
6830 
6831  $tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved seleteced properties
6832  if (!empty($user->conf->$tmpvar))
6833  {
6834  $tmparray = explode(',', $user->conf->$tmpvar);
6835  foreach ($array as $key => $val)
6836  {
6837  //var_dump($key);
6838  //var_dump($tmparray);
6839  if (in_array($key, $tmparray)) $array[$key]['checked'] = 1;
6840  else $array[$key]['checked'] = 0;
6841  }
6842  }
6843 
6844  $lis = '';
6845  $listcheckedstring = '';
6846 
6847  foreach ($array as $key => $val)
6848  {
6849  /* var_dump($val);
6850  var_dump(array_key_exists('enabled', $val));
6851  var_dump(!$val['enabled']);*/
6852  if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled'])
6853  {
6854  unset($array[$key]); // We don't want this field
6855  continue;
6856  }
6857  if ($val['label'])
6858  {
6859  if (!empty($val['langfile']) && is_object($langs)) {
6860  $langs->load($val['langfile']);
6861  }
6862 
6863  $lis .= '<li><input type="checkbox" id="checkbox'.$key.'" value="'.$key.'"'.(empty($val['checked']) ? '' : ' checked="checked"').'/><label for="checkbox'.$key.'">'.dol_escape_htmltag($langs->trans($val['label'])).'</label></li>';
6864  $listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
6865  }
6866  }
6867 
6868  $out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
6869 
6870  <dl class="dropdown">
6871  <dt>
6872  <a href="#'.$htmlname.'">
6873  '.img_picto('', 'list').'
6874  </a>
6875  <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
6876  </dt>
6877  <dd class="dropdowndd">
6878  <div class="multiselectcheckbox'.$htmlname.'">
6879  <ul class="ul'.$htmlname.'">
6880  '.$lis.'
6881  </ul>
6882  </div>
6883  </dd>
6884  </dl>
6885 
6886  <script type="text/javascript">
6887  jQuery(document).ready(function () {
6888  $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
6889  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
6890 
6891  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
6892 
6893  var title = $(this).val() + ",";
6894  if ($(this).is(\':checked\')) {
6895  $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
6896  }
6897  else {
6898  $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
6899  }
6900  // Now, we submit page
6901  //$(this).parents(\'form:first\').submit();
6902  });
6903 
6904 
6905  });
6906  </script>
6907 
6908  ';
6909  return $out;
6910  }
6911 
6921  public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
6922  {
6923  global $db;
6924 
6925  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
6926 
6927  $cat = new Categorie($db);
6928  $categories = $cat->containing($id, $type);
6929 
6930  if ($rendermode == 1)
6931  {
6932  $toprint = array();
6933  foreach ($categories as $c)
6934  {
6935  $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
6936  foreach ($ways as $way)
6937  {
6938  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>';
6939  }
6940  }
6941  return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6942  }
6943 
6944  if ($rendermode == 0)
6945  {
6946  $arrayselected = array();
6947  $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
6948  foreach ($categories as $c) {
6949  $arrayselected[] = $c->id;
6950  }
6951 
6952  return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
6953  }
6954 
6955  return 'ErrorBadValueForParameterRenderMode'; // Should not happened
6956  }
6957 
6966  public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false)
6967  {
6968  global $conf, $langs, $hookmanager;
6969  global $bc, $action;
6970 
6971  $object->fetchObjectLinked();
6972 
6973  // Bypass the default method
6974  $hookmanager->initHooks(array('commonobject'));
6975  $parameters = array(
6976  'morehtmlright' => $morehtmlright,
6977  'compatibleImportElementsList' => &$compatibleImportElementsList,
6978  );
6979  $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
6980 
6981  if (empty($reshook))
6982  {
6983  $nbofdifferenttypes = count($object->linkedObjects);
6984 
6985  print '<!-- showLinkedObjectBlock -->';
6986  print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
6987 
6988 
6989  print '<div class="div-table-responsive-no-min">';
6990  print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'" data-elementid="'.$object->id.'" >';
6991 
6992  print '<tr class="liste_titre">';
6993  print '<td>'.$langs->trans("Type").'</td>';
6994  print '<td>'.$langs->trans("Ref").'</td>';
6995  print '<td class="center"></td>';
6996  print '<td class="center">'.$langs->trans("Date").'</td>';
6997  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
6998  print '<td class="right">'.$langs->trans("Status").'</td>';
6999  print '<td></td>';
7000  print '</tr>';
7001 
7002  $nboftypesoutput = 0;
7003 
7004  foreach ($object->linkedObjects as $objecttype => $objects)
7005  {
7006  $tplpath = $element = $subelement = $objecttype;
7007 
7008  // to display inport button on tpl
7009  $showImportButton = false;
7010  if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
7011  $showImportButton = true;
7012  }
7013 
7014  $regs = array();
7015  if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs))
7016  {
7017  $element = $regs[1];
7018  $subelement = $regs[2];
7019  $tplpath = $element.'/'.$subelement;
7020  }
7021  $tplname = 'linkedobjectblock';
7022 
7023  // To work with non standard path
7024  if ($objecttype == 'facture') {
7025  $tplpath = 'compta/'.$element;
7026  if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
7027  } elseif ($objecttype == 'facturerec') {
7028  $tplpath = 'compta/facture';
7029  $tplname = 'linkedobjectblockForRec';
7030  if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
7031  } elseif ($objecttype == 'propal') {
7032  $tplpath = 'comm/'.$element;
7033  if (empty($conf->propal->enabled)) continue; // Do not show if module disabled
7034  } elseif ($objecttype == 'supplier_proposal') {
7035  if (empty($conf->supplier_proposal->enabled)) continue; // Do not show if module disabled
7036  } elseif ($objecttype == 'shipping' || $objecttype == 'shipment') {
7037  $tplpath = 'expedition';
7038  if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
7039  } elseif ($objecttype == 'reception') {
7040  $tplpath = 'reception';
7041  if (empty($conf->reception->enabled)) continue; // Do not show if module disabled
7042  } elseif ($objecttype == 'delivery') {
7043  $tplpath = 'delivery';
7044  if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
7045  } elseif ($objecttype == 'invoice_supplier') {
7046  $tplpath = 'fourn/facture';
7047  } elseif ($objecttype == 'order_supplier') {
7048  $tplpath = 'fourn/commande';
7049  } elseif ($objecttype == 'expensereport') {
7050  $tplpath = 'expensereport';
7051  } elseif ($objecttype == 'subscription') {
7052  $tplpath = 'adherents';
7053  }
7054 
7055  global $linkedObjectBlock;
7056  $linkedObjectBlock = $objects;
7057 
7058 
7059  // Output template part (modules that overwrite templates must declare this into descriptor)
7060  $dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
7061  foreach ($dirtpls as $reldir)
7062  {
7063  if ($nboftypesoutput == ($nbofdifferenttypes - 1)) // No more type to show after
7064  {
7065  global $noMoreLinkedObjectBlockAfter;
7066  $noMoreLinkedObjectBlockAfter = 1;
7067  }
7068 
7069  $res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
7070  if ($res)
7071  {
7072  $nboftypesoutput++;
7073  break;
7074  }
7075  }
7076  }
7077 
7078  if (!$nboftypesoutput)
7079  {
7080  print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>';
7081  }
7082 
7083  print '</table>';
7084 
7085  if (!empty($compatibleImportElementsList))
7086  {
7087  $res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
7088  }
7089 
7090 
7091  print '</div>';
7092 
7093  return $nbofdifferenttypes;
7094  }
7095  }
7096 
7105  public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
7106  {
7107  global $conf, $langs, $hookmanager;
7108  global $bc, $action;
7109 
7110  $linktoelem = '';
7111  $linktoelemlist = '';
7112  $listofidcompanytoscan = '';
7113 
7114  if (!is_object($object->thirdparty)) $object->fetch_thirdparty();
7115 
7116  $possiblelinks = array();
7117  if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0)
7118  {
7119  $listofidcompanytoscan = $object->thirdparty->id;
7120  if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) $listofidcompanytoscan .= ','.$object->thirdparty->parent;
7121  if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO))
7122  {
7123  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7124  $tmpproject = new Project($this->db);
7125  $tmpproject->fetch($object->fk_project);
7126  if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) $listofidcompanytoscan .= ','.$tmpproject->socid;
7127  unset($tmpproject);
7128  }
7129 
7130  $possiblelinks = array(
7131  'propal'=>array('enabled'=>$conf->propal->enabled, 'perms'=>1, 'label'=>'LinkToProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('propal').')'),
7132  'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande').')'),
7133  'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'),
7134  'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'),
7135  'contrat'=>array('enabled'=>$conf->contrat->enabled, 'perms'=>1, 'label'=>'LinkToContract',
7136  '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 FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t, ".MAIN_DB_PREFIX."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'),
7137  'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('intervention').')'),
7138  'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled, 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('supplier_proposal').')'),
7139  'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled, 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande_fournisseur').')'),
7140  'invoice_supplier'=>array('enabled'=>$conf->supplier_invoice->enabled, 'perms'=>1, 'label'=>'LinkToSupplierInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('facture_fourn').')'),
7141  'ticket'=>array('enabled'=>$conf->ticket->enabled, 'perms'=>1, 'label'=>'LinkToTicket', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('ticket').')')
7142  );
7143  }
7144 
7145  // Can complete the possiblelink array
7146  $hookmanager->initHooks(array('commonobject'));
7147  $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan);
7148 
7149  if (!empty($listofidcompanytoscan)) // If empty, we don't have criteria to scan the object we can link to
7150  {
7151  $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
7152  }
7153 
7154  if (empty($reshook))
7155  {
7156  if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
7157  {
7158  $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
7159  }
7160  } elseif ($reshook > 0)
7161  {
7162  if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
7163  {
7164  $possiblelinks = $hookmanager->resArray;
7165  }
7166  }
7167 
7168  foreach ($possiblelinks as $key => $possiblelink)
7169  {
7170  $num = 0;
7171 
7172  if (empty($possiblelink['enabled'])) continue;
7173 
7174  if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto)))
7175  {
7176  print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
7177  $sql = $possiblelink['sql'];
7178 
7179  $resqllist = $this->db->query($sql);
7180  if ($resqllist)
7181  {
7182  $num = $this->db->num_rows($resqllist);
7183  $i = 0;
7184 
7185  print '<br>';
7186  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
7187  print '<input type="hidden" name="action" value="addlink">';
7188  print '<input type="hidden" name="token" value="'.newToken().'">';
7189  print '<input type="hidden" name="id" value="'.$object->id.'">';
7190  print '<input type="hidden" name="addlink" value="'.$key.'">';
7191  print '<table class="noborder">';
7192  print '<tr class="liste_titre">';
7193  print '<td class="nowrap"></td>';
7194  print '<td class="center">'.$langs->trans("Ref").'</td>';
7195  print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
7196  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
7197  print '<td class="left">'.$langs->trans("Company").'</td>';
7198  print '</tr>';
7199  while ($i < $num)
7200  {
7201  $objp = $this->db->fetch_object($resqllist);
7202 
7203  print '<tr class="oddeven">';
7204  print '<td class="left">';
7205  print '<input type="radio" name="idtolinkto" value='.$objp->rowid.'>';
7206  print '</td>';
7207  print '<td class="center">'.$objp->ref.'</td>';
7208  print '<td>'.$objp->ref_client.'</td>';
7209  print '<td class="right">';
7210  if ($possiblelink[label] == 'LinkToContract') {
7211  $form = new Form($db);
7212  print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' ';
7213  }
7214  print price($objp->total_ht).'</td>';
7215  print '<td>'.$objp->name.'</td>';
7216  print '</tr>';
7217  $i++;
7218  }
7219  print '</table>';
7220  print '<div class="center"><input type="submit" class="button valignmiddle" value="'.$langs->trans('ToLink').'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" class="button button-cancel" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
7221 
7222  print '</form>';
7223  $this->db->free($resqllist);
7224  } else {
7225  dol_print_error($this->db);
7226  }
7227  print '</div>';
7228  if ($num > 0)
7229  {
7230  }
7231 
7232  //$linktoelem.=($linktoelem?' &nbsp; ':'');
7233  if ($num > 0) $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
7234  //else $linktoelem.=$langs->trans($possiblelink['label']);
7235  else $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
7236  }
7237  }
7238 
7239  if ($linktoelemlist)
7240  {
7241  $linktoelem = '
7242  <dl class="dropdown" id="linktoobjectname">
7243  ';
7244  if (!empty($conf->use_javascript_ajax)) $linktoelem .= '<dt><a href="#linktoobjectname">'.$langs->trans("LinkTo").'...</a></dt>';
7245  $linktoelem .= '<dd>
7246  <div class="multiselectlinkto">
7247  <ul class="ulselectedfields">'.$linktoelemlist.'
7248  </ul>
7249  </div>
7250  </dd>
7251  </dl>';
7252  } else {
7253  $linktoelem = '';
7254  }
7255 
7256  if (!empty($conf->use_javascript_ajax))
7257  {
7258  print '<!-- Add js to show linkto box -->
7259  <script>
7260  jQuery(document).ready(function() {
7261  jQuery(".linkto").click(function() {
7262  console.log("We choose to show/hide link for rel="+jQuery(this).attr(\'rel\'));
7263  jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
7264  });
7265  });
7266  </script>
7267  ';
7268  }
7269 
7270  return $linktoelem;
7271  }
7272 
7284  public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0)
7285  {
7286  global $langs;
7287 
7288  $yes = "yes"; $no = "no";
7289  if ($option)
7290  {
7291  $yes = "1";
7292  $no = "0";
7293  }
7294 
7295  $disabled = ($disabled ? ' disabled' : '');
7296 
7297  $resultyesno = '<select class="flat width75" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
7298  if ($useempty) $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
7299  if (("$value" == 'yes') || ($value == 1))
7300  {
7301  $resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
7302  $resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
7303  } else {
7304  $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
7305  $resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
7306  $resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
7307  }
7308  $resultyesno .= '</select>'."\n";
7309 
7310  if ($addjscombo) {
7311  $resultyesno .= ajax_combobox($htmlname);
7312  }
7313 
7314  return $resultyesno;
7315  }
7316 
7317  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7327  public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
7328  {
7329  // phpcs:enable
7330  $sql = "SELECT rowid, label";
7331  $sql .= " FROM ".MAIN_DB_PREFIX."export_model";
7332  $sql .= " WHERE type = '".$this->db->escape($type)."'";
7333  $sql .= " ORDER BY rowid";
7334  $result = $this->db->query($sql);
7335  if ($result)
7336  {
7337  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
7338  if ($useempty)
7339  {
7340  print '<option value="-1">&nbsp;</option>';
7341  }
7342 
7343  $num = $this->db->num_rows($result);
7344  $i = 0;
7345  while ($i < $num)
7346  {
7347  $obj = $this->db->fetch_object($result);
7348  if ($selected == $obj->rowid)
7349  {
7350  print '<option value="'.$obj->rowid.'" selected>';
7351  } else {
7352  print '<option value="'.$obj->rowid.'">';
7353  }
7354  print $obj->label;
7355  print '</option>';
7356  $i++;
7357  }
7358  print "</select>";
7359  } else {
7360  dol_print_error($this->db);
7361  }
7362  }
7363 
7382  public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
7383  {
7384  global $langs, $conf, $hookmanager, $extralanguages;
7385 
7386  $ret = '';
7387  if (empty($fieldid)) $fieldid = 'rowid';
7388  if (empty($fieldref)) $fieldref = 'ref';
7389 
7390  // Add where from hooks
7391  if (is_object($hookmanager))
7392  {
7393  $parameters = array();
7394  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
7395  $object->next_prev_filter .= $hookmanager->resPrint;
7396  }
7397  $previous_ref = $next_ref = '';
7398  if ($shownav)
7399  {
7400  //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
7401  $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
7402 
7403  $navurl = $_SERVER["PHP_SELF"];
7404  // Special case for project/task page
7405  if ($paramid == 'project_ref')
7406  {
7407  if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) // TODO Remove this when nav with project_ref on task pages are ok
7408  {
7409  $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
7410  $paramid = 'ref';
7411  }
7412  }
7413 
7414  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
7415  // accesskey is for Mac: CTRL + key for all browsers
7416  $stringforfirstkey = $langs->trans("KeyboardShortcut");
7417  if ($conf->browser->name == 'chrome')
7418  {
7419  $stringforfirstkey .= ' ALT +';
7420  } elseif ($conf->browser->name == 'firefox')
7421  {
7422  $stringforfirstkey .= ' ALT + SHIFT +';
7423  } else {
7424  $stringforfirstkey .= ' CTL +';
7425  }
7426 
7427  $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>';
7428  $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>';
7429  }
7430 
7431  //print "xx".$previous_ref."x".$next_ref;
7432  $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
7433 
7434  // Right part of banner
7435  if ($morehtmlright) $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
7436 
7437  if ($previous_ref || $next_ref || $morehtml)
7438  {
7439  $ret .= '<div class="pagination paginationref"><ul class="right">';
7440  }
7441  if ($morehtml)
7442  {
7443  $ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>';
7444  }
7445  if ($shownav && ($previous_ref || $next_ref))
7446  {
7447  $ret .= '<li class="pagination">'.$previous_ref.'</li>';
7448  $ret .= '<li class="pagination">'.$next_ref.'</li>';
7449  }
7450  if ($previous_ref || $next_ref || $morehtml)
7451  {
7452  $ret .= '</ul></div>';
7453  }
7454 
7455  $parameters = array();
7456  $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
7457  if (empty($reshook)) $morehtmlstatus .= $hookmanager->resPrint;
7458  else $morehtmlstatus = $hookmanager->resPrint;
7459  if ($morehtmlstatus) $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
7460 
7461  $parameters = array();
7462  $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
7463  if (empty($reshook)) $morehtmlref .= $hookmanager->resPrint;
7464  elseif ($reshook > 0) $morehtmlref = $hookmanager->resPrint;
7465 
7466  // Left part of banner
7467  if ($morehtmlleft)
7468  {
7469  if ($conf->browser->layout == 'phone') $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
7470  else $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
7471  }
7472 
7473  //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
7474  $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
7475 
7476  // For thirdparty, contact, user, member, the ref is the id, so we show something else
7477  if ($object->element == 'societe')
7478  {
7479  $ret .= dol_htmlentities($object->name);
7480 
7481  // List of extra languages
7482  $arrayoflangcode = array();
7483  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
7484 
7485  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
7486  if (!is_object($extralanguages)) {
7487  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
7488  $extralanguages = new ExtraLanguages($this->db);
7489  }
7490  $extralanguages->fetch_name_extralanguages('societe');
7491 
7492  if (!empty($extralanguages->attributes['societe']['name']))
7493  {
7494  $object->fetchValuesForExtraLanguages();
7495 
7496  $htmltext = '';
7497  // If there is extra languages
7498  foreach ($arrayoflangcode as $extralangcode) {
7499  $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
7500  if ($object->array_languages['name'][$extralangcode]) {
7501  $htmltext .= $object->array_languages['name'][$extralangcode];
7502  } else {
7503  $htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
7504  }
7505  }
7506  $ret .= '<!-- Show translations of name -->'."\n";
7507  $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
7508  }
7509  }
7510  } elseif ($object->element == 'member')
7511  {
7512  $ret .= $object->ref.'<br>';
7513  $fullname = $object->getFullName($langs);
7514  if ($object->morphy == 'mor' && $object->societe) {
7515  $ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).')' : '');
7516  } else {
7517  $ret .= dol_htmlentities($fullname).((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
7518  }
7519  } elseif (in_array($object->element, array('contact', 'user', 'usergroup')))
7520  {
7521  $ret .= dol_htmlentities($object->getFullName($langs));
7522  } elseif (in_array($object->element, array('action', 'agenda')))
7523  {
7524  $ret .= $object->ref.'<br>'.$object->label;
7525  } elseif (in_array($object->element, array('adherent_type')))
7526  {
7527  $ret .= $object->label;
7528  } elseif ($object->element == 'ecm_directories')
7529  {
7530  $ret .= '';
7531  } elseif ($fieldref != 'none')
7532  {
7533  $ret .= dol_htmlentities($object->$fieldref);
7534  }
7535 
7536  if ($morehtmlref)
7537  {
7538  // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
7539  if (substr($morehtmlref, 0, 4) != '<div')
7540  {
7541  $ret .= ' ';
7542  }
7543 
7544  $ret .= $morehtmlref;
7545  }
7546 
7547  $ret .= '</div>';
7548 
7549  $ret .= '</div><!-- End banner content -->';
7550 
7551  return $ret;
7552  }
7553 
7554 
7562  public function showbarcode(&$object, $width = 100)
7563  {
7564  global $conf;
7565 
7566  //Check if barcode is filled in the card
7567  if (empty($object->barcode)) return '';
7568 
7569  // Complete object if not complete
7570  if (empty($object->barcode_type_code) || empty($object->barcode_type_coder))
7571  {
7572  $result = $object->fetch_barcode();
7573  //Check if fetch_barcode() failed
7574  if ($result < 1) return '<!-- ErrorFetchBarcode -->';
7575  }
7576 
7577  // Barcode image
7578  $url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
7579  $out = '<!-- url barcode = '.$url.' -->';
7580  $out .= '<img src="'.$url.'">';
7581  return $out;
7582  }
7583 
7600  public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
7601  {
7602  global $conf, $langs;
7603 
7604  $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
7605  $id = (!empty($object->id) ? $object->id : $object->rowid);
7606 
7607  $ret = ''; $dir = ''; $file = ''; $originalfile = ''; $altfile = ''; $email = ''; $capture = '';
7608  if ($modulepart == 'societe')
7609  {
7610  $dir = $conf->societe->multidir_output[$entity];
7611  if (!empty($object->logo)) {
7612  if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
7613  elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small');
7614  else $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
7615  $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
7616  }
7617  $email = $object->email;
7618  } elseif ($modulepart == 'contact') {
7619  $dir = $conf->societe->multidir_output[$entity].'/contact';
7620  if (!empty($object->photo))
7621  {
7622  if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini');
7623  elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small');
7624  else $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
7625  $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
7626  }
7627  $email = $object->email;
7628  $capture = 'user';
7629  } elseif ($modulepart == 'userphoto') {
7630  $dir = $conf->user->dir_output;
7631  if (!empty($object->photo))
7632  {
7633  if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_mini');
7634  elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_small');
7635  else $file = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo;
7636  $originalfile = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo;
7637  }
7638  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7639  $email = $object->email;
7640  $capture = 'user';
7641  } elseif ($modulepart == 'memberphoto') {
7642  $dir = $conf->adherent->dir_output;
7643  if (!empty($object->photo))
7644  {
7645  if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
7646  elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
7647  else $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
7648  $originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
7649  }
7650  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7651  $email = $object->email;
7652  $capture = 'user';
7653  } else {
7654  // Generic case to show photos
7655  $dir = $conf->$modulepart->dir_output;
7656  if (!empty($object->photo))
7657  {
7658  if ((string) $imagesize == 'mini') $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
7659  elseif ((string) $imagesize == 'small') $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
7660  else $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
7661  $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
7662  }
7663  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7664  $email = $object->email;
7665  }
7666 
7667  if ($forcecapture) $capture = $forcecapture;
7668 
7669  if ($dir)
7670  {
7671  if ($file && file_exists($dir."/".$file))
7672  {
7673  if ($addlinktofullsize) {
7674  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
7675  if ($urladvanced) $ret .= '<a href="'.$urladvanced.'">';
7676  else $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
7677  }
7678  $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.'">';
7679  if ($addlinktofullsize) $ret .= '</a>';
7680  } elseif ($altfile && file_exists($dir."/".$altfile)) {
7681  if ($addlinktofullsize) {
7682  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
7683  if ($urladvanced) $ret .= '<a href="'.$urladvanced.'">';
7684  else $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
7685  }
7686  $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.'">';
7687  if ($addlinktofullsize) $ret .= '</a>';
7688  } else {
7689  $nophoto = '/public/theme/common/nophoto.png';
7690  if (in_array($modulepart, array('userphoto', 'contact', 'memberphoto'))) { // For module that are "physical" users
7691  if ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor') !== false) {
7692  $nophoto = '/public/theme/common/company.png';
7693  } else {
7694  $nophoto = '/public/theme/common/user_anonymous.png';
7695  if ($object->gender == 'man') $nophoto = '/public/theme/common/user_man.png';
7696  if ($object->gender == 'woman') $nophoto = '/public/theme/common/user_woman.png';
7697  }
7698  }
7699 
7700  if (!empty($conf->gravatar->enabled) && $email && empty($noexternsourceoverwrite)) {
7701  // see https://gravatar.com/site/implement/images/php/
7702  global $dolibarr_main_url_root;
7703  $ret .= '<!-- Put link to gravatar -->';
7704  //$defaultimg=urlencode(dol_buildpath($nophoto,3));
7705  $defaultimg = 'mm';
7706  $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="Gravatar avatar" 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
7707  } else {
7708  $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
7709  }
7710  }
7711 
7712  if ($caneditfield)
7713  {
7714  if ($object->photo) $ret .= "<br>\n";
7715  $ret .= '<table class="nobordernopadding centpercent">';
7716  if ($object->photo) $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> '.$langs->trans("Delete").'<br><br></td></tr>';
7717  $ret .= '<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'></td></tr>';
7718  $ret .= '</table>';
7719  }
7720  } else dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
7721 
7722  return $ret;
7723  }
7724 
7725  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7742  public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
7743  {
7744  // phpcs:enable
7745  global $conf, $user, $langs;
7746 
7747  // Permettre l'exclusion de groupes
7748  if (is_array($exclude)) $excludeGroups = implode("','", $exclude);
7749  // Permettre l'inclusion de groupes
7750  if (is_array($include)) $includeGroups = implode("','", $include);
7751 
7752  if (!is_array($selected)) $selected = array($selected);
7753 
7754  $out = '';
7755 
7756  // On recherche les groupes
7757  $sql = "SELECT ug.rowid, ug.nom as name";
7758  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
7759  {
7760  $sql .= ", e.label";
7761  }
7762  $sql .= " FROM ".MAIN_DB_PREFIX."usergroup as ug ";
7763  if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
7764  {
7765  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=ug.entity";
7766  if ($force_entity) $sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
7767  else $sql .= " WHERE ug.entity IS NOT NULL";
7768  } else {
7769  $sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
7770  }
7771  if (is_array($exclude) && $excludeGroups) $sql .= " AND ug.rowid NOT IN ('".$excludeGroups."')";
7772  if (is_array($include) && $includeGroups) $sql .= " AND ug.rowid IN ('".$includeGroups."')";
7773  $sql .= " ORDER BY ug.nom ASC";
7774 
7775  dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
7776  $resql = $this->db->query($sql);
7777  if ($resql)
7778  {
7779  // Enhance with select2
7780  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7781  $out .= ajax_combobox($htmlname);
7782 
7783  $out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
7784 
7785  $num = $this->db->num_rows($resql);
7786  $i = 0;
7787  if ($num)
7788  {
7789  if ($show_empty && !$multiple) $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
7790 
7791  while ($i < $num)
7792  {
7793  $obj = $this->db->fetch_object($resql);
7794  $disableline = 0;
7795  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) $disableline = 1;
7796 
7797  $out .= '<option value="'.$obj->rowid.'"';
7798  if ($disableline) $out .= ' disabled';
7799  if ((is_object($selected[0]) && $selected[0]->id == $obj->rowid) || (!is_object($selected[0]) && in_array($obj->rowid, $selected)))
7800  {
7801  $out .= ' selected';
7802  }
7803  $out .= '>';
7804 
7805  $out .= $obj->name;
7806  if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1)
7807  {
7808  $out .= " (".$obj->label.")";
7809  }
7810 
7811  $out .= '</option>';
7812  $i++;
7813  }
7814  } else {
7815  if ($show_empty) $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
7816  $out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
7817  }
7818  $out .= '</select>';
7819  } else {
7820  dol_print_error($this->db);
7821  }
7822 
7823  return $out;
7824  }
7825 
7826 
7832  public function showFilterButtons()
7833  {
7834  $out = '<div class="nowrap">';
7835  $out .= '<button type="submit" class="liste_titre button_search" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
7836  $out .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
7837  $out .= '</div>';
7838 
7839  return $out;
7840  }
7841 
7850  public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
7851  {
7852  global $conf, $langs;
7853 
7854  $out = '';
7855 
7856  if (!empty($conf->use_javascript_ajax)) $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
7857  $out .= '<script>
7858  $(document).ready(function() {
7859  $("#' . $cssclass.'s").click(function() {
7860  if($(this).is(\':checked\')){
7861  console.log("We check all '.$cssclass.' and trigger the change method");
7862  $(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
7863  }
7864  else
7865  {
7866  console.log("We uncheck all");
7867  $(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
7868  }'."\n";
7869  if ($calljsfunction) $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
7870  $out .= ' });
7871  $(".' . $cssclass.'").change(function() {
7872  $(this).closest("tr").toggleClass("highlight", this.checked);
7873  });
7874  });
7875  </script>';
7876 
7877  return $out;
7878  }
7879 
7889  public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
7890  {
7891  $out = $this->showFilterButtons();
7892  if ($addcheckuncheckall)
7893  {
7894  $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
7895  }
7896  return $out;
7897  }
7898 
7912  public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
7913  {
7914  global $db, $langs, $user;
7915 
7916  $out = '';
7917  $sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1';
7918  $sql .= ' AND entity IN (0,'.getEntity('exp_tax_cat').')';
7919  if (!empty($excludeid)) $sql .= ' AND rowid NOT IN ('.implode(',', $excludeid).')';
7920  $sql .= ' ORDER BY label';
7921 
7922  $resql = $db->query($sql);
7923  if ($resql)
7924  {
7925  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
7926  if ($useempty) $out .= '<option value="0">&nbsp;</option>';
7927 
7928  while ($obj = $db->fetch_object($resql))
7929  {
7930  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
7931  }
7932  $out .= '</select>';
7933  $out .= ajax_combobox('select_'.$htmlname);
7934 
7935  if (!empty($htmlname) && $user->admin && $info_admin) $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
7936 
7937  if (!empty($target))
7938  {
7939  $sql = "SELECT c.id FROM ".MAIN_DB_PREFIX."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
7940  $resql = $db->query($sql);
7941  if ($resql)
7942  {
7943  if ($db->num_rows($resql) > 0)
7944  {
7945  $obj = $db->fetch_object($resql);
7946  $out .= '<script>
7947  $(function() {
7948  $("select[name='.$target.']").on("change", function() {
7949  var current_val = $(this).val();
7950  if (current_val == '.$obj->id.') {';
7951  if (!empty($default_selected) || !empty($selected)) $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
7952 
7953  $out .= '
7954  $("select[name='.$htmlname.']").change();
7955  }
7956  });
7957 
7958  $("select[name='.$htmlname.']").change(function() {
7959 
7960  if ($("select[name='.$target.']").val() == '.$obj->id.') {
7961  // get price of kilometer to fill the unit price
7962  var data = '.json_encode($params).';
7963  data.fk_c_exp_tax_cat = $(this).val();
7964 
7965  $.ajax({
7966  method: "POST",
7967  dataType: "json",
7968  data: data,
7969  url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php').'",
7970  }).done(function( data, textStatus, jqXHR ) {
7971  console.log(data);
7972  if (typeof data.up != "undefined") {
7973  $("input[name=value_unit]").val(data.up);
7974  $("select[name='.$htmlname.']").attr("title", data.title);
7975  } else {
7976  $("input[name=value_unit]").val("");
7977  $("select[name='.$htmlname.']").attr("title", "");
7978  }
7979  });
7980  }
7981  });
7982  });
7983  </script>';
7984  }
7985  }
7986  }
7987  } else {
7988  dol_print_error($db);
7989  }
7990 
7991  return $out;
7992  }
7993 
8002  public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
8003  {
8004  global $db, $conf, $langs;
8005 
8006  $out = '';
8007  $sql = 'SELECT rowid, range_ik FROM '.MAIN_DB_PREFIX.'c_exp_tax_range';
8008  $sql .= ' WHERE entity = '.$conf->entity.' AND active = 1';
8009 
8010  $resql = $db->query($sql);
8011  if ($resql)
8012  {
8013  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
8014  if ($useempty) $out .= '<option value="0"></option>';
8015 
8016  while ($obj = $db->fetch_object($resql))
8017  {
8018  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
8019  }
8020  $out .= '</select>';
8021  } else {
8022  dol_print_error($db);
8023  }
8024 
8025  return $out;
8026  }
8027 
8038  public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
8039  {
8040  global $db, $langs;
8041 
8042  $out = '';
8043  $sql = 'SELECT id, code, label FROM '.MAIN_DB_PREFIX.'c_type_fees';
8044  $sql .= ' WHERE active = 1';
8045 
8046  $resql = $db->query($sql);
8047  if ($resql)
8048  {
8049  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
8050  if ($useempty) $out .= '<option value="0"></option>';
8051  if ($allchoice) $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
8052 
8053  $field = 'code';
8054  if ($useid) $field = 'id';
8055 
8056  while ($obj = $db->fetch_object($resql))
8057  {
8058  $key = $langs->trans($obj->code);
8059  $out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
8060  }
8061  $out .= '</select>';
8062  } else {
8063  dol_print_error($db);
8064  }
8065 
8066  return $out;
8067  }
8068 
8087  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)
8088  {
8089  global $user, $conf, $langs;
8090 
8091  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
8092 
8093  if (is_null($usertofilter))
8094  {
8095  $usertofilter = $user;
8096  }
8097 
8098  $out = '';
8099 
8100  $hideunselectables = false;
8101  if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) $hideunselectables = true;
8102 
8103  if (empty($projectsListId))
8104  {
8105  if (empty($usertofilter->rights->projet->all->lire))
8106  {
8107  $projectstatic = new Project($this->db);
8108  $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
8109  }
8110  }
8111 
8112  // Search all projects
8113  $sql = 'SELECT f.rowid, f.ref as fref, "nolabel" as flabel, p.rowid as pid, f.ref,
8114  p.title, p.fk_soc, p.fk_statut, p.public,';
8115  $sql .= ' s.nom as name';
8116  $sql .= ' FROM '.MAIN_DB_PREFIX.'projet as p';
8117  $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = p.fk_soc,';
8118  $sql .= ' '.MAIN_DB_PREFIX.'facture as f';
8119  $sql .= " WHERE p.entity IN (".getEntity('project').")";
8120  $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
8121  //if ($projectsListId) $sql.= " AND p.rowid IN (".$projectsListId.")";
8122  //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
8123  //if ($socid > 0) $sql.= " AND (p.fk_soc=".$socid." OR p.fk_soc IS NULL)";
8124  $sql .= " GROUP BY f.ref ORDER BY p.ref, f.ref ASC";
8125 
8126  $resql = $this->db->query($sql);
8127  if ($resql)
8128  {
8129  // Use select2 selector
8130  if (!empty($conf->use_javascript_ajax))
8131  {
8132  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
8133  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
8134  $out .= $comboenhancement;
8135  $morecss = 'minwidth200imp maxwidth500';
8136  }
8137 
8138  if (empty($option_only)) {
8139  $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
8140  }
8141  if (!empty($show_empty)) {
8142  $out .= '<option value="0" class="optiongrey">';
8143  if (!is_numeric($show_empty)) $out .= $show_empty;
8144  else $out .= '&nbsp;';
8145  $out .= '</option>';
8146  }
8147  $num = $this->db->num_rows($resql);
8148  $i = 0;
8149  if ($num)
8150  {
8151  while ($i < $num)
8152  {
8153  $obj = $this->db->fetch_object($resql);
8154  // 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.
8155  if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire))
8156  {
8157  // Do nothing
8158  } else {
8159  if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED)
8160  {
8161  $i++;
8162  continue;
8163  }
8164 
8165  $labeltoshow = '';
8166 
8167  if ($showproject == 'all')
8168  {
8169  $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
8170  if ($obj->name) $labeltoshow .= ' - '.$obj->name; // Soc name
8171 
8172  $disabled = 0;
8173  if ($obj->fk_statut == Project::STATUS_DRAFT)
8174  {
8175  $disabled = 1;
8176  $labeltoshow .= ' - '.$langs->trans("Draft");
8177  } elseif ($obj->fk_statut == Project::STATUS_CLOSED)
8178  {
8179  if ($discard_closed == 2) $disabled = 1;
8180  $labeltoshow .= ' - '.$langs->trans("Closed");
8181  } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid))
8182  {
8183  $disabled = 1;
8184  $labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
8185  }
8186  }
8187 
8188  if (!empty($selected) && $selected == $obj->rowid)
8189  {
8190  $out .= '<option value="'.$obj->rowid.'" selected';
8191  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
8192  $out .= '>'.$labeltoshow.'</option>';
8193  } else {
8194  if ($hideunselectables && $disabled && ($selected != $obj->rowid))
8195  {
8196  $resultat = '';
8197  } else {
8198  $resultat = '<option value="'.$obj->rowid.'"';
8199  if ($disabled) $resultat .= ' disabled';
8200  //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
8201  //else $labeltoshow.=' ('.$langs->trans("Private").')';
8202  $resultat .= '>';
8203  $resultat .= $labeltoshow;
8204  $resultat .= '</option>';
8205  }
8206  $out .= $resultat;
8207  }
8208  }
8209  $i++;
8210  }
8211  }
8212  if (empty($option_only)) {
8213  $out .= '</select>';
8214  }
8215 
8216  print $out;
8217 
8218  $this->db->free($resql);
8219  return $num;
8220  } else {
8221  dol_print_error($this->db);
8222  return -1;
8223  }
8224  }
8225 
8234  public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array())
8235  {
8236  global $langs;
8237 
8238  $ret = '';
8239 
8240  $ret .= '<div class="nowrap centpercent">';
8241  //$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
8242  $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor paddingright">';
8243  $ret .= '<span class="fas fa-filter linkobject boxfilter" title="Filter" id="idsubimgproductdistribution"></span>';
8244  $ret .= $langs->trans("Filters");
8245  $ret .= '</a>';
8246  //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
8247  $ret .= '<div name="search_component_params" class="search_component_params inline-block minwidth500 maxwidth300onsmartphone valignmiddle">';
8248  $texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
8249 
8250  $ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
8251  $ret .= '</div>';
8252  $ret .= '<input type="hidden" name="search_component_params_hidden" class="search_component_params_hidden" value="'.GETPOST("search_component_params_hidden").'">';
8253  // For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
8254  foreach ($arrayofcriterias as $criterias) {
8255  foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
8256  if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) continue;
8257  if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) continue;
8258  if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
8259  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
8260  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
8261  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
8262  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
8263  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
8264  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
8265  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
8266  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
8267  } else {
8268  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
8269  }
8270  }
8271  }
8272  $ret .= '</div>';
8273 
8274 
8275  return $ret;
8276  }
8277 
8287  public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
8288  {
8289  global $langs, $db, $user;
8290 
8291  $retstring = '';
8292 
8293  $TModels = array();
8294 
8295  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
8296  $formmail = new FormMail($db);
8297  $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
8298 
8299  if ($default) $TModels[0] = $langs->trans('DefaultMailModel');
8300  if ($result > 0) {
8301  foreach ($formmail->lines_model as $model) {
8302  $TModels[$model->id] = $model->label;
8303  }
8304  }
8305 
8306  $retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
8307 
8308  foreach ($TModels as $id_model=>$label_model) {
8309  $retstring .= '<option value="'.$id_model.'"';
8310  $retstring .= ">".$label_model."</option>";
8311  }
8312 
8313  $retstring .= "</select>";
8314 
8315  if ($addjscombo) $retstring .= ajax_combobox('select_'.$prefix.'model_mail');
8316 
8317  return $retstring;
8318  }
8319 }
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname= '')
Make an include_once using default root and alternate root if it fails.
selectDateToDate($set_time= '', $set_time_end= '', $prefix= 're', $empty=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
selectcontacts($socid, $selected= '', $htmlname= 'contactid', $showempty=0, $exclude= '', $limitto= '', $showfunction=0, $moreclass= '', $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).
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=0, $moreparamonempty= '', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
img_edit($titlealt= 'default', $float=0, $other= '')
Show logo editer/modifier fiche.
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.
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
Classe permettant la generation du formulaire html d&#39;envoi de mail unitaire Usage: $formail = new For...
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...
form_availability($page, $selected= '', $htmlname= 'availability', $addempty=0)
Show a form to select a delivery delay.
const STATUS_CLOSED
Warehouse closed, inactive.
selectSituationInvoices($selected= '', $socid=0)
Creates HTML last in cycle situation invoices selector.
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...
__construct($db)
Constructor.
Class to parse product price expressions.
load_cache_availability()
Charge dans cache la liste des délais de livraison possibles.
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.
const STATUS_OPEN_ALL
Warehouse open and operations for customer shipping, supplier dispatch, internal stock transfers/corr...
selectExpenseRanges($selected= '', $htmlname= 'fk_range', $useempty=0)
Return HTML to show the select ranges of expense range.
formInputReason($page, $selected= '', $htmlname= 'demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...) List found into table c_input_reason loaded by loadCacheInputReason.
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...
Class to manage contact/addresses.
load_cache_conditions_paiements()
Load into cache list of payment terms.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor &quot;?&quot;.
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name= 'massaction', $cssclass= 'checkforselect')
Generate select HTML to choose massaction.
select_users($selected= '', $htmlname= 'userid', $show_empty=0, $exclude=null, $disabled=0, $include= '', $enableonly= '', $force_entity= '0')
Return the HTML select list of users.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey= '', $novirtualstock=0)
constructProductListOption.
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...
selectUnits($selected= '', $htmlname= 'units', $showempty=0)
Creates HTML units selector (code =&gt; label)
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.
selectyesno($htmlname, $value= '', $option=0, $disabled=false, $useempty=0, $addjscombo=0)
Return an html string with a select combo box to choose yes or no.
Class to manage products or services.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_now($mode= 'auto')
Return date for now.
select_thirdparty_list($selected= '', $htmlname= 'socid', $filter= '', $showempty= '', $showtype=0, $forcecombo=0, $events=array(), $filterkey= '', $outputmode=0, $limit=0, $morecss= 'minwidth100', $moreparam= '', $multiple=false)
Output html form to select a third party.
if(!empty($_SERVER['MAIN_SHOW_TUNING_INFO'])) testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET...
Definition: main.inc.php:61
showLinkedObjectBlock($object, $morehtmlright= '', $compatibleImportElementsList=false)
Show linked object block.
Class to manage Dolibarr users.
Definition: user.class.php:44
select_country($selected= '', $htmlname= 'country_id', $htmloption= '', $maxlength=0, $morecss= 'minwidth300', $usecodeaskey= '', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array())
Return combo list of activated countries, into language of user.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass= 'checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear seach button.
select_contacts($socid, $selected= '', $htmlname= 'contactid', $showempty=0, $exclude= '', $limitto= '', $showfunction=0, $moreclass= '', $showsoc=0, $forcecombo=0, $events=array(), $options_only=false, $moreparam= '', $htmlid= '')
Return list of all contacts (for a third party or all)
dol_htmlentities($string, $flags=null, $encoding= 'UTF-8', $double_encode=false)
Replace htmlentities functions.
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete= 'resolve')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:391
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...
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
const TYPE_SERVICE
Service.
formSelectAccount($page, $selected= '', $htmlname= 'fk_account', $addempty=0)
Display form to select bank account.
form_conditions_reglement($page, $selected= '', $htmlname= 'cond_reglement_id', $addempty=0)
Show a form to select payment conditions.
const TYPE_PRODUCT
Regular product.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
editInPlace($object, $value, $htmlname, $condition, $inputType= 'textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:108
const STATUS_CLOSED
Closed status.
select_types_paiements($selected= '', $htmlname= 'paiementtype', $filtertype= '', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss= '')
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
$conf db
API class for accounts.
Definition: inc.php:54
select_conditions_paiements($selected=0, $htmlname= 'condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss= '')
Return list of payment modes.
Class to manage bank accounts.
selectExpense($selected= '', $htmlname= 'fk_c_type_fees', $useempty=0, $allchoice=1, $useid=0)
Return HTML to show a select of expense.
formconfirm($page, $title, $question, $action, $formquestion= '', $selectedchoice= '', $useajax=0, $height=0, $width=500, $disableformtag=0)
Show a confirmation HTML form or AJAX popup.
img_warning($titlealt= 'default', $moreatt= '', $morecss= 'pictowarning')
Show warning logo.
formSelectShippingMethod($page, $selected= '', $htmlname= 'shipping_method_id', $addempty=0)
Display form to select shipping mode.
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...
select2arrayoflanguage
Set array used for select2 translations.
currency_name($code_iso, $withcode= '', $outputlangs=null)
Return label of currency or code+label.
Class to manage hooks.
getImageFileNameForSize($file, $extName, $extImgTarget= '')
Return the filename of file to get the thumbs.
showFilterButtons()
Return HTML to show the search and clear seach button.
select_comptes($selected= '', $htmlname= 'accountid', $status=0, $filtre= '', $useempty=0, $moreattrib= '', $showcurrency=0, $morecss= '', $nooutput=0)
Return a HTML select list of bank accounts.
Class to manage generation of HTML components Only common components must be here.
selectInputReason($selected= '', $htmlname= 'demandreasonid', $exclude= '', $addempty=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
const STATUS_OPEN_INTERNAL
Warehouse open and operations for stock transfers/corrections allowed (not for customer shipping and ...
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname.
Class to manage third parties objects (customers, suppliers, prospects...)
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
Class to manage categories.
getServerTimeZoneInt($refgmtdate= 'now')
Return server timezone int.
Definition: date.lib.php:83
Class to manage projects.
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
price2num($amount, $rounding= '', $option=0)
Function that return a number with universal decimal format (decimal separator is &#39;...
selectCurrency($selected= '', $htmlname= 'currency_id', $mode=0)
Retourne la liste des devises, dans la langue de l&#39;utilisateur.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
Class to manage building of HTML components.
select_produits_fournisseurs_list($socid, $selected= '', $htmlname= 'productid', $filtertype= '', $filtre= '', $filterkey= '', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss= '', $showstockinlist=0)
Return list of suppliers products.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput= 'no')
Output a dimension with best unit.
select_incoterms($selected= '', $location_incoterms= '', $page= '', $htmlname= 'incoterm_id', $htmloption= '', $forcecombo=1, $events=array())
Return select list of incoterms.
img_picto($titlealt, $picto, $moreatt= '', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt= '', $morecss= '', $marginleftonlyshort=2)
Show picto whatever it&#39;s its name (generic 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())
Return select list of users.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array())
Output the component to make advanced search criteries.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart= '')
Return a path to have a the directory according to object where files are stored. ...
load_cache_types_paiements()
Charge dans cache la liste des types de paiements possibles.
showCheckAddButtons($cssclass= 'checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
form_project($page, $socid, $selected= '', $htmlname= 'projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0)
Show a form to select a project.
selectShippingMethod($selected= '', $htmlname= 'shipping_method_id', $filtre= '', $useempty=0, $moreattrib= '')
Return a HTML select list of shipping mode.
select_address($selected, $socid, $htmlname= 'address_id', $showempty=0)
Return list of delivery address.
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)
Return select list of users.
showbarcode(&$object, $width=100)
Return HTML code to output a barcode.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0)
Show a form + html select a date.
select_produits_fournisseurs($socid, $selected= '', $htmlname= 'productid', $filtertype= '', $filtre= '', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss= '')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
select_currency($selected= '', $htmlname= 'currency_id')
Retourne la liste des devises, dans la langue de l&#39;utilisateur.
select_product_fourn_price($productid, $htmlname= 'productfournpriceid', $selected_supplier= '')
Return list of suppliers prices for a product.
form_multicurrency_code($page, $selected= '', $htmlname= 'multicurrency_code')
Show form with multicurrency code.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages...
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.
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.
print $_SERVER["PHP_SELF"]
Edit parameters.
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)
Output a combo list with invoices qualified for a third party.
Class to manage standard extra languages.
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata= 'string', $editvalue= '', $extObject=null, $custommsg=null, $moreparam= '', $notabletag=0, $formatfunc= '', $paramid= 'id')
Output value of a field for an editable field.
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...
select_type_fees($selected= '', $htmlname= 'type', $showempty=0)
Return list of types of notes.
print
Draft customers invoices.
Definition: index.php:89
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
select_all_categories($type, $selected= '', $htmlname="parent", $maxlength=64, $markafterid=0, $outputmode=0, $include=0, $morecss= '')
Return list of categories having choosed type.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata= 'string', $moreparam= '', $fieldrequired=0, $notabletag=0, $paramid= 'id', $help= '')
Output key field for an editable field.
selectEstablishments($selected= '', $htmlname= 'entity', $status=0, $filtre= '', $useempty=0, $moreattrib= '')
Return a HTML select list of establishment.
load_cache_transport_mode()
Load in cache list of transport mode.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0)
Clean a string to keep only desirable HTML tags.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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) Si ...
form_users($page, $selected= '', $htmlname= 'userid', $exclude= '', $include= '')
Show a select form to choose a user.
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
form_thirdparty($page, $selected= '', $htmlname= 'socid', $filter= '', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0)
Output html select to select thirdparty.
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.
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= '')
Return list of products for a customer.
newToken()
Return the value of token currently saved into session with name &#39;newtoken&#39;.
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)
Output html form to select a third party.
print $_SERVER["PHP_SELF"] n
Edit parameters.
Definition: categories.php:101
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)
Return list of products for customer in Ajax if Ajax activated or go to select_produits_list.
Class to manage a WYSIWYG editor.
widgetForTranslation($fieldname, $object, $perm, $typeofdata= 'string', $check= '', $morecss= '')
Output edit in place form.
dol_trunc($string, $size=40, $trunc= 'right', $stringencoding= 'UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding &#39;...&#39; if string larger than length.
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.
select_dolgroups($selected= '', $htmlname= 'groupid', $show_empty=0, $exclude= '', $disabled=0, $include= '', $enableonly= '', $force_entity= '0', $multiple=false, $morecss= '')
Return select list of groups.
selectPriceBaseType($selected= '', $htmlname= 'price_base_type', $addjscombo=0)
Selection HT or TTC.
selectMultiCurrency($selected= '', $htmlname= 'multicurrency_code', $useempty=0, $filter= '', $excludeConfCurrency=false)
Return array of currencies in user language.
Class to manage invoices.
form_confirm($page, $title, $question, $action, $formquestion= '', $selectedchoice="", $useajax=0, $height=170, $width=500)
Show a confirmation HTML form or AJAX popup.
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.
const STATUS_DRAFT
Draft status.
selectModelMail($prefix, $modelType= '', $default=0, $addjscombo=0)
selectModelMail
select_export_model($selected= '', $htmlname= 'exportmodelid', $type= '', $useempty=0)
Return list of export templates.
form_multicurrency_rate($page, $rate= '', $htmlname= 'multicurrency_tx', $currency= '')
Show form with multicurrency rate.
selectTransportMode($selected= '', $htmlname= 'transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss= '')
Return list of transport mode for intracomm report.
form_modes_reglement($page, $selected= '', $htmlname= 'mode_reglement_id', $filtertype= '', $active=1, $addempty=0)
Show form with payment mode.
if(!defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN'
Draft customers invoices.
form_contacts($page, $societe, $selected= '', $htmlname= 'contactid')
Show forms to select a contact.
formSelectTransportMode($page, $selected= '', $htmlname= 'transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin= '1', $morecss= '', $textfordropdown= '')
Show information for admin users or standard users.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param= '')
Return URL we can use for advanced preview links.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:105
picto_from_langcode($codelang, $moreatt= '')
Return img flag of country for a language code or country code.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
Class to manage predefined suppliers products.
measuringUnitString($unit, $measuring_style= '', $scale= '', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
load_cache_vatrates($country_code)
Load into the cache vat rates of a country.
selectAvailabilityDelay($selected= '', $htmlname= 'availid', $filtertype= '', $addempty=0)
Retourne la liste des types de delais de livraison possibles.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $keepmoretags= '', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...