dolibarr  x.y.z
html.form.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5  * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6  * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7  * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8  * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9  * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10  * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11  * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12  * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13  * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14  * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15  * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17  * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18  * Copyright (C) 2014-2020 Alexandre Spangaro <aspangaro@open-dsi.fr>
19  * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20  * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
21  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22  * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23  * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24  *
25  * This program is free software; you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation; either version 3 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program. If not, see <https://www.gnu.org/licenses/>.
37  */
38 
52 class Form
53 {
57  public $db;
58 
62  public $error = '';
63 
67  public $errors = array();
68 
69  public $num;
70 
71  // Cache arrays
72  public $cache_types_paiements = array();
73  public $cache_conditions_paiements = array();
74  public $cache_transport_mode = array();
75  public $cache_availability = array();
76  public $cache_demand_reason = array();
77  public $cache_types_fees = array();
78  public $cache_vatrates = array();
79 
80 
86  public function __construct($db)
87  {
88  $this->db = $db;
89  }
90 
107  public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
108  {
109  global $conf, $langs;
110 
111  $ret = '';
112 
113  // TODO change for compatibility
114  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) {
115  if (!empty($perm)) {
116  $tmp = explode(':', $typeofdata);
117  $ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
118  if ($fieldrequired) {
119  $ret .= '<span class="fieldrequired">';
120  }
121  if ($help) {
122  $ret .= $this->textwithpicto($langs->trans($text), $help);
123  } else {
124  $ret .= $langs->trans($text);
125  }
126  if ($fieldrequired) {
127  $ret .= '</span>';
128  }
129  $ret .= '</div>'."\n";
130  } else {
131  if ($fieldrequired) {
132  $ret .= '<span class="fieldrequired">';
133  }
134  if ($help) {
135  $ret .= $this->textwithpicto($langs->trans($text), $help);
136  } else {
137  $ret .= $langs->trans($text);
138  }
139  if ($fieldrequired) {
140  $ret .= '</span>';
141  }
142  }
143  } else {
144  if (empty($notabletag) && $perm) {
145  $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
146  }
147  if ($fieldrequired) {
148  $ret .= '<span class="fieldrequired">';
149  }
150  if ($help) {
151  $ret .= $this->textwithpicto($langs->trans($text), $help);
152  } else {
153  $ret .= $langs->trans($text);
154  }
155  if ($fieldrequired) {
156  $ret .= '</span>';
157  }
158  if (!empty($notabletag)) {
159  $ret .= ' ';
160  }
161  if (empty($notabletag) && $perm) {
162  $ret .= '</td>';
163  }
164  if (empty($notabletag) && $perm) {
165  $ret .= '<td class="right">';
166  }
167  if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) {
168  $ret .= '<a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&token='.newToken().'&'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
169  }
170  if (!empty($notabletag) && $notabletag == 1) {
171  $ret .= ' : ';
172  }
173  if (!empty($notabletag) && $notabletag == 3) {
174  $ret .= ' ';
175  }
176  if (empty($notabletag) && $perm) {
177  $ret .= '</td>';
178  }
179  if (empty($notabletag) && $perm) {
180  $ret .= '</tr></table>';
181  }
182  }
183 
184  return $ret;
185  }
186 
207  public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array())
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)/', $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  $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
281  $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, $addnowlink, 0, '', '', '', '', 1, '', '', $gm);
282  } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
283  $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
284  $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, $addnowlink, 0, '', '', '', '', 1, '', '', $gm);
285  } elseif (preg_match('/^select;/', $typeofdata)) {
286  $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
287  $arraylist = array();
288  foreach ($arraydata as $val) {
289  $tmp = explode(':', $val);
290  $tmpkey = str_replace('|', ':', $tmp[0]);
291  $arraylist[$tmpkey] = $tmp[1];
292  }
293  $ret .= $this->selectarray($htmlname, $arraylist, $value);
294  } elseif (preg_match('/^ckeditor/', $typeofdata)) {
295  $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
296  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
297  $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]));
298  $ret .= $doleditor->Create(1);
299  }
300  if (empty($notabletag)) {
301  $ret .= '</td>';
302  }
303 
304  // Button save-cancel
305  if (empty($notabletag)) {
306  $ret .= '<td class="left">';
307  }
308  //else $ret.='<div class="clearboth"></div>';
309  $ret .= '<input type="submit" class="smallpaddingimp button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
310  if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
311  $ret .= '<br>'."\n";
312  }
313  $ret .= '<input type="submit" class="smallpaddingimp button button-cancel'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
314  if (empty($notabletag)) {
315  $ret .= '</td>';
316  }
317 
318  if (empty($notabletag)) {
319  $ret .= '</tr></table>'."\n";
320  }
321  $ret .= '</form>'."\n";
322  } else {
323  if (preg_match('/^(email)/', $typeofdata)) {
324  $ret .= dol_print_email($value, 0, 0, 0, 0, 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  $alt = '';
724  if ($tooltiptrigger) {
725  $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
726  }
727 
728  //For backwards compatibility
729  if ($type == '0') {
730  $type = 'info';
731  } elseif ($type == '1') {
732  $type = 'help';
733  }
734 
735  // If info or help with no javascript, show only text
736  if (empty($conf->use_javascript_ajax)) {
737  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
738  return $text;
739  } else {
740  $alt = $htmltext;
741  $htmltext = '';
742  }
743  }
744 
745  // If info or help with smartphone, show only text (tooltip hover can't works)
746  if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
747  if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
748  return $text;
749  }
750  }
751  // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
752  //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
753  //{
754  //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
755  //}
756 
757  $img = '';
758  if ($type == 'info') {
759  $img = img_help(0, $alt);
760  } elseif ($type == 'help') {
761  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
762  } elseif ($type == 'helpclickable') {
763  $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
764  } elseif ($type == 'superadmin') {
765  $img = img_picto($alt, 'redstar');
766  } elseif ($type == 'admin') {
767  $img = img_picto($alt, 'star');
768  } elseif ($type == 'warning') {
769  $img = img_warning($alt);
770  } elseif ($type != 'none') {
771  $img = img_picto($alt, $type); // $type can be an image path
772  }
773 
774  return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
775  }
776 
787  public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
788  {
789  global $conf, $langs, $hookmanager;
790 
791 
792  $disabled = 0;
793  $ret = '<div class="centpercent center">';
794  $ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>';
795 
796  // 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.
797  $parameters = array();
798  $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
799  // check if there is a mass action
800  if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
801  return;
802  }
803  if (empty($reshook)) {
804  $ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
805  foreach ($arrayofaction as $code => $label) {
806  $ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
807  }
808  }
809  $ret .= $hookmanager->resPrint;
810 
811  $ret .= '</select>';
812 
813  if (empty($conf->dol_optimize_smallscreen)) {
814  $ret .= ajax_combobox('.'.$name.'select');
815  }
816 
817  // 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
818  $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.
819  $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")).'">';
820  $ret .= '</div>';
821 
822  if (!empty($conf->use_javascript_ajax)) {
823  $ret .= '<!-- JS CODE TO ENABLE mass action select -->
824  <script>
825  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 */
826  {
827  atleastoneselected=0;
828  jQuery("."+cssclass).each(function( index ) {
829  /* console.log( index + ": " + $( this ).text() ); */
830  if ($(this).is(\':checked\')) atleastoneselected++;
831  });
832 
833  console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
834 
835  if (atleastoneselected || '.$alwaysvisible.')
836  {
837  jQuery("."+name).show();
838  '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').'
839  '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').'
840  }
841  else
842  {
843  jQuery("."+name).hide();
844  jQuery("."+name+"other").hide();
845  }
846  }
847 
848  jQuery(document).ready(function () {
849  initCheckForSelect(0, "' . $name.'", "'.$cssclass.'");
850  jQuery(".' . $cssclass.'").click(function() {
851  initCheckForSelect(1, "'.$name.'", "'.$cssclass.'");
852  });
853  jQuery(".' . $name.'select").change(function() {
854  var massaction = $( this ).val();
855  var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
856  if (massaction == "builddoc")
857  {
858  urlform = urlform + "#show_files";
859  }
860  $( this ).closest("form").attr("action", urlform);
861  console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform);
862  /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
863  if ($(this).val() != \'0\')
864  {
865  jQuery(".' . $name.'confirmed").prop(\'disabled\', false);
866  jQuery(".' . $name.'other").hide(); /* To disable if another div was open */
867  jQuery(".' . $name.'"+massaction).show();
868  }
869  else
870  {
871  jQuery(".' . $name.'confirmed").prop(\'disabled\', true);
872  jQuery(".' . $name.'other").hide(); /* To disable any div open */
873  }
874  });
875  });
876  </script>
877  ';
878  }
879 
880  return $ret;
881  }
882 
883  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
900  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)
901  {
902  // phpcs:enable
903  global $conf, $langs, $mysoc;
904 
905  $langs->load("dict");
906 
907  $out = '';
908  $countryArray = array();
909  $favorite = array();
910  $label = array();
911  $atleastonefavorite = 0;
912 
913  $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
914  $sql .= " FROM ".$this->db->prefix()."c_country";
915  $sql .= " WHERE active > 0";
916  //$sql.= " ORDER BY code ASC";
917 
918  dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
919  $resql = $this->db->query($sql);
920  if ($resql) {
921  $out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
922  $num = $this->db->num_rows($resql);
923  $i = 0;
924  if ($num) {
925  while ($i < $num) {
926  $obj = $this->db->fetch_object($resql);
927 
928  $countryArray[$i]['rowid'] = $obj->rowid;
929  $countryArray[$i]['code_iso'] = $obj->code_iso;
930  $countryArray[$i]['code_iso3'] = $obj->code_iso3;
931  $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 : ''));
932  $countryArray[$i]['favorite'] = $obj->favorite;
933  $countryArray[$i]['eec'] = $obj->eec;
934  $favorite[$i] = $obj->favorite;
935  $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
936  $i++;
937  }
938 
939  if (empty($disablefavorites)) {
940  $array1_sort_order = SORT_DESC;
941  $array2_sort_order = SORT_ASC;
942  array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
943  } else {
944  $countryArray = dol_sort_array($countryArray, 'label');
945  }
946 
947  if ($showempty) {
948  if (is_numeric($showempty)) {
949  $out .= '<option value="">&nbsp;</option>'."\n";
950  } else {
951  $out .= '<option value="">'.$langs->trans($showempty).'</option>'."\n";
952  }
953  }
954 
955  if ($addspecialentries) { // Add dedicated entries for groups of countries
956  //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
957  $out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
958  $out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
959  if ($mysoc->isInEEC()) {
960  $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
961  }
962  $out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
963  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
964  }
965 
966  foreach ($countryArray as $row) {
967  //if (empty($showempty) && empty($row['rowid'])) continue;
968  if (empty($row['rowid'])) {
969  continue;
970  }
971  if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
972  continue; // exclude some countries
973  }
974 
975  if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
976  $atleastonefavorite++;
977  }
978  if (empty($row['favorite']) && $atleastonefavorite) {
979  $atleastonefavorite = 0;
980  $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
981  }
982 
983  $labeltoshow = '';
984  if ($row['label']) {
985  $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
986  } else {
987  $labeltoshow .= '&nbsp;';
988  }
989  if ($row['code_iso']) {
990  $labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>';
991  if (empty($hideflags)) {
992  $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
993  $labeltoshow = $tmpflag.' '.$labeltoshow;
994  }
995  }
996 
997  if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
998  $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']).'">';
999  } else {
1000  $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']).'">';
1001  }
1002  $out .= $labeltoshow;
1003  $out .= '</option>'."\n";
1004  }
1005  }
1006  $out .= '</select>';
1007  } else {
1008  dol_print_error($this->db);
1009  }
1010 
1011  // Make select dynamic
1012  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1013  $out .= ajax_combobox('select'.$htmlname, array(), 0, 0, 'resolve');
1014 
1015  return $out;
1016  }
1017 
1018  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1032  public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1033  {
1034  // phpcs:enable
1035  global $conf, $langs;
1036 
1037  $langs->load("dict");
1038 
1039  $out = '';
1040  $moreattrib = '';
1041  $incotermArray = array();
1042 
1043  $sql = "SELECT rowid, code";
1044  $sql .= " FROM ".$this->db->prefix()."c_incoterms";
1045  $sql .= " WHERE active > 0";
1046  $sql .= " ORDER BY code ASC";
1047 
1048  dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
1049  $resql = $this->db->query($sql);
1050  if ($resql) {
1051  if ($conf->use_javascript_ajax && !$forcecombo) {
1052  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1053  $out .= ajax_combobox($htmlname, $events);
1054  }
1055 
1056  if (!empty($page)) {
1057  $out .= '<form method="post" action="'.$page.'">';
1058  $out .= '<input type="hidden" name="action" value="set_incoterms">';
1059  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
1060  }
1061 
1062  $out .= '<select id="'.$htmlname.'" class="flat selectincoterm width75" name="'.$htmlname.'" '.$htmloption.'>';
1063  $out .= '<option value="0">&nbsp;</option>';
1064  $num = $this->db->num_rows($resql);
1065  $i = 0;
1066  if ($num) {
1067  while ($i < $num) {
1068  $obj = $this->db->fetch_object($resql);
1069  $incotermArray[$i]['rowid'] = $obj->rowid;
1070  $incotermArray[$i]['code'] = $obj->code;
1071  $i++;
1072  }
1073 
1074  foreach ($incotermArray as $row) {
1075  if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1076  $out .= '<option value="'.$row['rowid'].'" selected>';
1077  } else {
1078  $out .= '<option value="'.$row['rowid'].'">';
1079  }
1080 
1081  if ($row['code']) {
1082  $out .= $row['code'];
1083  }
1084 
1085  $out .= '</option>';
1086  }
1087  }
1088  $out .= '</select>';
1089 
1090  if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1091  $out .= ajax_multiautocompleter('location_incoterms', '', DOL_URL_ROOT.'/core/ajax/locationincoterms.php')."\n";
1092  $moreattrib .= ' autocomplete="off"';
1093  }
1094  $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="'.$location_incoterms.'">'."\n";
1095 
1096  if (!empty($page)) {
1097  $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="'.$langs->trans("Modify").'"></form>';
1098  }
1099  } else {
1100  dol_print_error($this->db);
1101  }
1102 
1103  return $out;
1104  }
1105 
1106  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1118  public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1119  {
1120  // phpcs:enable
1121  global $langs, $conf;
1122 
1123  // If product & services are enabled or both disabled.
1124  if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1125  || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1126  if (empty($hidetext)) {
1127  print $langs->trans("Type").': ';
1128  }
1129  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
1130  if ($showempty) {
1131  print '<option value="-1"';
1132  if ($selected == -1) {
1133  print ' selected';
1134  }
1135  print '>&nbsp;</option>';
1136  }
1137 
1138  print '<option value="0"';
1139  if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1140  print ' selected';
1141  }
1142  print '>'.$langs->trans("Product");
1143 
1144  print '<option value="1"';
1145  if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1146  print ' selected';
1147  }
1148  print '>'.$langs->trans("Service");
1149 
1150  print '</select>';
1151  print ajax_combobox('select_'.$htmlname);
1152  //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1153  }
1154  if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1155  print $langs->trans("Service");
1156  print '<input type="hidden" name="'.$htmlname.'" value="1">';
1157  }
1158  if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1159  print $langs->trans("Product");
1160  print '<input type="hidden" name="'.$htmlname.'" value="0">';
1161  }
1162  if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1163  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
1164  }
1165  }
1166 
1167  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1173  public function load_cache_types_fees()
1174  {
1175  // phpcs:enable
1176  global $langs;
1177 
1178  $num = count($this->cache_types_fees);
1179  if ($num > 0) {
1180  return 0; // Cache already loaded
1181  }
1182 
1183  dol_syslog(__METHOD__, LOG_DEBUG);
1184 
1185  $langs->load("trips");
1186 
1187  $sql = "SELECT c.code, c.label";
1188  $sql .= " FROM ".$this->db->prefix()."c_type_fees as c";
1189  $sql .= " WHERE active > 0";
1190 
1191  $resql = $this->db->query($sql);
1192  if ($resql) {
1193  $num = $this->db->num_rows($resql);
1194  $i = 0;
1195 
1196  while ($i < $num) {
1197  $obj = $this->db->fetch_object($resql);
1198 
1199  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1200  $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1201  $this->cache_types_fees[$obj->code] = $label;
1202  $i++;
1203  }
1204 
1205  asort($this->cache_types_fees);
1206 
1207  return $num;
1208  } else {
1209  dol_print_error($this->db);
1210  return -1;
1211  }
1212  }
1213 
1214  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1223  public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1224  {
1225  // phpcs:enable
1226  global $user, $langs;
1227 
1228  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1229 
1230  $this->load_cache_types_fees();
1231 
1232  print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1233  if ($showempty) {
1234  print '<option value="-1"';
1235  if ($selected == -1) {
1236  print ' selected';
1237  }
1238  print '>&nbsp;</option>';
1239  }
1240 
1241  foreach ($this->cache_types_fees as $key => $value) {
1242  print '<option value="'.$key.'"';
1243  if ($key == $selected) {
1244  print ' selected';
1245  }
1246  print '>';
1247  print $value;
1248  print '</option>';
1249  }
1250 
1251  print '</select>';
1252  if ($user->admin) {
1253  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1254  }
1255  }
1256 
1257 
1258  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1280  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)
1281  {
1282  // phpcs:enable
1283  global $conf, $user, $langs;
1284 
1285  $out = '';
1286 
1287  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1288  if (is_null($ajaxoptions)) {
1289  $ajaxoptions = array();
1290  }
1291 
1292  require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1293 
1294  // No immediate load of all database
1295  $placeholder = '';
1296  if ($selected && empty($selected_input_value)) {
1297  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1298  $societetmp = new Societe($this->db);
1299  $societetmp->fetch($selected);
1300  $selected_input_value = $societetmp->name;
1301  unset($societetmp);
1302  }
1303 
1304  // mode 1
1305  $urloption = 'htmlname='.urlencode(str_replace('.', '_', $htmlname)).'&outjson=1&filter='.urlencode($filter).(empty($excludeids) ? '' : '&excludeids='.join(',', $excludeids)).($showtype ? '&showtype='.urlencode($showtype) : '').($showcode ? '&showcode='.urlencode($showcode) : '');
1306 
1307  $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
1308  if (empty($hidelabel)) {
1309  print $langs->trans("RefOrLabel").' : ';
1310  } elseif ($hidelabel > 1) {
1311  $placeholder = $langs->trans("RefOrLabel");
1312  if ($hidelabel == 2) {
1313  $out .= img_picto($langs->trans("Search"), 'search');
1314  }
1315  }
1316  $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' : '').' />';
1317  if ($hidelabel == 3) {
1318  $out .= img_picto($langs->trans("Search"), 'search');
1319  }
1320 
1321  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1322  } else {
1323  // Immediate load of all database
1324  $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1325  }
1326 
1327  return $out;
1328  }
1329 
1330  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1352  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)
1353  {
1354  // phpcs:enable
1355  global $conf, $user, $langs;
1356  global $hookmanager;
1357 
1358  $out = '';
1359  $num = 0;
1360  $outarray = array();
1361 
1362  if ($selected === '') {
1363  $selected = array();
1364  } elseif (!is_array($selected)) {
1365  $selected = array($selected);
1366  }
1367 
1368  // Clean $filter that may contains sql conditions so sql code
1369  if (function_exists('testSqlAndScriptInject')) {
1370  if (testSqlAndScriptInject($filter, 3) > 0) {
1371  $filter = '';
1372  }
1373  }
1374 
1375  // We search companies
1376  $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1377  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1378  $sql .= ", s.address, s.zip, s.town";
1379  $sql .= ", dictp.code as country_code";
1380  }
1381  $sql .= " FROM ".$this->db->prefix()."societe as s";
1382  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1383  $sql .= " LEFT JOIN ".$this->db->prefix()."c_country as dictp ON dictp.rowid = s.fk_pays";
1384  }
1385  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1386  $sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
1387  }
1388  $sql .= " WHERE s.entity IN (".getEntity('societe').")";
1389  if (!empty($user->socid)) {
1390  $sql .= " AND s.rowid = ".((int) $user->socid);
1391  }
1392  if ($filter) {
1393  $sql .= " AND (".$filter.")";
1394  }
1395  if (empty($user->rights->societe->client->voir) && !$user->socid) {
1396  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
1397  }
1398  if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1399  $sql .= " AND s.status <> 0";
1400  }
1401  if (!empty($excludeids)) {
1402  $sql .= " AND s.rowid NOT IN (".$this->db->sanitize(join(',', $excludeids)).")";
1403  }
1404  // Add where from hooks
1405  $parameters = array();
1406  $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1407  $sql .= $hookmanager->resPrint;
1408  // Add criteria
1409  if ($filterkey && $filterkey != '') {
1410  $sql .= " AND (";
1411  $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1412  // For natural search
1413  $scrit = explode(' ', $filterkey);
1414  $i = 0;
1415  if (count($scrit) > 1) {
1416  $sql .= "(";
1417  }
1418  foreach ($scrit as $crit) {
1419  if ($i > 0) {
1420  $sql .= " AND ";
1421  }
1422  $sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1423  $i++;
1424  }
1425  if (count($scrit) > 1) {
1426  $sql .= ")";
1427  }
1428  if (isModEnabled('barcode')) {
1429  $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1430  }
1431  $sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1432  $sql .= " OR s.name_alias LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.tva_intra LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1433  $sql .= ")";
1434  }
1435  $sql .= $this->db->order("nom", "ASC");
1436  $sql .= $this->db->plimit($limit, 0);
1437 
1438  // Build output string
1439  dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1440  $resql = $this->db->query($sql);
1441  if ($resql) {
1442  if (!$forcecombo) {
1443  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1444  $out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1445  }
1446 
1447  // Construct $out and $outarray
1448  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1449 
1450  $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1451  if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1452  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1453  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1454  if ($showempty && !is_numeric($showempty)) {
1455  $textifempty = $langs->trans($showempty);
1456  } else {
1457  $textifempty .= $langs->trans("All");
1458  }
1459  }
1460  if ($showempty) {
1461  $out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.($textifempty ? $textifempty : '&nbsp;').'</span>').'">'.$textifempty.'</option>'."\n";
1462  }
1463 
1464  $companytemp = new Societe($this->db);
1465 
1466  $num = $this->db->num_rows($resql);
1467  $i = 0;
1468  if ($num) {
1469  while ($i < $num) {
1470  $obj = $this->db->fetch_object($resql);
1471  $label = '';
1472  if ($showcode || !empty($conf->global->SOCIETE_ADD_REF_IN_LIST)) {
1473  if (($obj->client) && (!empty($obj->code_client))) {
1474  $label = $obj->code_client.' - ';
1475  }
1476  if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1477  $label .= $obj->code_fournisseur.' - ';
1478  }
1479  $label .= ' '.$obj->name;
1480  } else {
1481  $label = $obj->name;
1482  }
1483 
1484  if (!empty($obj->name_alias)) {
1485  $label .= ' ('.$obj->name_alias.')';
1486  }
1487 
1488  if (!empty($conf->global->SOCIETE_SHOW_VAT_IN_LIST) && !empty($obj->tva_intra)) {
1489  $label .= ' - '.$obj->tva_intra;
1490  }
1491 
1492  $labelhtml = $label;
1493 
1494  if ($showtype) {
1495  $companytemp->id = $obj->rowid;
1496  $companytemp->client = $obj->client;
1497  $companytemp->fournisseur = $obj->fournisseur;
1498  $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1499  if ($tmptype) {
1500  $labelhtml .= ' '.$tmptype;
1501  }
1502 
1503  if ($obj->client || $obj->fournisseur) {
1504  $label .= ' (';
1505  }
1506  if ($obj->client == 1 || $obj->client == 3) {
1507  $label .= $langs->trans("Customer");
1508  }
1509  if ($obj->client == 2 || $obj->client == 3) {
1510  $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1511  }
1512  if ($obj->fournisseur) {
1513  $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1514  }
1515  if ($obj->client || $obj->fournisseur) {
1516  $label .= ')';
1517  }
1518  }
1519 
1520  if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1521  $s = ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : '');
1522  if (!empty($obj->country_code)) {
1523  $s .= ', '.$langs->trans('Country'.$obj->country_code);
1524  }
1525  $label .= $s;
1526  $labelhtml .= $s;
1527  }
1528 
1529  if (empty($outputmode)) {
1530  if (in_array($obj->rowid, $selected)) {
1531  $out .= '<option value="'.$obj->rowid.'" selected data-html="'.dol_escape_htmltag($labelhtml).'">'.$label.'</option>';
1532  } else {
1533  $out .= '<option value="'.$obj->rowid.'" data-html="'.dol_escape_htmltag($labelhtml).'">'.$label.'</option>';
1534  }
1535  } else {
1536  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label, 'labelhtml'=>$labelhtml));
1537  }
1538 
1539  $i++;
1540  if (($i % 10) == 0) {
1541  $out .= "\n";
1542  }
1543  }
1544  }
1545  $out .= '</select>'."\n";
1546  } else {
1547  dol_print_error($this->db);
1548  }
1549 
1550  $this->result = array('nbofthirdparties'=>$num);
1551 
1552  if ($outputmode) {
1553  return $outarray;
1554  }
1555  return $out;
1556  }
1557 
1558 
1559  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1570  public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1571  {
1572  // phpcs:enable
1573  global $langs, $conf;
1574 
1575  // On recherche les remises
1576  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1577  $sql .= " re.description, re.fk_facture_source";
1578  $sql .= " FROM ".$this->db->prefix()."societe_remise_except as re";
1579  $sql .= " WHERE re.fk_soc = ".(int) $socid;
1580  $sql .= " AND re.entity = ".$conf->entity;
1581  if ($filter) {
1582  $sql .= " AND ".$filter;
1583  }
1584  $sql .= " ORDER BY re.description ASC";
1585 
1586  dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1587  $resql = $this->db->query($sql);
1588  if ($resql) {
1589  print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1590  $num = $this->db->num_rows($resql);
1591 
1592  $qualifiedlines = $num;
1593 
1594  $i = 0;
1595  if ($num) {
1596  print '<option value="0">&nbsp;</option>';
1597  while ($i < $num) {
1598  $obj = $this->db->fetch_object($resql);
1599  $desc = dol_trunc($obj->description, 40);
1600  if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
1601  $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
1602  }
1603  if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
1604  $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
1605  }
1606  if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
1607  $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
1608  }
1609  if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
1610  $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
1611  }
1612 
1613  $selectstring = '';
1614  if ($selected > 0 && $selected == $obj->rowid) {
1615  $selectstring = ' selected';
1616  }
1617 
1618  $disabled = '';
1619  if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1620  $qualifiedlines--;
1621  $disabled = ' disabled';
1622  }
1623 
1624  if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1625  $tmpfac = new Facture($this->db);
1626  if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1627  $desc = $desc.' - '.$tmpfac->ref;
1628  }
1629  }
1630 
1631  print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1632  $i++;
1633  }
1634  }
1635  print '</select>';
1636  print ajax_combobox('select_'.$htmlname);
1637 
1638  return $qualifiedlines;
1639  } else {
1640  dol_print_error($this->db);
1641  return -1;
1642  }
1643  }
1644 
1645  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1666  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 = '')
1667  {
1668  // phpcs:enable
1669  print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1670  return $this->num;
1671  }
1672 
1697  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)
1698  {
1699  global $conf, $langs, $hookmanager, $action;
1700 
1701  $langs->load('companies');
1702 
1703  if (empty($htmlid)) {
1704  $htmlid = $htmlname;
1705  }
1706  $num = 0;
1707 
1708  if ($selected === '') {
1709  $selected = array();
1710  } elseif (!is_array($selected)) {
1711  $selected = array($selected);
1712  }
1713  $out = '';
1714 
1715  if (!is_object($hookmanager)) {
1716  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1717  $hookmanager = new HookManager($this->db);
1718  }
1719 
1720  // We search third parties
1721  $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";
1722  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1723  $sql .= ", s.nom as company, s.town AS company_town";
1724  }
1725  $sql .= " FROM ".$this->db->prefix()."socpeople as sp";
1726  if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1727  $sql .= " LEFT OUTER JOIN ".$this->db->prefix()."societe as s ON s.rowid=sp.fk_soc";
1728  }
1729  $sql .= " WHERE sp.entity IN (".getEntity('contact').")";
1730  if ($socid > 0 || $socid == -1) {
1731  $sql .= " AND sp.fk_soc = ".((int) $socid);
1732  }
1733  if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1734  $sql .= " AND sp.statut <> 0";
1735  }
1736  // Add where from hooks
1737  $parameters = array();
1738  $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1739  $sql .= $hookmanager->resPrint;
1740  $sql .= " ORDER BY sp.lastname ASC";
1741 
1742  dol_syslog(get_class($this)."::selectcontacts", LOG_DEBUG);
1743  $resql = $this->db->query($sql);
1744  if ($resql) {
1745  $num = $this->db->num_rows($resql);
1746 
1747  if ($htmlname != 'none' && !$options_only) {
1748  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1749  }
1750 
1751  if ($showempty && ! is_numeric($showempty)) {
1752  $textforempty = $showempty;
1753  $out .= '<option class="optiongrey" value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>'.$textforempty.'</option>';
1754  } else {
1755  if (($showempty == 1 || ($showempty == 3 && $num > 1)) && ! $multiple) {
1756  $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1757  }
1758  if ($showempty == 2) {
1759  $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1760  }
1761  }
1762 
1763  $i = 0;
1764  if ($num) {
1765  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1766  $contactstatic = new Contact($this->db);
1767 
1768  while ($i < $num) {
1769  $obj = $this->db->fetch_object($resql);
1770 
1771  // Set email (or phones) and town extended infos
1772  $extendedInfos = '';
1773  if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1774  $extendedInfos = array();
1775  $email = trim($obj->email);
1776  if (!empty($email)) {
1777  $extendedInfos[] = $email;
1778  } else {
1779  $phone = trim($obj->phone);
1780  $phone_perso = trim($obj->phone_perso);
1781  $phone_mobile = trim($obj->phone_mobile);
1782  if (!empty($phone)) {
1783  $extendedInfos[] = $phone;
1784  }
1785  if (!empty($phone_perso)) {
1786  $extendedInfos[] = $phone_perso;
1787  }
1788  if (!empty($phone_mobile)) {
1789  $extendedInfos[] = $phone_mobile;
1790  }
1791  }
1792  $contact_town = trim($obj->contact_town);
1793  $company_town = trim($obj->company_town);
1794  if (!empty($contact_town)) {
1795  $extendedInfos[] = $contact_town;
1796  } elseif (!empty($company_town)) {
1797  $extendedInfos[] = $company_town;
1798  }
1799  $extendedInfos = implode(' - ', $extendedInfos);
1800  if (!empty($extendedInfos)) {
1801  $extendedInfos = ' - '.$extendedInfos;
1802  }
1803  }
1804 
1805  $contactstatic->id = $obj->rowid;
1806  $contactstatic->lastname = $obj->lastname;
1807  $contactstatic->firstname = $obj->firstname;
1808  if ($obj->statut == 1) {
1809  if ($htmlname != 'none') {
1810  $disabled = 0;
1811  if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1812  $disabled = 1;
1813  }
1814  if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1815  $disabled = 1;
1816  }
1817  if (!empty($selected) && in_array($obj->rowid, $selected)) {
1818  $out .= '<option value="'.$obj->rowid.'"';
1819  if ($disabled) {
1820  $out .= ' disabled';
1821  }
1822  $out .= ' selected>';
1823  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1824  if ($showfunction && $obj->poste) {
1825  $out .= ' ('.$obj->poste.')';
1826  }
1827  if (($showsoc > 0) && $obj->company) {
1828  $out .= ' - ('.$obj->company.')';
1829  }
1830  $out .= '</option>';
1831  } else {
1832  $out .= '<option value="'.$obj->rowid.'"';
1833  if ($disabled) {
1834  $out .= ' disabled';
1835  }
1836  $out .= '>';
1837  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1838  if ($showfunction && $obj->poste) {
1839  $out .= ' ('.$obj->poste.')';
1840  }
1841  if (($showsoc > 0) && $obj->company) {
1842  $out .= ' - ('.$obj->company.')';
1843  }
1844  $out .= '</option>';
1845  }
1846  } else {
1847  if (in_array($obj->rowid, $selected)) {
1848  $out .= $contactstatic->getFullName($langs).$extendedInfos;
1849  if ($showfunction && $obj->poste) {
1850  $out .= ' ('.$obj->poste.')';
1851  }
1852  if (($showsoc > 0) && $obj->company) {
1853  $out .= ' - ('.$obj->company.')';
1854  }
1855  }
1856  }
1857  }
1858  $i++;
1859  }
1860  } else {
1861  $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1862  $out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">';
1863  $out .= $labeltoshow;
1864  $out .= '</option>';
1865  }
1866 
1867  $parameters = array(
1868  'socid'=>$socid,
1869  'htmlname'=>$htmlname,
1870  'resql'=>$resql,
1871  'out'=>&$out,
1872  'showfunction'=>$showfunction,
1873  'showsoc'=>$showsoc,
1874  );
1875 
1876  $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1877 
1878  if ($htmlname != 'none' && !$options_only) {
1879  $out .= '</select>';
1880  }
1881 
1882  if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1883  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1884  $out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1885  }
1886 
1887  $this->num = $num;
1888  return $out;
1889  } else {
1890  dol_print_error($this->db);
1891  return -1;
1892  }
1893  }
1894 
1895  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1911  public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1912  {
1913  // phpcs:enable
1914  print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1915  }
1916 
1917  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1942  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)
1943  {
1944  // phpcs:enable
1945  global $conf, $user, $langs, $hookmanager;
1946  global $action;
1947 
1948  // If no preselected user defined, we take current user
1949  if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
1950  $selected = $user->id;
1951  }
1952 
1953  if ($selected === '') {
1954  $selected = array();
1955  } elseif (!is_array($selected)) {
1956  $selected = array($selected);
1957  }
1958 
1959  $excludeUsers = null;
1960  $includeUsers = null;
1961 
1962  // Permettre l'exclusion d'utilisateurs
1963  if (is_array($exclude)) {
1964  $excludeUsers = implode(",", $exclude);
1965  }
1966  // Permettre l'inclusion d'utilisateurs
1967  if (is_array($include)) {
1968  $includeUsers = implode(",", $include);
1969  } elseif ($include == 'hierarchy') {
1970  // Build list includeUsers to have only hierarchy
1971  $includeUsers = implode(",", $user->getAllChildIds(0));
1972  } elseif ($include == 'hierarchyme') {
1973  // Build list includeUsers to have only hierarchy and current user
1974  $includeUsers = implode(",", $user->getAllChildIds(1));
1975  }
1976 
1977  $out = '';
1978  $outarray = array();
1979 
1980  // Forge request to select users
1981  $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
1982  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
1983  $sql .= ", e.label";
1984  }
1985  $sql .= " FROM ".$this->db->prefix()."user as u";
1986  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
1987  $sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid = u.entity";
1988  if ($force_entity) {
1989  $sql .= " WHERE u.entity IN (0, ".$this->db->sanitize($force_entity).")";
1990  } else {
1991  $sql .= " WHERE u.entity IS NOT NULL";
1992  }
1993  } else {
1994  if (isModEnabled('multicompany') && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1995  $sql .= " LEFT JOIN ".$this->db->prefix()."usergroup_user as ug";
1996  $sql .= " ON ug.fk_user = u.rowid";
1997  $sql .= " WHERE ug.entity = ".$conf->entity;
1998  } else {
1999  $sql .= " WHERE u.entity IN (0, ".$conf->entity.")";
2000  }
2001  }
2002  if (!empty($user->socid)) {
2003  $sql .= " AND u.fk_soc = ".((int) $user->socid);
2004  }
2005  if (is_array($exclude) && $excludeUsers) {
2006  $sql .= " AND u.rowid NOT IN (".$this->db->sanitize($excludeUsers).")";
2007  }
2008  if ($includeUsers) {
2009  $sql .= " AND u.rowid IN (".$this->db->sanitize($includeUsers).")";
2010  }
2011  if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $notdisabled) {
2012  $sql .= " AND u.statut <> 0";
2013  }
2014  if (!empty($morefilter)) {
2015  $sql .= " ".$morefilter;
2016  }
2017 
2018  //Add hook to filter on user (for exemple on usergroup define in custom modules)
2019  $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2020  if (!empty($reshook)) {
2021  $sql .= $hookmanager->resPrint;
2022  }
2023 
2024  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2025  $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2026  } else {
2027  $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2028  }
2029 
2030  dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
2031 
2032  $resql = $this->db->query($sql);
2033  if ($resql) {
2034  $num = $this->db->num_rows($resql);
2035  $i = 0;
2036  if ($num) {
2037  // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2038  $out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
2039  if ($show_empty && !$multiple) {
2040  $textforempty = ' ';
2041  if (!empty($conf->use_javascript_ajax)) {
2042  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2043  }
2044  if (!is_numeric($show_empty)) {
2045  $textforempty = $show_empty;
2046  }
2047  $out .= '<option class="optiongrey" value="'.($show_empty < 0 ? $show_empty : -1).'"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
2048  }
2049  if ($show_every) {
2050  $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
2051  }
2052 
2053  $userstatic = new User($this->db);
2054 
2055  while ($i < $num) {
2056  $obj = $this->db->fetch_object($resql);
2057 
2058  $userstatic->id = $obj->rowid;
2059  $userstatic->lastname = $obj->lastname;
2060  $userstatic->firstname = $obj->firstname;
2061  $userstatic->photo = $obj->photo;
2062  $userstatic->statut = $obj->status;
2063  $userstatic->entity = $obj->entity;
2064  $userstatic->admin = $obj->admin;
2065 
2066  $disableline = '';
2067  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2068  $disableline = ($enableonlytext ? $enableonlytext : '1');
2069  }
2070 
2071  $labeltoshow = ''; $labeltoshowhtml = '';
2072 
2073  // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2074  $fullNameMode = 0;
2075  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2076  $fullNameMode = 1; //Firstname+lastname
2077  }
2078  $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2079  $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2080  if (empty($obj->firstname) && empty($obj->lastname)) {
2081  $labeltoshow .= $obj->login;
2082  $labeltoshowhtml .= $obj->login;
2083  }
2084 
2085  // Complete name with a more info string like: ' (info1 - info2 - ...)'
2086  $moreinfo = ''; $moreinfohtml = '';
2087  if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2088  $moreinfo .= ($moreinfo ? ' - ' : ' (');
2089  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2090  $moreinfo .= $obj->login;
2091  $moreinfohtml .= $obj->login;
2092  }
2093  if ($showstatus >= 0) {
2094  if ($obj->status == 1 && $showstatus == 1) {
2095  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
2096  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').$langs->trans('Enabled');
2097  }
2098  if ($obj->status == 0 && $showstatus == 1) {
2099  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
2100  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').$langs->trans('Disabled');
2101  }
2102  }
2103  if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2104  if (!$obj->entity) {
2105  $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
2106  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').$langs->trans("AllEntities");
2107  } else {
2108  if ($obj->entity != $conf->entity) {
2109  $moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2110  $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2111  }
2112  }
2113  }
2114  $moreinfo .= ($moreinfo ? ')' : '');
2115  $moreinfohtml .= ($moreinfohtml ? ')' : '');
2116  if ($disableline && $disableline != '1') {
2117  // Add text from $enableonlytext parameter
2118  $moreinfo .= ' - '.$disableline;
2119  $moreinfohtml .= ' - '.$disableline;
2120  }
2121  $labeltoshow .= $moreinfo;
2122  $labeltoshowhtml .= $moreinfohtml;
2123 
2124  $out .= '<option value="'.$obj->rowid.'"';
2125  if ($disableline) {
2126  $out .= ' disabled';
2127  }
2128  if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2129  $out .= ' selected';
2130  }
2131  $out .= ' data-html="';
2132  $outhtml = '';
2133  // if (!empty($obj->photo)) {
2134  $outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
2135  // }
2136  if ($showstatus >= 0 && $obj->status == 0) {
2137  $outhtml .= '<strike class="opacitymediumxxx">';
2138  }
2139  $outhtml .= $labeltoshowhtml;
2140  if ($showstatus >= 0 && $obj->status == 0) {
2141  $outhtml .= '</strike>';
2142  }
2143  $out .= dol_escape_htmltag($outhtml);
2144  $out .= '">';
2145  $out .= $labeltoshow;
2146  $out .= '</option>';
2147 
2148  $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
2149 
2150  $i++;
2151  }
2152  } else {
2153  $out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
2154  $out .= '<option value="">'.$langs->trans("None").'</option>';
2155  }
2156  $out .= '</select>';
2157 
2158  if ($num && !$forcecombo) {
2159  // Enhance with select2
2160  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2161  $out .= ajax_combobox($htmlname);
2162  }
2163  } else {
2164  dol_print_error($this->db);
2165  }
2166 
2167  if ($outputmode) {
2168  return $outarray;
2169  }
2170 
2171  return $out;
2172  }
2173 
2174 
2175  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2198  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())
2199  {
2200  // phpcs:enable
2201  global $conf, $user, $langs;
2202 
2203  $userstatic = new User($this->db);
2204  $out = '';
2205 
2206 
2207  $assignedtouser = array();
2208  if (!empty($_SESSION['assignedtouser'])) {
2209  $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2210  }
2211  $nbassignetouser = count($assignedtouser);
2212 
2213  //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2214  if ($nbassignetouser) {
2215  $out .= '<ul class="attendees">';
2216  }
2217  $i = 0;
2218  $ownerid = 0;
2219  foreach ($assignedtouser as $key => $value) {
2220  if ($value['id'] == $ownerid) {
2221  continue;
2222  }
2223 
2224  $out .= '<li>';
2225  $userstatic->fetch($value['id']);
2226  $out .= $userstatic->getNomUrl(-1);
2227  if ($i == 0) {
2228  $ownerid = $value['id'];
2229  $out .= ' ('.$langs->trans("Owner").')';
2230  }
2231  if ($nbassignetouser > 1 && $action != 'view') {
2232  $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.'">';
2233  }
2234  // Show my availability
2235  if ($showproperties) {
2236  if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2237  $out .= '<div class="myavailability inline-block">';
2238  $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>';
2239  $out .= '</div>';
2240  }
2241  }
2242  //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2243  //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2244 
2245  $out .= '</li>';
2246  $i++;
2247  }
2248  if ($nbassignetouser) {
2249  $out .= '</ul>';
2250  }
2251 
2252  // Method with no ajax
2253  if ($action != 'view') {
2254  $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2255  $out .= '<script type="text/javascript">jQuery(document).ready(function () {';
2256  $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2257  $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2258  $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }';
2259  $out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }';
2260  $out .= '});';
2261  $out .= '})</script>';
2262  $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2263  $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
2264  $out .= '<br>';
2265  }
2266 
2267  return $out;
2268  }
2269 
2270 
2271  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2299  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)
2300  {
2301  // phpcs:enable
2302  global $langs, $conf;
2303 
2304  $out = '';
2305 
2306  // check parameters
2307  $price_level = (!empty($price_level) ? $price_level : 0);
2308  if (is_null($ajaxoptions)) {
2309  $ajaxoptions = array();
2310  }
2311 
2312  if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2313  if (isModEnabled("product") && !isModEnabled('service')) {
2314  $filtertype = '0';
2315  } elseif (!isModEnabled('product') && isModEnabled("service")) {
2316  $filtertype = '1';
2317  }
2318  }
2319 
2320  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2321  $placeholder = '';
2322 
2323  if ($selected && empty($selected_input_value)) {
2324  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2325  $producttmpselect = new Product($this->db);
2326  $producttmpselect->fetch($selected);
2327  $selected_input_value = $producttmpselect->ref;
2328  unset($producttmpselect);
2329  }
2330  // handle case where product or service module is disabled + no filter specified
2331  if ($filtertype == '') {
2332  if (!isModEnabled('product')) { // when product module is disabled, show services only
2333  $filtertype = 1;
2334  } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2335  $filtertype = 0;
2336  }
2337  }
2338  // mode=1 means customers products
2339  $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;
2340  //Price by customer
2341  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2342  $urloption .= '&socid='.$socid;
2343  }
2344  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2345 
2346  if (isModEnabled('variants') && is_array($selected_combinations)) {
2347  // Code to automatically insert with javascript the select of attributes under the select of product
2348  // when a parent of variant has been selected.
2349  $out .= '
2350  <!-- script to auto show attributes select tags if a variant was selected -->
2351  <script>
2352  // auto show attributes fields
2353  selected = '.json_encode($selected_combinations).';
2354  combvalues = {};
2355 
2356  jQuery(document).ready(function () {
2357 
2358  jQuery("input[name=\'prod_entry_mode\']").change(function () {
2359  if (jQuery(this).val() == \'free\') {
2360  jQuery(\'div#attributes_box\').empty();
2361  }
2362  });
2363 
2364  jQuery("input#'.$htmlname.'").change(function () {
2365 
2366  if (!jQuery(this).val()) {
2367  jQuery(\'div#attributes_box\').empty();
2368  return;
2369  }
2370 
2371  console.log("A change has started. We get variants fields to inject html select");
2372 
2373  jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
2374  id: jQuery(this).val()
2375  }, function (data) {
2376  jQuery(\'div#attributes_box\').empty();
2377 
2378  jQuery.each(data, function (key, val) {
2379 
2380  combvalues[val.id] = val.values;
2381 
2382  var span = jQuery(document.createElement(\'div\')).css({
2383  \'display\': \'table-row\'
2384  });
2385 
2386  span.append(
2387  jQuery(document.createElement(\'div\')).text(val.label).css({
2388  \'font-weight\': \'bold\',
2389  \'display\': \'table-cell\'
2390  })
2391  );
2392 
2393  var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2394  \'margin-left\': \'15px\',
2395  \'white-space\': \'pre\'
2396  }).append(
2397  jQuery(document.createElement(\'option\')).val(\'\')
2398  );
2399 
2400  jQuery.each(combvalues[val.id], function (key, val) {
2401  var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2402 
2403  if (selected[val.fk_product_attribute] == val.id) {
2404  tag.attr(\'selected\', \'selected\');
2405  }
2406 
2407  html.append(tag);
2408  });
2409 
2410  span.append(html);
2411  jQuery(\'div#attributes_box\').append(span);
2412  });
2413  })
2414  });
2415 
2416  '.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2417  });
2418  </script>
2419  ';
2420  }
2421 
2422  if (empty($hidelabel)) {
2423  $out .= $langs->trans("RefOrLabel").' : ';
2424  } elseif ($hidelabel > 1) {
2425  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2426  if ($hidelabel == 2) {
2427  $out .= img_picto($langs->trans("Search"), 'search');
2428  }
2429  }
2430  $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' : '').' />';
2431  if ($hidelabel == 3) {
2432  $out .= img_picto($langs->trans("Search"), 'search');
2433  }
2434  } else {
2435  $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2436  }
2437 
2438  if (empty($nooutput)) {
2439  print $out;
2440  } else {
2441  return $out;
2442  }
2443  }
2444 
2445  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2446 
2462  public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2463  {
2464  // phpcs:enable
2465  global $conf, $user, $langs, $db;
2466 
2467  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2468 
2469  $error = 0;
2470  $out = '';
2471 
2472  if (!$forcecombo) {
2473  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2474  $events = array();
2475  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2476  }
2477 
2478  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2479 
2480  $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2481  $sql.= ' FROM '.MAIN_DB_PREFIX.'bom_bom as b';
2482  $sql.= ' WHERE b.entity IN ('.getEntity('bom').')';
2483  if (!empty($status)) $sql.= ' AND status = '. (int) $status;
2484  if (!empty($type)) $sql.= ' AND bomtype = '. (int) $type;
2485  if (!empty($TProducts)) $sql .= ' AND fk_product IN ('.$this->db->sanitize(implode(',', $TProducts)).')';
2486  if (!empty($limit)) $sql.= ' LIMIT '. (int) $limit;
2487  $resql = $db->query($sql);
2488  if ($resql) {
2489  if ($showempty) {
2490  $out .= '<option value="-1"';
2491  if (empty($selected)) $out .= ' selected';
2492  $out .= '>&nbsp;</option>';
2493  }
2494  while ($obj = $db->fetch_object($resql)) {
2495  $product = new Product($db);
2496  $res = $product->fetch($obj->fk_product);
2497  $out .= '<option value="'.$obj->rowid.'"';
2498  if ($obj->rowid == $selected) $out .= 'selected';
2499  $out .= '>'.$obj->ref.' - '.$product->label .' - '. $obj->label.'</option>';
2500  }
2501  } else {
2502  $error++;
2503  dol_print_error($db);
2504  }
2505  if (empty($nooutput)) {
2506  print $out;
2507  } else {
2508  return $out;
2509  }
2510  }
2511 
2512  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2538  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)
2539  {
2540  // phpcs:enable
2541  global $langs, $conf;
2542  global $hookmanager;
2543 
2544  $out = '';
2545  $outarray = array();
2546 
2547  // Units
2548  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2549  $langs->load('other');
2550  }
2551 
2552  $warehouseStatusArray = array();
2553  if (!empty($warehouseStatus)) {
2554  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2555  if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2556  $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2557  }
2558  if (preg_match('/warehouseopen/', $warehouseStatus)) {
2559  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2560  }
2561  if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2562  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2563  }
2564  }
2565 
2566  $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";
2567  if (count($warehouseStatusArray)) {
2568  $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
2569  } else {
2570  $selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2571  }
2572 
2573  $sql = "SELECT ";
2574  $sql .= $selectFields.$selectFieldsGrouped;
2575 
2576  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2577  //Product category
2578  $sql .= ", (SELECT ".$this->db->prefix()."categorie_product.fk_categorie
2579  FROM ".$this->db->prefix()."categorie_product
2580  WHERE ".$this->db->prefix()."categorie_product.fk_product=p.rowid
2581  LIMIT 1
2582  ) AS categorie_product_id ";
2583  }
2584 
2585  //Price by customer
2586  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2587  $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2588  $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';
2589  $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2590  }
2591  // Units
2592  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2593  $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";
2594  $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';
2595  }
2596 
2597  // Multilang : we add translation
2598  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2599  $sql .= ", pl.label as label_translated";
2600  $sql .= ", pl.description as description_translated";
2601  $selectFields .= ", label_translated";
2602  $selectFields .= ", description_translated";
2603  }
2604  // Price by quantity
2605  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2606  $sql .= ", (SELECT pp.rowid FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid";
2607  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2608  $sql .= " AND price_level = ".((int) $price_level);
2609  }
2610  $sql .= " ORDER BY date_price";
2611  $sql .= " DESC LIMIT 1) as price_rowid";
2612  $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
2613  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2614  $sql .= " AND price_level = ".((int) $price_level);
2615  }
2616  $sql .= " ORDER BY date_price";
2617  $sql .= " DESC LIMIT 1) as price_by_qty";
2618  $selectFields .= ", price_rowid, price_by_qty";
2619  }
2620  $sql .= " FROM ".$this->db->prefix()."product as p";
2621  if (count($warehouseStatusArray)) {
2622  $sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_product = p.rowid";
2623  $sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2624  $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.
2625  }
2626 
2627  // include search in supplier ref
2628  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2629  $sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2630  }
2631 
2632  //Price by customer
2633  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2634  $sql .= " LEFT JOIN ".$this->db->prefix()."product_customer_price as pcp ON pcp.fk_soc=".((int) $socid)." AND pcp.fk_product=p.rowid";
2635  }
2636  // Units
2637  if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2638  $sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
2639  }
2640  // Multilang : we add translation
2641  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2642  $sql .= " LEFT JOIN ".$this->db->prefix()."product_lang as pl ON pl.fk_product = p.rowid ";
2643  if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2644  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
2645  $soc = new Societe($this->db);
2646  $result = $soc->fetch($socid);
2647  if ($result > 0 && !empty($soc->default_lang)) {
2648  $sql .= " AND pl.lang = '".$this->db->escape($soc->default_lang)."'";
2649  } else {
2650  $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2651  }
2652  } else {
2653  $sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2654  }
2655  }
2656 
2657  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2658  $sql .= " LEFT JOIN ".$this->db->prefix()."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2659  }
2660 
2661  $sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2662 
2663  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2664  $sql .= " AND pac.rowid IS NULL";
2665  }
2666 
2667  if ($finished == 0) {
2668  $sql .= " AND p.finished = ".((int) $finished);
2669  } elseif ($finished == 1) {
2670  $sql .= " AND p.finished = ".((int) $finished);
2671  if ($status >= 0) {
2672  $sql .= " AND p.tosell = ".((int) $status);
2673  }
2674  } elseif ($status >= 0) {
2675  $sql .= " AND p.tosell = ".((int) $status);
2676  }
2677  if ($status_purchase >= 0) {
2678  $sql .= " AND p.tobuy = ".((int) $status_purchase);
2679  }
2680  // Filter by product type
2681  if (strval($filtertype) != '') {
2682  $sql .= " AND p.fk_product_type = ".((int) $filtertype);
2683  } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
2684  $sql .= " AND p.fk_product_type = 1";
2685  } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2686  $sql .= " AND p.fk_product_type = 0";
2687  }
2688  // Add where from hooks
2689  $parameters = array();
2690  $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2691  $sql .= $hookmanager->resPrint;
2692  // Add criteria on ref/label
2693  if ($filterkey != '') {
2694  $sql .= ' AND (';
2695  $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2696  // For natural search
2697  $scrit = explode(' ', $filterkey);
2698  $i = 0;
2699  if (count($scrit) > 1) {
2700  $sql .= "(";
2701  }
2702  foreach ($scrit as $crit) {
2703  if ($i > 0) {
2704  $sql .= " AND ";
2705  }
2706  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2707  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2708  $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2709  }
2710  if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2711  $sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'";
2712  }
2713  if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2714  $sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2715  if (getDolGlobalInt('MAIN_MULTILANGS')) {
2716  $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2717  }
2718  }
2719  if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2720  $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2721  }
2722  $sql .= ")";
2723  $i++;
2724  }
2725  if (count($scrit) > 1) {
2726  $sql .= ")";
2727  }
2728  if (isModEnabled('barcode')) {
2729  $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2730  }
2731  $sql .= ')';
2732  }
2733  if (count($warehouseStatusArray)) {
2734  $sql .= " GROUP BY ".$selectFields;
2735  }
2736 
2737  //Sort by category
2738  if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2739  $sql .= " ORDER BY categorie_product_id ";
2740  //ASC OR DESC order
2741  ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2742  } else {
2743  $sql .= $this->db->order("p.ref");
2744  }
2745 
2746  $sql .= $this->db->plimit($limit, 0);
2747 
2748  // Build output string
2749  dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2750  $result = $this->db->query($sql);
2751  if ($result) {
2752  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2753  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2754  require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2755 
2756  $num = $this->db->num_rows($result);
2757 
2758  $events = null;
2759 
2760  if (!$forcecombo) {
2761  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2762  $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2763  }
2764 
2765  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2766 
2767  $textifempty = '';
2768  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2769  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2770  if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2771  if ($showempty && !is_numeric($showempty)) {
2772  $textifempty = $langs->trans($showempty);
2773  } else {
2774  $textifempty .= $langs->trans("All");
2775  }
2776  } else {
2777  if ($showempty && !is_numeric($showempty)) {
2778  $textifempty = $langs->trans($showempty);
2779  }
2780  }
2781  if ($showempty) {
2782  $out .= '<option value="-1" selected>'.($textifempty ? $textifempty : '&nbsp;').'</option>';
2783  }
2784 
2785  $i = 0;
2786  while ($num && $i < $num) {
2787  $opt = '';
2788  $optJson = array();
2789  $objp = $this->db->fetch_object($result);
2790 
2791  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
2792  $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2793  $sql .= " FROM ".$this->db->prefix()."product_price_by_qty";
2794  $sql .= " WHERE fk_product_price = ".((int) $objp->price_rowid);
2795  $sql .= " ORDER BY quantity ASC";
2796 
2797  dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2798  $result2 = $this->db->query($sql);
2799  if ($result2) {
2800  $nb_prices = $this->db->num_rows($result2);
2801  $j = 0;
2802  while ($nb_prices && $j < $nb_prices) {
2803  $objp2 = $this->db->fetch_object($result2);
2804 
2805  $objp->price_by_qty_rowid = $objp2->rowid;
2806  $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2807  $objp->price_by_qty_quantity = $objp2->quantity;
2808  $objp->price_by_qty_unitprice = $objp2->unitprice;
2809  $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2810  // For backward compatibility
2811  $objp->quantity = $objp2->quantity;
2812  $objp->price = $objp2->price;
2813  $objp->unitprice = $objp2->unitprice;
2814  $objp->remise_percent = $objp2->remise_percent;
2815 
2816  //$objp->tva_tx is not overwritten by $objp2 value
2817  //$objp->default_vat_code is not overwritten by $objp2 value
2818 
2819  $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2820 
2821  $j++;
2822 
2823  // Add new entry
2824  // "key" value of json key array is used by jQuery automatically as selected value
2825  // "label" value of json key array is used by jQuery automatically as text for combo box
2826  $out .= $opt;
2827  array_push($outarray, $optJson);
2828  }
2829  }
2830  } else {
2831  if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
2832  $price_product = new Product($this->db);
2833  $price_product->fetch($objp->rowid, '', '', 1);
2834 
2835  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2836  $priceparser = new PriceParser($this->db);
2837  $price_result = $priceparser->parseProduct($price_product);
2838  if ($price_result >= 0) {
2839  $objp->price = $price_result;
2840  $objp->unitprice = $price_result;
2841  //Calculate the VAT
2842  $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2843  $objp->price_ttc = price2num($objp->price_ttc, 'MU');
2844  }
2845  }
2846 
2847  $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2848  // Add new entry
2849  // "key" value of json key array is used by jQuery automatically as selected value
2850  // "label" value of json key array is used by jQuery automatically as text for combo box
2851  $out .= $opt;
2852  array_push($outarray, $optJson);
2853  }
2854 
2855  $i++;
2856  }
2857 
2858  $out .= '</select>';
2859 
2860  $this->db->free($result);
2861 
2862  if (empty($outputmode)) {
2863  return $out;
2864  }
2865 
2866  return $outarray;
2867  } else {
2868  dol_print_error($this->db);
2869  }
2870 
2871  return '';
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 (getDolGlobalInt('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 (getDolGlobalInt('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 (getDolGlobalInt('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 (getDolGlobalInt('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 (getDolGlobalInt('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  return '';
3783  }
3784  }
3785 
3786  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3796  public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3797  {
3798  // phpcs:enable
3799  // looking for users
3800  $sql = "SELECT a.rowid, a.label";
3801  $sql .= " FROM ".$this->db->prefix()."societe_address as a";
3802  $sql .= " WHERE a.fk_soc = ".((int) $socid);
3803  $sql .= " ORDER BY a.label ASC";
3804 
3805  dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3806  $resql = $this->db->query($sql);
3807  if ($resql) {
3808  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3809  if ($showempty) {
3810  print '<option value="0">&nbsp;</option>';
3811  }
3812  $num = $this->db->num_rows($resql);
3813  $i = 0;
3814  if ($num) {
3815  while ($i < $num) {
3816  $obj = $this->db->fetch_object($resql);
3817 
3818  if ($selected && $selected == $obj->rowid) {
3819  print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3820  } else {
3821  print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3822  }
3823  $i++;
3824  }
3825  }
3826  print '</select>';
3827  return $num;
3828  } else {
3829  dol_print_error($this->db);
3830  return -1;
3831  }
3832  }
3833 
3834  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3841  {
3842  // phpcs:enable
3843  global $langs;
3844 
3845  $num = count($this->cache_conditions_paiements);
3846  if ($num > 0) {
3847  return 0; // Cache already loaded
3848  }
3849 
3850  dol_syslog(__METHOD__, LOG_DEBUG);
3851 
3852  $sql = "SELECT rowid, code, libelle as label, deposit_percent";
3853  $sql .= " FROM ".$this->db->prefix().'c_payment_term';
3854  $sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3855  $sql .= " AND active > 0";
3856  $sql .= " ORDER BY sortorder";
3857 
3858  $resql = $this->db->query($sql);
3859  if ($resql) {
3860  $num = $this->db->num_rows($resql);
3861  $i = 0;
3862  while ($i < $num) {
3863  $obj = $this->db->fetch_object($resql);
3864 
3865  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3866  $label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3867  $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3868  $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3869  $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
3870  $i++;
3871  }
3872 
3873  //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
3874 
3875  return $num;
3876  } else {
3877  dol_print_error($this->db);
3878  return -1;
3879  }
3880  }
3881 
3882  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3888  public function load_cache_availability()
3889  {
3890  // phpcs:enable
3891  global $langs;
3892 
3893  $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
3894  if ($num > 0) {
3895  return 0; // Cache already loaded
3896  }
3897 
3898  dol_syslog(__METHOD__, LOG_DEBUG);
3899 
3900  $langs->load('propal');
3901 
3902  $sql = "SELECT rowid, code, label, position";
3903  $sql .= " FROM ".$this->db->prefix().'c_availability';
3904  $sql .= " WHERE active > 0";
3905 
3906  $resql = $this->db->query($sql);
3907  if ($resql) {
3908  $num = $this->db->num_rows($resql);
3909  $i = 0;
3910  while ($i < $num) {
3911  $obj = $this->db->fetch_object($resql);
3912 
3913  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3914  $label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3915  $this->cache_availability[$obj->rowid]['code'] = $obj->code;
3916  $this->cache_availability[$obj->rowid]['label'] = $label;
3917  $this->cache_availability[$obj->rowid]['position'] = $obj->position;
3918  $i++;
3919  }
3920 
3921  $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
3922 
3923  return $num;
3924  } else {
3925  dol_print_error($this->db);
3926  return -1;
3927  }
3928  }
3929 
3940  public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
3941  {
3942  global $langs, $user;
3943 
3944  $this->load_cache_availability();
3945 
3946  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3947 
3948  print '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3949  if ($addempty) {
3950  print '<option value="0">&nbsp;</option>';
3951  }
3952  foreach ($this->cache_availability as $id => $arrayavailability) {
3953  if ($selected == $id) {
3954  print '<option value="'.$id.'" selected>';
3955  } else {
3956  print '<option value="'.$id.'">';
3957  }
3958  print dol_escape_htmltag($arrayavailability['label']);
3959  print '</option>';
3960  }
3961  print '</select>';
3962  if ($user->admin) {
3963  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3964  }
3965  print ajax_combobox($htmlname);
3966  }
3967 
3973  public function loadCacheInputReason()
3974  {
3975  global $langs;
3976 
3977  $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
3978  if ($num > 0) {
3979  return 0; // Cache already loaded
3980  }
3981 
3982  $sql = "SELECT rowid, code, label";
3983  $sql .= " FROM ".$this->db->prefix().'c_input_reason';
3984  $sql .= " WHERE active > 0";
3985 
3986  $resql = $this->db->query($sql);
3987  if ($resql) {
3988  $num = $this->db->num_rows($resql);
3989  $i = 0;
3990  $tmparray = array();
3991  while ($i < $num) {
3992  $obj = $this->db->fetch_object($resql);
3993 
3994  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3995  $label = ($obj->label != '-' ? $obj->label : '');
3996  if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) {
3997  $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3998  }
3999  if ($langs->trans($obj->code) != $obj->code) {
4000  $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4001  }
4002 
4003  $tmparray[$obj->rowid]['id'] = $obj->rowid;
4004  $tmparray[$obj->rowid]['code'] = $obj->code;
4005  $tmparray[$obj->rowid]['label'] = $label;
4006  $i++;
4007  }
4008 
4009  $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4010 
4011  unset($tmparray);
4012  return $num;
4013  } else {
4014  dol_print_error($this->db);
4015  return -1;
4016  }
4017  }
4018 
4031  public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4032  {
4033  global $langs, $user;
4034 
4035  $this->loadCacheInputReason();
4036 
4037  print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4038  if ($addempty) {
4039  print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
4040  }
4041  foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4042  if ($arraydemandreason['code'] == $exclude) {
4043  continue;
4044  }
4045 
4046  if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4047  print '<option value="'.$arraydemandreason['id'].'" selected>';
4048  } else {
4049  print '<option value="'.$arraydemandreason['id'].'">';
4050  }
4051  $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4052  print $langs->trans($label);
4053  print '</option>';
4054  }
4055  print '</select>';
4056  if ($user->admin && empty($notooltip)) {
4057  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4058  }
4059  print ajax_combobox('select_'.$htmlname);
4060  }
4061 
4062  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4068  public function load_cache_types_paiements()
4069  {
4070  // phpcs:enable
4071  global $langs;
4072 
4073  $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4074  if ($num > 0) {
4075  return $num; // Cache already loaded
4076  }
4077 
4078  dol_syslog(__METHOD__, LOG_DEBUG);
4079 
4080  $this->cache_types_paiements = array();
4081 
4082  $sql = "SELECT id, code, libelle as label, type, active";
4083  $sql .= " FROM ".$this->db->prefix()."c_paiement";
4084  $sql .= " WHERE entity IN (".getEntity('c_paiement').")";
4085 
4086  $resql = $this->db->query($sql);
4087  if ($resql) {
4088  $num = $this->db->num_rows($resql);
4089  $i = 0;
4090  while ($i < $num) {
4091  $obj = $this->db->fetch_object($resql);
4092 
4093  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
4094  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4095  $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4096  $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4097  $this->cache_types_paiements[$obj->id]['label'] = $label;
4098  $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4099  $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4100  $i++;
4101  }
4102 
4103  $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4104 
4105  return $num;
4106  } else {
4107  dol_print_error($this->db);
4108  return -1;
4109  }
4110  }
4111 
4112 
4113  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4131  public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4132  {
4133  // phpcs:enable
4134  print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent = -1);
4135  }
4136 
4137 
4154  public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4155  {
4156  global $langs, $user, $conf;
4157 
4158  $out = '';
4159  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
4160 
4162 
4163  // Set default value if not already set by caller
4164  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
4165  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4166  }
4167 
4168  $out.= '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4169  if ($addempty) {
4170  $out.= '<option value="0">&nbsp;</option>';
4171  }
4172 
4173  $selectedDepositPercent = null;
4174 
4175  foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4176  if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4177  continue;
4178  }
4179 
4180  if ($selected == $id) {
4181  $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4182  $out .= '<option value="'.$id.'" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4183  } else {
4184  $out .= '<option value="'.$id.'" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4185  }
4186  $label = $arrayconditions['label'];
4187 
4188  if (!empty($arrayconditions['deposit_percent'])) {
4189  $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4190  }
4191 
4192  $out.= $label;
4193  $out.= '</option>';
4194  }
4195  $out.= '</select>';
4196  if ($user->admin && empty($noinfoadmin)) {
4197  $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4198  }
4199  $out.= ajax_combobox($htmlname);
4200 
4201  if ($deposit_percent >= 0) {
4202  $out .= ' <span id="'.$htmlname.'_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4203  $out .= $langs->trans('DepositPercent') . ' : ';
4204  $out .= '<input id="'.$htmlname.'_deposit_percent" name="'.$htmlname.'_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4205  $out .= '</span>';
4206  $out .= '
4207  <script>
4208  $(document).ready(function () {
4209  $("#' . $htmlname . '").change(function () {
4210  let $selected = $(this).find("option:selected");
4211  let depositPercent = $selected.attr("data-deposit_percent");
4212 
4213  if (depositPercent.length > 0) {
4214  $("#'.$htmlname.'_deposit_percent_container").show().find("#'.$htmlname.'_deposit_percent").val(depositPercent);
4215  } else {
4216  $("#'.$htmlname.'_deposit_percent_container").hide();
4217  }
4218 
4219  return true;
4220  });
4221  });
4222  </script>';
4223  }
4224 
4225  return $out;
4226  }
4227 
4228 
4229  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4246  public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4247  {
4248  // phpcs:enable
4249  global $langs, $user, $conf;
4250 
4251  $out = '';
4252 
4253  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
4254 
4255  $filterarray = array();
4256  if ($filtertype == 'CRDT') {
4257  $filterarray = array(0, 2, 3);
4258  } elseif ($filtertype == 'DBIT') {
4259  $filterarray = array(1, 2, 3);
4260  } elseif ($filtertype != '' && $filtertype != '-1') {
4261  $filterarray = explode(',', $filtertype);
4262  }
4263 
4264  $this->load_cache_types_paiements();
4265 
4266  // Set default value if not already set by caller
4267  if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
4268  $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4269  }
4270 
4271  $out .= '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4272  if ($empty) {
4273  $out .= '<option value="">&nbsp;</option>';
4274  }
4275  foreach ($this->cache_types_paiements as $id => $arraytypes) {
4276  // If not good status
4277  if ($active >= 0 && $arraytypes['active'] != $active) {
4278  continue;
4279  }
4280 
4281  // On passe si on a demande de filtrer sur des modes de paiments particuliers
4282  if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4283  continue;
4284  }
4285 
4286  // We discard empty line if showempty is on because an empty line has already been output.
4287  if ($empty && empty($arraytypes['code'])) {
4288  continue;
4289  }
4290 
4291  if ($format == 0) {
4292  $out .= '<option value="'.$id.'"';
4293  } elseif ($format == 1) {
4294  $out .= '<option value="'.$arraytypes['code'].'"';
4295  } elseif ($format == 2) {
4296  $out .= '<option value="'.$arraytypes['code'].'"';
4297  } elseif ($format == 3) {
4298  $out .= '<option value="'.$id.'"';
4299  }
4300  // Print attribute selected or not
4301  if ($format == 1 || $format == 2) {
4302  if ($selected == $arraytypes['code']) {
4303  $out .= ' selected';
4304  }
4305  } else {
4306  if ($selected == $id) {
4307  $out .= ' selected';
4308  }
4309  }
4310  $out .= '>';
4311  $value = '';
4312  if ($format == 0) {
4313  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4314  } elseif ($format == 1) {
4315  $value = $arraytypes['code'];
4316  } elseif ($format == 2) {
4317  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4318  } elseif ($format == 3) {
4319  $value = $arraytypes['code'];
4320  }
4321  $out .= $value ? $value : '&nbsp;';
4322  $out .= '</option>';
4323  }
4324  $out .= '</select>';
4325  if ($user->admin && !$noadmininfo) {
4326  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4327  }
4328  $out .= ajax_combobox('select'.$htmlname);
4329 
4330  if (empty($nooutput)) {
4331  print $out;
4332  } else {
4333  return $out;
4334  }
4335  }
4336 
4337 
4346  public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4347  {
4348  global $langs;
4349 
4350  $return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4351  $options = array(
4352  'HT'=>$langs->trans("HT"),
4353  'TTC'=>$langs->trans("TTC")
4354  );
4355  foreach ($options as $id => $value) {
4356  if ($selected == $id) {
4357  $return .= '<option value="'.$id.'" selected>'.$value;
4358  } else {
4359  $return .= '<option value="'.$id.'">'.$value;
4360  }
4361  $return .= '</option>';
4362  }
4363  $return .= '</select>';
4364  if ($addjscombo) {
4365  $return .= ajax_combobox('select_'.$htmlname);
4366  }
4367 
4368  return $return;
4369  }
4370 
4371  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4377  public function load_cache_transport_mode()
4378  {
4379  // phpcs:enable
4380  global $langs;
4381 
4382  $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4383  if ($num > 0) {
4384  return $num; // Cache already loaded
4385  }
4386 
4387  dol_syslog(__METHOD__, LOG_DEBUG);
4388 
4389  $this->cache_transport_mode = array();
4390 
4391  $sql = "SELECT rowid, code, label, active";
4392  $sql .= " FROM ".$this->db->prefix()."c_transport_mode";
4393  $sql .= " WHERE entity IN (".getEntity('c_transport_mode').")";
4394 
4395  $resql = $this->db->query($sql);
4396  if ($resql) {
4397  $num = $this->db->num_rows($resql);
4398  $i = 0;
4399  while ($i < $num) {
4400  $obj = $this->db->fetch_object($resql);
4401 
4402  // If traduction exist, we use it else we take the default label
4403  $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4404  $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4405  $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4406  $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4407  $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4408  $i++;
4409  }
4410 
4411  $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4412 
4413  return $num;
4414  } else {
4415  dol_print_error($this->db);
4416  return -1;
4417  }
4418  }
4419 
4433  public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4434  {
4435  global $langs, $user;
4436 
4437  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
4438 
4439  $this->load_cache_transport_mode();
4440 
4441  print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4442  if ($empty) {
4443  print '<option value="">&nbsp;</option>';
4444  }
4445  foreach ($this->cache_transport_mode as $id => $arraytypes) {
4446  // If not good status
4447  if ($active >= 0 && $arraytypes['active'] != $active) {
4448  continue;
4449  }
4450 
4451  // We discard empty line if showempty is on because an empty line has already been output.
4452  if ($empty && empty($arraytypes['code'])) {
4453  continue;
4454  }
4455 
4456  if ($format == 0) {
4457  print '<option value="'.$id.'"';
4458  } elseif ($format == 1) {
4459  print '<option value="'.$arraytypes['code'].'"';
4460  } elseif ($format == 2) {
4461  print '<option value="'.$arraytypes['code'].'"';
4462  } elseif ($format == 3) {
4463  print '<option value="'.$id.'"';
4464  }
4465  // If text is selected, we compare with code, else with id
4466  if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4467  print ' selected';
4468  } elseif ($selected == $id) {
4469  print ' selected';
4470  }
4471  print '>';
4472  $value = '';
4473  if ($format == 0) {
4474  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4475  } elseif ($format == 1) {
4476  $value = $arraytypes['code'];
4477  } elseif ($format == 2) {
4478  $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4479  } elseif ($format == 3) {
4480  $value = $arraytypes['code'];
4481  }
4482  print $value ? $value : '&nbsp;';
4483  print '</option>';
4484  }
4485  print '</select>';
4486  if ($user->admin && !$noadmininfo) {
4487  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4488  }
4489  }
4490 
4503  public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4504  {
4505  global $langs, $conf, $user;
4506 
4507  $langs->load("admin");
4508  $langs->load("deliveries");
4509 
4510  $sql = "SELECT rowid, code, libelle as label";
4511  $sql .= " FROM ".$this->db->prefix()."c_shipment_mode";
4512  $sql .= " WHERE active > 0";
4513  if ($filtre) {
4514  $sql .= " AND ".$filtre;
4515  }
4516  $sql .= " ORDER BY libelle ASC";
4517 
4518  dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
4519  $result = $this->db->query($sql);
4520  if ($result) {
4521  $num = $this->db->num_rows($result);
4522  $i = 0;
4523  if ($num) {
4524  print '<select id="select'.$htmlname.'" class="flat selectshippingmethod'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4525  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4526  print '<option value="-1">&nbsp;</option>';
4527  }
4528  while ($i < $num) {
4529  $obj = $this->db->fetch_object($result);
4530  if ($selected == $obj->rowid) {
4531  print '<option value="'.$obj->rowid.'" selected>';
4532  } else {
4533  print '<option value="'.$obj->rowid.'">';
4534  }
4535  print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
4536  print '</option>';
4537  $i++;
4538  }
4539  print "</select>";
4540  if ($user->admin && empty($noinfoadmin)) {
4541  print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4542  }
4543 
4544  print ajax_combobox('select'.$htmlname);
4545  } else {
4546  print $langs->trans("NoShippingMethodDefined");
4547  }
4548  } else {
4549  dol_print_error($this->db);
4550  }
4551  }
4552 
4562  public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4563  {
4564  global $langs;
4565 
4566  $langs->load("deliveries");
4567 
4568  if ($htmlname != "none") {
4569  print '<form method="POST" action="'.$page.'">';
4570  print '<input type="hidden" name="action" value="setshippingmethod">';
4571  print '<input type="hidden" name="token" value="'.newToken().'">';
4572  $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4573  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4574  print '</form>';
4575  } else {
4576  if ($selected) {
4577  $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4578  print $langs->trans("SendingMethod".strtoupper($code));
4579  } else {
4580  print "&nbsp;";
4581  }
4582  }
4583  }
4584 
4593  public function selectSituationInvoices($selected = '', $socid = 0)
4594  {
4595  global $langs;
4596 
4597  $langs->load('bills');
4598 
4599  $opt = '<option value="" selected></option>';
4600  $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4601  $sql .= ' FROM '.$this->db->prefix().'facture';
4602  $sql .= ' WHERE entity IN ('.getEntity('invoice').')';
4603  $sql .= ' AND situation_counter >= 1';
4604  $sql .= ' AND fk_soc = '.(int) $socid;
4605  $sql .= ' AND type <> 2';
4606  $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4607  $resql = $this->db->query($sql);
4608 
4609  if ($resql && $this->db->num_rows($resql) > 0) {
4610  // Last seen cycle
4611  $ref = 0;
4612  while ($obj = $this->db->fetch_object($resql)) {
4613  //Same cycle ?
4614  if ($obj->situation_cycle_ref != $ref) {
4615  // Just seen this cycle
4616  $ref = $obj->situation_cycle_ref;
4617  //not final ?
4618  if ($obj->situation_final != 1) {
4619  //Not prov?
4620  if (substr($obj->ref, 1, 4) != 'PROV') {
4621  if ($selected == $obj->rowid) {
4622  $opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
4623  } else {
4624  $opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
4625  }
4626  }
4627  }
4628  }
4629  }
4630  } else {
4631  dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
4632  }
4633  if ($opt == '<option value ="" selected></option>') {
4634  $opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
4635  }
4636  return $opt;
4637  }
4638 
4648  public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4649  {
4650  global $langs;
4651 
4652  $langs->load('products');
4653 
4654  $return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
4655 
4656  $sql = "SELECT rowid, label, code FROM ".$this->db->prefix()."c_units";
4657  $sql .= ' WHERE active > 0';
4658  if (!empty($unit_type)) {
4659  $sql .= " AND unit_type = '".$this->db->escape($unit_type)."'";
4660  }
4661  $sql .= " ORDER BY sortorder";
4662 
4663  $resql = $this->db->query($sql);
4664  if ($resql && $this->db->num_rows($resql) > 0) {
4665  if ($showempty) {
4666  $return .= '<option value="none"></option>';
4667  }
4668 
4669  while ($res = $this->db->fetch_object($resql)) {
4670  $unitLabel = $res->label;
4671  if (!empty($langs->tab_translate['unit'.$res->code])) { // check if Translation is available before
4672  $unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
4673  }
4674 
4675  if ($selected == $res->rowid) {
4676  $return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
4677  } else {
4678  $return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
4679  }
4680  }
4681  $return .= '</select>';
4682  }
4683  return $return;
4684  }
4685 
4686  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4701  public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4702  {
4703  // phpcs:enable
4704  global $langs, $conf;
4705 
4706  $out = '';
4707 
4708  $langs->load("admin");
4709  $num = 0;
4710 
4711  $sql = "SELECT rowid, label, bank, clos as status, currency_code";
4712  $sql .= " FROM ".$this->db->prefix()."bank_account";
4713  $sql .= " WHERE entity IN (".getEntity('bank_account').")";
4714  if ($status != 2) {
4715  $sql .= " AND clos = ".(int) $status;
4716  }
4717  if ($filtre) {
4718  $sql .= " AND ".$filtre;
4719  }
4720  $sql .= " ORDER BY label";
4721 
4722  dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
4723  $result = $this->db->query($sql);
4724  if ($result) {
4725  $num = $this->db->num_rows($result);
4726  $i = 0;
4727  if ($num) {
4728  $out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4729  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4730  $out .= '<option value="-1">&nbsp;</option>';
4731  }
4732 
4733  while ($i < $num) {
4734  $obj = $this->db->fetch_object($result);
4735  if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4736  $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'" selected>';
4737  } else {
4738  $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'">';
4739  }
4740  $out .= trim($obj->label);
4741  if ($showcurrency) {
4742  $out .= ' ('.$obj->currency_code.')';
4743  }
4744  if ($status == 2 && $obj->status == 1) {
4745  $out .= ' ('.$langs->trans("Closed").')';
4746  }
4747  $out .= '</option>';
4748  $i++;
4749  }
4750  $out .= "</select>";
4751  $out .= ajax_combobox('select'.$htmlname);
4752  } else {
4753  if ($status == 0) {
4754  $out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
4755  } else {
4756  $out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
4757  }
4758  }
4759  } else {
4760  dol_print_error($this->db);
4761  }
4762 
4763  // Output or return
4764  if (empty($nooutput)) {
4765  print $out;
4766  } else {
4767  return $out;
4768  }
4769 
4770  return $num;
4771  }
4772 
4784  public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4785  {
4786  global $langs, $conf;
4787 
4788  $langs->load("admin");
4789  $num = 0;
4790 
4791  $sql = "SELECT rowid, name, fk_country, status, entity";
4792  $sql .= " FROM ".$this->db->prefix()."establishment";
4793  $sql .= " WHERE 1=1";
4794  if ($status != 2) {
4795  $sql .= " AND status = ".(int) $status;
4796  }
4797  if ($filtre) {
4798  $sql .= " AND ".$filtre;
4799  }
4800  $sql .= " ORDER BY name";
4801 
4802  dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
4803  $result = $this->db->query($sql);
4804  if ($result) {
4805  $num = $this->db->num_rows($result);
4806  $i = 0;
4807  if ($num) {
4808  print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4809  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4810  print '<option value="-1">&nbsp;</option>';
4811  }
4812 
4813  while ($i < $num) {
4814  $obj = $this->db->fetch_object($result);
4815  if ($selected == $obj->rowid) {
4816  print '<option value="'.$obj->rowid.'" selected>';
4817  } else {
4818  print '<option value="'.$obj->rowid.'">';
4819  }
4820  print trim($obj->name);
4821  if ($status == 2 && $obj->status == 1) {
4822  print ' ('.$langs->trans("Closed").')';
4823  }
4824  print '</option>';
4825  $i++;
4826  }
4827  print "</select>";
4828  } else {
4829  if ($status == 0) {
4830  print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
4831  } else {
4832  print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
4833  }
4834  }
4835  } else {
4836  dol_print_error($this->db);
4837  return -1;
4838  }
4839  }
4840 
4850  public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4851  {
4852  global $langs;
4853  if ($htmlname != "none") {
4854  print '<form method="POST" action="'.$page.'">';
4855  print '<input type="hidden" name="action" value="setbankaccount">';
4856  print '<input type="hidden" name="token" value="'.newToken().'">';
4857  print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4858  $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4859  if ($nbaccountfound > 0) {
4860  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
4861  }
4862  print '</form>';
4863  } else {
4864  $langs->load('banks');
4865 
4866  if ($selected) {
4867  require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
4868  $bankstatic = new Account($this->db);
4869  $result = $bankstatic->fetch($selected);
4870  if ($result) {
4871  print $bankstatic->getNomUrl(1);
4872  }
4873  } else {
4874  print "&nbsp;";
4875  }
4876  }
4877  }
4878 
4879  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4898  public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4899  {
4900  // phpcs:enable
4901  global $conf, $langs;
4902  $langs->load("categories");
4903 
4904  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4905 
4906  // For backward compatibility
4907  if (is_numeric($type)) {
4908  dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4909  }
4910 
4911  if ($type === Categorie::TYPE_BANK_LINE) {
4912  // TODO Move this into common category feature
4913  $cate_arbo = array();
4914  $sql = "SELECT c.label, c.rowid";
4915  $sql .= " FROM ".$this->db->prefix()."bank_categ as c";
4916  $sql .= " WHERE entity = ".$conf->entity;
4917  $sql .= " ORDER BY c.label";
4918  $result = $this->db->query($sql);
4919  if ($result) {
4920  $num = $this->db->num_rows($result);
4921  $i = 0;
4922  while ($i < $num) {
4923  $objp = $this->db->fetch_object($result);
4924  if ($objp) {
4925  $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label, 'color'=>'', 'picto'=>'category');
4926  }
4927  $i++;
4928  }
4929  $this->db->free($result);
4930  } else {
4931  dol_print_error($this->db);
4932  }
4933  } else {
4934  $cat = new Categorie($this->db);
4935  $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4936  }
4937 
4938  $outarray = array();
4939 
4940  $output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4941  if (is_array($cate_arbo)) {
4942  if (!count($cate_arbo)) {
4943  $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4944  } else {
4945  $output .= '<option value="-1">&nbsp;</option>';
4946  foreach ($cate_arbo as $key => $value) {
4947  if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
4948  $add = 'selected ';
4949  } else {
4950  $add = '';
4951  }
4952  $output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'"';
4953  $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')).'"';
4954  $output .= '>';
4955  $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
4956  $output .= '</option>';
4957 
4958  $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4959  }
4960  }
4961  }
4962  $output .= '</select>';
4963  $output .= "\n";
4964 
4965  if ($outputmode == 2) {
4966  return $cate_arbo;
4967  } elseif ($outputmode) {
4968  return $outarray;
4969  }
4970  return $output;
4971  }
4972 
4973  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4990  public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4991  {
4992  // phpcs:enable
4993  dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4994  print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4995  }
4996 
5024  public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5025  {
5026  global $langs, $conf;
5027 
5028  $more = '<!-- formconfirm - before call, page='.dol_escape_htmltag($page).' -->';
5029  $formconfirm = '';
5030  $inputok = array();
5031  $inputko = array();
5032 
5033  // Clean parameters
5034  $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5035  if ($conf->browser->layout == 'phone') {
5036  $width = '95%';
5037  }
5038 
5039  // Set height automatically if not defined
5040  if (empty($height)) {
5041  $height = 220;
5042  if (is_array($formquestion) && count($formquestion) > 2) {
5043  $height += ((count($formquestion) - 2) * 24);
5044  }
5045  }
5046 
5047  if (is_array($formquestion) && !empty($formquestion)) {
5048  // First add hidden fields and value
5049  foreach ($formquestion as $key => $input) {
5050  if (is_array($input) && !empty($input)) {
5051  if ($input['type'] == 'hidden') {
5052  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
5053  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
5054 
5055  $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";
5056  }
5057  }
5058  }
5059 
5060  // Now add questions
5061  $moreonecolumn = '';
5062  $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
5063  foreach ($formquestion as $key => $input) {
5064  if (is_array($input) && !empty($input)) {
5065  $size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : ''); // deprecated. Use morecss instead.
5066  $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
5067  $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
5068 
5069  if ($input['type'] == 'text') {
5070  $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";
5071  } elseif ($input['type'] == 'password') {
5072  $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";
5073  } elseif ($input['type'] == 'textarea') {
5074  /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5075  $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5076  $more .= $input['value'];
5077  $more .= '</textarea>';
5078  $more .= '</div></div>'."\n";*/
5079  $moreonecolumn .= '<div class="margintoponly">';
5080  $moreonecolumn .= $input['label'].'<br>';
5081  $moreonecolumn .= '<textarea name="'.dol_escape_htmltag($input['name']).'" id="'.dol_escape_htmltag($input['name']).'" class="'.$morecss.'"'.$moreattr.'>';
5082  $moreonecolumn .= $input['value'];
5083  $moreonecolumn .= '</textarea>';
5084  $moreonecolumn .= '</div>';
5085  } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5086  if (empty($morecss)) {
5087  $morecss = 'minwidth100';
5088  }
5089 
5090  $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5091  $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5092  $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5093  $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5094  $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5095  $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5096  $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5097 
5098  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5099  if (!empty($input['label'])) {
5100  $more .= $input['label'].'</div><div class="tagtd left">';
5101  }
5102  if ($input['type'] == 'select') {
5103  $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);
5104  } else {
5105  $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);
5106  }
5107  $more .= '</div></div>'."\n";
5108  } elseif ($input['type'] == 'checkbox') {
5109  $more .= '<div class="tagtr">';
5110  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
5111  $more .= '<input type="checkbox" class="flat'.($morecss ? ' '.$morecss : '').'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$moreattr;
5112  if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5113  $more .= ' checked';
5114  }
5115  if (is_bool($input['value']) && $input['value']) {
5116  $more .= ' checked';
5117  }
5118  if (isset($input['disabled'])) {
5119  $more .= ' disabled';
5120  }
5121  $more .= ' /></div>';
5122  $more .= '</div>'."\n";
5123  } elseif ($input['type'] == 'radio') {
5124  $i = 0;
5125  foreach ($input['values'] as $selkey => $selval) {
5126  $more .= '<div class="tagtr">';
5127  if ($i == 0) {
5128  $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
5129  } else {
5130  $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
5131  }
5132  $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;
5133  if (!empty($input['disabled'])) {
5134  $more .= ' disabled';
5135  }
5136  if (isset($input['default']) && $input['default'] === $selkey) {
5137  $more .= ' checked="checked"';
5138  }
5139  $more .= ' /> ';
5140  $more .= '<label for="'.dol_escape_htmltag($input['name'].$selkey).'" class="valignmiddle">'.$selval.'</label>';
5141  $more .= '</div></div>'."\n";
5142  $i++;
5143  }
5144  } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5145  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
5146  $more .= '<div class="tagtd">';
5147  $addnowlink = (empty($input['datenow']) ? 0 : 1);
5148  $more .= $this->selectDate($input['value'], $input['name'], ($input['type'] == 'datetime' ? 1 : 0), ($input['type'] == 'datetime' ? 1 : 0), 0, '', 1, $addnowlink);
5149  $more .= '</div></div>'."\n";
5150  $formquestion[] = array('name'=>$input['name'].'day');
5151  $formquestion[] = array('name'=>$input['name'].'month');
5152  $formquestion[] = array('name'=>$input['name'].'year');
5153  $formquestion[] = array('name'=>$input['name'].'hour');
5154  $formquestion[] = array('name'=>$input['name'].'min');
5155  } elseif ($input['type'] == 'other') {
5156  $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5157  if (!empty($input['label'])) {
5158  $more .= $input['label'].'</div><div class="tagtd">';
5159  }
5160  $more .= $input['value'];
5161  $more .= '</div></div>'."\n";
5162  } elseif ($input['type'] == 'onecolumn') {
5163  $moreonecolumn .= '<div class="margintoponly">';
5164  $moreonecolumn .= $input['value'];
5165  $moreonecolumn .= '</div>'."\n";
5166  } elseif ($input['type'] == 'hidden') {
5167  // Do nothing more, already added by a previous loop
5168  } elseif ($input['type'] == 'separator') {
5169  $more .= '<br>';
5170  } else {
5171  $more .= 'Error type '.$input['type'].' for the confirm box is not a supported type';
5172  }
5173  }
5174  }
5175  $more .= '</div>'."\n";
5176  $more .= $moreonecolumn;
5177  }
5178 
5179  // JQUERY method dialog is broken with smartphone, we use standard HTML.
5180  // 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
5181  // See page product/card.php for example
5182  if (!empty($conf->dol_use_jmobile)) {
5183  $useajax = 0;
5184  }
5185  if (empty($conf->use_javascript_ajax)) {
5186  $useajax = 0;
5187  }
5188 
5189  if ($useajax) {
5190  $autoOpen = true;
5191  $dialogconfirm = 'dialog-confirm';
5192  $button = '';
5193  if (!is_numeric($useajax)) {
5194  $button = $useajax;
5195  $useajax = 1;
5196  $autoOpen = false;
5197  $dialogconfirm .= '-'.$button;
5198  }
5199  $pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.urlencode($action).'&confirm=yes';
5200  $pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.urlencode($action).'&confirm=no' : '');
5201 
5202  // Add input fields into list of fields to read during submit (inputok and inputko)
5203  if (is_array($formquestion)) {
5204  foreach ($formquestion as $key => $input) {
5205  //print "xx ".$key." rr ".is_array($input)."<br>\n";
5206  // Add name of fields to propagate with the GET when submitting the form with button OK.
5207  if (is_array($input) && isset($input['name'])) {
5208  if (strpos($input['name'], ',') > 0) {
5209  $inputok = array_merge($inputok, explode(',', $input['name']));
5210  } else {
5211  array_push($inputok, $input['name']);
5212  }
5213  }
5214  // Add name of fields to propagate with the GET when submitting the form with button KO.
5215  if (isset($input['inputko']) && $input['inputko'] == 1) {
5216  array_push($inputko, $input['name']);
5217  }
5218  }
5219  }
5220 
5221  // Show JQuery confirm box.
5222  $formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
5223  if (is_array($formquestion) && !empty($formquestion['text'])) {
5224  $formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
5225  }
5226  if (!empty($more)) {
5227  $formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
5228  }
5229  $formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
5230  $formconfirm .= '</div>'."\n";
5231 
5232  $formconfirm .= "\n<!-- begin code of popup for formconfirm page=".$page." -->\n";
5233  $formconfirm .= '<script type="text/javascript">'."\n";
5234  $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5235  $formconfirm .= 'jQuery(document).ready(function() {
5236  $(function() {
5237  $( "#'.$dialogconfirm.'" ).dialog(
5238  {
5239  autoOpen: '.($autoOpen ? "true" : "false").',';
5240  if ($newselectedchoice == 'no') {
5241  $formconfirm .= '
5242  open: function() {
5243  $(this).parent().find("button.ui-button:eq(2)").focus();
5244  },';
5245  }
5246 
5247  $jsforcursor = '';
5248  if ($useajax == 1) {
5249  $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor'."\n";
5250  $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");'."\n";
5251  }
5252 
5253  $postconfirmas = 'GET';
5254 
5255  $formconfirm .= '
5256  resizable: false,
5257  height: "'.$height.'",
5258  width: "'.$width.'",
5259  modal: true,
5260  closeOnEscape: false,
5261  buttons: {
5262  "'.dol_escape_js($langs->transnoentities($labelbuttonyes)).'": function() {
5263  var options = "token='.urlencode(newToken()).'";
5264  var inputok = '.json_encode($inputok).'; /* List of fields into form */
5265  var page = "'.dol_escape_js(!empty($page) ? $page : '').'";
5266  var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
5267 
5268  if (inputok.length > 0) {
5269  $.each(inputok, function(i, inputname) {
5270  var more = "";
5271  var inputvalue;
5272  if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5273  inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5274  } else {
5275  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5276  inputvalue = $("#" + inputname + more).val();
5277  }
5278  if (typeof inputvalue == "undefined") { inputvalue=""; }
5279  console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5280  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5281  });
5282  }
5283  var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5284  if (pageyes.length > 0) {';
5285  if ($postconfirmas == 'GET') {
5286  $formconfirm .= 'location.href = urljump;';
5287  } else {
5288  $formconfirm .= $jsforcursor;
5289  $formconfirm .= 'var post = $.post(
5290  pageyes,
5291  options,
5292  function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5293  );';
5294  }
5295  $formconfirm .= '
5296  console.log("after post ok");
5297  }
5298  $(this).dialog("close");
5299  },
5300  "'.dol_escape_js($langs->transnoentities($labelbuttonno)).'": function() {
5301  var options = "token='.urlencode(newToken()).'";
5302  var inputko = '.json_encode($inputko).'; /* List of fields into form */
5303  var page = "'.dol_escape_js(!empty($page) ? $page : '').'";
5304  var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
5305  if (inputko.length > 0) {
5306  $.each(inputko, function(i, inputname) {
5307  var more = "";
5308  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5309  var inputvalue = $("#" + inputname + more).val();
5310  if (typeof inputvalue == "undefined") { inputvalue=""; }
5311  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5312  });
5313  }
5314  var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5315  //alert(urljump);
5316  if (pageno.length > 0) {';
5317  if ($postconfirmas == 'GET') {
5318  $formconfirm .= 'location.href = urljump;';
5319  } else {
5320  $formconfirm .= $jsforcursor;
5321  $formconfirm .= 'var post = $.post(
5322  pageno,
5323  options,
5324  function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5325  );';
5326  }
5327  $formconfirm .= '
5328  console.log("after post ko");
5329  }
5330  $(this).dialog("close");
5331  }
5332  }
5333  }
5334  );
5335 
5336  var button = "'.$button.'";
5337  if (button.length > 0) {
5338  $( "#" + button ).click(function() {
5339  $("#'.$dialogconfirm.'").dialog("open");
5340  });
5341  }
5342  });
5343  });
5344  </script>';
5345  $formconfirm .= "<!-- end ajax formconfirm -->\n";
5346  } else {
5347  $formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n";
5348 
5349  if (empty($disableformtag)) {
5350  $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
5351  }
5352 
5353  $formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
5354  $formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
5355 
5356  $formconfirm .= '<table class="valid centpercent">'."\n";
5357 
5358  // Line title
5359  $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5360  $formconfirm .= img_picto('', 'recent').' '.$title;
5361  $formconfirm .= '</td></tr>'."\n";
5362 
5363  // Line text
5364  if (is_array($formquestion) && !empty($formquestion['text'])) {
5365  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
5366  }
5367 
5368  // Line form fields
5369  if ($more) {
5370  $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'."\n";
5371  $formconfirm .= $more;
5372  $formconfirm .= '</td></tr>'."\n";
5373  }
5374 
5375  // Line with question
5376  $formconfirm .= '<tr class="valid">';
5377  $formconfirm .= '<td class="valid">'.$question.'</td>';
5378  $formconfirm .= '<td class="valid center">';
5379  $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5380  $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="'.$langs->trans("Validate").'">';
5381  $formconfirm .= '</td>';
5382  $formconfirm .= '</tr>'."\n";
5383 
5384  $formconfirm .= '</table>'."\n";
5385 
5386  if (empty($disableformtag)) {
5387  $formconfirm .= "</form>\n";
5388  }
5389  $formconfirm .= '<br>';
5390 
5391  if (!empty($conf->use_javascript_ajax)) {
5392  $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5393  $formconfirm .= '<script type="text/javascript">'."\n";
5394  $formconfirm .= '
5395  $(document).ready(function () {
5396  $(".confirmvalidatebutton").on("click", function() {
5397  console.log("We click on button");
5398  $(this).attr("disabled", "disabled");
5399  setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5400  //console.log($(this).closest("form"));
5401  $(this).closest("form").submit();
5402  });
5403  });
5404  ';
5405  $formconfirm .= '</script>'."\n";
5406  }
5407 
5408  $formconfirm .= "<!-- end formconfirm -->\n";
5409  }
5410 
5411  return $formconfirm;
5412  }
5413 
5414 
5415  // 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 = '')
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);
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  return '';
5726  }
5727 
5738  public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5739  {
5740  global $langs;
5741  if ($htmlname != "none") {
5742  print '<form method="POST" action="'.$page.'">';
5743  print '<input type="hidden" name="action" value="settransportmode">';
5744  print '<input type="hidden" name="token" value="'.newToken().'">';
5745  $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5746  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5747  print '</form>';
5748  } else {
5749  if ($selected) {
5750  $this->load_cache_transport_mode();
5751  print $this->cache_transport_mode[$selected]['label'];
5752  } else {
5753  print "&nbsp;";
5754  }
5755  }
5756  }
5757 
5758  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5767  public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5768  {
5769  // phpcs:enable
5770  global $langs;
5771  if ($htmlname != "none") {
5772  print '<form method="POST" action="'.$page.'">';
5773  print '<input type="hidden" name="action" value="setmulticurrencycode">';
5774  print '<input type="hidden" name="token" value="'.newToken().'">';
5775  print $this->selectMultiCurrency($selected, $htmlname, 0);
5776  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5777  print '</form>';
5778  } else {
5779  dol_include_once('/core/lib/company.lib.php');
5780  print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5781  }
5782  }
5783 
5784  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5794  public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5795  {
5796  // phpcs:enable
5797  global $langs, $mysoc, $conf;
5798 
5799  if ($htmlname != "none") {
5800  print '<form method="POST" action="'.$page.'">';
5801  print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5802  print '<input type="hidden" name="token" value="'.newToken().'">';
5803  print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> ';
5804  print '<select name="calculation_mode">';
5805  print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>';
5806  print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>';
5807  print '</select> ';
5808  print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5809  print '</form>';
5810  } else {
5811  if (!empty($rate)) {
5812  print price($rate, 1, $langs, 1, 0);
5813  if ($currency && $rate != 1) {
5814  print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
5815  }
5816  } else {
5817  print 1;
5818  }
5819  }
5820  }
5821 
5822 
5823  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5839  public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5840  {
5841  // phpcs:enable
5842  global $conf, $langs;
5843  if ($htmlname != "none") {
5844  print '<form method="post" action="'.$page.'">';
5845  print '<input type="hidden" name="action" value="setabsolutediscount">';
5846  print '<input type="hidden" name="token" value="'.newToken().'">';
5847  print '<div class="inline-block">';
5848  if (!empty($discount_type)) {
5849  if (!empty($conf->global->FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS)) {
5850  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5851  $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5852  } else {
5853  $translationKey = 'HasCreditNoteFromSupplier';
5854  }
5855  } else {
5856  if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5857  $translationKey = 'HasAbsoluteDiscountFromSupplier';
5858  } else {
5859  $translationKey = 'HasCreditNoteFromSupplier';
5860  }
5861  }
5862  } else {
5863  if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5864  if (!$filter || $filter == "fk_facture_source IS NULL") {
5865  $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
5866  } else {
5867  $translationKey = 'CompanyHasCreditNote';
5868  }
5869  } else {
5870  if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5871  $translationKey = 'CompanyHasAbsoluteDiscount';
5872  } else {
5873  $translationKey = 'CompanyHasCreditNote';
5874  }
5875  }
5876  }
5877  print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
5878  if (empty($hidelist)) {
5879  print ' ';
5880  }
5881  print '</div>';
5882  if (empty($hidelist)) {
5883  print '<div class="inline-block" style="padding-right: 10px">';
5884  $newfilter = 'discount_type='.intval($discount_type);
5885  if (!empty($discount_type)) {
5886  $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
5887  } else {
5888  $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
5889  }
5890  if ($filter) {
5891  $newfilter .= ' AND ('.$filter.')';
5892  }
5893  // output the combo of discounts
5894  $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
5895  if ($nbqualifiedlines > 0) {
5896  print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
5897  if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5898  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5899  }
5900  if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5901  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5902  }
5903 
5904  print '>';
5905  }
5906  print '</div>';
5907  }
5908  if ($more) {
5909  print '<div class="inline-block">';
5910  print $more;
5911  print '</div>';
5912  }
5913  print '</form>';
5914  } else {
5915  if ($selected) {
5916  print $selected;
5917  } else {
5918  print "0";
5919  }
5920  }
5921  }
5922 
5923 
5924  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5934  public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
5935  {
5936  // phpcs:enable
5937  global $langs, $conf;
5938 
5939  if ($htmlname != "none") {
5940  print '<form method="post" action="'.$page.'">';
5941  print '<input type="hidden" name="action" value="set_contact">';
5942  print '<input type="hidden" name="token" value="'.newToken().'">';
5943  print '<table class="nobordernopadding">';
5944  print '<tr><td>';
5945  print $this->selectcontacts($societe->id, $selected, $htmlname);
5946  $num = $this->num;
5947  if ($num == 0) {
5948  $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
5949  print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
5950  }
5951  print '</td>';
5952  print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5953  print '</tr></table></form>';
5954  } else {
5955  if ($selected) {
5956  require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
5957  $contact = new Contact($this->db);
5958  $contact->fetch($selected);
5959  print $contact->getFullName($langs);
5960  } else {
5961  print "&nbsp;";
5962  }
5963  }
5964  }
5965 
5966  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5983  public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
5984  {
5985  // phpcs:enable
5986  global $langs;
5987 
5988  $out = '';
5989  if ($htmlname != "none") {
5990  $out .= '<form method="post" action="'.$page.'">';
5991  $out .= '<input type="hidden" name="action" value="set_thirdparty">';
5992  $out .= '<input type="hidden" name="token" value="'.newToken().'">';
5993  $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
5994  $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5995  $out .= '</form>';
5996  } else {
5997  if ($selected) {
5998  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
5999  $soc = new Societe($this->db);
6000  $soc->fetch($selected);
6001  $out .= $soc->getNomUrl(0, '');
6002  } else {
6003  $out .= '<span class="opacitymedium">'.$textifnothirdparty.'</span>';
6004  }
6005  }
6006 
6007  if ($nooutput) {
6008  return $out;
6009  } else {
6010  print $out;
6011  }
6012 
6013  return '';
6014  }
6015 
6016  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6025  public function select_currency($selected = '', $htmlname = 'currency_id')
6026  {
6027  // phpcs:enable
6028  print $this->selectCurrency($selected, $htmlname);
6029  }
6030 
6040  public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6041  {
6042  global $conf, $langs, $user;
6043 
6044  $langs->loadCacheCurrencies('');
6045 
6046  $out = '';
6047 
6048  if ($selected == 'euro' || $selected == 'euros') {
6049  $selected = 'EUR'; // Pour compatibilite
6050  }
6051 
6052  $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
6053  if ($useempty) {
6054  $out .= '<option value="-1" selected></option>';
6055  }
6056  foreach ($langs->cache_currencies as $code_iso => $currency) {
6057  $labeltoshow = $currency['label'];
6058  if ($mode == 1) {
6059  $labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>';
6060  } else {
6061  $labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>';
6062  }
6063 
6064  if ($selected && $selected == $code_iso) {
6065  $out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
6066  } else {
6067  $out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
6068  }
6069  $out .= $labeltoshow;
6070  $out .= '</option>';
6071  }
6072  $out .= '</select>';
6073  if ($user->admin) {
6074  $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6075  }
6076 
6077  // Make select dynamic
6078  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6079  $out .= ajax_combobox($htmlname);
6080 
6081  return $out;
6082  }
6083 
6096  public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6097  {
6098  global $conf, $langs;
6099 
6100  $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6101 
6102  $TCurrency = array();
6103 
6104  $sql = "SELECT code FROM ".$this->db->prefix()."multicurrency";
6105  $sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
6106  if ($filter) {
6107  $sql .= " AND ".$filter;
6108  }
6109  $resql = $this->db->query($sql);
6110  if ($resql) {
6111  while ($obj = $this->db->fetch_object($resql)) {
6112  $TCurrency[$obj->code] = $obj->code;
6113  }
6114  }
6115 
6116  $out = '';
6117  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
6118  if ($useempty) {
6119  $out .= '<option value="">&nbsp;</option>';
6120  }
6121  // If company current currency not in table, we add it into list. Should always be available.
6122  if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6123  $TCurrency[$conf->currency] = $conf->currency;
6124  }
6125  if (count($TCurrency) > 0) {
6126  foreach ($langs->cache_currencies as $code_iso => $currency) {
6127  if (isset($TCurrency[$code_iso])) {
6128  if (!empty($selected) && $selected == $code_iso) {
6129  $out .= '<option value="'.$code_iso.'" selected="selected">';
6130  } else {
6131  $out .= '<option value="'.$code_iso.'">';
6132  }
6133 
6134  $out .= $currency['label'];
6135  $out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
6136  $out .= '</option>';
6137  }
6138  }
6139  }
6140 
6141  $out .= '</select>';
6142 
6143  // Make select dynamic
6144  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6145  $out .= ajax_combobox($htmlname);
6146 
6147  return $out;
6148  }
6149 
6150  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6157  public function load_cache_vatrates($country_code)
6158  {
6159  // phpcs:enable
6160  global $langs;
6161 
6162  $num = count($this->cache_vatrates);
6163  if ($num > 0) {
6164  return $num; // Cache already loaded
6165  }
6166 
6167  dol_syslog(__METHOD__, LOG_DEBUG);
6168 
6169  $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6170  $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6171  $sql .= " WHERE t.fk_pays = c.rowid";
6172  $sql .= " AND t.active > 0";
6173  $sql .= " AND c.code IN (".$this->db->sanitize($country_code, 1).")";
6174  $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6175 
6176  $resql = $this->db->query($sql);
6177  if ($resql) {
6178  $num = $this->db->num_rows($resql);
6179  if ($num) {
6180  for ($i = 0; $i < $num; $i++) {
6181  $obj = $this->db->fetch_object($resql);
6182  $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
6183  $this->cache_vatrates[$i]['code'] = $obj->code;
6184  $this->cache_vatrates[$i]['txtva'] = $obj->taux;
6185  $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
6186  $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
6187  $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
6188  $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
6189  $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
6190 
6191  $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
6192  $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
6193  $positiverates = '';
6194  if ($obj->taux) {
6195  $positiverates .= ($positiverates ? '/' : '').$obj->taux;
6196  }
6197  if ($obj->localtax1) {
6198  $positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
6199  }
6200  if ($obj->localtax2) {
6201  $positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
6202  }
6203  if (empty($positiverates)) {
6204  $positiverates = '0';
6205  }
6206  $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
6207  }
6208 
6209  return $num;
6210  } else {
6211  $this->error = '<span class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</span>';
6212  return -1;
6213  }
6214  } else {
6215  $this->error = '<span class="error">'.$this->db->error().'</span>';
6216  return -2;
6217  }
6218  }
6219 
6220  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6242  public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
6243  {
6244  // phpcs:enable
6245  global $langs, $conf, $mysoc;
6246 
6247  $langs->load('errors');
6248 
6249  $return = '';
6250 
6251  // Define defaultnpr, defaultttx and defaultcode
6252  $defaultnpr = ($info_bits & 0x01);
6253  $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6254  $defaulttx = str_replace('*', '', $selectedrate);
6255  $defaultcode = '';
6256  $reg = array();
6257  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6258  $defaultcode = $reg[1];
6259  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6260  }
6261  //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6262 
6263  // Check parameters
6264  if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6265  if ($societe_vendeuse->id == $mysoc->id) {
6266  $return .= '<span class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</span>';
6267  } else {
6268  $return .= '<span class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</span>';
6269  }
6270  return $return;
6271  }
6272 
6273  //var_dump($societe_acheteuse);
6274  //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";
6275  //exit;
6276 
6277  // Define list of countries to use to search VAT rates to show
6278  // First we defined code_country to use to find list
6279  if (is_object($societe_vendeuse)) {
6280  $code_country = "'".$societe_vendeuse->country_code."'";
6281  } else {
6282  $code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
6283  }
6284  if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) { // If option to have vat for end customer for services is on
6285  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6286  if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
6287  // We also add the buyer
6288  if (is_numeric($type)) {
6289  if ($type == 1) { // We know product is a service
6290  $code_country .= ",'".$societe_acheteuse->country_code."'";
6291  }
6292  } elseif (!$idprod) { // We don't know type of product
6293  $code_country .= ",'".$societe_acheteuse->country_code."'";
6294  } else {
6295  $prodstatic = new Product($this->db);
6296  $prodstatic->fetch($idprod);
6297  if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6298  $code_country .= ",'".$societe_acheteuse->country_code."'";
6299  }
6300  }
6301  }
6302  }
6303 
6304  // Now we get list
6305  $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6306 
6307  if ($num > 0) {
6308  // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6309  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6310  $tmpthirdparty = new Societe($this->db);
6311 
6312  $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6313  $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6314 
6315  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6316  $defaultcode = $reg[1];
6317  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6318  }
6319  if (empty($defaulttx)) {
6320  $defaultnpr = 0;
6321  }
6322  }
6323 
6324  // If we fails to find a default vat rate, we take the last one in list
6325  // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
6326  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6327  if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6328  // We take the last one found in list
6329  $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
6330  } else {
6331  // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
6332  $defaulttx = '';
6333  if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6334  $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6335  }
6336  if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6337  $defaultcode = $reg[1];
6338  $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6339  }
6340  }
6341  }
6342 
6343  // Disabled if seller is not subject to VAT
6344  $disabled = false;
6345  $title = '';
6346  if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6347  // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6348  // of using supplier invoices (this is a very bad idea !)
6349  if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
6350  $title = ' title="'.dol_escape_htmltag($langs->trans('VATIsNotUsed')).'"';
6351  $disabled = true;
6352  }
6353  }
6354 
6355  if (!$options_only) {
6356  $return .= '<select class="flat minwidth50imp maxwidth100" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
6357  }
6358 
6359  $selectedfound = false;
6360  foreach ($this->cache_vatrates as $rate) {
6361  // Keep only 0 if seller is not subject to VAT
6362  if ($disabled && $rate['txtva'] != 0) {
6363  continue;
6364  }
6365 
6366  // Define key to use into select list
6367  $key = $rate['txtva'];
6368  $key .= $rate['nprtva'] ? '*' : '';
6369  if ($mode > 0 && $rate['code']) {
6370  $key .= ' ('.$rate['code'].')';
6371  }
6372  if ($mode < 0) {
6373  $key = $rate['rowid'];
6374  }
6375 
6376  $return .= '<option value="'.$key.'"';
6377  if (!$selectedfound) {
6378  if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6379  if ($defaultcode == $rate['code']) {
6380  $return .= ' selected';
6381  $selectedfound = true;
6382  }
6383  } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6384  $return .= ' selected';
6385  $selectedfound = true;
6386  }
6387  }
6388  $return .= '>';
6389 
6390  // Show label of VAT
6391  if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
6392  // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
6393  $return .= $rate['labelpositiverates'];
6394  } else {
6395  // Simple label
6396  $return .= vatrate($rate['label']);
6397  }
6398 
6399  //$return.=($rate['code']?' '.$rate['code']:'');
6400  $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
6401 
6402  $return .= '</option>';
6403  }
6404 
6405  if (!$options_only) {
6406  $return .= '</select>';
6407  //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
6408  }
6409  } else {
6410  $return .= $this->error;
6411  }
6412 
6413  $this->num = $num;
6414  return $return;
6415  }
6416 
6417 
6418  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6443  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 = '')
6444  {
6445  // phpcs:enable
6446  $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6447  if (!empty($nooutput)) {
6448  return $retstring;
6449  }
6450  print $retstring;
6451  return;
6452  }
6453 
6469  public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6470  {
6471  global $langs;
6472 
6473  $ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6474  if ($forcenewline) {
6475  $ret .= '<br>';
6476  }
6477  $ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6478  return $ret;
6479  }
6480 
6508  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')
6509  {
6510  global $conf, $langs;
6511 
6512  if ($gm === 'auto') {
6513  $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6514  }
6515 
6516  $retstring = '';
6517 
6518  if ($prefix == '') {
6519  $prefix = 're';
6520  }
6521  if ($h == '') {
6522  $h = 0;
6523  }
6524  if ($m == '') {
6525  $m = 0;
6526  }
6527  $emptydate = 0;
6528  $emptyhours = 0;
6529  if ($stepminutes <= 0 || $stepminutes > 30) {
6530  $stepminutes = 1;
6531  }
6532  if ($empty == 1) {
6533  $emptydate = 1;
6534  $emptyhours = 1;
6535  }
6536  if ($empty == 2) {
6537  $emptydate = 0;
6538  $emptyhours = 1;
6539  }
6540  $orig_set_time = $set_time;
6541 
6542  if ($set_time === '' && $emptydate == 0) {
6543  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6544  if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6545  $set_time = dol_now($gm);
6546  } else {
6547  $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6548  }
6549  }
6550 
6551  // Analysis of the pre-selection date
6552  $reg = array();
6553  $shour = '';
6554  $smin = '';
6555  $ssec = '';
6556  if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
6557  // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6558  $syear = (!empty($reg[1]) ? $reg[1] : '');
6559  $smonth = (!empty($reg[2]) ? $reg[2] : '');
6560  $sday = (!empty($reg[3]) ? $reg[3] : '');
6561  $shour = (!empty($reg[4]) ? $reg[4] : '');
6562  $smin = (!empty($reg[5]) ? $reg[5] : '');
6563  } elseif (strval($set_time) != '' && $set_time != -1) {
6564  // set_time est un timestamps (0 possible)
6565  $syear = dol_print_date($set_time, "%Y", $gm);
6566  $smonth = dol_print_date($set_time, "%m", $gm);
6567  $sday = dol_print_date($set_time, "%d", $gm);
6568  if ($orig_set_time != '') {
6569  $shour = dol_print_date($set_time, "%H", $gm);
6570  $smin = dol_print_date($set_time, "%M", $gm);
6571  $ssec = dol_print_date($set_time, "%S", $gm);
6572  }
6573  } else {
6574  // Date est '' ou vaut -1
6575  $syear = '';
6576  $smonth = '';
6577  $sday = '';
6578  $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6579  $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6580  $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6581  }
6582  if ($h == 3) {
6583  $shour = '';
6584  }
6585  if ($m == 3) {
6586  $smin = '';
6587  }
6588 
6589  $nowgmt = dol_now('gmt');
6590  //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6591 
6592  // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6593  $usecalendar = 'combo';
6594  if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6595  $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6596  }
6597 
6598  if ($d) {
6599  // Show date with popup
6600  if ($usecalendar != 'combo') {
6601  $formated_date = '';
6602  //print "e".$set_time." t ".$conf->format_date_short;
6603  if (strval($set_time) != '' && $set_time != -1) {
6604  //$formated_date=dol_print_date($set_time,$conf->format_date_short);
6605  $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6606  }
6607 
6608  // Calendrier popup version eldy
6609  if ($usecalendar == "eldy") {
6610  // Input area to enter date manually
6611  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6612  $retstring .= ($disabled ? ' disabled' : '');
6613  $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6614  $retstring .= '>';
6615 
6616  // Icon calendar
6617  $retstringbuttom = '';
6618  if (!$disabled) {
6619  $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
6620  $base = DOL_URL_ROOT.'/core/';
6621  $retstringbuttom .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
6622  $retstringbuttom .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
6623  } else {
6624  $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6625  }
6626  $retstring = $retstringbuttom.$retstring;
6627 
6628  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
6629  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6630  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
6631  } elseif ($usecalendar == 'jquery') {
6632  if (!$disabled) {
6633  // Output javascript for datepicker
6634  $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (date('Y') - 100));
6635  $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (date('Y') + 100));
6636 
6637  $retstring .= "<script type='text/javascript'>";
6638  $retstring .= "$(function(){ $('#".$prefix."').datepicker({
6639  dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
6640  autoclose: true,
6641  todayHighlight: true,
6642  yearRange: '".$minYear.":".$maxYear."',";
6643  if (!empty($conf->dol_use_jmobile)) {
6644  $retstring .= "
6645  beforeShow: function (input, datePicker) {
6646  input.disabled = true;
6647  },
6648  onClose: function (dateText, datePicker) {
6649  this.disabled = false;
6650  },
6651  ";
6652  }
6653  // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6654  if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6655  $retstring .= "
6656  showOn: 'button', /* both has problem with autocompletion */
6657  buttonImage: '".DOL_URL_ROOT."/theme/".dol_escape_js($conf->theme)."/img/object_calendarday.png',
6658  buttonImageOnly: true";
6659  }
6660  $retstring .= "
6661  }) });";
6662  $retstring .= "</script>";
6663  }
6664 
6665  // Zone de saisie manuelle de la date
6666  $retstring .= '<div class="nowrap inline-block divfordateinput">';
6667  $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6668  $retstring .= ($disabled ? ' disabled' : '');
6669  $retstring .= ($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '');
6670  $retstring .= ' onChange="dpChangeDay(\''.dol_escape_js($prefix).'\',\''.dol_escape_js($langs->trans("FormatDateShortJavaInput")).'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6671  $retstring .= '>';
6672 
6673  // Icone calendrier
6674  if (!$disabled) {
6675  /* Not required. Managed by option buttonImage of jquery
6676  $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6677  $retstring.="<script type='text/javascript'>";
6678  $retstring.="jQuery(document).ready(function() {";
6679  $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
6680  $retstring.=" jQuery('#".$prefix."').focus();";
6681  $retstring.=' });';
6682  $retstring.='});';
6683  $retstring.="</script>";*/
6684  } else {
6685  $retstringbutton = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6686  $retsring = $retstringbutton.$retstring;
6687  }
6688 
6689  $retstring .= '</div>';
6690  $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
6691  $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6692  $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
6693  } else {
6694  $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6695  }
6696  } else {
6697  // Show date with combo selects
6698  // Day
6699  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
6700 
6701  if ($emptydate || $set_time == -1) {
6702  $retstring .= '<option value="0" selected>&nbsp;</option>';
6703  }
6704 
6705  for ($day = 1; $day <= 31; $day++) {
6706  $retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
6707  }
6708 
6709  $retstring .= "</select>";
6710 
6711  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
6712  if ($emptydate || $set_time == -1) {
6713  $retstring .= '<option value="0" selected>&nbsp;</option>';
6714  }
6715 
6716  // Month
6717  for ($month = 1; $month <= 12; $month++) {
6718  $retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
6719  $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6720  $retstring .= "</option>";
6721  }
6722  $retstring .= "</select>";
6723 
6724  // Year
6725  if ($emptydate || $set_time == -1) {
6726  $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.'">';
6727  } else {
6728  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
6729 
6730  for ($year = $syear - 10; $year < $syear + 10; $year++) {
6731  $retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
6732  }
6733  $retstring .= "</select>\n";
6734  }
6735  }
6736  }
6737 
6738  if ($d && $h) {
6739  $retstring .= ($h == 2 ? '<br>' : ' ');
6740  $retstring .= '<span class="nowraponall">';
6741  }
6742 
6743  if ($h) {
6744  $hourstart = 0;
6745  $hourend = 24;
6746  if ($openinghours != '') {
6747  $openinghours = explode(',', $openinghours);
6748  $hourstart = $openinghours[0];
6749  $hourend = $openinghours[1];
6750  if ($hourend < $hourstart) {
6751  $hourend = $hourstart;
6752  }
6753  }
6754  // Show hour
6755  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
6756  if ($emptyhours) {
6757  $retstring .= '<option value="-1">&nbsp;</option>';
6758  }
6759  for ($hour = $hourstart; $hour < $hourend; $hour++) {
6760  if (strlen($hour) < 2) {
6761  $hour = "0".$hour;
6762  }
6763  $retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour;
6764  //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6765  $retstring .= '</option>';
6766  }
6767  $retstring .= '</select>';
6768  //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6769  if ($m) {
6770  $retstring .= ":";
6771  }
6772  }
6773 
6774  if ($m) {
6775  // Show minutes
6776  $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
6777  if ($emptyhours) {
6778  $retstring .= '<option value="-1">&nbsp;</option>';
6779  }
6780  for ($min = 0; $min < 60; $min += $stepminutes) {
6781  if (strlen($min) < 2) {
6782  $min = "0".$min;
6783  }
6784  $retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
6785  }
6786  $retstring .= '</select>';
6787 
6788  $retstring .= '<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
6789  }
6790 
6791  if ($d && $h) {
6792  $retstring .= '</span>';
6793  }
6794 
6795  // Add a "Now" link
6796  if (!empty($conf->use_javascript_ajax) && $addnowlink) {
6797  // Script which will be inserted in the onClick of the "Now" link
6798  $reset_scripts = "";
6799  if ($addnowlink == 2) { // local computer time
6800  // pad add leading 0 on numbers
6801  $reset_scripts .= "Number.prototype.pad = function(size) {
6802  var s = String(this);
6803  while (s.length < (size || 2)) {s = '0' + s;}
6804  return s;
6805  };
6806  var d = new Date();";
6807  }
6808 
6809  // Generate the date part, depending on the use or not of the javascript calendar
6810  if ($addnowlink == 1) { // server time expressed in user time setup
6811  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6812  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6813  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6814  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6815  } elseif ($addnowlink == 2) {
6816  /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6817  * This break application for foreign languages.
6818  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6819  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6820  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6821  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6822  */
6823  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6824  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6825  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6826  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6827  }
6828  /*if ($usecalendar == "eldy")
6829  {
6830  $base=DOL_URL_ROOT.'/core/';
6831  $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6832  }
6833  else
6834  {
6835  $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6836  $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6837  $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6838  }*/
6839  // Update the hour part
6840  if ($h) {
6841  if ($fullday) {
6842  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6843  }
6844  //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
6845  if ($addnowlink == 1) {
6846  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6847  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6848  } elseif ($addnowlink == 2) {
6849  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
6850  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6851  }
6852 
6853  if ($fullday) {
6854  $reset_scripts .= ' } ';
6855  }
6856  }
6857  // Update the minute part
6858  if ($m) {
6859  if ($fullday) {
6860  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6861  }
6862  //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
6863  if ($addnowlink == 1) {
6864  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6865  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6866  } elseif ($addnowlink == 2) {
6867  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
6868  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6869  }
6870  if ($fullday) {
6871  $reset_scripts .= ' } ';
6872  }
6873  }
6874  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6875  if ($reset_scripts && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
6876  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
6877  $retstring .= $langs->trans("Now");
6878  $retstring .= '</button> ';
6879  }
6880  }
6881 
6882  // Add a "Plus one hour" link
6883  if ($conf->use_javascript_ajax && $addplusone) {
6884  // Script which will be inserted in the onClick of the "Add plusone" link
6885  $reset_scripts = "";
6886 
6887  // Generate the date part, depending on the use or not of the javascript calendar
6888  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');';
6889  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6890  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6891  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6892  // Update the hour part
6893  if ($h) {
6894  if ($fullday) {
6895  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6896  }
6897  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6898  if ($fullday) {
6899  $reset_scripts .= ' } ';
6900  }
6901  }
6902  // Update the minute part
6903  if ($m) {
6904  if ($fullday) {
6905  $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6906  }
6907  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6908  if ($fullday) {
6909  $reset_scripts .= ' } ';
6910  }
6911  }
6912  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6913  if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6914  $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
6915  $retstring .= $langs->trans("DateStartPlusOne");
6916  $retstring .= '</button> ';
6917  }
6918  }
6919 
6920  // Add a link to set data
6921  if ($conf->use_javascript_ajax && $adddateof) {
6922  $tmparray = dol_getdate($adddateof);
6923  if (empty($labeladddateof)) {
6924  $labeladddateof = $langs->trans("DateInvoice");
6925  }
6926  $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="console.log(\'Click on now link\'); jQuery(\'#re\').val(\''.dol_print_date($adddateof, 'dayinputnoreduce').'\');jQuery(\'#reday\').val(\''.$tmparray['mday'].'\');jQuery(\'#remonth\').val(\''.$tmparray['mon'].'\');jQuery(\'#reyear\').val(\''.$tmparray['year'].'\');">'.$labeladddateof.'</a>';
6927  }
6928 
6929  return $retstring;
6930  }
6931 
6940  public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
6941  {
6942  global $langs;
6943 
6944  $TDurationTypes = array(
6945  'y'=>$langs->trans('Years'),
6946  'm'=>$langs->trans('Month'),
6947  'w'=>$langs->trans('Weeks'),
6948  'd'=>$langs->trans('Days'),
6949  'h'=>$langs->trans('Hours'),
6950  'i'=>$langs->trans('Minutes')
6951  );
6952 
6953  // Removed undesired duration types
6954  foreach ($excludetypes as $value) {
6955  unset($TDurationTypes[$value]);
6956  }
6957 
6958  $retstring = '<select class="flat minwidth75 maxwidth100" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
6959  foreach ($TDurationTypes as $key => $typeduration) {
6960  $retstring .= '<option value="'.$key.'"';
6961  if ($key == $selected) {
6962  $retstring .= " selected";
6963  }
6964  $retstring .= ">".$typeduration."</option>";
6965  }
6966  $retstring .= "</select>";
6967 
6968  $retstring .= ajax_combobox('select_'.$prefix.'type_duration');
6969 
6970  return $retstring;
6971  }
6972 
6973  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6987  public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
6988  {
6989  // phpcs:enable
6990  global $langs;
6991 
6992  $retstring = '<span class="nowraponall">';
6993 
6994  $hourSelected = 0;
6995  $minSelected = 0;
6996 
6997  // Hours
6998  if ($iSecond != '') {
6999  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
7000 
7001  $hourSelected = convertSecondToTime($iSecond, 'allhour');
7002  $minSelected = convertSecondToTime($iSecond, 'min');
7003  }
7004 
7005  if ($typehour == 'select') {
7006  $retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
7007  for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7008  $retstring .= '<option value="'.$hour.'"';
7009  if ($hourSelected == $hour) {
7010  $retstring .= " selected";
7011  }
7012  $retstring .= ">".$hour."</option>";
7013  }
7014  $retstring .= "</select>";
7015  } elseif ($typehour == 'text' || $typehour == 'textselect') {
7016  $retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
7017  } else {
7018  return 'BadValueForParameterTypeHour';
7019  }
7020 
7021  if ($typehour != 'text') {
7022  $retstring .= ' '.$langs->trans('HourShort');
7023  } else {
7024  $retstring .= '<span class="">:</span>';
7025  }
7026 
7027  // Minutes
7028  if ($minunderhours) {
7029  $retstring .= '<br>';
7030  } else {
7031  $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7032  }
7033 
7034  if ($typehour == 'select' || $typehour == 'textselect') {
7035  $retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
7036  for ($min = 0; $min <= 55; $min = $min + 5) {
7037  $retstring .= '<option value="'.$min.'"';
7038  if ($minSelected == $min) {
7039  $retstring .= ' selected';
7040  }
7041  $retstring .= '>'.$min.'</option>';
7042  }
7043  $retstring .= "</select>";
7044  } elseif ($typehour == 'text') {
7045  $retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
7046  }
7047 
7048  if ($typehour != 'text') {
7049  $retstring .= ' '.$langs->trans('MinuteShort');
7050  }
7051 
7052  $retstring.="</span>";
7053 
7054  if (!empty($nooutput)) {
7055  return $retstring;
7056  }
7057 
7058  print $retstring;
7059  return;
7060  }
7061 
7081  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)
7082  {
7083  global $langs, $conf;
7084 
7085  $out = '';
7086 
7087  // check parameters
7088  if (is_null($ajaxoptions)) $ajaxoptions = array();
7089 
7090  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7091  $placeholder = '';
7092 
7093  if ($selected && empty($selected_input_value)) {
7094  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
7095  $tickettmpselect = new Ticket($this->db);
7096  $tickettmpselect->fetch($selected);
7097  $selected_input_value = $tickettmpselect->ref;
7098  unset($tickettmpselect);
7099  }
7100 
7101  $urloption = '';
7102  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7103 
7104  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7105  elseif ($hidelabel > 1) {
7106  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7107  if ($hidelabel == 2) {
7108  $out .= img_picto($langs->trans("Search"), 'search');
7109  }
7110  }
7111  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7112  if ($hidelabel == 3) {
7113  $out .= img_picto($langs->trans("Search"), 'search');
7114  }
7115  } else {
7116  $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7117  }
7118 
7119  if (empty($nooutput)) {
7120  print $out;
7121  } else {
7122  return $out;
7123  }
7124  return '';
7125  }
7126 
7127 
7144  public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7145  {
7146  global $langs, $conf;
7147 
7148  $out = '';
7149  $outarray = array();
7150 
7151  $selectFields = " p.rowid, p.ref, p.message";
7152 
7153  $sql = "SELECT ";
7154  $sql .= $selectFields;
7155  $sql .= " FROM ".$this->db->prefix()."ticket as p";
7156  $sql .= ' WHERE p.entity IN ('.getEntity('ticket').')';
7157 
7158  // Add criteria on ref/label
7159  if ($filterkey != '') {
7160  $sql .= ' AND (';
7161  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7162  // For natural search
7163  $scrit = explode(' ', $filterkey);
7164  $i = 0;
7165  if (count($scrit) > 1) $sql .= "(";
7166  foreach ($scrit as $crit) {
7167  if ($i > 0) $sql .= " AND ";
7168  $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.subject LIKE '".$this->db->escape($prefix.$crit)."%'";
7169  $sql .= ")";
7170  $i++;
7171  }
7172  if (count($scrit) > 1) $sql .= ")";
7173  $sql .= ')';
7174  }
7175 
7176  $sql .= $this->db->plimit($limit, 0);
7177 
7178  // Build output string
7179  dol_syslog(get_class($this)."::selectTicketsList search tickets", LOG_DEBUG);
7180  $result = $this->db->query($sql);
7181  if ($result) {
7182  require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
7183  require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
7184 
7185  $num = $this->db->num_rows($result);
7186 
7187  $events = null;
7188 
7189  if (!$forcecombo) {
7190  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7191  $out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
7192  }
7193 
7194  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7195 
7196  $textifempty = '';
7197  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7198  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7199  if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7200  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7201  else $textifempty .= $langs->trans("All");
7202  } else {
7203  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7204  }
7205  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7206 
7207  $i = 0;
7208  while ($num && $i < $num) {
7209  $opt = '';
7210  $optJson = array();
7211  $objp = $this->db->fetch_object($result);
7212 
7213  $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7214  // Add new entry
7215  // "key" value of json key array is used by jQuery automatically as selected value
7216  // "label" value of json key array is used by jQuery automatically as text for combo box
7217  $out .= $opt;
7218  array_push($outarray, $optJson);
7219 
7220  $i++;
7221  }
7222 
7223  $out .= '</select>';
7224 
7225  $this->db->free($result);
7226 
7227  if (empty($outputmode)) {
7228  return $out;
7229  }
7230  return $outarray;
7231  } else {
7232  dol_print_error($this->db);
7233  }
7234 
7235  return array();
7236  }
7237 
7249  protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7250  {
7251  $outkey = '';
7252  $outref = '';
7253  $outtype = '';
7254 
7255  $outkey = $objp->rowid;
7256  $outref = $objp->ref;
7257  $outtype = $objp->fk_product_type;
7258 
7259  $opt = '<option value="'.$objp->rowid.'"';
7260  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7261  $opt .= '>';
7262  $opt .= $objp->ref;
7263  $objRef = $objp->ref;
7264  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7265 
7266  $opt .= "</option>\n";
7267  $optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7268  }
7269 
7289  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)
7290  {
7291  global $langs, $conf;
7292 
7293  $out = '';
7294 
7295  // check parameters
7296  if (is_null($ajaxoptions)) $ajaxoptions = array();
7297 
7298  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7299  $placeholder = '';
7300 
7301  if ($selected && empty($selected_input_value)) {
7302  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7303  $projecttmpselect = new Project($this->db);
7304  $projecttmpselect->fetch($selected);
7305  $selected_input_value = $projecttmpselect->ref;
7306  unset($projecttmpselect);
7307  }
7308 
7309  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7310 
7311  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7312  elseif ($hidelabel > 1) {
7313  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7314  if ($hidelabel == 2) {
7315  $out .= img_picto($langs->trans("Search"), 'search');
7316  }
7317  }
7318  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7319  if ($hidelabel == 3) {
7320  $out .= img_picto($langs->trans("Search"), 'search');
7321  }
7322  } else {
7323  $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7324  }
7325 
7326  if (empty($nooutput)) {
7327  print $out;
7328  } else {
7329  return $out;
7330  }
7331  return '';
7332  }
7333 
7350  public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7351  {
7352  global $langs, $conf;
7353 
7354  $out = '';
7355  $outarray = array();
7356 
7357  $selectFields = " p.rowid, p.ref";
7358 
7359  $sql = "SELECT ";
7360  $sql .= $selectFields;
7361  $sql .= " FROM ".$this->db->prefix()."projet as p";
7362  $sql .= ' WHERE p.entity IN ('.getEntity('project').')';
7363 
7364  // Add criteria on ref/label
7365  if ($filterkey != '') {
7366  $sql .= ' AND (';
7367  $prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7368  // For natural search
7369  $scrit = explode(' ', $filterkey);
7370  $i = 0;
7371  if (count($scrit) > 1) $sql .= "(";
7372  foreach ($scrit as $crit) {
7373  if ($i > 0) $sql .= " AND ";
7374  $sql .= "p.ref LIKE '".$this->db->escape($prefix.$crit)."%'";
7375  $sql .= "";
7376  $i++;
7377  }
7378  if (count($scrit) > 1) $sql .= ")";
7379  $sql .= ')';
7380  }
7381 
7382  $sql .= $this->db->plimit($limit, 0);
7383 
7384  // Build output string
7385  dol_syslog(get_class($this)."::selectProjectsList search projects", LOG_DEBUG);
7386  $result = $this->db->query($sql);
7387  if ($result) {
7388  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7389  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
7390 
7391  $num = $this->db->num_rows($result);
7392 
7393  $events = null;
7394 
7395  if (!$forcecombo) {
7396  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7397  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7398  }
7399 
7400  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7401 
7402  $textifempty = '';
7403  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7404  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7405  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7406  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7407  else $textifempty .= $langs->trans("All");
7408  } else {
7409  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7410  }
7411  if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7412 
7413  $i = 0;
7414  while ($num && $i < $num) {
7415  $opt = '';
7416  $optJson = array();
7417  $objp = $this->db->fetch_object($result);
7418 
7419  $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7420  // Add new entry
7421  // "key" value of json key array is used by jQuery automatically as selected value
7422  // "label" value of json key array is used by jQuery automatically as text for combo box
7423  $out .= $opt;
7424  array_push($outarray, $optJson);
7425 
7426  $i++;
7427  }
7428 
7429  $out .= '</select>';
7430 
7431  $this->db->free($result);
7432 
7433  if (empty($outputmode)) {
7434  return $out;
7435  }
7436  return $outarray;
7437  } else {
7438  dol_print_error($this->db);
7439  }
7440 
7441  return array();
7442  }
7443 
7455  protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7456  {
7457  $outkey = '';
7458  $outref = '';
7459  $outtype = '';
7460 
7461  $label = $objp->label;
7462 
7463  $outkey = $objp->rowid;
7464  $outref = $objp->ref;
7465  $outlabel = $objp->label;
7466  $outtype = $objp->fk_product_type;
7467 
7468  $opt = '<option value="'.$objp->rowid.'"';
7469  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7470  $opt .= '>';
7471  $opt .= $objp->ref;
7472  $objRef = $objp->ref;
7473  if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7474 
7475  $opt .= "</option>\n";
7476  $optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7477  }
7478 
7479 
7499  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)
7500  {
7501  global $langs, $conf;
7502 
7503  $out = '';
7504 
7505  // check parameters
7506  if (is_null($ajaxoptions)) $ajaxoptions = array();
7507 
7508  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7509  $placeholder = '';
7510  $urloption = '';
7511 
7512  if ($selected && empty($selected_input_value)) {
7513  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7514  $adherenttmpselect = new Adherent($this->db);
7515  $adherenttmpselect->fetch($selected);
7516  $selected_input_value = $adherenttmpselect->ref;
7517  unset($adherenttmpselect);
7518  }
7519 
7520  $urloption = '';
7521 
7522  $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7523 
7524  if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7525  elseif ($hidelabel > 1) {
7526  $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7527  if ($hidelabel == 2) {
7528  $out .= img_picto($langs->trans("Search"), 'search');
7529  }
7530  }
7531  $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7532  if ($hidelabel == 3) {
7533  $out .= img_picto($langs->trans("Search"), 'search');
7534  }
7535  } else {
7536  $filterkey = '';
7537 
7538  $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
7539  }
7540 
7541  if (empty($nooutput)) {
7542  print $out;
7543  } else {
7544  return $out;
7545  }
7546  return '';
7547  }
7548 
7565  public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7566  {
7567  global $langs, $conf;
7568 
7569  $out = '';
7570  $outarray = array();
7571 
7572  $selectFields = " p.rowid, p.ref, p.firstname, p.lastname";
7573 
7574  $sql = "SELECT ";
7575  $sql .= $selectFields;
7576  $sql .= " FROM ".$this->db->prefix()."adherent as p";
7577  $sql .= ' WHERE p.entity IN ('.getEntity('adherent').')';
7578 
7579  // Add criteria on ref/label
7580  if ($filterkey != '') {
7581  $sql .= ' AND (';
7582  $prefix = empty($conf->global->MEMBER_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7583  // For natural search
7584  $scrit = explode(' ', $filterkey);
7585  $i = 0;
7586  if (count($scrit) > 1) $sql .= "(";
7587  foreach ($scrit as $crit) {
7588  if ($i > 0) $sql .= " AND ";
7589  $sql .= "(p.firstname LIKE '".$this->db->escape($prefix.$crit)."%'";
7590  $sql .= " OR p.lastname LIKE '".$this->db->escape($prefix.$crit)."%')";
7591  $i++;
7592  }
7593  if (count($scrit) > 1) $sql .= ")";
7594  $sql .= ')';
7595  }
7596  if ($status != -1) {
7597  $sql .= ' AND statut = '.((int) $status);
7598  }
7599  $sql .= $this->db->plimit($limit, 0);
7600 
7601  // Build output string
7602  dol_syslog(get_class($this)."::selectMembersList search adherents", LOG_DEBUG);
7603  $result = $this->db->query($sql);
7604  if ($result) {
7605  require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7606  require_once DOL_DOCUMENT_ROOT.'/core/lib/member.lib.php';
7607 
7608  $num = $this->db->num_rows($result);
7609 
7610  $events = null;
7611 
7612  if (!$forcecombo) {
7613  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7614  $out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7615  }
7616 
7617  $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7618 
7619  $textifempty = '';
7620  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7621  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7622  if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7623  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7624  else $textifempty .= $langs->trans("All");
7625  } else {
7626  if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7627  }
7628  if ($showempty) {
7629  $out .= '<option value="-1" selected>'.$textifempty.'</option>';
7630  }
7631 
7632  $i = 0;
7633  while ($num && $i < $num) {
7634  $opt = '';
7635  $optJson = array();
7636  $objp = $this->db->fetch_object($result);
7637 
7638  $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
7639 
7640  // Add new entry
7641  // "key" value of json key array is used by jQuery automatically as selected value
7642  // "label" value of json key array is used by jQuery automatically as text for combo box
7643  $out .= $opt;
7644  array_push($outarray, $optJson);
7645 
7646  $i++;
7647  }
7648 
7649  $out .= '</select>';
7650 
7651  $this->db->free($result);
7652 
7653  if (empty($outputmode)) {
7654  return $out;
7655  }
7656  return $outarray;
7657  } else {
7658  dol_print_error($this->db);
7659  }
7660 
7661  return array();
7662  }
7663 
7675  protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7676  {
7677  $outkey = '';
7678  $outlabel = '';
7679  $outtype = '';
7680 
7681  $outkey = $objp->rowid;
7682  $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
7683  $outtype = $objp->fk_adherent_type;
7684 
7685  $opt = '<option value="'.$objp->rowid.'"';
7686  $opt .= ($objp->rowid == $selected) ? ' selected' : '';
7687  $opt .= '>';
7688  if (!empty($filterkey) && $filterkey != '') {
7689  $outlabel = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $outlabel, 1);
7690  }
7691  $opt .= $outlabel;
7692  $opt .= "</option>\n";
7693 
7694  $optJson = array('key'=>$outkey, 'value'=>$outlabel, 'type'=>$outtype);
7695  }
7696 
7716  public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
7717  {
7718  global $conf, $user;
7719 
7720  $objecttmp = null;
7721 
7722  // Example of value for $objectdec:
7723  // Bom:bom/class/bom.class.php:0:t.status=1
7724  // Bom:bom/class/bom.class.php:0:t.status=1:ref
7725  // Bom:bom/class/bom.class.php:0:(t.status:=:1):ref
7726  $InfoFieldList = explode(":", $objectdesc, 4);
7727  $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
7728  $reg = array();
7729  if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
7730  $InfoFieldList[4] = $reg[1]; // take the sort field
7731  }
7732  $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
7733 
7734  $classname = $InfoFieldList[0];
7735  $classpath = $InfoFieldList[1];
7736  $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
7737  $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
7738  $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
7739 
7740  if (!empty($classpath)) {
7741  dol_include_once($classpath);
7742 
7743  if ($classname && class_exists($classname)) {
7744  $objecttmp = new $classname($this->db);
7745 
7746  // Make some replacement
7747  $sharedentities = getEntity(strtolower($classname));
7748  $filter = str_replace(
7749  array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
7750  array($conf->entity, $sharedentities, $user->id),
7751  $filter
7752  );
7753  }
7754  }
7755  if (!is_object($objecttmp)) {
7756  dol_syslog('Error bad setup of type for field '.join(',', $InfoFieldList), LOG_WARNING);
7757  return 'Error bad setup of type for field '.join(',', $InfoFieldList);
7758  }
7759 
7760  //var_dump($filter);
7761  $prefixforautocompletemode = $objecttmp->element;
7762  if ($prefixforautocompletemode == 'societe') {
7763  $prefixforautocompletemode = 'company';
7764  }
7765  if ($prefixforautocompletemode == 'product') {
7766  $prefixforautocompletemode = 'produit';
7767  }
7768  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7769 
7770  dol_syslog(get_class($this)."::selectForForms filter=".$filter, LOG_DEBUG);
7771  $out = '';
7772  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo) {
7773  // No immediate load of all database
7774  $placeholder = '';
7775  if ($preselectedvalue && empty($selected_input_value)) {
7776  $objecttmp->fetch($preselectedvalue);
7777  $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
7778  //unset($objecttmp);
7779  }
7780 
7781  $objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
7782  $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
7783 
7784  // No immediate load of all database
7785  $urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&objectdesc='.urlencode($objectdesc).'&filter='.urlencode($filter).($sortfield ? '&sortfield='.urlencode($sortfield) : '');
7786  // Activate the auto complete using ajax call.
7787  $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
7788  $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
7789  $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).'"' : '') .' />';
7790  } else {
7791  // Immediate load of table record.
7792  $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
7793  }
7794 
7795  return $out;
7796  }
7797 
7804  protected static function forgeCriteriaCallback($matches)
7805  {
7806  global $db;
7807 
7808  //dol_syslog("Convert matches ".$matches[1]);
7809  if (empty($matches[1])) {
7810  return '';
7811  }
7812  $tmp = explode(':', $matches[1]);
7813  if (count($tmp) < 3) {
7814  return '';
7815  }
7816 
7817  $tmpescaped = $tmp[2];
7818  $regbis = array();
7819  if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
7820  $tmpescaped = "'".$db->escape($regbis[1])."'";
7821  } else {
7822  $tmpescaped = $db->escape($tmpescaped);
7823  }
7824  return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
7825  }
7826 
7847  public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
7848  {
7849  global $conf, $langs, $user, $hookmanager;
7850 
7851  //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
7852 
7853  $prefixforautocompletemode = $objecttmp->element;
7854  if ($prefixforautocompletemode == 'societe') {
7855  $prefixforautocompletemode = 'company';
7856  }
7857  $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7858 
7859  if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
7860  $tmpfieldstoshow = '';
7861  foreach ($objecttmp->fields as $key => $val) {
7862  if (!dol_eval($val['enabled'], 1, 1, '1')) {
7863  continue;
7864  }
7865  if (!empty($val['showoncombobox'])) {
7866  $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
7867  }
7868  }
7869  if ($tmpfieldstoshow) {
7870  $fieldstoshow = $tmpfieldstoshow;
7871  }
7872  } else {
7873  // For backward compatibility
7874  $objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
7875  }
7876 
7877  if (empty($fieldstoshow)) {
7878  if (isset($objecttmp->fields['ref'])) {
7879  $fieldstoshow = 't.ref';
7880  } else {
7881  $langs->load("errors");
7882  $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
7883  return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
7884  }
7885  }
7886 
7887  $out = '';
7888  $outarray = array();
7889  $tmparray = array();
7890 
7891  $num = 0;
7892 
7893  // Search data
7894  $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".$this->db->prefix().$objecttmp->table_element." as t";
7895  if (isset($objecttmp->ismultientitymanaged)) {
7896  if (!is_numeric($objecttmp->ismultientitymanaged)) {
7897  $tmparray = explode('@', $objecttmp->ismultientitymanaged);
7898  $sql .= " INNER JOIN ".$this->db->prefix().$tmparray[1]." as parenttable ON parenttable.rowid = t.".$tmparray[0];
7899  }
7900  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7901  if (empty($user->rights->societe->client->voir) && !$user->socid) {
7902  $sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
7903  }
7904  }
7905  }
7906 
7907  // Add where from hooks
7908  $parameters = array();
7909  $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
7910  if (!empty($hookmanager->resPrint)) {
7911  $sql .= $hookmanager->resPrint;
7912  } else {
7913  $sql .= " WHERE 1=1";
7914  if (isset($objecttmp->ismultientitymanaged)) {
7915  if ($objecttmp->ismultientitymanaged == 1) {
7916  $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
7917  }
7918  if (!is_numeric($objecttmp->ismultientitymanaged)) {
7919  $sql .= " AND parenttable.entity = t.".$tmparray[0];
7920  }
7921  if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
7922  if ($objecttmp->element == 'societe') {
7923  $sql .= " AND t.rowid = ".((int) $user->socid);
7924  } else {
7925  $sql .= " AND t.fk_soc = ".((int) $user->socid);
7926  }
7927  }
7928  if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7929  if (empty($user->rights->societe->client->voir) && !$user->socid) {
7930  $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
7931  }
7932  }
7933  }
7934  if ($searchkey != '') {
7935  $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
7936  }
7937 
7938  if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
7939  /*if (! DolibarrApi::_checkFilters($filter))
7940  {
7941  throw new RestException(503, 'Error when validating parameter sqlfilters '.$filter);
7942  }*/
7943  $regexstring = '\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^\‍(\‍)]+)\‍)';
7944  $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $filter).")";
7945  }
7946  }
7947  $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
7948  //$sql.=$this->db->plimit($limit, 0);
7949  //print $sql;
7950 
7951  // Build output string
7952  $resql = $this->db->query($sql);
7953  if ($resql) {
7954  // Construct $out and $outarray
7955  $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
7956 
7957  // 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
7958  $textifempty = '&nbsp;';
7959 
7960  //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7961  if (!empty($conf->global->$confkeyforautocompletemode)) {
7962  if ($showempty && !is_numeric($showempty)) {
7963  $textifempty = $langs->trans($showempty);
7964  } else {
7965  $textifempty .= $langs->trans("All");
7966  }
7967  }
7968  if ($showempty) {
7969  $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
7970  }
7971 
7972  $num = $this->db->num_rows($resql);
7973  $i = 0;
7974  if ($num) {
7975  while ($i < $num) {
7976  $obj = $this->db->fetch_object($resql);
7977  $label = '';
7978  $tmparray = explode(',', $fieldstoshow);
7979  $oldvalueforshowoncombobox = 0;
7980  foreach ($tmparray as $key => $val) {
7981  $val = preg_replace('/t\./', '', $val);
7982  $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
7983  $label .= $obj->$val;
7984  $oldvalueforshowoncombobox = !empty($objecttmp->fields[$val]['showoncombobox']) ? $objecttmp->fields[$val]['showoncombobox'] : 0;
7985  }
7986  if (empty($outputmode)) {
7987  if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
7988  $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
7989  } else {
7990  $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
7991  }
7992  } else {
7993  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
7994  }
7995 
7996  $i++;
7997  if (($i % 10) == 0) {
7998  $out .= "\n";
7999  }
8000  }
8001  }
8002 
8003  $out .= '</select>'."\n";
8004 
8005  if (!$forcecombo) {
8006  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
8007  $out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
8008  }
8009  } else {
8010  dol_print_error($this->db);
8011  }
8012 
8013  $this->result = array('nbofelement'=>$num);
8014 
8015  if ($outputmode) {
8016  return $outarray;
8017  }
8018  return $out;
8019  }
8020 
8021 
8045  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)
8046  {
8047  global $conf, $langs;
8048 
8049  // Do we want a multiselect ?
8050  //$jsbeautify = 0;
8051  //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8052  $jsbeautify = 1;
8053 
8054  if ($value_as_key) {
8055  $array = array_combine($array, $array);
8056  }
8057 
8058  $out = '';
8059 
8060  if ($addjscombo < 0) {
8061  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8062  $addjscombo = 1;
8063  } else {
8064  $addjscombo = 0;
8065  }
8066  }
8067 
8068  $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8069  $out .= '<select id="'.preg_replace('/^\./', '', $idname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
8070  $out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
8071  $out .= '>';
8072 
8073  if ($show_empty) {
8074  $textforempty = ' ';
8075  if (!empty($conf->use_javascript_ajax)) {
8076  $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8077  }
8078  if (!is_numeric($show_empty)) {
8079  $textforempty = $show_empty;
8080  }
8081  $out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
8082  }
8083 
8084  if (is_array($array)) {
8085  // Translate
8086  if ($translate) {
8087  foreach ($array as $key => $value) {
8088  if (!is_array($value)) {
8089  $array[$key] = $langs->trans($value);
8090  } else {
8091  $array[$key]['label'] = $langs->trans($value['label']);
8092  }
8093  }
8094  }
8095 
8096  // Sort
8097  if ($sort == 'ASC') {
8098  asort($array);
8099  } elseif ($sort == 'DESC') {
8100  arsort($array);
8101  }
8102 
8103  foreach ($array as $key => $tmpvalue) {
8104  if (is_array($tmpvalue)) {
8105  $value = $tmpvalue['label'];
8106  $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8107  $style = empty($tmpvalue['css']) ? '' : ' class="'.$tmpvalue['css'].'"';
8108  } else {
8109  $value = $tmpvalue;
8110  $disabled = '';
8111  $style = '';
8112  }
8113  if (!empty($disablebademail)) {
8114  if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8115  || ($disablebademail == 2 && preg_match('/---/', $value))) {
8116  $disabled = ' disabled';
8117  $style = ' class="warning"';
8118  }
8119  }
8120 
8121  if ($key_in_label) {
8122  if (empty($nohtmlescape)) {
8123  $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
8124  } else {
8125  $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
8126  }
8127  } else {
8128  if (empty($nohtmlescape)) {
8129  $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
8130  } else {
8131  $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8132  }
8133  if ($value == '' || $value == '-') {
8134  $selectOptionValue = '&nbsp;';
8135  }
8136  }
8137 
8138  $out .= '<option value="'.$key.'"';
8139  $out .= $style.$disabled;
8140  if (is_array($id)) {
8141  if (in_array($key, $id) && !$disabled) {
8142  $out .= ' selected'; // To preselect a value
8143  }
8144  } else {
8145  $id = (string) $id; // if $id = 0, then $id = '0'
8146  if ($id != '' && ($id == $key || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
8147  $out .= ' selected'; // To preselect a value
8148  }
8149  }
8150  if ($nohtmlescape) {
8151  $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
8152  }
8153  if (is_array($tmpvalue)) {
8154  foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
8155  if (preg_match('/^data-/', $keyforvalue)) {
8156  $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
8157  }
8158  }
8159  }
8160  $out .= '>';
8161  //var_dump($selectOptionValue);
8162  $out .= $selectOptionValue;
8163  $out .= "</option>\n";
8164  }
8165  }
8166 
8167  $out .= "</select>";
8168 
8169  // Add code for jquery to use multiselect
8170  if ($addjscombo && $jsbeautify) {
8171  // Enhance with select2
8172  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
8173  $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', ($show_empty < 0 ? (string) $show_empty : '-1'), $morecss);
8174  }
8175 
8176  return $out;
8177  }
8178 
8179 
8198  public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8199  {
8200  global $conf, $langs;
8201  global $delayedhtmlcontent; // Will be used later outside of this function
8202 
8203  // TODO Use an internal dolibarr component instead of select2
8204  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8205  return '';
8206  }
8207 
8208  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
8209 
8210  $outdelayed = '';
8211  if (!empty($conf->use_javascript_ajax)) {
8212  $tmpplugin = 'select2';
8213  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8214  <script>
8215  $(document).ready(function () {
8216 
8217  '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
8218 
8219  $(".'.$htmlname.'").select2({
8220  ajax: {
8221  dir: "ltr",
8222  url: "'.$url.'",
8223  dataType: \'json\',
8224  delay: 250,
8225  data: function (params) {
8226  return {
8227  q: params.term, // search term
8228  page: params.page
8229  }
8230  },
8231  processResults: function (data) {
8232  // parse the results into the format expected by Select2.
8233  // since we are using custom formatting functions we do not need to alter the remote JSON data
8234  //console.log(data);
8235  saveRemoteData = data;
8236  /* format json result for select2 */
8237  result = []
8238  $.each( data, function( key, value ) {
8239  result.push({id: key, text: value.text});
8240  });
8241  //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
8242  //console.log(result);
8243  return {results: result, more: false}
8244  },
8245  cache: true
8246  },
8247  language: select2arrayoflanguage,
8248  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8249  placeholder: "'.dol_escape_js($placeholder).'",
8250  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8251  minimumInputLength: '.$minimumInputLength.',
8252  formatResult: function(result, container, query, escapeMarkup) {
8253  return escapeMarkup(result.text);
8254  },
8255  });
8256 
8257  '.($callurlonselect ? '
8258  /* Code to execute a GET when we select a value */
8259  $(".'.$htmlname.'").change(function() {
8260  var selected = $(".'.$htmlname.'").val();
8261  console.log("We select in selectArrayAjax the entry "+selected)
8262  $(".'.$htmlname.'").val(""); /* reset visible combo value */
8263  $.each( saveRemoteData, function( key, value ) {
8264  if (key == selected)
8265  {
8266  console.log("selectArrayAjax - Do a redirect to "+value.url)
8267  location.assign(value.url);
8268  }
8269  });
8270  });' : '').'
8271 
8272  });
8273  </script>';
8274  }
8275 
8276  if ($acceptdelayedhtml) {
8277  $delayedhtmlcontent .= $outdelayed;
8278  } else {
8279  $out .= $outdelayed;
8280  }
8281  return $out;
8282  }
8283 
8302  public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
8303  {
8304  global $conf, $langs;
8305  global $delayedhtmlcontent; // Will be used later outside of this function
8306 
8307  // TODO Use an internal dolibarr component instead of select2
8308  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
8309  return '';
8310  }
8311 
8312  $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
8313 
8314  $formattedarrayresult = array();
8315 
8316  foreach ($array as $key => $value) {
8317  $o = new stdClass();
8318  $o->id = $key;
8319  $o->text = $value['text'];
8320  $o->url = $value['url'];
8321  $formattedarrayresult[] = $o;
8322  }
8323 
8324  $outdelayed = '';
8325  if (!empty($conf->use_javascript_ajax)) {
8326  $tmpplugin = 'select2';
8327  $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8328  <script>
8329  $(document).ready(function () {
8330  var data = '.json_encode($formattedarrayresult).';
8331 
8332  '.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
8333 
8334  $(".'.$htmlname.'").select2({
8335  data: data,
8336  language: select2arrayoflanguage,
8337  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8338  placeholder: "'.dol_escape_js($placeholder).'",
8339  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8340  minimumInputLength: '.$minimumInputLength.',
8341  formatResult: function(result, container, query, escapeMarkup) {
8342  return escapeMarkup(result.text);
8343  },
8344  matcher: function (params, data) {
8345 
8346  if(! data.id) return null;';
8347 
8348  if ($callurlonselect) {
8349  // We forge the url with 'sall='
8350  $outdelayed .= '
8351 
8352  var urlBase = data.url;
8353  var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8354  /* console.log("params.term="+params.term); */
8355  /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8356  saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8357  }
8358 
8359  if (!$disableFiltering) {
8360  $outdelayed .= '
8361 
8362  if(data.text.match(new RegExp(params.term))) {
8363  return data;
8364  }
8365 
8366  return null;';
8367  } else {
8368  $outdelayed .= '
8369 
8370  return data;';
8371  }
8372 
8373  $outdelayed .= '
8374  }
8375  });
8376 
8377  '.($callurlonselect ? '
8378  /* Code to execute a GET when we select a value */
8379  $(".'.$htmlname.'").change(function() {
8380  var selected = $(".'.$htmlname.'").val();
8381  console.log("We select "+selected)
8382 
8383  $(".'.$htmlname.'").val(""); /* reset visible combo value */
8384  $.each( saveRemoteData, function( key, value ) {
8385  if (key == selected)
8386  {
8387  console.log("selectArrayFilter - Do a redirect to "+value.url)
8388  location.assign(value.url);
8389  }
8390  });
8391  });' : '').'
8392 
8393  });
8394  </script>';
8395  }
8396 
8397  if ($acceptdelayedhtml) {
8398  $delayedhtmlcontent .= $outdelayed;
8399  } else {
8400  $out .= $outdelayed;
8401  }
8402  return $out;
8403  }
8404 
8423  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)
8424  {
8425  global $conf, $langs;
8426 
8427  $out = '';
8428 
8429  if ($addjscombo < 0) {
8430  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8431  $addjscombo = 1;
8432  } else {
8433  $addjscombo = 0;
8434  }
8435  }
8436 
8437  // Try also magic suggest
8438  $out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
8439  if (is_array($array) && !empty($array)) {
8440  if ($value_as_key) {
8441  $array = array_combine($array, $array);
8442  }
8443 
8444  if (!empty($array)) {
8445  foreach ($array as $key => $value) {
8446  $tmpkey = $key;
8447  $tmpvalue = $value;
8448  $tmpcolor = '';
8449  $tmppicto = '';
8450  if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
8451  $tmpkey = $value['id'];
8452  $tmpvalue = $value['label'];
8453  $tmpcolor = $value['color'];
8454  $tmppicto = $value['picto'];
8455  }
8456  $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
8457  $newval = ($key_in_label ? $tmpkey.' - '.$newval : $newval);
8458 
8459  $out .= '<option value="'.$tmpkey.'"';
8460  if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
8461  $out .= ' selected';
8462  }
8463  $out .= ' data-html="'.dol_escape_htmltag(($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #'.$tmpcolor.'"') : '').$newval).'"';
8464  $out .= '>';
8465  $out .= dol_htmlentitiesbr($newval);
8466  $out .= '</option>'."\n";
8467  }
8468  }
8469  }
8470  $out .= '</select>'."\n";
8471 
8472  // Add code for jquery to use multiselect
8473  if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8474  $out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->';
8475  $out .= "\n".'<script>'."\n";
8476  if ($addjscombo == 1) {
8477  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
8478  $out .= 'function formatResult(record, container) {'."\n";
8479  $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";
8480  $out .= ' return record.text;';
8481  $out .= '}'."\n";
8482  $out .= 'function formatSelection(record) {'."\n";
8483  if ($elemtype == 'category') {
8484  $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
8485  } else {
8486  $out .= 'return record.text;';
8487  }
8488  $out .= '}'."\n";
8489  $out .= '$(document).ready(function () {
8490  $(\'#'.$htmlname.'\').'.$tmpplugin.'({';
8491  if ($placeholder) {
8492  $out .= '
8493  placeholder: {
8494  id: \'-1\',
8495  text: \''.dol_escape_js($placeholder).'\'
8496  },';
8497  }
8498  $out .= ' dir: \'ltr\',
8499  // Specify format function for dropdown item
8500  formatResult: formatResult,
8501  templateResult: formatResult, /* For 4.0 */
8502  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
8503  // Specify format function for selected item
8504  formatSelection: formatSelection,
8505  templateSelection: formatSelection /* For 4.0 */
8506  });
8507 
8508  /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
8509  the size only if component is not hidden by default on load */
8510  $(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\');
8511  });'."\n";
8512  } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
8513  // Add other js lib
8514  // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
8515  // ...
8516  $out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
8517  $out .= '$(document).ready(function () {
8518  $(\'#'.$htmlname.'\').multiSelect({
8519  containerHTML: \'<div class="multi-select-container">\',
8520  menuHTML: \'<div class="multi-select-menu">\',
8521  buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
8522  menuItemHTML: \'<label class="multi-select-menuitem">\',
8523  activeClass: \'multi-select-container--open\',
8524  noneText: \''.$placeholder.'\'
8525  });
8526  })';
8527  }
8528  $out .= '</script>';
8529  }
8530 
8531  return $out;
8532  }
8533 
8534 
8545  public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
8546  {
8547  global $conf, $langs, $user, $extrafields;
8548 
8549  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8550  return '';
8551  }
8552 
8553  $tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved selected fields to show
8554 
8555  if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
8556  $tmparray = explode(',', $user->conf->$tmpvar);
8557  foreach ($array as $key => $val) {
8558  //var_dump($key);
8559  //var_dump($tmparray);
8560  if (in_array($key, $tmparray)) {
8561  $array[$key]['checked'] = 1;
8562  } else {
8563  $array[$key]['checked'] = 0;
8564  }
8565  }
8566  } else { // There is no list of fields already customized for user
8567  foreach ($array as $key => $val) {
8568  if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
8569  $array[$key]['checked'] = 0;
8570  }
8571  }
8572  }
8573 
8574  $listoffieldsforselection = '';
8575  $listcheckedstring = '';
8576 
8577  foreach ($array as $key => $val) {
8578  // var_dump($val);
8579  // var_dump(array_key_exists('enabled', $val));
8580  // var_dump(!$val['enabled']);
8581  if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
8582  unset($array[$key]); // We don't want this field
8583  continue;
8584  }
8585  if (!empty($val['type']) && $val['type'] == 'separate') {
8586  // Field remains in array but we don't add it into $listoffieldsforselection
8587  //$listoffieldsforselection .= '<li>-----</li>';
8588  continue;
8589  }
8590  if ($val['label']) {
8591  if (!empty($val['langfile']) && is_object($langs)) {
8592  $langs->load($val['langfile']);
8593  }
8594 
8595  // Note: $val['checked'] <> 0 means we must show the field into the combo list
8596  $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>';
8597  $listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
8598  }
8599  }
8600 
8601  $out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
8602 
8603  <dl class="dropdown">
8604  <dt>
8605  <a href="#'.$htmlname.'">
8606  '.img_picto('', 'list').'
8607  </a>
8608  <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
8609  </dt>
8610  <dd class="dropdowndd">
8611  <div class="multiselectcheckbox'.$htmlname.'">
8612  <ul class="'.$htmlname.($pos == '1' ? 'left' : '').'">
8613  '.$listoffieldsforselection.'
8614  </ul>
8615  </div>
8616  </dd>
8617  </dl>
8618 
8619  <script type="text/javascript">
8620  jQuery(document).ready(function () {
8621  $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
8622  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
8623 
8624  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
8625 
8626  var title = $(this).val() + ",";
8627  if ($(this).is(\':checked\')) {
8628  $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
8629  }
8630  else {
8631  $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
8632  }
8633  // Now, we submit page
8634  //$(this).parents(\'form:first\').submit();
8635  });
8636 
8637 
8638  });
8639  </script>
8640 
8641  ';
8642  return $out;
8643  }
8644 
8654  public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
8655  {
8656  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
8657 
8658  $cat = new Categorie($this->db);
8659  $categories = $cat->containing($id, $type);
8660 
8661  if ($rendermode == 1) {
8662  $toprint = array();
8663  foreach ($categories as $c) {
8664  $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
8665  foreach ($ways as $way) {
8666  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>';
8667  }
8668  }
8669  return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
8670  }
8671 
8672  if ($rendermode == 0) {
8673  $arrayselected = array();
8674  $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
8675  foreach ($categories as $c) {
8676  $arrayselected[] = $c->id;
8677  }
8678 
8679  return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
8680  }
8681 
8682  return 'ErrorBadValueForParameterRenderMode'; // Should not happened
8683  }
8684 
8694  public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false, $title = 'RelatedObjects')
8695  {
8696  global $conf, $langs, $hookmanager;
8697  global $bc, $action;
8698 
8699  $object->fetchObjectLinked();
8700 
8701  // Bypass the default method
8702  $hookmanager->initHooks(array('commonobject'));
8703  $parameters = array(
8704  'morehtmlright' => $morehtmlright,
8705  'compatibleImportElementsList' => &$compatibleImportElementsList,
8706  );
8707  $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8708 
8709  if (empty($reshook)) {
8710  $nbofdifferenttypes = count($object->linkedObjects);
8711 
8712  print '<!-- showLinkedObjectBlock -->';
8713  print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
8714 
8715 
8716  print '<div class="div-table-responsive-no-min">';
8717  print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'" data-elementid="'.$object->id.'" >';
8718 
8719  print '<tr class="liste_titre">';
8720  print '<td>'.$langs->trans("Type").'</td>';
8721  print '<td>'.$langs->trans("Ref").'</td>';
8722  print '<td class="center"></td>';
8723  print '<td class="center">'.$langs->trans("Date").'</td>';
8724  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8725  print '<td class="right">'.$langs->trans("Status").'</td>';
8726  print '<td></td>';
8727  print '</tr>';
8728 
8729  $nboftypesoutput = 0;
8730 
8731  foreach ($object->linkedObjects as $objecttype => $objects) {
8732  $tplpath = $element = $subelement = $objecttype;
8733 
8734  // to display inport button on tpl
8735  $showImportButton = false;
8736  if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
8737  $showImportButton = true;
8738  }
8739 
8740  $regs = array();
8741  if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
8742  $element = $regs[1];
8743  $subelement = $regs[2];
8744  $tplpath = $element.'/'.$subelement;
8745  }
8746  $tplname = 'linkedobjectblock';
8747 
8748  // To work with non standard path
8749  if ($objecttype == 'facture') {
8750  $tplpath = 'compta/'.$element;
8751  if (!isModEnabled('facture')) {
8752  continue; // Do not show if module disabled
8753  }
8754  } elseif ($objecttype == 'facturerec') {
8755  $tplpath = 'compta/facture';
8756  $tplname = 'linkedobjectblockForRec';
8757  if (!isModEnabled('facture')) {
8758  continue; // Do not show if module disabled
8759  }
8760  } elseif ($objecttype == 'propal') {
8761  $tplpath = 'comm/'.$element;
8762  if (!isModEnabled('propal')) {
8763  continue; // Do not show if module disabled
8764  }
8765  } elseif ($objecttype == 'supplier_proposal') {
8766  if (!isModEnabled('supplier_proposal')) {
8767  continue; // Do not show if module disabled
8768  }
8769  } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
8770  $tplpath = 'expedition';
8771  if (!isModEnabled('expedition')) {
8772  continue; // Do not show if module disabled
8773  }
8774  } elseif ($objecttype == 'reception') {
8775  $tplpath = 'reception';
8776  if (!isModEnabled('reception')) {
8777  continue; // Do not show if module disabled
8778  }
8779  } elseif ($objecttype == 'delivery') {
8780  $tplpath = 'delivery';
8781  if (!isModEnabled('expedition')) {
8782  continue; // Do not show if module disabled
8783  }
8784  } elseif ($objecttype == 'ficheinter') {
8785  $tplpath = 'fichinter';
8786  if (!isModEnabled('ficheinter')) {
8787  continue; // Do not show if module disabled
8788  }
8789  } elseif ($objecttype == 'invoice_supplier') {
8790  $tplpath = 'fourn/facture';
8791  } elseif ($objecttype == 'order_supplier') {
8792  $tplpath = 'fourn/commande';
8793  } elseif ($objecttype == 'expensereport') {
8794  $tplpath = 'expensereport';
8795  } elseif ($objecttype == 'subscription') {
8796  $tplpath = 'adherents';
8797  } elseif ($objecttype == 'conferenceorbooth') {
8798  $tplpath = 'eventorganization';
8799  } elseif ($objecttype == 'conferenceorboothattendee') {
8800  $tplpath = 'eventorganization';
8801  } elseif ($objecttype == 'mo') {
8802  $tplpath = 'mrp';
8803  if (!isModEnabled('mrp')) {
8804  continue; // Do not show if module disabled
8805  }
8806  }
8807 
8808  global $linkedObjectBlock;
8809  $linkedObjectBlock = $objects;
8810 
8811  // Output template part (modules that overwrite templates must declare this into descriptor)
8812  $dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
8813  foreach ($dirtpls as $reldir) {
8814  if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
8815  global $noMoreLinkedObjectBlockAfter;
8816  $noMoreLinkedObjectBlockAfter = 1;
8817  }
8818 
8819  $res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
8820  if ($res) {
8821  $nboftypesoutput++;
8822  break;
8823  }
8824  }
8825  }
8826 
8827  if (!$nboftypesoutput) {
8828  print '<tr><td class="impair" colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
8829  }
8830 
8831  print '</table>';
8832 
8833  if (!empty($compatibleImportElementsList)) {
8834  $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
8835  }
8836 
8837 
8838  print '</div>';
8839 
8840  return $nbofdifferenttypes;
8841  }
8842  }
8843 
8852  public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
8853  {
8854  global $conf, $langs, $hookmanager;
8855  global $action;
8856 
8857  $linktoelem = '';
8858  $linktoelemlist = '';
8859  $listofidcompanytoscan = '';
8860 
8861  if (!is_object($object->thirdparty)) {
8862  $object->fetch_thirdparty();
8863  }
8864 
8865  $possiblelinks = array();
8866  if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
8867  $listofidcompanytoscan = $object->thirdparty->id;
8868  if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
8869  $listofidcompanytoscan .= ','.$object->thirdparty->parent;
8870  }
8871  if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
8872  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
8873  $tmpproject = new Project($this->db);
8874  $tmpproject->fetch($object->fk_project);
8875  if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
8876  $listofidcompanytoscan .= ','.$tmpproject->socid;
8877  }
8878  unset($tmpproject);
8879  }
8880 
8881  $possiblelinks = array(
8882  'propal'=>array(
8883  'enabled'=>isModEnabled('propal'),
8884  'perms'=>1,
8885  'label'=>'LinkToProposal',
8886  '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').')'),
8887  'shipping'=>array(
8888  'enabled'=>isModEnabled('expedition'),
8889  'perms'=>1,
8890  'label'=>'LinkToExpedition',
8891  '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').')'),
8892  'order'=>array(
8893  'enabled'=>isModEnabled('commande'),
8894  'perms'=>1,
8895  'label'=>'LinkToOrder',
8896  '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').')'),
8897  'invoice'=>array(
8898  'enabled'=>isModEnabled('facture'),
8899  'perms'=>1,
8900  'label'=>'LinkToInvoice',
8901  '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').')'),
8902  'invoice_template'=>array(
8903  'enabled'=>isModEnabled('facture'),
8904  'perms'=>1,
8905  'label'=>'LinkToTemplateInvoice',
8906  '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').')'),
8907  'contrat'=>array(
8908  'enabled'=>isModEnabled('contrat'),
8909  'perms'=>1,
8910  'label'=>'LinkToContract',
8911  '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
8912  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'
8913  ),
8914  'fichinter'=>array(
8915  'enabled'=>isModEnabled('ficheinter'),
8916  'perms'=>1,
8917  'label'=>'LinkToIntervention',
8918  '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').')'),
8919  'supplier_proposal'=>array(
8920  'enabled'=>(isModEnabled('supplier_proposal') ? $conf->supplier_proposal->enabled : 0),
8921  'perms'=>1,
8922  'label'=>'LinkToSupplierProposal',
8923  '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').')'),
8924  'order_supplier'=>array(
8925  'enabled'=>(isModEnabled("supplier_order") ? $conf->supplier_order->enabled : 0),
8926  'perms'=>1,
8927  'label'=>'LinkToSupplierOrder',
8928  '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').')'),
8929  'invoice_supplier'=>array(
8930  'enabled'=>(isModEnabled("supplier_invoice") ? $conf->supplier_invoice->enabled : 0),
8931  'perms'=>1, 'label'=>'LinkToSupplierInvoice',
8932  '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').')'),
8933  'ticket'=>array(
8934  'enabled'=>isModEnabled('ticket'),
8935  'perms'=>1,
8936  'label'=>'LinkToTicket',
8937  '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').')'),
8938  'mo'=>array(
8939  'enabled'=>isModEnabled('mrp'),
8940  'perms'=>1,
8941  'label'=>'LinkToMo',
8942  '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').')')
8943  );
8944  }
8945 
8946  if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
8947  // Can complete the possiblelink array
8948  $hookmanager->initHooks(array('commonobject'));
8949  $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
8950  $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8951  }
8952 
8953  if (empty($reshook)) {
8954  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8955  $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
8956  }
8957  } elseif ($reshook > 0) {
8958  if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8959  $possiblelinks = $hookmanager->resArray;
8960  }
8961  }
8962 
8963  foreach ($possiblelinks as $key => $possiblelink) {
8964  $num = 0;
8965 
8966  if (empty($possiblelink['enabled'])) {
8967  continue;
8968  }
8969 
8970  if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
8971  print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
8972 
8973  if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8974  print '<br><form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
8975  print '<input type="hidden" name="id" value="' . $object->id . '">';
8976  print '<input type="hidden" name="action" value="addlinkbyref">';
8977  print '<input type="hidden" name="token" value="'.newToken().'">';
8978  print '<input type="hidden" name="addlink" value="' . $key . '">';
8979  print '<table class="noborder">';
8980  print '<tr>';
8981  print '<td>' . $langs->trans("Ref") . '</td>';
8982  print '<td><input type="text" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;<input type="submit" class="button valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;<input type="submit" class="button" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
8983  print '</tr>';
8984  print '</table>';
8985  print '</form>';
8986  }
8987 
8988  $sql = $possiblelink['sql'];
8989 
8990  $resqllist = $this->db->query($sql);
8991  if ($resqllist) {
8992  $num = $this->db->num_rows($resqllist);
8993  $i = 0;
8994 
8995  print '<br>';
8996  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
8997  print '<input type="hidden" name="action" value="addlink">';
8998  print '<input type="hidden" name="token" value="'.newToken().'">';
8999  print '<input type="hidden" name="id" value="'.$object->id.'">';
9000  print '<input type="hidden" name="addlink" value="'.$key.'">';
9001  print '<table class="noborder">';
9002  print '<tr class="liste_titre">';
9003  print '<td class="nowrap"></td>';
9004  print '<td class="center">'.$langs->trans("Ref").'</td>';
9005  print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
9006  print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
9007  print '<td class="left">'.$langs->trans("Company").'</td>';
9008  print '</tr>';
9009  while ($i < $num) {
9010  $objp = $this->db->fetch_object($resqllist);
9011 
9012  print '<tr class="oddeven">';
9013  print '<td class="left">';
9014  print '<input type="radio" name="idtolinkto" id="'.$key.'_'.$objp->rowid.'" value="'.$objp->rowid.'">';
9015  print '</td>';
9016  print '<td class="center"><label for="'.$key.'_'.$objp->rowid.'">'.$objp->ref.'</label></td>';
9017  print '<td>'.(!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')).'</td>';
9018  print '<td class="right">';
9019  if ($possiblelink['label'] == 'LinkToContract') {
9020  $form = new Form($this->db);
9021  print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' ';
9022  }
9023  print '<span class="amount">'.(isset($objp->total_ht) ? price($objp->total_ht) : '').'</span>';
9024  print '</td>';
9025  print '<td>'.$objp->name.'</td>';
9026  print '</tr>';
9027  $i++;
9028  }
9029  print '</table>';
9030  print '<div class="center">';
9031  print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly" value="'.$langs->trans('ToLink').'">';
9032  if (empty($conf->use_javascript_ajax)) {
9033  print '<input type="submit" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
9034  } else {
9035  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>';
9036  }
9037  print '</form>';
9038  $this->db->free($resqllist);
9039  } else {
9040  dol_print_error($this->db);
9041  }
9042  print '</div>';
9043 
9044  //$linktoelem.=($linktoelem?' &nbsp; ':'');
9045  if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
9046  $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
9047  // } else $linktoelem.=$langs->trans($possiblelink['label']);
9048  } else {
9049  $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
9050  }
9051  }
9052  }
9053 
9054  if ($linktoelemlist) {
9055  $linktoelem = '
9056  <dl class="dropdown" id="linktoobjectname">
9057  ';
9058  if (!empty($conf->use_javascript_ajax)) {
9059  $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>'.$langs->trans("LinkTo").'...</a></dt>';
9060  }
9061  $linktoelem .= '<dd>
9062  <div class="multiselectlinkto">
9063  <ul class="ulselectedfields">'.$linktoelemlist.'
9064  </ul>
9065  </div>
9066  </dd>
9067  </dl>';
9068  } else {
9069  $linktoelem = '';
9070  }
9071 
9072  if (!empty($conf->use_javascript_ajax)) {
9073  print '<!-- Add js to show linkto box -->
9074  <script>
9075  jQuery(document).ready(function() {
9076  jQuery(".linkto").click(function() {
9077  console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
9078  jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
9079  });
9080  });
9081  </script>
9082  ';
9083  }
9084 
9085  return $linktoelem;
9086  }
9087 
9102  public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '', $labelyes = 'Yes', $labelno = 'No')
9103  {
9104  global $langs;
9105 
9106  $yes = "yes";
9107  $no = "no";
9108  if ($option) {
9109  $yes = "1";
9110  $no = "0";
9111  }
9112 
9113  $disabled = ($disabled ? ' disabled' : '');
9114 
9115  $resultyesno = '<select class="flat width75'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
9116  if ($useempty) {
9117  $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
9118  }
9119  if (("$value" == 'yes') || ($value == 1)) {
9120  $resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans($labelyes).'</option>'."\n";
9121  $resultyesno .= '<option value="'.$no.'">'.$langs->trans($labelno).'</option>'."\n";
9122  } else {
9123  $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
9124  $resultyesno .= '<option value="'.$yes.'">'.$langs->trans($labelyes).'</option>'."\n";
9125  $resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans($labelno).'</option>'."\n";
9126  }
9127  $resultyesno .= '</select>'."\n";
9128 
9129  if ($addjscombo) {
9130  $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
9131  }
9132 
9133  return $resultyesno;
9134  }
9135 
9136  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9146  public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
9147  {
9148  // phpcs:enable
9149  $sql = "SELECT rowid, label";
9150  $sql .= " FROM ".$this->db->prefix()."export_model";
9151  $sql .= " WHERE type = '".$this->db->escape($type)."'";
9152  $sql .= " ORDER BY rowid";
9153  $result = $this->db->query($sql);
9154  if ($result) {
9155  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
9156  if ($useempty) {
9157  print '<option value="-1">&nbsp;</option>';
9158  }
9159 
9160  $num = $this->db->num_rows($result);
9161  $i = 0;
9162  while ($i < $num) {
9163  $obj = $this->db->fetch_object($result);
9164  if ($selected == $obj->rowid) {
9165  print '<option value="'.$obj->rowid.'" selected>';
9166  } else {
9167  print '<option value="'.$obj->rowid.'">';
9168  }
9169  print $obj->label;
9170  print '</option>';
9171  $i++;
9172  }
9173  print "</select>";
9174  } else {
9175  dol_print_error($this->db);
9176  }
9177  }
9178 
9197  public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
9198  {
9199  global $conf, $langs, $hookmanager, $extralanguages;
9200 
9201  $ret = '';
9202  if (empty($fieldid)) {
9203  $fieldid = 'rowid';
9204  }
9205  if (empty($fieldref)) {
9206  $fieldref = 'ref';
9207  }
9208 
9209  // Preparing gender's display if there is one
9210  $addgendertxt = '';
9211  if (property_exists($object, 'gender') && !empty($object->gender)) {
9212  $addgendertxt = ' ';
9213  switch ($object->gender) {
9214  case 'man':
9215  $addgendertxt .= '<i class="fas fa-mars"></i>';
9216  break;
9217  case 'woman':
9218  $addgendertxt .= '<i class="fas fa-venus"></i>';
9219  break;
9220  case 'other':
9221  $addgendertxt .= '<i class="fas fa-transgender"></i>';
9222  break;
9223  }
9224  }
9225 
9226  /*
9227  $addadmin = '';
9228  if (property_exists($object, 'admin')) {
9229  if (isModEnabled('multicompany') && !empty($object->admin) && empty($object->entity)) {
9230  $addadmin .= img_picto($langs->trans("SuperAdministratorDesc"), "redstar", 'class="paddingleft"');
9231  } elseif (!empty($object->admin)) {
9232  $addadmin .= img_picto($langs->trans("AdministratorDesc"), "star", 'class="paddingleft"');
9233  }
9234  }*/
9235 
9236  // Add where from hooks
9237  if (is_object($hookmanager)) {
9238  $parameters = array('showrefnav' => true);
9239  $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
9240  $object->next_prev_filter .= $hookmanager->resPrint;
9241  }
9242  $previous_ref = $next_ref = '';
9243  if ($shownav) {
9244  //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
9245  $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
9246 
9247  $navurl = $_SERVER["PHP_SELF"];
9248  // Special case for project/task page
9249  if ($paramid == 'project_ref') {
9250  if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
9251  $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
9252  $paramid = 'ref';
9253  }
9254  }
9255 
9256  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
9257  // accesskey is for Mac: CTRL + key for all browsers
9258  $stringforfirstkey = $langs->trans("KeyboardShortcut");
9259  if ($conf->browser->name == 'chrome') {
9260  $stringforfirstkey .= ' ALT +';
9261  } elseif ($conf->browser->name == 'firefox') {
9262  $stringforfirstkey .= ' ALT + SHIFT +';
9263  } else {
9264  $stringforfirstkey .= ' CTL +';
9265  }
9266 
9267  $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>';
9268  $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>';
9269  }
9270 
9271  //print "xx".$previous_ref."x".$next_ref;
9272  $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
9273 
9274  // Right part of banner
9275  if ($morehtmlright) {
9276  $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
9277  }
9278 
9279  if ($previous_ref || $next_ref || $morehtml) {
9280  $ret .= '<div class="pagination paginationref"><ul class="right">';
9281  }
9282  if ($morehtml) {
9283  $ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>';
9284  }
9285  if ($shownav && ($previous_ref || $next_ref)) {
9286  $ret .= '<li class="pagination">'.$previous_ref.'</li>';
9287  $ret .= '<li class="pagination">'.$next_ref.'</li>';
9288  }
9289  if ($previous_ref || $next_ref || $morehtml) {
9290  $ret .= '</ul></div>';
9291  }
9292 
9293  $parameters = array();
9294  $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
9295  if (empty($reshook)) {
9296  $morehtmlstatus .= $hookmanager->resPrint;
9297  } else {
9298  $morehtmlstatus = $hookmanager->resPrint;
9299  }
9300  if ($morehtmlstatus) {
9301  $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
9302  }
9303 
9304  $parameters = array();
9305  $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
9306  if (empty($reshook)) {
9307  $morehtmlref .= $hookmanager->resPrint;
9308  } elseif ($reshook > 0) {
9309  $morehtmlref = $hookmanager->resPrint;
9310  }
9311 
9312  // Left part of banner
9313  if ($morehtmlleft) {
9314  if ($conf->browser->layout == 'phone') {
9315  $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
9316  } else {
9317  $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
9318  }
9319  }
9320 
9321  //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
9322  $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
9323 
9324  // For thirdparty, contact, user, member, the ref is the id, so we show something else
9325  if ($object->element == 'societe') {
9326  $ret .= dol_htmlentities($object->name);
9327 
9328  // List of extra languages
9329  $arrayoflangcode = array();
9330  if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
9331  $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
9332  }
9333 
9334  if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
9335  if (!is_object($extralanguages)) {
9336  include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
9337  $extralanguages = new ExtraLanguages($this->db);
9338  }
9339  $extralanguages->fetch_name_extralanguages('societe');
9340 
9341  if (!empty($extralanguages->attributes['societe']['name'])) {
9342  $object->fetchValuesForExtraLanguages();
9343 
9344  $htmltext = '';
9345  // If there is extra languages
9346  foreach ($arrayoflangcode as $extralangcode) {
9347  $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
9348  if ($object->array_languages['name'][$extralangcode]) {
9349  $htmltext .= $object->array_languages['name'][$extralangcode];
9350  } else {
9351  $htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
9352  }
9353  }
9354  $ret .= '<!-- Show translations of name -->'."\n";
9355  $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
9356  }
9357  }
9358  } elseif ($object->element == 'member') {
9359  $ret .= $object->ref.'<br>';
9360  $fullname = $object->getFullName($langs);
9361  if ($object->morphy == 'mor' && $object->societe) {
9362  $ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).$addgendertxt.')' : '');
9363  } else {
9364  $ret .= dol_htmlentities($fullname).$addgendertxt.((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
9365  }
9366  } elseif (in_array($object->element, array('contact', 'user', 'usergroup'))) {
9367  $ret .= dol_htmlentities($object->getFullName($langs)).$addgendertxt;
9368  } elseif (in_array($object->element, array('action', 'agenda'))) {
9369  $ret .= $object->ref.'<br>'.$object->label;
9370  } elseif (in_array($object->element, array('adherent_type'))) {
9371  $ret .= $object->label;
9372  } elseif ($object->element == 'ecm_directories') {
9373  $ret .= '';
9374  } elseif ($fieldref != 'none') {
9375  $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
9376  }
9377 
9378  if ($morehtmlref) {
9379  // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9380  if (substr($morehtmlref, 0, 4) != '<div') {
9381  $ret .= ' ';
9382  }
9383 
9384  $ret .= $morehtmlref;
9385  }
9386 
9387  $ret .= '</div>';
9388 
9389  $ret .= '</div><!-- End banner content -->';
9390 
9391  return $ret;
9392  }
9393 
9394 
9403  public function showbarcode(&$object, $width = 100, $morecss = '')
9404  {
9405  global $conf;
9406 
9407  //Check if barcode is filled in the card
9408  if (empty($object->barcode)) {
9409  return '';
9410  }
9411 
9412  // Complete object if not complete
9413  if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
9414  $result = $object->fetch_barcode();
9415  //Check if fetch_barcode() failed
9416  if ($result < 1) {
9417  return '<!-- ErrorFetchBarcode -->';
9418  }
9419  }
9420 
9421  // Barcode image
9422  $url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
9423  $out = '<!-- url barcode = '.$url.' -->';
9424  $out .= '<img src="'.$url.'"'.($morecss ? ' class="'.$morecss.'"' : '').'>';
9425 
9426  return $out;
9427  }
9428 
9445  public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
9446  {
9447  global $conf, $langs;
9448 
9449  $entity = (!empty($object->entity) ? $object->entity : $conf->entity);
9450  $id = (!empty($object->id) ? $object->id : $object->rowid);
9451 
9452  $ret = '';
9453  $dir = '';
9454  $file = '';
9455  $originalfile = '';
9456  $altfile = '';
9457  $email = '';
9458  $capture = '';
9459  if ($modulepart == 'societe') {
9460  $dir = $conf->societe->multidir_output[$entity];
9461  if (!empty($object->logo)) {
9462  if (dolIsAllowedForPreview($object->logo)) {
9463  if ((string) $imagesize == 'mini') {
9464  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
9465  } elseif ((string) $imagesize == 'small') {
9466  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small');
9467  } else {
9468  $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9469  }
9470  $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9471  }
9472  }
9473  $email = $object->email;
9474  } elseif ($modulepart == 'contact') {
9475  $dir = $conf->societe->multidir_output[$entity].'/contact';
9476  if (!empty($object->photo)) {
9477  if (dolIsAllowedForPreview($object->photo)) {
9478  if ((string) $imagesize == 'mini') {
9479  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9480  } elseif ((string) $imagesize == 'small') {
9481  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small');
9482  } else {
9483  $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9484  }
9485  $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9486  }
9487  }
9488  $email = $object->email;
9489  $capture = 'user';
9490  } elseif ($modulepart == 'userphoto') {
9491  $dir = $conf->user->dir_output;
9492  if (!empty($object->photo)) {
9493  if (dolIsAllowedForPreview($object->photo)) {
9494  if ((string) $imagesize == 'mini') {
9495  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9496  } elseif ((string) $imagesize == 'small') {
9497  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_small');
9498  } else {
9499  $file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9500  }
9501  $originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9502  }
9503  }
9504  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9505  $altfile = $object->id.".jpg"; // For backward compatibility
9506  }
9507  $email = $object->email;
9508  $capture = 'user';
9509  } elseif ($modulepart == 'memberphoto') {
9510  $dir = $conf->adherent->dir_output;
9511  if (!empty($object->photo)) {
9512  if (dolIsAllowedForPreview($object->photo)) {
9513  if ((string) $imagesize == 'mini') {
9514  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9515  } elseif ((string) $imagesize == 'small') {
9516  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
9517  } else {
9518  $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9519  }
9520  $originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9521  }
9522  }
9523  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9524  $altfile = $object->id.".jpg"; // For backward compatibility
9525  }
9526  $email = $object->email;
9527  $capture = 'user';
9528  } else {
9529  // Generic case to show photos
9530  $dir = $conf->$modulepart->dir_output;
9531  if (!empty($object->photo)) {
9532  if (dolIsAllowedForPreview($object->photo)) {
9533  if ((string) $imagesize == 'mini') {
9534  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
9535  } elseif ((string) $imagesize == 'small') {
9536  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
9537  } else {
9538  $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9539  }
9540  $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9541  }
9542  }
9543  if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9544  $altfile = $object->id.".jpg"; // For backward compatibility
9545  }
9546  $email = $object->email;
9547  }
9548 
9549  if ($forcecapture) {
9550  $capture = $forcecapture;
9551  }
9552 
9553  if ($dir) {
9554  if ($file && file_exists($dir."/".$file)) {
9555  if ($addlinktofullsize) {
9556  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9557  if ($urladvanced) {
9558  $ret .= '<a href="'.$urladvanced.'">';
9559  } else {
9560  $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9561  }
9562  }
9563  $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.'">';
9564  if ($addlinktofullsize) {
9565  $ret .= '</a>';
9566  }
9567  } elseif ($altfile && file_exists($dir."/".$altfile)) {
9568  if ($addlinktofullsize) {
9569  $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9570  if ($urladvanced) {
9571  $ret .= '<a href="'.$urladvanced.'">';
9572  } else {
9573  $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9574  }
9575  }
9576  $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.'">';
9577  if ($addlinktofullsize) {
9578  $ret .= '</a>';
9579  }
9580  } else {
9581  $nophoto = '/public/theme/common/nophoto.png';
9582  $defaultimg = 'identicon'; // For gravatar
9583  if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
9584  if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor')) !== false) {
9585  $nophoto = 'company';
9586  } else {
9587  $nophoto = '/public/theme/common/user_anonymous.png';
9588  if (!empty($object->gender) && $object->gender == 'man') {
9589  $nophoto = '/public/theme/common/user_man.png';
9590  }
9591  if (!empty($object->gender) && $object->gender == 'woman') {
9592  $nophoto = '/public/theme/common/user_woman.png';
9593  }
9594  }
9595  }
9596 
9597  if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
9598  // see https://gravatar.com/site/implement/images/php/
9599  $ret .= '<!-- Put link to gravatar -->';
9600  $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
9601  } else {
9602  if ($nophoto == 'company') {
9603  $ret .= '<div class="divforspanimg photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').'>'.img_picto('', 'company').'</div>';
9604  $ret .= '<div class="difforspanimgright"></div>';
9605  } else {
9606  $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
9607  }
9608  }
9609  }
9610 
9611  if ($caneditfield) {
9612  if ($object->photo) {
9613  $ret .= "<br>\n";
9614  }
9615  $ret .= '<table class="nobordernopadding centpercent">';
9616  if ($object->photo) {
9617  $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">'.$langs->trans("Delete").'</label><br><br></td></tr>';
9618  }
9619  $ret .= '<tr><td class="tdoverflow">';
9620  $maxfilesizearray = getMaxFileSizeArray();
9621  $maxmin = $maxfilesizearray['maxmin'];
9622  if ($maxmin > 0) {
9623  $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
9624  }
9625  $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'>';
9626  $ret .= '</td></tr>';
9627  $ret .= '</table>';
9628  }
9629  } else {
9630  dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
9631  }
9632 
9633  return $ret;
9634  }
9635 
9636  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9653  public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
9654  {
9655  // phpcs:enable
9656  global $conf, $user, $langs;
9657 
9658  // Permettre l'exclusion de groupes
9659  $excludeGroups = null;
9660  if (is_array($exclude)) {
9661  $excludeGroups = implode(",", $exclude);
9662  }
9663  // Permettre l'inclusion de groupes
9664  $includeGroups = null;
9665  if (is_array($include)) {
9666  $includeGroups = implode(",", $include);
9667  }
9668 
9669  if (!is_array($selected)) {
9670  $selected = array($selected);
9671  }
9672 
9673  $out = '';
9674 
9675  // On recherche les groupes
9676  $sql = "SELECT ug.rowid, ug.nom as name";
9677  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9678  $sql .= ", e.label";
9679  }
9680  $sql .= " FROM ".$this->db->prefix()."usergroup as ug ";
9681  if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
9682  $sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid=ug.entity";
9683  if ($force_entity) {
9684  $sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
9685  } else {
9686  $sql .= " WHERE ug.entity IS NOT NULL";
9687  }
9688  } else {
9689  $sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
9690  }
9691  if (is_array($exclude) && $excludeGroups) {
9692  $sql .= " AND ug.rowid NOT IN (".$this->db->sanitize($excludeGroups).")";
9693  }
9694  if (is_array($include) && $includeGroups) {
9695  $sql .= " AND ug.rowid IN (".$this->db->sanitize($includeGroups).")";
9696  }
9697  $sql .= " ORDER BY ug.nom ASC";
9698 
9699  dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
9700  $resql = $this->db->query($sql);
9701  if ($resql) {
9702  // Enhance with select2
9703  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9704 
9705  $out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
9706 
9707  $num = $this->db->num_rows($resql);
9708  $i = 0;
9709  if ($num) {
9710  if ($show_empty && !$multiple) {
9711  $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
9712  }
9713 
9714  while ($i < $num) {
9715  $obj = $this->db->fetch_object($resql);
9716  $disableline = 0;
9717  if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
9718  $disableline = 1;
9719  }
9720 
9721  $out .= '<option value="'.$obj->rowid.'"';
9722  if ($disableline) {
9723  $out .= ' disabled';
9724  }
9725  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))) {
9726  $out .= ' selected';
9727  }
9728  $out .= '>';
9729 
9730  $out .= $obj->name;
9731  if (isModEnabled('multicompany') && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
9732  $out .= " (".$obj->label.")";
9733  }
9734 
9735  $out .= '</option>';
9736  $i++;
9737  }
9738  } else {
9739  if ($show_empty) {
9740  $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
9741  }
9742  $out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
9743  }
9744  $out .= '</select>';
9745 
9746  $out .= ajax_combobox($htmlname);
9747  } else {
9748  dol_print_error($this->db);
9749  }
9750 
9751  return $out;
9752  }
9753 
9754 
9761  public function showFilterButtons($pos = '')
9762  {
9763  $out = '<div class="nowraponall">';
9764  if ($pos == 'left') {
9765  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9766  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9767  } else {
9768  $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9769  $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9770  }
9771  $out .= '</div>';
9772 
9773  return $out;
9774  }
9775 
9784  public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9785  {
9786  global $conf, $langs;
9787 
9788  $out = '';
9789 
9790  if (!empty($conf->use_javascript_ajax)) {
9791  $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
9792  }
9793  $out .= '<script>
9794  $(document).ready(function() {
9795  $("#' . $cssclass.'s").click(function() {
9796  if($(this).is(\':checked\')){
9797  console.log("We check all '.$cssclass.' and trigger the change method");
9798  $(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
9799  }
9800  else
9801  {
9802  console.log("We uncheck all");
9803  $(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
9804  }'."\n";
9805  if ($calljsfunction) {
9806  $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
9807  }
9808  $out .= ' });
9809  $(".' . $cssclass.'").change(function() {
9810  $(this).closest("tr").toggleClass("highlight", this.checked);
9811  });
9812  });
9813  </script>';
9814 
9815  return $out;
9816  }
9817 
9827  public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9828  {
9829  $out = $this->showFilterButtons();
9830  if ($addcheckuncheckall) {
9831  $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
9832  }
9833  return $out;
9834  }
9835 
9849  public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
9850  {
9851  global $langs, $user;
9852 
9853  $out = '';
9854  $sql = "SELECT rowid, label FROM ".$this->db->prefix()."c_exp_tax_cat WHERE active = 1";
9855  $sql .= " AND entity IN (0,".getEntity('exp_tax_cat').")";
9856  if (!empty($excludeid)) {
9857  $sql .= " AND rowid NOT IN (".$this->db->sanitize(implode(',', $excludeid)).")";
9858  }
9859  $sql .= " ORDER BY label";
9860 
9861  $resql = $this->db->query($sql);
9862  if ($resql) {
9863  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
9864  if ($useempty) {
9865  $out .= '<option value="0">&nbsp;</option>';
9866  }
9867 
9868  while ($obj = $this->db->fetch_object($resql)) {
9869  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
9870  }
9871  $out .= '</select>';
9872  $out .= ajax_combobox('select_'.$htmlname);
9873 
9874  if (!empty($htmlname) && $user->admin && $info_admin) {
9875  $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
9876  }
9877 
9878  if (!empty($target)) {
9879  $sql = "SELECT c.id FROM ".$this->db->prefix()."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
9880  $resql = $this->db->query($sql);
9881  if ($resql) {
9882  if ($this->db->num_rows($resql) > 0) {
9883  $obj = $this->db->fetch_object($resql);
9884  $out .= '<script>
9885  $(function() {
9886  $("select[name='.$target.']").on("change", function() {
9887  var current_val = $(this).val();
9888  if (current_val == '.$obj->id.') {';
9889  if (!empty($default_selected) || !empty($selected)) {
9890  $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
9891  }
9892 
9893  $out .= '
9894  $("select[name='.$htmlname.']").change();
9895  }
9896  });
9897 
9898  $("select[name='.$htmlname.']").change(function() {
9899 
9900  if ($("select[name='.$target.']").val() == '.$obj->id.') {
9901  // get price of kilometer to fill the unit price
9902  $.ajax({
9903  method: "POST",
9904  dataType: "json",
9905  data: { fk_c_exp_tax_cat: $(this).val(), token: \''.currentToken().'\' },
9906  url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php?'.join('&', $params)).'",
9907  }).done(function( data, textStatus, jqXHR ) {
9908  console.log(data);
9909  if (typeof data.up != "undefined") {
9910  $("input[name=value_unit]").val(data.up);
9911  $("select[name='.$htmlname.']").attr("title", data.title);
9912  } else {
9913  $("input[name=value_unit]").val("");
9914  $("select[name='.$htmlname.']").attr("title", "");
9915  }
9916  });
9917  }
9918  });
9919  });
9920  </script>';
9921  }
9922  }
9923  }
9924  } else {
9925  dol_print_error($this->db);
9926  }
9927 
9928  return $out;
9929  }
9930 
9939  public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
9940  {
9941  global $conf, $langs;
9942 
9943  $out = '';
9944  $sql = "SELECT rowid, range_ik FROM ".$this->db->prefix()."c_exp_tax_range";
9945  $sql .= " WHERE entity = ".$conf->entity." AND active = 1";
9946 
9947  $resql = $this->db->query($sql);
9948  if ($resql) {
9949  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9950  if ($useempty) {
9951  $out .= '<option value="0"></option>';
9952  }
9953 
9954  while ($obj = $this->db->fetch_object($resql)) {
9955  $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
9956  }
9957  $out .= '</select>';
9958  } else {
9959  dol_print_error($this->db);
9960  }
9961 
9962  return $out;
9963  }
9964 
9975  public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
9976  {
9977  global $langs;
9978 
9979  $out = '';
9980  $sql = "SELECT id, code, label FROM ".$this->db->prefix()."c_type_fees";
9981  $sql .= " WHERE active = 1";
9982 
9983  $resql = $this->db->query($sql);
9984  if ($resql) {
9985  $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9986  if ($useempty) {
9987  $out .= '<option value="0"></option>';
9988  }
9989  if ($allchoice) {
9990  $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
9991  }
9992 
9993  $field = 'code';
9994  if ($useid) {
9995  $field = 'id';
9996  }
9997 
9998  while ($obj = $this->db->fetch_object($resql)) {
9999  $key = $langs->trans($obj->code);
10000  $out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
10001  }
10002  $out .= '</select>';
10003  } else {
10004  dol_print_error($this->db);
10005  }
10006 
10007  return $out;
10008  }
10009 
10028  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)
10029  {
10030  global $user, $conf, $langs;
10031 
10032  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
10033 
10034  if (is_null($usertofilter)) {
10035  $usertofilter = $user;
10036  }
10037 
10038  $out = '';
10039 
10040  $hideunselectables = false;
10041  if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
10042  $hideunselectables = true;
10043  }
10044 
10045  if (empty($projectsListId)) {
10046  if (empty($usertofilter->rights->projet->all->lire)) {
10047  $projectstatic = new Project($this->db);
10048  $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
10049  }
10050  }
10051 
10052  // Search all projects
10053  $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
10054  p.title, p.fk_soc, p.fk_statut, p.public,";
10055  $sql .= ' s.nom as name';
10056  $sql .= ' FROM '.$this->db->prefix().'projet as p';
10057  $sql .= ' LEFT JOIN '.$this->db->prefix().'societe as s ON s.rowid = p.fk_soc,';
10058  $sql .= ' '.$this->db->prefix().'facture as f';
10059  $sql .= " WHERE p.entity IN (".getEntity('project').")";
10060  $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
10061  //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
10062  //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
10063  //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
10064  $sql .= " ORDER BY p.ref, f.ref ASC";
10065 
10066  $resql = $this->db->query($sql);
10067  if ($resql) {
10068  // Use select2 selector
10069  if (!empty($conf->use_javascript_ajax)) {
10070  include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
10071  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10072  $out .= $comboenhancement;
10073  $morecss = 'minwidth200imp maxwidth500';
10074  }
10075 
10076  if (empty($option_only)) {
10077  $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
10078  }
10079  if (!empty($show_empty)) {
10080  $out .= '<option value="0" class="optiongrey">';
10081  if (!is_numeric($show_empty)) {
10082  $out .= $show_empty;
10083  } else {
10084  $out .= '&nbsp;';
10085  }
10086  $out .= '</option>';
10087  }
10088  $num = $this->db->num_rows($resql);
10089  $i = 0;
10090  if ($num) {
10091  while ($i < $num) {
10092  $obj = $this->db->fetch_object($resql);
10093  // 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.
10094  if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
10095  // Do nothing
10096  } else {
10097  if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
10098  $i++;
10099  continue;
10100  }
10101 
10102  $labeltoshow = '';
10103 
10104  if ($showproject == 'all') {
10105  $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
10106  if ($obj->name) {
10107  $labeltoshow .= ' - '.$obj->name; // Soc name
10108  }
10109 
10110  $disabled = 0;
10111  if ($obj->fk_statut == Project::STATUS_DRAFT) {
10112  $disabled = 1;
10113  $labeltoshow .= ' - '.$langs->trans("Draft");
10114  } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
10115  if ($discard_closed == 2) {
10116  $disabled = 1;
10117  }
10118  $labeltoshow .= ' - '.$langs->trans("Closed");
10119  } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
10120  $disabled = 1;
10121  $labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
10122  }
10123  }
10124 
10125  if (!empty($selected) && $selected == $obj->rowid) {
10126  $out .= '<option value="'.$obj->rowid.'" selected';
10127  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10128  $out .= '>'.$labeltoshow.'</option>';
10129  } else {
10130  if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
10131  $resultat = '';
10132  } else {
10133  $resultat = '<option value="'.$obj->rowid.'"';
10134  if ($disabled) {
10135  $resultat .= ' disabled';
10136  }
10137  //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
10138  //else $labeltoshow.=' ('.$langs->trans("Private").')';
10139  $resultat .= '>';
10140  $resultat .= $labeltoshow;
10141  $resultat .= '</option>';
10142  }
10143  $out .= $resultat;
10144  }
10145  }
10146  $i++;
10147  }
10148  }
10149  if (empty($option_only)) {
10150  $out .= '</select>';
10151  }
10152 
10153  print $out;
10154 
10155  $this->db->free($resql);
10156  return $num;
10157  } else {
10158  dol_print_error($this->db);
10159  return -1;
10160  }
10161  }
10162 
10176  public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
10177  {
10178  global $user, $conf, $langs;
10179 
10180  $out = '';
10181 
10182  dol_syslog('FactureRec::fetch', LOG_DEBUG);
10183 
10184  $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
10185  //$sql.= ', el.fk_source';
10186  $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
10187  $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
10188  $sql .= " ORDER BY f.titre ASC";
10189 
10190  $resql = $this->db->query($sql);
10191  if ($resql) {
10192  // Use select2 selector
10193  if (!empty($conf->use_javascript_ajax)) {
10194  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10195  $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
10196  $out .= $comboenhancement;
10197  $morecss = 'minwidth200imp maxwidth500';
10198  }
10199 
10200  if (empty($option_only)) {
10201  $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
10202  }
10203  if (!empty($show_empty)) {
10204  $out .= '<option value="0" class="optiongrey">';
10205  if (!is_numeric($show_empty)) {
10206  $out .= $show_empty;
10207  } else {
10208  $out .= '&nbsp;';
10209  }
10210  $out .= '</option>';
10211  }
10212  $num = $this->db->num_rows($resql);
10213  if ($num) {
10214  while ($obj = $this->db->fetch_object($resql)) {
10215  $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
10216 
10217  $disabled = 0;
10218  if (!empty($obj->suspended)) {
10219  $disabled = 1;
10220  $labeltoshow .= ' - ' . $langs->trans("Closed");
10221  }
10222 
10223 
10224  if (!empty($selected) && $selected == $obj->rowid) {
10225  $out .= '<option value="' . $obj->rowid . '" selected';
10226  //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
10227  $out .= '>' . $labeltoshow . '</option>';
10228  } else {
10229  if ($disabled && ($selected != $obj->rowid)) {
10230  $resultat = '';
10231  } else {
10232  $resultat = '<option value="' . $obj->rowid . '"';
10233  if ($disabled) {
10234  $resultat .= ' disabled';
10235  }
10236  $resultat .= '>';
10237  $resultat .= $labeltoshow;
10238  $resultat .= '</option>';
10239  }
10240  $out .= $resultat;
10241  }
10242  }
10243  }
10244  if (empty($option_only)) {
10245  $out .= '</select>';
10246  }
10247 
10248  print $out;
10249 
10250  $this->db->free($resql);
10251  return $num;
10252  } else {
10253  $this->errors[]=$this->db->lasterror;
10254  return -1;
10255  }
10256  }
10257 
10267  public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
10268  {
10269  global $langs;
10270 
10271  $ret = '';
10272 
10273  $ret .= '<div class="divadvancedsearchfieldcomp inline-block">';
10274  //$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
10275  $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
10276  $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("Filters")).'" id="idsubimgproductdistribution"></span>';
10277  //$ret .= $langs->trans("Filters");
10278  $ret .= '</a>';
10279 
10280  $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
10281 
10282  // Show select fields as tags.
10283  $ret .= '<div name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
10284 
10285  if ($search_component_params_hidden) {
10286  if (!preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
10287  $search_component_params_hidden .= '('.$search_component_params_hidden.')';
10288  }
10289  $errormessage = '';
10290  if (!dolCheckFilters($search_component_params_hidden, $errormessage)) {
10291  print 'ERROR in parsing search string';
10292  }
10293  $regexstring = '\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^\‍(\‍)]+)\‍)';
10294  //var_dump($search_component_params_hidden);
10295  $htmltags = preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $search_component_params_hidden);
10296  //var_dump($htmltags);
10297  $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch"><span class="tagsearchdelete select2-selection__choice__remove">x</span> '.$htmltags.'</span>';
10298  }
10299 
10300  //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
10301 
10302  //$ret .= search_component_params
10303  //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
10304  //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
10305 
10306  $show_search_component_params_hidden = 1;
10307  if ($show_search_component_params_hidden) {
10308  $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
10309  }
10310  $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%')) -->";
10311  $ret .= '<input type="hidden" name="search_component_params_hidden" value="'.dol_escape_htmltag($search_component_params_hidden).'">';
10312  // For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
10313  foreach ($arrayofcriterias as $criterias) {
10314  foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
10315  if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
10316  continue;
10317  }
10318  if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
10319  continue;
10320  }
10321  if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
10322  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
10323  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
10324  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
10325  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
10326  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
10327  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
10328  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
10329  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
10330  } else {
10331  $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
10332  }
10333  }
10334  }
10335 
10336  $ret .= '</div>';
10337 
10338  $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";
10339  $ret .= '<input type="text" placeholder="'.$langs->trans("Search").'" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
10340 
10341  $ret .= '</div>';
10342  $ret .= '</div>';
10343 
10344  return $ret;
10345  }
10346 
10356  public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
10357  {
10358  global $langs, $user;
10359 
10360  $retstring = '';
10361 
10362  $TModels = array();
10363 
10364  include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
10365  $formmail = new FormMail($this->db);
10366  $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
10367 
10368  if ($default) {
10369  $TModels[0] = $langs->trans('DefaultMailModel');
10370  }
10371  if ($result > 0) {
10372  foreach ($formmail->lines_model as $model) {
10373  $TModels[$model->id] = $model->label;
10374  }
10375  }
10376 
10377  $retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
10378 
10379  foreach ($TModels as $id_model => $label_model) {
10380  $retstring .= '<option value="'.$id_model.'"';
10381  $retstring .= ">".$label_model."</option>";
10382  }
10383 
10384  $retstring .= "</select>";
10385 
10386  if ($addjscombo) {
10387  $retstring .= ajax_combobox('select_'.$prefix.'model_mail');
10388  }
10389 
10390  return $retstring;
10391  }
10392 
10404  public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = 0, $morecss = '', $dol_openinpopup = '')
10405  {
10406  global $langs;
10407 
10408  $buttons = array();
10409 
10410  $save = array(
10411  'name' => 'save',
10412  'label_key' => $save_label,
10413  );
10414 
10415  if ($save_label == 'Create' || $save_label == 'Add' ) {
10416  $save['name'] = 'add';
10417  } elseif ($save_label == 'Modify') {
10418  $save['name'] = 'edit';
10419  }
10420 
10421  $cancel = array(
10422  'name' => 'cancel',
10423  'label_key' => 'Cancel',
10424  );
10425 
10426  !empty($save_label) ? $buttons[] = $save : '';
10427 
10428  if (!empty($morebuttons)) {
10429  $buttons[] = $morebuttons;
10430  }
10431 
10432  !empty($cancel_label) ? $buttons[] = $cancel : '';
10433 
10434  $retstring = $withoutdiv ? '': '<div class="center">';
10435 
10436  foreach ($buttons as $button) {
10437  $addclass = empty($button['addclass']) ? '' : $button['addclass'];
10438  $retstring .= '<input type="submit" class="button button-'.$button['name'].($morecss ? ' '.$morecss : '').' '.$addclass.'" name="'.$button['name'].'" value="'.dol_escape_htmltag($langs->trans($button['label_key'])).'">';
10439  }
10440  $retstring .= $withoutdiv ? '': '</div>';
10441 
10442  if ($dol_openinpopup) {
10443  $retstring .= '<!-- buttons are shown into a $dol_openinpopup='.$dol_openinpopup.' context, so we enable the close of dialog on cancel -->'."\n";
10444  $retstring .= '<script>';
10445  $retstring .= 'jQuery(".button-cancel").click(function(e) {
10446  e.preventDefault(); console.log(\'We click on cancel in iframe popup '.$dol_openinpopup.'\');
10447  window.parent.jQuery(\'#idfordialog'.$dol_openinpopup.'\').dialog(\'close\');
10448  });';
10449  $retstring .= '</script>';
10450  }
10451 
10452  return $retstring;
10453  }
10454 }
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 operations for stock transfers/corrections allowed (not for customer shipping and ...
const STATUS_OPEN_ALL
Warehouse open and operations for customer shipping, supplier dispatch, internal stock transfers/corr...
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.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_produits_list($selected='', $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1)
Return list of products for a customer.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0)
Return combo list of activated countries, into language of user.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
select_thirdparty_list($selected='', $htmlname='socid', $filter='', $showempty='', $showtype=0, $forcecombo=0, $events=array(), $filterkey='', $outputmode=0, $limit=0, $morecss='minwidth100', $moreparam='', $multiple=false, $excludeids=array(), $showcode=0)
Output html form to select a third party.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minute...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='')
Output the component to make advanced search criteries.
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=0, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array())
Output value of a field for an editable field.
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.
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='')
Show a form to select a project.
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:45
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
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter is valid and will pass the preg_replace_callback() to replace Gener...
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.
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...
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,...