dolibarr  9.0.0
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-2014 Philippe Grand <philippe.grand@atoo-net.com>
14  * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15  * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16  * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17  * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18  * Copyright (C) 2014 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
19  * Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es>
20  * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
21  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22  *
23  * This program is free software; you can redistribute it and/or modify
24  * it under the terms of the GNU General Public License as published by
25  * the Free Software Foundation; either version 3 of the License, or
26  * (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program. If not, see <http://www.gnu.org/licenses/>.
35  */
36 
50 class Form
51 {
55  public $db;
56 
60  public $error='';
61 
65  public $errors = array();
66 
67  public $num;
68 
69  // Cache arrays
70  public $cache_types_paiements=array();
71  public $cache_conditions_paiements=array();
72  public $cache_availability=array();
73  public $cache_demand_reason=array();
74  public $cache_types_fees=array();
75  public $cache_vatrates=array();
76 
77 
83  public function __construct($db)
84  {
85  $this->db = $db;
86  }
87 
103  function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id')
104  {
105  global $conf,$langs;
106 
107  $ret='';
108 
109  // TODO change for compatibility
110  if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! preg_match('/^select;/',$typeofdata))
111  {
112  if (! empty($perm))
113  {
114  $tmp=explode(':',$typeofdata);
115  $ret.= '<div class="editkey_'.$tmp[0].(! empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
116  if ($fieldrequired) $ret.='<span class="fieldrequired">';
117  $ret.= $langs->trans($text);
118  if ($fieldrequired) $ret.='</span>';
119  $ret.= '</div>'."\n";
120  }
121  else
122  {
123  if ($fieldrequired) $ret.='<span class="fieldrequired">';
124  $ret.= $langs->trans($text);
125  if ($fieldrequired) $ret.='</span>';
126  }
127  }
128  else
129  {
130  if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='<table class="nobordernopadding" width="100%"><tr><td class="nowrap">';
131  if ($fieldrequired) $ret.='<span class="fieldrequired">';
132  $ret.=$langs->trans($text);
133  if ($fieldrequired) $ret.='</span>';
134  if (! empty($notabletag)) $ret.=' ';
135  if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='</td>';
136  if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='<td align="right">';
137  if ($htmlname && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='<a href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&amp;'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
138  if (! empty($notabletag) && $notabletag == 1) $ret.=' : ';
139  if (! empty($notabletag) && $notabletag == 3) $ret.=' ';
140  if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='</td>';
141  if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='</tr></table>';
142  }
143 
144  return $ret;
145  }
146 
165  function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=0, $formatfunc='', $paramid='id')
166  {
167  global $conf,$langs,$db;
168 
169  $ret='';
170 
171  // Check parameters
172  if (empty($typeofdata)) return 'ErrorBadParameter';
173 
174  // When option to edit inline is activated
175  if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! preg_match('/^select;|datehourpicker/',$typeofdata)) // TODO add jquery timepicker
176  {
177  $ret.=$this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
178  }
179  else
180  {
181  if (GETPOST('action','aZ09') == 'edit'.$htmlname)
182  {
183  $ret.="\n";
184  $ret.='<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam?'?'.$moreparam:'').'">';
185  $ret.='<input type="hidden" name="action" value="set'.$htmlname.'">';
186  $ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
187  $ret.='<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
188  if (empty($notabletag)) $ret.='<table class="nobordernopadding centpercent" cellpadding="0" cellspacing="0">';
189  if (empty($notabletag)) $ret.='<tr><td>';
190  if (preg_match('/^(string|email)/',$typeofdata))
191  {
192  $tmp=explode(':',$typeofdata);
193  $ret.='<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue?$editvalue:$value).'"'.($tmp[1]?' size="'.$tmp[1].'"':'').'>';
194  }
195  else if (preg_match('/^(numeric|amount)/',$typeofdata))
196  {
197  $tmp=explode(':',$typeofdata);
198  $valuetoshow=price2num($editvalue?$editvalue:$value);
199  $ret.='<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow!=''?price($valuetoshow):'').'"'.($tmp[1]?' size="'.$tmp[1].'"':'').'>';
200  }
201  else if (preg_match('/^text/',$typeofdata) || preg_match('/^note/',$typeofdata))
202  {
203  $tmp=explode(':',$typeofdata);
204  $cols=$tmp[2];
205  $morealt='';
206  if (preg_match('/%/',$cols))
207  {
208  $morealt=' style="width: '.$cols.'"';
209  $cols='';
210  }
211 
212  $valuetoshow = ($editvalue?$editvalue:$value);
213 
214  $ret.='<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1]?$tmp[1]:'20').'"'.($cols?' cols="'.$cols.'"':'class="quatrevingtpercent"').$morealt.'">';
215  $ret.=dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
216  $ret.='</textarea>';
217  }
218  else if ($typeofdata == 'day' || $typeofdata == 'datepicker')
219  {
220  $ret.=$this->selectDate($value,$htmlname,0,0,1,'form'.$htmlname,1,0);
221  }
222  else if ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker')
223  {
224  $ret.=$this->selectDate($value,$htmlname,1,1,1,'form'.$htmlname,1,0);
225  }
226  else if (preg_match('/^select;/',$typeofdata))
227  {
228  $arraydata=explode(',',preg_replace('/^select;/','',$typeofdata));
229  foreach($arraydata as $val)
230  {
231  $tmp=explode(':',$val);
232  $arraylist[$tmp[0]]=$tmp[1];
233  }
234  $ret.=$this->selectarray($htmlname,$arraylist,$value);
235  }
236  else if (preg_match('/^ckeditor/',$typeofdata))
237  {
238  $tmp=explode(':',$typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols
239  require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
240  $doleditor=new DolEditor($htmlname, ($editvalue?$editvalue:$value), ($tmp[2]?$tmp[2]:''), ($tmp[3]?$tmp[3]:'100'), ($tmp[1]?$tmp[1]:'dolibarr_notes'), 'In', ($tmp[5]?$tmp[5]:0), true, true, ($tmp[6]?$tmp[6]:'20'), ($tmp[7]?$tmp[7]:'100'));
241  $ret.=$doleditor->Create(1);
242  }
243  if (empty($notabletag)) $ret.='</td>';
244 
245  if (empty($notabletag)) $ret.='<td align="left">';
246  //else $ret.='<div class="clearboth"></div>';
247  $ret.='<input type="submit" class="button'.(empty($notabletag)?'':' ').'" name="modify" value="'.$langs->trans("Modify").'">';
248  if (preg_match('/ckeditor|textarea/',$typeofdata) && empty($notabletag)) $ret.='<br>'."\n";
249  $ret.='<input type="submit" class="button'.(empty($notabletag)?'':' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
250  if (empty($notabletag)) $ret.='</td>';
251 
252  if (empty($notabletag)) $ret.='</tr></table>'."\n";
253  $ret.='</form>'."\n";
254  }
255  else
256  {
257  if (preg_match('/^(email)/',$typeofdata)) $ret.=dol_print_email($value,0,0,0,0,1);
258  elseif (preg_match('/^(amount|numeric)/',$typeofdata)) $ret.=($value != '' ? price($value,'',$langs,0,-1,-1,$conf->currency) : '');
259  elseif (preg_match('/^text/',$typeofdata) || preg_match('/^note/',$typeofdata)) $ret.=dol_htmlentitiesbr($value);
260  elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret.=dol_print_date($value,'day');
261  elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret.=dol_print_date($value,'dayhour');
262  else if (preg_match('/^select;/',$typeofdata))
263  {
264  $arraydata=explode(',',preg_replace('/^select;/','',$typeofdata));
265  foreach($arraydata as $val)
266  {
267  $tmp=explode(':',$val);
268  $arraylist[$tmp[0]]=$tmp[1];
269  }
270  $ret.=$arraylist[$value];
271  }
272  else if (preg_match('/^ckeditor/',$typeofdata))
273  {
274  $tmpcontent=dol_htmlentitiesbr($value);
275  if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB))
276  {
277  $firstline=preg_replace('/<br>.*/','',$tmpcontent);
278  $firstline=preg_replace('/[\n\r].*/','',$firstline);
279  $tmpcontent=$firstline.((strlen($firstline) != strlen($tmpcontent))?'...':'');
280  }
281  $ret.=$tmpcontent;
282  }
283  else $ret.=$value;
284 
285  if ($formatfunc && method_exists($object, $formatfunc))
286  {
287  $ret=$object->$formatfunc($ret);
288  }
289  }
290  }
291  return $ret;
292  }
293 
307  private function editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
308  {
309  global $conf;
310 
311  $out='';
312 
313  // Check parameters
314  if (preg_match('/^text/',$inputType)) $value = dol_nl2br($value);
315  else if (preg_match('/^numeric/',$inputType)) $value = price($value);
316  else if ($inputType == 'day' || $inputType == 'datepicker') $value = dol_print_date($value, 'day');
317 
318  if ($condition)
319  {
320  $element = false;
321  $table_element = false;
322  $fk_element = false;
323  $loadmethod = false;
324  $savemethod = false;
325  $ext_element = false;
326  $button_only = false;
327  $inputOption = '';
328 
329  if (is_object($object))
330  {
331  $element = $object->element;
332  $table_element = $object->table_element;
333  $fk_element = $object->id;
334  }
335 
336  if (is_object($extObject))
337  {
338  $ext_element = $extObject->element;
339  }
340 
341  if (preg_match('/^(string|email|numeric)/',$inputType))
342  {
343  $tmp=explode(':',$inputType);
344  $inputType=$tmp[0];
345  if (! empty($tmp[1])) $inputOption=$tmp[1];
346  if (! empty($tmp[2])) $savemethod=$tmp[2];
347  $out.= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
348  }
349  else if ((preg_match('/^day$/',$inputType)) || (preg_match('/^datepicker/',$inputType)) || (preg_match('/^datehourpicker/',$inputType)))
350  {
351  $tmp=explode(':',$inputType);
352  $inputType=$tmp[0];
353  if (! empty($tmp[1])) $inputOption=$tmp[1];
354  if (! empty($tmp[2])) $savemethod=$tmp[2];
355 
356  $out.= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
357  }
358  else if (preg_match('/^(select|autocomplete)/',$inputType))
359  {
360  $tmp=explode(':',$inputType);
361  $inputType=$tmp[0]; $loadmethod=$tmp[1];
362  if (! empty($tmp[2])) $savemethod=$tmp[2];
363  if (! empty($tmp[3])) $button_only=true;
364  }
365  else if (preg_match('/^textarea/',$inputType))
366  {
367  $tmp=explode(':',$inputType);
368  $inputType=$tmp[0];
369  $rows=(empty($tmp[1])?'8':$tmp[1]);
370  $cols=(empty($tmp[2])?'80':$tmp[2]);
371  }
372  else if (preg_match('/^ckeditor/',$inputType))
373  {
374  $tmp=explode(':',$inputType);
375  $inputType=$tmp[0]; $toolbar=$tmp[1];
376  if (! empty($tmp[2])) $width=$tmp[2];
377  if (! empty($tmp[3])) $heigth=$tmp[3];
378  if (! empty($tmp[4])) $savemethod=$tmp[4];
379 
380  if (! empty($conf->fckeditor->enabled))
381  {
382  $out.= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
383  }
384  else
385  {
386  $inputType = 'textarea';
387  }
388  }
389 
390  $out.= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
391  $out.= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
392  $out.= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
393  $out.= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
394  if (! empty($savemethod)) $out.= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
395  if (! empty($ext_element)) $out.= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
396  if (! empty($custommsg))
397  {
398  if (is_array($custommsg))
399  {
400  if (!empty($custommsg['success']))
401  $out.= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
402  if (!empty($custommsg['error']))
403  $out.= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
404  }
405  else
406  $out.= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
407  }
408  if ($inputType == 'textarea') {
409  $out.= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n";
410  $out.= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n";
411  }
412  $out.= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
413  $out.= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(! empty($editvalue) ? $editvalue : $value).'</span>'."\n";
414  }
415  else
416  {
417  $out = $value;
418  }
419 
420  return $out;
421  }
422 
442  function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 2, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger='', $forcenowrap=0)
443  {
444  global $conf;
445 
446  if ($incbefore) $text = $incbefore.$text;
447  if (! $htmltext) return $text;
448 
449  $tag='td';
450  if ($notabs == 2) $tag='div';
451  if ($notabs == 3) $tag='span';
452  // Sanitize tooltip
453  //$htmltext=str_replace("\\","\\\\",$htmltext);
454  $htmltext=str_replace("\r","",$htmltext);
455  $htmltext=str_replace("\n","",$htmltext);
456 
457  $extrastyle='';
458  if ($direction < 0) { $extracss=($extracss?$extracss.' ':'').'inline-block'; $extrastyle='padding: 0px; padding-left: 3px !important;'; }
459  if ($direction > 0) { $extracss=($extracss?$extracss.' ':'').'inline-block'; $extrastyle='padding: 0px; padding-right: 3px !important;'; }
460 
461  $classfortooltip='classfortooltip';
462 
463  $s='';$textfordialog='';
464 
465  if ($tooltiptrigger == '')
466  {
467  $htmltext=str_replace('"',"&quot;",$htmltext);
468  }
469  else
470  {
471  $classfortooltip='classfortooltiponclick';
472  $textfordialog.='<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
473  }
474  if ($tooltipon == 2 || $tooltipon == 3)
475  {
476  $paramfortooltipimg=' class="'.$classfortooltip.' inline-block'.($extracss?' '.$extracss:'').'" style="padding: 0px;'.($extrastyle?' '.$extrastyle:'').'"';
477  if ($tooltiptrigger == '') $paramfortooltipimg.=' title="'.($noencodehtmltext?$htmltext:dol_escape_htmltag($htmltext,1)).'"'; // Attribut to put on img tag to store tooltip
478  else $paramfortooltipimg.=' dolid="'.$tooltiptrigger.'"';
479  }
480  else $paramfortooltipimg =($extracss?' class="'.$extracss.'"':'').($extrastyle?' style="'.$extrastyle.'"':''); // Attribut to put on td text tag
481  if ($tooltipon == 1 || $tooltipon == 3)
482  {
483  $paramfortooltiptd=' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss?' '.$extracss:'').'" style="padding: 0px;'.($extrastyle?' '.$extrastyle:'').'" ';
484  if ($tooltiptrigger == '') $paramfortooltiptd.=' title="'.($noencodehtmltext?$htmltext:dol_escape_htmltag($htmltext,1)).'"'; // Attribut to put on td tag to store tooltip
485  else $paramfortooltiptd.=' dolid="'.$tooltiptrigger.'"';
486  }
487  else $paramfortooltiptd =($extracss?' class="'.$extracss.'"':'').($extrastyle?' style="'.$extrastyle.'"':''); // Attribut to put on td text tag
488  if (empty($notabs)) $s.='<table class="nobordernopadding" summary=""><tr style="height: auto;">';
489  elseif ($notabs == 2) $s.='<div class="inline-block'.($forcenowrap?' nowrap':'').'">';
490  // Define value if value is before
491  if ($direction < 0) {
492  $s.='<'.$tag.$paramfortooltipimg;
493  if ($tag == 'td') {
494  $s .= ' valign="top" width="14"';
495  }
496  $s.= '>'.$textfordialog.$img.'</'.$tag.'>';
497  }
498  // Use another method to help avoid having a space in value in order to use this value with jquery
499  // Define label
500  if ((string) $text != '') $s.='<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
501  // Define value if value is after
502  if ($direction > 0) {
503  $s.='<'.$tag.$paramfortooltipimg;
504  if ($tag == 'td') $s .= ' valign="middle" width="14"';
505  $s.= '>'.$textfordialog.$img.'</'.$tag.'>';
506  }
507  if (empty($notabs)) $s.='</tr></table>';
508  elseif ($notabs == 2) $s.='</div>';
509 
510  return $s;
511  }
512 
527  function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 2, $tooltiptrigger='', $forcenowrap=0)
528  {
529  global $conf, $langs;
530 
531  $alt = '';
532  if ($tooltiptrigger) $alt=$langs->transnoentitiesnoconv("ClickToShowHelp");
533 
534  //For backwards compatibility
535  if ($type == '0') $type = 'info';
536  elseif ($type == '1') $type = 'help';
537 
538  // If info or help with no javascript, show only text
539  if (empty($conf->use_javascript_ajax))
540  {
541  if ($type == 'info' || $type == 'help') return $text;
542  else
543  {
544  $alt = $htmltext;
545  $htmltext = '';
546  }
547  }
548 
549  // If info or help with smartphone, show only text (tooltip hover can't works)
550  if (! empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger))
551  {
552  if ($type == 'info' || $type == 'help') return $text;
553  }
554  // If info or help with smartphone, show only text (tooltip on lick does not works with dialog on smaprtphone)
555  if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
556  {
557  if ($type == 'info' || $type == 'help') return $text;
558  }
559 
560  $img='';
561  if ($type == 'info') $img = img_help(0, $alt);
562  elseif ($type == 'help') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
563  elseif ($type == 'superadmin') $img = img_picto($alt, 'redstar');
564  elseif ($type == 'admin') $img = img_picto($alt, 'star');
565  elseif ($type == 'warning') $img = img_warning($alt);
566  elseif ($type != 'none') $img = img_picto($alt, $type); // $type can be an image path
567 
568  return $this->textwithtooltip($text, $htmltext, (($tooltiptrigger && ! $img)?3:2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
569  }
570 
579  function selectMassAction($selected, $arrayofaction, $alwaysvisible=0)
580  {
581  global $conf,$langs,$hookmanager;
582 
583  if (count($arrayofaction) == 0) return;
584 
585  $disabled=0;
586  $ret='<div class="centpercent center">';
587  $ret.='<select class="flat'.(empty($conf->use_javascript_ajax)?'':' hideobject').' massaction massactionselect" name="massaction"'.($disabled?' disabled="disabled"':'').'>';
588 
589  // 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.
590  $parameters=array();
591  $reshook=$hookmanager->executeHooks('addMoreMassActions',$parameters); // Note that $action and $object may have been modified by hook
592  if (empty($reshook))
593  {
594  $ret.='<option value="0"'.($disabled?' disabled="disabled"':'').'>-- '.$langs->trans("SelectAction").' --</option>';
595  foreach($arrayofaction as $code => $label)
596  {
597  $ret.='<option value="'.$code.'"'.($disabled?' disabled="disabled"':'').'>'.$label.'</option>';
598  }
599  }
600  $ret.=$hookmanager->resPrint;
601 
602  $ret.='</select>';
603  // 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
604  $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.
605  $ret.='<input type="submit" disabled name="confirmmassaction" class="button'.(empty($conf->use_javascript_ajax)?'':' hideobject').' massaction massactionconfirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
606  $ret.='</div>';
607 
608  if (! empty($conf->use_javascript_ajax))
609  {
610  $ret.='<!-- JS CODE TO ENABLE mass action select -->
611  <script type="text/javascript">
612  function initCheckForSelect(mode) /* mode is 0 during init of page or click all, 1 when we click on 1 checkbox */
613  {
614  atleastoneselected=0;
615  jQuery(".checkforselect").each(function( index ) {
616  /* console.log( index + ": " + $( this ).text() ); */
617  if ($(this).is(\':checked\')) atleastoneselected++;
618  });
619  console.log("initCheckForSelect mode="+mode+" atleastoneselected="+atleastoneselected);
620  if (atleastoneselected || '.$alwaysvisible.')
621  {
622  jQuery(".massaction").show();
623  '.($selected ? 'if (atleastoneselected) { jQuery(".massactionselect").val("'.$selected.'"); jQuery(".massactionconfirmed").prop(\'disabled\', false); }' : '').'
624  '.($selected ? 'if (! atleastoneselected) { jQuery(".massactionselect").val("0"); jQuery(".massactionconfirmed").prop(\'disabled\', true); } ' : '').'
625  }
626  else
627  {
628  jQuery(".massaction").hide();
629  }
630  }
631 
632  jQuery(document).ready(function () {
633  initCheckForSelect(0);
634  jQuery(".checkforselect").click(function() {
635  initCheckForSelect(1);
636  });
637  jQuery(".massactionselect").change(function() {
638  var massaction = $( this ).val();
639  var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
640  if (massaction == "builddoc")
641  {
642  urlform = urlform + "#show_files";
643  }
644  $( this ).closest("form").attr("action", urlform);
645  console.log("we select a mass action "+massaction+" - "+urlform);
646  /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
647  if ($(this).val() != \'0\')
648  {
649  jQuery(".massactionconfirmed").prop(\'disabled\', false);
650  }
651  else
652  {
653  jQuery(".massactionconfirmed").prop(\'disabled\', true);
654  }
655  });
656  });
657  </script>
658  ';
659  }
660 
661  return $ret;
662  }
663 
664  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
679  function select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0)
680  {
681  // phpcs:enable
682  global $conf,$langs,$mysoc;
683 
684  $langs->load("dict");
685 
686  $out='';
687  $countryArray=array();
688  $favorite=array();
689  $label=array();
690  $atleastonefavorite=0;
691 
692  $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
693  $sql.= " FROM ".MAIN_DB_PREFIX."c_country";
694  $sql.= " WHERE active > 0";
695  //$sql.= " ORDER BY code ASC";
696 
697  dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
698  $resql=$this->db->query($sql);
699  if ($resql)
700  {
701  $out.= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'" '.$htmloption.'>';
702  $num = $this->db->num_rows($resql);
703  $i = 0;
704  if ($num)
705  {
706  $foundselected=false;
707 
708  while ($i < $num)
709  {
710  $obj = $this->db->fetch_object($resql);
711  $countryArray[$i]['rowid'] = $obj->rowid;
712  $countryArray[$i]['code_iso'] = $obj->code_iso;
713  $countryArray[$i]['code_iso3'] = $obj->code_iso3;
714  $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:''));
715  $countryArray[$i]['favorite'] = $obj->favorite;
716  $favorite[$i] = $obj->favorite;
717  $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
718  $i++;
719  }
720 
721  if (empty($disablefavorites)) array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
722  else $countryArray = dol_sort_array($countryArray, 'label');
723 
724  if ($showempty)
725  {
726  $out.='<option value="">&nbsp;</option>'."\n";
727  }
728 
729  if ($addspecialentries) // Add dedicated entries for groups of countries
730  {
731  //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
732  $out.= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
733  $out.= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
734  if ($mysoc->isInEEC()) $out.= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
735  $out.= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
736  $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
737  }
738 
739  foreach ($countryArray as $row)
740  {
741  //if (empty($showempty) && empty($row['rowid'])) continue;
742  if (empty($row['rowid'])) continue;
743 
744  if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) $atleastonefavorite++;
745  if (empty($row['favorite']) && $atleastonefavorite)
746  {
747  $atleastonefavorite=0;
748  $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
749  }
750  if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label']) )
751  {
752  $foundselected=true;
753  $out.= '<option value="'.($usecodeaskey?($usecodeaskey=='code2'?$row['code_iso']:$row['code_iso3']):$row['rowid']).'" selected>';
754  }
755  else
756  {
757  $out.= '<option value="'.($usecodeaskey?($usecodeaskey=='code2'?$row['code_iso']:$row['code_iso3']):$row['rowid']).'">';
758  }
759  if ($row['label']) $out.= dol_trunc($row['label'],$maxlength,'middle');
760  else $out.= '&nbsp;';
761  if ($row['code_iso']) $out.= ' ('.$row['code_iso'] . ')';
762  $out.= '</option>';
763  }
764  }
765  $out.= '</select>';
766  }
767  else
768  {
769  dol_print_error($this->db);
770  }
771 
772  // Make select dynamic
773  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
774  $out .= ajax_combobox('select'.$htmlname);
775 
776  return $out;
777  }
778 
779  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
792  function select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array())
793  {
794  // phpcs:enable
795  global $conf,$langs;
796 
797  $langs->load("dict");
798 
799  $out='';
800  $incotermArray=array();
801 
802  $sql = "SELECT rowid, code";
803  $sql.= " FROM ".MAIN_DB_PREFIX."c_incoterms";
804  $sql.= " WHERE active > 0";
805  $sql.= " ORDER BY code ASC";
806 
807  dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
808  $resql=$this->db->query($sql);
809  if ($resql)
810  {
811  if ($conf->use_javascript_ajax && ! $forcecombo)
812  {
813  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
814  $out .= ajax_combobox($htmlname, $events);
815  }
816 
817  if (!empty($page))
818  {
819  $out .= '<form method="post" action="'.$page.'">';
820  $out .= '<input type="hidden" name="action" value="set_incoterms">';
821  $out .= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
822  }
823 
824  $out.= '<select id="'.$htmlname.'" class="flat selectincoterm minwidth100imp noenlargeonsmartphone" name="'.$htmlname.'" '.$htmloption.'>';
825  $out.= '<option value="0">&nbsp;</option>';
826  $num = $this->db->num_rows($resql);
827  $i = 0;
828  if ($num)
829  {
830  $foundselected=false;
831 
832  while ($i < $num)
833  {
834  $obj = $this->db->fetch_object($resql);
835  $incotermArray[$i]['rowid'] = $obj->rowid;
836  $incotermArray[$i]['code'] = $obj->code;
837  $i++;
838  }
839 
840  foreach ($incotermArray as $row)
841  {
842  if ($selected && ($selected == $row['rowid'] || $selected == $row['code']))
843  {
844  $out.= '<option value="'.$row['rowid'].'" selected>';
845  }
846  else
847  {
848  $out.= '<option value="'.$row['rowid'].'">';
849  }
850 
851  if ($row['code']) $out.= $row['code'];
852 
853  $out.= '</option>';
854  }
855  }
856  $out.= '</select>';
857 
858  $out .= '<input id="location_incoterms" class="maxwidth100onsmartphone" name="location_incoterms" value="'.$location_incoterms.'">';
859 
860  if (!empty($page))
861  {
862  $out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'"></form>';
863  }
864  }
865  else
866  {
867  dol_print_error($this->db);
868  }
869 
870  return $out;
871  }
872 
873  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
885  function select_type_of_lines($selected='',$htmlname='type',$showempty=0,$hidetext=0,$forceall=0)
886  {
887  // phpcs:enable
888  global $db,$langs,$user,$conf;
889 
890  // If product & services are enabled or both disabled.
891  if ($forceall > 0 || (empty($forceall) && ! empty($conf->product->enabled) && ! empty($conf->service->enabled))
892  || (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled)) )
893  {
894  if (empty($hidetext)) print $langs->trans("Type").': ';
895  print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
896  if ($showempty)
897  {
898  print '<option value="-1"';
899  if ($selected == -1) print ' selected';
900  print '>&nbsp;</option>';
901  }
902 
903  print '<option value="0"';
904  if (0 == $selected) print ' selected';
905  print '>'.$langs->trans("Product");
906 
907  print '<option value="1"';
908  if (1 == $selected) print ' selected';
909  print '>'.$langs->trans("Service");
910 
911  print '</select>';
912  //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
913  }
914  if (empty($forceall) && empty($conf->product->enabled) && ! empty($conf->service->enabled))
915  {
916  print $langs->trans("Service");
917  print '<input type="hidden" name="'.$htmlname.'" value="1">';
918  }
919  if (empty($forceall) && ! empty($conf->product->enabled) && empty($conf->service->enabled))
920  {
921  print $langs->trans("Product");
922  print '<input type="hidden" name="'.$htmlname.'" value="0">';
923  }
924  if ($forceall < 0) // This should happened only for contracts when both predefined product and service are disabled.
925  {
926  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
927  }
928  }
929 
930  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
937  {
938  // phpcs:enable
939  global $langs;
940 
941  $num = count($this->cache_types_fees);
942  if ($num > 0) return 0; // Cache already loaded
943 
944  dol_syslog(__METHOD__, LOG_DEBUG);
945 
946  $langs->load("trips");
947 
948  $sql = "SELECT c.code, c.label";
949  $sql.= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
950  $sql.= " WHERE active > 0";
951 
952  $resql=$this->db->query($sql);
953  if ($resql)
954  {
955  $num = $this->db->num_rows($resql);
956  $i = 0;
957 
958  while ($i < $num)
959  {
960  $obj = $this->db->fetch_object($resql);
961 
962  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
963  $label=($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
964  $this->cache_types_fees[$obj->code] = $label;
965  $i++;
966  }
967 
968  asort($this->cache_types_fees);
969 
970  return $num;
971  }
972  else
973  {
974  dol_print_error($this->db);
975  return -1;
976  }
977  }
978 
979  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
988  function select_type_fees($selected='',$htmlname='type',$showempty=0)
989  {
990  // phpcs:enable
991  global $user, $langs;
992 
993  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
994 
995  $this->load_cache_types_fees();
996 
997  print '<select class="flat" name="'.$htmlname.'">';
998  if ($showempty)
999  {
1000  print '<option value="-1"';
1001  if ($selected == -1) print ' selected';
1002  print '>&nbsp;</option>';
1003  }
1004 
1005  foreach($this->cache_types_fees as $key => $value)
1006  {
1007  print '<option value="'.$key.'"';
1008  if ($key == $selected) print ' selected';
1009  print '>';
1010  print $value;
1011  print '</option>';
1012  }
1013 
1014  print '</select>';
1015  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1016  }
1017 
1018 
1019  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1032  function select_thirdparty($selected='', $htmlname='socid', $filter='', $limit=20, $ajaxoptions=array(), $forcecombo=0)
1033  {
1034  // phpcs:enable
1035  return $this->select_thirdparty_list($selected,$htmlname,$filter,1,0,$forcecombo,array(),'',0, $limit);
1036  }
1037 
1038  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1058  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)
1059  {
1060  // phpcs:enable
1061  global $conf,$user,$langs;
1062 
1063  $out='';
1064 
1065  if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && ! $forcecombo)
1066  {
1067  // No immediate load of all database
1068  $placeholder='';
1069  if ($selected && empty($selected_input_value))
1070  {
1071  require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1072  $societetmp = new Societe($this->db);
1073  $societetmp->fetch($selected);
1074  $selected_input_value=$societetmp->name;
1075  unset($societetmp);
1076  }
1077  // mode 1
1078  $urloption='htmlname='.$htmlname.'&outjson=1&filter='.$filter.($showtype?'&showtype='.$showtype:'');
1079  $out.= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1080  $out.='<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
1081  if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1082  else if ($hidelabel > 1) {
1083  $placeholder=' placeholder="'.$langs->trans("RefOrLabel").'"';
1084  if ($hidelabel == 2) {
1085  $out.= img_picto($langs->trans("Search"), 'search');
1086  }
1087  }
1088  $out.= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1089  if ($hidelabel == 3) {
1090  $out.= img_picto($langs->trans("Search"), 'search');
1091  }
1092  }
1093  else
1094  {
1095  // Immediate load of all database
1096  $out.=$this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple);
1097  }
1098 
1099  return $out;
1100  }
1101 
1102  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1122  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)
1123  {
1124  // phpcs:enable
1125  global $conf,$user,$langs;
1126 
1127  $out='';
1128  $num=0;
1129  $outarray=array();
1130 
1131  if ($selected === '') $selected = array();
1132  else if (!is_array($selected)) $selected = array($selected);
1133 
1134  // Clean $filter that may contains sql conditions so sql code
1135  if (function_exists('testSqlAndScriptInject')) {
1136  if (testSqlAndScriptInject($filter, 3)>0) {
1137  $filter ='';
1138  }
1139  }
1140 
1141  // On recherche les societes
1142  $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1143 
1144  if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1145  $sql .= ", s.address, s.zip, s.town";
1146  $sql .= ", dictp.code as country_code";
1147  }
1148 
1149  $sql.= " FROM (".MAIN_DB_PREFIX ."societe as s";
1150  if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1151  $sql.= " )";
1152  if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1153  $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid=s.fk_pays";
1154  }
1155  $sql.= " WHERE s.entity IN (".getEntity('societe').")";
1156  if (! empty($user->socid)) $sql.= " AND s.rowid = ".$user->socid;
1157  if ($filter) $sql.= " AND (".$filter.")";
1158  if (!$user->rights->societe->client->voir && !$user->socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
1159  if (! empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) $sql.= " AND s.status <> 0";
1160  // Add criteria
1161  if ($filterkey && $filterkey != '')
1162  {
1163  $sql.=" AND (";
1164  $prefix=empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE)?'%':''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1165  // For natural search
1166  $scrit = explode(' ', $filterkey);
1167  $i=0;
1168  if (count($scrit) > 1) $sql.="(";
1169  foreach ($scrit as $crit) {
1170  if ($i > 0) $sql.=" AND ";
1171  $sql.="(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1172  $i++;
1173  }
1174  if (count($scrit) > 1) $sql.=")";
1175  if (! empty($conf->barcode->enabled))
1176  {
1177  $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1178  }
1179  $sql.= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1180  $sql.=")";
1181  }
1182  $sql.=$this->db->order("nom","ASC");
1183  $sql.=$this->db->plimit($limit, 0);
1184 
1185  // Build output string
1186  dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1187  $resql=$this->db->query($sql);
1188  if ($resql)
1189  {
1190  if (! $forcecombo)
1191  {
1192  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1193  $out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
1194  }
1195 
1196  // Construct $out and $outarray
1197  $out.= '<select id="'.$htmlname.'" class="flat'.($morecss?' '.$morecss:'').'"'.($moreparam?' '.$moreparam:'').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1198 
1199  $textifempty='';
1200  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1201  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1202  if (! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT))
1203  {
1204  if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
1205  else $textifempty.=$langs->trans("All");
1206  }
1207  if ($showempty) $out.= '<option value="-1">'.$textifempty.'</option>'."\n";
1208 
1209  $num = $this->db->num_rows($resql);
1210  $i = 0;
1211  if ($num)
1212  {
1213  while ($i < $num)
1214  {
1215  $obj = $this->db->fetch_object($resql);
1216  $label='';
1217  if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1218  if (($obj->client) && (!empty($obj->code_client))) {
1219  $label = $obj->code_client. ' - ';
1220  }
1221  if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1222  $label .= $obj->code_fournisseur. ' - ';
1223  }
1224  $label.=' '.$obj->name;
1225  }
1226  else
1227  {
1228  $label=$obj->name;
1229  }
1230 
1231  if(!empty($obj->name_alias)) {
1232  $label.=' ('.$obj->name_alias.')';
1233  }
1234 
1235  if ($showtype)
1236  {
1237  if ($obj->client || $obj->fournisseur) $label.=' (';
1238  if ($obj->client == 1 || $obj->client == 3) $label.=$langs->trans("Customer");
1239  if ($obj->client == 2 || $obj->client == 3) $label.=($obj->client==3?', ':'').$langs->trans("Prospect");
1240  if ($obj->fournisseur) $label.=($obj->client?', ':'').$langs->trans("Supplier");
1241  if ($obj->client || $obj->fournisseur) $label.=')';
1242  }
1243 
1244  if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1245  $label.='-'.$obj->address.'-'. $obj->zip.' '. $obj->town;
1246  if (!empty($obj->country_code)) {
1247  $label.= ' '. $langs->trans('Country'.$obj->country_code);
1248  }
1249  }
1250 
1251  if (empty($outputmode))
1252  {
1253  if (in_array($obj->rowid,$selected))
1254  {
1255  $out.= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1256  }
1257  else
1258  {
1259  $out.= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1260  }
1261  }
1262  else
1263  {
1264  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1265  }
1266 
1267  $i++;
1268  if (($i % 10) == 0) $out.="\n";
1269  }
1270  }
1271  $out.= '</select>'."\n";
1272  }
1273  else
1274  {
1275  dol_print_error($this->db);
1276  }
1277 
1278  $this->result=array('nbofthirdparties'=>$num);
1279 
1280  if ($outputmode) return $outarray;
1281  return $out;
1282  }
1283 
1284 
1285  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1296  function select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
1297  {
1298  // phpcs:enable
1299  global $langs,$conf;
1300 
1301  // On recherche les remises
1302  $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1303  $sql.= " re.description, re.fk_facture_source";
1304  $sql.= " FROM ".MAIN_DB_PREFIX ."societe_remise_except as re";
1305  $sql.= " WHERE re.fk_soc = ".(int) $socid;
1306  $sql.= " AND re.entity = " . $conf->entity;
1307  if ($filter) $sql.= " AND ".$filter;
1308  $sql.= " ORDER BY re.description ASC";
1309 
1310  dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1311  $resql=$this->db->query($sql);
1312  if ($resql)
1313  {
1314  print '<select class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1315  $num = $this->db->num_rows($resql);
1316 
1317  $qualifiedlines=$num;
1318 
1319  $i = 0;
1320  if ($num)
1321  {
1322  print '<option value="0">&nbsp;</option>';
1323  while ($i < $num)
1324  {
1325  $obj = $this->db->fetch_object($resql);
1326  $desc=dol_trunc($obj->description,40);
1327  if (preg_match('/\(CREDIT_NOTE\)/', $desc)) $desc=preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1328  if (preg_match('/\(DEPOSIT\)/', $desc)) $desc=preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1329  if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) $desc=preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1330  if (preg_match('/\(EXCESS PAID\)/', $desc)) $desc=preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1331 
1332  $selectstring='';
1333  if ($selected > 0 && $selected == $obj->rowid) $selectstring=' selected';
1334 
1335  $disabled='';
1336  if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue)
1337  {
1338  $qualifiedlines--;
1339  $disabled=' disabled';
1340  }
1341 
1342  if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source))
1343  {
1344  $tmpfac = new Facture($this->db);
1345  if ($tmpfac->fetch($obj->fk_facture_source) > 0) $desc=$desc.' - '.$tmpfac->ref;
1346  }
1347 
1348  print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1349  $i++;
1350  }
1351  }
1352  print '</select>';
1353  return $qualifiedlines;
1354  }
1355  else
1356  {
1357  dol_print_error($this->db);
1358  return -1;
1359  }
1360  }
1361 
1362  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1383  function select_contacts($socid,$selected='',$htmlname='contactid',$showempty=0,$exclude='',$limitto='',$showfunction=0, $moreclass='', $showsoc=0, $forcecombo=0, $events=array(), $options_only=false, $moreparam='', $htmlid='')
1384  {
1385  // phpcs:enable
1386  print $this->selectcontacts($socid,$selected,$htmlname,$showempty,$exclude,$limitto,$showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1387  return $this->num;
1388  }
1389 
1411  function selectcontacts($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $moreclass='', $options_only=false, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false)
1412  {
1413  global $conf,$langs;
1414 
1415  $langs->load('companies');
1416 
1417  if (empty($htmlid)) $htmlid = $htmlname;
1418 
1419  if ($selected === '') $selected = array();
1420  else if (!is_array($selected)) $selected = array($selected);
1421  $out='';
1422 
1423  // On recherche les societes
1424  $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste";
1425  if ($showsoc > 0) $sql.= " , s.nom as company";
1426  $sql.= " FROM ".MAIN_DB_PREFIX ."socpeople as sp";
1427  if ($showsoc > 0) $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX ."societe as s ON s.rowid=sp.fk_soc";
1428  $sql.= " WHERE sp.entity IN (".getEntity('socpeople').")";
1429  if ($socid > 0 || $socid == -1) $sql.= " AND sp.fk_soc=".$socid;
1430  if (! empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) $sql.= " AND sp.statut <> 0";
1431  $sql.= " ORDER BY sp.lastname ASC";
1432 
1433  dol_syslog(get_class($this)."::select_contacts", LOG_DEBUG);
1434  $resql=$this->db->query($sql);
1435  if ($resql)
1436  {
1437  $num=$this->db->num_rows($resql);
1438 
1439  if ($conf->use_javascript_ajax && ! $forcecombo && ! $options_only)
1440  {
1441  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1442  $out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
1443  }
1444 
1445  if ($htmlname != 'none' && ! $options_only) $out.= '<select class="flat'.($moreclass?' '.$moreclass:'').'" id="'.$htmlid.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1446  if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) $out.= '<option value="0"'.(in_array(0,$selected)?' selected':'').'>&nbsp;</option>';
1447  if ($showempty == 2) $out.= '<option value="0"'.(in_array(0,$selected)?' selected':'').'>'.$langs->trans("Internal").'</option>';
1448 
1449  $num = $this->db->num_rows($resql);
1450  $i = 0;
1451  if ($num)
1452  {
1453  include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1454  $contactstatic=new Contact($this->db);
1455 
1456  while ($i < $num)
1457  {
1458  $obj = $this->db->fetch_object($resql);
1459 
1460  $contactstatic->id=$obj->rowid;
1461  $contactstatic->lastname=$obj->lastname;
1462  $contactstatic->firstname=$obj->firstname;
1463  if ($obj->statut == 1){
1464  if ($htmlname != 'none')
1465  {
1466  $disabled=0;
1467  if (is_array($exclude) && count($exclude) && in_array($obj->rowid,$exclude)) $disabled=1;
1468  if (is_array($limitto) && count($limitto) && ! in_array($obj->rowid,$limitto)) $disabled=1;
1469  if (!empty($selected) && in_array($obj->rowid, $selected))
1470  {
1471  $out.= '<option value="'.$obj->rowid.'"';
1472  if ($disabled) $out.= ' disabled';
1473  $out.= ' selected>';
1474  $out.= $contactstatic->getFullName($langs);
1475  if ($showfunction && $obj->poste) $out.= ' ('.$obj->poste.')';
1476  if (($showsoc > 0) && $obj->company) $out.= ' - ('.$obj->company.')';
1477  $out.= '</option>';
1478  }
1479  else
1480  {
1481  $out.= '<option value="'.$obj->rowid.'"';
1482  if ($disabled) $out.= ' disabled';
1483  $out.= '>';
1484  $out.= $contactstatic->getFullName($langs);
1485  if ($showfunction && $obj->poste) $out.= ' ('.$obj->poste.')';
1486  if (($showsoc > 0) && $obj->company) $out.= ' - ('.$obj->company.')';
1487  $out.= '</option>';
1488  }
1489  }
1490  else
1491  {
1492  if (in_array($obj->rowid, $selected))
1493  {
1494  $out.= $contactstatic->getFullName($langs);
1495  if ($showfunction && $obj->poste) $out.= ' ('.$obj->poste.')';
1496  if (($showsoc > 0) && $obj->company) $out.= ' - ('.$obj->company.')';
1497  }
1498  }
1499  }
1500  $i++;
1501  }
1502  }
1503  else
1504  {
1505  $out.= '<option value="-1"'.(($showempty==2 || $multiple) ? '' : ' selected').' disabled>';
1506  $out.= ($socid != -1) ? ($langs->trans($socid?"NoContactDefinedForThirdParty":"NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1507  $out.= '</option>';
1508  }
1509  if ($htmlname != 'none' && ! $options_only)
1510  {
1511  $out.= '</select>';
1512  }
1513 
1514  $this->num = $num;
1515  return $out;
1516  }
1517  else
1518  {
1519  dol_print_error($this->db);
1520  return -1;
1521  }
1522  }
1523 
1524  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1540  function select_users($selected='',$htmlname='userid',$show_empty=0,$exclude=null,$disabled=0,$include='',$enableonly='',$force_entity='0')
1541  {
1542  // phpcs:enable
1543  print $this->select_dolusers($selected,$htmlname,$show_empty,$exclude,$disabled,$include,$enableonly,$force_entity);
1544  }
1545 
1546  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1570  function select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $noactive=0, $outputmode=0, $multiple=false)
1571  {
1572  // phpcs:enable
1573  global $conf,$user,$langs;
1574 
1575  // If no preselected user defined, we take current user
1576  if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) $selected=$user->id;
1577 
1578  if ($selected === '') $selected = array();
1579  else if (!is_array($selected)) $selected = array($selected);
1580 
1581  $excludeUsers=null;
1582  $includeUsers=null;
1583 
1584  // Permettre l'exclusion d'utilisateurs
1585  if (is_array($exclude)) $excludeUsers = implode(",",$exclude);
1586  // Permettre l'inclusion d'utilisateurs
1587  if (is_array($include)) $includeUsers = implode(",",$include);
1588  else if ($include == 'hierarchy')
1589  {
1590  // Build list includeUsers to have only hierarchy
1591  $includeUsers = implode(",",$user->getAllChildIds(0));
1592  }
1593  else if ($include == 'hierarchyme')
1594  {
1595  // Build list includeUsers to have only hierarchy and current user
1596  $includeUsers = implode(",",$user->getAllChildIds(1));
1597  }
1598 
1599  $out='';
1600  $outarray = array();
1601 
1602  // Forge request to select users
1603  $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut, u.login, u.admin, u.entity";
1604  if (! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
1605  {
1606  $sql.= ", e.label";
1607  }
1608  $sql.= " FROM ".MAIN_DB_PREFIX ."user as u";
1609  if (! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
1610  {
1611  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX ."entity as e ON e.rowid=u.entity";
1612  if ($force_entity) $sql.= " WHERE u.entity IN (0,".$force_entity.")";
1613  else $sql.= " WHERE u.entity IS NOT NULL";
1614  }
1615  else
1616  {
1617  if (! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
1618  {
1619  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
1620  $sql.= " ON ug.fk_user = u.rowid";
1621  $sql.= " WHERE ug.entity = ".$conf->entity;
1622  }
1623  else
1624  {
1625  $sql.= " WHERE u.entity IN (0,".$conf->entity.")";
1626  }
1627  }
1628  if (! empty($user->societe_id)) $sql.= " AND u.fk_soc = ".$user->societe_id;
1629  if (is_array($exclude) && $excludeUsers) $sql.= " AND u.rowid NOT IN (".$excludeUsers.")";
1630  if ($includeUsers) $sql.= " AND u.rowid IN (".$includeUsers.")";
1631  if (! empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) $sql.= " AND u.statut <> 0";
1632  if (! empty($morefilter)) $sql.=" ".$morefilter;
1633 
1634  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1635  {
1636  $sql.= " ORDER BY u.firstname ASC";
1637  }
1638  else
1639  {
1640  $sql.= " ORDER BY u.lastname ASC";
1641  }
1642 
1643  dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1644  $resql=$this->db->query($sql);
1645  if ($resql)
1646  {
1647  $num = $this->db->num_rows($resql);
1648  $i = 0;
1649  if ($num)
1650  {
1651  // Enhance with select2
1652  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1653  $out .= ajax_combobox($htmlname);
1654 
1655  // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1656  $out.= '<select class="flat'.($morecss?' minwidth100 '.$morecss:' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled?' disabled':'').'>';
1657  if ($show_empty && !$multiple) $out.= '<option value="-1"'.((empty($selected) || in_array(-1,$selected))?' selected':'').'>&nbsp;</option>'."\n";
1658  if ($show_every) $out.= '<option value="-2"'.((in_array(-2,$selected))?' selected':'').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
1659 
1660  $userstatic=new User($this->db);
1661 
1662  while ($i < $num)
1663  {
1664  $obj = $this->db->fetch_object($resql);
1665 
1666  $userstatic->id=$obj->rowid;
1667  $userstatic->lastname=$obj->lastname;
1668  $userstatic->firstname=$obj->firstname;
1669 
1670  $disableline='';
1671  if (is_array($enableonly) && count($enableonly) && ! in_array($obj->rowid,$enableonly)) $disableline=($enableonlytext?$enableonlytext:'1');
1672 
1673  if ((is_object($selected) && $selected->id == $obj->rowid) || (! is_object($selected) && in_array($obj->rowid,$selected) ))
1674  {
1675  $out.= '<option value="'.$obj->rowid.'"';
1676  if ($disableline) $out.= ' disabled';
1677  $out.= ' selected>';
1678  }
1679  else
1680  {
1681  $out.= '<option value="'.$obj->rowid.'"';
1682  if ($disableline) $out.= ' disabled';
1683  $out.= '>';
1684  }
1685 
1686  // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
1687  $fullNameMode = 0;
1688  if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))
1689  {
1690  $fullNameMode = 1; //Firstname+lastname
1691  }
1692  $out.= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1693 
1694  // Complete name with more info
1695  $moreinfo=0;
1696  if (! empty($conf->global->MAIN_SHOW_LOGIN))
1697  {
1698  $out.= ($moreinfo?' - ':' (').$obj->login;
1699  $moreinfo++;
1700  }
1701  if ($showstatus >= 0)
1702  {
1703  if ($obj->statut == 1 && $showstatus == 1)
1704  {
1705  $out.=($moreinfo?' - ':' (').$langs->trans('Enabled');
1706  $moreinfo++;
1707  }
1708  if ($obj->statut == 0)
1709  {
1710  $out.=($moreinfo?' - ':' (').$langs->trans('Disabled');
1711  $moreinfo++;
1712  }
1713  }
1714  if (! empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && ! $user->entity)
1715  {
1716  if (! $obj->entity)
1717  {
1718  $out.=($moreinfo?' - ':' (').$langs->trans("AllEntities");
1719  $moreinfo++;
1720  }
1721  else
1722  {
1723  $out.=($moreinfo?' - ':' (').($obj->label?$obj->label:$langs->trans("EntityNameNotDefined"));
1724  $moreinfo++;
1725  }
1726  }
1727  $out.=($moreinfo?')':'');
1728  if ($disableline && $disableline != '1')
1729  {
1730  $out.=' - '.$disableline; // This is text from $enableonlytext parameter
1731  }
1732  $out.= '</option>';
1733  $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1734 
1735  $i++;
1736  }
1737  }
1738  else
1739  {
1740  $out.= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
1741  $out.= '<option value="">'.$langs->trans("None").'</option>';
1742  }
1743  $out.= '</select>';
1744  }
1745  else
1746  {
1747  dol_print_error($this->db);
1748  }
1749 
1750  if ($outputmode) return $outarray;
1751  return $out;
1752  }
1753 
1754 
1755  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1778  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())
1779  {
1780  // phpcs:enable
1781  global $conf, $user, $langs;
1782 
1783  $userstatic=new User($this->db);
1784  $out='';
1785 
1786  // Method with no ajax
1787  //$out.='<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
1788  if ($action == 'view')
1789  {
1790  $out.='';
1791  }
1792  else
1793  {
1794  $out.='<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
1795  $out.='<script type="text/javascript" language="javascript">jQuery(document).ready(function () { jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });})</script>';
1796  $out.=$this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
1797  $out.=' <input type="submit" class="button valignmiddle" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
1798  $out.='<br>';
1799  }
1800  $assignedtouser=array();
1801  if (!empty($_SESSION['assignedtouser']))
1802  {
1803  $assignedtouser=json_decode($_SESSION['assignedtouser'], true);
1804  }
1805  $nbassignetouser=count($assignedtouser);
1806 
1807  if ($nbassignetouser && $action != 'view') $out.='<br>';
1808  if ($nbassignetouser) $out.='<ul class="attendees">';
1809  $i=0; $ownerid=0;
1810  foreach($assignedtouser as $key => $value)
1811  {
1812  if ($value['id'] == $ownerid) continue;
1813 
1814  $out.='<li>';
1815  $userstatic->fetch($value['id']);
1816  $out.= $userstatic->getNomUrl(-1);
1817  if ($i == 0) { $ownerid = $value['id']; $out.=' ('.$langs->trans("Owner").')'; }
1818  if ($nbassignetouser > 1 && $action != 'view')
1819  {
1820  $out.=' <input type="image" style="border: 0px;" src="'.img_picto($langs->trans("Remove"), 'delete', '', 0, 1).'" value="'.$userstatic->id.'" class="removedassigned" id="removedassigned_'.$userstatic->id.'" name="removedassigned_'.$userstatic->id.'">';
1821  }
1822  // Show my availability
1823  if ($showproperties)
1824  {
1825  if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid)))
1826  {
1827  $out.='<div class="myavailability inline-block">';
1828  $out.='&nbsp;-&nbsp;<span class="opacitymedium">'.$langs->trans("Availability").':</span> <input id="transparency" class="marginleftonly marginrightonly" '.($action == 'view'?'disabled':'').' type="checkbox" name="transparency"'.($listofuserid[$ownerid]['transparency']?' checked':'').'>'.$langs->trans("Busy");
1829  $out.='</div>';
1830  }
1831  }
1832  //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
1833  //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
1834 
1835  $out.='</li>';
1836  $i++;
1837  }
1838  if ($nbassignetouser) $out.='</ul>';
1839 
1840  //$out.='</form>';
1841  return $out;
1842  }
1843 
1844 
1845  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1871  function select_produits($selected='', $htmlname='productid', $filtertype='', $limit=20, $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 = array())
1872  {
1873  // phpcs:enable
1874  global $langs,$conf;
1875 
1876  $price_level = (! empty($price_level) ? $price_level : 0);
1877 
1878  if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
1879  {
1880  $placeholder='';
1881 
1882  if ($selected && empty($selected_input_value))
1883  {
1884  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1885  $producttmpselect = new Product($this->db);
1886  $producttmpselect->fetch($selected);
1887  $selected_input_value=$producttmpselect->ref;
1888  unset($producttmpselect);
1889  }
1890  // mode=1 means customers products
1891  $urloption='htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
1892  //Price by customer
1893  if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
1894  $urloption.='&socid='.$socid;
1895  }
1896  print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1897 
1898  if (!empty($conf->variants->enabled)) {
1899  ?>
1900  <script>
1901 
1902  selected = <?php echo json_encode($selected_combinations) ?>;
1903  combvalues = {};
1904 
1905  jQuery(document).ready(function () {
1906 
1907  jQuery("input[name='prod_entry_mode']").change(function () {
1908  if (jQuery(this).val() == 'free') {
1909  jQuery('div#attributes_box').empty();
1910  }
1911  });
1912 
1913  jQuery("input#<?php echo $htmlname ?>").change(function () {
1914 
1915  if (!jQuery(this).val()) {
1916  jQuery('div#attributes_box').empty();
1917  return;
1918  }
1919 
1920  jQuery.getJSON("<?php echo dol_buildpath('/variants/ajax/getCombinations.php', 2) ?>", {
1921  id: jQuery(this).val()
1922  }, function (data) {
1923  jQuery('div#attributes_box').empty();
1924 
1925  jQuery.each(data, function (key, val) {
1926 
1927  combvalues[val.id] = val.values;
1928 
1929  var span = jQuery(document.createElement('div')).css({
1930  'display': 'table-row'
1931  });
1932 
1933  span.append(
1934  jQuery(document.createElement('div')).text(val.label).css({
1935  'font-weight': 'bold',
1936  'display': 'table-cell',
1937  'text-align': 'right'
1938  })
1939  );
1940 
1941  var html = jQuery(document.createElement('select')).attr('name', 'combinations[' + val.id + ']').css({
1942  'margin-left': '15px',
1943  'white-space': 'pre'
1944  }).append(
1945  jQuery(document.createElement('option')).val('')
1946  );
1947 
1948  jQuery.each(combvalues[val.id], function (key, val) {
1949  var tag = jQuery(document.createElement('option')).val(val.id).html(val.value);
1950 
1951  if (selected[val.fk_product_attribute] == val.id) {
1952  tag.attr('selected', 'selected');
1953  }
1954 
1955  html.append(tag);
1956  });
1957 
1958  span.append(html);
1959  jQuery('div#attributes_box').append(span);
1960  });
1961  })
1962  });
1963 
1964  <?php if ($selected): ?>
1965  jQuery("input#<?php echo $htmlname ?>").change();
1966  <?php endif ?>
1967  });
1968  </script>
1969  <?php
1970  }
1971  if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1972  else if ($hidelabel > 1) {
1973  $placeholder=' placeholder="'.$langs->trans("RefOrLabel").'"';
1974  if ($hidelabel == 2) {
1975  print img_picto($langs->trans("Search"), 'search');
1976  }
1977  }
1978  print '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1979  if ($hidelabel == 3) {
1980  print img_picto($langs->trans("Search"), 'search');
1981  }
1982  }
1983  else
1984  {
1985  print $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
1986  }
1987  }
1988 
1989  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2013  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='')
2014  {
2015  // phpcs:enable
2016  global $langs,$conf,$user,$db;
2017 
2018  $out='';
2019  $outarray=array();
2020 
2021  $warehouseStatusArray = array();
2022  if (! empty($warehouseStatus))
2023  {
2024  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2025  if (preg_match('/warehouseclosed/', $warehouseStatus))
2026  {
2027  $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2028  }
2029  if (preg_match('/warehouseopen/', $warehouseStatus))
2030  {
2031  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2032  }
2033  if (preg_match('/warehouseinternal/', $warehouseStatus))
2034  {
2035  $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2036  }
2037  }
2038 
2039  $selectFields = " p.rowid, p.label, p.ref, p.description, p.barcode, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.duration, p.fk_price_expression";
2040  (count($warehouseStatusArray)) ? $selectFieldsGrouped = ", sum(ps.reel) as stock" : $selectFieldsGrouped = ", p.stock";
2041 
2042  $sql = "SELECT ";
2043  $sql.= $selectFields . $selectFieldsGrouped;
2044  //Price by customer
2045  if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid))
2046  {
2047  $sql.=', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2048  $sql.=' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx';
2049  $selectFields.= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx";
2050  }
2051 
2052  // Multilang : we add translation
2053  if (! empty($conf->global->MAIN_MULTILANGS))
2054  {
2055  $sql.= ", pl.label as label_translated";
2056  $selectFields.= ", label_translated";
2057  }
2058  // Price by quantity
2059  if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
2060  {
2061  $sql.= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
2062  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql.= " AND price_level=".$price_level;
2063  $sql.= " ORDER BY date_price";
2064  $sql.= " DESC LIMIT 1) as price_rowid";
2065  $sql.= ", (SELECT pp.price_by_qty FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable
2066  if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql.= " AND price_level=".$price_level;
2067  $sql.= " ORDER BY date_price";
2068  $sql.= " DESC LIMIT 1) as price_by_qty";
2069  $selectFields.= ", price_rowid, price_by_qty";
2070  }
2071  $sql.= " FROM ".MAIN_DB_PREFIX."product as p";
2072  if (count($warehouseStatusArray))
2073  {
2074  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
2075  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid";
2076  }
2077 
2078  // include search in supplier ref
2079  if(!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
2080  {
2081  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2082  }
2083 
2084  //Price by customer
2085  if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2086  $sql.=" LEFT JOIN ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".$socid." AND pcp.fk_product=p.rowid";
2087  }
2088  // Multilang : we add translation
2089  if (! empty($conf->global->MAIN_MULTILANGS))
2090  {
2091  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='". $langs->getDefaultLang() ."'";
2092  }
2093 
2094  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2095  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2096  }
2097 
2098  $sql.= ' WHERE p.entity IN ('.getEntity('product').')';
2099  if (count($warehouseStatusArray))
2100  {
2101  $sql.= ' AND (p.fk_product_type = 1 OR e.statut IN ('.$this->db->escape(implode(',',$warehouseStatusArray)).'))';
2102  }
2103 
2104  if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2105  $sql .= " AND pac.rowid IS NULL";
2106  }
2107 
2108  if ($finished == 0)
2109  {
2110  $sql.= " AND p.finished = ".$finished;
2111  }
2112  elseif ($finished == 1)
2113  {
2114  $sql.= " AND p.finished = ".$finished;
2115  if ($status >= 0) $sql.= " AND p.tosell = ".$status;
2116  }
2117  elseif ($status >= 0)
2118  {
2119  $sql.= " AND p.tosell = ".$status;
2120  }
2121  if (strval($filtertype) != '') $sql.=" AND p.fk_product_type=".$filtertype;
2122  // Add criteria on ref/label
2123  if ($filterkey != '')
2124  {
2125  $sql.=' AND (';
2126  $prefix=empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE)?'%':''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2127  // For natural search
2128  $scrit = explode(' ', $filterkey);
2129  $i=0;
2130  if (count($scrit) > 1) $sql.="(";
2131  foreach ($scrit as $crit)
2132  {
2133  if ($i > 0) $sql.=" AND ";
2134  $sql.="(p.ref LIKE '".$db->escape($prefix.$crit)."%' OR p.label LIKE '".$db->escape($prefix.$crit)."%'";
2135  if (! empty($conf->global->MAIN_MULTILANGS)) $sql.=" OR pl.label LIKE '".$db->escape($prefix.$crit)."%'";
2136  if (! empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) $sql.=" OR pfp.ref_fourn LIKE '".$db->escape($prefix.$crit)."%'";
2137  $sql.=")";
2138  $i++;
2139  }
2140  if (count($scrit) > 1) $sql.=")";
2141  if (! empty($conf->barcode->enabled)) $sql.= " OR p.barcode LIKE '".$db->escape($prefix.$filterkey)."%'";
2142  $sql.=')';
2143  }
2144  if (count($warehouseStatusArray))
2145  {
2146  $sql.= ' GROUP BY'.$selectFields;
2147  }
2148  $sql.= $db->order("p.ref");
2149  $sql.= $db->plimit($limit, 0);
2150 
2151  // Build output string
2152  dol_syslog(get_class($this)."::select_produits_list search product", LOG_DEBUG);
2153  $result=$this->db->query($sql);
2154  if ($result)
2155  {
2156  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2157  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2158  $num = $this->db->num_rows($result);
2159 
2160  $events=null;
2161 
2162  if (! $forcecombo)
2163  {
2164  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2165  $out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT);
2166  }
2167 
2168  $out.='<select class="flat'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2169 
2170  $textifempty='';
2171  // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2172  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2173  if (! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2174  {
2175  if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
2176  else $textifempty.=$langs->trans("All");
2177  }
2178  else
2179  {
2180  if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
2181  }
2182  if ($showempty) $out.='<option value="0" selected>'.$textifempty.'</option>';
2183 
2184  $i = 0;
2185  while ($num && $i < $num)
2186  {
2187  $opt = '';
2188  $optJson = array();
2189  $objp = $this->db->fetch_object($result);
2190 
2191  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)
2192  { // Price by quantity will return many prices for the same product
2193  $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2194  $sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
2195  $sql.= " WHERE fk_product_price=".$objp->price_rowid;
2196  $sql.= " ORDER BY quantity ASC";
2197 
2198  dol_syslog(get_class($this)."::select_produits_list search price by qty", LOG_DEBUG);
2199  $result2 = $this->db->query($sql);
2200  if ($result2)
2201  {
2202  $nb_prices = $this->db->num_rows($result2);
2203  $j = 0;
2204  while ($nb_prices && $j < $nb_prices) {
2205  $objp2 = $this->db->fetch_object($result2);
2206 
2207  $objp->price_by_qty_rowid = $objp2->rowid;
2208  $objp->price_by_qty_price_base_type = $objp2->price_base_type;
2209  $objp->price_by_qty_quantity = $objp2->quantity;
2210  $objp->price_by_qty_unitprice = $objp2->unitprice;
2211  $objp->price_by_qty_remise_percent = $objp2->remise_percent;
2212  // For backward compatibility
2213  $objp->quantity = $objp2->quantity;
2214  $objp->price = $objp2->price;
2215  $objp->unitprice = $objp2->unitprice;
2216  $objp->remise_percent = $objp2->remise_percent;
2217  $objp->remise = $objp2->remise;
2218 
2219  $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel);
2220 
2221  $j++;
2222 
2223  // Add new entry
2224  // "key" value of json key array is used by jQuery automatically as selected value
2225  // "label" value of json key array is used by jQuery automatically as text for combo box
2226  $out.=$opt;
2227  array_push($outarray, $optJson);
2228  }
2229  }
2230  }
2231  else
2232  {
2233  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2234  $price_product = new Product($this->db);
2235  $price_product->fetch($objp->rowid, '', '', 1);
2236  $priceparser = new PriceParser($this->db);
2237  $price_result = $priceparser->parseProduct($price_product);
2238  if ($price_result >= 0) {
2239  $objp->price = $price_result;
2240  $objp->unitprice = $price_result;
2241  //Calculate the VAT
2242  $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2243  $objp->price_ttc = price2num($objp->price_ttc,'MU');
2244  }
2245  }
2246  $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel);
2247  // Add new entry
2248  // "key" value of json key array is used by jQuery automatically as selected value
2249  // "label" value of json key array is used by jQuery automatically as text for combo box
2250  $out.=$opt;
2251  array_push($outarray, $optJson);
2252  }
2253 
2254  $i++;
2255  }
2256 
2257  $out.='</select>';
2258 
2259  $this->db->free($result);
2260 
2261  if (empty($outputmode)) return $out;
2262  return $outarray;
2263  }
2264  else
2265  {
2266  dol_print_error($db);
2267  }
2268  }
2269 
2281  private function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0)
2282  {
2283  global $langs,$conf,$user,$db;
2284 
2285  $outkey='';
2286  $outval='';
2287  $outref='';
2288  $outlabel='';
2289  $outdesc='';
2290  $outbarcode='';
2291  $outtype='';
2292  $outprice_ht='';
2293  $outprice_ttc='';
2294  $outpricebasetype='';
2295  $outtva_tx='';
2296  $outqty=1;
2297  $outdiscount=0;
2298 
2299  $maxlengtharticle=(empty($conf->global->PRODUCT_MAX_LENGTH_COMBO)?48:$conf->global->PRODUCT_MAX_LENGTH_COMBO);
2300 
2301  $label=$objp->label;
2302  if (! empty($objp->label_translated)) $label=$objp->label_translated;
2303  if (! empty($filterkey) && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$label,1);
2304 
2305  $outkey=$objp->rowid;
2306  $outref=$objp->ref;
2307  $outlabel=$objp->label;
2308  $outdesc=$objp->description;
2309  $outbarcode=$objp->barcode;
2310 
2311  $outtype=$objp->fk_product_type;
2312  $outdurationvalue=$outtype == Product::TYPE_SERVICE?substr($objp->duration,0,dol_strlen($objp->duration)-1):'';
2313  $outdurationunit=$outtype == Product::TYPE_SERVICE?substr($objp->duration,-1):'';
2314 
2315  $opt = '<option value="'.$objp->rowid.'"';
2316  $opt.= ($objp->rowid == $selected)?' selected':'';
2317  if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)
2318  {
2319  $opt.= ' pbq="'.$objp->price_by_qty_rowid.'" data-pbq="'.$objp->price_by_qty_rowid.'" data-pbqqty="'.$objp->price_by_qty_quantity.'" data-pbqpercent="'.$objp->price_by_qty_remise_percent.'"';
2320  }
2321  if (! empty($conf->stock->enabled) && $objp->fk_product_type == 0 && isset($objp->stock))
2322  {
2323  if ($objp->stock > 0) $opt.= ' class="product_line_stock_ok"';
2324  else if ($objp->stock <= 0) $opt.= ' class="product_line_stock_too_low"';
2325  }
2326  $opt.= '>';
2327  $opt.= $objp->ref;
2328  if ($outbarcode) $opt.=' ('.$outbarcode.')';
2329  $opt.=' - '.dol_trunc($label,$maxlengtharticle);
2330 
2331  $objRef = $objp->ref;
2332  if (! empty($filterkey) && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
2333  $outval.=$objRef;
2334  if ($outbarcode) $outval.=' ('.$outbarcode.')';
2335  $outval.=' - '.dol_trunc($label,$maxlengtharticle);
2336 
2337  $found=0;
2338 
2339  // Multiprice
2340  // If we need a particular price level (from 1 to 6)
2341  if (empty($hidepriceinlabel) && $price_level >= 1 && (! empty($conf->global->PRODUIT_MULTIPRICES) || ! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)))
2342  {
2343  $sql = "SELECT price, price_ttc, price_base_type, tva_tx";
2344  $sql.= " FROM ".MAIN_DB_PREFIX."product_price";
2345  $sql.= " WHERE fk_product='".$objp->rowid."'";
2346  $sql.= " AND entity IN (".getEntity('productprice').")";
2347  $sql.= " AND price_level=".$price_level;
2348  $sql.= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2349  $sql.= " LIMIT 1";
2350 
2351  dol_syslog(get_class($this).'::constructProductListOption search price for level '.$price_level.'', LOG_DEBUG);
2352  $result2 = $this->db->query($sql);
2353  if ($result2)
2354  {
2355  $objp2 = $this->db->fetch_object($result2);
2356  if ($objp2)
2357  {
2358  $found=1;
2359  if ($objp2->price_base_type == 'HT')
2360  {
2361  $opt.= ' - '.price($objp2->price,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("HT");
2362  $outval.= ' - '.price($objp2->price,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("HT");
2363  }
2364  else
2365  {
2366  $opt.= ' - '.price($objp2->price_ttc,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("TTC");
2367  $outval.= ' - '.price($objp2->price_ttc,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("TTC");
2368  }
2369  $outprice_ht=price($objp2->price);
2370  $outprice_ttc=price($objp2->price_ttc);
2371  $outpricebasetype=$objp2->price_base_type;
2372  $outtva_tx=$objp2->tva_tx;
2373  }
2374  }
2375  else
2376  {
2377  dol_print_error($this->db);
2378  }
2379  }
2380 
2381  // Price by quantity
2382  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)))
2383  {
2384  $found = 1;
2385  $outqty=$objp->quantity;
2386  $outdiscount=$objp->remise_percent;
2387  if ($objp->quantity == 1)
2388  {
2389  $opt.= ' - '.price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/";
2390  $outval.= ' - '.price($objp->unitprice,0,$langs,0,0,-1,$conf->currency)."/";
2391  $opt.= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2392  $outval.=$langs->transnoentities("Unit");
2393  }
2394  else
2395  {
2396  $opt.= ' - '.price($objp->price,1,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2397  $outval.= ' - '.price($objp->price,0,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2398  $opt.= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2399  $outval.=$langs->transnoentities("Units");
2400  }
2401 
2402  $outprice_ht=price($objp->unitprice);
2403  $outprice_ttc=price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
2404  $outpricebasetype=$objp->price_base_type;
2405  $outtva_tx=$objp->tva_tx;
2406  }
2407  if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1)
2408  {
2409  $opt.=" (".price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2410  $outval.=" (".price($objp->unitprice,0,$langs,0,0,-1,$conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2411  }
2412  if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1)
2413  {
2414  $opt.=" - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2415  $outval.=" - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2416  }
2417 
2418  // Price by customer
2419  if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES))
2420  {
2421  if (!empty($objp->idprodcustprice))
2422  {
2423  $found = 1;
2424 
2425  if ($objp->custprice_base_type == 'HT')
2426  {
2427  $opt.= ' - '.price($objp->custprice,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("HT");
2428  $outval.= ' - '.price($objp->custprice,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("HT");
2429  }
2430  else
2431  {
2432  $opt.= ' - '.price($objp->custprice_ttc,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("TTC");
2433  $outval.= ' - '.price($objp->custprice_ttc,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("TTC");
2434  }
2435 
2436  $outprice_ht=price($objp->custprice);
2437  $outprice_ttc=price($objp->custprice_ttc);
2438  $outpricebasetype=$objp->custprice_base_type;
2439  $outtva_tx=$objp->custtva_tx;
2440  }
2441  }
2442 
2443  // If level no defined or multiprice not found, we used the default price
2444  if (empty($hidepriceinlabel) && ! $found)
2445  {
2446  if ($objp->price_base_type == 'HT')
2447  {
2448  $opt.= ' - '.price($objp->price,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("HT");
2449  $outval.= ' - '.price($objp->price,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("HT");
2450  }
2451  else
2452  {
2453  $opt.= ' - '.price($objp->price_ttc,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("TTC");
2454  $outval.= ' - '.price($objp->price_ttc,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("TTC");
2455  }
2456  $outprice_ht=price($objp->price);
2457  $outprice_ttc=price($objp->price_ttc);
2458  $outpricebasetype=$objp->price_base_type;
2459  $outtva_tx=$objp->tva_tx;
2460  }
2461 
2462  if (! empty($conf->stock->enabled) && isset($objp->stock) && $objp->fk_product_type == 0)
2463  {
2464  $opt.= ' - '.$langs->trans("Stock").':'.$objp->stock;
2465 
2466  if ($objp->stock > 0) {
2467  $outval.= ' - <span class="product_line_stock_ok">'.$langs->transnoentities("Stock").':'.$objp->stock.'</span>';
2468  }elseif ($objp->stock <= 0) {
2469  $outval.= ' - <span class="product_line_stock_too_low">'.$langs->transnoentities("Stock").':'.$objp->stock.'</span>';
2470  }
2471  }
2472 
2473  if ($outdurationvalue && $outdurationunit)
2474  {
2475  $da=array("h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
2476  if (isset($da[$outdurationunit]))
2477  {
2478  $key = $da[$outdurationunit].($outdurationvalue > 1?'s':'');
2479  $opt.= ' - '.$outdurationvalue.' '.$langs->trans($key);
2480  $outval.=' - '.$outdurationvalue.' '.$langs->transnoentities($key);
2481  }
2482  }
2483 
2484  $opt.= "</option>\n";
2485  $optJson = array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>$outprice_ht, 'price_ttc'=>$outprice_ttc, 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit);
2486  }
2487 
2488  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2503  function select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='')
2504  {
2505  // phpcs:enable
2506  global $langs,$conf;
2507  global $price_level, $status, $finished;
2508 
2509  $selected_input_value='';
2510  if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2511  {
2512  if ($selected > 0)
2513  {
2514  require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2515  $producttmpselect = new Product($this->db);
2516  $producttmpselect->fetch($selected);
2517  $selected_input_value=$producttmpselect->ref;
2518  unset($producttmpselect);
2519  }
2520 
2521  // mode=2 means suppliers products
2522  $urloption=($socid > 0?'socid='.$socid.'&':'').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
2523  print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
2524  print ($hidelabel?'':$langs->trans("RefOrLabel").' : ').'<input type="text" size="20" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'">';
2525  }
2526  else
2527  {
2528  print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', -1, 0, 0, $alsoproductwithnosupplierprice, $morecss);
2529  }
2530  }
2531 
2532  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2549  function select_produits_fournisseurs_list($socid,$selected='',$htmlname='productid',$filtertype='',$filtre='',$filterkey='',$statut=-1,$outputmode=0,$limit=100,$alsoproductwithnosupplierprice=0,$morecss='')
2550  {
2551  // phpcs:enable
2552  global $langs,$conf,$db;
2553 
2554  $out='';
2555  $outarray=array();
2556 
2557  $langs->load('stocks');
2558 
2559  $sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration, p.fk_product_type,";
2560  $sql.= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
2561  $sql.= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,";
2562  $sql.= " pfp.supplier_reputation";
2563  $sql.= " FROM ".MAIN_DB_PREFIX."product as p";
2564  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2565  if ($socid) $sql.= " AND pfp.fk_soc = ".$socid;
2566  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2567  $sql.= " WHERE p.entity IN (".getEntity('product').")";
2568  $sql.= " AND p.tobuy = 1";
2569  if (strval($filtertype) != '') $sql.=" AND p.fk_product_type=".$this->db->escape($filtertype);
2570  if (! empty($filtre)) $sql.=" ".$filtre;
2571  // Add criteria on ref/label
2572  if ($filterkey != '')
2573  {
2574  $sql.=' AND (';
2575  $prefix=empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE)?'%':''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2576  // For natural search
2577  $scrit = explode(' ', $filterkey);
2578  $i=0;
2579  if (count($scrit) > 1) $sql.="(";
2580  foreach ($scrit as $crit)
2581  {
2582  if ($i > 0) $sql.=" AND ";
2583  $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)."%')";
2584  $i++;
2585  }
2586  if (count($scrit) > 1) $sql.=")";
2587  if (! empty($conf->barcode->enabled)) $sql.= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2588  $sql.=')';
2589  }
2590  $sql.= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
2591  $sql.= $db->plimit($limit, 0);
2592 
2593  // Build output string
2594 
2595  dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
2596  $result=$this->db->query($sql);
2597  if ($result)
2598  {
2599  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2600 
2601  $num = $this->db->num_rows($result);
2602 
2603  //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
2604  $out.='<select class="flat maxwidthonsmartphone'.($morecss?' '.$morecss:'').'" id="'.$htmlname.'" name="'.$htmlname.'">';
2605  if (! $selected) $out.='<option value="0" selected>&nbsp;</option>';
2606  else $out.='<option value="0">&nbsp;</option>';
2607 
2608  $i = 0;
2609  while ($i < $num)
2610  {
2611  $objp = $this->db->fetch_object($result);
2612 
2613  $outkey=$objp->idprodfournprice; // id in table of price
2614  if (! $outkey && $alsoproductwithnosupplierprice) $outkey='idprod_'.$objp->rowid; // id of product
2615 
2616  $outref=$objp->ref;
2617  $outval='';
2618  $outqty=1;
2619  $outdiscount=0;
2620  $outtype=$objp->fk_product_type;
2621  $outdurationvalue=$outtype == Product::TYPE_SERVICE?substr($objp->duration,0,dol_strlen($objp->duration)-1):'';
2622  $outdurationunit=$outtype == Product::TYPE_SERVICE?substr($objp->duration,-1):'';
2623 
2624  $opt = '<option value="'.$outkey.'"';
2625  if ($selected && $selected == $objp->idprodfournprice) $opt.= ' selected';
2626  if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) $opt.=' disabled';
2627  if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0)
2628  {
2629  $opt.= ' pbq="'.$objp->idprodfournprice.'" data-pbq="'.$objp->idprodfournprice.'" data-pbqqty="'.$objp->quantity.'" data-pbqpercent="'.$objp->remise_percent.'"';
2630  }
2631  $opt.= '>';
2632 
2633  $objRef = $objp->ref;
2634  if ($filterkey && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
2635  $objRefFourn = $objp->ref_fourn;
2636  if ($filterkey && $filterkey != '') $objRefFourn=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRefFourn,1);
2637  $label = $objp->label;
2638  if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$label,1);
2639 
2640  $opt.=$objp->ref;
2641  if (! empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn))
2642  $opt.=' ('.$objp->ref_fourn.')';
2643  $opt.=' - ';
2644  $outval.=$objRef;
2645  if (! empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn))
2646  $outval.=' ('.$objRefFourn.')';
2647  $outval.=' - ';
2648  $opt.=dol_trunc($label, 72).' - ';
2649  $outval.=dol_trunc($label, 72).' - ';
2650 
2651  if (! empty($objp->idprodfournprice))
2652  {
2653  $outqty=$objp->quantity;
2654  $outdiscount=$objp->remise_percent;
2655  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2656  $prod_supplier = new ProductFournisseur($this->db);
2657  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2658  $prod_supplier->id = $objp->fk_product;
2659  $prod_supplier->fourn_qty = $objp->quantity;
2660  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
2661  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2662  $priceparser = new PriceParser($this->db);
2663  $price_result = $priceparser->parseProductSupplier($prod_supplier);
2664  if ($price_result >= 0) {
2665  $objp->fprice = $price_result;
2666  if ($objp->quantity >= 1)
2667  {
2668  $objp->unitprice = $objp->fprice / $objp->quantity;
2669  }
2670  }
2671  }
2672  if ($objp->quantity == 1)
2673  {
2674  $opt.= price($objp->fprice,1,$langs,0,0,-1,$conf->currency)."/";
2675  $outval.= price($objp->fprice,0,$langs,0,0,-1,$conf->currency)."/";
2676  $opt.= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2677  $outval.=$langs->transnoentities("Unit");
2678  }
2679  else
2680  {
2681  $opt.= price($objp->fprice,1,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2682  $outval.= price($objp->fprice,0,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2683  $opt.= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2684  $outval.= ' '.$langs->transnoentities("Units");
2685  }
2686 
2687  if ($objp->quantity >= 1)
2688  {
2689  $opt.=" (".price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2690  $outval.=" (".price($objp->unitprice,0,$langs,0,0,-1,$conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2691  }
2692  if ($objp->remise_percent >= 1)
2693  {
2694  $opt.=" - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2695  $outval.=" - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2696  }
2697  if ($objp->duration)
2698  {
2699  $opt .= " - ".$objp->duration;
2700  $outval.=" - ".$objp->duration;
2701  }
2702  if (! $socid)
2703  {
2704  $opt .= " - ".dol_trunc($objp->name,8);
2705  $outval.=" - ".dol_trunc($objp->name,8);
2706  }
2707  if ($objp->supplier_reputation)
2708  {
2709  //TODO dictionary
2710  $reputations=array(''=>$langs->trans('Standard'),'FAVORITE'=>$langs->trans('Favorite'),'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
2711 
2712  $opt .= " - ".$reputations[$objp->supplier_reputation];
2713  $outval.=" - ".$reputations[$objp->supplier_reputation];
2714  }
2715  }
2716  else
2717  {
2718  if (empty($alsoproductwithnosupplierprice)) // No supplier price defined for couple product/supplier
2719  {
2720  $opt.= $langs->trans("NoPriceDefinedForThisSupplier");
2721  $outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier");
2722  }
2723  else // No supplier price defined for product, even on other suppliers
2724  {
2725  $opt.= $langs->trans("NoPriceDefinedForThisSupplier");
2726  $outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier");
2727  }
2728  }
2729  $opt .= "</option>\n";
2730 
2731 
2732  // Add new entry
2733  // "key" value of json key array is used by jQuery automatically as selected value
2734  // "label" value of json key array is used by jQuery automatically as text for combo box
2735  $out.=$opt;
2736  array_push($outarray, array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'qty'=>$outqty, 'discount'=>$outdiscount, 'type'=>$outtype, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit, 'disabled'=>(empty($objp->idprodfournprice)?true:false)));
2737  // Exemple of var_dump $outarray
2738  // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
2739  // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
2740  // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
2741  //}
2742  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2743  //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
2744  //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2745 
2746  $i++;
2747  }
2748  $out.='</select>';
2749 
2750  $this->db->free($result);
2751 
2752  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2753  $out.=ajax_combobox($htmlname);
2754 
2755  if (empty($outputmode)) return $out;
2756  return $outarray;
2757  }
2758  else
2759  {
2760  dol_print_error($this->db);
2761  }
2762  }
2763 
2764  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2773  function select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier='')
2774  {
2775  // phpcs:enable
2776  global $langs,$conf;
2777 
2778  $langs->load('stocks');
2779 
2780  $sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration, pfp.fk_soc,";
2781  $sql.= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.unitprice,";
2782  $sql.= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
2783  $sql.= " FROM ".MAIN_DB_PREFIX."product as p";
2784  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2785  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2786  $sql.= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
2787  $sql.= " AND p.tobuy = 1";
2788  $sql.= " AND s.fournisseur = 1";
2789  $sql.= " AND p.rowid = ".$productid;
2790  $sql.= " ORDER BY s.nom, pfp.ref_fourn DESC";
2791 
2792  dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
2793  $result=$this->db->query($sql);
2794 
2795  if ($result)
2796  {
2797  $num = $this->db->num_rows($result);
2798 
2799  $form = '<select class="flat" name="'.$htmlname.'">';
2800 
2801  if (! $num)
2802  {
2803  $form.= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
2804  }
2805  else
2806  {
2807  require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2808  $form.= '<option value="0">&nbsp;</option>';
2809 
2810  $i = 0;
2811  while ($i < $num)
2812  {
2813  $objp = $this->db->fetch_object($result);
2814 
2815  $opt = '<option value="'.$objp->idprodfournprice.'"';
2816  //if there is only one supplier, preselect it
2817  if($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
2818  $opt .= ' selected';
2819  }
2820  $opt.= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
2821 
2822  if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2823  $prod_supplier = new ProductFournisseur($this->db);
2824  $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2825  $prod_supplier->id = $productid;
2826  $prod_supplier->fourn_qty = $objp->quantity;
2827  $prod_supplier->fourn_tva_tx = $objp->tva_tx;
2828  $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2829  $priceparser = new PriceParser($this->db);
2830  $price_result = $priceparser->parseProductSupplier($prod_supplier);
2831  if ($price_result >= 0) {
2832  $objp->fprice = $price_result;
2833  if ($objp->quantity >= 1)
2834  {
2835  $objp->unitprice = $objp->fprice / $objp->quantity;
2836  }
2837  }
2838  }
2839  if ($objp->quantity == 1)
2840  {
2841  $opt.= price($objp->fprice,1,$langs,0,0,-1,$conf->currency)."/";
2842  }
2843 
2844  $opt.= $objp->quantity.' ';
2845 
2846  if ($objp->quantity == 1)
2847  {
2848  $opt.= $langs->trans("Unit");
2849  }
2850  else
2851  {
2852  $opt.= $langs->trans("Units");
2853  }
2854  if ($objp->quantity > 1)
2855  {
2856  $opt.=" - ";
2857  $opt.= price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/".$langs->trans("Unit");
2858  }
2859  if ($objp->duration) $opt .= " - ".$objp->duration;
2860  $opt .= "</option>\n";
2861 
2862  $form.= $opt;
2863  $i++;
2864  }
2865  }
2866 
2867  $form.= '</select>';
2868  $this->db->free($result);
2869  return $form;
2870  }
2871  else
2872  {
2873  dol_print_error($this->db);
2874  }
2875  }
2876 
2877  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2887  function select_address($selected, $socid, $htmlname='address_id',$showempty=0)
2888  {
2889  // phpcs:enable
2890  // looking for users
2891  $sql = "SELECT a.rowid, a.label";
2892  $sql .= " FROM ".MAIN_DB_PREFIX ."societe_address as a";
2893  $sql .= " WHERE a.fk_soc = ".$socid;
2894  $sql .= " ORDER BY a.label ASC";
2895 
2896  dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
2897  $resql=$this->db->query($sql);
2898  if ($resql)
2899  {
2900  print '<select class="flat" name="'.$htmlname.'">';
2901  if ($showempty) print '<option value="0">&nbsp;</option>';
2902  $num = $this->db->num_rows($resql);
2903  $i = 0;
2904  if ($num)
2905  {
2906  while ($i < $num)
2907  {
2908  $obj = $this->db->fetch_object($resql);
2909 
2910  if ($selected && $selected == $obj->rowid)
2911  {
2912  print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
2913  }
2914  else
2915  {
2916  print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
2917  }
2918  $i++;
2919  }
2920  }
2921  print '</select>';
2922  return $num;
2923  }
2924  else
2925  {
2926  dol_print_error($this->db);
2927  }
2928  }
2929 
2930 
2931  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2938  {
2939  // phpcs:enable
2940  global $langs;
2941 
2942  $num = count($this->cache_conditions_paiements);
2943  if ($num > 0) return 0; // Cache already loaded
2944 
2945  dol_syslog(__METHOD__, LOG_DEBUG);
2946 
2947  $sql = "SELECT rowid, code, libelle as label";
2948  $sql.= " FROM ".MAIN_DB_PREFIX.'c_payment_term';
2949  $sql.= " WHERE entity IN (".getEntity('c_payment_term').")";
2950  $sql.= " AND active > 0";
2951  $sql.= " ORDER BY sortorder";
2952 
2953  $resql = $this->db->query($sql);
2954  if ($resql)
2955  {
2956  $num = $this->db->num_rows($resql);
2957  $i = 0;
2958  while ($i < $num)
2959  {
2960  $obj = $this->db->fetch_object($resql);
2961 
2962  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
2963  $label=($langs->trans("PaymentConditionShort".$obj->code)!=("PaymentConditionShort".$obj->code)?$langs->trans("PaymentConditionShort".$obj->code):($obj->label!='-'?$obj->label:''));
2964  $this->cache_conditions_paiements[$obj->rowid]['code'] =$obj->code;
2965  $this->cache_conditions_paiements[$obj->rowid]['label']=$label;
2966  $i++;
2967  }
2968 
2969  //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
2970 
2971  return $num;
2972  }
2973  else
2974  {
2975  dol_print_error($this->db);
2976  return -1;
2977  }
2978  }
2979 
2980  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2987  {
2988  // phpcs:enable
2989  global $langs;
2990 
2991  $num = count($this->cache_availability);
2992  if ($num > 0) return 0; // Cache already loaded
2993 
2994  dol_syslog(__METHOD__, LOG_DEBUG);
2995 
2996  $langs->load('propal');
2997 
2998  $sql = "SELECT rowid, code, label";
2999  $sql.= " FROM ".MAIN_DB_PREFIX.'c_availability';
3000  $sql.= " WHERE active > 0";
3001 
3002  $resql = $this->db->query($sql);
3003  if ($resql)
3004  {
3005  $num = $this->db->num_rows($resql);
3006  $i = 0;
3007  while ($i < $num)
3008  {
3009  $obj = $this->db->fetch_object($resql);
3010 
3011  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3012  $label=($langs->trans("AvailabilityType".$obj->code)!=("AvailabilityType".$obj->code)?$langs->trans("AvailabilityType".$obj->code):($obj->label!='-'?$obj->label:''));
3013  $this->cache_availability[$obj->rowid]['code'] =$obj->code;
3014  $this->cache_availability[$obj->rowid]['label']=$label;
3015  $i++;
3016  }
3017 
3018  $this->cache_availability = dol_sort_array($this->cache_availability, 'label', 'asc', 0, 0, 1);
3019 
3020  return $num;
3021  }
3022  else
3023  {
3024  dol_print_error($this->db);
3025  return -1;
3026  }
3027  }
3028 
3038  function selectAvailabilityDelay($selected='',$htmlname='availid',$filtertype='',$addempty=0)
3039  {
3040  global $langs,$user;
3041 
3042  $this->load_cache_availability();
3043 
3044  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3045 
3046  print '<select id="'.$htmlname.'" class="flat" name="'.$htmlname.'">';
3047  if ($addempty) print '<option value="0">&nbsp;</option>';
3048  foreach($this->cache_availability as $id => $arrayavailability)
3049  {
3050  if ($selected == $id)
3051  {
3052  print '<option value="'.$id.'" selected>';
3053  }
3054  else
3055  {
3056  print '<option value="'.$id.'">';
3057  }
3058  print $arrayavailability['label'];
3059  print '</option>';
3060  }
3061  print '</select>';
3062  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3063  }
3064 
3071  {
3072  global $langs;
3073 
3074  $num = count($this->cache_demand_reason);
3075  if ($num > 0) return 0; // Cache already loaded
3076 
3077  $sql = "SELECT rowid, code, label";
3078  $sql.= " FROM ".MAIN_DB_PREFIX.'c_input_reason';
3079  $sql.= " WHERE active > 0";
3080 
3081  $resql = $this->db->query($sql);
3082  if ($resql)
3083  {
3084  $num = $this->db->num_rows($resql);
3085  $i = 0;
3086  $tmparray=array();
3087  while ($i < $num)
3088  {
3089  $obj = $this->db->fetch_object($resql);
3090 
3091  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3092  $label=($obj->label!='-'?$obj->label:'');
3093  if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3094  if ($langs->trans($obj->code) != $obj->code) $label=$langs->trans($obj->code); // So translation key SRC_XXX will work
3095 
3096  $tmparray[$obj->rowid]['id'] =$obj->rowid;
3097  $tmparray[$obj->rowid]['code'] =$obj->code;
3098  $tmparray[$obj->rowid]['label']=$label;
3099  $i++;
3100  }
3101 
3102  $this->cache_demand_reason=dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3103 
3104  unset($tmparray);
3105  return $num;
3106  }
3107  else
3108  {
3109  dol_print_error($this->db);
3110  return -1;
3111  }
3112  }
3113 
3124  function selectInputReason($selected='',$htmlname='demandreasonid',$exclude='',$addempty=0)
3125  {
3126  global $langs,$user;
3127 
3128  $this->loadCacheInputReason();
3129 
3130  print '<select class="flat" name="'.$htmlname.'">';
3131  if ($addempty) print '<option value="0"'.(empty($selected)?' selected':'').'>&nbsp;</option>';
3132  foreach($this->cache_demand_reason as $id => $arraydemandreason)
3133  {
3134  if ($arraydemandreason['code']==$exclude) continue;
3135 
3136  if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code']))
3137  {
3138  print '<option value="'.$arraydemandreason['id'].'" selected>';
3139  }
3140  else
3141  {
3142  print '<option value="'.$arraydemandreason['id'].'">';
3143  }
3144  $label=$arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3145  print $langs->trans($label);
3146  print '</option>';
3147  }
3148  print '</select>';
3149  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3150  }
3151 
3152  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3159  {
3160  // phpcs:enable
3161  global $langs;
3162 
3163  $num=count($this->cache_types_paiements);
3164  if ($num > 0) return $num; // Cache already loaded
3165 
3166  dol_syslog(__METHOD__, LOG_DEBUG);
3167 
3168  $this->cache_types_paiements = array();
3169 
3170  $sql = "SELECT id, code, libelle as label, type, active";
3171  $sql.= " FROM ".MAIN_DB_PREFIX."c_paiement";
3172  $sql.= " WHERE entity IN (".getEntity('c_paiement').")";
3173  //if ($active >= 0) $sql.= " AND active = ".$active;
3174 
3175  $resql = $this->db->query($sql);
3176  if ($resql)
3177  {
3178  $num = $this->db->num_rows($resql);
3179  $i = 0;
3180  while ($i < $num)
3181  {
3182  $obj = $this->db->fetch_object($resql);
3183 
3184  // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3185  $label=($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code)!=("PaymentTypeShort".$obj->code)?$langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code):($obj->label!='-'?$obj->label:''));
3186  $this->cache_types_paiements[$obj->id]['id'] =$obj->id;
3187  $this->cache_types_paiements[$obj->id]['code'] =$obj->code;
3188  $this->cache_types_paiements[$obj->id]['label']=$label;
3189  $this->cache_types_paiements[$obj->id]['type'] =$obj->type;
3190  $this->cache_types_paiements[$obj->id]['active'] =$obj->active;
3191  $i++;
3192  }
3193 
3194  $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3195 
3196  return $num;
3197  }
3198  else
3199  {
3200  dol_print_error($this->db);
3201  return -1;
3202  }
3203  }
3204 
3205 
3206  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3220  function select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='')
3221  {
3222  // phpcs:enable
3223  global $langs, $user, $conf;
3224 
3225  dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3226 
3228 
3229  // Set default value if not already set by caller
3230  if (empty($selected) && ! empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
3231 
3232  print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'">';
3233  if ($addempty) print '<option value="0">&nbsp;</option>';
3234  foreach($this->cache_conditions_paiements as $id => $arrayconditions)
3235  {
3236  if ($selected == $id)
3237  {
3238  print '<option value="'.$id.'" selected>';
3239  }
3240  else
3241  {
3242  print '<option value="'.$id.'">';
3243  }
3244  print $arrayconditions['label'];
3245  print '</option>';
3246  }
3247  print '</select>';
3248  if ($user->admin && empty($noinfoadmin)) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3249  }
3250 
3251 
3252  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3267  function select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
3268  {
3269  // phpcs:enable
3270  global $langs,$user;
3271 
3272  dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
3273 
3274  $filterarray=array();
3275  if ($filtertype == 'CRDT') $filterarray=array(0,2,3);
3276  elseif ($filtertype == 'DBIT') $filterarray=array(1,2,3);
3277  elseif ($filtertype != '' && $filtertype != '-1') $filterarray=explode(',',$filtertype);
3278 
3279  $this->load_cache_types_paiements();
3280 
3281  print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'">';
3282  if ($empty) print '<option value="">&nbsp;</option>';
3283  foreach($this->cache_types_paiements as $id => $arraytypes)
3284  {
3285  // If not good status
3286  if ($active >= 0 && $arraytypes['active'] != $active) continue;
3287 
3288  // On passe si on a demande de filtrer sur des modes de paiments particuliers
3289  if (count($filterarray) && ! in_array($arraytypes['type'],$filterarray)) continue;
3290 
3291  // We discard empty line if showempty is on because an empty line has already been output.
3292  if ($empty && empty($arraytypes['code'])) continue;
3293 
3294  if ($format == 0) print '<option value="'.$id.'"';
3295  elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3296  elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3297  elseif ($format == 3) print '<option value="'.$id.'"';
3298  // Si selected est text, on compare avec code, sinon avec id
3299  if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) print ' selected';
3300  elseif ($selected == $id) print ' selected';
3301  print '>';
3302  if ($format == 0) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
3303  elseif ($format == 1) $value=$arraytypes['code'];
3304  elseif ($format == 2) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
3305  elseif ($format == 3) $value=$arraytypes['code'];
3306  print $value?$value:'&nbsp;';
3307  print '</option>';
3308  }
3309  print '</select>';
3310  if ($user->admin && ! $noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3311  }
3312 
3313 
3321  function selectPriceBaseType($selected='',$htmlname='price_base_type')
3322  {
3323  global $langs;
3324 
3325  $return='';
3326 
3327  $return.= '<select class="flat" name="'.$htmlname.'">';
3328  $options = array(
3329  'HT'=>$langs->trans("HT"),
3330  'TTC'=>$langs->trans("TTC")
3331  );
3332  foreach($options as $id => $value)
3333  {
3334  if ($selected == $id)
3335  {
3336  $return.= '<option value="'.$id.'" selected>'.$value;
3337  }
3338  else
3339  {
3340  $return.= '<option value="'.$id.'">'.$value;
3341  }
3342  $return.= '</option>';
3343  }
3344  $return.= '</select>';
3345 
3346  return $return;
3347  }
3348 
3359  function selectShippingMethod($selected='',$htmlname='shipping_method_id',$filtre='',$useempty=0,$moreattrib='')
3360  {
3361  global $langs, $conf, $user;
3362 
3363  $langs->load("admin");
3364  $langs->load("deliveries");
3365 
3366  $sql = "SELECT rowid, code, libelle as label";
3367  $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode";
3368  $sql.= " WHERE active > 0";
3369  if ($filtre) $sql.=" AND ".$filtre;
3370  $sql.= " ORDER BY libelle ASC";
3371 
3372  dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
3373  $result = $this->db->query($sql);
3374  if ($result) {
3375  $num = $this->db->num_rows($result);
3376  $i = 0;
3377  if ($num) {
3378  print '<select id="select'.$htmlname.'" class="flat selectshippingmethod" name="'.$htmlname.'"'.($moreattrib?' '.$moreattrib:'').'>';
3379  if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
3380  print '<option value="-1">&nbsp;</option>';
3381  }
3382  while ($i < $num) {
3383  $obj = $this->db->fetch_object($result);
3384  if ($selected == $obj->rowid) {
3385  print '<option value="'.$obj->rowid.'" selected>';
3386  } else {
3387  print '<option value="'.$obj->rowid.'">';
3388  }
3389  print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
3390  print '</option>';
3391  $i++;
3392  }
3393  print "</select>";
3394  if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3395  } else {
3396  print $langs->trans("NoShippingMethodDefined");
3397  }
3398  } else {
3399  dol_print_error($this->db);
3400  }
3401  }
3402 
3412  function formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
3413  {
3414  global $langs, $db;
3415 
3416  $langs->load("deliveries");
3417 
3418  if ($htmlname != "none") {
3419  print '<form method="POST" action="'.$page.'">';
3420  print '<input type="hidden" name="action" value="setshippingmethod">';
3421  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
3422  $this->selectShippingMethod($selected, $htmlname, '', $addempty);
3423  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3424  print '</form>';
3425  } else {
3426  if ($selected) {
3427  $code=$langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code');
3428  print $langs->trans("SendingMethod".strtoupper($code));
3429  } else {
3430  print "&nbsp;";
3431  }
3432  }
3433  }
3434 
3443  function selectSituationInvoices($selected = '', $socid = 0)
3444  {
3445  global $langs;
3446 
3447  $langs->load('bills');
3448 
3449  $opt = '<option value ="" selected></option>';
3450  $sql = 'SELECT rowid, facnumber, situation_cycle_ref, situation_counter, situation_final, fk_soc FROM ' . MAIN_DB_PREFIX . 'facture WHERE situation_counter>=1';
3451  $sql.= ' ORDER by situation_cycle_ref, situation_counter desc';
3452  $resql = $this->db->query($sql);
3453  if ($resql && $this->db->num_rows($resql) > 0) {
3454  // Last seen cycle
3455  $ref = 0;
3456  while ($obj = $this->db->fetch_object($resql)){
3457  //Same company ?
3458  if ($socid == $obj->fk_soc) {
3459  //Same cycle ?
3460  if ($obj->situation_cycle_ref != $ref) {
3461  // Just seen this cycle
3462  $ref = $obj->situation_cycle_ref;
3463  //not final ?
3464  if ($obj->situation_final != 1) {
3465  //Not prov?
3466  if (substr($obj->facnumber, 1, 4) != 'PROV') {
3467  if ($selected == $obj->rowid) {
3468  $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->facnumber . '</option>';
3469  } else {
3470  $opt .= '<option value="' . $obj->rowid . '">' . $obj->facnumber . '</option>';
3471  }
3472  }
3473  }
3474  }
3475  }
3476  }
3477  }
3478  else
3479  {
3480  dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
3481  }
3482  if ($opt == '<option value ="" selected></option>')
3483  {
3484  $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
3485  }
3486  return $opt;
3487  }
3488 
3497  function selectUnits($selected = '', $htmlname = 'units', $showempty=0)
3498  {
3499  global $langs;
3500 
3501  $langs->load('products');
3502 
3503  $return= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
3504 
3505  $sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units';
3506  $sql.= ' WHERE active > 0';
3507 
3508  $resql = $this->db->query($sql);
3509  if($resql && $this->db->num_rows($resql) > 0)
3510  {
3511  if ($showempty) $return .= '<option value="none"></option>';
3512 
3513  while($res = $this->db->fetch_object($resql))
3514  {
3515  $unitLabel = $res->label;
3516  if (! empty($langs->tab_translate['unit'.$res->code])) // check if Translation is available before
3517  {
3518  $unitLabel = $langs->trans('unit'.$res->code)!=$res->label?$langs->trans('unit'.$res->code):$res->label;
3519  }
3520 
3521  if ($selected == $res->rowid)
3522  {
3523  $return.='<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
3524  }
3525  else
3526  {
3527  $return.='<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
3528  }
3529  }
3530  $return.='</select>';
3531  }
3532  return $return;
3533  }
3534 
3535  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3548  function select_comptes($selected='',$htmlname='accountid',$statut=0,$filtre='',$useempty=0,$moreattrib='',$showcurrency=0)
3549  {
3550  // phpcs:enable
3551  global $langs, $conf;
3552 
3553  $langs->load("admin");
3554 
3555  $sql = "SELECT rowid, label, bank, clos as status, currency_code";
3556  $sql.= " FROM ".MAIN_DB_PREFIX."bank_account";
3557  $sql.= " WHERE entity IN (".getEntity('bank_account').")";
3558  if ($statut != 2) $sql.= " AND clos = '".$statut."'";
3559  if ($filtre) $sql.=" AND ".$filtre;
3560  $sql.= " ORDER BY label";
3561 
3562  dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
3563  $result = $this->db->query($sql);
3564  if ($result)
3565  {
3566  $num = $this->db->num_rows($result);
3567  $i = 0;
3568  if ($num)
3569  {
3570  print '<select id="select'.$htmlname.'" class="flat selectbankaccount" name="'.$htmlname.'"'.($moreattrib?' '.$moreattrib:'').'>';
3571  if ($useempty == 1 || ($useempty == 2 && $num > 1))
3572  {
3573  print '<option value="-1">&nbsp;</option>';
3574  }
3575 
3576  while ($i < $num)
3577  {
3578  $obj = $this->db->fetch_object($result);
3579  if ($selected == $obj->rowid)
3580  {
3581  print '<option value="'.$obj->rowid.'" selected>';
3582  }
3583  else
3584  {
3585  print '<option value="'.$obj->rowid.'">';
3586  }
3587  print trim($obj->label);
3588  if ($showcurrency) print ' ('.$obj->currency_code.')';
3589  if ($statut == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
3590  print '</option>';
3591  $i++;
3592  }
3593  print "</select>";
3594  }
3595  else
3596  {
3597  if ($statut == 0) print $langs->trans("NoActiveBankAccountDefined");
3598  else print $langs->trans("NoBankAccountFound");
3599  }
3600  }
3601  else {
3602  dol_print_error($this->db);
3603  }
3604  }
3605 
3615  function formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
3616  {
3617  global $langs;
3618  if ($htmlname != "none") {
3619  print '<form method="POST" action="'.$page.'">';
3620  print '<input type="hidden" name="action" value="setbankaccount">';
3621  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
3622  $this->select_comptes($selected, $htmlname, 0, '', $addempty);
3623  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3624  print '</form>';
3625  } else {
3626 
3627  $langs->load('banks');
3628 
3629  if ($selected) {
3630  require_once DOL_DOCUMENT_ROOT .'/compta/bank/class/account.class.php';
3631  $bankstatic=new Account($this->db);
3632  $result = $bankstatic->fetch($selected);
3633  if ($result) print $bankstatic->getNomUrl(1);
3634  } else {
3635  print "&nbsp;";
3636  }
3637  }
3638  }
3639 
3640  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3653  function select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $excludeafterid=0, $outputmode=0)
3654  {
3655  // phpcs:enable
3656  global $conf, $langs;
3657  $langs->load("categories");
3658 
3659  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
3660 
3661  // For backward compatibility
3662  if (is_numeric($type))
3663  {
3664  dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
3665  }
3666 
3667  if ($type === Categorie::TYPE_BANK_LINE)
3668  {
3669  // TODO Move this into common category feature
3670  $categids=array();
3671  $sql = "SELECT c.label, c.rowid";
3672  $sql.= " FROM ".MAIN_DB_PREFIX."bank_categ as c";
3673  $sql.= " WHERE entity = ".$conf->entity;
3674  $sql.= " ORDER BY c.label";
3675  $result = $this->db->query($sql);
3676  if ($result)
3677  {
3678  $num = $this->db->num_rows($result);
3679  $i = 0;
3680  while ($i < $num)
3681  {
3682  $objp = $this->db->fetch_object($result);
3683  if ($objp) $cate_arbo[$objp->rowid]=array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
3684  $i++;
3685  }
3686  $this->db->free($result);
3687  }
3688  else dol_print_error($this->db);
3689  }
3690  else
3691  {
3692  $cat = new Categorie($this->db);
3693  $cate_arbo = $cat->get_full_arbo($type, $excludeafterid);
3694  }
3695 
3696  $output = '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
3697  $outarray=array();
3698  if (is_array($cate_arbo))
3699  {
3700  if (! count($cate_arbo)) $output.= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
3701  else
3702  {
3703  $output.= '<option value="-1">&nbsp;</option>';
3704  foreach($cate_arbo as $key => $value)
3705  {
3706  if ($cate_arbo[$key]['id'] == $selected || ($selected == 'auto' && count($cate_arbo) == 1))
3707  {
3708  $add = 'selected ';
3709  }
3710  else
3711  {
3712  $add = '';
3713  }
3714  $output.= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'],$maxlength,'middle').'</option>';
3715 
3716  $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
3717  }
3718  }
3719  }
3720  $output.= '</select>';
3721  $output.= "\n";
3722 
3723  if ($outputmode) return $outarray;
3724  return $output;
3725  }
3726 
3727  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3744  function form_confirm($page, $title, $question, $action, $formquestion='', $selectedchoice="", $useajax=0, $height=170, $width=500)
3745  {
3746  // phpcs:enable
3747  dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
3748  print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
3749  }
3750 
3775  function formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=210, $width=500, $disableformtag=0)
3776  {
3777  global $langs,$conf;
3778  global $useglobalvars;
3779 
3780  $more='';
3781  $formconfirm='';
3782  $inputok=array();
3783  $inputko=array();
3784 
3785  // Clean parameters
3786  $newselectedchoice=empty($selectedchoice)?"no":$selectedchoice;
3787  if ($conf->browser->layout == 'phone') $width='95%';
3788 
3789  if (is_array($formquestion) && ! empty($formquestion))
3790  {
3791  // First add hidden fields and value
3792  foreach ($formquestion as $key => $input)
3793  {
3794  if (is_array($input) && ! empty($input))
3795  {
3796  if ($input['type'] == 'hidden')
3797  {
3798  $more.='<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
3799  }
3800  }
3801  }
3802 
3803  // Now add questions
3804  $more.='<table class="paddingtopbottomonly" width="100%">'."\n";
3805  if (! empty($formquestion['text'])) $more.='<tr><td colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
3806  foreach ($formquestion as $key => $input)
3807  {
3808  if (is_array($input) && ! empty($input))
3809  {
3810  $size=(! empty($input['size'])?' size="'.$input['size'].'"':'');
3811  $moreattr=(! empty($input['moreattr'])?' '.$input['moreattr']:'');
3812  $morecss=(! empty($input['morecss'])?' '.$input['morecss']:'');
3813 
3814  if ($input['type'] == 'text')
3815  {
3816  $more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td><td align="left"><input type="text" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></td></tr>'."\n";
3817  }
3818  elseif ($input['type'] == 'password')
3819  {
3820  $more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td><td align="left"><input type="password" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></td></tr>'."\n";
3821  }
3822  elseif ($input['type'] == 'select')
3823  {
3824  $more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>';
3825  if (! empty($input['label'])) $more.=$input['label'].'</td><td class="tdtop" align="left">';
3826  $more.=$this->selectarray($input['name'],$input['values'],$input['default'],1,0,0,$moreattr,0,0,0,'',$morecss);
3827  $more.='</td></tr>'."\n";
3828  }
3829  elseif ($input['type'] == 'checkbox')
3830  {
3831  $more.='<tr>';
3832  $more.='<td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].' </td><td align="left">';
3833  $more.='<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr;
3834  if (! is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') $more.=' checked';
3835  if (is_bool($input['value']) && $input['value']) $more.=' checked';
3836  if (isset($input['disabled'])) $more.=' disabled';
3837  $more.=' /></td>';
3838  $more.='</tr>'."\n";
3839  }
3840  elseif ($input['type'] == 'radio')
3841  {
3842  $i=0;
3843  foreach($input['values'] as $selkey => $selval)
3844  {
3845  $more.='<tr>';
3846  if ($i==0) $more.='<td'.(empty($input['tdclass'])?' class="tdtop"':(' class="tdtop '.$input['tdclass'].'"')).'>'.$input['label'].'</td>';
3847  else $more.='<td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>&nbsp;</td>';
3848  $more.='<td><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr;
3849  if ($input['disabled']) $more.=' disabled';
3850  $more.=' /> ';
3851  $more.=$selval;
3852  $more.='</td></tr>'."\n";
3853  $i++;
3854  }
3855  }
3856  elseif ($input['type'] == 'date')
3857  {
3858  $more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td>';
3859  $more.='<td align="left">';
3860  $more.=$this->selectDate($input['value'],$input['name'],0,0,0,'',1,0);
3861  $more.='</td></tr>'."\n";
3862  $formquestion[] = array('name'=>$input['name'].'day');
3863  $formquestion[] = array('name'=>$input['name'].'month');
3864  $formquestion[] = array('name'=>$input['name'].'year');
3865  $formquestion[] = array('name'=>$input['name'].'hour');
3866  $formquestion[] = array('name'=>$input['name'].'min');
3867  }
3868  elseif ($input['type'] == 'other')
3869  {
3870  $more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>';
3871  if (! empty($input['label'])) $more.=$input['label'].'</td><td align="left">';
3872  $more.=$input['value'];
3873  $more.='</td></tr>'."\n";
3874  }
3875 
3876  elseif ($input['type'] == 'onecolumn')
3877  {
3878  $more.='<tr><td colspan="2" align="left">';
3879  $more.=$input['value'];
3880  $more.='</td></tr>'."\n";
3881  }
3882  }
3883  }
3884  $more.='</table>'."\n";
3885  }
3886 
3887  // JQUI method dialog is broken with jmobile, we use standard HTML.
3888  // 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
3889  // See page product/card.php for example
3890  if (! empty($conf->dol_use_jmobile)) $useajax=0;
3891  if (empty($conf->use_javascript_ajax)) $useajax=0;
3892 
3893  if ($useajax)
3894  {
3895  $autoOpen=true;
3896  $dialogconfirm='dialog-confirm';
3897  $button='';
3898  if (! is_numeric($useajax))
3899  {
3900  $button=$useajax;
3901  $useajax=1;
3902  $autoOpen=false;
3903  $dialogconfirm.='-'.$button;
3904  }
3905  $pageyes=$page.(preg_match('/\?/',$page)?'&':'?').'action='.$action.'&confirm=yes';
3906  $pageno=($useajax == 2 ? $page.(preg_match('/\?/',$page)?'&':'?').'confirm=no':'');
3907  // Add input fields into list of fields to read during submit (inputok and inputko)
3908  if (is_array($formquestion))
3909  {
3910  foreach ($formquestion as $key => $input)
3911  {
3912  //print "xx ".$key." rr ".is_array($input)."<br>\n";
3913  if (is_array($input) && isset($input['name'])) array_push($inputok,$input['name']);
3914  if (isset($input['inputko']) && $input['inputko'] == 1) array_push($inputko,$input['name']);
3915  }
3916  }
3917  // Show JQuery confirm box. Note that global var $useglobalvars is used inside this template
3918  $formconfirm.= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
3919  if (! empty($more)) {
3920  $formconfirm.= '<div class="confirmquestions">'.$more.'</div>';
3921  }
3922  $formconfirm.= ($question ? '<div class="confirmmessage">'.img_help('','').' '.$question . '</div>': '');
3923  $formconfirm.= '</div>'."\n";
3924 
3925  $formconfirm.= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
3926  $formconfirm.= '<script type="text/javascript">'."\n";
3927  $formconfirm.= 'jQuery(document).ready(function() {
3928  $(function() {
3929  $( "#'.$dialogconfirm.'" ).dialog(
3930  {
3931  autoOpen: '.($autoOpen ? "true" : "false").',';
3932  if ($newselectedchoice == 'no')
3933  {
3934  $formconfirm.='
3935  open: function() {
3936  $(this).parent().find("button.ui-button:eq(2)").focus();
3937  },';
3938  }
3939  $formconfirm.='
3940  resizable: false,
3941  height: "'.$height.'",
3942  width: "'.$width.'",
3943  modal: true,
3944  closeOnEscape: false,
3945  buttons: {
3946  "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
3947  var options="";
3948  var inputok = '.json_encode($inputok).';
3949  var pageyes = "'.dol_escape_js(! empty($pageyes)?$pageyes:'').'";
3950  if (inputok.length>0) {
3951  $.each(inputok, function(i, inputname) {
3952  var more = "";
3953  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
3954  if ($("#" + inputname).attr("type") == "radio") { more = ":checked"; }
3955  var inputvalue = $("#" + inputname + more).val();
3956  if (typeof inputvalue == "undefined") { inputvalue=""; }
3957  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
3958  });
3959  }
3960  var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
3961  //alert(urljump);
3962  if (pageyes.length > 0) { location.href = urljump; }
3963  $(this).dialog("close");
3964  },
3965  "'.dol_escape_js($langs->transnoentities("No")).'": function() {
3966  var options = "";
3967  var inputko = '.json_encode($inputko).';
3968  var pageno="'.dol_escape_js(! empty($pageno)?$pageno:'').'";
3969  if (inputko.length>0) {
3970  $.each(inputko, function(i, inputname) {
3971  var more = "";
3972  if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
3973  var inputvalue = $("#" + inputname + more).val();
3974  if (typeof inputvalue == "undefined") { inputvalue=""; }
3975  options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
3976  });
3977  }
3978  var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
3979  //alert(urljump);
3980  if (pageno.length > 0) { location.href = urljump; }
3981  $(this).dialog("close");
3982  }
3983  }
3984  }
3985  );
3986 
3987  var button = "'.$button.'";
3988  if (button.length > 0) {
3989  $( "#" + button ).click(function() {
3990  $("#'.$dialogconfirm.'").dialog("open");
3991  });
3992  }
3993  });
3994  });
3995  </script>';
3996  $formconfirm.= "<!-- end ajax formconfirm -->\n";
3997  }
3998  else
3999  {
4000  $formconfirm.= "\n<!-- begin formconfirm page=".$page." -->\n";
4001 
4002  if (empty($disableformtag)) $formconfirm.= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
4003 
4004  $formconfirm.= '<input type="hidden" name="action" value="'.$action.'">'."\n";
4005  if (empty($disableformtag)) $formconfirm.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'."\n";
4006 
4007  $formconfirm.= '<table width="100%" class="valid">'."\n";
4008 
4009  // Line title
4010  $formconfirm.= '<tr class="validtitre"><td class="validtitre" colspan="3">'.img_picto('','recent').' '.$title.'</td></tr>'."\n";
4011 
4012  // Line form fields
4013  if ($more)
4014  {
4015  $formconfirm.='<tr class="valid"><td class="valid" colspan="3">'."\n";
4016  $formconfirm.=$more;
4017  $formconfirm.='</td></tr>'."\n";
4018  }
4019 
4020  // Line with question
4021  $formconfirm.= '<tr class="valid">';
4022  $formconfirm.= '<td class="valid">'.$question.'</td>';
4023  $formconfirm.= '<td class="valid">';
4024  $formconfirm.= $this->selectyesno("confirm",$newselectedchoice);
4025  $formconfirm.= '</td>';
4026  $formconfirm.= '<td class="valid" align="center"><input class="button valignmiddle" type="submit" value="'.$langs->trans("Validate").'"></td>';
4027  $formconfirm.= '</tr>'."\n";
4028 
4029  $formconfirm.= '</table>'."\n";
4030 
4031  if (empty($disableformtag)) $formconfirm.= "</form>\n";
4032  $formconfirm.= '<br>';
4033 
4034  $formconfirm.= "<!-- end formconfirm -->\n";
4035  }
4036 
4037  return $formconfirm;
4038  }
4039 
4040 
4041  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4055  function form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0)
4056  {
4057  // phpcs:enable
4058  global $langs;
4059 
4060  require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
4061  require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
4062 
4063  $out='';
4064 
4065  $formproject=new FormProjets($this->db);
4066 
4067  $langs->load("project");
4068  if ($htmlname != "none")
4069  {
4070  $out.="\n";
4071  $out.='<form method="post" action="'.$page.'">';
4072  $out.='<input type="hidden" name="action" value="classin">';
4073  $out.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4074  $out.=$formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
4075  $out.='<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4076  $out.='</form>';
4077  }
4078  else
4079  {
4080  if ($selected)
4081  {
4082  $projet = new Project($this->db);
4083  $projet->fetch($selected);
4084  //print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
4085  $out.=$projet->getNomUrl(0,'',1);
4086  }
4087  else
4088  {
4089  $out.="&nbsp;";
4090  }
4091  }
4092 
4093  if (empty($nooutput))
4094  {
4095  print $out;
4096  return '';
4097  }
4098  return $out;
4099  }
4100 
4101  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4111  function form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0)
4112  {
4113  // phpcs:enable
4114  global $langs;
4115  if ($htmlname != "none")
4116  {
4117  print '<form method="post" action="'.$page.'">';
4118  print '<input type="hidden" name="action" value="setconditions">';
4119  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4120  $this->select_conditions_paiements($selected,$htmlname,-1,$addempty);
4121  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4122  print '</form>';
4123  }
4124  else
4125  {
4126  if ($selected)
4127  {
4129  print $this->cache_conditions_paiements[$selected]['label'];
4130  } else {
4131  print "&nbsp;";
4132  }
4133  }
4134  }
4135 
4136  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4146  function form_availability($page, $selected='', $htmlname='availability', $addempty=0)
4147  {
4148  // phpcs:enable
4149  global $langs;
4150  if ($htmlname != "none")
4151  {
4152  print '<form method="post" action="'.$page.'">';
4153  print '<input type="hidden" name="action" value="setavailability">';
4154  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4155  $this->selectAvailabilityDelay($selected,$htmlname,-1,$addempty);
4156  print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4157  print '</form>';
4158  }
4159  else
4160  {
4161  if ($selected)
4162  {
4163  $this->load_cache_availability();
4164  print $this->cache_availability[$selected]['label'];
4165  } else {
4166  print "&nbsp;";
4167  }
4168  }
4169  }
4170 
4181  function formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
4182  {
4183  global $langs;
4184  if ($htmlname != "none")
4185  {
4186  print '<form method="post" action="'.$page.'">';
4187  print '<input type="hidden" name="action" value="setdemandreason">';
4188  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4189  $this->selectInputReason($selected,$htmlname,-1,$addempty);
4190  print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4191  print '</form>';
4192  }
4193  else
4194  {
4195  if ($selected)
4196  {
4197  $this->loadCacheInputReason();
4198  foreach ($this->cache_demand_reason as $key => $val)
4199  {
4200  if ($val['id'] == $selected)
4201  {
4202  print $val['label'];
4203  break;
4204  }
4205  }
4206  } else {
4207  print "&nbsp;";
4208  }
4209  }
4210  }
4211 
4212  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4225  function form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0)
4226  {
4227  // phpcs:enable
4228  global $langs;
4229 
4230  $ret='';
4231 
4232  if ($htmlname != "none")
4233  {
4234  $ret.='<form method="post" action="'.$page.'" name="form'.$htmlname.'">';
4235  $ret.='<input type="hidden" name="action" value="set'.$htmlname.'">';
4236  $ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4237  $ret.='<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4238  $ret.='<tr><td>';
4239  $ret.=$this->selectDate($selected,$htmlname,$displayhour,$displaymin,1,'form'.$htmlname,1,0);
4240  $ret.='</td>';
4241  $ret.='<td align="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4242  $ret.='</tr></table></form>';
4243  }
4244  else
4245  {
4246  if ($displayhour) $ret.=dol_print_date($selected,'dayhour');
4247  else $ret.=dol_print_date($selected,'day');
4248  }
4249 
4250  if (empty($nooutput)) print $ret;
4251  return $ret;
4252  }
4253 
4254 
4255  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4266  function form_users($page, $selected='', $htmlname='userid', $exclude='', $include='')
4267  {
4268  // phpcs:enable
4269  global $langs;
4270 
4271  if ($htmlname != "none")
4272  {
4273  print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
4274  print '<input type="hidden" name="action" value="set'.$htmlname.'">';
4275  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4276  print $this->select_dolusers($selected,$htmlname,1,$exclude,0,$include);
4277  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4278  print '</form>';
4279  }
4280  else
4281  {
4282  if ($selected)
4283  {
4284  require_once DOL_DOCUMENT_ROOT .'/user/class/user.class.php';
4285  $theuser=new User($this->db);
4286  $theuser->fetch($selected);
4287  print $theuser->getNomUrl(1);
4288  } else {
4289  print "&nbsp;";
4290  }
4291  }
4292  }
4293 
4294 
4295  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4307  function form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0)
4308  {
4309  // phpcs:enable
4310  global $langs;
4311  if ($htmlname != "none")
4312  {
4313  print '<form method="POST" action="'.$page.'">';
4314  print '<input type="hidden" name="action" value="setmode">';
4315  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4316  $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active);
4317  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4318  print '</form>';
4319  }
4320  else
4321  {
4322  if ($selected)
4323  {
4324  $this->load_cache_types_paiements();
4325  print $this->cache_types_paiements[$selected]['label'];
4326  } else {
4327  print "&nbsp;";
4328  }
4329  }
4330  }
4331 
4332  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4341  function form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
4342  {
4343  // phpcs:enable
4344  global $langs;
4345  if ($htmlname != "none")
4346  {
4347  print '<form method="POST" action="'.$page.'">';
4348  print '<input type="hidden" name="action" value="setmulticurrencycode">';
4349  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4350  print $this->selectMultiCurrency($selected, $htmlname, 0);
4351  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4352  print '</form>';
4353  }
4354  else
4355  {
4356  dol_include_once('/core/lib/company.lib.php');
4357  print !empty($selected) ? currency_name($selected,1) : '&nbsp;';
4358  }
4359  }
4360 
4361  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4371  function form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
4372  {
4373  // phpcs:enable
4374  global $langs, $mysoc, $conf;
4375 
4376  if ($htmlname != "none")
4377  {
4378  print '<form method="POST" action="'.$page.'">';
4379  print '<input type="hidden" name="action" value="setmulticurrencyrate">';
4380  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4381  print '<input type="text" name="'.$htmlname.'" value="'.(!empty($rate) ? price($rate) : 1).'" size="10" /> ';
4382  print '<select name="calculation_mode">';
4383  print '<option value="1">'.$currency.' > '.$conf->currency.'</option>';
4384  print '<option value="2">'.$conf->currency.' > '.$currency.'</option>';
4385  print '</select> ';
4386  print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4387  print '</form>';
4388  }
4389  else
4390  {
4391  if (! empty($rate))
4392  {
4393  print price($rate, 1, $langs, 1, 0);
4394  if ($currency && $rate != 1) print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
4395  }
4396  else
4397  {
4398  print 1;
4399  }
4400  }
4401  }
4402 
4403 
4404  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4420  function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
4421  {
4422  // phpcs:enable
4423  global $conf,$langs;
4424  if ($htmlname != "none")
4425  {
4426  print '<form method="post" action="'.$page.'">';
4427  print '<input type="hidden" name="action" value="setabsolutediscount">';
4428  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4429  print '<div class="inline-block">';
4430  if(! empty($discount_type)) {
4431  if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4432  {
4433  if (! $filter || $filter=="fk_invoice_supplier_source IS NULL") $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
4434  else $translationKey = 'HasCreditNoteFromSupplier';
4435  }
4436  else
4437  {
4438  if (! $filter || $filter=="fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") $translationKey = 'HasAbsoluteDiscountFromSupplier';
4439  else $translationKey = 'HasCreditNoteFromSupplier';
4440  }
4441  } else {
4442  if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4443  {
4444  if (! $filter || $filter=="fk_facture_source IS NULL") $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
4445  else $translationKey = 'CompanyHasCreditNote';
4446  }
4447  else
4448  {
4449  if (! $filter || $filter=="fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") $translationKey = 'CompanyHasAbsoluteDiscount';
4450  else $translationKey = 'CompanyHasCreditNote';
4451  }
4452  }
4453  print $langs->trans($translationKey,price($amount,0,$langs,0,0,-1,$conf->currency));
4454  if (empty($hidelist)) print ': ';
4455  print '</div>';
4456  if (empty($hidelist))
4457  {
4458  print '<div class="inline-block" style="padding-right: 10px">';
4459  $newfilter = 'discount_type='.intval($discount_type);
4460  if(! empty($discount_type)) {
4461  $newfilter.= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
4462  } else {
4463  $newfilter.= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
4464  }
4465  if ($filter) $newfilter.=' AND ('.$filter.')';
4466  $nbqualifiedlines=$this->select_remises($selected,$htmlname,$newfilter,$socid,$maxvalue);
4467  if ($nbqualifiedlines > 0)
4468  {
4469  print ' &nbsp; <input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
4470  if(! empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')")
4471  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4472  if(empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')")
4473  print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4474 
4475  print '>';
4476  }
4477  print '</div>';
4478  }
4479  if ($more)
4480  {
4481  print '<div class="inline-block">';
4482  print $more;
4483  print '</div>';
4484  }
4485  print '</form>';
4486  }
4487  else
4488  {
4489  if ($selected)
4490  {
4491  print $selected;
4492  }
4493  else
4494  {
4495  print "0";
4496  }
4497  }
4498  }
4499 
4500 
4501  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4511  function form_contacts($page, $societe, $selected='', $htmlname='contactid')
4512  {
4513  // phpcs:enable
4514  global $langs, $conf;
4515 
4516  if ($htmlname != "none")
4517  {
4518  print '<form method="post" action="'.$page.'">';
4519  print '<input type="hidden" name="action" value="set_contact">';
4520  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4521  print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4522  print '<tr><td>';
4523  $num=$this->select_contacts($societe->id, $selected, $htmlname);
4524  if ($num==0)
4525  {
4526  $addcontact = (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
4527  print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
4528  }
4529  print '</td>';
4530  print '<td align="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4531  print '</tr></table></form>';
4532  }
4533  else
4534  {
4535  if ($selected)
4536  {
4537  require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php';
4538  $contact=new Contact($this->db);
4539  $contact->fetch($selected);
4540  print $contact->getFullName($langs);
4541  } else {
4542  print "&nbsp;";
4543  }
4544  }
4545  }
4546 
4547  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4562  function form_thirdparty($page, $selected='', $htmlname='socid', $filter='',$showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0)
4563  {
4564  // phpcs:enable
4565  global $langs;
4566 
4567  $out = '';
4568  if ($htmlname != "none")
4569  {
4570  $out.='<form method="post" action="'.$page.'">';
4571  $out.= '<input type="hidden" name="action" value="set_thirdparty">';
4572  $out.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4573  $out.= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events);
4574  $out.= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4575  $out.= '</form>';
4576  }
4577  else
4578  {
4579  if ($selected)
4580  {
4581  require_once DOL_DOCUMENT_ROOT .'/societe/class/societe.class.php';
4582  $soc = new Societe($this->db);
4583  $soc->fetch($selected);
4584  $out.= $soc->getNomUrl($langs);
4585  }
4586  else
4587  {
4588  $out.= "&nbsp;";
4589  }
4590  }
4591 
4592  if ($nooutput) return $out;
4593  else print $out;
4594  }
4595 
4596  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4605  function select_currency($selected='',$htmlname='currency_id')
4606  {
4607  // phpcs:enable
4608  print $this->selectCurrency($selected,$htmlname);
4609  }
4610 
4618  function selectCurrency($selected='',$htmlname='currency_id')
4619  {
4620  global $conf,$langs,$user;
4621 
4622  $langs->loadCacheCurrencies('');
4623 
4624  $out='';
4625 
4626  if ($selected=='euro' || $selected=='euros') $selected='EUR'; // Pour compatibilite
4627 
4628  $out.= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
4629  foreach ($langs->cache_currencies as $code_iso => $currency)
4630  {
4631  if ($selected && $selected == $code_iso)
4632  {
4633  $out.= '<option value="'.$code_iso.'" selected>';
4634  }
4635  else
4636  {
4637  $out.= '<option value="'.$code_iso.'">';
4638  }
4639  $out.= $currency['label'];
4640  $out.= ' ('.$langs->getCurrencySymbol($code_iso).')';
4641  $out.= '</option>';
4642  }
4643  $out.= '</select>';
4644  if ($user->admin) $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
4645 
4646  // Make select dynamic
4647  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4648  $out .= ajax_combobox($htmlname);
4649 
4650  return $out;
4651  }
4652 
4661  function selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0)
4662  {
4663  global $db,$conf,$langs,$user;
4664 
4665  $langs->loadCacheCurrencies(''); // Load ->cache_currencies
4666 
4667  $TCurrency = array();
4668 
4669  $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
4670  $sql.= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
4671  $resql = $db->query($sql);
4672  if ($resql)
4673  {
4674  while ($obj = $db->fetch_object($resql)) $TCurrency[$obj->code] = $obj->code;
4675  }
4676 
4677  $out='';
4678  $out.= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
4679  if ($useempty) $out .= '<option value=""></option>';
4680  // If company current currency not in table, we add it into list. Should always be available.
4681  if (! in_array($conf->currency, $TCurrency))
4682  {
4683  $TCurrency[$conf->currency] = $conf->currency;
4684  }
4685  if (count($TCurrency) > 0)
4686  {
4687  foreach ($langs->cache_currencies as $code_iso => $currency)
4688  {
4689  if (isset($TCurrency[$code_iso]))
4690  {
4691  if (!empty($selected) && $selected == $code_iso) $out.= '<option value="'.$code_iso.'" selected="selected">';
4692  else $out.= '<option value="'.$code_iso.'">';
4693 
4694  $out.= $currency['label'];
4695  $out.= ' ('.$langs->getCurrencySymbol($code_iso).')';
4696  $out.= '</option>';
4697  }
4698  }
4699  }
4700 
4701  $out.= '</select>';
4702  // Make select dynamic
4703  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4704  $out.= ajax_combobox($htmlname);
4705 
4706  return $out;
4707  }
4708 
4709  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4716  function load_cache_vatrates($country_code)
4717  {
4718  // phpcs:enable
4719  global $langs;
4720 
4721  $num = count($this->cache_vatrates);
4722  if ($num > 0) return $num; // Cache already loaded
4723 
4724  dol_syslog(__METHOD__, LOG_DEBUG);
4725 
4726  $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
4727  $sql.= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
4728  $sql.= " WHERE t.fk_pays = c.rowid";
4729  $sql.= " AND t.active > 0";
4730  $sql.= " AND c.code IN (".$country_code.")";
4731  $sql.= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
4732 
4733  $resql=$this->db->query($sql);
4734  if ($resql)
4735  {
4736  $num = $this->db->num_rows($resql);
4737  if ($num)
4738  {
4739  for ($i = 0; $i < $num; $i++)
4740  {
4741  $obj = $this->db->fetch_object($resql);
4742  $this->cache_vatrates[$i]['rowid'] = $obj->rowid;
4743  $this->cache_vatrates[$i]['code'] = $obj->code;
4744  $this->cache_vatrates[$i]['txtva'] = $obj->taux;
4745  $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
4746  $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1;
4747  $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type;
4748  $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2;
4749  $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type;
4750 
4751  $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code?' ('.$obj->code.')':''); // Label must contains only 0-9 , . % or *
4752  $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
4753  $positiverates='';
4754  if ($obj->taux) $positiverates.=($positiverates?'/':'').$obj->taux;
4755  if ($obj->localtax1) $positiverates.=($positiverates?'/':'').$obj->localtax1;
4756  if ($obj->localtax2) $positiverates.=($positiverates?'/':'').$obj->localtax2;
4757  if (empty($positiverates)) $positiverates='0';
4758  $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code?' ('.$obj->code.')':''); // Must never be used as key, only label
4759  }
4760 
4761  return $num;
4762  }
4763  else
4764  {
4765  $this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry",$country_code).'</font>';
4766  return -1;
4767  }
4768  }
4769  else
4770  {
4771  $this->error = '<font class="error">'.$this->db->error().'</font>';
4772  return -2;
4773  }
4774  }
4775 
4776  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4798  function load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse='', $societe_acheteuse='', $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0)
4799  {
4800  // phpcs:enable
4801  global $langs,$conf,$mysoc;
4802 
4803  $langs->load('errors');
4804 
4805  $return='';
4806 
4807  // Define defaultnpr, defaultttx and defaultcode
4808  $defaultnpr=($info_bits & 0x01);
4809  $defaultnpr=(preg_match('/\*/',$selectedrate) ? 1 : $defaultnpr);
4810  $defaulttx=str_replace('*','',$selectedrate);
4811  $defaultcode='';
4812  if (preg_match('/\((.*)\)/', $defaulttx, $reg))
4813  {
4814  $defaultcode=$reg[1];
4815  $defaulttx=preg_replace('/\s*\(.*\)/','',$defaulttx);
4816  }
4817  //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
4818 
4819  // Check parameters
4820  if (is_object($societe_vendeuse) && ! $societe_vendeuse->country_code)
4821  {
4822  if ($societe_vendeuse->id == $mysoc->id)
4823  {
4824  $return.= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</div>';
4825  }
4826  else
4827  {
4828  $return.= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</div>';
4829  }
4830  return $return;
4831  }
4832 
4833  //var_dump($societe_acheteuse);
4834  //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";
4835  //exit;
4836 
4837  // Define list of countries to use to search VAT rates to show
4838  // First we defined code_country to use to find list
4839  if (is_object($societe_vendeuse))
4840  {
4841  $code_country="'".$societe_vendeuse->country_code."'";
4842  }
4843  else
4844  {
4845  $code_country="'".$mysoc->country_code."'"; // Pour compatibilite ascendente
4846  }
4847  if (! empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) // If option to have vat for end customer for services is on
4848  {
4849  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
4850  if (! isInEEC($societe_vendeuse) && (! is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && ! $societe_acheteuse->isACompany())))
4851  {
4852  // We also add the buyer
4853  if (is_numeric($type))
4854  {
4855  if ($type == 1) // We know product is a service
4856  {
4857  $code_country.=",'".$societe_acheteuse->country_code."'";
4858  }
4859  }
4860  else if (! $idprod) // We don't know type of product
4861  {
4862  $code_country.=",'".$societe_acheteuse->country_code."'";
4863  }
4864  else
4865  {
4866  $prodstatic=new Product($this->db);
4867  $prodstatic->fetch($idprod);
4868  if ($prodstatic->type == Product::TYPE_SERVICE) // We know product is a service
4869  {
4870  $code_country.=",'".$societe_acheteuse->country_code."'";
4871  }
4872  }
4873  }
4874  }
4875 
4876  // Now we get list
4877  $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
4878 
4879  if ($num > 0)
4880  {
4881  // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
4882  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
4883  {
4884  $tmpthirdparty=new Societe($this->db);
4885  $defaulttx=get_default_tva($societe_vendeuse, (is_object($societe_acheteuse)?$societe_acheteuse:$tmpthirdparty), $idprod);
4886  $defaultnpr=get_default_npr($societe_vendeuse, (is_object($societe_acheteuse)?$societe_acheteuse:$tmpthirdparty), $idprod);
4887  if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
4888  $defaultcode=$reg[1];
4889  $defaulttx=preg_replace('/\s*\(.*\)/','',$defaulttx);
4890  }
4891  if (empty($defaulttx)) $defaultnpr=0;
4892  }
4893 
4894  // Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
4895  // Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
4896  if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
4897  {
4898  if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) $defaulttx = $this->cache_vatrates[$num-1]['txtva'];
4899  else $defaulttx=($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
4900  }
4901 
4902  // Disabled if seller is not subject to VAT
4903  $disabled=false; $title='';
4904  if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0")
4905  {
4906  $title=' title="'.$langs->trans('VATIsNotUsed').'"';
4907  $disabled=true;
4908  }
4909 
4910  if (! $options_only) $return.= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled?' disabled':'').$title.'>';
4911 
4912  $selectedfound=false;
4913  foreach ($this->cache_vatrates as $rate)
4914  {
4915  // Keep only 0 if seller is not subject to VAT
4916  if ($disabled && $rate['txtva'] != 0) continue;
4917 
4918  // Define key to use into select list
4919  $key = $rate['txtva'];
4920  $key.= $rate['nprtva'] ? '*': '';
4921  if ($mode > 0 && $rate['code']) $key.=' ('.$rate['code'].')';
4922  if ($mode < 0) $key = $rate['rowid'];
4923 
4924  $return.= '<option value="'.$key.'"';
4925  if (! $selectedfound)
4926  {
4927  if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
4928  {
4929  if ($defaultcode == $rate['code'])
4930  {
4931  $return.= ' selected';
4932  $selectedfound=true;
4933  }
4934  }
4935  elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
4936  {
4937  $return.= ' selected';
4938  $selectedfound=true;
4939  }
4940  }
4941  $return.= '>';
4942  //if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
4943  if ($mysoc->country_code == 'IN' || ! empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES))
4944  {
4945  $return.= $rate['labelpositiverates'];
4946  }
4947  else
4948  {
4949  $return.= vatrate($rate['label']);
4950  }
4951  //$return.=($rate['code']?' '.$rate['code']:'');
4952  $return.= (empty($rate['code']) && $rate['nprtva']) ? ' *': ''; // We show the * (old behaviour only if new vat code is not used)
4953 
4954  $return.= '</option>';
4955  }
4956 
4957  if (! $options_only) $return.= '</select>';
4958  }
4959  else
4960  {
4961  $return.= $this->error;
4962  }
4963 
4964  $this->num = $num;
4965  return $return;
4966  }
4967 
4968 
4969  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4994  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='')
4995  {
4996  // phpcs:enable
4997  $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
4998  if (! empty($nooutput)) {
4999  return $retstring;
5000  }
5001  print $retstring;
5002  return;
5003  }
5004 
5027  function selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='')
5028  {
5029  global $conf,$langs;
5030 
5031  $retstring='';
5032 
5033  if ($prefix=='') $prefix='re';
5034  if ($h == '') $h=0;
5035  if ($m == '') $m=0;
5036  $emptydate=0;
5037  $emptyhours=0;
5038  if ($empty == 1) { $emptydate=1; $emptyhours=1; }
5039  if ($empty == 2) { $emptydate=0; $emptyhours=1; }
5040  $orig_set_time=$set_time;
5041 
5042  if ($set_time === '' && $emptydate == 0)
5043  {
5044  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5045  $set_time = dol_now('tzuser')-(getServerTimeZoneInt('now')*3600); // set_time must be relative to PHP server timezone
5046  }
5047 
5048  // Analysis of the pre-selection date
5049  if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/',$set_time,$reg)) // deprecated usage
5050  {
5051  // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
5052  $syear = (! empty($reg[1])?$reg[1]:'');
5053  $smonth = (! empty($reg[2])?$reg[2]:'');
5054  $sday = (! empty($reg[3])?$reg[3]:'');
5055  $shour = (! empty($reg[4])?$reg[4]:'');
5056  $smin = (! empty($reg[5])?$reg[5]:'');
5057  }
5058  elseif (strval($set_time) != '' && $set_time != -1)
5059  {
5060  // set_time est un timestamps (0 possible)
5061  $syear = dol_print_date($set_time, "%Y");
5062  $smonth = dol_print_date($set_time, "%m");
5063  $sday = dol_print_date($set_time, "%d");
5064  if ($orig_set_time != '')
5065  {
5066  $shour = dol_print_date($set_time, "%H");
5067  $smin = dol_print_date($set_time, "%M");
5068  $ssec = dol_print_date($set_time, "%S");
5069  }
5070  else
5071  {
5072  $shour = '';
5073  $smin = '';
5074  $ssec = '';
5075  }
5076  }
5077  else
5078  {
5079  // Date est '' ou vaut -1
5080  $syear = '';
5081  $smonth = '';
5082  $sday = '';
5083  $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
5084  $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
5085  $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
5086  }
5087  if ($h == 3) $shour = '';
5088  if ($m == 3) $smin = '';
5089 
5090  // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
5091  $usecalendar='combo';
5092  if (! empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
5093  $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy')?'jquery':$conf->global->MAIN_POPUP_CALENDAR);
5094  }
5095 
5096  if ($d)
5097  {
5098  // Show date with popup
5099  if ($usecalendar != 'combo')
5100  {
5101  $formated_date='';
5102  //print "e".$set_time." t ".$conf->format_date_short;
5103  if (strval($set_time) != '' && $set_time != -1)
5104  {
5105  //$formated_date=dol_print_date($set_time,$conf->format_date_short);
5106  $formated_date=dol_print_date($set_time,$langs->trans("FormatDateShortInput")); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5107  }
5108 
5109  // Calendrier popup version eldy
5110  if ($usecalendar == "eldy")
5111  {
5112  // Zone de saisie manuelle de la date
5113  $retstring.='<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidth75" maxlength="11" value="'.$formated_date.'"';
5114  $retstring.=($disabled?' disabled':'');
5115  $retstring.=' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5116  $retstring.='>';
5117 
5118  // Icone calendrier
5119  if (! $disabled)
5120  {
5121  $retstring.='<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
5122  $base=DOL_URL_ROOT.'/core/';
5123  $retstring.=' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
5124  $retstring.='>'.img_object($langs->trans("SelectDate"),'calendarday','class="datecallink"').'</button>';
5125  }
5126  else $retstring.='<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"),'calendarday','class="datecallink"').'</button>';
5127 
5128  $retstring.='<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
5129  $retstring.='<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5130  $retstring.='<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
5131  }
5132  elseif ($usecalendar == 'jquery')
5133  {
5134  if (! $disabled)
5135  {
5136  // Output javascript for datepicker
5137  $retstring.="<script type='text/javascript'>";
5138  $retstring.="$(function(){ $('#".$prefix."').datepicker({
5139  dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
5140  autoclose: true,
5141  todayHighlight: true,";
5142  if (! empty($conf->dol_use_jmobile))
5143  {
5144  $retstring.="
5145  beforeShow: function (input, datePicker) {
5146  input.disabled = true;
5147  },
5148  onClose: function (dateText, datePicker) {
5149  this.disabled = false;
5150  },
5151  ";
5152  }
5153  // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
5154  if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS))
5155  {
5156  $retstring.="
5157  showOn: 'button',
5158  buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png',
5159  buttonImageOnly: true";
5160  }
5161  $retstring.="
5162  }) });";
5163  $retstring.="</script>";
5164  }
5165 
5166  // Zone de saisie manuelle de la date
5167  $retstring.='<div class="nowrap inline-block">';
5168  $retstring.='<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidth75" maxlength="11" value="'.$formated_date.'"';
5169  $retstring.=($disabled?' disabled':'');
5170  $retstring.=' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5171  $retstring.='>';
5172 
5173  // Icone calendrier
5174  if (! $disabled)
5175  {
5176  /* Not required. Managed by option buttonImage of jquery
5177  $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
5178  $retstring.="<script type='text/javascript'>";
5179  $retstring.="jQuery(document).ready(function() {";
5180  $retstring.=' jQuery("#'.$prefix.'id").click(function() {';
5181  $retstring.=" jQuery('#".$prefix."').focus();";
5182  $retstring.=' });';
5183  $retstring.='});';
5184  $retstring.="</script>";*/
5185  }
5186  else
5187  {
5188  $retstring.='<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"),'calendarday','class="datecallink"').'</button>';
5189  }
5190 
5191  $retstring.='</div>';
5192  $retstring.='<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n";
5193  $retstring.='<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5194  $retstring.='<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n";
5195  }
5196  else
5197  {
5198  $retstring.="Bad value of MAIN_POPUP_CALENDAR";
5199  }
5200  }
5201  // Show date with combo selects
5202  else
5203  {
5204  //$retstring.='<div class="inline-block">';
5205  // Day
5206  $retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
5207 
5208  if ($emptydate || $set_time == -1)
5209  {
5210  $retstring.='<option value="0" selected>&nbsp;</option>';
5211  }
5212 
5213  for ($day = 1 ; $day <= 31; $day++)
5214  {
5215  $retstring.='<option value="'.$day.'"'.($day == $sday ? ' selected':'').'>'.$day.'</option>';
5216  }
5217 
5218  $retstring.="</select>";
5219 
5220  $retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
5221  if ($emptydate || $set_time == -1)
5222  {
5223  $retstring.='<option value="0" selected>&nbsp;</option>';
5224  }
5225 
5226  // Month
5227  for ($month = 1 ; $month <= 12 ; $month++)
5228  {
5229  $retstring.='<option value="'.$month.'"'.($month == $smonth?' selected':'').'>';
5230  $retstring.=dol_print_date(mktime(12,0,0,$month,1,2000),"%b");
5231  $retstring.="</option>";
5232  }
5233  $retstring.="</select>";
5234 
5235  // Year
5236  if ($emptydate || $set_time == -1)
5237  {
5238  $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.'">';
5239  }
5240  else
5241  {
5242  $retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
5243 
5244  for ($year = $syear - 10; $year < $syear + 10 ; $year++)
5245  {
5246  $retstring.='<option value="'.$year.'"'.($year == $syear ? ' selected':'').'>'.$year.'</option>';
5247  }
5248  $retstring.="</select>\n";
5249  }
5250  //$retstring.='</div>';
5251  }
5252  }
5253 
5254  if ($d && $h) $retstring.=($h==2?'<br>':' ');
5255 
5256  if ($h)
5257  {
5258  // Show hour
5259  $retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth50 '.($fullday?$fullday.'hour':'').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
5260  if ($emptyhours) $retstring.='<option value="-1">&nbsp;</option>';
5261  for ($hour = 0; $hour < 24; $hour++)
5262  {
5263  if (strlen($hour) < 2) $hour = "0" . $hour;
5264  $retstring.='<option value="'.$hour.'"'.(($hour == $shour)?' selected':'').'>'.$hour.(empty($conf->dol_optimize_smallscreen)?'':'H').'</option>';
5265  }
5266  $retstring.='</select>';
5267  if ($m && empty($conf->dol_optimize_smallscreen)) $retstring.=":";
5268  }
5269 
5270  if ($m)
5271  {
5272  // Show minutes
5273  $retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth50 '.($fullday?$fullday.'min':'').'" id="'.$prefix.'min" name="'.$prefix.'min">';
5274  if ($emptyhours) $retstring.='<option value="-1">&nbsp;</option>';
5275  for ($min = 0; $min < 60 ; $min++)
5276  {
5277  if (strlen($min) < 2) $min = "0" . $min;
5278  $retstring.='<option value="'.$min.'"'.(($min == $smin)?' selected':'').'>'.$min.(empty($conf->dol_optimize_smallscreen)?'':'').'</option>';
5279  }
5280  $retstring.='</select>';
5281 
5282  $retstring.='<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
5283  }
5284 
5285  // Add a "Now" link
5286  if ($conf->use_javascript_ajax && $addnowlink)
5287  {
5288  // Script which will be inserted in the onClick of the "Now" link
5289  $reset_scripts = "";
5290 
5291  // Generate the date part, depending on the use or not of the javascript calendar
5292  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');';
5293  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');';
5294  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');';
5295  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');';
5296  /*if ($usecalendar == "eldy")
5297  {
5298  $base=DOL_URL_ROOT.'/core/';
5299  $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
5300  }
5301  else
5302  {
5303  $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
5304  $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
5305  $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
5306  }*/
5307  // Update the hour part
5308  if ($h)
5309  {
5310  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5311  //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
5312  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');';
5313  if ($fullday) $reset_scripts .= ' } ';
5314  }
5315  // Update the minute part
5316  if ($m)
5317  {
5318  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5319  //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
5320  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');';
5321  if ($fullday) $reset_scripts .= ' } ';
5322  }
5323  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5324  if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5325  {
5326  $retstring.=' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
5327  $retstring.=$langs->trans("Now");
5328  $retstring.='</button> ';
5329  }
5330  }
5331 
5332  // Add a "Plus one hour" link
5333  if ($conf->use_javascript_ajax && $addplusone)
5334  {
5335  // Script which will be inserted in the onClick of the "Add plusone" link
5336  $reset_scripts = "";
5337 
5338  // Generate the date part, depending on the use or not of the javascript calendar
5339  $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');';
5340  $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');';
5341  $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');';
5342  $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');';
5343  // Update the hour part
5344  if ($h)
5345  {
5346  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5347  $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');';
5348  if ($fullday) $reset_scripts .= ' } ';
5349  }
5350  // Update the minute part
5351  if ($m)
5352  {
5353  if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5354  $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');';
5355  if ($fullday) $reset_scripts .= ' } ';
5356  }
5357  // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5358  if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5359  {
5360  $retstring.=' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
5361  $retstring.=$langs->trans("DateStartPlusOne");
5362  $retstring.='</button> ';
5363  }
5364  }
5365 
5366  // Add a "Plus one hour" link
5367  if ($conf->use_javascript_ajax && $adddateof)
5368  {
5369  $tmparray=dol_getdate($adddateof);
5370  $retstring.=' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="jQuery(\'#re\').val(\''.dol_print_date($adddateof,'day').'\');jQuery(\'#reday\').val(\''.$tmparray['mday'].'\');jQuery(\'#remonth\').val(\''.$tmparray['mon'].'\');jQuery(\'#reyear\').val(\''.$tmparray['year'].'\');">'.$langs->trans("DateInvoice").'</a>';
5371  }
5372 
5373  return $retstring;
5374  }
5375 
5376  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
5390  function select_duration($prefix, $iSecond='', $disabled=0, $typehour='select', $minunderhours=0, $nooutput=0)
5391  {
5392  // phpcs:enable
5393  global $langs;
5394 
5395  $retstring='';
5396 
5397  $hourSelected=0; $minSelected=0;
5398 
5399  // Hours
5400  if ($iSecond != '')
5401  {
5402  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5403 
5404  $hourSelected = convertSecondToTime($iSecond,'allhour');
5405  $minSelected = convertSecondToTime($iSecond,'min');
5406  }
5407 
5408  if ($typehour=='select' )
5409  {
5410  $retstring.='<select class="flat" name="'.$prefix.'hour"'.($disabled?' disabled':'').'>';
5411  for ($hour = 0; $hour < 25; $hour++) // For a duration, we allow 24 hours
5412  {
5413  $retstring.='<option value="'.$hour.'"';
5414  if ($hourSelected == $hour)
5415  {
5416  $retstring.=" selected";
5417  }
5418  $retstring.=">".$hour."</option>";
5419  }
5420  $retstring.="</select>";
5421  }
5422  elseif ($typehour=='text' || $typehour=='textselect')
5423  {
5424  $retstring.='<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" size="1" name="'.$prefix.'hour"'.($disabled?' disabled':'').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '')?((int) $hourSelected):'').'">';
5425  }
5426  else return 'BadValueForParameterTypeHour';
5427 
5428  if ($typehour!='text') $retstring.=' '.$langs->trans('HourShort');
5429  else $retstring.='<span class="hideonsmartphone">:</span>';
5430 
5431  // Minutes
5432  if ($minunderhours) $retstring.='<br>';
5433  else $retstring.='<span class="hideonsmartphone">&nbsp;</span>';
5434 
5435  if ($typehour=='select' || $typehour=='textselect')
5436  {
5437  $retstring.='<select class="flat" name="'.$prefix.'min"'.($disabled?' disabled':'').'>';
5438  for ($min = 0; $min <= 55; $min=$min+5)
5439  {
5440  $retstring.='<option value="'.$min.'"';
5441  if ($minSelected == $min) $retstring.=' selected';
5442  $retstring.='>'.$min.'</option>';
5443  }
5444  $retstring.="</select>";
5445  }
5446  elseif ($typehour=='text' )
5447  {
5448  $retstring.='<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" size="1" name="'.$prefix.'min"'.($disabled?' disabled':'').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '')?((int) $minSelected):'').'">';
5449  }
5450 
5451  if ($typehour!='text') $retstring.=' '.$langs->trans('MinuteShort');
5452 
5453  //$retstring.="&nbsp;";
5454 
5455  if (! empty($nooutput)) return $retstring;
5456 
5457  print $retstring;
5458  return;
5459  }
5460 
5461 
5478  function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0)
5479  {
5480  global $conf, $user;
5481 
5482  $objecttmp = null;
5483 
5484  $InfoFieldList = explode(":", $objectdesc);
5485  $classname=$InfoFieldList[0];
5486  $classpath=$InfoFieldList[1];
5487  if (! empty($classpath))
5488  {
5489  dol_include_once($classpath);
5490  if ($classname && class_exists($classname))
5491  {
5492  $objecttmp = new $classname($this->db);
5493  }
5494  }
5495  if (! is_object($objecttmp))
5496  {
5497  dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
5498  return 'Error bad setup of type for field '.join(',', $InfoFieldList);
5499  }
5500 
5501  $prefixforautocompletemode=$objecttmp->element;
5502  if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode='company';
5503  $confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
5504 
5505  dol_syslog(get_class($this)."::selectForForms", LOG_DEBUG);
5506 
5507  $out='';
5508  if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->$confkeyforautocompletemode) && ! $forcecombo)
5509  {
5510  $objectdesc=$classname.':'.$classpath;
5511  $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
5512  //if ($objecttmp->element == 'societe') $urlforajaxcall = DOL_URL_ROOT.'/societe/ajax/company.php';
5513 
5514  // No immediate load of all database
5515  $urloption='htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.($moreparams?$moreparams:'');
5516  // Activate the auto complete using ajax call.
5517  $out.= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
5518  $out.= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
5519  if ($placeholder) $placeholder=' placeholder="'.$placeholder.'"';
5520  $out.= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$preselectedvalue.'"'.$placeholder.' />';
5521  }
5522  else
5523  {
5524  // Immediate load of all database
5525  $out.=$this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo);
5526  }
5527 
5528  return $out;
5529  }
5530 
5548  function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0, $outputmode=0)
5549  {
5550  global $conf, $langs, $user;
5551 
5552  $prefixforautocompletemode=$objecttmp->element;
5553  if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode='company';
5554  $confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
5555 
5556  $fieldstoshow='t.ref';
5557  if (! empty($objecttmp->fields)) // For object that declare it, it is better to use declared fields ( like societe, contact, ...)
5558  {
5559  $tmpfieldstoshow='';
5560  foreach($objecttmp->fields as $key => $val)
5561  {
5562  if ($val['showoncombobox']) $tmpfieldstoshow.=($tmpfieldstoshow?',':'').'t.'.$key;
5563  }
5564  if ($tmpfieldstoshow) $fieldstoshow = $tmpfieldstoshow;
5565  }
5566 
5567  $out='';
5568  $outarray=array();
5569 
5570  $num=0;
5571 
5572  // Search data
5573  $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX .$objecttmp->table_element." as t";
5574  if ($objecttmp->ismultientitymanaged == 2)
5575  if (!$user->rights->societe->client->voir && !$user->societe_id) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
5576  $sql.= " WHERE 1=1";
5577  if(! empty($objecttmp->ismultientitymanaged)) $sql.= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
5578  if ($objecttmp->ismultientitymanaged == 1 && ! empty($user->societe_id))
5579  {
5580  if ($objecttmp->element == 'societe') $sql.= " AND t.rowid = ".$user->societe_id;
5581  else $sql.= " AND t.fk_soc = ".$user->societe_id;
5582  }
5583  if ($searchkey != '') $sql.=natural_search(explode(',',$fieldstoshow), $searchkey);
5584  if ($objecttmp->ismultientitymanaged == 2)
5585  if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND t.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
5586  $sql.=$this->db->order($fieldstoshow,"ASC");
5587  //$sql.=$this->db->plimit($limit, 0);
5588 
5589  // Build output string
5590  $resql=$this->db->query($sql);
5591  if ($resql)
5592  {
5593  if (! $forcecombo)
5594  {
5595  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5596  $out .= ajax_combobox($htmlname, null, $conf->global->$confkeyforautocompletemode);
5597  }
5598 
5599  // Construct $out and $outarray
5600  $out.= '<select id="'.$htmlname.'" class="flat'.($morecss?' '.$morecss:'').'"'.($moreparams?' '.$moreparams:'').' name="'.$htmlname.'">'."\n";
5601 
5602  // 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
5603  $textifempty='&nbsp;';
5604 
5605  //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
5606  if (! empty($conf->global->$confkeyforautocompletemode))
5607  {
5608  if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
5609  else $textifempty.=$langs->trans("All");
5610  }
5611  if ($showempty) $out.= '<option value="-1">'.$textifempty.'</option>'."\n";
5612 
5613  $num = $this->db->num_rows($resql);
5614  $i = 0;
5615  if ($num)
5616  {
5617  while ($i < $num)
5618  {
5619  $obj = $this->db->fetch_object($resql);
5620  $label='';
5621  $tmparray=explode(',', $fieldstoshow);
5622  foreach($tmparray as $key => $val)
5623  {
5624  $val = preg_replace('/t\./','',$val);
5625  $label .= (($label && $obj->$val)?' - ':'').$obj->$val;
5626  }
5627  if (empty($outputmode))
5628  {
5629  if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid)
5630  {
5631  $out.= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
5632  }
5633  else
5634  {
5635  $out.= '<option value="'.$obj->rowid.'">'.$label.'</option>';
5636  }
5637  }
5638  else
5639  {
5640  array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
5641  }
5642 
5643  $i++;
5644  if (($i % 10) == 0) $out.="\n";
5645  }
5646  }
5647 
5648  $out.= '</select>'."\n";
5649  }
5650  else
5651  {
5652  dol_print_error($this->db);
5653  }
5654 
5655  $this->result=array('nbofelement'=>$num);
5656 
5657  if ($outputmode) return $outarray;
5658  return $out;
5659  }
5660 
5661 
5685  static function selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='', $addjscombo=0, $moreparamonempty='',$disablebademail=0, $nohtmlescape=0)
5686  {
5687  global $conf, $langs;
5688 
5689  // Do we want a multiselect ?
5690  //$jsbeautify = 0;
5691  //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
5692  $jsbeautify = 1;
5693 
5694  if ($value_as_key) $array=array_combine($array, $array);
5695 
5696  $out='';
5697 
5698  // Add code for jquery to use multiselect
5699  if ($addjscombo && $jsbeautify)
5700  {
5701  $minLengthToAutocomplete=0;
5702  $tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?(constant('REQUIRE_JQUERY_MULTISELECT')?constant('REQUIRE_JQUERY_MULTISELECT'):'select2'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
5703 
5704  // Enhance with select2
5705  include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5706  $out .= ajax_combobox($htmlname);
5707  }
5708 
5709  $out.='<select id="'.preg_replace('/^\./','',$htmlname).'" '.($disabled?'disabled ':'').'class="flat '.(preg_replace('/^\./','',$htmlname)).($morecss?' '.$morecss:'').'"';
5710  $out.=' name="'.preg_replace('/^\./','',$htmlname).'" '.($moreparam?$moreparam:'');
5711  $out.='>';
5712 
5713  if ($show_empty)
5714  {
5715  $textforempty=' ';
5716  if (! empty($conf->use_javascript_ajax)) $textforempty='&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
5717  if (! is_numeric($show_empty)) $textforempty=$show_empty;
5718  $out.='<option class="optiongrey" '.($moreparamonempty?$moreparamonempty.' ':'').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ?' selected':'').'>'.$textforempty.'</option>'."\n";
5719  }
5720 
5721  if (is_array($array))
5722  {
5723  // Translate
5724  if ($translate)
5725  {
5726  foreach($array as $key => $value)
5727  {
5728  $array[$key]=$langs->trans($value);
5729  }
5730  }
5731 
5732  // Sort
5733  if ($sort == 'ASC') asort($array);
5734  elseif ($sort == 'DESC') arsort($array);
5735 
5736  foreach($array as $key => $value)
5737  {
5738  $disabled=''; $style='';
5739  if (! empty($disablebademail))
5740  {
5741  if (! preg_match('/&lt;.+@.+&gt;/', $value))
5742  {
5743  //$value=preg_replace('/'.preg_quote($a,'/').'/', $b, $value);
5744  $disabled=' disabled';
5745  $style=' class="warning"';
5746  }
5747  }
5748 
5749  if ($key_in_label)
5750  {
5751  if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen?dol_trunc($value,$maxlen):$value));
5752  else $selectOptionValue = $key.' - '.($maxlen?dol_trunc($value,$maxlen):$value);
5753  }
5754  else
5755  {
5756  if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($maxlen?dol_trunc($value,$maxlen):$value);
5757  else $selectOptionValue = $maxlen?dol_trunc($value,$maxlen):$value;
5758  if ($value == '' || $value == '-') $selectOptionValue='&nbsp;';
5759  }
5760 
5761  $out.='<option value="'.$key.'"';
5762  $out.=$style.$disabled;
5763  if ($id != '' && $id == $key && ! $disabled) $out.=' selected'; // To preselect a value
5764  if ($nohtmlescape) $out.=' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
5765  $out.='>';
5766  //var_dump($selectOptionValue);
5767  $out.=$selectOptionValue;
5768  $out.="</option>\n";
5769  }
5770  }
5771 
5772  $out.="</select>";
5773  return $out;
5774  }
5775 
5776 
5795  static function selectArrayAjax($htmlname, $url, $id='', $moreparam='', $moreparamtourl='', $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0)
5796  {
5797  global $conf, $langs;
5798  global $delayedhtmlcontent;
5799 
5800  // TODO Use an internal dolibarr component instead of select2
5801  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && ! defined('REQUIRE_JQUERY_MULTISELECT')) return '';
5802 
5803  $out='<select type="text" class="'.$htmlname.($morecss?' '.$morecss:'').'" '.($moreparam?$moreparam.' ':'').'name="'.$htmlname.'"></select>';
5804 
5805  $tmpplugin='select2';
5806  $outdelayed="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
5807  <script type="text/javascript">
5808  $(document).ready(function () {
5809 
5810  '.($callurlonselect ? 'var saveRemoteData = [];':'').'
5811 
5812  $(".'.$htmlname.'").select2({
5813  ajax: {
5814  dir: "ltr",
5815  url: "'.$url.'",
5816  dataType: \'json\',
5817  delay: 250,
5818  data: function (params) {
5819  return {
5820  q: params.term, // search term
5821  page: params.page
5822  };
5823  },
5824  processResults: function (data) {
5825  // parse the results into the format expected by Select2.
5826  // since we are using custom formatting functions we do not need to alter the remote JSON data
5827  //console.log(data);
5828  saveRemoteData = data;
5829  /* format json result for select2 */
5830  result = []
5831  $.each( data, function( key, value ) {
5832  result.push({id: key, text: value.text});
5833  });
5834  //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
5835  //console.log(result);
5836  return {results: result, more: false}
5837  },
5838  cache: true
5839  },
5840  language: select2arrayoflanguage,
5841  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
5842  placeholder: "'.dol_escape_js($placeholder).'",
5843  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
5844  minimumInputLength: '.$minimumInputLength.',
5845  formatResult: function(result, container, query, escapeMarkup) {
5846  return escapeMarkup(result.text);
5847  },
5848  });
5849 
5850  '.($callurlonselect ? '
5851  /* Code to execute a GET when we select a value */
5852  $(".'.$htmlname.'").change(function() {
5853  var selected = $(".'.$htmlname.'").val();
5854  console.log("We select in selectArrayAjax the entry "+selected)
5855  $(".'.$htmlname.'").val(""); /* reset visible combo value */
5856  $.each( saveRemoteData, function( key, value ) {
5857  if (key == selected)
5858  {
5859  console.log("selectArrayAjax - Do a redirect to "+value.url)
5860  location.assign(value.url);
5861  }
5862  });
5863  });' : '' ) . '
5864 
5865  });
5866  </script>';
5867 
5868  if ($acceptdelayedhtml)
5869  {
5870  $delayedhtmlcontent.=$outdelayed;
5871  }
5872  else
5873  {
5874  $out.=$outdelayed;
5875  }
5876  return $out;
5877  }
5878 
5897  static function selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0)
5898  {
5899  global $conf, $langs;
5900  global $delayedhtmlcontent;
5901 
5902  // TODO Use an internal dolibarr component instead of select2
5903  if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && ! defined('REQUIRE_JQUERY_MULTISELECT')) return '';
5904 
5905  $out='<select type="text" class="'.$htmlname.($morecss?' '.$morecss:'').'" '.($moreparam?$moreparam.' ':'').'name="'.$htmlname.'"><option></option></select>';
5906 
5907  $formattedarrayresult = array();
5908 
5909  foreach($array as $key => $value) {
5910  $o = new stdClass();
5911  $o->id = $key;
5912  $o->text = $value['text'];
5913  $o->url = $value['url'];
5914  $formattedarrayresult[] = $o;
5915  }
5916 
5917  $tmpplugin='select2';
5918  $outdelayed="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
5919  <script type="text/javascript">
5920  $(document).ready(function () {
5921  var data = '.json_encode($formattedarrayresult).';
5922 
5923  '.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';':'').'
5924 
5925  $(".'.$htmlname.'").select2({
5926  data: data,
5927  language: select2arrayoflanguage,
5928  containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
5929  placeholder: "'.dol_escape_js($placeholder).'",
5930  escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
5931  minimumInputLength: '.$minimumInputLength.',
5932  formatResult: function(result, container, query, escapeMarkup) {
5933  return escapeMarkup(result.text);
5934  },
5935  matcher: function (params, data) {
5936 
5937  if(! data.id) return null;';
5938 
5939  if($callurlonselect) {
5940  $outdelayed.='
5941 
5942  var urlBase = data.url;
5943  var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
5944  /* console.log("params.term="+params.term); */
5945  /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
5946  saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term);';
5947  }
5948 
5949  if(! $disableFiltering) {
5950  $outdelayed.='
5951 
5952  if(data.text.match(new RegExp(params.term))) {
5953  return data;
5954  }
5955 
5956  return null;';
5957  } else {
5958  $outdelayed.='
5959 
5960  return data;';
5961  }
5962 
5963  $outdelayed.='
5964  }
5965  });
5966 
5967  '.($callurlonselect ? '
5968  /* Code to execute a GET when we select a value */
5969  $(".'.$htmlname.'").change(function() {
5970  var selected = $(".'.$htmlname.'").val();
5971  console.log("We select "+selected)
5972 
5973  $(".'.$htmlname.'").val(""); /* reset visible combo value */
5974  $.each( saveRemoteData, function( key, value ) {
5975  if (key == selected)
5976  {
5977  console.log("selectArrayAjax - Do a redirect to "+value.url)
5978  location.assign(value.url);
5979  }
5980  });
5981  });' : '' ) . '
5982 
5983  });
5984  </script>';
5985 
5986  if ($acceptdelayedhtml)
5987  {
5988  $delayedhtmlcontent.=$outdelayed;
5989  }
5990  else
5991  {
5992  $out.=$outdelayed;
5993  }
5994  return $out;
5995  }
5996 
6015  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)
6016  {
6017  global $conf, $langs;
6018 
6019  $out = '';
6020 
6021  if ($addjscombo < 0) {
6022  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $addjscombo = 1;
6023  else $addjscombo = 0;
6024  }
6025 
6026  // Add code for jquery to use multiselect
6027  if (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))
6028  {
6029  $out.="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6030  <script type="text/javascript">'."\n";
6031  if ($addjscombo == 1)
6032  {
6033  $tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
6034  $out.= 'function formatResult(record) {'."\n";
6035  if ($elemtype == 'category')
6036  {
6037  $out.=' //return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> <a href="'.DOL_URL_ROOT.'/categories/viewcat.php?type=0&id=\'+record.id+\'">\'+record.text+\'</a></span>\';
6038  return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> \'+record.text+\'</span>\';';
6039  }
6040  else
6041  {
6042  $out.='return record.text;';
6043  }
6044  $out.= '};'."\n";
6045  $out.= 'function formatSelection(record) {'."\n";
6046  if ($elemtype == 'category')
6047  {
6048  $out.=' //return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> <a href="'.DOL_URL_ROOT.'/categories/viewcat.php?type=0&id=\'+record.id+\'">\'+record.text+\'</a></span>\';
6049  return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> \'+record.text+\'</span>\';';
6050  }
6051  else
6052  {
6053  $out.='return record.text;';
6054  }
6055  $out.= '};'."\n";
6056  $out.= '$(document).ready(function () {
6057  $(\'#'.$htmlname.'\').'.$tmpplugin.'({
6058  dir: \'ltr\',
6059  // Specify format function for dropdown item
6060  formatResult: formatResult,
6061  templateResult: formatResult, /* For 4.0 */
6062  // Specify format function for selected item
6063  formatSelection: formatSelection,
6064  templateResult: formatSelection /* For 4.0 */
6065  });
6066  });'."\n";
6067  }
6068  elseif ($addjscombo == 2)
6069  {
6070  // Add other js lib
6071  // ...
6072  $out.= '$(document).ready(function () {
6073  $(\'#'.$htmlname.'\').multiSelect({
6074  containerHTML: \'<div class="multi-select-container">\',
6075  menuHTML: \'<div class="multi-select-menu">\',
6076  buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
6077  menuItemHTML: \'<label class="multi-select-menuitem">\',
6078  activeClass: \'multi-select-container--open\',
6079  noneText: \''.$placeholder.'\'
6080  });
6081  })';
6082  }
6083  $out.= '</script>';
6084  }
6085 
6086  // Try also magic suggest
6087 
6088  $out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss?' '.$morecss:'').'" multiple name="'.$htmlname.'[]"'.($moreattrib?' '.$moreattrib:'').($width?' style="width: '.(preg_match('/%/',$width)?$width:$width.'px').'"':'').'>'."\n";
6089  if (is_array($array) && ! empty($array))
6090  {
6091  if ($value_as_key) $array=array_combine($array, $array);
6092 
6093  if (! empty($array))
6094  {
6095  foreach ($array as $key => $value)
6096  {
6097  $out.= '<option value="'.$key.'"';
6098  if (is_array($selected) && ! empty($selected) && in_array($key, $selected) && !empty($key))
6099  {
6100  $out.= ' selected';
6101  }
6102  $out.= '>';
6103 
6104  $newval = ($translate ? $langs->trans($value) : $value);
6105  $newval = ($key_in_label ? $key.' - '.$newval : $newval);
6106  $out.= dol_htmlentitiesbr($newval);
6107  $out.= '</option>'."\n";
6108  }
6109  }
6110  }
6111  $out.= '</select>'."\n";
6112 
6113  return $out;
6114  }
6115 
6116 
6126  static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
6127  {
6128  global $conf,$langs,$user;
6129 
6130  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) return '';
6131 
6132  $tmpvar="MAIN_SELECTEDFIELDS_".$varpage;
6133  if (! empty($user->conf->$tmpvar))
6134  {
6135  $tmparray=explode(',', $user->conf->$tmpvar);
6136  foreach($array as $key => $val)
6137  {
6138  //var_dump($key);
6139  //var_dump($tmparray);
6140  if (in_array($key, $tmparray)) $array[$key]['checked']=1;
6141  else $array[$key]['checked']=0;
6142  }
6143  }
6144  //var_dump($array);
6145 
6146  $lis='';
6147  $listcheckedstring='';
6148 
6149  foreach($array as $key => $val)
6150  {
6151  /* var_dump($val);
6152  var_dump(array_key_exists('enabled', $val));
6153  var_dump(!$val['enabled']);*/
6154  if (array_key_exists('enabled', $val) && isset($val['enabled']) && ! $val['enabled'])
6155  {
6156  unset($array[$key]); // We don't want this field
6157  continue;
6158  }
6159  if ($val['label'])
6160  {
6161  $lis.='<li><input type="checkbox" id="checkbox'.$key.'" value="'.$key.'"'.(empty($val['checked'])?'':' checked="checked"').'/><label for="checkbox'.$key.'">'.dol_escape_htmltag($langs->trans($val['label'])).'</label></li>';
6162  $listcheckedstring.=(empty($val['checked'])?'':$key.',');
6163  }
6164  }
6165 
6166  $out ='<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
6167 
6168  <dl class="dropdown">
6169  <dt>
6170  <a href="#">
6171  '.img_picto('','list').'
6172  </a>
6173  <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
6174  </dt>
6175  <dd class="dropdowndd">
6176  <div class="multiselectcheckbox'.$htmlname.'">
6177  <ul class="ul'.$htmlname.'">
6178  '.$lis.'
6179  </ul>
6180  </div>
6181  </dd>
6182  </dl>
6183 
6184  <script type="text/javascript">
6185  jQuery(document).ready(function () {
6186  $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
6187  console.log("A new field was added/removed")
6188  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\')
6189  var title = $(this).val() + ",";
6190  if ($(this).is(\':checked\')) {
6191  $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
6192  }
6193  else {
6194  $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
6195  }
6196  // Now, we submit page
6197  $(this).parents(\'form:first\').submit();
6198  });
6199  });
6200  </script>
6201 
6202  ';
6203  return $out;
6204  }
6205 
6214  function showCategories($id, $type, $rendermode=0)
6215  {
6216  global $db;
6217 
6218  include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
6219 
6220  $cat = new Categorie($db);
6221  $categories = $cat->containing($id, $type);
6222 
6223  if ($rendermode == 1)
6224  {
6225  $toprint = array();
6226  foreach($categories as $c)
6227  {
6228  $ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
6229  foreach($ways as $way)
6230  {
6231  $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color?' style="background: #'.$c->color.';"':' style="background: #aaa"').'>'.img_object('','category').' '.$way.'</li>';
6232  }
6233  }
6234  return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6235  }
6236 
6237  if ($rendermode == 0)
6238  {
6239  $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
6240  foreach($categories as $c) {
6241  $arrayselected[] = $c->id;
6242  }
6243 
6244  return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
6245  }
6246 
6247  return 'ErrorBadValueForParameterRenderMode'; // Should not happened
6248  }
6249 
6250 
6259  function showLinkedObjectBlock($object, $morehtmlright='',$compatibleImportElementsList=false)
6260  {
6261  global $conf,$langs,$hookmanager;
6262  global $bc;
6263 
6264  $object->fetchObjectLinked();
6265 
6266  // Bypass the default method
6267  $hookmanager->initHooks(array('commonobject'));
6268  $parameters=array(
6269  'morehtmlright' => $morehtmlright,
6270  'compatibleImportElementsList' => &$compatibleImportElementsList,
6271  );
6272  $reshook=$hookmanager->executeHooks('showLinkedObjectBlock',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
6273 
6274  if (empty($reshook))
6275  {
6276  $nbofdifferenttypes = count($object->linkedObjects);
6277 
6278  print '<!-- showLinkedObjectBlock -->';
6279  print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
6280 
6281 
6282  print '<div class="div-table-responsive-no-min">';
6283  print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'" data-elementid="'.$object->id.'" >';
6284 
6285  print '<tr class="liste_titre">';
6286  print '<td>'.$langs->trans("Type").'</td>';
6287  print '<td>'.$langs->trans("Ref").'</td>';
6288  print '<td align="center"></td>';
6289  print '<td align="center">'.$langs->trans("Date").'</td>';
6290  print '<td align="right">'.$langs->trans("AmountHTShort").'</td>';
6291  print '<td align="right">'.$langs->trans("Status").'</td>';
6292  print '<td></td>';
6293  print '</tr>';
6294 
6295  $nboftypesoutput=0;
6296 
6297  foreach($object->linkedObjects as $objecttype => $objects)
6298  {
6299  $tplpath = $element = $subelement = $objecttype;
6300 
6301  // to display inport button on tpl
6302  $showImportButton=false;
6303  if(!empty($compatibleImportElementsList) && in_array($element,$compatibleImportElementsList)){
6304  $showImportButton=true;
6305  }
6306 
6307  if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
6308  {
6309  $element = $regs[1];
6310  $subelement = $regs[2];
6311  $tplpath = $element.'/'.$subelement;
6312  }
6313  $tplname='linkedobjectblock';
6314 
6315  // To work with non standard path
6316  if ($objecttype == 'facture') {
6317  $tplpath = 'compta/'.$element;
6318  if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
6319  }
6320  else if ($objecttype == 'facturerec') {
6321  $tplpath = 'compta/facture';
6322  $tplname = 'linkedobjectblockForRec';
6323  if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
6324  }
6325  else if ($objecttype == 'propal') {
6326  $tplpath = 'comm/'.$element;
6327  if (empty($conf->propal->enabled)) continue; // Do not show if module disabled
6328  }
6329  else if ($objecttype == 'supplier_proposal') {
6330  if (empty($conf->supplier_proposal->enabled)) continue; // Do not show if module disabled
6331  }
6332  else if ($objecttype == 'shipping' || $objecttype == 'shipment') {
6333  $tplpath = 'expedition';
6334  if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
6335  }
6336  else if ($objecttype == 'delivery') {
6337  $tplpath = 'livraison';
6338  if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
6339  }
6340  else if ($objecttype == 'invoice_supplier') {
6341  $tplpath = 'fourn/facture';
6342  }
6343  else if ($objecttype == 'order_supplier') {
6344  $tplpath = 'fourn/commande';
6345  }
6346  else if ($objecttype == 'expensereport') {
6347  $tplpath = 'expensereport';
6348  }
6349  else if ($objecttype == 'subscription') {
6350  $tplpath = 'adherents';
6351  }
6352 
6353  global $linkedObjectBlock;
6354  $linkedObjectBlock = $objects;
6355 
6356 
6357  // Output template part (modules that overwrite templates must declare this into descriptor)
6358  $dirtpls=array_merge($conf->modules_parts['tpl'],array('/'.$tplpath.'/tpl'));
6359  foreach($dirtpls as $reldir)
6360  {
6361  if ($nboftypesoutput == ($nbofdifferenttypes - 1)) // No more type to show after
6362  {
6363  global $noMoreLinkedObjectBlockAfter;
6364  $noMoreLinkedObjectBlockAfter=1;
6365  }
6366 
6367  $res=@include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
6368  if ($res)
6369  {
6370  $nboftypesoutput++;
6371  break;
6372  }
6373  }
6374  }
6375 
6376  if (! $nboftypesoutput)
6377  {
6378  print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>';
6379  }
6380 
6381  print '</table>';
6382 
6383  if(!empty($compatibleImportElementsList))
6384  {
6385  $res=@include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
6386  }
6387 
6388 
6389  print '</div>';
6390 
6391  return $nbofdifferenttypes;
6392  }
6393  }
6394 
6403  function showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array())
6404  {
6405  global $conf, $langs, $hookmanager;
6406  global $bc;
6407 
6408  $linktoelem='';
6409  $linktoelemlist='';
6410  $listofidcompanytoscan='';
6411 
6412  if (! is_object($object->thirdparty)) $object->fetch_thirdparty();
6413 
6414  $possiblelinks=array();
6415  if (is_object($object->thirdparty) && ! empty($object->thirdparty->id) && $object->thirdparty->id > 0)
6416  {
6417  $listofidcompanytoscan=$object->thirdparty->id;
6418  if (($object->thirdparty->parent > 0) && ! empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) $listofidcompanytoscan.=','.$object->thirdparty->parent;
6419  if (($object->fk_project > 0) && ! empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO))
6420  {
6421  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
6422  $tmpproject=new Project($this->db);
6423  $tmpproject->fetch($object->fk_project);
6424  if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) $listofidcompanytoscan.=','.$tmpproject->socid;
6425  unset($tmpproject);
6426  }
6427 
6428  $possiblelinks=array(
6429  'propal'=>array('enabled'=>$conf->propal->enabled, 'perms'=>1, 'label'=>'LinkToProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('propal').')'),
6430  'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande').')'),
6431  'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.facnumber as ref, t.ref_client, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('facture').')'),
6432  'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('facture').')'),
6433  'contrat'=>array('enabled'=>$conf->contrat->enabled , 'perms'=>1, 'label'=>'LinkToContract', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, '' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'),
6434  'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('intervention').')'),
6435  'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled , 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('supplier_proposal').')'),
6436  'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled , 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande_fournisseur').')'),
6437  'invoice_supplier'=>array('enabled'=>$conf->supplier_invoice->enabled , 'perms'=>1, 'label'=>'LinkToSupplierInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('facture_fourn').')')
6438  );
6439  }
6440 
6441  global $action;
6442 
6443  // Can complete the possiblelink array
6444  $hookmanager->initHooks(array('commonobject'));
6445  $parameters=array('listofidcompanytoscan' => $listofidcompanytoscan);
6446  $reshook=$hookmanager->executeHooks('showLinkToObjectBlock',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
6447 
6448  if (empty($reshook))
6449  {
6450  if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6451  {
6452  $possiblelinks=array_merge($possiblelinks, $hookmanager->resArray);
6453  }
6454  }
6455  else if ($reshook > 0)
6456  {
6457  if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6458  {
6459  $possiblelinks=$hookmanager->resArray;
6460  }
6461  }
6462 
6463  foreach($possiblelinks as $key => $possiblelink)
6464  {
6465  $num = 0;
6466 
6467  if (empty($possiblelink['enabled'])) continue;
6468 
6469  if (! empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || ! in_array($key, $excludelinksto)))
6470  {
6471  print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax)?'':' style="display:none"').'>';
6472  $sql = $possiblelink['sql'];
6473 
6474  $resqllist = $this->db->query($sql);
6475  if ($resqllist)
6476  {
6477  $num = $this->db->num_rows($resqllist);
6478  $i = 0;
6479 
6480  print '<br>';
6481  print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
6482  print '<input type="hidden" name="action" value="addlink">';
6483  print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
6484  print '<input type="hidden" name="id" value="'.$object->id.'">';
6485  print '<input type="hidden" name="addlink" value="'.$key.'">';
6486  print '<table class="noborder">';
6487  print '<tr class="liste_titre">';
6488  print '<td class="nowrap"></td>';
6489  print '<td align="center">' . $langs->trans("Ref") . '</td>';
6490  print '<td align="left">' . $langs->trans("RefCustomer") . '</td>';
6491  print '<td align="right">' . $langs->trans("AmountHTShort") . '</td>';
6492  print '<td align="left">' . $langs->trans("Company") . '</td>';
6493  print '</tr>';
6494  while ($i < $num)
6495  {
6496  $objp = $this->db->fetch_object($resqllist);
6497 
6498  print '<tr class="oddeven">';
6499  print '<td aling="left">';
6500  print '<input type="radio" name="idtolinkto" value=' . $objp->rowid . '>';
6501  print '</td>';
6502  print '<td align="center">' . $objp->ref . '</td>';
6503  print '<td>' . $objp->ref_client . '</td>';
6504  print '<td align="right">' . price($objp->total_ht) . '</td>';
6505  print '<td>' . $objp->name . '</td>';
6506  print '</tr>';
6507  $i++;
6508  }
6509  print '</table>';
6510  print '<div class="center"><input type="submit" class="button valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" class="button" name="cancel" value="' . $langs->trans('Cancel') . '"></div>';
6511 
6512  print '</form>';
6513  $this->db->free($resqllist);
6514  } else {
6515  dol_print_error($this->db);
6516  }
6517  print '</div>';
6518  if ($num > 0)
6519  {
6520  }
6521 
6522  //$linktoelem.=($linktoelem?' &nbsp; ':'');
6523  if ($num > 0) $linktoelemlist.='<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">' . $langs->trans($possiblelink['label']) .' ('.$num.')</a></li>';
6524  //else $linktoelem.=$langs->trans($possiblelink['label']);
6525  else $linktoelemlist.='<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
6526  }
6527  }
6528 
6529  if ($linktoelemlist)
6530  {
6531  $linktoelem='
6532  <dl class="dropdown" id="linktoobjectname">
6533  ';
6534  if (! empty($conf->use_javascript_ajax)) $linktoelem.='<dt><a href="#linktoobjectname">'.$langs->trans("LinkTo").'...</a></dt>';
6535  $linktoelem.='<dd>
6536  <div class="multiselectlinkto">
6537  <ul class="ulselectedfields">'.$linktoelemlist.'
6538  </ul>
6539  </div>
6540  </dd>
6541  </dl>';
6542  }
6543  else
6544  {
6545  $linktoelem='';
6546  }
6547 
6548  if (! empty($conf->use_javascript_ajax))
6549  {
6550  print '<!-- Add js to show linkto box -->
6551  <script type="text/javascript" language="javascript">
6552  jQuery(document).ready(function() {
6553  jQuery(".linkto").click(function() {
6554  console.log("We choose to show/hide link for rel="+jQuery(this).attr(\'rel\'));
6555  jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
6556  jQuery(this).toggle();
6557  });
6558  });
6559  </script>
6560  ';
6561  }
6562 
6563  return $linktoelem;
6564  }
6565 
6576  function selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0)
6577  {
6578  global $langs;
6579 
6580  $yes="yes"; $no="no";
6581  if ($option)
6582  {
6583  $yes="1";
6584  $no="0";
6585  }
6586 
6587  $disabled = ($disabled ? ' disabled' : '');
6588 
6589  $resultyesno = '<select class="flat width75" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
6590  if ($useempty) $resultyesno .= '<option value="-1"'.(($value < 0)?' selected':'').'>&nbsp;</option>'."\n";
6591  if (("$value" == 'yes') || ($value == 1))
6592  {
6593  $resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
6594  $resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
6595  }
6596  else
6597  {
6598  $selected=(($useempty && $value != '0' && $value != 'no')?'':' selected');
6599  $resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
6600  $resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
6601  }
6602  $resultyesno .= '</select>'."\n";
6603  return $resultyesno;
6604  }
6605 
6606 
6607 
6608  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6618  function select_export_model($selected='',$htmlname='exportmodelid',$type='',$useempty=0)
6619  {
6620  // phpcs:enable
6621  $sql = "SELECT rowid, label";
6622  $sql.= " FROM ".MAIN_DB_PREFIX."export_model";
6623  $sql.= " WHERE type = '".$type."'";
6624  $sql.= " ORDER BY rowid";
6625  $result = $this->db->query($sql);
6626  if ($result)
6627  {
6628  print '<select class="flat" name="'.$htmlname.'">';
6629  if ($useempty)
6630  {
6631  print '<option value="-1">&nbsp;</option>';
6632  }
6633 
6634  $num = $this->db->num_rows($result);
6635  $i = 0;
6636  while ($i < $num)
6637  {
6638  $obj = $this->db->fetch_object($result);
6639  if ($selected == $obj->rowid)
6640  {
6641  print '<option value="'.$obj->rowid.'" selected>';
6642  }
6643  else
6644  {
6645  print '<option value="'.$obj->rowid.'">';
6646  }
6647  print $obj->label;
6648  print '</option>';
6649  $i++;
6650  }
6651  print "</select>";
6652  }
6653  else {
6654  dol_print_error($this->db);
6655  }
6656  }
6657 
6676  function showrefnav($object,$paramid,$morehtml='',$shownav=1,$fieldid='rowid',$fieldref='ref',$morehtmlref='',$moreparam='',$nodbprefix=0,$morehtmlleft='',$morehtmlstatus='',$morehtmlright='')
6677  {
6678  global $langs,$conf,$hookmanager;
6679 
6680  $ret='';
6681  if (empty($fieldid)) $fieldid='rowid';
6682  if (empty($fieldref)) $fieldref='ref';
6683 
6684  // Add where from hooks
6685  if (is_object($hookmanager))
6686  {
6687  $parameters=array();
6688  $reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters, $object); // Note that $action and $object may have been modified by hook
6689  $object->next_prev_filter.=$hookmanager->resPrint;
6690  }
6691  $previous_ref = $next_ref = '';
6692  if ($shownav)
6693  {
6694  //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
6695  $object->load_previous_next_ref((isset($object->next_prev_filter)?$object->next_prev_filter:''), $fieldid, $nodbprefix);
6696 
6697  $navurl = $_SERVER["PHP_SELF"];
6698  // Special case for project/task page
6699  if ($paramid == 'project_ref')
6700  {
6701  $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/','/tasks.php',$navurl);
6702  $paramid='ref';
6703  }
6704 
6705  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
6706  // accesskey is for Mac: CTRL + key for all browsers
6707  $previous_ref = $object->ref_previous?'<a accesskey="p" title="'.$langs->trans("KeyboardShortcut").' ALT+p|ALT+SHIFT+p|CTRL+p" 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>';
6708  $next_ref = $object->ref_next?'<a accesskey="n" title="'.$langs->trans("KeyboardShortcut").' ALT+n|ALT+SHIFT+n|CTRL+n" 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>';
6709  }
6710 
6711  //print "xx".$previous_ref."x".$next_ref;
6712  $ret.='<!-- Start banner content --><div style="vertical-align: middle">';
6713 
6714  // Right part of banner
6715  if ($morehtmlright) $ret.='<div class="inline-block floatleft">'.$morehtmlright.'</div>';
6716 
6717  if ($previous_ref || $next_ref || $morehtml)
6718  {
6719  $ret.='<div class="pagination paginationref"><ul class="right">';
6720  }
6721  if ($morehtml)
6722  {
6723  $ret.='<li class="noborder litext">'.$morehtml.'</li>';
6724  }
6725  if ($shownav && ($previous_ref || $next_ref))
6726  {
6727  $ret.='<li class="pagination">'.$previous_ref.'</li>';
6728  $ret.='<li class="pagination">'.$next_ref.'</li>';
6729  }
6730  if ($previous_ref || $next_ref || $morehtml)
6731  {
6732  $ret.='</ul></div>';
6733  }
6734 
6735