dolibarr  17.0.4
html.form.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5  * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6  * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7  * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9  * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10  * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11  * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12  * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13  * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14  * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15  * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17  * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18  * Copyright (C) 2014-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
19  * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20  * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
21  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22  * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23  * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24  * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25  *
26  * This program is free software; you can redistribute it and/or modify
27  * it under the terms of the GNU General Public License as published by
28  * the Free Software Foundation; either version 3 of the License, or
29  * (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program. If not, see <https://www.gnu.org/licenses/>.
38  */
39 
53 class Form
54 {
58  public $db;
59 
63  public $error = '';
64 
68  public $errors = array();
69 
70  public $num;
71 
72  // Cache arrays
73  public $cache_types_paiements = array();
74  public $cache_conditions_paiements = array();
75  public $cache_transport_mode = array();
76  public $cache_availability = array();
77  public $cache_demand_reason = array();
78  public $cache_types_fees = array();
79  public $cache_vatrates = array();
80 
81 
87  public function __construct($db)
88  {
89  $this->db = $db;
90  }
91 
108  public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
109  {
110  global $conf, $langs;
111 
112  $ret = '';
113 
114  // TODO change for compatibility
115  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) {
116  if (!empty($perm)) {
117  $tmp = explode(':', $typeofdata);
118  $ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
119  if ($fieldrequired) {
120  $ret .= '<span class="fieldrequired">';
121  }
122  if ($help) {
123  $ret .= $this->textwithpicto($langs->trans($text), $help);
124  } else {
125  $ret .= $langs->trans($text);
126  }
127  if ($fieldrequired) {
128  $ret .= '</span>';
129  }
130  $ret .= '</div>'."\n";
131  } else {
132  if ($fieldrequired) {
133  $ret .= '<span class="fieldrequired">';
134  }
135  if ($help) {
136  $ret .= $this->textwithpicto($langs->trans($text), $help);
137  } else {
138  $ret .= $langs->trans($text);
139  }
140  if ($fieldrequired) {
141  $ret .= '</span>';
142  }
143  }
144  } else {
145  if (empty($notabletag) && $perm) {
146  $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
147  }
148  if ($fieldrequired) {
149  $ret .= '<span class="fieldrequired">';
150  }
151  if ($help) {
152  $ret .= $this->textwithpicto($langs->trans($text), $help);
153  } else {
154  $ret .= $langs->trans($text);
155  }
156  if ($fieldrequired) {
157  $ret .= '</span>';
158  }
159  if (!empty($notabletag)) {
160  $ret .= ' ';
161  }
162  if (empty($notabletag) && $perm) {
163  $ret .= '</td>';
164  }
165  if (empty($notabletag) && $perm) {
166  $ret .= '<td class="right">';
167  }
168  if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) {
169  $ret .= '<a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&token='.newToken().'&'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
170  }
171  if (!empty($notabletag) && $notabletag == 1) {
172  $ret .= ' : ';
173  }
174  if (!empty($notabletag) && $notabletag == 3) {
175  $ret .= ' ';
176  }
177  if (empty($notabletag) && $perm) {
178  $ret .= '</td>';
179  }
180  if (empty($notabletag) && $perm) {
181  $ret .= '</tr></table>';
182  }
183  }
184 
185  return $ret;
186  }
187 
207  public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id', $gm = 'auto')
208  {
209  global $conf, $langs;
210 
211  $ret = '';
212 
213  // Check parameters
214  if (empty($typeofdata)) {
215  return 'ErrorBadParameter typeofdata is empty';
216  }
217  // Clean paramater $typeofdata
218  if ($typeofdata == 'datetime') {
219  $typeofdata = 'dayhour';
220  }
221  $reg = array();
222  if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
223  if ($reg[1] == 'varchar') {
224  $typeofdata = 'string';
225  } elseif ($reg[1] == 'int') {
226  $typeofdata = 'numeric';
227  } else {
228  return 'ErrorBadParameter '.$typeofdata;
229  }
230  }
231 
232  // When option to edit inline is activated
233  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
234  $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
235  } else {
236  $editmode = (GETPOST('action', 'aZ09') == 'edit'.$htmlname);
237  if ($editmode) {
238  $ret .= "\n";
239  $ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">';
240  $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
241  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
242  $ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
243  if (empty($notabletag)) {
244  $ret .= '<table class="nobordernopadding centpercent">';
245  }
246  if (empty($notabletag)) {
247  $ret .= '<tr><td>';
248  }
249  if (preg_match('/^(string|safehtmlstring|email|url)/', $typeofdata)) {
250  $tmp = explode(':', $typeofdata);
251  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.(empty($tmp[1]) ? '' : ' size="'.$tmp[1].'"').' autofocus>';
252  } elseif (preg_match('/^(integer)/', $typeofdata)) {
253  $tmp = explode(':', $typeofdata);
254  $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
255  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.$valuetoshow.'"'.(empty($tmp[1]) ? '' : ' size="'.$tmp[1].'"').' autofocus>';
256  } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
257  $tmp = explode(':', $typeofdata);
258  $valuetoshow = price2num($editvalue ? $editvalue : $value);
259  $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ? price($valuetoshow) : '').'"'.(empty($tmp[1]) ? '' : ' size="'.$tmp[1].'"').' autofocus>';
260  } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
261  $tmp = explode(':', $typeofdata);
262  $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
263  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
264  $tmp = explode(':', $typeofdata);
265  $cols = (empty($tmp[2]) ? '' : $tmp[2]);
266  $morealt = '';
267  if (preg_match('/%/', $cols)) {
268  $morealt = ' style="width: '.$cols.'"';
269  $cols = '';
270  }
271 
272  $valuetoshow = ($editvalue ? $editvalue : $value);
273  $ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.(empty($tmp[1]) ? '20' : $tmp[1]).'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'" autofocus>';
274  // textarea convert automatically entities chars into simple chars.
275  // 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.
276  $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
277  $ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
278  $ret .= '</textarea>';
279  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
280  $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0, 0, '', '', '', '', 1, '', '', $gm);
281  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
282  $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0, 0, '', '', '', '', 1, '', '', $gm);
283  } elseif (preg_match('/^select;/', $typeofdata)) {
284  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
285  $arraylist = array();
286  foreach ($arraydata as $val) {
287  $tmp = explode(':', $val);
288  $tmpkey = str_replace('|', ':', $tmp[0]);
289  $arraylist[$tmpkey] = $tmp[1];
290  }
291  $ret .= $this->selectarray($htmlname, $arraylist, $value);
292  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
293  $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
294  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
295  $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? '100' : $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? 0 : $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? '20' : $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
296  $ret .= $doleditor->Create(1);
297  }
298  if (empty($notabletag)) {
299  $ret .= '</td>';
300  }
301 
302  // Button save-cancel
303  if (empty($notabletag)) {
304  $ret .= '<td class="left">';
305  }
306  //else $ret.='<div class="clearboth"></div>';
307  $ret .= '<input type="submit" class="smallpaddingimp button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
308  if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
309  $ret .= '<br>'."\n";
310  }
311  $ret .= '<input type="submit" class="smallpaddingimp button button-cancel'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
312  if (empty($notabletag)) {
313  $ret .= '</td>';
314  }
315 
316  if (empty($notabletag)) {
317  $ret .= '</tr></table>'."\n";
318  }
319  $ret .= '</form>'."\n";
320  } else {
321  if (preg_match('/^(email)/', $typeofdata)) {
322  $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
323  } elseif (preg_match('/^url/', $typeofdata)) {
324  $ret .= dol_print_url($value, '_blank', 32, 1);
325  } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
326  $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
327  } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
328  $tmp = explode(':', $typeofdata);
329  $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($tmp[1] ? $tmp[1] : '') . '/>';
330  } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
331  $ret .= dol_htmlentitiesbr($value);
332  } elseif (preg_match('/^safehtmlstring/', $typeofdata)) {
333  $ret .= dol_string_onlythesehtmltags($value);
334  } elseif (preg_match('/^restricthtml/', $typeofdata)) {
335  $ret .= dol_string_onlythesehtmltags($value);
336  } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
337  $ret .= '<span class="valuedate">'.dol_print_date($value, 'day', $gm).'</span>';
338  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
339  $ret .= '<span class="valuedate">'.dol_print_date($value, 'dayhour', $gm).'</span>';
340  } elseif (preg_match('/^select;/', $typeofdata)) {
341  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
342  $arraylist = array();
343  foreach ($arraydata as $val) {
344  $tmp = explode(':', $val);
345  $arraylist[$tmp[0]] = $tmp[1];
346  }
347  $ret .= $arraylist[$value];
348  if ($htmlname == 'fk_product_type') {
349  if ($value == 0) {
350  $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"').$ret;
351  } else {
352  $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"').$ret;
353  }
354  }
355  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
356  $tmpcontent = dol_htmlentitiesbr($value);
357  if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
358  $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
359  $firstline = preg_replace('/[\n\r].*/', '', $firstline);
360  $tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
361  }
362  // We dont use dol_escape_htmltag to get the html formating active, but this need we must also
363  // clean data from some dangerous html
364  $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent));
365  } else {
366  $ret .= dol_escape_htmltag($value);
367  }
368 
369  if ($formatfunc && method_exists($object, $formatfunc)) {
370  $ret = $object->$formatfunc($ret);
371  }
372  }
373  }
374  return $ret;
375  }
376 
388  public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
389  {
390  global $conf, $langs, $extralanguages;
391 
392  $result = '';
393 
394  // List of extra languages
395  $arrayoflangcode = array();
396  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
397  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
398  }
399 
400  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
401  if (!is_object($extralanguages)) {
402  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
403  $extralanguages = new ExtraLanguages($this->db);
404  }
405  $extralanguages->fetch_name_extralanguages('societe');
406 
407  if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
408  return ''; // No extralang field to show
409  }
410 
411  $result .= '<!-- Widget for translation -->'."\n";
412  $result .= '<div class="inline-block paddingleft image-'.$object->element.'-'.$fieldname.'">';
413  $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
414  $result .= $s;
415  $result .= '</div>';
416 
417  $result .= '<div class="inline-block hidden field-'.$object->element.'-'.$fieldname.'">';
418 
419  $resultforextrlang = '';
420  foreach ($arrayoflangcode as $langcode) {
421  $valuetoshow = GETPOSTISSET('field-'.$object->element."-".$fieldname."-".$langcode) ? GETPOST('field-'.$object->element.'-'.$fieldname."-".$langcode, $check) : '';
422  if (empty($valuetoshow)) {
423  $object->fetchValuesForExtraLanguages();
424  //var_dump($object->array_languages);
425  $valuetoshow = $object->array_languages[$fieldname][$langcode];
426  }
427 
428  $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
429  $resultforextrlang .= $s;
430 
431  // TODO Use the showInputField() method of ExtraLanguages object
432  if ($typeofdata == 'textarea') {
433  $resultforextrlang .= '<textarea name="field-'.$object->element."-".$fieldname."-".$langcode.'" id="'.$fieldname."-".$langcode.'" class="'.$morecss.'" rows="'.ROWS_2.'" wrap="soft">';
434  $resultforextrlang .= $valuetoshow;
435  $resultforextrlang .= '</textarea>';
436  } else {
437  $resultforextrlang .= '<input type="text" class="inputfieldforlang '.($morecss ? ' '.$morecss : '').'" name="field-'.$object->element.'-'.$fieldname.'-'.$langcode.'" value="'.$valuetoshow.'">';
438  }
439  }
440  $result .= $resultforextrlang;
441 
442  $result .= '</div>';
443  $result .= '<script>$(".image-'.$object->element.'-'.$fieldname.'").click(function() { console.log("Toggle lang widget"); jQuery(".field-'.$object->element.'-'.$fieldname.'").toggle(); });</script>';
444  }
445 
446  return $result;
447  }
448 
462  protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
463  {
464  global $conf;
465 
466  $out = '';
467 
468  // Check parameters
469  if (preg_match('/^text/', $inputType)) {
470  $value = dol_nl2br($value);
471  } elseif (preg_match('/^numeric/', $inputType)) {
472  $value = price($value);
473  } elseif ($inputType == 'day' || $inputType == 'datepicker') {
474  $value = dol_print_date($value, 'day');
475  }
476 
477  if ($condition) {
478  $element = false;
479  $table_element = false;
480  $fk_element = false;
481  $loadmethod = false;
482  $savemethod = false;
483  $ext_element = false;
484  $button_only = false;
485  $inputOption = '';
486  $rows = '';
487  $cols = '';
488 
489  if (is_object($object)) {
490  $element = $object->element;
491  $table_element = $object->table_element;
492  $fk_element = $object->id;
493  }
494 
495  if (is_object($extObject)) {
496  $ext_element = $extObject->element;
497  }
498 
499  if (preg_match('/^(string|email|numeric)/', $inputType)) {
500  $tmp = explode(':', $inputType);
501  $inputType = $tmp[0];
502  if (!empty($tmp[1])) {
503  $inputOption = $tmp[1];
504  }
505  if (!empty($tmp[2])) {
506  $savemethod = $tmp[2];
507  }
508  $out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
509  } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
510  $tmp = explode(':', $inputType);
511  $inputType = $tmp[0];
512  if (!empty($tmp[1])) {
513  $inputOption = $tmp[1];
514  }
515  if (!empty($tmp[2])) {
516  $savemethod = $tmp[2];
517  }
518 
519  $out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
520  } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
521  $tmp = explode(':', $inputType);
522  $inputType = $tmp[0];
523  $loadmethod = $tmp[1];
524  if (!empty($tmp[2])) {
525  $savemethod = $tmp[2];
526  }
527  if (!empty($tmp[3])) {
528  $button_only = true;
529  }
530  } elseif (preg_match('/^textarea/', $inputType)) {
531  $tmp = explode(':', $inputType);
532  $inputType = $tmp[0];
533  $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
534  $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
535  } elseif (preg_match('/^ckeditor/', $inputType)) {
536  $tmp = explode(':', $inputType);
537  $inputType = $tmp[0];
538  $toolbar = $tmp[1];
539  if (!empty($tmp[2])) {
540  $width = $tmp[2];
541  }
542  if (!empty($tmp[3])) {
543  $heigth = $tmp[3];
544  }
545  if (!empty($tmp[4])) {
546  $savemethod = $tmp[4];
547  }
548 
549  if (isModEnabled('fckeditor')) {
550  $out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
551  } else {
552  $inputType = 'textarea';
553  }
554  }
555 
556  $out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
557  $out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
558  $out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
559  $out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
560  if (!empty($savemethod)) {
561  $out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
562  }
563  if (!empty($ext_element)) {
564  $out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
565  }
566  if (!empty($custommsg)) {
567  if (is_array($custommsg)) {
568  if (!empty($custommsg['success'])) {
569  $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
570  }
571  if (!empty($custommsg['error'])) {
572  $out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
573  }
574  } else {
575  $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
576  }
577  }
578  if ($inputType == 'textarea') {
579  $out .= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n";
580  $out .= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n";
581  }
582  $out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
583  $out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n";
584  } else {
585  $out = $value;
586  }
587 
588  return $out;
589  }
590 
609  public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
610  {
611  if ($incbefore) {
612  $text = $incbefore.$text;
613  }
614  if (!$htmltext) {
615  return $text;
616  }
617  $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
618 
619  $tag = 'td';
620  if ($notabs == 2) {
621  $tag = 'div';
622  }
623  if ($notabs == 3) {
624  $tag = 'span';
625  }
626  // Sanitize tooltip
627  $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
628 
629  $extrastyle = '';
630  if ($direction < 0) {
631  $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : '');
632  $extrastyle = 'padding: 0px; padding-left: 3px;';
633  }
634  if ($direction > 0) {
635  $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : '');
636  $extrastyle = 'padding: 0px; padding-right: 3px;';
637  }
638 
639  $classfortooltip = 'classfortooltip';
640 
641  $s = '';
642  $textfordialog = '';
643 
644  if ($tooltiptrigger == '') {
645  $htmltext = str_replace('"', '&quot;', $htmltext);
646  } else {
647  $classfortooltip = 'classfortooltiponclick';
648  $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
649  }
650  if ($tooltipon == 2 || $tooltipon == 3) {
651  $paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
652  if ($tooltiptrigger == '') {
653  $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
654  } else {
655  $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
656  }
657  } else {
658  $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
659  }
660  if ($tooltipon == 1 || $tooltipon == 3) {
661  $paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
662  if ($tooltiptrigger == '') {
663  $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
664  } else {
665  $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
666  }
667  } else {
668  $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
669  }
670  if (empty($notabs)) {
671  $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
672  } elseif ($notabs == 2) {
673  $s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">';
674  }
675  // Define value if value is before
676  if ($direction < 0) {
677  $s .= '<'.$tag.$paramfortooltipimg;
678  if ($tag == 'td') {
679  $s .= ' class="valigntop" width="14"';
680  }
681  $s .= '>'.$textfordialog.$img.'</'.$tag.'>';
682  }
683  // Use another method to help avoid having a space in value in order to use this value with jquery
684  // Define label
685  if ((string) $text != '') {
686  $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
687  }
688  // Define value if value is after
689  if ($direction > 0) {
690  $s .= '<'.$tag.$paramfortooltipimg;
691  if ($tag == 'td') {
692  $s .= ' class="valignmiddle" width="14"';
693  }
694  $s .= '>'.$textfordialog.$img.'</'.$tag.'>';
695  }
696  if (empty($notabs)) {
697  $s .= '</tr></table>';
698  } elseif ($notabs == 2) {
699  $s .= '</div>';
700  }
701 
702  return $s;
703  }
704 
719  public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
720  {
721  global $conf, $langs;
722 
723  //For backwards compatibility
724  if ($type == '0') {
725  $type = 'info';
726  } elseif ($type == '1') {
727  $type = 'help';
728  }
729 
730  if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
731  $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
732  }
733 
734  $alt = '';
735  if ($tooltiptrigger) {
736  $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
737  }
738 
739  // If info or help with no javascript, show only text
740  if (empty($conf->use_javascript_ajax)) {
741  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
742  return $text;
743  } else {
744  $alt = $htmltext;
745  $htmltext = '';
746  }
747  }
748 
749  // If info or help with smartphone, show only text (tooltip hover can't works)
750  if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
751  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
752  return $text;
753  }
754  }
755  // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
756  //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
757  //{
758  //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>';
759  //}
760 
761  $img = '';
762  if ($type == 'info') {
763  $img = img_help(0, $alt);
764  } elseif ($type == 'help') {
765  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
766  } elseif ($type == 'helpclickable') {
767  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
768  } elseif ($type == 'superadmin') {
769  $img = img_picto($alt, 'redstar');
770  } elseif ($type == 'admin') {
771  $img = img_picto($alt, 'star');
772  } elseif ($type == 'warning') {
773  $img = img_warning($alt);
774  } elseif ($type != 'none') {
775  $img = img_picto($alt, $type); // $type can be an image path
776  }
777 
778  return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
779  }
780 
791  public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
792  {
793  global $conf, $langs, $hookmanager;
794 
795 
796  $disabled = 0;
797  $ret = '<div class="centpercent center">';
798  $ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>';
799 
800  // 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.
801  $parameters = array();
802  $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
803  // check if there is a mass action
804  if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
805  return;
806  }
807  if (empty($reshook)) {
808  $ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
809  foreach ($arrayofaction as $code => $label) {
810  $ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
811  }
812  }
813  $ret .= $hookmanager->resPrint;
814 
815  $ret .= '</select>';
816 
817  if (empty($conf->dol_optimize_smallscreen)) {
818  $ret .= ajax_combobox('.'.$name.'select');
819  }
820 
821  // 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
822  $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.
823  $ret .= '<input type="submit" disabled name="confirmmassaction"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display: none"').' class="button smallpaddingimp'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
824  $ret .= '</div>';
825 
826  if (!empty($conf->use_javascript_ajax)) {
827  $ret .= '<!-- JS CODE TO ENABLE mass action select -->
828  <script>
829  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 */
830  {
831  atleastoneselected=0;
832  jQuery("."+cssclass).each(function( index ) {
833  /* console.log( index + ": " + $( this ).text() ); */
834  if ($(this).is(\':checked\')) atleastoneselected++;
835  });
836 
837  console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
838 
839  if (atleastoneselected || '.$alwaysvisible.')
840  {
841  jQuery("."+name).show();
842  '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').'
843  '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').'
844  }
845  else
846  {
847  jQuery("."+name).hide();
848  jQuery("."+name+"other").hide();
849  }
850  }
851 
852  jQuery(document).ready(function () {
853  initCheckForSelect(0, "' . $name.'", "'.$cssclass.'");
854  jQuery(".' . $cssclass.'").click(function() {
855  initCheckForSelect(1, "'.$name.'", "'.$cssclass.'");
856  });
857  jQuery(".' . $name.'select").change(function() {
858  var massaction = $( this ).val();
859  var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
860  if (massaction == "builddoc")
861  {
862  urlform = urlform + "#show_files";
863  }
864  $( this ).closest("form").attr("action", urlform);
865  console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform);
866  /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
867  if ($(this).val() != \'0\')
868  {
869  jQuery(".' . $name.'confirmed").prop(\'disabled\', false);
870  jQuery(".' . $name.'other").hide(); /* To disable if another div was open */
871  jQuery(".' . $name.'"+massaction).show();
872  }
873  else
874  {
875  jQuery(".' . $name.'confirmed").prop(\'disabled\', true);
876  jQuery(".' . $name.'other").hide(); /* To disable any div open */
877  }
878  });
879  });
880  </script>
881  ';
882  }
883 
884  return $ret;
885  }
886 
887  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
904  public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
905  {
906  // phpcs:enable
907  global $conf, $langs, $mysoc;
908 
909  $langs->load("dict");
910 
911  $out = '';
912  $countryArray = array();
913  $favorite = array();
914  $label = array();
915  $atleastonefavorite = 0;
916 
917  $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
918  $sql .= " FROM ".$this->db->prefix()."c_country";
919  $sql .= " WHERE active > 0";
920  //$sql.= " ORDER BY code ASC";
921 
922  dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
923  $resql = $this->db->query($sql);
924  if ($resql) {
925  $out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
926  $num = $this->db->num_rows($resql);
927  $i = 0;
928  if ($num) {
929  while ($i < $num) {
930  $obj = $this->db->fetch_object($resql);
931 
932  $countryArray[$i]['rowid'] = $obj->rowid;
933  $countryArray[$i]['code_iso'] = $obj->code_iso;
934  $countryArray[$i]['code_iso3'] = $obj->code_iso3;
935  $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 : ''));
936  $countryArray[$i]['favorite'] = $obj->favorite;
937  $countryArray[$i]['eec'] = $obj->eec;
938  $favorite[$i] = $obj->favorite;
939  $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
940  $i++;
941  }
942 
943  if (empty($disablefavorites)) {
944  $array1_sort_order = SORT_DESC;
945  $array2_sort_order = SORT_ASC;
946  array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
947  } else {
948  $countryArray = dol_sort_array($countryArray, 'label');
949  }
950 
951  if ($showempty) {
952  if (is_numeric($showempty)) {
953  $out .= '<option value="">&nbsp;</option>'."\n";
954  } else {
955  $out .= '<option value="">'.$langs->trans($showempty).'</option>'."\n";
956  }
957  }
958 
959  if ($addspecialentries) { // Add dedicated entries for groups of countries
960  //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
961  $out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
962  $out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
963  if ($mysoc->isInEEC()) {
964  $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
965  }
966  $out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
967  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
968  }
969 
970  foreach ($countryArray as $row) {
971  //if (empty($showempty) && empty($row['rowid'])) continue;
972  if (empty($row['rowid'])) {
973  continue;
974  }
975  if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
976  continue; // exclude some countries
977  }
978 
979  if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
980  $atleastonefavorite++;
981  }
982  if (empty($row['favorite']) && $atleastonefavorite) {
983  $atleastonefavorite = 0;
984  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
985  }
986 
987  $labeltoshow = '';
988  if ($row['label']) {
989  $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
990  } else {
991  $labeltoshow .= '&nbsp;';
992  }
993  if ($row['code_iso']) {
994  $labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>';
995  if (empty($hideflags)) {
996  $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
997  $labeltoshow = $tmpflag.' '.$labeltoshow;
998  }
999  }
1000 
1001  if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1002  $out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" selected data-html="'.dol_escape_htmltag($labeltoshow).'" data-eec="'.((int) $row['eec']).'">';
1003  } else {
1004  $out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" data-html="'.dol_escape_htmltag($labeltoshow).'" data-eec="'.((int) $row['eec']).'">';
1005  }
1006  $out .= $labeltoshow;
1007  $out .= '</option>'."\n";
1008  }
1009  }
1010  $out .= '</select>';
1011  } else {
1012  dol_print_error($this->db);
1013  }
1014 
1015  // Make select dynamic
1016  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1017  $out .= ajax_combobox('select'.$htmlname, array(), 0, 0, 'resolve');
1018 
1019  return $out;
1020  }
1021 
1022  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1036  public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1037  {
1038  // phpcs:enable
1039  global $conf, $langs;
1040 
1041  $langs->load("dict");
1042 
1043  $out = '';
1044  $moreattrib = '';
1045  $incotermArray = array();
1046 
1047  $sql = "SELECT rowid, code";
1048  $sql .= " FROM ".$this->db->prefix()."c_incoterms";
1049  $sql .= " WHERE active > 0";
1050  $sql .= " ORDER BY code ASC";
1051 
1052  dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
1053  $resql = $this->db->query($sql);
1054  if ($resql) {
1055  if ($conf->use_javascript_ajax && !$forcecombo) {
1056  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1057  $out .= ajax_combobox($htmlname, $events);
1058  }
1059 
1060  if (!empty($page)) {
1061  $out .= '<form method="post" action="'.$page.'">';
1062  $out .= '<input type="hidden" name="action" value="set_incoterms">';
1063  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
1064  }
1065 
1066  $out .= '<select id="'.$htmlname.'" class="flat selectincoterm width75" name="'.$htmlname.'" '.$htmloption.'>';
1067  $out .= '<option value="0">&nbsp;</option>';
1068  $num = $this->db->num_rows($resql);
1069  $i = 0;
1070  if ($num) {
1071  while ($i < $num) {
1072  $obj = $this->db->fetch_object($resql);
1073  $incotermArray[$i]['rowid'] = $obj->rowid;
1074  $incotermArray[$i]['code'] = $obj->code;
1075  $i++;
1076  }
1077 
1078  foreach ($incotermArray as $row) {
1079  if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1080  $out .= '<option value="'.$row['rowid'].'" selected>';
1081  } else {
1082  $out .= '<option value="'.$row['rowid'].'">';
1083  }
1084 
1085  if ($row['code']) {
1086  $out .= $row['code'];
1087  }
1088 
1089  $out .= '</option>';
1090  }
1091  }
1092  $out .= '</select>';
1093 
1094  if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1095  $out .= ajax_multiautocompleter('location_incoterms', '', DOL_URL_ROOT.'/core/ajax/locationincoterms.php')."\n";
1096  $moreattrib .= ' autocomplete="off"';
1097  }
1098  $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="'.$location_incoterms.'">'."\n";
1099 
1100  if (!empty($page)) {
1101  $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="'.$langs->trans("Modify").'"></form>';
1102  }
1103  } else {
1104  dol_print_error($this->db);
1105  }
1106 
1107  return $out;
1108  }
1109 
1110  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1122  public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1123  {
1124  // phpcs:enable
1125  global $langs, $conf;
1126 
1127  // If product & services are enabled or both disabled.
1128  if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1129  || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1130  if (empty($hidetext)) {
1131  print $langs->trans("Type").': ';
1132  }
1133  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
1134  if ($showempty) {
1135  print '<option value="-1"';
1136  if ($selected == -1) {
1137  print ' selected';
1138  }
1139  print '>&nbsp;</option>';
1140  }
1141 
1142  print '<option value="0"';
1143  if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1144  print ' selected';
1145  }
1146  print '>'.$langs->trans("Product");
1147 
1148  print '<option value="1"';
1149  if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1150  print ' selected';
1151  }
1152  print '>'.$langs->trans("Service");
1153 
1154  print '</select>';
1155  print ajax_combobox('select_'.$htmlname);
1156  //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1157  }
1158  if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1159  print $langs->trans("Service");
1160  print '<input type="hidden" name="'.$htmlname.'" value="1">';
1161  }
1162  if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1163  print $langs->trans("Product");
1164  print '<input type="hidden" name="'.$htmlname.'" value="0">';
1165  }
1166  if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1167  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
1168  }
1169  }
1170 
1171  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1177  public function load_cache_types_fees()
1178  {
1179  // phpcs:enable
1180  global $langs;
1181 
1182  $num = count($this->cache_types_fees);
1183  if ($num > 0) {
1184  return 0; // Cache already loaded
1185  }
1186 
1187  dol_syslog(__METHOD__, LOG_DEBUG);
1188 
1189  $langs->load("trips");
1190 
1191  $sql = "SELECT c.code, c.label";
1192  $sql .= " FROM ".$this->db->prefix()."c_type_fees as c";
1193  $sql .= " WHERE active > 0";
1194 
1195  $resql = $this->db->query($sql);
1196  if ($resql) {
1197  $num = $this->db->num_rows($resql);
1198  $i = 0;
1199 
1200  while ($i < $num) {
1201  $obj = $this->db->fetch_object($resql);
1202 
1203  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1204  $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1205  $this->cache_types_fees[$obj->code] = $label;
1206  $i++;
1207  }
1208 
1209  asort($this->cache_types_fees);
1210 
1211  return $num;
1212  } else {
1213  dol_print_error($this->db);
1214  return -1;
1215  }
1216  }
1217 
1218  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1227  public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1228  {
1229  // phpcs:enable
1230  global $user, $langs;
1231 
1232  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1233 
1234  $this->load_cache_types_fees();
1235 
1236  print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1237  if ($showempty) {
1238  print '<option value="-1"';
1239  if ($selected == -1) {
1240  print ' selected';
1241  }
1242  print '>&nbsp;</option>';
1243  }
1244 
1245  foreach ($this->cache_types_fees as $key => $value) {
1246  print '<option value="'.$key.'"';
1247  if ($key == $selected) {
1248  print ' selected';
1249  }
1250  print '>';
1251  print $value;
1252  print '</option>';
1253  }
1254 
1255  print '</select>';
1256  if ($user->admin) {
1257  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1258  }
1259  }
1260 
1261 
1262  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1284  public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array(), $showcode = 0)
1285  {
1286  // phpcs:enable
1287  global $conf, $user, $langs;
1288 
1289  $out = '';
1290 
1291  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1292  if (is_null($ajaxoptions)) {
1293  $ajaxoptions = array();
1294  }
1295 
1296  require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1297 
1298  // No immediate load of all database
1299  $placeholder = '';
1300  if ($selected && empty($selected_input_value)) {
1301  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1302  $societetmp = new Societe($this->db);
1303  $societetmp->fetch($selected);
1304  $selected_input_value = $societetmp->name;
1305  unset($societetmp);
1306  }
1307 
1308  // mode 1
1309  $urloption = 'htmlname='.urlencode(str_replace('.', '_', $htmlname)).'&outjson=1&filter='.urlencode($filter).(empty($excludeids) ? '' : '&excludeids='.join(',', $excludeids)).($showtype ? '&showtype='.urlencode($showtype) : '').($showcode ? '&showcode='.urlencode($showcode) : '');
1310 
1311  $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
1312  if (empty($hidelabel)) {
1313  print $langs->trans("RefOrLabel").' : ';
1314  } elseif ($hidelabel > 1) {
1315  $placeholder = $langs->trans("RefOrLabel");
1316  if ($hidelabel == 2) {
1317  $out .= img_picto($langs->trans("Search"), 'search');
1318  }
1319  }
1320  $out .= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '').' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1321  if ($hidelabel == 3) {
1322  $out .= img_picto($langs->trans("Search"), 'search');
1323  }
1324 
1325  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1326  } else {
1327  // Immediate load of all database
1328  $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1329  }
1330 
1331  return $out;
1332  }
1333 
1334  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1356  public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array(), $showcode = 0)
1357  {
1358  // phpcs:enable
1359  global $conf, $user, $langs;
1360  global $hookmanager;
1361 
1362  $out = '';
1363  $num = 0;
1364  $outarray = array();
1365 
1366  if ($selected === '') {
1367  $selected = array();
1368  } elseif (!is_array($selected)) {
1369  $selected = array($selected);
1370  }
1371 
1372  // Clean $filter that may contains sql conditions so sql code
1373  if (function_exists('testSqlAndScriptInject')) {
1374  if (testSqlAndScriptInject($filter, 3) > 0) {
1375  $filter = '';
1376  }
1377  }
1378 
1379  // We search companies
1380  $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1381  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1382  $sql .= ", s.address, s.zip, s.town";
1383  $sql .= ", dictp.code as country_code";
1384  }
1385  $sql .= " FROM ".$this->db->prefix()."societe as s";
1386  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1387  $sql .= " LEFT JOIN ".$this->db->prefix()."c_country as dictp ON dictp.rowid = s.fk_pays";
1388  }
1389  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1390  $sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
1391  }
1392  $sql .= " WHERE s.entity IN (".getEntity('societe').")";
1393  if (!empty($user->socid)) {
1394  $sql .= " AND s.rowid = ".((int) $user->socid);
1395  }
1396  if ($filter) {
1397  $sql .= " AND (".$filter.")";
1398  }
1399  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1400  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
1401  }
1402  if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1403  $sql .= " AND s.status <> 0";
1404  }
1405  if (!empty($excludeids)) {
1406  $sql .= " AND s.rowid NOT IN (".$this->db->sanitize(join(',', $excludeids)).")";
1407  }
1408  // Add where from hooks
1409  $parameters = array();
1410  $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1411  $sql .= $hookmanager->resPrint;
1412  // Add criteria
1413  if ($filterkey && $filterkey != '') {
1414  $sql .= " AND (";
1415  $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1416  // For natural search
1417  $scrit = explode(' ', $filterkey);
1418  $i = 0;
1419  if (count($scrit) > 1) {
1420  $sql .= "(";
1421  }
1422  foreach ($scrit as $crit) {
1423  if ($i > 0) {
1424  $sql .= " AND ";
1425  }
1426  $sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1427  $i++;
1428  }
1429  if (count($scrit) > 1) {
1430  $sql .= ")";
1431  }
1432  if (isModEnabled('barcode')) {
1433  $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1434  }
1435  $sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1436  $sql .= " OR s.name_alias LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.tva_intra LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1437  $sql .= ")";
1438  }
1439  $sql .= $this->db->order("nom", "ASC");
1440  $sql .= $this->db->plimit($limit, 0);
1441 
1442  // Build output string
1443  dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1444  $resql = $this->db->query($sql);
1445  if ($resql) {
1446  if (!$forcecombo) {
1447  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1448  $out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1449  }
1450 
1451  // Construct $out and $outarray
1452  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1453 
1454  $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1455  if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1456  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1457  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1458  if ($showempty && !is_numeric($showempty)) {
1459  $textifempty = $langs->trans($showempty);
1460  } else {
1461  $textifempty .= $langs->trans("All");
1462  }
1463  }
1464  if ($showempty) {
1465  $out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.($textifempty ? $textifempty : '&nbsp;').'</span>').'">'.$textifempty.'</option>'."\n";
1466  }
1467 
1468  $companytemp = new Societe($this->db);
1469 
1470  $num = $this->db->num_rows($resql);
1471  $i = 0;
1472  if ($num) {
1473  while ($i < $num) {
1474  $obj = $this->db->fetch_object($resql);
1475  $label = '';
1476  if ($showcode || !empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) {
1477  if (($obj->client) && (!empty($obj->code_client))) {
1478  $label = $obj->code_client.' - ';
1479  }
1480  if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1481  $label .= $obj->code_fournisseur.' - ';
1482  }
1483  $label .= ' '.$obj->name;
1484  } else {
1485  $label = $obj->name;
1486  }
1487 
1488  if (!empty($obj->name_alias)) {
1489  $label .= ' ('.$obj->name_alias.')';
1490  }
1491 
1492  if (!empty($conf->global->SOCIETE_SHOW_VAT_IN_LIST) && !empty($obj->tva_intra)) {
1493  $label .= ' - '.$obj->tva_intra;
1494  }
1495 
1496  $labelhtml = $label;
1497 
1498  if ($showtype) {
1499  $companytemp->id = $obj->rowid;
1500  $companytemp->client = $obj->client;
1501  $companytemp->fournisseur = $obj->fournisseur;
1502  $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1503  if ($tmptype) {
1504  $labelhtml .= ' '.$tmptype;
1505  }
1506 
1507  if ($obj->client || $obj->fournisseur) {
1508  $label .= ' (';
1509  }
1510  if ($obj->client == 1 || $obj->client == 3) {
1511  $label .= $langs->trans("Customer");
1512  }
1513  if ($obj->client == 2 || $obj->client == 3) {
1514  $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1515  }
1516  if ($obj->fournisseur) {
1517  $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1518  }
1519  if ($obj->client || $obj->fournisseur) {
1520  $label .= ')';
1521  }
1522  }
1523 
1524  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1525  $s = ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : '');
1526  if (!empty($obj->country_code)) {
1527  $s .= ', '.$langs->trans('Country'.$obj->country_code);
1528  }
1529  $label .= $s;
1530  $labelhtml .= $s;
1531  }
1532 
1533  if (empty($outputmode)) {
1534  if (in_array($obj->rowid, $selected)) {
1535  $out .= '<option value="'.$obj->rowid.'" selected data-html="'.dol_escape_htmltag($labelhtml).'">'.$label.'</option>';
1536  } else {
1537  $out .= '<option value="'.$obj->rowid.'" data-html="'.dol_escape_htmltag($labelhtml).'">'.$label.'</option>';
1538  }
1539  } else {
1540  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label, 'labelhtml'=>$labelhtml));
1541  }
1542 
1543  $i++;
1544  if (($i % 10) == 0) {
1545  $out .= "\n";
1546  }
1547  }
1548  }
1549  $out .= '</select>'."\n";
1550  } else {
1551  dol_print_error($this->db);
1552  }
1553 
1554  $this->result = array('nbofthirdparties'=>$num);
1555 
1556  if ($outputmode) {
1557  return $outarray;
1558  }
1559  return $out;
1560  }
1561 
1562 
1563  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1574  public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1575  {
1576  // phpcs:enable
1577  global $langs, $conf;
1578 
1579  // On recherche les remises
1580  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1581  $sql .= " re.description, re.fk_facture_source";
1582  $sql .= " FROM ".$this->db->prefix()."societe_remise_except as re";
1583  $sql .= " WHERE re.fk_soc = ".(int) $socid;
1584  $sql .= " AND re.entity = ".$conf->entity;
1585  if ($filter) {
1586  $sql .= " AND ".$filter;
1587  }
1588  $sql .= " ORDER BY re.description ASC";
1589 
1590  dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1591  $resql = $this->db->query($sql);
1592  if ($resql) {
1593  print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1594  $num = $this->db->num_rows($resql);
1595 
1596  $qualifiedlines = $num;
1597 
1598  $i = 0;
1599  if ($num) {
1600  print '<option value="0">&nbsp;</option>';
1601  while ($i < $num) {
1602  $obj = $this->db->fetch_object($resql);
1603  $desc = dol_trunc($obj->description, 40);
1604  if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
1605  $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
1606  }
1607  if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
1608  $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
1609  }
1610  if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
1611  $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
1612  }
1613  if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
1614  $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
1615  }
1616 
1617  $selectstring = '';
1618  if ($selected > 0 && $selected == $obj->rowid) {
1619  $selectstring = ' selected';
1620  }
1621 
1622  $disabled = '';
1623  if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1624  $qualifiedlines--;
1625  $disabled = ' disabled';
1626  }
1627 
1628  if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1629  $tmpfac = new Facture($this->db);
1630  if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1631  $desc = $desc.' - '.$tmpfac->ref;
1632  }
1633  }
1634 
1635  print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1636  $i++;
1637  }
1638  }
1639  print '</select>';
1640  print ajax_combobox('select_'.$htmlname);
1641 
1642  return $qualifiedlines;
1643  } else {
1644  dol_print_error($this->db);
1645  return -1;
1646  }
1647  }
1648 
1649  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1670  public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1671  {
1672  // phpcs:enable
1673  print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1674  return $this->num;
1675  }
1676 
1701  public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1702  {
1703  global $conf, $langs, $hookmanager, $action;
1704 
1705  $langs->load('companies');
1706 
1707  if (empty($htmlid)) {
1708  $htmlid = $htmlname;
1709  }
1710  $num = 0;
1711 
1712  if ($selected === '') {
1713  $selected = array();
1714  } elseif (!is_array($selected)) {
1715  $selected = array($selected);
1716  }
1717  $out = '';
1718 
1719  if (!is_object($hookmanager)) {
1720  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1721  $hookmanager = new HookManager($this->db);
1722  }
1723 
1724  // We search third parties
1725  $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";
1726  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1727  $sql .= ", s.nom as company, s.town AS company_town";
1728  }
1729  $sql .= " FROM ".$this->db->prefix()."socpeople as sp";
1730  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1731  $sql .= " LEFT OUTER JOIN ".$this->db->prefix()."societe as s ON s.rowid=sp.fk_soc";
1732  }
1733  $sql .= " WHERE sp.entity IN (".getEntity('contact').")";
1734  if ($socid > 0 || $socid == -1) {
1735  $sql .= " AND sp.fk_soc = ".((int) $socid);
1736  }
1737  if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1738  $sql .= " AND sp.statut <> 0";
1739  }
1740  // Add where from hooks
1741  $parameters = array();
1742  $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1743  $sql .= $hookmanager->resPrint;
1744  $sql .= " ORDER BY sp.lastname ASC";
1745 
1746  dol_syslog(get_class($this)."::selectcontacts", LOG_DEBUG);
1747  $resql = $this->db->query($sql);
1748  if ($resql) {
1749  $num = $this->db->num_rows($resql);
1750 
1751  if ($htmlname != 'none' && !$options_only) {
1752  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1753  }
1754 
1755  if ($showempty && ! is_numeric($showempty)) {
1756  $textforempty = $showempty;
1757  $out .= '<option class="optiongrey" value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>'.$textforempty.'</option>';
1758  } else {
1759  if (($showempty == 1 || ($showempty == 3 && $num > 1)) && ! $multiple) {
1760  $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1761  }
1762  if ($showempty == 2) {
1763  $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1764  }
1765  }
1766 
1767  $i = 0;
1768  if ($num) {
1769  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1770  $contactstatic = new Contact($this->db);
1771 
1772  while ($i < $num) {
1773  $obj = $this->db->fetch_object($resql);
1774 
1775  // Set email (or phones) and town extended infos
1776  $extendedInfos = '';
1777  if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1778  $extendedInfos = array();
1779  $email = trim($obj->email);
1780  if (!empty($email)) {
1781  $extendedInfos[] = $email;
1782  } else {
1783  $phone = trim($obj->phone);
1784  $phone_perso = trim($obj->phone_perso);
1785  $phone_mobile = trim($obj->phone_mobile);
1786  if (!empty($phone)) {
1787  $extendedInfos[] = $phone;
1788  }
1789  if (!empty($phone_perso)) {
1790  $extendedInfos[] = $phone_perso;
1791  }
1792  if (!empty($phone_mobile)) {
1793  $extendedInfos[] = $phone_mobile;
1794  }
1795  }
1796  $contact_town = trim($obj->contact_town);
1797  $company_town = trim($obj->company_town);
1798  if (!empty($contact_town)) {
1799  $extendedInfos[] = $contact_town;
1800  } elseif (!empty($company_town)) {
1801  $extendedInfos[] = $company_town;
1802  }
1803  $extendedInfos = implode(' - ', $extendedInfos);
1804  if (!empty($extendedInfos)) {
1805  $extendedInfos = ' - '.$extendedInfos;
1806  }
1807  }
1808 
1809  $contactstatic->id = $obj->rowid;
1810  $contactstatic->lastname = $obj->lastname;
1811  $contactstatic->firstname = $obj->firstname;
1812  if ($obj->statut == 1) {
1813  if ($htmlname != 'none') {
1814  $disabled = 0;
1815  if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1816  $disabled = 1;
1817  }
1818  if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1819  $disabled = 1;
1820  }
1821  if (!empty($selected) && in_array($obj->rowid, $selected)) {
1822  $out .= '<option value="'.$obj->rowid.'"';
1823  if ($disabled) {
1824  $out .= ' disabled';
1825  }
1826  $out .= ' selected>';
1827  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1828  if ($showfunction && $obj->poste) {
1829  $out .= ' ('.$obj->poste.')';
1830  }
1831  if (($showsoc > 0) && $obj->company) {
1832  $out .= ' - ('.$obj->company.')';
1833  }
1834  $out .= '</option>';
1835  } else {
1836  $out .= '<option value="'.$obj->rowid.'"';
1837  if ($disabled) {
1838  $out .= ' disabled';
1839  }
1840  $out .= '>';
1841  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1842  if ($showfunction && $obj->poste) {
1843  $out .= ' ('.$obj->poste.')';
1844  }
1845  if (($showsoc > 0) && $obj->company) {
1846  $out .= ' - ('.$obj->company.')';
1847  }
1848  $out .= '</option>';
1849  }
1850  } else {
1851  if (in_array($obj->rowid, $selected)) {
1852  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1853  if ($showfunction && $obj->poste) {
1854  $out .= ' ('.$obj->poste.')';
1855  }
1856  if (($showsoc > 0) && $obj->company) {
1857  $out .= ' - ('.$obj->company.')';
1858  }
1859  }
1860  }
1861  }
1862  $i++;
1863  }
1864  } else {
1865  $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1866  $out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">';
1867  $out .= $labeltoshow;
1868  $out .= '</option>';
1869  }
1870 
1871  $parameters = array(
1872  'socid'=>$socid,
1873  'htmlname'=>$htmlname,
1874  'resql'=>$resql,
1875  'out'=>&$out,
1876  'showfunction'=>$showfunction,
1877  'showsoc'=>$showsoc,
1878  );
1879 
1880  $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1881 
1882  if ($htmlname != 'none' && !$options_only) {
1883  $out .= '</select>';
1884  }
1885 
1886  if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1887  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1888  $out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1889  }
1890 
1891  $this->num = $num;
1892  return $out;
1893  } else {
1894  dol_print_error($this->db);
1895  return -1;
1896  }
1897  }
1898 
1899  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1915  public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1916  {
1917  // phpcs:enable
1918  print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1919  }
1920 
1921  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1946  public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
1947  {
1948  // phpcs:enable
1949  global $conf, $user, $langs, $hookmanager;
1950  global $action;
1951 
1952  // If no preselected user defined, we take current user
1953  if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
1954  $selected = $user->id;
1955  }
1956 
1957  if ($selected === '') {
1958  $selected = array();
1959  } elseif (!is_array($selected)) {
1960  $selected = array($selected);
1961  }
1962 
1963  $excludeUsers = null;
1964  $includeUsers = null;
1965 
1966  // Permettre l'exclusion d'utilisateurs
1967  if (is_array($exclude)) {
1968  $excludeUsers = implode(",", $exclude);
1969  }
1970  // Permettre l'inclusion d'utilisateurs
1971  if (is_array($include)) {
1972  $includeUsers = implode(",", $include);
1973  } elseif ($include == 'hierarchy') {
1974  // Build list includeUsers to have only hierarchy
1975  $includeUsers = implode(",", $user->getAllChildIds(0));
1976  } elseif ($include == 'hierarchyme') {
1977  // Build list includeUsers to have only hierarchy and current user
1978  $includeUsers = implode(",", $user->getAllChildIds(1));
1979  }
1980 
1981  $out = '';
1982  $outarray = array();
1983 
1984  // Forge request to select users
1985  $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
1986  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
1987  $sql .= ", e.label";
1988  }
1989  $sql .= " FROM ".$this->db->prefix()."user as u";
1990  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
1991  $sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid = u.entity";
1992  if ($force_entity) {
1993  $sql .= " WHERE u.entity IN (0, ".$this->db->sanitize($force_entity).")";
1994  } else {
1995  $sql .= " WHERE u.entity IS NOT NULL";
1996  }
1997  } else {
1998  if (isModEnabled('multicompany') && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1999  $sql .= " LEFT JOIN ".$this->db->prefix()."usergroup_user as ug";
2000  $sql .= " ON ug.fk_user = u.rowid";
2001  $sql .= " WHERE ug.entity = ".$conf->entity;
2002  } else {
2003  $sql .= " WHERE u.entity IN (0, ".$conf->entity.")";
2004  }
2005  }
2006  if (!empty($user->socid)) {
2007  $sql .= " AND u.fk_soc = ".((int) $user->socid);
2008  }
2009  if (is_array($exclude) && $excludeUsers) {
2010  $sql .= " AND u.rowid NOT IN (".$this->db->sanitize($excludeUsers).")";
2011  }
2012  if ($includeUsers) {
2013  $sql .= " AND u.rowid IN (".$this->db->sanitize($includeUsers).")";
2014  }
2015  if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $notdisabled) {
2016  $sql .= " AND u.statut <> 0";
2017  }
2018  if (!empty($morefilter)) {
2019  $sql .= " ".$morefilter;
2020  }
2021 
2022  //Add hook to filter on user (for exemple on usergroup define in custom modules)
2023  $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2024  if (!empty($reshook)) {
2025  $sql .= $hookmanager->resPrint;
2026  }
2027 
2028  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2029  $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2030  } else {
2031  $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2032  }
2033 
2034  dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
2035 
2036  $resql = $this->db->query($sql);
2037  if ($resql) {
2038  $num = $this->db->num_rows($resql);
2039  $i = 0;
2040  if ($num) {
2041  // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2042  $out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
2043  if ($show_empty && !$multiple) {
2044  $textforempty = ' ';
2045  if (!empty($conf->use_javascript_ajax)) {
2046  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2047  }
2048  if (!is_numeric($show_empty)) {
2049  $textforempty = $show_empty;
2050  }
2051  $out .= '<option class="optiongrey" value="'.($show_empty < 0 ? $show_empty : -1).'"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
2052  }
2053  if ($show_every) {
2054  $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
2055  }
2056 
2057  $userstatic = new User($this->db);
2058 
2059  while ($i < $num) {
2060  $obj = $this->db->fetch_object($resql);
2061 
2062  $userstatic->id = $obj->rowid;
2063  $userstatic->lastname = $obj->lastname;
2064  $userstatic->firstname = $obj->firstname;
2065  $userstatic->photo = $obj->photo;
2066  $userstatic->statut = $obj->status;
2067  $userstatic->entity = $obj->entity;
2068  $userstatic->admin = $obj->admin;
2069 
2070  $disableline = '';
2071  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2072  $disableline = ($enableonlytext ? $enableonlytext : '1');
2073  }
2074 
2075  $labeltoshow = ''; $labeltoshowhtml = '';
2076 
2077  // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2078  $fullNameMode = 0;
2079  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2080  $fullNameMode = 1; //Firstname+lastname
2081  }
2082  $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2083  $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2084  if (empty($obj->firstname) && empty($obj->lastname)) {
2085  $labeltoshow .= $obj->login;
2086  $labeltoshowhtml .= $obj->login;
2087  }
2088 
2089  // Complete name with a more info string like: ' (info1 - info2 - ...)'
2090  $moreinfo = ''; $moreinfohtml = '';
2091  if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2092  $moreinfo .= ($moreinfo ? ' - ' : ' (');
2093  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2094  $moreinfo .= $obj->login;
2095  $moreinfohtml .= $obj->login;
2096  }
2097  if ($showstatus >= 0) {
2098  if ($obj->status == 1 && $showstatus == 1) {
2099  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
2100  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').$langs->trans('Enabled');
2101  }
2102  if ($obj->status == 0 && $showstatus == 1) {
2103  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
2104  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').$langs->trans('Disabled');
2105  }
2106  }
2107  if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2108  if (!$obj->entity) {
2109  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
2110  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').$langs->trans("AllEntities");
2111  } else {
2112  if ($obj->entity != $conf->entity) {
2113  $moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2114  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2115  }
2116  }
2117  }
2118  $moreinfo .= ($moreinfo ? ')' : '');
2119  $moreinfohtml .= ($moreinfohtml ? ')' : '');
2120  if ($disableline && $disableline != '1') {
2121  // Add text from $enableonlytext parameter
2122  $moreinfo .= ' - '.$disableline;
2123  $moreinfohtml .= ' - '.$disableline;
2124  }
2125  $labeltoshow .= $moreinfo;
2126  $labeltoshowhtml .= $moreinfohtml;
2127 
2128  $out .= '<option value="'.$obj->rowid.'"';
2129  if ($disableline) {
2130  $out .= ' disabled';
2131  }
2132  if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2133  $out .= ' selected';
2134  }
2135  $out .= ' data-html="';
2136  $outhtml = '';
2137  // if (!empty($obj->photo)) {
2138  $outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
2139  // }
2140  if ($showstatus >= 0 && $obj->status == 0) {
2141  $outhtml .= '<strike class="opacitymediumxxx">';
2142  }
2143  $outhtml .= $labeltoshowhtml;
2144  if ($showstatus >= 0 && $obj->status == 0) {
2145  $outhtml .= '</strike>';
2146  }
2147  $out .= dol_escape_htmltag($outhtml);
2148  $out .= '">';
2149  $out .= $labeltoshow;
2150  $out .= '</option>';
2151 
2152  $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
2153 
2154  $i++;
2155  }
2156  } else {
2157  $out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
2158  $out .= '<option value="">'.$langs->trans("None").'</option>';
2159  }
2160  $out .= '</select>';
2161 
2162  if ($num && !$forcecombo) {
2163  // Enhance with select2
2164  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2165  $out .= ajax_combobox($htmlname);
2166  }
2167  } else {
2168  dol_print_error($this->db);
2169  }
2170 
2171  if ($outputmode) {
2172  return $outarray;
2173  }
2174 
2175  return $out;
2176  }
2177 
2178 
2179  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2202  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())
2203  {
2204  // phpcs:enable
2205  global $conf, $user, $langs;
2206 
2207  $userstatic = new User($this->db);
2208  $out = '';
2209 
2210 
2211  $assignedtouser = array();
2212  if (!empty($_SESSION['assignedtouser'])) {
2213  $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2214  }
2215  $nbassignetouser = count($assignedtouser);
2216 
2217  //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2218  if ($nbassignetouser) {
2219  $out .= '<ul class="attendees">';
2220  }
2221  $i = 0;
2222  $ownerid = 0;
2223  foreach ($assignedtouser as $key => $value) {
2224  if ($value['id'] == $ownerid) {
2225  continue;
2226  }
2227 
2228  $out .= '<li>';
2229  $userstatic->fetch($value['id']);
2230  $out .= $userstatic->getNomUrl(-1);
2231  if ($i == 0) {
2232  $ownerid = $value['id'];
2233  $out .= ' ('.$langs->trans("Owner").')';
2234  }
2235  if ($nbassignetouser > 1 && $action != 'view') {
2236  $out .= ' <input type="image" style="border: 0px;" src="'.img_picto($langs->trans("Remove"), 'delete', '', 0, 1).'" value="'.$userstatic->id.'" class="removedassigned reposition" id="removedassigned_'.$userstatic->id.'" name="removedassigned_'.$userstatic->id.'">';
2237  }
2238  // Show my availability
2239  if ($showproperties) {
2240  if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2241  $out .= '<div class="myavailability inline-block">';
2242  $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>';
2243  $out .= '</div>';
2244  }
2245  }
2246  //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2247  //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2248 
2249  $out .= '</li>';
2250  $i++;
2251  }
2252  if ($nbassignetouser) {
2253  $out .= '</ul>';
2254  }
2255 
2256  // Method with no ajax
2257  if ($action != 'view') {
2258  $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2259  $out .= '<script type="text/javascript">jQuery(document).ready(function () {';
2260  $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2261  $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2262  $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }';
2263  $out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }';
2264  $out .= '});';
2265  $out .= '})</script>';
2266  $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2267  $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
2268  $out .= '<br>';
2269  }
2270 
2271  return $out;
2272  }
2273 
2274 
2275  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2303  public function select_produits($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1)
2304  {
2305  // phpcs:enable
2306  global $langs, $conf;
2307 
2308  $out = '';
2309 
2310  // check parameters
2311  $price_level = (!empty($price_level) ? $price_level : 0);
2312  if (is_null($ajaxoptions)) {
2313  $ajaxoptions = array();
2314  }
2315 
2316  if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2317  if (isModEnabled("product") && !isModEnabled('service')) {
2318  $filtertype = '0';
2319  } elseif (!isModEnabled('product') && isModEnabled("service")) {
2320  $filtertype = '1';
2321  }
2322  }
2323 
2324  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2325  $placeholder = '';
2326 
2327  if ($selected && empty($selected_input_value)) {
2328  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2329  $producttmpselect = new Product($this->db);
2330  $producttmpselect->fetch($selected);
2331  $selected_input_value = $producttmpselect->ref;
2332  unset($producttmpselect);
2333  }
2334  // handle case where product or service module is disabled + no filter specified
2335  if ($filtertype == '') {
2336  if (!isModEnabled('product')) { // when product module is disabled, show services only
2337  $filtertype = 1;
2338  } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2339  $filtertype = 0;
2340  }
2341  }
2342  // mode=1 means customers products
2343  $urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&status_purchase='.$status_purchase.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
2344  //Price by customer
2345  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2346  $urloption .= '&socid='.$socid;
2347  }
2348  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2349 
2350  if (isModEnabled('variants') && is_array($selected_combinations)) {
2351  // Code to automatically insert with javascript the select of attributes under the select of product
2352  // when a parent of variant has been selected.
2353  $out .= '
2354  <!-- script to auto show attributes select tags if a variant was selected -->
2355  <script>
2356  // auto show attributes fields
2357  selected = '.json_encode($selected_combinations).';
2358  combvalues = {};
2359 
2360  jQuery(document).ready(function () {
2361 
2362  jQuery("input[name=\'prod_entry_mode\']").change(function () {
2363  if (jQuery(this).val() == \'free\') {
2364  jQuery(\'div#attributes_box\').empty();
2365  }
2366  });
2367 
2368  jQuery("input#'.$htmlname.'").change(function () {
2369 
2370  if (!jQuery(this).val()) {
2371  jQuery(\'div#attributes_box\').empty();
2372  return;
2373  }
2374 
2375  console.log("A change has started. We get variants fields to inject html select");
2376 
2377  jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
2378  id: jQuery(this).val()
2379  }, function (data) {
2380  jQuery(\'div#attributes_box\').empty();
2381 
2382  jQuery.each(data, function (key, val) {
2383 
2384  combvalues[val.id] = val.values;
2385 
2386  var span = jQuery(document.createElement(\'div\')).css({
2387  \'display\': \'table-row\'
2388  });
2389 
2390  span.append(
2391  jQuery(document.createElement(\'div\')).text(val.label).css({
2392  \'font-weight\': \'bold\',
2393  \'display\': \'table-cell\'
2394  })
2395  );
2396 
2397  var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2398  \'margin-left\': \'15px\',
2399  \'white-space\': \'pre\'
2400  }).append(
2401  jQuery(document.createElement(\'option\')).val(\'\')
2402  );
2403 
2404  jQuery.each(combvalues[val.id], function (key, val) {
2405  var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2406 
2407  if (selected[val.fk_product_attribute] == val.id) {
2408  tag.attr(\'selected\', \'selected\');
2409  }
2410 
2411  html.append(tag);
2412  });
2413 
2414  span.append(html);
2415  jQuery(\'div#attributes_box\').append(span);
2416  });
2417  })
2418  });
2419 
2420  '.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2421  });
2422  </script>
2423  ';
2424  }
2425 
2426  if (empty($hidelabel)) {
2427  $out .= $langs->trans("RefOrLabel").' : ';
2428  } elseif ($hidelabel > 1) {
2429  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2430  if ($hidelabel == 2) {
2431  $out .= img_picto($langs->trans("Search"), 'search');
2432  }
2433  }
2434  $out .= '<input type="text" class="minwidth100'.($morecss ? ' '.$morecss : '').'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
2435  if ($hidelabel == 3) {
2436  $out .= img_picto($langs->trans("Search"), 'search');
2437  }
2438  } else {
2439  $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2440  }
2441 
2442  if (empty($nooutput)) {
2443  print $out;
2444  } else {
2445  return $out;
2446  }
2447  }
2448 
2449  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2450 
2466  public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2467  {
2468  // phpcs:enable
2469  global $conf, $user, $langs, $db;
2470 
2471  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2472 
2473  $error = 0;
2474  $out = '';
2475 
2476  if (!$forcecombo) {
2477  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2478  $events = array();
2479  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2480  }
2481 
2482  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2483 
2484  $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2485  $sql.= ' FROM '.MAIN_DB_PREFIX.'bom_bom as b';
2486  $sql.= ' WHERE b.entity IN ('.getEntity('bom').')';
2487  if (!empty($status)) $sql.= ' AND status = '. (int) $status;
2488  if (!empty($type)) $sql.= ' AND bomtype = '. (int) $type;
2489  if (!empty($TProducts)) $sql .= ' AND fk_product IN ('.$this->db->sanitize(implode(',', $TProducts)).')';
2490  if (!empty($limit)) $sql.= ' LIMIT '. (int) $limit;
2491  $resql = $db->query($sql);
2492  if ($resql) {
2493  if ($showempty) {
2494  $out .= '<option value="-1"';
2495  if (empty($selected)) $out .= ' selected';
2496  $out .= '>&nbsp;</option>';
2497  }
2498  while ($obj = $db->fetch_object($resql)) {
2499  $product = new Product($db);
2500  $res = $product->fetch($obj->fk_product);
2501  $out .= '<option value="'.$obj->rowid.'"';
2502  if ($obj->rowid == $selected) $out .= 'selected';
2503  $out .= '>'.$obj->ref.' - '.$product->label .' - '. $obj->label.'</option>';
2504  }
2505  } else {
2506  $error++;
2507  dol_print_error($db);
2508  }
2509  $out .= '</select>';
2510  if (empty($nooutput)) {
2511  print $out;
2512  } else {
2513  return $out;
2514  }
2515  }
2516 
2517  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2543  public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1)
2544  {
2545  // phpcs:enable
2546  global $langs, $conf;
2547  global $hookmanager;
2548 
2549  $out = '';
2550  $outarray = array();
2551 
2552  // Units
2553  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2554  $langs->load('other');
2555  }
2556 
2557  $warehouseStatusArray = array();
2558  if (!empty($warehouseStatus)) {
2559  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2560  if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2561  $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2562  }
2563  if (preg_match('/warehouseopen/', $warehouseStatus)) {
2564  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2565  }
2566  if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2567  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2568  }
2569  }
2570 
2571  $selectFields = " p.rowid, p.ref, p.label, p.description, p.barcode, p.fk_country, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.default_vat_code, p.duration, p.fk_price_expression";
2572  if (count($warehouseStatusArray)) {
2573  $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
2574  } else {
2575  $selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2576  }
2577 
2578  $sql = "SELECT ";
2579  $sql .= $selectFields.$selectFieldsGrouped;
2580 
2581  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2582  //Product category
2583  $sql .= ", (SELECT ".$this->db->prefix()."categorie_product.fk_categorie
2584  FROM ".$this->db->prefix()."categorie_product
2585  WHERE ".$this->db->prefix()."categorie_product.fk_product=p.rowid
2586  LIMIT 1
2587  ) AS categorie_product_id ";
2588  }
2589 
2590  //Price by customer
2591  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2592  $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2593  $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref';
2594  $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2595  }
2596  // Units
2597  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2598  $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";
2599  $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';
2600  }
2601 
2602  // Multilang : we add translation
2603  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2604  $sql .= ", pl.label as label_translated";
2605  $sql .= ", pl.description as description_translated";
2606  $selectFields .= ", label_translated";
2607  $selectFields .= ", description_translated";
2608  }
2609  // Price by quantity
2610  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2611  $sql .= ", (SELECT pp.rowid FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid";
2612  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2613  $sql .= " AND price_level = ".((int) $price_level);
2614  }
2615  $sql .= " ORDER BY date_price";
2616  $sql .= " DESC LIMIT 1) as price_rowid";
2617  $sql .= ", (SELECT pp.price_by_qty FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable
2618  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2619  $sql .= " AND price_level = ".((int) $price_level);
2620  }
2621  $sql .= " ORDER BY date_price";
2622  $sql .= " DESC LIMIT 1) as price_by_qty";
2623  $selectFields .= ", price_rowid, price_by_qty";
2624  }
2625  $sql .= " FROM ".$this->db->prefix()."product as p";
2626  if (count($warehouseStatusArray)) {
2627  $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_product = p.rowid";
2628  $sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2629  $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.
2630  }
2631 
2632  // include search in supplier ref
2633  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2634  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2635  }
2636 
2637  //Price by customer
2638  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2639  $sql .= " LEFT JOIN ".$this->db->prefix()."product_customer_price as pcp ON pcp.fk_soc=".((int) $socid)." AND pcp.fk_product=p.rowid";
2640  }
2641  // Units
2642  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2643  $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
2644  }
2645  // Multilang : we add translation
2646  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2647  $sql .= " LEFT JOIN ".$this->db->prefix()."product_lang as pl ON pl.fk_product = p.rowid ";
2648  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2649  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
2650  $soc = new Societe($this->db);
2651  $result = $soc->fetch($socid);
2652  if ($result > 0 && !empty($soc->default_lang)) {
2653  $sql .= " AND pl.lang = '".$this->db->escape($soc->default_lang)."'";
2654  } else {
2655  $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2656  }
2657  } else {
2658  $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2659  }
2660  }
2661 
2662  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2663  $sql .= " LEFT JOIN ".$this->db->prefix()."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2664  }
2665 
2666  $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2667 
2668  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2669  $sql .= " AND pac.rowid IS NULL";
2670  }
2671 
2672  if ($finished == 0) {
2673  $sql .= " AND p.finished = ".((int) $finished);
2674  } elseif ($finished == 1) {
2675  $sql .= " AND p.finished = ".((int) $finished);
2676  }
2677  if ($status >= 0) {
2678  $sql .= " AND p.tosell = ".((int) $status);
2679  }
2680  if ($status_purchase >= 0) {
2681  $sql .= " AND p.tobuy = ".((int) $status_purchase);
2682  }
2683  // Filter by product type
2684  if (strval($filtertype) != '') {
2685  $sql .= " AND p.fk_product_type = ".((int) $filtertype);
2686  } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
2687  $sql .= " AND p.fk_product_type = 1";
2688  } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2689  $sql .= " AND p.fk_product_type = 0";
2690  }
2691  // Add where from hooks
2692  $parameters = array();
2693  $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2694  $sql .= $hookmanager->resPrint;
2695  // Add criteria on ref/label
2696  if ($filterkey != '') {
2697  $sql .= ' AND (';
2698  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2699  // For natural search
2700  $scrit = explode(' ', $filterkey);
2701  $i = 0;
2702  if (count($scrit) > 1) {
2703  $sql .= "(";
2704  }
2705  foreach ($scrit as $crit) {
2706  if ($i > 0) {
2707  $sql .= " AND ";
2708  }
2709  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2710  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2711  $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2712  }
2713  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2714  $sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'";
2715  }
2716  if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2717  $sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2718  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2719  $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2720  }
2721  }
2722  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2723  $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2724  }
2725  $sql .= ")";
2726  $i++;
2727  }
2728  if (count($scrit) > 1) {
2729  $sql .= ")";
2730  }
2731  if (isModEnabled('barcode')) {
2732  $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2733  }
2734  $sql .= ')';
2735  }
2736  if (count($warehouseStatusArray)) {
2737  $sql .= " GROUP BY ".$selectFields;
2738  }
2739 
2740  //Sort by category
2741  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2742  $sql .= " ORDER BY categorie_product_id ";
2743  //ASC OR DESC order
2744  ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2745  } else {
2746  $sql .= $this->db->order("p.ref");
2747  }
2748 
2749  $sql .= $this->db->plimit($limit, 0);
2750 
2751  // Build output string
2752  dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2753  $result = $this->db->query($sql);
2754  if ($result) {
2755  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2756  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2757  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2758 
2759  $num = $this->db->num_rows($result);
2760 
2761  $events = null;
2762 
2763  if (!$forcecombo) {
2764  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2765  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2766  }
2767 
2768  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2769 
2770  $textifempty = '';
2771  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2772  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2773  if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2774  if ($showempty && !is_numeric($showempty)) {
2775  $textifempty = $langs->trans($showempty);
2776  } else {
2777  $textifempty .= $langs->trans("All");
2778  }
2779  } else {
2780  if ($showempty && !is_numeric($showempty)) {
2781  $textifempty = $langs->trans($showempty);
2782  }
2783  }
2784  if ($showempty) {
2785  $out .= '<option value="-1" selected>'.($textifempty ? $textifempty : '&nbsp;').'</option>';
2786  }
2787 
2788  $i = 0;
2789  while ($num && $i < $num) {
2790  $opt = '';
2791  $optJson = array();
2792  $objp = $this->db->fetch_object($result);
2793 
2794  if ((!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product
2795  $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2796  $sql .= " FROM ".$this->db->prefix()."product_price_by_qty";
2797  $sql .= " WHERE fk_product_price = ".((int) $objp->price_rowid);
2798  $sql .= " ORDER BY quantity ASC";
2799 
2800  dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2801  $result2 = $this->db->query($sql);
2802  if ($result2) {
2803  $nb_prices = $this->db->num_rows($result2);
2804  $j = 0;
2805  while ($nb_prices && $j < $nb_prices) {
2806  $objp2 = $this->db->fetch_object($result2);
2807 
2808  $objp->price_by_qty_rowid = $objp2->rowid;
2809  $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2810  $objp->price_by_qty_quantity = $objp2->quantity;
2811  $objp->price_by_qty_unitprice = $objp2->unitprice;
2812  $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2813  // For backward compatibility
2814  $objp->quantity = $objp2->quantity;
2815  $objp->price = $objp2->price;
2816  $objp->unitprice = $objp2->unitprice;
2817  $objp->remise_percent = $objp2->remise_percent;
2818 
2819  //$objp->tva_tx is not overwritten by $objp2 value
2820  //$objp->default_vat_code is not overwritten by $objp2 value
2821 
2822  $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2823 
2824  $j++;
2825 
2826  // Add new entry
2827  // "key" value of json key array is used by jQuery automatically as selected value
2828  // "label" value of json key array is used by jQuery automatically as text for combo box
2829  $out .= $opt;
2830  array_push($outarray, $optJson);
2831  }
2832  }
2833  } else {
2834  if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
2835  $price_product = new Product($this->db);
2836  $price_product->fetch($objp->rowid, '', '', 1);
2837 
2838  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2839  $priceparser = new PriceParser($this->db);
2840  $price_result = $priceparser->parseProduct($price_product);
2841  if ($price_result >= 0) {
2842  $objp->price = $price_result;
2843  $objp->unitprice = $price_result;
2844  //Calculate the VAT
2845  $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2846  $objp->price_ttc = price2num($objp->price_ttc, 'MU');
2847  }
2848  }
2849 
2850  $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2851  // Add new entry
2852  // "key" value of json key array is used by jQuery automatically as selected value
2853  // "label" value of json key array is used by jQuery automatically as text for combo box
2854  $out .= $opt;
2855  array_push($outarray, $optJson);
2856  }
2857 
2858  $i++;
2859  }
2860 
2861  $out .= '</select>';
2862 
2863  $this->db->free($result);
2864 
2865  if (empty($outputmode)) {
2866  return $out;
2867  }
2868  return $outarray;
2869  } else {
2870  dol_print_error($this->db);
2871  }
2872  }
2873 
2889  protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2890  {
2891  global $langs, $conf, $user;
2892 
2893  $outkey = '';
2894  $outval = '';
2895  $outref = '';
2896  $outlabel = '';
2897  $outlabel_translated = '';
2898  $outdesc = '';
2899  $outdesc_translated = '';
2900  $outbarcode = '';
2901  $outorigin = '';
2902  $outtype = '';
2903  $outprice_ht = '';
2904  $outprice_ttc = '';
2905  $outpricebasetype = '';
2906  $outtva_tx = '';
2907  $outdefault_vat_code = '';
2908  $outqty = 1;
2909  $outdiscount = 0;
2910 
2911  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2912 
2913  $label = $objp->label;
2914  if (!empty($objp->label_translated)) {
2915  $label = $objp->label_translated;
2916  }
2917  if (!empty($filterkey) && $filterkey != '') {
2918  $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2919  }
2920 
2921  $outkey = $objp->rowid;
2922  $outref = $objp->ref;
2923  $outrefcust = empty($objp->custref) ? '' : $objp->custref;
2924  $outlabel = $objp->label;
2925  $outdesc = $objp->description;
2926  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2927  $outlabel_translated = $objp->label_translated;
2928  $outdesc_translated = $objp->description_translated;
2929  }
2930  $outbarcode = $objp->barcode;
2931  $outorigin = $objp->fk_country;
2932  $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
2933 
2934  $outtype = $objp->fk_product_type;
2935  $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2936  $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2937 
2938  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2939  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
2940  }
2941 
2942  // Units
2943  $outvalUnits = '';
2944  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2945  if (!empty($objp->unit_short)) {
2946  $outvalUnits .= ' - '.$objp->unit_short;
2947  }
2948  }
2949  if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2950  if (!empty($objp->weight) && $objp->weight_units !== null) {
2951  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2952  $outvalUnits .= ' - '.$unitToShow;
2953  }
2954  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2955  $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2956  $outvalUnits .= ' - '.$unitToShow;
2957  }
2958  if (!empty($objp->surface) && $objp->surface_units !== null) {
2959  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2960  $outvalUnits .= ' - '.$unitToShow;
2961  }
2962  if (!empty($objp->volume) && $objp->volume_units !== null) {
2963  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2964  $outvalUnits .= ' - '.$unitToShow;
2965  }
2966  }
2967  if ($outdurationvalue && $outdurationunit) {
2968  $da = array(
2969  'h' => $langs->trans('Hour'),
2970  'd' => $langs->trans('Day'),
2971  'w' => $langs->trans('Week'),
2972  'm' => $langs->trans('Month'),
2973  'y' => $langs->trans('Year')
2974  );
2975  if (isset($da[$outdurationunit])) {
2976  $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2977  }
2978  }
2979 
2980  $opt = '<option value="'.$objp->rowid.'"';
2981  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
2982  if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
2983  $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.'"';
2984  }
2985  if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
2986  if (!empty($user->rights->stock->lire)) {
2987  if ($objp->stock > 0) {
2988  $opt .= ' class="product_line_stock_ok"';
2989  } elseif ($objp->stock <= 0) {
2990  $opt .= ' class="product_line_stock_too_low"';
2991  }
2992  }
2993  }
2994  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2995  $opt .= ' data-labeltrans="'.$outlabel_translated.'"';
2996  $opt .= ' data-desctrans="'.dol_escape_htmltag($outdesc_translated).'"';
2997  }
2998  $opt .= '>';
2999  $opt .= $objp->ref;
3000  if (!empty($objp->custref)) {
3001  $opt.= ' (' . $objp->custref . ')';
3002  }
3003  if ($outbarcode) {
3004  $opt .= ' ('.$outbarcode.')';
3005  }
3006  $opt .= ' - '.dol_trunc($label, $maxlengtharticle);
3007  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3008  $opt .= ' ('.getCountry($outorigin, 1).')';
3009  }
3010 
3011  $objRef = $objp->ref;
3012  if (!empty($objp->custref)) {
3013  $objRef .= ' (' . $objp->custref . ')';
3014  }
3015  if (!empty($filterkey) && $filterkey != '') {
3016  $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
3017  }
3018  $outval .= $objRef;
3019  if ($outbarcode) {
3020  $outval .= ' ('.$outbarcode.')';
3021  }
3022  $outval .= ' - '.dol_trunc($label, $maxlengtharticle);
3023  if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
3024  $outval .= ' ('.getCountry($outorigin, 1).')';
3025  }
3026 
3027  // Units
3028  $opt .= $outvalUnits;
3029  $outval .= $outvalUnits;
3030 
3031  $found = 0;
3032 
3033  // Multiprice
3034  // If we need a particular price level (from 1 to n)
3035  if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
3036  $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3037  $sql .= " FROM ".$this->db->prefix()."product_price";
3038  $sql .= " WHERE fk_product = ".((int) $objp->rowid);
3039  $sql .= " AND entity IN (".getEntity('productprice').")";
3040  $sql .= " AND price_level = ".((int) $price_level);
3041  $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3042  $sql .= " LIMIT 1";
3043 
3044  dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
3045  $result2 = $this->db->query($sql);
3046  if ($result2) {
3047  $objp2 = $this->db->fetch_object($result2);
3048  if ($objp2) {
3049  $found = 1;
3050  if ($objp2->price_base_type == 'HT') {
3051  $opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3052  $outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3053  } else {
3054  $opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3055  $outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3056  }
3057  $outprice_ht = price($objp2->price);
3058  $outprice_ttc = price($objp2->price_ttc);
3059  $outpricebasetype = $objp2->price_base_type;
3060  if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { // using this option is a bug. kept for backward compatibility
3061  $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3062  $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3063  } else {
3064  $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3065  $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3066  }
3067  }
3068  } else {
3069  dol_print_error($this->db);
3070  }
3071  }
3072 
3073  // Price by quantity
3074  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))) {
3075  $found = 1;
3076  $outqty = $objp->quantity;
3077  $outdiscount = $objp->remise_percent;
3078  if ($objp->quantity == 1) {
3079  $opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
3080  $outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
3081  $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3082  $outval .= $langs->transnoentities("Unit");
3083  } else {
3084  $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
3085  $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
3086  $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3087  $outval .= $langs->transnoentities("Units");
3088  }
3089 
3090  $outprice_ht = price($objp->unitprice);
3091  $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3092  $outpricebasetype = $objp->price_base_type;
3093  $outtva_tx = $objp->tva_tx; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3094  $outdefault_vat_code = $objp->default_vat_code; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3095  }
3096  if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3097  $opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
3098  $outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
3099  }
3100  if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3101  $opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3102  $outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3103  }
3104 
3105  // Price by customer
3106  if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
3107  if (!empty($objp->idprodcustprice)) {
3108  $found = 1;
3109 
3110  if ($objp->custprice_base_type == 'HT') {
3111  $opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3112  $outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3113  } else {
3114  $opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3115  $outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3116  }
3117 
3118  $outprice_ht = price($objp->custprice);
3119  $outprice_ttc = price($objp->custprice_ttc);
3120  $outpricebasetype = $objp->custprice_base_type;
3121  $outtva_tx = $objp->custtva_tx;
3122  $outdefault_vat_code = $objp->custdefault_vat_code;
3123  }
3124  }
3125 
3126  // If level no defined or multiprice not found, we used the default price
3127  if (empty($hidepriceinlabel) && !$found) {
3128  if ($objp->price_base_type == 'HT') {
3129  $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3130  $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3131  } else {
3132  $opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3133  $outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3134  }
3135  $outprice_ht = price($objp->price);
3136  $outprice_ttc = price($objp->price_ttc);
3137  $outpricebasetype = $objp->price_base_type;
3138  $outtva_tx = $objp->tva_tx;
3139  $outdefault_vat_code = $objp->default_vat_code;
3140  }
3141 
3142  if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3143  if (!empty($user->rights->stock->lire)) {
3144  $opt .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3145 
3146  if ($objp->stock > 0) {
3147  $outval .= ' - <span class="product_line_stock_ok">';
3148  } elseif ($objp->stock <= 0) {
3149  $outval .= ' - <span class="product_line_stock_too_low">';
3150  }
3151  $outval .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS'));
3152  $outval .= '</span>';
3153  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3154  $langs->load("stocks");
3155 
3156  $tmpproduct = new Product($this->db);
3157  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3158  $tmpproduct->load_virtual_stock();
3159  $virtualstock = $tmpproduct->stock_theorique;
3160 
3161  $opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3162 
3163  $outval .= ' - '.$langs->transnoentities("VirtualStock").':';
3164  if ($virtualstock > 0) {
3165  $outval .= '<span class="product_line_stock_ok">';
3166  } elseif ($virtualstock <= 0) {
3167  $outval .= '<span class="product_line_stock_too_low">';
3168  }
3169  $outval .= $virtualstock;
3170  $outval .= '</span>';
3171 
3172  unset($tmpproduct);
3173  }
3174  }
3175  }
3176 
3177  $opt .= "</option>\n";
3178  $optJson = array(
3179  'key'=>$outkey,
3180  'value'=>$outref,
3181  'label'=>$outval,
3182  'label2'=>$outlabel,
3183  'desc'=>$outdesc,
3184  'type'=>$outtype,
3185  'price_ht'=>price2num($outprice_ht),
3186  'price_ttc'=>price2num($outprice_ttc),
3187  'price_ht_locale'=>price(price2num($outprice_ht)),
3188  'price_ttc_locale'=>price(price2num($outprice_ttc)),
3189  'pricebasetype'=>$outpricebasetype,
3190  'tva_tx'=>$outtva_tx,
3191  'default_vat_code'=>$outdefault_vat_code,
3192  'qty'=>$outqty,
3193  'discount'=>$outdiscount,
3194  'duration_value'=>$outdurationvalue,
3195  'duration_unit'=>$outdurationunit,
3196  'pbq'=>$outpbq,
3197  'labeltrans'=>$outlabel_translated,
3198  'desctrans'=>$outdesc_translated,
3199  'ref_customer'=>$outrefcust
3200  );
3201  }
3202 
3203  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3219  public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3220  {
3221  // phpcs:enable
3222  global $langs, $conf;
3223  global $price_level, $status, $finished;
3224 
3225  if (!isset($status)) {
3226  $status = 1;
3227  }
3228 
3229  $selected_input_value = '';
3230  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
3231  if ($selected > 0) {
3232  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
3233  $producttmpselect = new Product($this->db);
3234  $producttmpselect->fetch($selected);
3235  $selected_input_value = $producttmpselect->ref;
3236  unset($producttmpselect);
3237  }
3238 
3239  // mode=2 means suppliers products
3240  $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
3241  print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3242  print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" class="minwidth300" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.$placeholder.'"' : '').'>';
3243  } else {
3244  print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3245  }
3246  }
3247 
3248  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3267  public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0, $placeholder = '')
3268  {
3269  // phpcs:enable
3270  global $langs, $conf, $user;
3271  global $hookmanager;
3272 
3273  $out = '';
3274  $outarray = array();
3275 
3276  $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3277 
3278  $langs->load('stocks');
3279  // Units
3280  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3281  $langs->load('other');
3282  }
3283 
3284  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock, p.tva_tx as tva_tx_sale, p.default_vat_code as default_vat_code_sale,";
3285  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
3286  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name,";
3287  $sql .= " pfp.supplier_reputation";
3288  // if we use supplier description of the products
3289  if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3290  $sql .= ", pfp.desc_fourn as description";
3291  } else {
3292  $sql .= ", p.description";
3293  }
3294  // Units
3295  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3296  $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";
3297  }
3298  if (isModEnabled('barcode')) {
3299  $sql .= ", pfp.barcode";
3300  }
3301  $sql .= " FROM ".$this->db->prefix()."product as p";
3302  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )";
3303  if ($socid > 0) {
3304  $sql .= " AND pfp.fk_soc = ".((int) $socid);
3305  }
3306  $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid";
3307  // Units
3308  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3309  $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
3310  }
3311  $sql .= " WHERE p.entity IN (".getEntity('product').")";
3312  if ($statut != -1) {
3313  $sql .= " AND p.tobuy = ".((int) $statut);
3314  }
3315  if (strval($filtertype) != '') {
3316  $sql .= " AND p.fk_product_type = ".((int) $filtertype);
3317  }
3318  if (!empty($filtre)) {
3319  $sql .= " ".$filtre;
3320  }
3321  // Add where from hooks
3322  $parameters = array();
3323  $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3324  $sql .= $hookmanager->resPrint;
3325  // Add criteria on ref/label
3326  if ($filterkey != '') {
3327  $sql .= ' AND (';
3328  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3329  // For natural search
3330  $scrit = explode(' ', $filterkey);
3331  $i = 0;
3332  if (count($scrit) > 1) {
3333  $sql .= "(";
3334  }
3335  foreach ($scrit as $crit) {
3336  if ($i > 0) {
3337  $sql .= " AND ";
3338  }
3339  $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)."%'";
3340  if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3341  $sql .= " OR pfp.desc_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
3342  }
3343  $sql .= ")";
3344  $i++;
3345  }
3346  if (count($scrit) > 1) {
3347  $sql .= ")";
3348  }
3349  if (isModEnabled('barcode')) {
3350  $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3351  $sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3352  }
3353  $sql .= ')';
3354  }
3355  $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3356  $sql .= $this->db->plimit($limit, 0);
3357 
3358  // Build output string
3359 
3360  dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
3361  $result = $this->db->query($sql);
3362  if ($result) {
3363  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3364  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
3365 
3366  $num = $this->db->num_rows($result);
3367 
3368  //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3369  $out .= '<select class="flat '.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
3370  if (!$selected) {
3371  $out .= '<option value="-1" selected>'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3372  } else {
3373  $out .= '<option value="-1">'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3374  }
3375 
3376  $i = 0;
3377  while ($i < $num) {
3378  $objp = $this->db->fetch_object($result);
3379 
3380  if (is_null($objp->idprodfournprice)) {
3381  // There is no supplier price found, we will use the vat rate for sale
3382  $objp->tva_tx = $objp->tva_tx_sale;
3383  $objp->default_vat_code = $objp->default_vat_code_sale;
3384  }
3385 
3386  $outkey = $objp->idprodfournprice; // id in table of price
3387  if (!$outkey && $alsoproductwithnosupplierprice) {
3388  $outkey = 'idprod_'.$objp->rowid; // id of product
3389  }
3390 
3391  $outref = $objp->ref;
3392  $outbarcode = $objp->barcode;
3393  $outqty = 1;
3394  $outdiscount = 0;
3395  $outtype = $objp->fk_product_type;
3396  $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3397  $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
3398 
3399  // Units
3400  $outvalUnits = '';
3401  if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3402  if (!empty($objp->unit_short)) {
3403  $outvalUnits .= ' - '.$objp->unit_short;
3404  }
3405  if (!empty($objp->weight) && $objp->weight_units !== null) {
3406  $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3407  $outvalUnits .= ' - '.$unitToShow;
3408  }
3409  if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3410  $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
3411  $outvalUnits .= ' - '.$unitToShow;
3412  }
3413  if (!empty($objp->surface) && $objp->surface_units !== null) {
3414  $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3415  $outvalUnits .= ' - '.$unitToShow;
3416  }
3417  if (!empty($objp->volume) && $objp->volume_units !== null) {
3418  $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3419  $outvalUnits .= ' - '.$unitToShow;
3420  }
3421  if ($outdurationvalue && $outdurationunit) {
3422  $da = array(
3423  'h' => $langs->trans('Hour'),
3424  'd' => $langs->trans('Day'),
3425  'w' => $langs->trans('Week'),
3426  'm' => $langs->trans('Month'),
3427  'y' => $langs->trans('Year')
3428  );
3429  if (isset($da[$outdurationunit])) {
3430  $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
3431  }
3432  }
3433  }
3434 
3435  $objRef = $objp->ref;
3436  if ($filterkey && $filterkey != '') {
3437  $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
3438  }
3439  $objRefFourn = $objp->ref_fourn;
3440  if ($filterkey && $filterkey != '') {
3441  $objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1);
3442  }
3443  $label = $objp->label;
3444  if ($filterkey && $filterkey != '') {
3445  $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
3446  }
3447 
3448  $optlabel = $objp->ref;
3449  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3450  $optlabel .= ' <span class="opacitymedium">('.$objp->ref_fourn.')</span>';
3451  }
3452  if (isModEnabled('barcode') && !empty($objp->barcode)) {
3453  $optlabel .= ' ('.$outbarcode.')';
3454  }
3455  $optlabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3456 
3457  $outvallabel = $objRef;
3458  if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3459  $outvallabel .= ' ('.$objRefFourn.')';
3460  }
3461  if (isModEnabled('barcode') && !empty($objp->barcode)) {
3462  $outvallabel .= ' ('.$outbarcode.')';
3463  }
3464  $outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3465 
3466  // Units
3467  $optlabel .= $outvalUnits;
3468  $outvallabel .= $outvalUnits;
3469 
3470  if (!empty($objp->idprodfournprice)) {
3471  $outqty = $objp->quantity;
3472  $outdiscount = $objp->remise_percent;
3473  if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3474  $prod_supplier = new ProductFournisseur($this->db);
3475  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3476  $prod_supplier->id = $objp->fk_product;
3477  $prod_supplier->fourn_qty = $objp->quantity;
3478  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3479  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3480 
3481  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3482  $priceparser = new PriceParser($this->db);
3483  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3484  if ($price_result >= 0) {
3485  $objp->fprice = $price_result;
3486  if ($objp->quantity >= 1) {
3487  $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3488  }
3489  }
3490  }
3491  if ($objp->quantity == 1) {
3492  $optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3493  $outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
3494  $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3495  $outvallabel .= $langs->transnoentities("Unit");
3496  } else {
3497  $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;
3498  $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;
3499  $optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3500  $outvallabel .= ' '.$langs->transnoentities("Units");
3501  }
3502 
3503  if ($objp->quantity > 1) {
3504  $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
3505  $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
3506  }
3507  if ($objp->remise_percent >= 1) {
3508  $optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3509  $outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3510  }
3511  if ($objp->duration) {
3512  $optlabel .= " - ".$objp->duration;
3513  $outvallabel .= " - ".$objp->duration;
3514  }
3515  if (!$socid) {
3516  $optlabel .= " - ".dol_trunc($objp->name, 8);
3517  $outvallabel .= " - ".dol_trunc($objp->name, 8);
3518  }
3519  if ($objp->supplier_reputation) {
3520  //TODO dictionary
3521  $reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
3522 
3523  $optlabel .= " - ".$reputations[$objp->supplier_reputation];
3524  $outvallabel .= " - ".$reputations[$objp->supplier_reputation];
3525  }
3526  } else {
3527  if (empty($alsoproductwithnosupplierprice)) { // No supplier price defined for couple product/supplier
3528  $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3529  $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3530  } else // No supplier price defined for product, even on other suppliers
3531  {
3532  $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3533  $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3534  }
3535  }
3536 
3537  if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3538  $novirtualstock = ($showstockinlist == 2);
3539 
3540  if (!empty($user->rights->stock->lire)) {
3541  $outvallabel .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3542 
3543  if ($objp->stock > 0) {
3544  $optlabel .= ' - <span class="product_line_stock_ok">';
3545  } elseif ($objp->stock <= 0) {
3546  $optlabel .= ' - <span class="product_line_stock_too_low">';
3547  }
3548  $optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS'));
3549  $optlabel .= '</span>';
3550  if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation
3551  $langs->load("stocks");
3552 
3553  $tmpproduct = new Product($this->db);
3554  $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3555  $tmpproduct->load_virtual_stock();
3556  $virtualstock = $tmpproduct->stock_theorique;
3557 
3558  $outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3559 
3560  $optlabel .= ' - '.$langs->transnoentities("VirtualStock").':';
3561  if ($virtualstock > 0) {
3562  $optlabel .= '<span class="product_line_stock_ok">';
3563  } elseif ($virtualstock <= 0) {
3564  $optlabel .= '<span class="product_line_stock_too_low">';
3565  }
3566  $optlabel .= $virtualstock;
3567  $optlabel .= '</span>';
3568 
3569  unset($tmpproduct);
3570  }
3571  }
3572  }
3573 
3574  $optstart = '<option value="'.$outkey.'"';
3575  if ($selected && $selected == $objp->idprodfournprice) {
3576  $optstart .= ' selected';
3577  }
3578  if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3579  $optstart .= ' disabled';
3580  }
3581 
3582  if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3583  $optstart .= ' data-product-id="'.dol_escape_htmltag($objp->rowid).'"';
3584  $optstart .= ' data-price-id="'.dol_escape_htmltag($objp->idprodfournprice).'"';
3585  $optstart .= ' data-qty="'.dol_escape_htmltag($objp->quantity).'"';
3586  $optstart .= ' data-up="'.dol_escape_htmltag(price2num($objp->unitprice)).'"';
3587  $optstart .= ' data-up-locale="'.dol_escape_htmltag(price($objp->unitprice)).'"';
3588  $optstart .= ' data-discount="'.dol_escape_htmltag($outdiscount).'"';
3589  $optstart .= ' data-tvatx="'.dol_escape_htmltag(price2num($objp->tva_tx)).'"';
3590  $optstart .= ' data-tvatx-formated="'.dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)).'"';
3591  $optstart .= ' data-default-vat-code="'.dol_escape_htmltag($objp->default_vat_code).'"';
3592  }
3593  $optstart .= ' data-description="'.dol_escape_htmltag($objp->description, 0, 1).'"';
3594 
3595  $outarrayentry = array(
3596  'key' => $outkey,
3597  'value' => $outref,
3598  'label' => $outvallabel,
3599  'qty' => $outqty,
3600  'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3601  'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3602  'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3603  'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
3604  'tva_tx' => price2num($objp->tva_tx),
3605  'default_vat_code' => $objp->default_vat_code,
3606  'discount' => $outdiscount,
3607  'type' => $outtype,
3608  'duration_value' => $outdurationvalue,
3609  'duration_unit' => $outdurationunit,
3610  'disabled' => (empty($objp->idprodfournprice) ? true : false),
3611  'description' => $objp->description
3612  );
3613 
3614  $parameters = array(
3615  'objp' => &$objp,
3616  'optstart' => &$optstart,
3617  'optlabel' => &$optlabel,
3618  'outvallabel' => &$outvallabel,
3619  'outarrayentry' => &$outarrayentry
3620  );
3621  $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
3622 
3623 
3624  // Add new entry
3625  // "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
3626  // "label" value of json key array is used by jQuery automatically as text for combo box
3627  $out .= $optstart . ' data-html="'.dol_escape_htmltag($optlabel).'">' . $optlabel . "</option>\n";;
3628  array_push(
3629  $outarray,
3630  array('key'=>$outkey,
3631  'value'=>$outref,
3632  'label'=>$outvallabel,
3633  'qty'=>$outqty,
3634  'price_qty_ht'=>price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
3635  'price_qty_ht_locale'=>price($objp->fprice),
3636  'price_unit_ht'=>price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
3637  'price_unit_ht_locale'=>price($objp->unitprice),
3638  'price_ht'=>price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
3639  'tva_tx_formated' => price($objp->tva_tx),
3640  'tva_tx'=>price2num($objp->tva_tx),
3641  'default_vat_code'=>$objp->default_vat_code,
3642  'discount'=>$outdiscount,
3643  'type'=>$outtype,
3644  'duration_value'=>$outdurationvalue,
3645  'duration_unit'=>$outdurationunit,
3646  'disabled'=>(empty($objp->idprodfournprice) ? true : false),
3647  'description'=>$objp->description
3648  )
3649  );
3650  // Exemple of var_dump $outarray
3651  // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3652  // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3653  // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3654  //}
3655  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3656  //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3657  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3658 
3659  $i++;
3660  }
3661  $out .= '</select>';
3662 
3663  $this->db->free($result);
3664 
3665  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3666  $out .= ajax_combobox($htmlname);
3667  } else {
3668  dol_print_error($this->db);
3669  }
3670 
3671  if (empty($outputmode)) {
3672  return $out;
3673  }
3674  return $outarray;
3675  }
3676 
3677  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3686  public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3687  {
3688  // phpcs:enable
3689  global $langs, $conf;
3690 
3691  $langs->load('stocks');
3692 
3693  $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3694  $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3695  $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3696  $sql .= " FROM ".$this->db->prefix()."product as p";
3697  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3698  $sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid";
3699  $sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3700  $sql .= " AND p.tobuy = 1";
3701  $sql .= " AND s.fournisseur = 1";
3702  $sql .= " AND p.rowid = ".((int) $productid);
3703  if (empty($conf->global->PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED)) {
3704  $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3705  } else {
3706  $sql .= " ORDER BY pfp.unitprice ASC";
3707  }
3708 
3709  dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3710  $result = $this->db->query($sql);
3711 
3712  if ($result) {
3713  $num = $this->db->num_rows($result);
3714 
3715  $form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3716 
3717  if (!$num) {
3718  $form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3719  } else {
3720  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3721  $form .= '<option value="0">&nbsp;</option>';
3722 
3723  $i = 0;
3724  while ($i < $num) {
3725  $objp = $this->db->fetch_object($result);
3726 
3727  $opt = '<option value="'.$objp->idprodfournprice.'"';
3728  //if there is only one supplier, preselect it
3729  if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && !empty($conf->global->PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED))) {
3730  $opt .= ' selected';
3731  }
3732  $opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3733 
3734  if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3735  $prod_supplier = new ProductFournisseur($this->db);
3736  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3737  $prod_supplier->id = $productid;
3738  $prod_supplier->fourn_qty = $objp->quantity;
3739  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3740  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3741 
3742  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3743  $priceparser = new PriceParser($this->db);
3744  $price_result = $priceparser->parseProductSupplier($prod_supplier);
3745  if ($price_result >= 0) {
3746  $objp->fprice = $price_result;
3747  if ($objp->quantity >= 1) {
3748  $objp->unitprice = $objp->fprice / $objp->quantity;
3749  }
3750  }
3751  }
3752  if ($objp->quantity == 1) {
3753  $opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3754  }
3755 
3756  $opt .= $objp->quantity.' ';
3757 
3758  if ($objp->quantity == 1) {
3759  $opt .= $langs->trans("Unit");
3760  } else {
3761  $opt .= $langs->trans("Units");
3762  }
3763  if ($objp->quantity > 1) {
3764  $opt .= " - ";
3765  $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");
3766  }
3767  if ($objp->duration) {
3768  $opt .= " - ".$objp->duration;
3769  }
3770  $opt .= "</option>\n";
3771 
3772  $form .= $opt;
3773  $i++;
3774  }
3775  }
3776 
3777  $form .= '</select>';
3778  $this->db->free($result);
3779  return $form;
3780  } else {
3781  dol_print_error($this->db);
3782  }
3783  }
3784 
3785  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3795  public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3796  {
3797  // phpcs:enable
3798  // looking for users
3799  $sql = "SELECT a.rowid, a.label";
3800  $sql .= " FROM ".$this->db->prefix()."societe_address as a";
3801  $sql .= " WHERE a.fk_soc = ".((int) $socid);
3802  $sql .= " ORDER BY a.label ASC";
3803 
3804  dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3805  $resql = $this->db->query($sql);
3806  if ($resql) {
3807  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3808  if ($showempty) {
3809  print '<option value="0">&nbsp;</option>';
3810  }
3811  $num = $this->db->num_rows($resql);
3812  $i = 0;
3813  if ($num) {
3814  while ($i < $num) {
3815  $obj = $this->db->fetch_object($resql);
3816 
3817  if ($selected && $selected == $obj->rowid) {
3818  print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3819  } else {
3820  print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3821  }
3822  $i++;
3823  }
3824  }
3825  print '</select>';
3826  return $num;
3827  } else {
3828  dol_print_error($this->db);
3829  }
3830  }
3831 
3832  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3839  {
3840  // phpcs:enable
3841  global $langs;
3842 
3843  $num = count($this->cache_conditions_paiements);
3844  if ($num > 0) {
3845  return 0; // Cache already loaded
3846  }
3847 
3848  dol_syslog(__METHOD__, LOG_DEBUG);
3849 
3850  $sql = "SELECT rowid, code, libelle as label, deposit_percent";
3851  $sql .= " FROM ".$this->db->prefix().'c_payment_term';
3852  $sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3853  $sql .= " AND active > 0";
3854  $sql .= " ORDER BY sortorder";
3855 
3856  $resql = $this->db->query($sql);
3857  if ($resql) {
3858  $num = $this->db->num_rows($resql);
3859  $i = 0;
3860  while ($i < $num) {
3861  $obj = $this->db->fetch_object($resql);
3862 
3863  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3864  $label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3865  $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3866  $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3867  $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
3868  $i++;
3869  }
3870 
3871  //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
3872 
3873  return $num;
3874  } else {
3875  dol_print_error($this->db);
3876  return -1;
3877  }
3878  }
3879 
3880  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3886  public function load_cache_availability()
3887  {
3888  // phpcs:enable
3889  global $langs;
3890 
3891  $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
3892  if ($num > 0) {
3893  return 0; // Cache already loaded
3894  }
3895 
3896  dol_syslog(__METHOD__, LOG_DEBUG);
3897 
3898  $langs->load('propal');
3899 
3900  $sql = "SELECT rowid, code, label, position";
3901  $sql .= " FROM ".$this->db->prefix().'c_availability';
3902  $sql .= " WHERE active > 0";
3903 
3904  $resql = $this->db->query($sql);
3905  if ($resql) {
3906  $num = $this->db->num_rows($resql);
3907  $i = 0;
3908  while ($i < $num) {
3909  $obj = $this->db->fetch_object($resql);
3910 
3911  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3912  $label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3913  $this->cache_availability[$obj->rowid]['code'] = $obj->code;
3914  $this->cache_availability[$obj->rowid]['label'] = $label;
3915  $this->cache_availability[$obj->rowid]['position'] = $obj->position;
3916  $i++;
3917  }
3918 
3919  $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
3920 
3921  return $num;
3922  } else {
3923  dol_print_error($this->db);
3924  return -1;
3925  }
3926  }
3927 
3938  public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
3939  {
3940  global $langs, $user;
3941 
3942  $this->load_cache_availability();
3943 
3944  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3945 
3946  print '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3947  if ($addempty) {
3948  print '<option value="0">&nbsp;</option>';
3949  }
3950  foreach ($this->cache_availability as $id => $arrayavailability) {
3951  if ($selected == $id) {
3952  print '<option value="'.$id.'" selected>';
3953  } else {
3954  print '<option value="'.$id.'">';
3955  }
3956  print dol_escape_htmltag($arrayavailability['label']);
3957  print '</option>';
3958  }
3959  print '</select>';
3960  if ($user->admin) {
3961  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3962  }
3963  print ajax_combobox($htmlname);
3964  }
3965 
3971  public function loadCacheInputReason()
3972  {
3973  global $langs;
3974 
3975  $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
3976  if ($num > 0) {
3977  return 0; // Cache already loaded
3978  }
3979 
3980  $sql = "SELECT rowid, code, label";
3981  $sql .= " FROM ".$this->db->prefix().'c_input_reason';
3982  $sql .= " WHERE active > 0";
3983 
3984  $resql = $this->db->query($sql);
3985  if ($resql) {
3986  $num = $this->db->num_rows($resql);
3987  $i = 0;
3988  $tmparray = array();
3989  while ($i < $num) {
3990  $obj = $this->db->fetch_object($resql);
3991 
3992  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3993  $label = ($obj->label != '-' ? $obj->label : '');
3994  if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) {
3995  $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3996  }
3997  if ($langs->trans($obj->code) != $obj->code) {
3998  $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3999  }
4000 
4001  $tmparray[$obj->rowid]['id'] = $obj->rowid;
4002  $tmparray[$obj->rowid]['code'] = $obj->code;
4003  $tmparray[$obj->rowid]['label'] = $label;
4004  $i++;
4005  }
4006 
4007  $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4008 
4009  unset($tmparray);
4010  return $num;
4011  } else {
4012  dol_print_error($this->db);
4013  return -1;
4014  }
4015  }
4016 
4029  public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4030  {
4031  global $langs, $user;
4032 
4033  $this->loadCacheInputReason();
4034 
4035  print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4036  if ($addempty) {
4037  print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
4038  }
4039  foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4040  if ($arraydemandreason['code'] == $exclude) {
4041  continue;
4042  }
4043 
4044  if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4045  print '<option value="'.$arraydemandreason['id'].'" selected>';
4046  } else {
4047  print '<option value="'.$arraydemandreason['id'].'">';
4048  }
4049  $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4050  print $langs->trans($label);
4051  print '</option>';
4052  }
4053  print '</select>';
4054  if ($user->admin && empty($notooltip)) {
4055  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4056  }
4057  print ajax_combobox('select_'.$htmlname);
4058  }
4059 
4060  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4066  public function load_cache_types_paiements()
4067  {
4068  // phpcs:enable
4069  global $langs;
4070 
4071  $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4072  if ($num > 0) {
4073  return $num; // Cache already loaded
4074  }
4075 
4076  dol_syslog(__METHOD__, LOG_DEBUG);
4077 
4078  $this->cache_types_paiements = array();
4079 
4080  $sql = "SELECT id, code, libelle as label, type, active";
4081  $sql .= " FROM ".$this->db->prefix()."c_paiement";
4082  $sql .= " WHERE entity IN (".getEntity('c_paiement').")";
4083 
4084  $resql = $this->db->query($sql);
4085  if ($resql) {
4086  $num = $this->db->num_rows($resql);
4087  $i = 0;
4088  while ($i < $num) {
4089  $obj = $this->db->fetch_object($resql);
4090 
4091  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4092  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4093  $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4094  $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4095  $this->cache_types_paiements[$obj->id]['label'] = $label;
4096  $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4097  $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4098  $i++;
4099  }
4100 
4101  $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4102 
4103  return $num;
4104  } else {
4105  dol_print_error($this->db);
4106  return -1;
4107  }
4108  }
4109 
4110 
4111  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4129  public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4130  {
4131  // phpcs:enable
4132  print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4133  }
4134 
4135 
4152  public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4153  {
4154  global $langs, $user, $conf;
4155 
4156  $out = '';
4157  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
4158 
4160 
4161  // Set default value if not already set by caller
4162  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
4163  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4164  }
4165 
4166  $out.= '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4167  if ($addempty) {
4168  $out.= '<option value="0">&nbsp;</option>';
4169  }
4170 
4171  $selectedDepositPercent = null;
4172 
4173  foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4174  if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4175  continue;
4176  }
4177 
4178  if ($selected == $id) {
4179  $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4180  $out .= '<option value="'.$id.'" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4181  } else {
4182  $out .= '<option value="'.$id.'" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4183  }
4184  $label = $arrayconditions['label'];
4185 
4186  if (!empty($arrayconditions['deposit_percent'])) {
4187  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4188  }
4189 
4190  $out.= $label;
4191  $out.= '</option>';
4192  }
4193  $out.= '</select>';
4194  if ($user->admin && empty($noinfoadmin)) {
4195  $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4196  }
4197  $out.= ajax_combobox($htmlname);
4198 
4199  if ($deposit_percent >= 0) {
4200  $out .= ' <span id="'.$htmlname.'_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4201  $out .= $langs->trans('DepositPercent') . ' : ';
4202  $out .= '<input id="'.$htmlname.'_deposit_percent" name="'.$htmlname.'_deposit_percent" class="maxwidth50" value="' . strval($deposit_percent) . '" />';
4203  $out .= '</span>';
4204  $out .= '
4205  <script>
4206  $(document).ready(function () {
4207  $("#' . $htmlname . '").change(function () {
4208  let $selected = $(this).find("option:selected");
4209  let depositPercent = $selected.attr("data-deposit_percent");
4210 
4211  if (depositPercent.length > 0) {
4212  $("#'.$htmlname.'_deposit_percent_container").show().find("#'.$htmlname.'_deposit_percent").val(depositPercent);
4213  } else {
4214  $("#'.$htmlname.'_deposit_percent_container").hide();
4215  }
4216 
4217  return true;
4218  });
4219  });
4220  </script>';
4221  }
4222 
4223  return $out;
4224  }
4225 
4226 
4227  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4244  public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4245  {
4246  // phpcs:enable
4247  global $langs, $user, $conf;
4248 
4249  $out = '';
4250 
4251  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
4252 
4253  $filterarray = array();
4254  if ($filtertype == 'CRDT') {
4255  $filterarray = array(0, 2, 3);
4256  } elseif ($filtertype == 'DBIT') {
4257  $filterarray = array(1, 2, 3);
4258  } elseif ($filtertype != '' && $filtertype != '-1') {
4259  $filterarray = explode(',', $filtertype);
4260  }
4261 
4262  $this->load_cache_types_paiements();
4263 
4264  // Set default value if not already set by caller
4265  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
4266  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4267  }
4268 
4269  $out .= '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4270  if ($empty) {
4271  $out .= '<option value="">&nbsp;</option>';
4272  }
4273  foreach ($this->cache_types_paiements as $id => $arraytypes) {
4274  // If not good status
4275  if ($active >= 0 && $arraytypes['active'] != $active) {
4276  continue;
4277  }
4278 
4279  // On passe si on a demande de filtrer sur des modes de paiments particuliers
4280  if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4281  continue;
4282  }
4283 
4284  // We discard empty line if showempty is on because an empty line has already been output.
4285  if ($empty && empty($arraytypes['code'])) {
4286  continue;
4287  }
4288 
4289  if ($format == 0) {
4290  $out .= '<option value="'.$id.'"';
4291  } elseif ($format == 1) {
4292  $out .= '<option value="'.$arraytypes['code'].'"';
4293  } elseif ($format == 2) {
4294  $out .= '<option value="'.$arraytypes['code'].'"';
4295  } elseif ($format == 3) {
4296  $out .= '<option value="'.$id.'"';
4297  }
4298  // Print attribute selected or not
4299  if ($format == 1 || $format == 2) {
4300  if ($selected == $arraytypes['code']) {
4301  $out .= ' selected';
4302  }
4303  } else {
4304  if ($selected == $id) {
4305  $out .= ' selected';
4306  }
4307  }
4308  $out .= '>';
4309  $value = '';
4310  if ($format == 0) {
4311  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4312  } elseif ($format == 1) {
4313  $value = $arraytypes['code'];
4314  } elseif ($format == 2) {
4315  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4316  } elseif ($format == 3) {
4317  $value = $arraytypes['code'];
4318  }
4319  $out .= $value ? $value : '&nbsp;';
4320  $out .= '</option>';
4321  }
4322  $out .= '</select>';
4323  if ($user->admin && !$noadmininfo) {
4324  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4325  }
4326  $out .= ajax_combobox('select'.$htmlname);
4327 
4328  if (empty($nooutput)) {
4329  print $out;
4330  } else {
4331  return $out;
4332  }
4333  }
4334 
4335 
4344  public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4345  {
4346  global $langs;
4347 
4348  $return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4349  $options = array(
4350  'HT'=>$langs->trans("HT"),
4351  'TTC'=>$langs->trans("TTC")
4352  );
4353  foreach ($options as $id => $value) {
4354  if ($selected == $id) {
4355  $return .= '<option value="'.$id.'" selected>'.$value;
4356  } else {
4357  $return .= '<option value="'.$id.'">'.$value;
4358  }
4359  $return .= '</option>';
4360  }
4361  $return .= '</select>';
4362  if ($addjscombo) {
4363  $return .= ajax_combobox('select_'.$htmlname);
4364  }
4365 
4366  return $return;
4367  }
4368 
4369  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4375  public function load_cache_transport_mode()
4376  {
4377  // phpcs:enable
4378  global $langs;
4379 
4380  $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4381  if ($num > 0) {
4382  return $num; // Cache already loaded
4383  }
4384 
4385  dol_syslog(__METHOD__, LOG_DEBUG);
4386 
4387  $this->cache_transport_mode = array();
4388 
4389  $sql = "SELECT rowid, code, label, active";
4390  $sql .= " FROM ".$this->db->prefix()."c_transport_mode";
4391  $sql .= " WHERE entity IN (".getEntity('c_transport_mode').")";
4392 
4393  $resql = $this->db->query($sql);
4394  if ($resql) {
4395  $num = $this->db->num_rows($resql);
4396  $i = 0;
4397  while ($i < $num) {
4398  $obj = $this->db->fetch_object($resql);
4399 
4400  // If traduction exist, we use it else we take the default label
4401  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4402  $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4403  $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4404  $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4405  $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4406  $i++;
4407  }
4408 
4409  $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4410 
4411  return $num;
4412  } else {
4413  dol_print_error($this->db);
4414  return -1;
4415  }
4416  }
4417 
4431  public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4432  {
4433  global $langs, $user;
4434 
4435  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
4436 
4437  $this->load_cache_transport_mode();
4438 
4439  print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4440  if ($empty) {
4441  print '<option value="">&nbsp;</option>';
4442  }
4443  foreach ($this->cache_transport_mode as $id => $arraytypes) {
4444  // If not good status
4445  if ($active >= 0 && $arraytypes['active'] != $active) {
4446  continue;
4447  }
4448 
4449  // We discard empty line if showempty is on because an empty line has already been output.
4450  if ($empty && empty($arraytypes['code'])) {
4451  continue;
4452  }
4453 
4454  if ($format == 0) {
4455  print '<option value="'.$id.'"';
4456  } elseif ($format == 1) {
4457  print '<option value="'.$arraytypes['code'].'"';
4458  } elseif ($format == 2) {
4459  print '<option value="'.$arraytypes['code'].'"';
4460  } elseif ($format == 3) {
4461  print '<option value="'.$id.'"';
4462  }
4463  // If text is selected, we compare with code, else with id
4464  if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4465  print ' selected';
4466  } elseif ($selected == $id) {
4467  print ' selected';
4468  }
4469  print '>';
4470  $value = '';
4471  if ($format == 0) {
4472  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4473  } elseif ($format == 1) {
4474  $value = $arraytypes['code'];
4475  } elseif ($format == 2) {
4476  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4477  } elseif ($format == 3) {
4478  $value = $arraytypes['code'];
4479  }
4480  print $value ? $value : '&nbsp;';
4481  print '</option>';
4482  }
4483  print '</select>';
4484  if ($user->admin && !$noadmininfo) {
4485  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4486  }
4487  }
4488 
4501  public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4502  {
4503  global $langs, $conf, $user;
4504 
4505  $langs->load("admin");
4506  $langs->load("deliveries");
4507 
4508  $sql = "SELECT rowid, code, libelle as label";
4509  $sql .= " FROM ".$this->db->prefix()."c_shipment_mode";
4510  $sql .= " WHERE active > 0";
4511  if ($filtre) {
4512  $sql .= " AND ".$filtre;
4513  }
4514  $sql .= " ORDER BY libelle ASC";
4515 
4516  dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
4517  $result = $this->db->query($sql);
4518  if ($result) {
4519  $num = $this->db->num_rows($result);
4520  $i = 0;
4521  if ($num) {
4522  print '<select id="select'.$htmlname.'" class="flat selectshippingmethod'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4523  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4524  print '<option value="-1">&nbsp;</option>';
4525  }
4526  while ($i < $num) {
4527  $obj = $this->db->fetch_object($result);
4528  if ($selected == $obj->rowid) {
4529  print '<option value="'.$obj->rowid.'" selected>';
4530  } else {
4531  print '<option value="'.$obj->rowid.'">';
4532  }
4533  print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
4534  print '</option>';
4535  $i++;
4536  }
4537  print "</select>";
4538  if ($user->admin && empty($noinfoadmin)) {
4539  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4540  }
4541 
4542  print ajax_combobox('select'.$htmlname);
4543  } else {
4544  print $langs->trans("NoShippingMethodDefined");
4545  }
4546  } else {
4547  dol_print_error($this->db);
4548  }
4549  }
4550 
4560  public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4561  {
4562  global $langs;
4563 
4564  $langs->load("deliveries");
4565 
4566  if ($htmlname != "none") {
4567  print '<form method="POST" action="'.$page.'">';
4568  print '<input type="hidden" name="action" value="setshippingmethod">';
4569  print '<input type="hidden" name="token" value="'.newToken().'">';
4570  $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4571  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4572  print '</form>';
4573  } else {
4574  if ($selected) {
4575  $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4576  print $langs->trans("SendingMethod".strtoupper($code));
4577  } else {
4578  print "&nbsp;";
4579  }
4580  }
4581  }
4582 
4591  public function selectSituationInvoices($selected = '', $socid = 0)
4592  {
4593  global $langs;
4594 
4595  $langs->load('bills');
4596 
4597  $opt = '<option value="" selected></option>';
4598  $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4599  $sql .= ' FROM '.$this->db->prefix().'facture';
4600  $sql .= ' WHERE entity IN ('.getEntity('invoice').')';
4601  $sql .= ' AND situation_counter >= 1';
4602  $sql .= ' AND fk_soc = '.(int) $socid;
4603  $sql .= ' AND type <> 2';
4604  $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4605  $resql = $this->db->query($sql);
4606 
4607  if ($resql && $this->db->num_rows($resql) > 0) {
4608  // Last seen cycle
4609  $ref = 0;
4610  while ($obj = $this->db->fetch_object($resql)) {
4611  //Same cycle ?
4612  if ($obj->situation_cycle_ref != $ref) {
4613  // Just seen this cycle
4614  $ref = $obj->situation_cycle_ref;
4615  //not final ?
4616  if ($obj->situation_final != 1) {
4617  //Not prov?
4618  if (substr($obj->ref, 1, 4) != 'PROV') {
4619  if ($selected == $obj->rowid) {
4620  $opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
4621  } else {
4622  $opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
4623  }
4624  }
4625  }
4626  }
4627  }
4628  } else {
4629  dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
4630  }
4631  if ($opt == '<option value ="" selected></option>') {
4632  $opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
4633  }
4634  return $opt;
4635  }
4636 
4646  public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4647  {
4648  global $langs;
4649 
4650  $langs->load('products');
4651 
4652  $return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
4653 
4654  $sql = "SELECT rowid, label, code FROM ".$this->db->prefix()."c_units";
4655  $sql .= ' WHERE active > 0';
4656  if (!empty($unit_type)) {
4657  $sql .= " AND unit_type = '".$this->db->escape($unit_type)."'";
4658  }
4659  $sql .= " ORDER BY sortorder";
4660 
4661  $resql = $this->db->query($sql);
4662  if ($resql && $this->db->num_rows($resql) > 0) {
4663  if ($showempty) {
4664  $return .= '<option value="none"></option>';
4665  }
4666 
4667  while ($res = $this->db->fetch_object($resql)) {
4668  $unitLabel = $res->label;
4669  if (!empty($langs->tab_translate['unit'.$res->code])) { // check if Translation is available before
4670  $unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
4671  }
4672 
4673  if ($selected == $res->rowid) {
4674  $return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
4675  } else {
4676  $return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
4677  }
4678  }
4679  $return .= '</select>';
4680  }
4681  return $return;
4682  }
4683 
4684  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4699  public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4700  {
4701  // phpcs:enable
4702  global $langs, $conf;
4703 
4704  $out = '';
4705 
4706  $langs->load("admin");
4707  $num = 0;
4708 
4709  $sql = "SELECT rowid, label, bank, clos as status, currency_code";
4710  $sql .= " FROM ".$this->db->prefix()."bank_account";
4711  $sql .= " WHERE entity IN (".getEntity('bank_account').")";
4712  if ($status != 2) {
4713  $sql .= " AND clos = ".(int) $status;
4714  }
4715  if ($filtre) {
4716  $sql .= " AND ".$filtre;
4717  }
4718  $sql .= " ORDER BY label";
4719 
4720  dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
4721  $result = $this->db->query($sql);
4722  if ($result) {
4723  $num = $this->db->num_rows($result);
4724  $i = 0;
4725  if ($num) {
4726  $out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4727  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4728  $out .= '<option value="-1">&nbsp;</option>';
4729  }
4730 
4731  while ($i < $num) {
4732  $obj = $this->db->fetch_object($result);
4733  if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4734  $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'" selected>';
4735  } else {
4736  $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'">';
4737  }
4738  $out .= trim($obj->label);
4739  if ($showcurrency) {
4740  $out .= ' ('.$obj->currency_code.')';
4741  }
4742  if ($status == 2 && $obj->status == 1) {
4743  $out .= ' ('.$langs->trans("Closed").')';
4744  }
4745  $out .= '</option>';
4746  $i++;
4747  }
4748  $out .= "</select>";
4749  $out .= ajax_combobox('select'.$htmlname);
4750  } else {
4751  if ($status == 0) {
4752  $out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
4753  } else {
4754  $out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
4755  }
4756  }
4757  } else {
4758  dol_print_error($this->db);
4759  }
4760 
4761  // Output or return
4762  if (empty($nooutput)) {
4763  print $out;
4764  } else {
4765  return $out;
4766  }
4767 
4768  return $num;
4769  }
4770 
4782  public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4783  {
4784  global $langs, $conf;
4785 
4786  $langs->load("admin");
4787  $num = 0;
4788 
4789  $sql = "SELECT rowid, name, fk_country, status, entity";
4790  $sql .= " FROM ".$this->db->prefix()."establishment";
4791  $sql .= " WHERE 1=1";
4792  if ($status != 2) {
4793  $sql .= " AND status = ".(int) $status;
4794  }
4795  if ($filtre) {
4796  $sql .= " AND ".$filtre;
4797  }
4798  $sql .= " ORDER BY name";
4799 
4800  dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
4801  $result = $this->db->query($sql);
4802  if ($result) {
4803  $num = $this->db->num_rows($result);
4804  $i = 0;
4805  if ($num) {
4806  print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4807  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4808  print '<option value="-1">&nbsp;</option>';
4809  }
4810 
4811  while ($i < $num) {
4812  $obj = $this->db->fetch_object($result);
4813  if ($selected == $obj->rowid) {
4814  print '<option value="'.$obj->rowid.'" selected>';
4815  } else {
4816  print '<option value="'.$obj->rowid.'">';
4817  }
4818  print trim($obj->name);
4819  if ($status == 2 && $obj->status == 1) {
4820  print ' ('.$langs->trans("Closed").')';
4821  }
4822  print '</option>';
4823  $i++;
4824  }
4825  print "</select>";
4826  } else {
4827  if ($status == 0) {
4828  print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
4829  } else {
4830  print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
4831  }
4832  }
4833  } else {
4834  dol_print_error($this->db);
4835  }
4836  }
4837 
4847  public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4848  {
4849  global $langs;
4850  if ($htmlname != "none") {
4851  print '<form method="POST" action="'.$page.'">';
4852  print '<input type="hidden" name="action" value="setbankaccount">';
4853  print '<input type="hidden" name="token" value="'.newToken().'">';
4854  print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4855  $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4856  if ($nbaccountfound > 0) {
4857  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4858  }
4859  print '</form>';
4860  } else {
4861  $langs->load('banks');
4862 
4863  if ($selected) {
4864  require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
4865  $bankstatic = new Account($this->db);
4866  $result = $bankstatic->fetch($selected);
4867  if ($result) {
4868  print $bankstatic->getNomUrl(1);
4869  }
4870  } else {
4871  print "&nbsp;";
4872  }
4873  }
4874  }
4875 
4876  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4895  public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4896  {
4897  // phpcs:enable
4898  global $conf, $langs;
4899  $langs->load("categories");
4900 
4901  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4902 
4903  // For backward compatibility
4904  if (is_numeric($type)) {
4905  dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4906  }
4907 
4908  if ($type === Categorie::TYPE_BANK_LINE) {
4909  // TODO Move this into common category feature
4910  $cate_arbo = array();
4911  $sql = "SELECT c.label, c.rowid";
4912  $sql .= " FROM ".$this->db->prefix()."bank_categ as c";
4913  $sql .= " WHERE entity = ".$conf->entity;
4914  $sql .= " ORDER BY c.label";
4915  $result = $this->db->query($sql);
4916  if ($result) {
4917  $num = $this->db->num_rows($result);
4918  $i = 0;
4919  while ($i < $num) {
4920  $objp = $this->db->fetch_object($result);
4921  if ($objp) {
4922  $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label, 'color'=>'', 'picto'=>'category');
4923  }
4924  $i++;
4925  }
4926  $this->db->free($result);
4927  } else {
4928  dol_print_error($this->db);
4929  }
4930  } else {
4931  $cat = new Categorie($this->db);
4932  $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4933  }
4934 
4935  $outarray = array();
4936 
4937  $output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4938  if (is_array($cate_arbo)) {
4939  if (!count($cate_arbo)) {
4940  $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4941  } else {
4942  $output .= '<option value="-1">&nbsp;</option>';
4943  foreach ($cate_arbo as $key => $value) {
4944  if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
4945  $add = 'selected ';
4946  } else {
4947  $add = '';
4948  }
4949  $output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'"';
4950  $output .= ' data-html="'.dol_escape_htmltag(img_picto('', 'category', 'class="pictofixedwidth" style="color: #'.$cate_arbo[$key]['color'].'"').dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle')).'"';
4951  $output .= '>';
4952  $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
4953  $output .= '</option>';
4954 
4955  $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4956  }
4957  }
4958  }
4959  $output .= '</select>';
4960  $output .= "\n";
4961 
4962  if ($outputmode == 2) {
4963  return $cate_arbo;
4964  } elseif ($outputmode) {
4965  return $outarray;
4966  }
4967  return $output;
4968  }
4969 
4970  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4987  public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4988  {
4989  // phpcs:enable
4990  dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4991  print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4992  }
4993 
5021  public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5022  {
5023  global $langs, $conf;
5024 
5025  $more = '<!-- formconfirm - before call, page='.dol_escape_htmltag($page).' -->';
5026  $formconfirm = '';
5027  $inputok = array();
5028  $inputko = array();
5029 
5030  // Clean parameters
5031  $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5032  if ($conf->browser->layout == 'phone') {
5033  $width = '95%';
5034  }
5035 
5036  // Set height automatically if not defined
5037  if (empty($height)) {
5038  $height = 220;
5039  if (is_array($formquestion) && count($formquestion) > 2) {
5040  $height += ((count($formquestion) - 2) * 24);
5041  }
5042  }
5043 
5044  if (is_array($formquestion) && !empty($formquestion)) {
5045  // First add hidden fields and value
5046  foreach ($formquestion as $key => $input) {
5047  if (is_array($input) && !empty($input)) {
5048  if ($input['type'] == 'hidden') {
5049  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
5050  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
5051 
5052  $more .= '<input type="hidden" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'" value="'.dol_escape_htmltag($input['value']).'" class="'.$morecss.'"'.$moreattr.'>'."\n";
5053  }
5054  }
5055  }
5056 
5057  // Now add questions
5058  $moreonecolumn = '';
5059  $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
5060  foreach ($formquestion as $key => $input) {
5061  if (is_array($input) && !empty($input)) {
5062  $size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : ''); // deprecated. Use morecss instead.
5063  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
5064  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
5065 
5066  if ($input['type'] == 'text') {
5067  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="text" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$size.' value="'.(empty($input['value']) ? '' : $input['value']).'"'.$moreattr.' /></div></div>'."\n";
5068  } elseif ($input['type'] == 'password') {
5069  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="password" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$size.' value="'.(empty($input['value']) ? '' : $input['value']).'"'.$moreattr.' /></div></div>'."\n";
5070  } elseif ($input['type'] == 'textarea') {
5071  /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5072  $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5073  $more .= $input['value'];
5074  $more .= '</textarea>';
5075  $more .= '</div></div>'."\n";*/
5076  $moreonecolumn .= '<div class="margintoponly">';
5077  $moreonecolumn .= $input['label'].'<br>';
5078  $moreonecolumn .= '<textarea name="'.dol_escape_htmltag($input['name']).'" id="'.dol_escape_htmltag($input['name']).'" class="'.$morecss.'"'.$moreattr.'>';
5079  $moreonecolumn .= $input['value'];
5080  $moreonecolumn .= '</textarea>';
5081  $moreonecolumn .= '</div>';
5082  } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5083  if (empty($morecss)) {
5084  $morecss = 'minwidth100';
5085  }
5086 
5087  $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5088  $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5089  $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5090  $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5091  $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5092  $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5093  $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5094 
5095  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5096  if (!empty($input['label'])) {
5097  $more .= $input['label'].'</div><div class="tagtd left">';
5098  }
5099  if ($input['type'] == 'select') {
5100  $more .= $this->selectarray($input['name'], $input['values'], !empty($input['default']) ? $input['default'] : '-1', $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
5101  } else {
5102  $more .= $this->multiselectarray($input['name'], $input['values'], is_array($input['default']) ? $input['default'] : [$input['default']], $key_in_label, $value_as_key, $morecss, $translate, $maxlen, $moreattr);
5103  }
5104  $more .= '</div></div>'."\n";
5105  } elseif ($input['type'] == 'checkbox') {
5106  $more .= '<div class="tagtr">';
5107  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
5108  $more .= '<input type="checkbox" class="flat'.($morecss ? ' '.$morecss : '').'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$moreattr;
5109  if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5110  $more .= ' checked';
5111  }
5112  if (is_bool($input['value']) && $input['value']) {
5113  $more .= ' checked';
5114  }
5115  if (isset($input['disabled'])) {
5116  $more .= ' disabled';
5117  }
5118  $more .= ' /></div>';
5119  $more .= '</div>'."\n";
5120  } elseif ($input['type'] == 'radio') {
5121  $i = 0;
5122  foreach ($input['values'] as $selkey => $selval) {
5123  $more .= '<div class="tagtr">';
5124  if (isset($input['label'])) {
5125  if ($i == 0) {
5126  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
5127  } else {
5128  $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
5129  }
5130  }
5131  $more .= '<div class="tagtd'.($i == 0 ? ' tdtop' : '').'"><input type="radio" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name'].$selkey).'" name="'.dol_escape_htmltag($input['name']).'" value="'.$selkey.'"'.$moreattr;
5132  if (!empty($input['disabled'])) {
5133  $more .= ' disabled';
5134  }
5135  if (isset($input['default']) && $input['default'] === $selkey) {
5136  $more .= ' checked="checked"';
5137  }
5138  $more .= ' /> ';
5139  $more .= '<label for="'.dol_escape_htmltag($input['name'].$selkey).'" class="valignmiddle">'.$selval.'</label>';
5140  $more .= '</div></div>'."\n";
5141  $i++;
5142  }
5143  } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5144  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
5145  $more .= '<div class="tagtd">';
5146  $addnowlink = (empty($input['datenow']) ? 0 : 1);
5147  $more .= $this->selectDate($input['value'], $input['name'], ($input['type'] == 'datetime' ? 1 : 0), ($input['type'] == 'datetime' ? 1 : 0), 0, '', 1, $addnowlink);
5148  $more .= '</div></div>'."\n";
5149  $formquestion[] = array('name'=>$input['name'].'day');
5150  $formquestion[] = array('name'=>$input['name'].'month');
5151  $formquestion[] = array('name'=>$input['name'].'year');
5152  $formquestion[] = array('name'=>$input['name'].'hour');
5153  $formquestion[] = array('name'=>$input['name'].'min');
5154  } elseif ($input['type'] == 'other') {
5155  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5156  if (!empty($input['label'])) {
5157  $more .= $input['label'].'</div><div class="tagtd">';
5158  }
5159  $more .= $input['value'];
5160  $more .= '</div></div>'."\n";
5161  } elseif ($input['type'] == 'onecolumn') {
5162  $moreonecolumn .= '<div class="margintoponly">';
5163  $moreonecolumn .= $input['value'];
5164  $moreonecolumn .= '</div>'."\n";
5165  } elseif ($input['type'] == 'hidden') {
5166  // Do nothing more, already added by a previous loop
5167  } elseif ($input['type'] == 'separator') {
5168  $more .= '<br>';
5169  } else {
5170  $more .= 'Error type '.$input['type'].' for the confirm box is not a supported type';
5171  }
5172  }
5173  }
5174  $more .= '</div>'."\n";
5175  $more .= $moreonecolumn;
5176  }
5177 
5178  // JQUERY method dialog is broken with smartphone, we use standard HTML.
5179  // 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
5180  // See page product/card.php for example
5181  if (!empty($conf->dol_use_jmobile)) {
5182  $useajax = 0;
5183  }
5184  if (empty($conf->use_javascript_ajax)) {
5185  $useajax = 0;
5186  }
5187 
5188  if ($useajax) {
5189  $autoOpen = true;
5190  $dialogconfirm = 'dialog-confirm';
5191  $button = '';
5192  if (!is_numeric($useajax)) {
5193  $button = $useajax;
5194  $useajax = 1;
5195  $autoOpen = false;
5196  $dialogconfirm .= '-'.$button;
5197  }
5198  $pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.urlencode($action).'&confirm=yes';
5199  $pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.urlencode($action).'&confirm=no' : '');
5200 
5201  // Add input fields into list of fields to read during submit (inputok and inputko)
5202  if (is_array($formquestion)) {
5203  foreach ($formquestion as $key => $input) {
5204  //print "xx ".$key." rr ".is_array($input)."<br>\n";
5205  // Add name of fields to propagate with the GET when submitting the form with button OK.
5206  if (is_array($input) && isset($input['name'])) {
5207  if (strpos($input['name'], ',') > 0) {
5208  $inputok = array_merge($inputok, explode(',', $input['name']));
5209  } else {
5210  array_push($inputok, $input['name']);
5211  }
5212  }
5213  // Add name of fields to propagate with the GET when submitting the form with button KO.
5214  if (isset($input['inputko']) && $input['inputko'] == 1) {
5215  array_push($inputko, $input['name']);
5216  }
5217  }
5218  }
5219 
5220  // Show JQuery confirm box.
5221  $formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
5222  if (is_array($formquestion) && !empty($formquestion['text'])) {
5223  $formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
5224  }
5225  if (!empty($more)) {
5226  $formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
5227  }
5228  $formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
5229  $formconfirm .= '</div>'."\n";
5230 
5231  $formconfirm .= "\n<!-- begin code of popup for formconfirm page=".$page." -->\n";
5232  $formconfirm .= '<script type="text/javascript">'."\n";
5233  $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5234  $formconfirm .= 'jQuery(document).ready(function() {
5235  $(function() {
5236  $( "#'.$dialogconfirm.'" ).dialog(
5237  {
5238  autoOpen: '.($autoOpen ? "true" : "false").',';
5239  if ($newselectedchoice == 'no') {
5240  $formconfirm .= '
5241  open: function() {
5242  $(this).parent().find("button.ui-button:eq(2)").focus();
5243  },';
5244  }
5245 
5246  $jsforcursor = '';
5247  if ($useajax == 1) {
5248  $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor'."\n";
5249  $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");'."\n";
5250  }
5251 
5252  $postconfirmas = 'GET';
5253 
5254  $formconfirm .= '
5255  resizable: false,
5256  height: "'.$height.'",
5257  width: "'.$width.'",
5258  modal: true,
5259  closeOnEscape: false,
5260  buttons: {
5261  "'.dol_escape_js($langs->transnoentities($labelbuttonyes)).'": function() {
5262  var options = "token='.urlencode(newToken()).'";
5263  var inputok = '.json_encode($inputok).'; /* List of fields into form */
5264  var page = "'.dol_escape_js(!empty($page) ? $page : '').'";
5265  var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
5266 
5267  if (inputok.length > 0) {
5268  $.each(inputok, function(i, inputname) {
5269  var more = "";
5270  var inputvalue;
5271  if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5272  inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5273  } else {
5274  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5275  inputvalue = $("#" + inputname + more).val();
5276  }
5277  if (typeof inputvalue == "undefined") { inputvalue=""; }
5278  console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5279  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5280  });
5281  }
5282  var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5283  if (pageyes.length > 0) {';
5284  if ($postconfirmas == 'GET') {
5285  $formconfirm .= 'location.href = urljump;';
5286  } else {
5287  $formconfirm .= $jsforcursor;
5288  $formconfirm .= 'var post = $.post(
5289  pageyes,
5290  options,
5291  function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5292  );';
5293  }
5294  $formconfirm .= '
5295  console.log("after post ok");
5296  }
5297  $(this).dialog("close");
5298  },
5299  "'.dol_escape_js($langs->transnoentities($labelbuttonno)).'": function() {
5300  var options = "token='.urlencode(newToken()).'";
5301  var inputko = '.json_encode($inputko).'; /* List of fields into form */
5302  var page = "'.dol_escape_js(!empty($page) ? $page : '').'";
5303  var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
5304  if (inputko.length > 0) {
5305  $.each(inputko, function(i, inputname) {
5306  var more = "";
5307  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5308  var inputvalue = $("#" + inputname + more).val();
5309  if (typeof inputvalue == "undefined") { inputvalue=""; }
5310  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5311  });
5312  }
5313  var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5314  //alert(urljump);
5315  if (pageno.length > 0) {';
5316  if ($postconfirmas == 'GET') {
5317  $formconfirm .= 'location.href = urljump;';
5318  } else {
5319  $formconfirm .= $jsforcursor;
5320  $formconfirm .= 'var post = $.post(
5321  pageno,
5322  options,
5323  function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5324  );';
5325  }
5326  $formconfirm .= '
5327  console.log("after post ko");
5328  }
5329  $(this).dialog("close");
5330  }
5331  }
5332  }
5333  );
5334 
5335  var button = "'.$button.'";
5336  if (button.length > 0) {
5337  $( "#" + button ).click(function() {
5338  $("#'.$dialogconfirm.'").dialog("open");
5339  });
5340  }
5341  });
5342  });
5343  </script>';
5344  $formconfirm .= "<!-- end ajax formconfirm -->\n";
5345  } else {
5346  $formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n";
5347 
5348  if (empty($disableformtag)) {
5349  $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
5350  }
5351 
5352  $formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
5353  $formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
5354 
5355  $formconfirm .= '<table class="valid centpercent">'."\n";
5356 
5357  // Line title
5358  $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5359  $formconfirm .= img_picto('', 'pictoconfirm').' '.$title;
5360  $formconfirm .= '</td></tr>'."\n";
5361 
5362  // Line text
5363  if (is_array($formquestion) && !empty($formquestion['text'])) {
5364  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
5365  }
5366 
5367  // Line form fields
5368  if ($more) {
5369  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'."\n";
5370  $formconfirm .= $more;
5371  $formconfirm .= '</td></tr>'."\n";
5372  }
5373 
5374  // Line with question
5375  $formconfirm .= '<tr class="valid">';
5376  $formconfirm .= '<td class="valid">'.$question.'</td>';
5377  $formconfirm .= '<td class="valid center">';
5378  $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5379  $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="'.$langs->trans("Validate").'">';
5380  $formconfirm .= '</td>';
5381  $formconfirm .= '</tr>'."\n";
5382 
5383  $formconfirm .= '</table>'."\n";
5384 
5385  if (empty($disableformtag)) {
5386  $formconfirm .= "</form>\n";
5387  }
5388  $formconfirm .= '<br>';
5389 
5390  if (!empty($conf->use_javascript_ajax)) {
5391  $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5392  $formconfirm .= '<script type="text/javascript">'."\n";
5393  $formconfirm .= '
5394  $(document).ready(function () {
5395  $(".confirmvalidatebutton").on("click", function() {
5396  console.log("We click on button");
5397  $(this).attr("disabled", "disabled");
5398  setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5399  //console.log($(this).closest("form"));
5400  $(this).closest("form").submit();
5401  });
5402  });
5403  ';
5404  $formconfirm .= '</script>'."\n";
5405  }
5406 
5407  $formconfirm .= "<!-- end formconfirm -->\n";
5408  }
5409 
5410  return $formconfirm;
5411  }
5412 
5413 
5414  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5430  public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5431  {
5432  // phpcs:enable
5433  global $langs;
5434 
5435  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
5436  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
5437 
5438  $out = '';
5439 
5440  $formproject = new FormProjets($this->db);
5441 
5442  $langs->load("project");
5443  if ($htmlname != "none") {
5444  $out .= '<form method="post" action="'.$page.'">';
5445  $out .= '<input type="hidden" name="action" value="classin">';
5446  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5447  $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5448  $out .= '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5449  $out .= '</form>';
5450  } else {
5451  $out .= '<span class="project_head_block">';
5452  if ($selected) {
5453  $projet = new Project($this->db);
5454  $projet->fetch($selected);
5455  $out .= $projet->getNomUrl(0, '', 1);
5456  } else {
5457  $out .= '<span class="opacitymedium">'.$textifnoproject.'</span>';
5458  }
5459  $out .= '</span>';
5460  }
5461 
5462  if (empty($nooutput)) {
5463  print $out;
5464  return '';
5465  }
5466  return $out;
5467  }
5468 
5469  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5485  public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5486  {
5487  // phpcs:enable
5488  global $langs;
5489 
5490  $out = '';
5491 
5492  if ($htmlname != "none") {
5493  $out .= '<form method="POST" action="'.$page.'">';
5494  $out .= '<input type="hidden" name="action" value="setconditions">';
5495  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5496  if ($type) {
5497  $out .= '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5498  }
5499  $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5500  $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
5501  $out .= '</form>';
5502  } else {
5503  if ($selected) {
5505  if (isset($this->cache_conditions_paiements[$selected])) {
5506  $label = $this->cache_conditions_paiements[$selected]['label'];
5507 
5508  if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5509  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5510  }
5511 
5512  $out .= $label;
5513  } else {
5514  $langs->load('errors');
5515  $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5516  }
5517  } else {
5518  $out .= '&nbsp;';
5519  }
5520  }
5521 
5522  if (empty($nooutput)) {
5523  print $out;
5524  return '';
5525  }
5526  return $out;
5527  }
5528 
5529  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5539  public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5540  {
5541  // phpcs:enable
5542  global $langs;
5543  if ($htmlname != "none") {
5544  print '<form method="post" action="'.$page.'">';
5545  print '<input type="hidden" name="action" value="setavailability">';
5546  print '<input type="hidden" name="token" value="'.newToken().'">';
5547  $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5548  print '<input type="submit" name="modify" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5549  print '<input type="submit" name="cancel" class="button smallpaddingimp" value="'.$langs->trans("Cancel").'">';
5550  print '</form>';
5551  } else {
5552  if ($selected) {
5553  $this->load_cache_availability();
5554  print $this->cache_availability[$selected]['label'];
5555  } else {
5556  print "&nbsp;";
5557  }
5558  }
5559  }
5560 
5571  public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5572  {
5573  global $langs;
5574  if ($htmlname != "none") {
5575  print '<form method="post" action="'.$page.'">';
5576  print '<input type="hidden" name="action" value="setdemandreason">';
5577  print '<input type="hidden" name="token" value="'.newToken().'">';
5578  $this->selectInputReason($selected, $htmlname, -1, $addempty);
5579  print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5580  print '</form>';
5581  } else {
5582  if ($selected) {
5583  $this->loadCacheInputReason();
5584  foreach ($this->cache_demand_reason as $key => $val) {
5585  if ($val['id'] == $selected) {
5586  print $val['label'];
5587  break;
5588  }
5589  }
5590  } else {
5591  print "&nbsp;";
5592  }
5593  }
5594  }
5595 
5596  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5610  public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
5611  {
5612  // phpcs:enable
5613  global $langs;
5614 
5615  $ret = '';
5616 
5617  if ($htmlname != "none") {
5618  $ret .= '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5619  $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
5620  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
5621  if ($type) {
5622  $ret .= '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5623  }
5624  $ret .= '<table class="nobordernopadding">';
5625  $ret .= '<tr><td>';
5626  $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
5627  $ret .= '</td>';
5628  $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5629  $ret .= '</tr></table></form>';
5630  } else {
5631  if ($displayhour) {
5632  $ret .= dol_print_date($selected, 'dayhour');
5633  } else {
5634  $ret .= dol_print_date($selected, 'day');
5635  }
5636  }
5637 
5638  if (empty($nooutput)) {
5639  print $ret;
5640  }
5641  return $ret;
5642  }
5643 
5644 
5645  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5656  public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
5657  {
5658  // phpcs:enable
5659  global $langs;
5660 
5661  if ($htmlname != "none") {
5662  print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5663  print '<input type="hidden" name="action" value="set'.$htmlname.'">';
5664  print '<input type="hidden" name="token" value="'.newToken().'">';
5665  print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5666  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5667  print '</form>';
5668  } else {
5669  if ($selected) {
5670  require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
5671  $theuser = new User($this->db);
5672  $theuser->fetch($selected);
5673  print $theuser->getNomUrl(1);
5674  } else {
5675  print "&nbsp;";
5676  }
5677  }
5678  }
5679 
5680 
5681  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5695  public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
5696  {
5697  // phpcs:enable
5698  global $langs;
5699 
5700  $out = '';
5701  if ($htmlname != "none") {
5702  $out .= '<form method="POST" action="'.$page.'">';
5703  $out .= '<input type="hidden" name="action" value="setmode">';
5704  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5705  if ($type) {
5706  $out .= '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5707  }
5708  $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
5709  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5710  $out .= '</form>';
5711  } else {
5712  if ($selected) {
5713  $this->load_cache_types_paiements();
5714  $out .= $this->cache_types_paiements[$selected]['label'];
5715  } else {
5716  $out .= "&nbsp;";
5717  }
5718  }
5719 
5720  if ($nooutput) {
5721  return $out;
5722  } else {
5723  print $out;
5724  }
5725  }
5726 
5737  public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5738  {
5739  global $langs;
5740  if ($htmlname != "none") {
5741  print '<form method="POST" action="'.$page.'">';
5742  print '<input type="hidden" name="action" value="settransportmode">';
5743  print '<input type="hidden" name="token" value="'.newToken().'">';
5744  $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5745  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5746  print '</form>';
5747  } else {
5748  if ($selected) {
5749  $this->load_cache_transport_mode();
5750  print $this->cache_transport_mode[$selected]['label'];
5751  } else {
5752  print "&nbsp;";
5753  }
5754  }
5755  }
5756 
5757  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5766  public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5767  {
5768  // phpcs:enable
5769  global $langs;
5770  if ($htmlname != "none") {
5771  print '<form method="POST" action="'.$page.'">';
5772  print '<input type="hidden" name="action" value="setmulticurrencycode">';
5773  print '<input type="hidden" name="token" value="'.newToken().'">';
5774  print $this->selectMultiCurrency($selected, $htmlname, 0);
5775  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5776  print '</form>';
5777  } else {
5778  dol_include_once('/core/lib/company.lib.php');
5779  print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5780  }
5781  }
5782 
5783  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5793  public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5794  {
5795  // phpcs:enable
5796  global $langs, $mysoc, $conf;
5797 
5798  if ($htmlname != "none") {
5799  print '<form method="POST" action="'.$page.'">';
5800  print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5801  print '<input type="hidden" name="token" value="'.newToken().'">';
5802  print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> ';
5803  print '<select name="calculation_mode">';
5804  print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>';
5805  print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>';
5806  print '</select> ';
5807  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5808  print '</form>';
5809  } else {
5810  if (!empty($rate)) {
5811  print price($rate, 1, $langs, 1, 0);
5812  if ($currency && $rate != 1) {
5813  print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
5814  }
5815  } else {
5816  print 1;
5817  }
5818  }
5819  }
5820 
5821 
5822  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5838  public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5839  {
5840  // phpcs:enable
5841  global $conf, $langs;
5842  if ($htmlname != "none") {
5843  print '<form method="post" action="'.$page.'">';
5844  print '<input type="hidden" name="action" value="setabsolutediscount">';
5845  print '<input type="hidden" name="token" value="'.newToken().'">';
5846  print '<div class="inline-block">';
5847  if (!empty($discount_type)) {
5848  if (!empty($conf->global->FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS)) {
5849  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5850  $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5851  } else {
5852  $translationKey = 'HasCreditNoteFromSupplier';
5853  }
5854  } else {
5855  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5856  $translationKey = 'HasAbsoluteDiscountFromSupplier';
5857  } else {
5858  $translationKey = 'HasCreditNoteFromSupplier';
5859  }
5860  }
5861  } else {
5862  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5863  if (!$filter || $filter == "fk_facture_source IS NULL") {
5864  $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
5865  } else {
5866  $translationKey = 'CompanyHasCreditNote';
5867  }
5868  } else {
5869  if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5870  $translationKey = 'CompanyHasAbsoluteDiscount';
5871  } else {
5872  $translationKey = 'CompanyHasCreditNote';
5873  }
5874  }
5875  }
5876  print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
5877  if (empty($hidelist)) {
5878  print ' ';
5879  }
5880  print '</div>';
5881  if (empty($hidelist)) {
5882  print '<div class="inline-block" style="padding-right: 10px">';
5883  $newfilter = 'discount_type='.intval($discount_type);
5884  if (!empty($discount_type)) {
5885  $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
5886  } else {
5887  $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
5888  }
5889  if ($filter) {
5890  $newfilter .= ' AND ('.$filter.')';
5891  }
5892  // output the combo of discounts
5893  $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
5894  if ($nbqualifiedlines > 0) {
5895  print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
5896  if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5897  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5898  }
5899  if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5900  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5901  }
5902 
5903  print '>';
5904  }
5905  print '</div>';
5906  }
5907  if ($more) {
5908  print '<div class="inline-block">';
5909  print $more;
5910  print '</div>';
5911  }
5912  print '</form>';
5913  } else {
5914  if ($selected) {
5915  print $selected;
5916  } else {
5917  print "0";
5918  }
5919  }
5920  }
5921 
5922 
5923  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5933  public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
5934  {
5935  // phpcs:enable
5936  global $langs, $conf;
5937 
5938  if ($htmlname != "none") {
5939  print '<form method="post" action="'.$page.'">';
5940  print '<input type="hidden" name="action" value="set_contact">';
5941  print '<input type="hidden" name="token" value="'.newToken().'">';
5942  print '<table class="nobordernopadding">';
5943  print '<tr><td>';
5944  print $this->selectcontacts($societe->id, $selected, $htmlname);
5945  $num = $this->num;
5946  if ($num == 0) {
5947  $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
5948  print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
5949  }
5950  print '</td>';
5951  print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5952  print '</tr></table></form>';
5953  } else {
5954  if ($selected) {
5955  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
5956  $contact = new Contact($this->db);
5957  $contact->fetch($selected);
5958  print $contact->getFullName($langs);
5959  } else {
5960  print "&nbsp;";
5961  }
5962  }
5963  }
5964 
5965  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5982  public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
5983  {
5984  // phpcs:enable
5985  global $langs;
5986 
5987  $out = '';
5988  if ($htmlname != "none") {
5989  $out .= '<form method="post" action="'.$page.'">';
5990  $out .= '<input type="hidden" name="action" value="set_thirdparty">';
5991  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5992  $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
5993  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5994  $out .= '</form>';
5995  } else {
5996  if ($selected) {
5997  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
5998  $soc = new Societe($this->db);
5999  $soc->fetch($selected);
6000  $out .= $soc->getNomUrl(0, '');
6001  } else {
6002  $out .= '<span class="opacitymedium">'.$textifnothirdparty.'</span>';
6003  }
6004  }
6005 
6006  if ($nooutput) {
6007  return $out;
6008  } else {
6009  print $out;
6010  }
6011  }
6012 
6013  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6022  public function select_currency($selected = '', $htmlname = 'currency_id')
6023  {
6024  // phpcs:enable
6025  print $this->selectCurrency($selected, $htmlname);
6026  }
6027 
6037  public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6038  {
6039  global $conf, $langs, $user;
6040 
6041  $langs->loadCacheCurrencies('');
6042 
6043  $out = '';
6044 
6045  if ($selected == 'euro' || $selected == 'euros') {
6046  $selected = 'EUR'; // Pour compatibilite
6047  }
6048 
6049  $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
6050  if ($useempty) {
6051  $out .= '<option value="-1" selected></option>';
6052  }
6053  foreach ($langs->cache_currencies as $code_iso => $currency) {
6054  $labeltoshow = $currency['label'];
6055  if ($mode == 1) {
6056  $labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>';
6057  } else {
6058  $labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>';
6059  }
6060 
6061  if ($selected && $selected == $code_iso) {
6062  $out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
6063  } else {
6064  $out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
6065  }
6066  $out .= $labeltoshow;
6067  $out .= '</option>';
6068  }
6069  $out .= '</select>';
6070  if ($user->admin) {
6071  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6072  }
6073 
6074  // Make select dynamic
6075  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6076  $out .= ajax_combobox($htmlname);
6077 
6078  return $out;
6079  }
6080 
6093  public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6094  {
6095  global $conf, $langs;
6096 
6097  $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6098 
6099  $TCurrency = array();
6100 
6101  $sql = "SELECT code FROM ".$this->db->prefix()."multicurrency";
6102  $sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
6103  if ($filter) {
6104  $sql .= " AND ".$filter;
6105  }
6106  $resql = $this->db->query($sql);
6107  if ($resql) {
6108  while ($obj = $this->db->fetch_object($resql)) {
6109  $TCurrency[$obj->code] = $obj->code;
6110  }
6111  }
6112 
6113  $out = '';
6114  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
6115  if ($useempty) {
6116  $out .= '<option value="">&nbsp;</option>';
6117  }
6118  // If company current currency not in table, we add it into list. Should always be available.
6119  if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6120  $TCurrency[$conf->currency] = $conf->currency;
6121  }
6122  if (count($TCurrency) > 0) {
6123  foreach ($langs->cache_currencies as $code_iso => $currency) {
6124  if (isset($TCurrency[$code_iso])) {
6125  if (!empty($selected) && $selected == $code_iso) {
6126  $out .= '<option value="'.$code_iso.'" selected="selected">';
6127  } else {
6128  $out .= '<option value="'.$code_iso.'">';
6129  }
6130 
6131  $out .= $currency['label'];
6132  $out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
6133  $out .= '</option>';
6134  }
6135  }
6136  }
6137 
6138  $out .= '</select>';
6139 
6140  // Make select dynamic
6141  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6142  $out .= ajax_combobox($htmlname);
6143 
6144  return $out;
6145  }
6146 
6147  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6154  public function load_cache_vatrates($country_code)
6155  {
6156  // phpcs:enable
6157  global $langs;
6158 
6159  $num = count($this->cache_vatrates);
6160  if ($num > 0) {
6161  return $num; // Cache already loaded
6162  }
6163 
6164  dol_syslog(__METHOD__, LOG_DEBUG);
6165 
6166  $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6167  $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6168  $sql .= " WHERE t.fk_pays = c.rowid";
6169  $sql .= " AND t.active > 0";
6170  $sql .= " AND c.code IN (".$this->db->sanitize($country_code, 1).")";
6171  $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6172 
6173  $resql = $this->db->query($sql);
6174  if ($resql) {
6175  $num = $this->db->num_rows($resql);
6176  if ($num) {
6177  for ($i = 0; $i < $num; $i++) {
6178  $obj = $this->db->fetch_object($resql);
6179  $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
6180  $this->cache_vatrates[$i]['code'] = $obj->code;
6181  $this->cache_vatrates[$i]['txtva'] = $obj->taux;
6182  $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
6183  $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
6184  $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
6185  $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
6186  $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
6187 
6188  $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
6189  $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
6190  $positiverates = '';
6191  if ($obj->taux) {
6192  $positiverates .= ($positiverates ? '/' : '').$obj->taux;
6193  }
6194  if ($obj->localtax1) {
6195  $positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
6196  }
6197  if ($obj->localtax2) {
6198  $positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
6199  }
6200  if (empty($positiverates)) {
6201  $positiverates = '0';
6202  }
6203  $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
6204  }
6205 
6206  return $num;
6207  } else {
6208  $this->error = '<span class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</span>';
6209  return -1;
6210  }
6211  } else {
6212  $this->error = '<span class="error">'.$this->db->error().'</span>';
6213  return -2;
6214  }
6215  }
6216 
6217  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6239  public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
6240  {
6241  // phpcs:enable
6242  global $langs, $conf, $mysoc;
6243 
6244  $langs->load('errors');
6245 
6246  $return = '';
6247 
6248  // Define defaultnpr, defaultttx and defaultcode
6249  $defaultnpr = ($info_bits & 0x01);
6250  $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6251  $defaulttx = str_replace('*', '', $selectedrate);
6252  $defaultcode = '';
6253  $reg = array();
6254  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6255  $defaultcode = $reg[1];
6256  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6257  }
6258  //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6259 
6260  // Check parameters
6261  if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6262  if ($societe_vendeuse->id == $mysoc->id) {
6263  $return .= '<span class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</span>';
6264  } else {
6265  $return .= '<span class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</span>';
6266  }
6267  return $return;
6268  }
6269 
6270  //var_dump($societe_acheteuse);
6271  //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";
6272  //exit;
6273 
6274  // Define list of countries to use to search VAT rates to show
6275  // First we defined code_country to use to find list
6276  if (is_object($societe_vendeuse)) {
6277  $code_country = "'".$societe_vendeuse->country_code."'";
6278  } else {
6279  $code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
6280  }
6281  if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) { // If option to have vat for end customer for services is on
6282  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6283  if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
6284  // We also add the buyer country code
6285  if (is_numeric($type)) {
6286  if ($type == 1) { // We know product is a service
6287  $code_country .= ",'".$societe_acheteuse->country_code."'";
6288  }
6289  } elseif (!$idprod) { // We don't know type of product
6290  $code_country .= ",'".$societe_acheteuse->country_code."'";
6291  } else {
6292  $prodstatic = new Product($this->db);
6293  $prodstatic->fetch($idprod);
6294  if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6295  $code_country .= ",'".$societe_acheteuse->country_code."'";
6296  }
6297  }
6298  }
6299  }
6300 
6301  // Now we get list
6302  $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6303 
6304  if ($num > 0) {
6305  // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6306  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6307  $tmpthirdparty = new Societe($this->db);
6308 
6309  $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6310  $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6311 
6312  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6313  $defaultcode = $reg[1];
6314  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6315  }
6316  if (empty($defaulttx)) {
6317  $defaultnpr = 0;
6318  }
6319  }
6320 
6321  // If we fails to find a default vat rate, we take the last one in list
6322  // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6323  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6324  if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6325  // We take the last one found in list
6326  $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
6327  } else {
6328  // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6329  $defaulttx = '';
6330  if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6331  $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6332  }
6333  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6334  $defaultcode = $reg[1];
6335  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6336  }
6337  }
6338  }
6339 
6340  // Disabled if seller is not subject to VAT
6341  $disabled = false;
6342  $title = '';
6343  if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6344  // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6345  // of using supplier invoices (this is a very bad idea !)
6346  if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
6347  $title = ' title="'.dol_escape_htmltag($langs->trans('VATIsNotUsed')).'"';
6348  $disabled = true;
6349  }
6350  }
6351 
6352  if (!$options_only) {
6353  $return .= '<select class="flat minwidth50imp maxwidth100" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
6354  }
6355 
6356  $selectedfound = false;
6357  foreach ($this->cache_vatrates as $rate) {
6358  // Keep only 0 if seller is not subject to VAT
6359  if ($disabled && $rate['txtva'] != 0) {
6360  continue;
6361  }
6362 
6363  // Define key to use into select list
6364  $key = $rate['txtva'];
6365  $key .= $rate['nprtva'] ? '*' : '';
6366  if ($mode > 0 && $rate['code']) {
6367  $key .= ' ('.$rate['code'].')';
6368  }
6369  if ($mode < 0) {
6370  $key = $rate['rowid'];
6371  }
6372 
6373  $return .= '<option value="'.$key.'"';
6374  if (!$selectedfound) {
6375  if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6376  if ($defaultcode == $rate['code']) {
6377  $return .= ' selected';
6378  $selectedfound = true;
6379  }
6380  } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6381  $return .= ' selected';
6382  $selectedfound = true;
6383  }
6384  }
6385  $return .= '>';
6386 
6387  // Show label of VAT
6388  if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
6389  // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6390  $return .= $rate['labelpositiverates'];
6391  } else {
6392  // Simple label
6393  $return .= vatrate($rate['label']);
6394  }
6395 
6396  //$return.=($rate['code']?' '.$rate['code']:'');
6397  $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6398 
6399  $return .= '</option>';
6400  }
6401 
6402  if (!$options_only) {
6403  $return .= '</select>';
6404  //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
6405  }
6406  } else {
6407  $return .= $this->error;
6408  }
6409 
6410  $this->num = $num;
6411  return $return;
6412  }
6413 
6414 
6415  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6440  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 = '')
6441  {
6442  // phpcs:enable
6443  $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6444  if (!empty($nooutput)) {
6445  return $retstring;
6446  }
6447  print $retstring;
6448  return;
6449  }
6450 
6466  public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6467  {
6468  global $langs;
6469 
6470  $ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6471  if ($forcenewline) {
6472  $ret .= '<br>';
6473  }
6474  $ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6475  return $ret;
6476  }
6477 
6505  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')
6506  {
6507  global $conf, $langs;
6508 
6509  if ($gm === 'auto') {
6510  $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6511  }
6512 
6513  $retstring = '';
6514 
6515  if ($prefix == '') {
6516  $prefix = 're';
6517  }
6518  if ($h == '') {
6519  $h = 0;
6520  }
6521  if ($m == '') {
6522  $m = 0;
6523  }
6524  $emptydate = 0;
6525  $emptyhours = 0;
6526  if ($stepminutes <= 0 || $stepminutes > 30) {
6527  $stepminutes = 1;
6528  }
6529  if ($empty == 1) {
6530  $emptydate = 1;
6531  $emptyhours = 1;
6532  }
6533  if ($empty == 2) {
6534  $emptydate = 0;
6535  $emptyhours = 1;
6536  }
6537  $orig_set_time = $set_time;
6538 
6539  if ($set_time === '' && $emptydate == 0) {
6540  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6541  if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6542  $set_time = dol_now($gm);
6543  } else {
6544  $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6545  }
6546  }
6547 
6548  // Analysis of the pre-selection date
6549  $reg = array();
6550  $shour = '';
6551  $smin = '';
6552  $ssec = '';
6553  if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
6554  // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6555  $syear = (!empty($reg[1]) ? $reg[1] : '');
6556  $smonth = (!empty($reg[2]) ? $reg[2] : '');
6557  $sday = (!empty($reg[3]) ? $reg[3] : '');
6558  $shour = (!empty($reg[4]) ? $reg[4] : '');
6559  $smin = (!empty($reg[5]) ? $reg[5] : '');
6560  } elseif (strval($set_time) != '' && $set_time != -1) {
6561  // set_time est un timestamps (0 possible)
6562  $syear = dol_print_date($set_time, "%Y", $gm);
6563  $smonth = dol_print_date($set_time, "%m", $gm);
6564  $sday = dol_print_date($set_time, "%d", $gm);
6565  if ($orig_set_time != '') {
6566  $shour = dol_print_date($set_time, "%H", $gm);
6567  $smin = dol_print_date($set_time, "%M", $gm);
6568  $ssec = dol_print_date($set_time, "%S", $gm);
6569  }
6570  } else {
6571  // Date est '' ou vaut -1
6572  $syear = '';
6573  $smonth = '';
6574  $sday = '';
6575  $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6576  $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6577  $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6578  }
6579  if ($h == 3) {
6580  $shour = '';
6581  }
6582  if ($m == 3) {
6583  $smin = '';
6584  }
6585 
6586  $nowgmt = dol_now('gmt');
6587  //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6588 
6589  // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6590  $usecalendar = 'combo';
6591  if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6592  $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6593  }
6594 
6595  if ($d) {
6596  // Show date with popup
6597  if ($usecalendar != 'combo') {
6598  $formated_date = '';
6599  //print "e".$set_time." t ".$conf->format_date_short;
6600  if (strval($set_time) != '' && $set_time != -1) {
6601  //$formated_date=dol_print_date($set_time,$conf->format_date_short);
6602  $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6603  }
6604 
6605  // Calendrier popup version eldy
6606  if ($usecalendar == "eldy") {
6607  // Input area to enter date manually
6608  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6609  $retstring .= ($disabled ? ' disabled' : '');
6610  $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6611  $retstring .= '>';
6612 
6613  // Icon calendar
6614  $retstringbuttom = '';
6615  if (!$disabled) {
6616  $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
6617  $base = DOL_URL_ROOT.'/core/';
6618  $retstringbuttom .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
6619  $retstringbuttom .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
6620  } else {
6621  $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6622  }
6623  $retstring = $retstringbuttom.$retstring;
6624 
6625  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
6626  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6627  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
6628  } elseif ($usecalendar == 'jquery') {
6629  if (!$disabled) {
6630  // Output javascript for datepicker
6631  $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (date('Y') - 100));
6632  $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (date('Y') + 100));
6633 
6634  $retstring .= "<script type='text/javascript'>";
6635  $retstring .= "$(function(){ $('#".$prefix."').datepicker({
6636  dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
6637  autoclose: true,
6638  todayHighlight: true,
6639  yearRange: '".$minYear.":".$maxYear."',";
6640  if (!empty($conf->dol_use_jmobile)) {
6641  $retstring .= "
6642  beforeShow: function (input, datePicker) {
6643  input.disabled = true;
6644  },
6645  onClose: function (dateText, datePicker) {
6646  this.disabled = false;
6647  },
6648  ";
6649  }
6650  // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6651  if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6652  $retstring .= "
6653  showOn: 'button', /* both has problem with autocompletion */
6654  buttonImage: '".DOL_URL_ROOT."/theme/".dol_escape_js($conf->theme)."/img/object_calendarday.png',
6655  buttonImageOnly: true";
6656  }
6657  $retstring .= "
6658  }) });";
6659  $retstring .= "</script>";
6660  }
6661 
6662  // Zone de saisie manuelle de la date
6663  $retstring .= '<div class="nowraponall inline-block divfordateinput">';
6664  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6665  $retstring .= ($disabled ? ' disabled' : '');
6666  $retstring .= ($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '');
6667  $retstring .= ' onChange="dpChangeDay(\''.dol_escape_js($prefix).'\',\''.dol_escape_js($langs->trans("FormatDateShortJavaInput")).'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6668  $retstring .= '>';
6669 
6670  // Icone calendrier
6671  if (!$disabled) {
6672  /* Not required. Managed by option buttonImage of jquery
6673  $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6674  $retstring.="<script type='text/javascript'>";
6675  $retstring.="jQuery(document).ready(function() {";
6676  $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
6677  $retstring.=" jQuery('#".$prefix."').focus();";
6678  $retstring.=' });';
6679  $retstring.='});';
6680  $retstring.="</script>";*/
6681  } else {
6682  $retstringbutton = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6683  $retsring = $retstringbutton.$retstring;
6684  }
6685 
6686  $retstring .= '</div>';
6687  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
6688  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6689  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
6690  } else {
6691  $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6692  }
6693  } else {
6694  // Show date with combo selects
6695  // Day
6696  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
6697 
6698  if ($emptydate || $set_time == -1) {
6699  $retstring .= '<option value="0" selected>&nbsp;</option>';
6700  }
6701 
6702  for ($day = 1; $day <= 31; $day++) {
6703  $retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
6704  }
6705 
6706  $retstring .= "</select>";
6707 
6708  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
6709  if ($emptydate || $set_time == -1) {
6710  $retstring .= '<option value="0" selected>&nbsp;</option>';
6711  }
6712 
6713  // Month
6714  for ($month = 1; $month <= 12; $month++) {
6715  $retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
6716  $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6717  $retstring .= "</option>";
6718  }
6719  $retstring .= "</select>";
6720 
6721  // Year
6722  if ($emptydate || $set_time == -1) {
6723  $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.'">';
6724  } else {
6725  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
6726 
6727  for ($year = $syear - 10; $year < $syear + 10; $year++) {
6728  $retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
6729  }
6730  $retstring .= "</select>\n";
6731  }
6732  }
6733  }
6734 
6735  if ($d && $h) {
6736  $retstring .= ($h == 2 ? '<br>' : ' ');
6737  $retstring .= '<span class="nowraponall">';
6738  }
6739 
6740  if ($h) {
6741  $hourstart = 0;
6742  $hourend = 24;
6743  if ($openinghours != '') {
6744  $openinghours = explode(',', $openinghours);
6745  $hourstart = $openinghours[0];
6746  $hourend = $openinghours[1];
6747  if ($hourend < $hourstart) {
6748  $hourend = $hourstart;
6749  }
6750  }
6751  // Show hour
6752  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
6753  if ($emptyhours) {
6754  $retstring .= '<option value="-1">&nbsp;</option>';
6755  }
6756  for ($hour = $hourstart; $hour < $hourend; $hour++) {
6757  if (strlen($hour) < 2) {
6758  $hour = "0".$hour;
6759  }
6760  $retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour;
6761  //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6762  $retstring .= '</option>';
6763  }
6764  $retstring .= '</select>';
6765  //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6766  if ($m) {
6767  $retstring .= ":";
6768  }
6769  }
6770 
6771  if ($m) {
6772  // Show minutes
6773  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
6774  if ($emptyhours) {
6775  $retstring .= '<option value="-1">&nbsp;</option>';
6776  }
6777  for ($min = 0; $min < 60; $min += $stepminutes) {
6778  if (strlen($min) < 2) {
6779  $min = "0".$min;
6780  }
6781  $retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
6782  }
6783  $retstring .= '</select>';
6784 
6785  $retstring .= '<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
6786  }
6787 
6788  if ($d && $h) {
6789  $retstring .= '</span>';
6790  }
6791 
6792  // Add a "Now" link
6793  if (!empty($conf->use_javascript_ajax) && $addnowlink) {
6794  // Script which will be inserted in the onClick of the "Now" link
6795  $reset_scripts = "";
6796  if ($addnowlink == 2) { // local computer time
6797  // pad add leading 0 on numbers
6798  $reset_scripts .= "Number.prototype.pad = function(size) {
6799  var s = String(this);
6800  while (s.length < (size || 2)) {s = '0' + s;}
6801  return s;
6802  };
6803  var d = new Date();";
6804  }
6805 
6806  // Generate the date part, depending on the use or not of the javascript calendar
6807  if ($addnowlink == 1) { // server time expressed in user time setup
6808  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6809  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6810  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6811  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6812  } elseif ($addnowlink == 2) {
6813  /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6814  * This break application for foreign languages.
6815  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6816  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6817  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6818  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6819  */
6820  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6821  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6822  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6823  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6824  }
6825  /*if ($usecalendar == "eldy")
6826  {
6827  $base=DOL_URL_ROOT.'/core/';
6828  $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6829  }
6830  else
6831  {
6832  $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6833  $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6834  $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6835  }*/
6836  // Update the hour part
6837  if ($h) {
6838  if ($fullday) {
6839  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6840  }
6841  //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
6842  if ($addnowlink == 1) {
6843  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6844  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6845  } elseif ($addnowlink == 2) {
6846  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
6847  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6848  }
6849 
6850  if ($fullday) {
6851  $reset_scripts .= ' } ';
6852  }
6853  }
6854  // Update the minute part
6855  if ($m) {
6856  if ($fullday) {
6857  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6858  }
6859  //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
6860  if ($addnowlink == 1) {
6861  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6862  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6863  } elseif ($addnowlink == 2) {
6864  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
6865  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6866  }
6867  if ($fullday) {
6868  $reset_scripts .= ' } ';
6869  }
6870  }
6871  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6872  if ($reset_scripts && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
6873  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
6874  $retstring .= $langs->trans("Now");
6875  $retstring .= '</button> ';
6876  }
6877  }
6878 
6879  // Add a "Plus one hour" link
6880  if ($conf->use_javascript_ajax && $addplusone) {
6881  // Script which will be inserted in the onClick of the "Add plusone" link
6882  $reset_scripts = "";
6883 
6884  // Generate the date part, depending on the use or not of the javascript calendar
6885  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');';
6886  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6887  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6888  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6889  // Update the hour part
6890  if ($h) {
6891  if ($fullday) {
6892  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6893  }
6894  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6895  if ($fullday) {
6896  $reset_scripts .= ' } ';
6897  }
6898  }
6899  // Update the minute part
6900  if ($m) {
6901  if ($fullday) {
6902  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6903  }
6904  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6905  if ($fullday) {
6906  $reset_scripts .= ' } ';
6907  }
6908  }
6909  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6910  if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6911  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
6912  $retstring .= $langs->trans("DateStartPlusOne");
6913  $retstring .= '</button> ';
6914  }
6915  }
6916 
6917  // Add a link to set data
6918  if ($conf->use_javascript_ajax && $adddateof) {
6919  $tmparray = dol_getdate($adddateof);
6920  if (empty($labeladddateof)) {
6921  $labeladddateof = $langs->trans("DateInvoice");
6922  }
6923  $reset_scripts = 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($adddateof, 'dayinputnoreduce').'\');';
6924  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
6925  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
6926  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
6927  $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$labeladddateof.'</a>';
6928  }
6929 
6930  return $retstring;
6931  }
6932 
6941  public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
6942  {
6943  global $langs;
6944 
6945  $TDurationTypes = array(
6946  'y'=>$langs->trans('Years'),
6947  'm'=>$langs->trans('Month'),
6948  'w'=>$langs->trans('Weeks'),
6949  'd'=>$langs->trans('Days'),
6950  'h'=>$langs->trans('Hours'),
6951  'i'=>$langs->trans('Minutes')
6952  );
6953 
6954  // Removed undesired duration types
6955  foreach ($excludetypes as $value) {
6956  unset($TDurationTypes[$value]);
6957  }
6958 
6959  $retstring = '<select class="flat minwidth75 maxwidth100" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
6960  foreach ($TDurationTypes as $key => $typeduration) {
6961  $retstring .= '<option value="'.$key.'"';
6962  if ($key == $selected) {
6963  $retstring .= " selected";
6964  }
6965  $retstring .= ">".$typeduration."</option>";
6966  }
6967  $retstring .= "</select>";
6968 
6969  $retstring .= ajax_combobox('select_'.$prefix.'type_duration');
6970 
6971  return $retstring;
6972  }
6973 
6974  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6988  public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
6989  {
6990  // phpcs:enable
6991  global $langs;
6992 
6993  $retstring = '<span class="nowraponall">';
6994 
6995  $hourSelected = 0;
6996  $minSelected = 0;
6997 
6998  // Hours
6999  if ($iSecond != '') {
7000  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
7001 
7002  $hourSelected = convertSecondToTime($iSecond, 'allhour');
7003  $minSelected = convertSecondToTime($iSecond, 'min');
7004  }
7005 
7006  if ($typehour == 'select') {
7007  $retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
7008  for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7009  $retstring .= '<option value="'.$hour.'"';
7010  if ($hourSelected == $hour) {
7011  $retstring .= " selected";
7012  }
7013  $retstring .= ">".$hour."</option>";
7014  }
7015  $retstring .= "</select>";
7016  } elseif ($typehour == 'text' || $typehour == 'textselect') {
7017  $retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
7018  } else {
7019  return 'BadValueForParameterTypeHour';
7020  }
7021 
7022  if ($typehour != 'text') {
7023  $retstring .= ' '.$langs->trans('HourShort');
7024  } else {
7025  $retstring .= '<span class="">:</span>';
7026  }
7027 
7028  // Minutes
7029  if ($minunderhours) {
7030  $retstring .= '<br>';
7031  } else {
7032  $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7033  }
7034 
7035  if ($typehour == 'select' || $typehour == 'textselect') {
7036  $retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
7037  for ($min = 0; $min <= 55; $min = $min + 5) {
7038  $retstring .= '<option value="'.$min.'"';
7039  if ($minSelected == $min) {
7040  $retstring .= ' selected';
7041  }
7042  $retstring .= '>'.$min.'</option>';
7043  }
7044  $retstring .= "</select>";
7045  } elseif ($typehour == 'text') {
7046  $retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
7047  }
7048 
7049  if ($typehour != 'text') {
7050  $retstring .= ' '.$langs->trans('MinuteShort');
7051  }
7052 
7053  $retstring.="</span>";
7054 
7055  if (!empty($nooutput)) {
7056  return $retstring;
7057  }
7058 
7059  print $retstring;
7060  return;
7061  }
7062 
7082  public function selectTickets($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7083  {
7084  global $langs, $conf;
7085 
7086  $out = '';
7087 
7088  // check parameters
7089  if (is_null($ajaxoptions)) $ajaxoptions = array();
7090 
7091  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7092  $placeholder = '';
7093 
7094  if ($selected && empty($selected_input_value)) {
7095  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
7096  $tickettmpselect = new Ticket($this->db);
7097  $tickettmpselect->fetch($selected);
7098  $selected_input_value = $tickettmpselect->ref;
7099  unset($tickettmpselect);
7100  }
7101 
7102  $urloption = '';
7103  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7104 
7105  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7106  elseif ($hidelabel > 1) {
7107  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7108  if ($hidelabel == 2) {
7109  $out .= img_picto($langs->trans("Search"), 'search');
7110  }
7111  }
7112  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7113  if ($hidelabel == 3) {
7114  $out .= img_picto($langs->trans("Search"), 'search');
7115  }
7116  } else {
7117  $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7118  }
7119 
7120  if (empty($nooutput)) print $out;
7121  else return $out;
7122  }
7123 
7124 
7141  public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7142  {
7143  global $langs, $conf;
7144 
7145  $out = '';
7146  $outarray = array();
7147 
7148  $selectFields = " p.rowid, p.ref, p.message";
7149 
7150  $sql = "SELECT ";
7151  $sql .= $selectFields;
7152  $sql .= " FROM ".$this->db->prefix()."ticket as p";
7153  $sql .= ' WHERE p.entity IN ('.getEntity('ticket').')';
7154 
7155  // Add criteria on ref/label
7156  if ($filterkey != '') {
7157  $sql .= ' AND (';
7158  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7159  // For natural search
7160  $scrit = explode(' ', $filterkey);
7161  $i = 0;
7162  if (count($scrit) > 1) $sql .= "(";
7163  foreach ($scrit as $crit) {
7164  if ($i > 0) $sql .= " AND ";
7165  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.subject LIKE '".$this->db->escape($prefix.$crit)."%'";
7166  $sql .= ")";
7167  $i++;
7168  }
7169  if (count($scrit) > 1) $sql .= ")";
7170  $sql .= ')';
7171  }
7172 
7173  $sql .= $this->db->plimit($limit, 0);
7174 
7175  // Build output string
7176  dol_syslog(get_class($this)."::selectTicketsList search tickets", LOG_DEBUG);
7177  $result = $this->db->query($sql);
7178  if ($result) {
7179  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
7180  require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
7181 
7182  $num = $this->db->num_rows($result);
7183 
7184  $events = null;
7185 
7186  if (!$forcecombo) {
7187  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7188  $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7189  }
7190 
7191  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7192 
7193  $textifempty = '';
7194  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7195  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7196  if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7197  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7198  else $textifempty .= $langs->trans("All");
7199  } else {
7200  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7201  }
7202  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7203 
7204  $i = 0;
7205  while ($num && $i < $num) {
7206  $opt = '';
7207  $optJson = array();
7208  $objp = $this->db->fetch_object($result);
7209 
7210  $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7211  // Add new entry
7212  // "key" value of json key array is used by jQuery automatically as selected value
7213  // "label" value of json key array is used by jQuery automatically as text for combo box
7214  $out .= $opt;
7215  array_push($outarray, $optJson);
7216 
7217  $i++;
7218  }
7219 
7220  $out .= '</select>';
7221 
7222  $this->db->free($result);
7223 
7224  if (empty($outputmode)) return $out;
7225  return $outarray;
7226  } else {
7227  dol_print_error($this->db);
7228  }
7229  }
7230 
7242  protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7243  {
7244  $outkey = '';
7245  $outref = '';
7246  $outtype = '';
7247 
7248  $outkey = $objp->rowid;
7249  $outref = $objp->ref;
7250  $outtype = $objp->fk_product_type;
7251 
7252  $opt = '<option value="'.$objp->rowid.'"';
7253  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7254  $opt .= '>';
7255  $opt .= $objp->ref;
7256  $objRef = $objp->ref;
7257  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7258 
7259  $opt .= "</option>\n";
7260  $optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7261  }
7262 
7282  public function selectProjects($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7283  {
7284  global $langs, $conf;
7285 
7286  $out = '';
7287 
7288  // check parameters
7289  if (is_null($ajaxoptions)) $ajaxoptions = array();
7290 
7291  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7292  $placeholder = '';
7293 
7294  if ($selected && empty($selected_input_value)) {
7295  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7296  $projecttmpselect = new Project($this->db);
7297  $projecttmpselect->fetch($selected);
7298  $selected_input_value = $projecttmpselect->ref;
7299  unset($projecttmpselect);
7300  }
7301 
7302  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7303 
7304  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7305  elseif ($hidelabel > 1) {
7306  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7307  if ($hidelabel == 2) {
7308  $out .= img_picto($langs->trans("Search"), 'search');
7309  }
7310  }
7311  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7312  if ($hidelabel == 3) {
7313  $out .= img_picto($langs->trans("Search"), 'search');
7314  }
7315  } else {
7316  $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7317  }
7318 
7319  if (empty($nooutput)) print $out;
7320  else return $out;
7321  }
7322 
7339  public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7340  {
7341  global $langs, $conf;
7342 
7343  $out = '';
7344  $outarray = array();
7345 
7346  $selectFields = " p.rowid, p.ref";
7347 
7348  $sql = "SELECT ";
7349  $sql .= $selectFields;
7350  $sql .= " FROM ".$this->db->prefix()."projet as p";
7351  $sql .= ' WHERE p.entity IN ('.getEntity('project').')';
7352 
7353  // Add criteria on ref/label
7354  if ($filterkey != '') {
7355  $sql .= ' AND (';
7356  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7357  // For natural search
7358  $scrit = explode(' ', $filterkey);
7359  $i = 0;
7360  if (count($scrit) > 1) $sql .= "(";
7361  foreach ($scrit as $crit) {
7362  if ($i > 0) $sql .= " AND ";
7363  $sql .= "p.ref LIKE '".$this->db->escape($prefix.$crit)."%'";
7364  $sql .= "";
7365  $i++;
7366  }
7367  if (count($scrit) > 1) $sql .= ")";
7368  $sql .= ')';
7369  }
7370 
7371  $sql .= $this->db->plimit($limit, 0);
7372 
7373  // Build output string
7374  dol_syslog(get_class($this)."::selectProjectsList search projects", LOG_DEBUG);
7375  $result = $this->db->query($sql);
7376  if ($result) {
7377  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7378  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
7379 
7380  $num = $this->db->num_rows($result);
7381 
7382  $events = null;
7383 
7384  if (!$forcecombo) {
7385  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7386  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7387  }
7388 
7389  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7390 
7391  $textifempty = '';
7392  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7393  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7394  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7395  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7396  else $textifempty .= $langs->trans("All");
7397  } else {
7398  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7399  }
7400  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7401 
7402  $i = 0;
7403  while ($num && $i < $num) {
7404  $opt = '';
7405  $optJson = array();
7406  $objp = $this->db->fetch_object($result);
7407 
7408  $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7409  // Add new entry
7410  // "key" value of json key array is used by jQuery automatically as selected value
7411  // "label" value of json key array is used by jQuery automatically as text for combo box
7412  $out .= $opt;
7413  array_push($outarray, $optJson);
7414 
7415  $i++;
7416  }
7417 
7418  $out .= '</select>';
7419 
7420  $this->db->free($result);
7421 
7422  if (empty($outputmode)) return $out;
7423  return $outarray;
7424  } else {
7425  dol_print_error($this->db);
7426  }
7427  }
7428 
7440  protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7441  {
7442  $outkey = '';
7443  $outval = '';
7444  $outref = '';
7445  $outlabel = '';
7446  $outtype = '';
7447 
7448  $label = $objp->label;
7449 
7450  $outkey = $objp->rowid;
7451  $outref = $objp->ref;
7452  $outlabel = $objp->label;
7453  $outtype = $objp->fk_product_type;
7454 
7455  $opt = '<option value="'.$objp->rowid.'"';
7456  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7457  $opt .= '>';
7458  $opt .= $objp->ref;
7459  $objRef = $objp->ref;
7460  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7461  $outval .= $objRef;
7462 
7463  $opt .= "</option>\n";
7464  $optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7465  }
7466 
7467 
7487  public function selectMembers($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7488  {
7489  global $langs, $conf;
7490 
7491  $out = '';
7492 
7493  // check parameters
7494  if (is_null($ajaxoptions)) $ajaxoptions = array();
7495 
7496  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7497  $placeholder = '';
7498  $urloption = '';
7499 
7500  if ($selected && empty($selected_input_value)) {
7501  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7502  $adherenttmpselect = new Adherent($this->db);
7503  $adherenttmpselect->fetch($selected);
7504  $selected_input_value = $adherenttmpselect->ref;
7505  unset($adherenttmpselect);
7506  }
7507 
7508  $urloption = '';
7509 
7510  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7511 
7512  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7513  elseif ($hidelabel > 1) {
7514  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7515  if ($hidelabel == 2) {
7516  $out .= img_picto($langs->trans("Search"), 'search');
7517  }
7518  }
7519  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7520  if ($hidelabel == 3) {
7521  $out .= img_picto($langs->trans("Search"), 'search');
7522  }
7523  } else {
7524  $filterkey = '';
7525 
7526  $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
7527  }
7528 
7529  if (empty($nooutput)) print $out;
7530  else return $out;
7531  }
7532 
7549  public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7550  {
7551  global $langs, $conf;
7552 
7553  $out = '';
7554  $outarray = array();
7555 
7556  $selectFields = " p.rowid, p.ref, p.firstname, p.lastname";
7557 
7558  $sql = "SELECT ";
7559  $sql .= $selectFields;
7560  $sql .= " FROM ".$this->db->prefix()."adherent as p";
7561  $sql .= ' WHERE p.entity IN ('.getEntity('adherent').')';
7562 
7563  // Add criteria on ref/label
7564  if ($filterkey != '') {
7565  $sql .= ' AND (';
7566  $prefix = empty($conf->global->MEMBER_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7567  // For natural search
7568  $scrit = explode(' ', $filterkey);
7569  $i = 0;
7570  if (count($scrit) > 1) $sql .= "(";
7571  foreach ($scrit as $crit) {
7572  if ($i > 0) $sql .= " AND ";
7573  $sql .= "(p.firstname LIKE '".$this->db->escape($prefix.$crit)."%'";
7574  $sql .= " OR p.lastname LIKE '".$this->db->escape($prefix.$crit)."%')";
7575  $i++;
7576  }
7577  if (count($scrit) > 1) $sql .= ")";
7578  $sql .= ')';
7579  }
7580  if ($status != -1) {
7581  $sql .= ' AND statut = '.((int) $status);
7582  }
7583  $sql .= $this->db->plimit($limit, 0);
7584 
7585  // Build output string
7586  dol_syslog(get_class($this)."::selectMembersList search adherents", LOG_DEBUG);
7587  $result = $this->db->query($sql);
7588  if ($result) {
7589  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7590  require_once DOL_DOCUMENT_ROOT.'/core/lib/member.lib.php';
7591 
7592  $num = $this->db->num_rows($result);
7593 
7594  $events = null;
7595 
7596  if (!$forcecombo) {
7597  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7598  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7599  }
7600 
7601  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7602 
7603  $textifempty = '';
7604  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7605  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7606  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7607  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7608  else $textifempty .= $langs->trans("All");
7609  } else {
7610  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7611  }
7612  if ($showempty) {
7613  $out .= '<option value="-1" selected>'.$textifempty.'</option>';
7614  }
7615 
7616  $i = 0;
7617  while ($num && $i < $num) {
7618  $opt = '';
7619  $optJson = array();
7620  $objp = $this->db->fetch_object($result);
7621 
7622  $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
7623 
7624  // Add new entry
7625  // "key" value of json key array is used by jQuery automatically as selected value
7626  // "label" value of json key array is used by jQuery automatically as text for combo box
7627  $out .= $opt;
7628  array_push($outarray, $optJson);
7629 
7630  $i++;
7631  }
7632 
7633  $out .= '</select>';
7634 
7635  $this->db->free($result);
7636 
7637  if (empty($outputmode)) return $out;
7638  return $outarray;
7639  } else {
7640  dol_print_error($this->db);
7641  }
7642  }
7643 
7655  protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7656  {
7657  $outkey = '';
7658  $outlabel = '';
7659  $outtype = '';
7660 
7661  $outkey = $objp->rowid;
7662  $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
7663  $outtype = $objp->fk_adherent_type;
7664 
7665  $opt = '<option value="'.$objp->rowid.'"';
7666  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7667  $opt .= '>';
7668  if (!empty($filterkey) && $filterkey != '') {
7669  $outlabel = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $outlabel, 1);
7670  }
7671  $opt .= $outlabel;
7672  $opt .= "</option>\n";
7673 
7674  $optJson = array('key'=>$outkey, 'value'=>$outlabel, 'type'=>$outtype);
7675  }
7676 
7696  public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
7697  {
7698  global $conf, $user;
7699 
7700  $objecttmp = null;
7701 
7702  // Example of value for $objectdec:
7703  // Bom:bom/class/bom.class.php:0:t.status=1
7704  // Bom:bom/class/bom.class.php:0:t.status=1:ref
7705  // Bom:bom/class/bom.class.php:0:(t.status:=:1):ref
7706  $InfoFieldList = explode(":", $objectdesc, 4);
7707  $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
7708  $reg = array();
7709  if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
7710  $InfoFieldList[4] = $reg[1]; // take the sort field
7711  }
7712  $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
7713 
7714  $classname = $InfoFieldList[0];
7715  $classpath = $InfoFieldList[1];
7716  $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
7717  $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
7718  $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
7719 
7720  if (!empty($classpath)) {
7721  dol_include_once($classpath);
7722 
7723  if ($classname && class_exists($classname)) {
7724  $objecttmp = new $classname($this->db);
7725 
7726  // Make some replacement
7727  $sharedentities = getEntity(strtolower($classname));
7728  $filter = str_replace(
7729  array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
7730  array($conf->entity, $sharedentities, $user->id),
7731  $filter
7732  );
7733  }
7734  }
7735  if (!is_object($objecttmp)) {
7736  dol_syslog('Error bad setup of type for field '.join(',', $InfoFieldList), LOG_WARNING);
7737  return 'Error bad setup of type for field '.join(',', $InfoFieldList);
7738  }
7739 
7740  //var_dump($filter);
7741  $prefixforautocompletemode = $objecttmp->element;
7742  if ($prefixforautocompletemode == 'societe') {
7743  $prefixforautocompletemode = 'company';
7744  }
7745  if ($prefixforautocompletemode == 'product') {
7746  $prefixforautocompletemode = 'produit';
7747  }
7748  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7749 
7750  dol_syslog(get_class($this)."::selectForForms filter=".$filter, LOG_DEBUG);
7751  $out = '';
7752  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo) {
7753  // No immediate load of all database
7754  $placeholder = '';
7755  if ($preselectedvalue && empty($selected_input_value)) {
7756  $objecttmp->fetch($preselectedvalue);
7757  $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
7758  //unset($objecttmp);
7759  }
7760 
7761  $objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
7762  $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
7763 
7764  // No immediate load of all database
7765  $urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&objectdesc='.urlencode($objectdesc).'&filter='.urlencode($filter).($sortfield ? '&sortfield='.urlencode($sortfield) : '');
7766  // Activate the auto complete using ajax call.
7767  $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
7768  $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
7769  $out .= '<input type="text" class="'.$morecss.'"'.($disabled ? ' disabled="disabled"' : '').' name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '') .' />';
7770  } else {
7771  // Immediate load of table record.
7772  $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
7773  }
7774 
7775  return $out;
7776  }
7777 
7778 
7799  public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
7800  {
7801  global $conf, $langs, $user, $hookmanager;
7802 
7803  //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
7804 
7805  $prefixforautocompletemode = $objecttmp->element;
7806  if ($prefixforautocompletemode == 'societe') {
7807  $prefixforautocompletemode = 'company';
7808  }
7809  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7810 
7811  if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
7812  $tmpfieldstoshow = '';
7813  foreach ($objecttmp->fields as $key => $val) {
7814  if (!dol_eval($val['enabled'], 1, 1, '1')) {
7815  continue;
7816  }
7817  if (!empty($val['showoncombobox'])) {
7818  $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
7819  }
7820  }
7821  if ($tmpfieldstoshow) {
7822  $fieldstoshow = $tmpfieldstoshow;
7823  }
7824  } else {
7825  // For backward compatibility
7826  $objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
7827  }
7828 
7829  if (empty($fieldstoshow)) {
7830  if (isset($objecttmp->fields['ref'])) {
7831  $fieldstoshow = 't.ref';
7832  } else {
7833  $langs->load("errors");
7834  $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
7835  return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
7836  }
7837  }
7838 
7839  $out = '';
7840  $outarray = array();
7841  $tmparray = array();
7842 
7843  $num = 0;
7844 
7845  // Search data
7846  $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".$this->db->prefix().$objecttmp->table_element." as t";
7847  if (isset($objecttmp->ismultientitymanaged)) {
7848  if (!is_numeric($objecttmp->ismultientitymanaged)) {
7849  $tmparray = explode('@', $objecttmp->ismultientitymanaged);
7850  $sql .= " INNER JOIN ".$this->db->prefix().$tmparray[1]." as parenttable ON parenttable.rowid = t.".$tmparray[0];
7851  }
7852  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7853  if (empty($user->rights->societe->client->voir) && !$user->socid) {
7854  $sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
7855  }
7856  }
7857  }
7858 
7859  // Add where from hooks
7860  $parameters = array(
7861  'object' => $objecttmp,
7862  'htmlname' => $htmlname,
7863  'filter' => $filter,
7864  'searchkey' => $searchkey
7865  );
7866 
7867  $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
7868  if (!empty($hookmanager->resPrint)) {
7869  $sql .= $hookmanager->resPrint;
7870  } else {
7871  $sql .= " WHERE 1=1";
7872  if (isset($objecttmp->ismultientitymanaged)) {
7873  if ($objecttmp->ismultientitymanaged == 1) {
7874  $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
7875  }
7876  if (!is_numeric($objecttmp->ismultientitymanaged)) {
7877  $sql .= " AND parenttable.entity = t.".$tmparray[0];
7878  }
7879  if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
7880  if ($objecttmp->element == 'societe') {
7881  $sql .= " AND t.rowid = ".((int) $user->socid);
7882  } else {
7883  $sql .= " AND t.fk_soc = ".((int) $user->socid);
7884  }
7885  }
7886  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7887  if (empty($user->rights->societe->client->voir) && !$user->socid) {
7888  $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
7889  }
7890  }
7891  }
7892  if ($searchkey != '') {
7893  $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
7894  }
7895 
7896  if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
7897  $errormessage = '';
7898  $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
7899  if ($errormessage) {
7900  return 'Error forging a SQL request from an universal criteria: '.$errormessage;
7901  }
7902  }
7903  }
7904  $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
7905  //$sql.=$this->db->plimit($limit, 0);
7906  //print $sql;
7907 
7908  // Build output string
7909  $resql = $this->db->query($sql);
7910  if ($resql) {
7911  // Construct $out and $outarray
7912  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
7913 
7914  // 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
7915  $textifempty = '&nbsp;';
7916 
7917  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7918  if (!empty($conf->global->$confkeyforautocompletemode)) {
7919  if ($showempty && !is_numeric($showempty)) {
7920  $textifempty = $langs->trans($showempty);
7921  } else {
7922  $textifempty .= $langs->trans("All");
7923  }
7924  }
7925  if ($showempty) {
7926  $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
7927  }
7928 
7929  $num = $this->db->num_rows($resql);
7930  $i = 0;
7931  if ($num) {
7932  while ($i < $num) {
7933  $obj = $this->db->fetch_object($resql);
7934  $label = '';
7935  $tmparray = explode(',', $fieldstoshow);
7936  $oldvalueforshowoncombobox = 0;
7937  foreach ($tmparray as $key => $val) {
7938  $val = preg_replace('/t\./', '', $val);
7939  $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
7940  $label .= $obj->$val;
7941  $oldvalueforshowoncombobox = !empty($objecttmp->fields[$val]['showoncombobox']) ? $objecttmp->fields[$val]['showoncombobox'] : 0;
7942  }
7943  if (empty($outputmode)) {
7944  if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
7945  $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
7946  } else {
7947  $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
7948  }
7949  } else {
7950  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
7951  }
7952 
7953  $i++;
7954  if (($i % 10) == 0) {
7955  $out .= "\n";
7956  }
7957  }
7958  }
7959 
7960  $out .= '</select>'."\n";
7961 
7962  if (!$forcecombo) {
7963  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7964  $out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
7965  }
7966  } else {
7967  dol_print_error($this->db);
7968  }
7969 
7970  $this->result = array('nbofelement'=>$num);
7971 
7972  if ($outputmode) {
7973  return $outarray;
7974  }
7975  return $out;
7976  }
7977 
7978 
8002  public static function selectarray($htmlname, $array, $id = '', $show_empty = 0, $key_in_label = 0, $value_as_key = 0, $moreparam = '', $translate = 0, $maxlen = 0, $disabled = 0, $sort = '', $morecss = 'minwidth75', $addjscombo = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
8003  {
8004  global $conf, $langs;
8005 
8006  // Do we want a multiselect ?
8007  //$jsbeautify = 0;
8008  //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8009  $jsbeautify = 1;
8010 
8011  if ($value_as_key) {
8012  $array = array_combine($array, $array);
8013  }
8014 
8015  $out = '';
8016 
8017  if ($addjscombo < 0) {
8018  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8019  $addjscombo = 1;
8020  } else {
8021  $addjscombo = 0;
8022  }
8023  }
8024 
8025  $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8026  $out .= '<select id="'.preg_replace('/^\./', '', $idname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
8027  $out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
8028  $out .= '>';
8029 
8030  if ($show_empty) {
8031  $textforempty = ' ';
8032  if (!empty($conf->use_javascript_ajax)) {
8033  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8034  }
8035  if (!is_numeric($show_empty)) {
8036  $textforempty = $show_empty;
8037  }
8038  $out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
8039  }
8040 
8041  if (is_array($array)) {
8042  // Translate
8043  if ($translate) {
8044  foreach ($array as $key => $value) {
8045  if (!is_array($value)) {
8046  $array[$key] = $langs->trans($value);
8047  } else {
8048  $array[$key]['label'] = $langs->trans($value['label']);
8049  }
8050  }
8051  }
8052 
8053  // Sort
8054  if ($sort == 'ASC') {
8055  asort($array);
8056  } elseif ($sort == 'DESC') {
8057  arsort($array);
8058  }
8059 
8060  foreach ($array as $key => $tmpvalue) {
8061  if (is_array($tmpvalue)) {
8062  $value = $tmpvalue['label'];
8063  $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8064  $style = empty($tmpvalue['css']) ? '' : ' class="'.$tmpvalue['css'].'"';
8065  } else {
8066  $value = $tmpvalue;
8067  $disabled = '';
8068  $style = '';
8069  }
8070  if (!empty($disablebademail)) {
8071  if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8072  || ($disablebademail == 2 && preg_match('/---/', $value))) {
8073  $disabled = ' disabled';
8074  $style = ' class="warning"';
8075  }
8076  }
8077 
8078  if ($key_in_label) {
8079  if (empty($nohtmlescape)) {
8080  $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
8081  } else {
8082  $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
8083  }
8084  } else {
8085  if (empty($nohtmlescape)) {
8086  $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
8087  } else {
8088  $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8089  }
8090  if ($value == '' || $value == '-') {
8091  $selectOptionValue = '&nbsp;';
8092  }
8093  }
8094 
8095  $out .= '<option value="'.$key.'"';
8096  $out .= $style.$disabled;
8097  if (is_array($id)) {
8098  if (in_array($key, $id) && !$disabled) {
8099  $out .= ' selected'; // To preselect a value
8100  }
8101  } else {
8102  $id = (string) $id; // if $id = 0, then $id = '0'
8103  if ($id != '' && ($id == $key || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8104  $out .= ' selected'; // To preselect a value
8105  }
8106  }
8107  if ($nohtmlescape) {
8108  $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
8109  }
8110  if (is_array($tmpvalue)) {
8111  foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8112  if (preg_match('/^data-/', $keyforvalue)) {
8113  $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
8114  }
8115  }
8116  }
8117  $out .= '>';
8118  //var_dump($selectOptionValue);
8119  $out .= $selectOptionValue;
8120  $out .= "</option>\n";
8121  }
8122  }
8123 
8124  $out .= "</select>";
8125 
8126  // Add code for jquery to use multiselect
8127  if ($addjscombo && $jsbeautify) {
8128  // Enhance with select2
8129  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
8130  $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', ($show_empty < 0 ? (string) $show_empty : '-1'), $morecss);
8131  }
8132 
8133  return $out;
8134  }
8135 
8136 
8155  public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8156  {
8157  global $conf, $langs;
8158  global $delayedhtmlcontent; // Will be used later outside of this function
8159 
8160  // TODO Use an internal dolibarr component instead of select2
8161  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8162  return '';
8163  }
8164 
8165  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
8166 
8167  $outdelayed = '';
8168  if (!empty($conf->use_javascript_ajax)) {
8169  $tmpplugin = 'select2';
8170  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8171  <script>
8172  $(document).ready(function () {
8173 
8174  '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
8175 
8176  $(".'.$htmlname.'").select2({
8177  ajax: {
8178  dir: "ltr",
8179  url: "'.$url.'",
8180  dataType: \'json\',
8181  delay: 250,
8182  data: function (params) {
8183  return {
8184  q: params.term, // search term
8185  page: params.page
8186  };
8187  },
8188  processResults: function (data) {
8189  // parse the results into the format expected by Select2.
8190  // since we are using custom formatting functions we do not need to alter the remote JSON data
8191  //console.log(data);
8192  saveRemoteData = data;
8193  /* format json result for select2 */
8194  result = []
8195  $.each( data, function( key, value ) {
8196  result.push({id: key, text: value.text});
8197  });
8198  //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8199  //console.log(result);
8200  return {results: result, more: false}
8201  },
8202  cache: true
8203  },
8204  language: select2arrayoflanguage,
8205  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8206  placeholder: "'.dol_escape_js($placeholder).'",
8207  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8208  minimumInputLength: '.$minimumInputLength.',
8209  formatResult: function(result, container, query, escapeMarkup) {
8210  return escapeMarkup(result.text);
8211  },
8212  });
8213 
8214  '.($callurlonselect ? '
8215  /* Code to execute a GET when we select a value */
8216  $(".'.$htmlname.'").change(function() {
8217  var selected = $(".'.$htmlname.'").val();
8218  console.log("We select in selectArrayAjax the entry "+selected)
8219  $(".'.$htmlname.'").val(""); /* reset visible combo value */
8220  $.each( saveRemoteData, function( key, value ) {
8221  if (key == selected)
8222  {
8223  console.log("selectArrayAjax - Do a redirect to "+value.url)
8224  location.assign(value.url);
8225  }
8226  });
8227  });' : '').'
8228 
8229  });
8230  </script>';
8231  }
8232 
8233  if ($acceptdelayedhtml) {
8234  $delayedhtmlcontent .= $outdelayed;
8235  } else {
8236  $out .= $outdelayed;
8237  }
8238  return $out;
8239  }
8240 
8259  public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8260  {
8261  global $conf, $langs;
8262  global $delayedhtmlcontent; // Will be used later outside of this function
8263 
8264  // TODO Use an internal dolibarr component instead of select2
8265  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8266  return '';
8267  }
8268 
8269  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
8270 
8271  $formattedarrayresult = array();
8272 
8273  foreach ($array as $key => $value) {
8274  $o = new stdClass();
8275  $o->id = $key;
8276  $o->text = $value['text'];
8277  $o->url = $value['url'];
8278  $formattedarrayresult[] = $o;
8279  }
8280 
8281  $outdelayed = '';
8282  if (!empty($conf->use_javascript_ajax)) {
8283  $tmpplugin = 'select2';
8284  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8285  <script>
8286  $(document).ready(function () {
8287  var data = '.json_encode($formattedarrayresult).';
8288 
8289  '.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
8290 
8291  $(".'.$htmlname.'").select2({
8292  data: data,
8293  language: select2arrayoflanguage,
8294  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8295  placeholder: "'.dol_escape_js($placeholder).'",
8296  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8297  minimumInputLength: '.$minimumInputLength.',
8298  formatResult: function(result, container, query, escapeMarkup) {
8299  return escapeMarkup(result.text);
8300  },
8301  matcher: function (params, data) {
8302 
8303  if(! data.id) return null;';
8304 
8305  if ($callurlonselect) {
8306  // We forge the url with 'sall='
8307  $outdelayed .= '
8308 
8309  var urlBase = data.url;
8310  var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8311  /* console.log("params.term="+params.term); */
8312  /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8313  saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8314  }
8315 
8316  if (!$disableFiltering) {
8317  $outdelayed .= '
8318 
8319  if(data.text.match(new RegExp(params.term))) {
8320  return data;
8321  }
8322 
8323  return null;';
8324  } else {
8325  $outdelayed .= '
8326 
8327  return data;';
8328  }
8329 
8330  $outdelayed .= '
8331  }
8332  });
8333 
8334  '.($callurlonselect ? '
8335  /* Code to execute a GET when we select a value */
8336  $(".'.$htmlname.'").change(function() {
8337  var selected = $(".'.$htmlname.'").val();
8338  console.log("We select "+selected)
8339 
8340  $(".'.$htmlname.'").val(""); /* reset visible combo value */
8341  $.each( saveRemoteData, function( key, value ) {
8342  if (key == selected)
8343  {
8344  console.log("selectArrayFilter - Do a redirect to "+value.url)
8345  location.assign(value.url);
8346  }
8347  });
8348  });' : '').'
8349 
8350  });
8351  </script>';
8352  }
8353 
8354  if ($acceptdelayedhtml) {
8355  $delayedhtmlcontent .= $outdelayed;
8356  } else {
8357  $out .= $outdelayed;
8358  }
8359  return $out;
8360  }
8361 
8380  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)
8381  {
8382  global $conf, $langs;
8383 
8384  $out = '';
8385 
8386  if ($addjscombo < 0) {
8387  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8388  $addjscombo = 1;
8389  } else {
8390  $addjscombo = 0;
8391  }
8392  }
8393 
8394  $useenhancedmultiselect = 0;
8395  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8396  $useenhancedmultiselect = 1;
8397  }
8398 
8399  // Output select component
8400  $out .= '<select id="'.$htmlname.'" class="multiselect'.($useenhancedmultiselect ? ' multiselectononeline' : '').($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
8401  if (is_array($array) && !empty($array)) {
8402  if ($value_as_key) {
8403  $array = array_combine($array, $array);
8404  }
8405 
8406  if (!empty($array)) {
8407  foreach ($array as $key => $value) {
8408  $tmpkey = $key;
8409  $tmpvalue = $value;
8410  $tmpcolor = '';
8411  $tmppicto = '';
8412  if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
8413  $tmpkey = $value['id'];
8414  $tmpvalue = $value['label'];
8415  $tmpcolor = $value['color'];
8416  $tmppicto = $value['picto'];
8417  }
8418  $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
8419  $newval = ($key_in_label ? $tmpkey.' - '.$newval : $newval);
8420 
8421  $out .= '<option value="'.$tmpkey.'"';
8422  if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
8423  $out .= ' selected';
8424  }
8425  $out .= ' data-html="'.dol_escape_htmltag(($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #'.$tmpcolor.'"') : '').$newval).'"';
8426  $out .= '>';
8427  $out .= dol_htmlentitiesbr($newval);
8428  $out .= '</option>'."\n";
8429  }
8430  }
8431  }
8432  $out .= '</select>'."\n";
8433 
8434  // Add code for jquery to use multiselect
8435  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8436  $out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->';
8437  $out .= "\n".'<script>'."\n";
8438  if ($addjscombo == 1) {
8439  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
8440  $out .= 'function formatResult(record, container) {'."\n";
8441  $out .= ' if ($(record.element).attr("data-html") != undefined) return htmlEntityDecodeJs($(record.element).attr("data-html")); // If property html set, we decode html entities and use this'."\n";
8442  $out .= ' return record.text;';
8443  $out .= '};'."\n";
8444  $out .= 'function formatSelection(record) {'."\n";
8445  if ($elemtype == 'category') {
8446  $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
8447  } else {
8448  $out .= 'return record.text;';
8449  }
8450  $out .= '};'."\n";
8451  $out .= '$(document).ready(function () {
8452  $(\'#'.$htmlname.'\').'.$tmpplugin.'({';
8453  if ($placeholder) {
8454  $out .= '
8455  placeholder: {
8456  id: \'-1\',
8457  text: \''.dol_escape_js($placeholder).'\'
8458  },';
8459  }
8460  $out .= ' dir: \'ltr\',
8461  // Specify format function for dropdown item
8462  formatResult: formatResult,
8463  templateResult: formatResult, /* For 4.0 */
8464  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8465  // Specify format function for selected item
8466  formatSelection: formatSelection,
8467  templateSelection: formatSelection /* For 4.0 */
8468  });
8469 
8470  /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
8471  the size only if component is not hidden by default on load */
8472  $(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\');
8473  });'."\n";
8474  } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
8475  // Add other js lib
8476  // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
8477  // ...
8478  $out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
8479  $out .= '$(document).ready(function () {
8480  $(\'#'.$htmlname.'\').multiSelect({
8481  containerHTML: \'<div class="multi-select-container">\',
8482  menuHTML: \'<div class="multi-select-menu">\',
8483  buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
8484  menuItemHTML: \'<label class="multi-select-menuitem">\',
8485  activeClass: \'multi-select-container--open\',
8486  noneText: \''.$placeholder.'\'
8487  });
8488  })';
8489  }
8490  $out .= '</script>';
8491  }
8492 
8493  return $out;
8494  }
8495 
8496 
8507  public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
8508  {
8509  global $conf, $langs, $user, $extrafields;
8510 
8511  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8512  return '';
8513  }
8514  if (empty($array)) {
8515  return '';
8516  }
8517 
8518  $tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved selected fields to show
8519 
8520  if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
8521  $tmparray = explode(',', $user->conf->$tmpvar);
8522  foreach ($array as $key => $val) {
8523  //var_dump($key);
8524  //var_dump($tmparray);
8525  if (in_array($key, $tmparray)) {
8526  $array[$key]['checked'] = 1;
8527  } else {
8528  $array[$key]['checked'] = 0;
8529  }
8530  }
8531  } else { // There is no list of fields already customized for user
8532  foreach ($array as $key => $val) {
8533  if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
8534  $array[$key]['checked'] = 0;
8535  }
8536  }
8537  }
8538 
8539  $listoffieldsforselection = '';
8540  $listcheckedstring = '';
8541 
8542  foreach ($array as $key => $val) {
8543  // var_dump($val);
8544  // var_dump(array_key_exists('enabled', $val));
8545  // var_dump(!$val['enabled']);
8546  if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
8547  unset($array[$key]); // We don't want this field
8548  continue;
8549  }
8550  if (!empty($val['type']) && $val['type'] == 'separate') {
8551  // Field remains in array but we don't add it into $listoffieldsforselection
8552  //$listoffieldsforselection .= '<li>-----</li>';
8553  continue;
8554  }
8555  if ($val['label']) {
8556  if (!empty($val['langfile']) && is_object($langs)) {
8557  $langs->load($val['langfile']);
8558  }
8559 
8560  // Note: $val['checked'] <> 0 means we must show the field into the combo list
8561  $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox'.$key.'" value="'.$key.'"'.((empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"').'/><label for="checkbox'.$key.'">'.dol_escape_htmltag($langs->trans($val['label'])).'</label></li>';
8562  $listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
8563  }
8564  }
8565 
8566  $out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
8567 
8568  <dl class="dropdown">
8569  <dt>
8570  <a href="#'.$htmlname.'">
8571  '.img_picto('', 'list').'
8572  </a>
8573  <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
8574  </dt>
8575  <dd class="dropdowndd">
8576  <div class="multiselectcheckbox'.$htmlname.'">
8577  <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
8578  '.$listoffieldsforselection.'
8579  </ul>
8580  </div>
8581  </dd>
8582  </dl>
8583 
8584  <script type="text/javascript">
8585  jQuery(document).ready(function () {
8586  $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
8587  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
8588 
8589  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
8590 
8591  var title = $(this).val() + ",";
8592  if ($(this).is(\':checked\')) {
8593  $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
8594  }
8595  else {
8596  $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
8597  }
8598  // Now, we submit page
8599  //$(this).parents(\'form:first\').submit();
8600  });
8601 
8602 
8603  });
8604  </script>
8605 
8606  ';
8607  return $out;
8608  }
8609 
8619  public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
8620  {
8621  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
8622 
8623  $cat = new Categorie($this->db);
8624  $categories = $cat->containing($id, $type);
8625 
8626  if ($rendermode == 1) {
8627  $toprint = array();
8628  foreach ($categories as $c) {
8629  $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
8630  foreach ($ways as $way) {
8631  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>';
8632  }
8633  }
8634  return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
8635  }
8636 
8637  if ($rendermode == 0) {
8638  $arrayselected = array();
8639  $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
8640  foreach ($categories as $c) {
8641  $arrayselected[] = $c->id;
8642  }
8643 
8644  return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
8645  }
8646 
8647  return 'ErrorBadValueForParameterRenderMode'; // Should not happened
8648  }
8649 
8659  public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false, $title = 'RelatedObjects')
8660  {
8661  global $conf, $langs, $hookmanager;
8662  global $bc, $action;
8663 
8664  $object->fetchObjectLinked();
8665 
8666  // Bypass the default method
8667  $hookmanager->initHooks(array('commonobject'));
8668  $parameters = array(
8669  'morehtmlright' => $morehtmlright,
8670  'compatibleImportElementsList' => &$compatibleImportElementsList,
8671  );
8672  $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8673 
8674  if (empty($reshook)) {
8675  $nbofdifferenttypes = count($object->linkedObjects);
8676 
8677  print '<!-- showLinkedObjectBlock -->';
8678  print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
8679 
8680 
8681  print '<div class="div-table-responsive-no-min">';
8682  print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'" data-elementid="'.$object->id.'" >';
8683 
8684  print '<tr class="liste_titre">';
8685  print '<td>'.$langs->trans("Type").'</td>';
8686  print '<td>'.$langs->trans("Ref").'</td>';
8687  print '<td class="center"></td>';
8688  print '<td class="center">'.$langs->trans("Date").'</td>';
8689  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8690  print '<td class="right">'.$langs->trans("Status").'</td>';
8691  print '<td></td>';
8692  print '</tr>';
8693 
8694  $nboftypesoutput = 0;
8695 
8696  foreach ($object->linkedObjects as $objecttype => $objects) {
8697  $tplpath = $element = $subelement = $objecttype;
8698 
8699  // to display inport button on tpl
8700  $showImportButton = false;
8701  if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
8702  $showImportButton = true;
8703  }
8704 
8705  $regs = array();
8706  if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
8707  $element = $regs[1];
8708  $subelement = $regs[2];
8709  $tplpath = $element.'/'.$subelement;
8710  }
8711  $tplname = 'linkedobjectblock';
8712 
8713  // To work with non standard path
8714  if ($objecttype == 'facture') {
8715  $tplpath = 'compta/'.$element;
8716  if (!isModEnabled('facture')) {
8717  continue; // Do not show if module disabled
8718  }
8719  } elseif ($objecttype == 'facturerec') {
8720  $tplpath = 'compta/facture';
8721  $tplname = 'linkedobjectblockForRec';
8722  if (!isModEnabled('facture')) {
8723  continue; // Do not show if module disabled
8724  }
8725  } elseif ($objecttype == 'propal') {
8726  $tplpath = 'comm/'.$element;
8727  if (!isModEnabled('propal')) {
8728  continue; // Do not show if module disabled
8729  }
8730  } elseif ($objecttype == 'supplier_proposal') {
8731  if (!isModEnabled('supplier_proposal')) {
8732  continue; // Do not show if module disabled
8733  }
8734  } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
8735  $tplpath = 'expedition';
8736  if (!isModEnabled('expedition')) {
8737  continue; // Do not show if module disabled
8738  }
8739  } elseif ($objecttype == 'reception') {
8740  $tplpath = 'reception';
8741  if (!isModEnabled('reception')) {
8742  continue; // Do not show if module disabled
8743  }
8744  } elseif ($objecttype == 'delivery') {
8745  $tplpath = 'delivery';
8746  if (!isModEnabled('expedition')) {
8747  continue; // Do not show if module disabled
8748  }
8749  } elseif ($objecttype == 'ficheinter') {
8750  $tplpath = 'fichinter';
8751  if (!isModEnabled('ficheinter')) {
8752  continue; // Do not show if module disabled
8753  }
8754  } elseif ($objecttype == 'invoice_supplier') {
8755  $tplpath = 'fourn/facture';
8756  } elseif ($objecttype == 'order_supplier') {
8757  $tplpath = 'fourn/commande';
8758  } elseif ($objecttype == 'expensereport') {
8759  $tplpath = 'expensereport';
8760  } elseif ($objecttype == 'subscription') {
8761  $tplpath = 'adherents';
8762  } elseif ($objecttype == 'conferenceorbooth') {
8763  $tplpath = 'eventorganization';
8764  } elseif ($objecttype == 'conferenceorboothattendee') {
8765  $tplpath = 'eventorganization';
8766  } elseif ($objecttype == 'mo') {
8767  $tplpath = 'mrp';
8768  if (!isModEnabled('mrp')) {
8769  continue; // Do not show if module disabled
8770  }
8771  }
8772 
8773  global $linkedObjectBlock;
8774  $linkedObjectBlock = $objects;
8775 
8776  // Output template part (modules that overwrite templates must declare this into descriptor)
8777  $dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
8778  foreach ($dirtpls as $reldir) {
8779  if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
8780  global $noMoreLinkedObjectBlockAfter;
8781  $noMoreLinkedObjectBlockAfter = 1;
8782  }
8783 
8784  $res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
8785  if ($res) {
8786  $nboftypesoutput++;
8787  break;
8788  }
8789  }
8790  }
8791 
8792  if (!$nboftypesoutput) {
8793  print '<tr><td class="impair" colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
8794  }
8795 
8796  print '</table>';
8797 
8798  if (!empty($compatibleImportElementsList)) {
8799  $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
8800  }
8801 
8802 
8803  print '</div>';
8804 
8805  return $nbofdifferenttypes;
8806  }
8807  }
8808 
8817  public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
8818  {
8819  global $conf, $langs, $hookmanager;
8820  global $action;
8821 
8822  $linktoelem = '';
8823  $linktoelemlist = '';
8824  $listofidcompanytoscan = '';
8825 
8826  if (!is_object($object->thirdparty)) {
8827  $object->fetch_thirdparty();
8828  }
8829 
8830  $possiblelinks = array();
8831  if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
8832  $listofidcompanytoscan = $object->thirdparty->id;
8833  if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
8834  $listofidcompanytoscan .= ','.$object->thirdparty->parent;
8835  }
8836  if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
8837  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
8838  $tmpproject = new Project($this->db);
8839  $tmpproject->fetch($object->fk_project);
8840  if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
8841  $listofidcompanytoscan .= ','.$tmpproject->socid;
8842  }
8843  unset($tmpproject);
8844  }
8845 
8846  $possiblelinks = array(
8847  'propal'=>array(
8848  'enabled'=>isModEnabled('propal'),
8849  'perms'=>1,
8850  'label'=>'LinkToProposal',
8851  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('propal').')'),
8852  'shipping'=>array(
8853  'enabled'=>isModEnabled('expedition'),
8854  'perms'=>1,
8855  'label'=>'LinkToExpedition',
8856  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."expedition as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('shipping').')'),
8857  'order'=>array(
8858  'enabled'=>isModEnabled('commande'),
8859  'perms'=>1,
8860  'label'=>'LinkToOrder',
8861  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande').')'),
8862  'invoice'=>array(
8863  'enabled'=>isModEnabled('facture'),
8864  'perms'=>1,
8865  'label'=>'LinkToInvoice',
8866  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('invoice').')'),
8867  'invoice_template'=>array(
8868  'enabled'=>isModEnabled('facture'),
8869  'perms'=>1,
8870  'label'=>'LinkToTemplateInvoice',
8871  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('invoice').')'),
8872  'contrat'=>array(
8873  'enabled'=>isModEnabled('contrat'),
8874  'perms'=>1,
8875  'label'=>'LinkToContract',
8876  '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
8877  FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."contrat as t, ".$this->db->prefix()."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('contract').') GROUP BY s.rowid, s.nom, s.client, t.rowid, t.ref, t.ref_customer, t.ref_supplier'),
8878  'fichinter'=>array(
8879  'enabled'=>isModEnabled('ficheinter'),
8880  'perms'=>1,
8881  'label'=>'LinkToIntervention',
8882  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('intervention').')'),
8883  'supplier_proposal'=>array(
8884  'enabled'=>(isModEnabled('supplier_proposal') ? $conf->supplier_proposal->enabled : 0),
8885  'perms'=>1,
8886  'label'=>'LinkToSupplierProposal',
8887  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('supplier_proposal').')'),
8888  'order_supplier'=>array(
8889  'enabled'=>(isModEnabled("supplier_order") ? $conf->supplier_order->enabled : 0),
8890  'perms'=>1,
8891  'label'=>'LinkToSupplierOrder',
8892  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande_fournisseur').')'),
8893  'invoice_supplier'=>array(
8894  'enabled'=>(isModEnabled("supplier_invoice") ? $conf->supplier_invoice->enabled : 0),
8895  'perms'=>1, 'label'=>'LinkToSupplierInvoice',
8896  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('facture_fourn').')'),
8897  'ticket'=>array(
8898  'enabled'=>isModEnabled('ticket'),
8899  'perms'=>1,
8900  'label'=>'LinkToTicket',
8901  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('ticket').')'),
8902  'mo'=>array(
8903  'enabled'=>isModEnabled('mrp'),
8904  'perms'=>1,
8905  'label'=>'LinkToMo',
8906  'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix()."mrp_mo as t ON t.fk_soc = s.rowid WHERE t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('mo').')')
8907  );
8908  }
8909 
8910  if ($object->table_element == 'commande_fournisseur') {
8911  $possiblelinks['mo']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix().'mrp_mo as t ON t.fk_soc = s.rowid WHERE t.entity IN ('.getEntity('mo').')';
8912  } elseif ($object->table_element == 'mrp_mo') {
8913  $possiblelinks['order_supplier']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix().'commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.entity IN ('.getEntity('commande_fournisseur').')';
8914  }
8915 
8916  if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
8917  // Can complete the possiblelink array
8918  $hookmanager->initHooks(array('commonobject'));
8919  $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
8920  $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8921  }
8922 
8923  if (empty($reshook)) {
8924  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8925  $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
8926  }
8927  } elseif ($reshook > 0) {
8928  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8929  $possiblelinks = $hookmanager->resArray;
8930  }
8931  }
8932 
8933  foreach ($possiblelinks as $key => $possiblelink) {
8934  $num = 0;
8935 
8936  if (empty($possiblelink['enabled'])) {
8937  continue;
8938  }
8939 
8940  if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
8941  print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
8942 
8943  if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8944  print '<br><form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
8945  print '<input type="hidden" name="id" value="' . $object->id . '">';
8946  print '<input type="hidden" name="action" value="addlinkbyref">';
8947  print '<input type="hidden" name="token" value="'.newToken().'">';
8948  print '<input type="hidden" name="addlink" value="' . $key . '">';
8949  print '<table class="noborder">';
8950  print '<tr>';
8951  print '<td>' . $langs->trans("Ref") . '</td>';
8952  print '<td><input type="text" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
8953  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
8954  print '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
8955  print '</tr>';
8956  print '</table>';
8957  print '</form>';
8958  }
8959 
8960  $sql = $possiblelink['sql'];
8961 
8962  $resqllist = $this->db->query($sql);
8963  if ($resqllist) {
8964  $num = $this->db->num_rows($resqllist);
8965  $i = 0;
8966 
8967  print '<br>';
8968  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
8969  print '<input type="hidden" name="action" value="addlink">';
8970  print '<input type="hidden" name="token" value="'.newToken().'">';
8971  print '<input type="hidden" name="id" value="'.$object->id.'">';
8972  print '<input type="hidden" name="addlink" value="'.$key.'">';
8973  print '<table class="noborder">';
8974  print '<tr class="liste_titre">';
8975  print '<td class="nowrap"></td>';
8976  print '<td class="center">'.$langs->trans("Ref").'</td>';
8977  print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
8978  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8979  print '<td class="left">'.$langs->trans("Company").'</td>';
8980  print '</tr>';
8981  while ($i < $num) {
8982  $objp = $this->db->fetch_object($resqllist);
8983 
8984  print '<tr class="oddeven">';
8985  print '<td class="left">';
8986  print '<input type="radio" name="idtolinkto" id="'.$key.'_'.$objp->rowid.'" value="'.$objp->rowid.'">';
8987  print '</td>';
8988  print '<td class="center"><label for="'.$key.'_'.$objp->rowid.'">'.$objp->ref.'</label></td>';
8989  print '<td>'.(!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')).'</td>';
8990  print '<td class="right">';
8991  if ($possiblelink['label'] == 'LinkToContract') {
8992  $form = new Form($this->db);
8993  print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' ';
8994  }
8995  print '<span class="amount">'.(isset($objp->total_ht) ? price($objp->total_ht) : '').'</span>';
8996  print '</td>';
8997  print '<td>'.$objp->name.'</td>';
8998  print '</tr>';
8999  $i++;
9000  }
9001  print '</table>';
9002  print '<div class="center">';
9003  print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly" value="'.$langs->trans('ToLink').'">';
9004  if (empty($conf->use_javascript_ajax)) {
9005  print '<input type="submit" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
9006  } else {
9007  print '<input type="submit"; onclick="javascript:jQuery(\'#'.$key.'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
9008  }
9009  print '</form>';
9010  $this->db->free($resqllist);
9011  } else {
9012  dol_print_error($this->db);
9013  }
9014  print '</div>';
9015 
9016  //$linktoelem.=($linktoelem?' &nbsp; ':'');
9017  if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
9018  $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
9019  // } else $linktoelem.=$langs->trans($possiblelink['label']);
9020  } else {
9021  $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
9022  }
9023  }
9024  }
9025 
9026  if ($linktoelemlist) {
9027  $linktoelem = '
9028  <dl class="dropdown" id="linktoobjectname">
9029  ';
9030  if (!empty($conf->use_javascript_ajax)) {
9031  $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>'.$langs->trans("LinkTo").'...</a></dt>';
9032  }
9033  $linktoelem .= '<dd>
9034  <div class="multiselectlinkto">
9035  <ul class="ulselectedfields">'.$linktoelemlist.'
9036  </ul>
9037  </div>
9038  </dd>
9039  </dl>';
9040  } else {
9041  $linktoelem = '';
9042  }
9043 
9044  if (!empty($conf->use_javascript_ajax)) {
9045  print '<!-- Add js to show linkto box -->
9046  <script>
9047  jQuery(document).ready(function() {
9048  jQuery(".linkto").click(function() {
9049  console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9050  jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9051  });
9052  });
9053  </script>
9054  ';
9055  }
9056 
9057  return $linktoelem;
9058  }
9059 
9074  public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '', $labelyes = 'Yes', $labelno = 'No')
9075  {
9076  global $langs;
9077 
9078  $yes = "yes";
9079  $no = "no";
9080  if ($option) {
9081  $yes = "1";
9082  $no = "0";
9083  }
9084 
9085 
9086  $disabled = ($disabled ? ' disabled' : '');
9087 
9088  $resultyesno = '<select class="flat width75'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
9089  if ($useempty) {
9090  $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
9091  }
9092  if (("$value" == 'yes') || ($value == 1)) {
9093  $resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans($labelyes).'</option>'."\n";
9094  $resultyesno .= '<option value="'.$no.'">'.$langs->trans($labelno).'</option>'."\n";
9095  } else {
9096  $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9097  $resultyesno .= '<option value="'.$yes.'">'.$langs->trans($labelyes).'</option>'."\n";
9098  $resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans($labelno).'</option>'."\n";
9099  }
9100  $resultyesno .= '</select>'."\n";
9101 
9102  if ($addjscombo) {
9103  $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9104  }
9105 
9106  return $resultyesno;
9107  }
9108 
9109  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9119  public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9120  {
9121  // phpcs:enable
9122  $sql = "SELECT rowid, label";
9123  $sql .= " FROM ".$this->db->prefix()."export_model";
9124  $sql .= " WHERE type = '".$this->db->escape($type)."'";
9125  $sql .= " ORDER BY rowid";
9126  $result = $this->db->query($sql);
9127  if ($result) {
9128  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
9129  if ($useempty) {
9130  print '<option value="-1">&nbsp;</option>';
9131  }
9132 
9133  $num = $this->db->num_rows($result);
9134  $i = 0;
9135  while ($i < $num) {
9136  $obj = $this->db->fetch_object($result);
9137  if ($selected == $obj->rowid) {
9138  print '<option value="'.$obj->rowid.'" selected>';
9139  } else {
9140  print '<option value="'.$obj->rowid.'">';
9141  }
9142  print $obj->label;
9143  print '</option>';
9144  $i++;
9145  }
9146  print "</select>";
9147  } else {
9148  dol_print_error($this->db);
9149  }
9150  }
9151 
9170  public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9171  {
9172  global $conf, $langs, $hookmanager, $extralanguages;
9173 
9174  $ret = '';
9175  if (empty($fieldid)) {
9176  $fieldid = 'rowid';
9177  }
9178  if (empty($fieldref)) {
9179  $fieldref = 'ref';
9180  }
9181 
9182  // Preparing gender's display if there is one
9183  $addgendertxt = '';
9184  if (property_exists($object, 'gender') && !empty($object->gender)) {
9185  $addgendertxt = ' ';
9186  switch ($object->gender) {
9187  case 'man':
9188  $addgendertxt .= '<i class="fas fa-mars"></i>';
9189  break;
9190  case 'woman':
9191  $addgendertxt .= '<i class="fas fa-venus"></i>';
9192  break;
9193  case 'other':
9194  $addgendertxt .= '<i class="fas fa-transgender"></i>';
9195  break;
9196  }
9197  }
9198 
9199  /*
9200  $addadmin = '';
9201  if (property_exists($object, 'admin')) {
9202  if (isModEnabled('multicompany') && !empty($object->admin) && empty($object->entity)) {
9203  $addadmin .= img_picto($langs->trans("SuperAdministratorDesc"), "redstar", 'class="paddingleft"');
9204  } elseif (!empty($object->admin)) {
9205  $addadmin .= img_picto($langs->trans("AdministratorDesc"), "star", 'class="paddingleft"');
9206  }
9207  }*/
9208 
9209  // Add where from hooks
9210  if (is_object($hookmanager)) {
9211  $parameters = array('showrefnav' => true);
9212  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9213  $object->next_prev_filter .= $hookmanager->resPrint;
9214  }
9215  $previous_ref = $next_ref = '';
9216  if ($shownav) {
9217  //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9218  $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9219 
9220  $navurl = $_SERVER["PHP_SELF"];
9221  // Special case for project/task page
9222  if ($paramid == 'project_ref') {
9223  if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9224  $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9225  $paramid = 'ref';
9226  }
9227  }
9228 
9229  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9230  // accesskey is for Mac: CTRL + key for all browsers
9231  $stringforfirstkey = $langs->trans("KeyboardShortcut");
9232  if ($conf->browser->name == 'chrome') {
9233  $stringforfirstkey .= ' ALT +';
9234  } elseif ($conf->browser->name == 'firefox') {
9235  $stringforfirstkey .= ' ALT + SHIFT +';
9236  } else {
9237  $stringforfirstkey .= ' CTL +';
9238  }
9239 
9240  $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>';
9241  $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>';
9242  }
9243 
9244  //print "xx".$previous_ref."x".$next_ref;
9245  $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9246 
9247  // Right part of banner
9248  if ($morehtmlright) {
9249  $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
9250  }
9251 
9252  if ($previous_ref || $next_ref || $morehtml) {
9253  $ret .= '<div class="pagination paginationref"><ul class="right">';
9254  }
9255  if ($morehtml) {
9256  $ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>';
9257  }
9258  if ($shownav && ($previous_ref || $next_ref)) {
9259  $ret .= '<li class="pagination">'.$previous_ref.'</li>';
9260  $ret .= '<li class="pagination">'.$next_ref.'</li>';
9261  }
9262  if ($previous_ref || $next_ref || $morehtml) {
9263  $ret .= '</ul></div>';
9264  }
9265 
9266  $parameters = array();
9267  $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9268  if (empty($reshook)) {
9269  $morehtmlstatus .= $hookmanager->resPrint;
9270  } else {
9271  $morehtmlstatus = $hookmanager->resPrint;
9272  }
9273  if ($morehtmlstatus) {
9274  $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
9275  }
9276 
9277  $parameters = array();
9278  $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9279  if (empty($reshook)) {
9280  $morehtmlref .= $hookmanager->resPrint;
9281  } elseif ($reshook > 0) {
9282  $morehtmlref = $hookmanager->resPrint;
9283  }
9284 
9285  // Left part of banner
9286  if ($morehtmlleft) {
9287  if ($conf->browser->layout == 'phone') {
9288  $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
9289  } else {
9290  $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
9291  }
9292  }
9293 
9294  //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9295  $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
9296 
9297  // For thirdparty, contact, user, member, the ref is the id, so we show something else
9298  if ($object->element == 'societe') {
9299  $ret .= dol_htmlentities($object->name);
9300 
9301  // List of extra languages
9302  $arrayoflangcode = array();
9303  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
9304  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
9305  }
9306 
9307  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9308  if (!is_object($extralanguages)) {
9309  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
9310  $extralanguages = new ExtraLanguages($this->db);
9311  }
9312  $extralanguages->fetch_name_extralanguages('societe');
9313 
9314  if (!empty($extralanguages->attributes['societe']['name'])) {
9315  $object->fetchValuesForExtraLanguages();
9316 
9317  $htmltext = '';
9318  // If there is extra languages
9319  foreach ($arrayoflangcode as $extralangcode) {
9320  $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9321  if ($object->array_languages['name'][$extralangcode]) {
9322  $htmltext .= $object->array_languages['name'][$extralangcode];
9323  } else {
9324  $htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
9325  }
9326  }
9327  $ret .= '<!-- Show translations of name -->'."\n";
9328  $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
9329  }
9330  }
9331  } elseif ($object->element == 'member') {
9332  $ret .= $object->ref.'<br>';
9333  $fullname = $object->getFullName($langs);
9334  if ($object->morphy == 'mor' && $object->societe) {
9335  $ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).$addgendertxt.')' : '');
9336  } else {
9337  $ret .= dol_htmlentities($fullname).$addgendertxt.((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
9338  }
9339  } elseif (in_array($object->element, array('contact', 'user', 'usergroup'))) {
9340  $ret .= dol_htmlentities($object->getFullName($langs)).$addgendertxt;
9341  } elseif (in_array($object->element, array('action', 'agenda'))) {
9342  $ret .= $object->ref.'<br>'.$object->label;
9343  } elseif (in_array($object->element, array('adherent_type'))) {
9344  $ret .= $object->label;
9345  } elseif ($object->element == 'ecm_directories') {
9346  $ret .= '';
9347  } elseif ($fieldref != 'none') {
9348  $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
9349  }
9350 
9351  if ($morehtmlref) {
9352  // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9353  if (substr($morehtmlref, 0, 4) != '<div') {
9354  $ret .= ' ';
9355  }
9356 
9357  $ret .= $morehtmlref;
9358  }
9359 
9360  $ret .= '</div>';
9361 
9362  $ret .= '</div><!-- End banner content -->';
9363 
9364  return $ret;
9365  }
9366 
9367 
9376  public function showbarcode(&$object, $width = 100, $morecss = '')
9377  {
9378  global $conf;
9379 
9380  //Check if barcode is filled in the card
9381  if (empty($object->barcode)) {
9382  return '';
9383  }
9384 
9385  // Complete object if not complete
9386  if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
9387  $result = $object->fetch_barcode();
9388  //Check if fetch_barcode() failed
9389  if ($result < 1) {
9390  return '<!-- ErrorFetchBarcode -->';
9391  }
9392  }
9393 
9394  // Barcode image
9395  $url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
9396  $out = '<!-- url barcode = '.$url.' -->';
9397  $out .= '<img src="'.$url.'"'.($morecss ? ' class="'.$morecss.'"' : '').'>';
9398  return $out;
9399  }
9400 
9417  public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
9418  {
9419  global $conf, $langs;
9420 
9421  $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
9422  $id = (!empty($object->id) ? $object->id : $object->rowid);
9423 
9424  $ret = '';
9425  $dir = '';
9426  $file = '';
9427  $originalfile = '';
9428  $altfile = '';
9429  $email = '';
9430  $capture = '';
9431  if ($modulepart == 'societe') {
9432  $dir = $conf->societe->multidir_output[$entity];
9433  if (!empty($object->logo)) {
9434  if (dolIsAllowedForPreview($object->logo)) {
9435  if ((string) $imagesize == 'mini') {
9436  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
9437  } elseif ((string) $imagesize == 'small') {
9438  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small');
9439  } else {
9440  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9441  }
9442  $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9443  }
9444  }
9445  $email = $object->email;
9446  } elseif ($modulepart == 'contact') {
9447  $dir = $conf->societe->multidir_output[$entity].'/contact';
9448  if (!empty($object->photo)) {
9449  if (dolIsAllowedForPreview($object->photo)) {
9450  if ((string) $imagesize == 'mini') {
9451  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9452  } elseif ((string) $imagesize == 'small') {
9453  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small');
9454  } else {
9455  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9456  }
9457  $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9458  }
9459  }
9460  $email = $object->email;
9461  $capture = 'user';
9462  } elseif ($modulepart == 'userphoto') {
9463  $dir = $conf->user->dir_output;
9464  if (!empty($object->photo)) {
9465  if (dolIsAllowedForPreview($object->photo)) {
9466  if ((string) $imagesize == 'mini') {
9467  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9468  } elseif ((string) $imagesize == 'small') {
9469  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_small');
9470  } else {
9471  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9472  }
9473  $originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9474  }
9475  }
9476  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9477  $altfile = $object->id.".jpg"; // For backward compatibility
9478  }
9479  $email = $object->email;
9480  $capture = 'user';
9481  } elseif ($modulepart == 'memberphoto') {
9482  $dir = $conf->adherent->dir_output;
9483  if (!empty($object->photo)) {
9484  if (dolIsAllowedForPreview($object->photo)) {
9485  if ((string) $imagesize == 'mini') {
9486  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9487  } elseif ((string) $imagesize == 'small') {
9488  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
9489  } else {
9490  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9491  }
9492  $originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9493  }
9494  }
9495  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9496  $altfile = $object->id.".jpg"; // For backward compatibility
9497  }
9498  $email = $object->email;
9499  $capture = 'user';
9500  } else {
9501  // Generic case to show photos
9502  $dir = $conf->$modulepart->dir_output;
9503  if (!empty($object->photo)) {
9504  if (dolIsAllowedForPreview($object->photo)) {
9505  if ((string) $imagesize == 'mini') {
9506  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
9507  } elseif ((string) $imagesize == 'small') {
9508  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
9509  } else {
9510  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9511  }
9512  $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9513  }
9514  }
9515  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9516  $altfile = $object->id.".jpg"; // For backward compatibility
9517  }
9518  $email = $object->email;
9519  }
9520 
9521  if ($forcecapture) {
9522  $capture = $forcecapture;
9523  }
9524 
9525  if ($dir) {
9526  if ($file && file_exists($dir."/".$file)) {
9527  if ($addlinktofullsize) {
9528  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9529  if ($urladvanced) {
9530  $ret .= '<a href="'.$urladvanced.'">';
9531  } else {
9532  $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9533  }
9534  }
9535  $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.'">';
9536  if ($addlinktofullsize) {
9537  $ret .= '</a>';
9538  }
9539  } elseif ($altfile && file_exists($dir."/".$altfile)) {
9540  if ($addlinktofullsize) {
9541  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9542  if ($urladvanced) {
9543  $ret .= '<a href="'.$urladvanced.'">';
9544  } else {
9545  $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9546  }
9547  }
9548  $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.'">';
9549  if ($addlinktofullsize) {
9550  $ret .= '</a>';
9551  }
9552  } else {
9553  $nophoto = '/public/theme/common/nophoto.png';
9554  $defaultimg = 'identicon'; // For gravatar
9555  if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
9556  if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor')) !== false) {
9557  $nophoto = 'company';
9558  } else {
9559  $nophoto = '/public/theme/common/user_anonymous.png';
9560  if (!empty($object->gender) && $object->gender == 'man') {
9561  $nophoto = '/public/theme/common/user_man.png';
9562  }
9563  if (!empty($object->gender) && $object->gender == 'woman') {
9564  $nophoto = '/public/theme/common/user_woman.png';
9565  }
9566  }
9567  }
9568 
9569  if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
9570  // see https://gravatar.com/site/implement/images/php/
9571  $ret .= '<!-- Put link to gravatar -->';
9572  $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" title="'.$email.' Gravatar avatar" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="https://www.gravatar.com/avatar/'.md5(strtolower(trim($email))).'?s='.$width.'&d='.$defaultimg.'">'; // gravatar need md5 hash
9573  } else {
9574  if ($nophoto == 'company') {
9575  $ret .= '<div class="divforspanimg photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').'>'.img_picto('', 'company').'</div>';
9576  $ret .= '<div class="difforspanimgright"></div>';
9577  } else {
9578  $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
9579  }
9580  }
9581  }
9582 
9583  if ($caneditfield) {
9584  if ($object->photo) {
9585  $ret .= "<br>\n";
9586  }
9587  $ret .= '<table class="nobordernopadding centpercent">';
9588  if ($object->photo) {
9589  $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">'.$langs->trans("Delete").'</label><br><br></td></tr>';
9590  }
9591  $ret .= '<tr><td class="tdoverflow">';
9592  $maxfilesizearray = getMaxFileSizeArray();
9593  $maxmin = $maxfilesizearray['maxmin'];
9594  if ($maxmin > 0) {
9595  $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
9596  }
9597  $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'>';
9598  $ret .= '</td></tr>';
9599  $ret .= '</table>';
9600  }
9601  } else {
9602  dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
9603  }
9604 
9605  return $ret;
9606  }
9607 
9608  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9625  public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
9626  {
9627  // phpcs:enable
9628  global $conf, $user, $langs;
9629 
9630  // Permettre l'exclusion de groupes
9631  $excludeGroups = null;
9632  if (is_array($exclude)) {
9633  $excludeGroups = implode(",", $exclude);
9634  }
9635  // Permettre l'inclusion de groupes
9636  $includeGroups = null;
9637  if (is_array($include)) {
9638  $includeGroups = implode(",", $include);
9639  }
9640 
9641  if (!is_array($selected)) {
9642  $selected = array($selected);
9643  }
9644 
9645  $out = '';
9646 
9647  // On recherche les groupes
9648  $sql = "SELECT ug.rowid, ug.nom as name";
9649  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9650  $sql .= ", e.label";
9651  }
9652  $sql .= " FROM ".$this->db->prefix()."usergroup as ug ";
9653  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9654  $sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid=ug.entity";
9655  if ($force_entity) {
9656  $sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
9657  } else {
9658  $sql .= " WHERE ug.entity IS NOT NULL";
9659  }
9660  } else {
9661  $sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
9662  }
9663  if (is_array($exclude) && $excludeGroups) {
9664  $sql .= " AND ug.rowid NOT IN (".$this->db->sanitize($excludeGroups).")";
9665  }
9666  if (is_array($include) && $includeGroups) {
9667  $sql .= " AND ug.rowid IN (".$this->db->sanitize($includeGroups).")";
9668  }
9669  $sql .= " ORDER BY ug.nom ASC";
9670 
9671  dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
9672  $resql = $this->db->query($sql);
9673  if ($resql) {
9674  // Enhance with select2
9675  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9676 
9677  $out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
9678 
9679  $num = $this->db->num_rows($resql);
9680  $i = 0;
9681  if ($num) {
9682  if ($show_empty && !$multiple) {
9683  $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
9684  }
9685 
9686  while ($i < $num) {
9687  $obj = $this->db->fetch_object($resql);
9688  $disableline = 0;
9689  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
9690  $disableline = 1;
9691  }
9692 
9693  $out .= '<option value="'.$obj->rowid.'"';
9694  if ($disableline) {
9695  $out .= ' disabled';
9696  }
9697  if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid) || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
9698  $out .= ' selected';
9699  }
9700  $out .= '>';
9701 
9702  $out .= $obj->name;
9703  if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
9704  $out .= " (".$obj->label.")";
9705  }
9706 
9707  $out .= '</option>';
9708  $i++;
9709  }
9710  } else {
9711  if ($show_empty) {
9712  $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
9713  }
9714  $out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
9715  }
9716  $out .= '</select>';
9717 
9718  $out .= ajax_combobox($htmlname);
9719  } else {
9720  dol_print_error($this->db);
9721  }
9722 
9723  return $out;
9724  }
9725 
9726 
9733  public function showFilterButtons($pos = '')
9734  {
9735  $out = '<div class="nowraponall">';
9736  if ($pos == 'left') {
9737  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9738  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9739  } else {
9740  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9741  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9742  }
9743  $out .= '</div>';
9744 
9745  return $out;
9746  }
9747 
9756  public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9757  {
9758  global $conf, $langs;
9759 
9760  $out = '';
9761 
9762  if (!empty($conf->use_javascript_ajax)) {
9763  $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
9764  }
9765  $out .= '<script>
9766  $(document).ready(function() {
9767  $("#' . $cssclass.'s").click(function() {
9768  if($(this).is(\':checked\')){
9769  console.log("We check all '.$cssclass.' and trigger the change method");
9770  $(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
9771  }
9772  else
9773  {
9774  console.log("We uncheck all");
9775  $(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
9776  }'."\n";
9777  if ($calljsfunction) {
9778  $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
9779  }
9780  $out .= ' });
9781  $(".' . $cssclass.'").change(function() {
9782  $(this).closest("tr").toggleClass("highlight", this.checked);
9783  });
9784  });
9785  </script>';
9786 
9787  return $out;
9788  }
9789 
9799  public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9800  {
9801  $out = $this->showFilterButtons();
9802  if ($addcheckuncheckall) {
9803  $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
9804  }
9805  return $out;
9806  }
9807 
9821  public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
9822  {
9823  global $langs, $user;
9824 
9825  $out = '';
9826  $sql = "SELECT rowid, label FROM ".$this->db->prefix()."c_exp_tax_cat WHERE active = 1";
9827  $sql .= " AND entity IN (0,".getEntity('exp_tax_cat').")";
9828  if (!empty($excludeid)) {
9829  $sql .= " AND rowid NOT IN (".$this->db->sanitize(implode(',', $excludeid)).")";
9830  }
9831  $sql .= " ORDER BY label";
9832 
9833  $resql = $this->db->query($sql);
9834  if ($resql) {
9835  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
9836  if ($useempty) {
9837  $out .= '<option value="0">&nbsp;</option>';
9838  }
9839 
9840  while ($obj = $this->db->fetch_object($resql)) {
9841  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
9842  }
9843  $out .= '</select>';
9844  $out .= ajax_combobox('select_'.$htmlname);
9845 
9846  if (!empty($htmlname) && $user->admin && $info_admin) {
9847  $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
9848  }
9849 
9850  if (!empty($target)) {
9851  $sql = "SELECT c.id FROM ".$this->db->prefix()."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
9852  $resql = $this->db->query($sql);
9853  if ($resql) {
9854  if ($this->db->num_rows($resql) > 0) {
9855  $obj = $this->db->fetch_object($resql);
9856  $out .= '<script>
9857  $(function() {
9858  $("select[name='.$target.']").on("change", function() {
9859  var current_val = $(this).val();
9860  if (current_val == '.$obj->id.') {';
9861  if (!empty($default_selected) || !empty($selected)) {
9862  $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
9863  }
9864 
9865  $out .= '
9866  $("select[name='.$htmlname.']").change();
9867  }
9868  });
9869 
9870  $("select[name='.$htmlname.']").change(function() {
9871 
9872  if ($("select[name='.$target.']").val() == '.$obj->id.') {
9873  // get price of kilometer to fill the unit price
9874  $.ajax({
9875  method: "POST",
9876  dataType: "json",
9877  data: { fk_c_exp_tax_cat: $(this).val(), token: \''.currentToken().'\' },
9878  url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php?'.join('&', $params)).'",
9879  }).done(function( data, textStatus, jqXHR ) {
9880  console.log(data);
9881  if (typeof data.up != "undefined") {
9882  $("input[name=value_unit]").val(data.up);
9883  $("select[name='.$htmlname.']").attr("title", data.title);
9884  } else {
9885  $("input[name=value_unit]").val("");
9886  $("select[name='.$htmlname.']").attr("title", "");
9887  }
9888  });
9889  }
9890  });
9891  });
9892  </script>';
9893  }
9894  }
9895  }
9896  } else {
9897  dol_print_error($this->db);
9898  }
9899 
9900  return $out;
9901  }
9902 
9911  public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
9912  {
9913  global $conf, $langs;
9914 
9915  $out = '';
9916  $sql = "SELECT rowid, range_ik FROM ".$this->db->prefix()."c_exp_tax_range";
9917  $sql .= " WHERE entity = ".$conf->entity." AND active = 1";
9918 
9919  $resql = $this->db->query($sql);
9920  if ($resql) {
9921  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9922  if ($useempty) {
9923  $out .= '<option value="0"></option>';
9924  }
9925 
9926  while ($obj = $this->db->fetch_object($resql)) {
9927  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
9928  }
9929  $out .= '</select>';
9930  } else {
9931  dol_print_error($this->db);
9932  }
9933 
9934  return $out;
9935  }
9936 
9947  public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
9948  {
9949  global $langs;
9950 
9951  $out = '';
9952  $sql = "SELECT id, code, label FROM ".$this->db->prefix()."c_type_fees";
9953  $sql .= " WHERE active = 1";
9954 
9955  $resql = $this->db->query($sql);
9956  if ($resql) {
9957  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9958  if ($useempty) {
9959  $out .= '<option value="0"></option>';
9960  }
9961  if ($allchoice) {
9962  $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
9963  }
9964 
9965  $field = 'code';
9966  if ($useid) {
9967  $field = 'id';
9968  }
9969 
9970  while ($obj = $this->db->fetch_object($resql)) {
9971  $key = $langs->trans($obj->code);
9972  $out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
9973  }
9974  $out .= '</select>';
9975  } else {
9976  dol_print_error($this->db);
9977  }
9978 
9979  return $out;
9980  }
9981 
10000  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)
10001  {
10002  global $user, $conf, $langs;
10003 
10004  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
10005 
10006  if (is_null($usertofilter)) {
10007  $usertofilter = $user;
10008  }
10009 
10010  $out = '';
10011 
10012  $hideunselectables = false;
10013  if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
10014  $hideunselectables = true;
10015  }
10016 
10017  if (empty($projectsListId)) {
10018  if (empty($usertofilter->rights->projet->all->lire)) {
10019  $projectstatic = new Project($this->db);
10020  $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10021  }
10022  }
10023 
10024  // Search all projects
10025  $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10026  p.title, p.fk_soc, p.fk_statut, p.public,";
10027  $sql .= ' s.nom as name';
10028  $sql .= ' FROM '.$this->db->prefix().'projet as p';
10029  $sql .= ' LEFT JOIN '.$this->db->prefix().'societe as s ON s.rowid = p.fk_soc,';
10030  $sql .= ' '.$this->db->prefix().'facture as f';
10031  $sql .= " WHERE p.entity IN (".getEntity('project').")";
10032  $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10033  //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10034  //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10035  //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10036  $sql .= " ORDER BY p.ref, f.ref ASC";
10037 
10038  $resql = $this->db->query($sql);
10039  if ($resql) {
10040  // Use select2 selector
10041  if (!empty($conf->use_javascript_ajax)) {
10042  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
10043  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10044  $out .= $comboenhancement;
10045  $morecss = 'minwidth200imp maxwidth500';
10046  }
10047 
10048  if (empty($option_only)) {
10049  $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
10050  }
10051  if (!empty($show_empty)) {
10052  $out .= '<option value="0" class="optiongrey">';
10053  if (!is_numeric($show_empty)) {
10054  $out .= $show_empty;
10055  } else {
10056  $out .= '&nbsp;';
10057  }
10058  $out .= '</option>';
10059  }
10060  $num = $this->db->num_rows($resql);
10061  $i = 0;
10062  if ($num) {
10063  while ($i < $num) {
10064  $obj = $this->db->fetch_object($resql);
10065  // 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.
10066  if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
10067  // Do nothing
10068  } else {
10069  if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10070  $i++;
10071  continue;
10072  }
10073 
10074  $labeltoshow = '';
10075 
10076  if ($showproject == 'all') {
10077  $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10078  if ($obj->name) {
10079  $labeltoshow .= ' - '.$obj->name; // Soc name
10080  }
10081 
10082  $disabled = 0;
10083  if ($obj->fk_statut == Project::STATUS_DRAFT) {
10084  $disabled = 1;
10085  $labeltoshow .= ' - '.$langs->trans("Draft");
10086  } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10087  if ($discard_closed == 2) {
10088  $disabled = 1;
10089  }
10090  $labeltoshow .= ' - '.$langs->trans("Closed");
10091  } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10092  $disabled = 1;
10093  $labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
10094  }
10095  }
10096 
10097  if (!empty($selected) && $selected == $obj->rowid) {
10098  $out .= '<option value="'.$obj->rowid.'" selected';
10099  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10100  $out .= '>'.$labeltoshow.'</option>';
10101  } else {
10102  if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10103  $resultat = '';
10104  } else {
10105  $resultat = '<option value="'.$obj->rowid.'"';
10106  if ($disabled) {
10107  $resultat .= ' disabled';
10108  }
10109  //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10110  //else $labeltoshow.=' ('.$langs->trans("Private").')';
10111  $resultat .= '>';
10112  $resultat .= $labeltoshow;
10113  $resultat .= '</option>';
10114  }
10115  $out .= $resultat;
10116  }
10117  }
10118  $i++;
10119  }
10120  }
10121  if (empty($option_only)) {
10122  $out .= '</select>';
10123  }
10124 
10125  print $out;
10126 
10127  $this->db->free($resql);
10128  return $num;
10129  } else {
10130  dol_print_error($this->db);
10131  return -1;
10132  }
10133  }
10134 
10148  public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
10149  {
10150  global $user, $conf, $langs;
10151 
10152  $out = '';
10153 
10154  dol_syslog('FactureRec::fetch', LOG_DEBUG);
10155 
10156  $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10157  //$sql.= ', el.fk_source';
10158  $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10159  $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10160  $sql .= " ORDER BY f.titre ASC";
10161 
10162  $resql = $this->db->query($sql);
10163  if ($resql) {
10164  // Use select2 selector
10165  if (!empty($conf->use_javascript_ajax)) {
10166  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10167  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10168  $out .= $comboenhancement;
10169  $morecss = 'minwidth200imp maxwidth500';
10170  }
10171 
10172  if (empty($option_only)) {
10173  $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10174  }
10175  if (!empty($show_empty)) {
10176  $out .= '<option value="0" class="optiongrey">';
10177  if (!is_numeric($show_empty)) {
10178  $out .= $show_empty;
10179  } else {
10180  $out .= '&nbsp;';
10181  }
10182  $out .= '</option>';
10183  }
10184  $num = $this->db->num_rows($resql);
10185  if ($num) {
10186  while ($obj = $this->db->fetch_object($resql)) {
10187  $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10188 
10189  $disabled = 0;
10190  if (!empty($obj->suspended)) {
10191  $disabled = 1;
10192  $labeltoshow .= ' - ' . $langs->trans("Closed");
10193  }
10194 
10195 
10196  if (!empty($selected) && $selected == $obj->rowid) {
10197  $out .= '<option value="' . $obj->rowid . '" selected';
10198  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10199  $out .= '>' . $labeltoshow . '</option>';
10200  } else {
10201  if ($disabled && ($selected != $obj->rowid)) {
10202  $resultat = '';
10203  } else {
10204  $resultat = '<option value="' . $obj->rowid . '"';
10205  if ($disabled) {
10206  $resultat .= ' disabled';
10207  }
10208  $resultat .= '>';
10209  $resultat .= $labeltoshow;
10210  $resultat .= '</option>';
10211  }
10212  $out .= $resultat;
10213  }
10214  }
10215  }
10216  if (empty($option_only)) {
10217  $out .= '</select>';
10218  }
10219 
10220  print $out;
10221 
10222  $this->db->free($resql);
10223  return $num;
10224  } else {
10225  $this->errors[]=$this->db->lasterror;
10226  return -1;
10227  }
10228  }
10229 
10239  public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10240  {
10241  global $langs;
10242 
10243  $ret = '';
10244 
10245  $ret .= '<div class="divadvancedsearchfieldcomp inline-block">';
10246  //$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
10247  $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10248  $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("Filters")).'" id="idsubimgproductdistribution"></span>';
10249  //$ret .= $langs->trans("Filters");
10250  $ret .= '</a>';
10251 
10252  $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10253 
10254  // Show select fields as tags.
10255  $ret .= '<div name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10256 
10257  if ($search_component_params_hidden) {
10258  if (!preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10259  $search_component_params_hidden .= '('.$search_component_params_hidden.')';
10260  }
10261  $errormessage = '';
10262  $searchtags = forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage);
10263  if ($errormessage) {
10264  print 'ERROR in parsing search string: '.dol_escape_htmltag($errormessage);
10265  }
10266  //var_dump($searchtags);
10267  $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch"><span class="tagsearchdelete select2-selection__choice__remove">x</span> '.dol_escape_htmltag($searchtags).'</span>';
10268  }
10269 
10270  //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10271 
10272  //$ret .= search_component_params
10273  //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10274  //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10275 
10276  $show_search_component_params_hidden = 1;
10277  if ($show_search_component_params_hidden) {
10278  $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10279  }
10280  $ret .= "<!-- We store the full search string into this field. For example: (t.ref:like:'SO-%') and ((t.ref:like:'CO-%') or (t.ref:like:'AA%')) -->";
10281  $ret .= '<input type="hidden" name="search_component_params_hidden" value="'.dol_escape_htmltag($search_component_params_hidden).'">';
10282  // For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
10283  foreach ($arrayofcriterias as $criterias) {
10284  foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
10285  if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10286  continue;
10287  }
10288  if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10289  continue;
10290  }
10291  if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10292  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
10293  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
10294  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
10295  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
10296  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
10297  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
10298  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
10299  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
10300  } else {
10301  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
10302  }
10303  }
10304  }
10305 
10306  $ret .= '</div>';
10307 
10308  $ret .= "<!-- Syntax of Generic filter string: t.ref:like:'SO-%', t.date_creation:<:'20160101', t.date_creation:<:'2016-01-01 12:30:00', t.nature:is:NULL, t.field2:isnot:NULL -->\n";
10309  $ret .= '<input type="text" placeholder="'.$langs->trans("Search").'" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10310 
10311  $ret .= '</div>';
10312  $ret .= '</div>';
10313 
10314  return $ret;
10315  }
10316 
10326  public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
10327  {
10328  global $langs, $user;
10329 
10330  $retstring = '';
10331 
10332  $TModels = array();
10333 
10334  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
10335  $formmail = new FormMail($this->db);
10336  $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
10337 
10338  if ($default) {
10339  $TModels[0] = $langs->trans('DefaultMailModel');
10340  }
10341  if ($result > 0) {
10342  foreach ($formmail->lines_model as $model) {
10343  $TModels[$model->id] = $model->label;
10344  }
10345  }
10346 
10347  $retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
10348 
10349  foreach ($TModels as $id_model => $label_model) {
10350  $retstring .= '<option value="'.$id_model.'"';
10351  $retstring .= ">".$label_model."</option>";
10352  }
10353 
10354  $retstring .= "</select>";
10355 
10356  if ($addjscombo) {
10357  $retstring .= ajax_combobox('select_'.$prefix.'model_mail');
10358  }
10359 
10360  return $retstring;
10361  }
10362 
10374  public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = 0, $morecss = '', $dol_openinpopup = '')
10375  {
10376  global $langs;
10377 
10378  $buttons = array();
10379 
10380  $save = array(
10381  'name' => 'save',
10382  'label_key' => $save_label,
10383  );
10384 
10385  if ($save_label == 'Create' || $save_label == 'Add' ) {
10386  $save['name'] = 'add';
10387  } elseif ($save_label == 'Modify') {
10388  $save['name'] = 'edit';
10389  }
10390 
10391  $cancel = array(
10392  'name' => 'cancel',
10393  'label_key' => 'Cancel',
10394  );
10395 
10396  !empty($save_label) ? $buttons[] = $save : '';
10397 
10398  if (!empty($morebuttons)) {
10399  $buttons[] = $morebuttons;
10400  }
10401 
10402  !empty($cancel_label) ? $buttons[] = $cancel : '';
10403 
10404  $retstring = $withoutdiv ? '': '<div class="center">';
10405 
10406  foreach ($buttons as $button) {
10407  $addclass = empty($button['addclass']) ? '' : $button['addclass'];
10408  $retstring .= '<input type="submit" class="button button-'.$button['name'].($morecss ? ' '.$morecss : '').' '.$addclass.'" name="'.$button['name'].'" value="'.dol_escape_htmltag($langs->trans($button['label_key'])).'">';
10409  }
10410  $retstring .= $withoutdiv ? '': '</div>';
10411 
10412  if ($dol_openinpopup) {
10413  $retstring .= '<!-- buttons are shown into a $dol_openinpopup='.$dol_openinpopup.' context, so we enable the close of dialog on cancel -->'."\n";
10414  $retstring .= '<script>';
10415  $retstring .= 'jQuery(".button-cancel").click(function(e) {
10416  e.preventDefault(); console.log(\'We click on cancel in iframe popup '.$dol_openinpopup.'\');
10417  window.parent.jQuery(\'#idfordialog'.$dol_openinpopup.'\').dialog(\'close\');
10418  });';
10419  $retstring .= '</script>';
10420  }
10421 
10422  return $retstring;
10423  }
10424 }
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition: ajax.lib.php:47
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition: ajax.lib.php:449
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input field into an au...
Definition: ajax.lib.php:297
Class to manage bank accounts.
Class to manage categories.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0)
selectModelMail
showFilterButtons($pos='')
Return HTML to show the search and clear seach button.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
load_cache_vatrates($country_code)
Load into the cache vat rates of a country.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_address($selected, $socid, $htmlname='address_id', $showempty=0)
Return list of delivery address.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
select_contacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $showsoc=0, $forcecombo=0, $events=array(), $options_only=false, $moreparam='', $htmlid='')
Return list of all contacts (for a third party or all)
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
Show a confirmation HTML form or AJAX popup.
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
selectcontacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=false, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0)
Return HTML code of the SELECT of list of all contacts (for a third party or all).
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear seach button.
select_company($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $limit=0, $morecss='minwidth100', $moreparam='', $selected_input_value='', $hidelabel=1, $ajaxoptions=array(), $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
textwithpicto($text, $htmltext, $direction=1, $type='help', $extracss='', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0')
Return the HTML select list of users.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_dolgroups($selected='', $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity='0', $multiple=false, $morecss='')
Return select list of groups.
selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='', $openinghours='', $stepminutes=1, $labeladddateof='', $placeholder='', $gm='auto')
Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
form_users($page, $selected='', $htmlname='userid', $exclude='', $include='')
Show a select form to choose a user.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=0, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_cache_availability()
Load int a cache property th elist of possible delivery delays.
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
selectMembersList($selected='', $htmlname='adherentid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of adherents.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=false, $title='RelatedObjects')
Show linked object block.
selectTicketsList($selected='', $htmlname='ticketid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of tickets.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
print list of payment modes.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier='')
Return list of suppliers prices for a product.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $markafterid=0, $outputmode=0, $include=0, $morecss='')
Return list of categories having choosed type.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
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.
selectProjectsList($selected='', $htmlname='projectid', $filtertype='', $limit=20, $filterkey='', $status=1, $outputmode=0, $showempty='1', $forcecombo=0, $morecss='')
Return list of projects.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
Load in cache list of transport mode.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array())
Return select list of users.
form_confirm($page, $title, $question, $action, $formquestion='', $selectedchoice="", $useajax=0, $height=170, $width=500)
Show a confirmation HTML form or AJAX popup.
load_cache_conditions_paiements()
Load into cache list of payment terms.
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_produits_list($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1)
Return list of products for a customer.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=0, $formatfunc='', $paramid='id', $gm='auto')
Output value of a field for an editable field.
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='')
Output the component to make advanced search criteries.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
select_produits($selected='', $htmlname='productid', $filtertype='', $limit=0, $price_level=0, $status=1, $finished=2, $selected_input_value='', $hidelabel=0, $ajaxoptions=array(), $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $selected_combinations=null, $nooutput=0, $status_purchase=-1)
Return list of products for customer in Ajax if Ajax activated or go to select_produits_list.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse='', $societe_acheteuse='', $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0)
Output an HTML select vat rate.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
load_cache_types_paiements()
Charge dans cache la liste des types de paiements 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.
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Retourne la liste des types de delais de livraison possibles.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday='', $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
Classe permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new For...
Class to manage building of HTML components.
Class to manage hooks.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php:47
currency_name($code_iso, $withcode='', $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition: date.lib.php:83
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
forgeSQLFromUniversalSearchCriteria($filter, &$error='')
forgeSQLFromUniversalSearchCriteria
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_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...
dol_print_url($url, $target='_blank', $max=32, $withpicto=0)
Show Url link.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array())
Clean a string to keep only desirable HTML tags.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Fonction qui renvoie si tva doit etre tva percue recuperable.
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
$formconfirm
if ($action == 'delbookkeepingyear') {
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:87
table tableforfield button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
Definition: style.css.php:843
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition: repair.php:119
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:122
getMaxFileSizeArray()
Return the max allowed for file upload.
$conf db
API class for accounts.
Definition: inc.php:41
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...