Test Failed
Push — master ( d56fde...b8c830 )
by Alxarafe
37:54
created

Form::showphoto()   D

Complexity

Conditions 58

Size

Total Lines 141
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 58
eloc 87
nop 10
dl 0
loc 141
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (c) 2002-2007  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (C) 2004-2012  Laurent Destailleur     <[email protected]>
4
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
5
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
6
 * Copyright (C) 2004       Eric Seigne             <[email protected]>
7
 * Copyright (C) 2005-2017  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2006       Andre Cianfarani        <[email protected]>
9
 * Copyright (C) 2006       Marc Barilley/Ocebo     <[email protected]>
10
 * Copyright (C) 2007       Franky Van Liedekerke   <[email protected]>
11
 * Copyright (C) 2007       Patrick Raguin          <[email protected]>
12
 * Copyright (C) 2010       Juanjo Menent           <[email protected]>
13
 * Copyright (C) 2010-2014  Philippe Grand          <[email protected]>
14
 * Copyright (C) 2011       Herve Prot              <[email protected]>
15
 * Copyright (C) 2012-2016  Marcos García           <[email protected]>
16
 * Copyright (C) 2012       Cedric Salvador         <[email protected]>
17
 * Copyright (C) 2012-2015  Raphaël Doursenaud      <[email protected]>
18
 * Copyright (C) 2014       Alexandre Spangaro      <[email protected]>
19
 * Copyright (C) 2018       Ferran Marcet           <[email protected]>
20
 * Copyright (C) 2018       Frédéric France         <[email protected]>
21
 * Copyright (C) 2018       Nicolas ZABOURI	        <[email protected]>
22
 * Copyright (C) 2018       Christophe Battarel     <[email protected]>
23
 * Copyright (C) 2018       Josep Lluis Amador      <[email protected]>
24
 *
25
 * This program is free software; you can redistribute it and/or modify
26
 * it under the terms of the GNU General Public License as published by
27
 * the Free Software Foundation; either version 3 of the License, or
28
 * (at your option) any later version.
29
 *
30
 * This program is distributed in the hope that it will be useful,
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33
 * GNU General Public License for more details.
34
 *
35
 * You should have received a copy of the GNU General Public License
36
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37
 */
38
39
/**
40
 *	\file       htdocs/core/class/html.form.class.php
41
 *  \ingroup    core
42
 *	\brief      File of class with all html predefined components
43
 */
44
45
46
/**
47
 *	Class to manage generation of HTML components
48
 *	Only common components must be here.
49
 *
50
 *  TODO Merge all function load_cache_* and loadCache* (except load_cache_vatrates) into one generic function loadCacheTable
51
 */
52
class Form
53
{
54
	/**
55
     * @var DoliDB Database handler.
56
     */
57
    public $db;
58
59
	/**
60
	 * @var string Error code (or message)
61
	 */
62
	public $error='';
63
64
    /**
65
     * @var string[]    Array of error strings
66
     */
67
    public $errors = array();
68
69
	public $num;
70
71
	// Cache arrays
72
	public $cache_types_paiements=array();
73
	public $cache_conditions_paiements=array();
74
	public $cache_availability=array();
75
	public $cache_demand_reason=array();
76
	public $cache_types_fees=array();
77
	public $cache_vatrates=array();
78
79
80
	/**
81
	 * Constructor
82
	 *
83
	 * @param		DoliDB		$db      Database handler
84
	 */
85
	public function __construct($db)
86
	{
87
		$this->db = $db;
88
	}
89
90
	/**
91
	 * Output key field for an editable field
92
	 *
93
	 * @param   string	$text			Text of label or key to translate
94
	 * @param   string	$htmlname		Name of select field ('edit' prefix will be added)
95
	 * @param   string	$preselected    Value to show/edit (not used in this function)
96
	 * @param	object	$object			Object
97
	 * @param	boolean	$perm			Permission to allow button to edit parameter. Set it to 0 to have a not edited field.
98
	 * @param	string	$typeofdata		Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'datepicker' ('day' do not work, don't know why), 'ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...)
99
	 * @param	string	$moreparam		More param to add on a href URL.
100
	 * @param   int     $fieldrequired  1 if we want to show field as mandatory using the "fieldrequired" CSS.
101
	 * @param   int     $notabletag     1=Do not output table tags but output a ':', 2=Do not output table tags and no ':', 3=Do not output table tags but output a ' '
102
	 * @param	string	$paramid		Key of parameter for id ('id', 'socid')
103
	 * @return	string					HTML edit field
104
	 */
105
	function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id')
106
	{
107
		global $conf,$langs;
108
109
		$ret='';
110
111
		// TODO change for compatibility
112
		if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! preg_match('/^select;/',$typeofdata))
113
		{
114
			if (! empty($perm))
115
			{
116
				$tmp=explode(':',$typeofdata);
117
				$ret.= '<div class="editkey_'.$tmp[0].(! empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
118
				if ($fieldrequired) $ret.='<span class="fieldrequired">';
119
				$ret.= $langs->trans($text);
120
				if ($fieldrequired) $ret.='</span>';
121
				$ret.= '</div>'."\n";
122
			}
123
			else
124
			{
125
				if ($fieldrequired) $ret.='<span class="fieldrequired">';
126
				$ret.= $langs->trans($text);
127
				if ($fieldrequired) $ret.='</span>';
128
			}
129
		}
130
		else
131
		{
132
			if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='<table class="nobordernopadding" width="100%"><tr><td class="nowrap">';
133
			if ($fieldrequired) $ret.='<span class="fieldrequired">';
134
			$ret.=$langs->trans($text);
135
			if ($fieldrequired) $ret.='</span>';
136
			if (! empty($notabletag)) $ret.=' ';
137
			if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='</td>';
138
			if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='<td align="right">';
139
			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>';
140
			if (! empty($notabletag) && $notabletag == 1) $ret.=' : ';
141
			if (! empty($notabletag) && $notabletag == 3) $ret.=' ';
142
			if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='</td>';
143
			if (empty($notabletag) && GETPOST('action','aZ09') != 'edit'.$htmlname && $perm) $ret.='</tr></table>';
144
		}
145
146
		return $ret;
147
	}
148
149
	/**
150
	 * Output value of a field for an editable field
151
	 *
152
	 * @param	string	$text			Text of label (not used in this function)
153
	 * @param	string	$htmlname		Name of select field
154
	 * @param	string	$value			Value to show/edit
155
	 * @param	object	$object			Object
156
	 * @param	boolean	$perm			Permission to allow button to edit parameter
157
	 * @param	string	$typeofdata		Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols%', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datepickerhour', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select:xxx'...)
158
	 * @param	string	$editvalue		When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of value). Use '' to use same than $value
159
	 * @param	object	$extObject		External object
160
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
161
	 * @param	string	$moreparam		More param to add on the form action href URL
162
	 * @param   int     $notabletag     Do no output table tags
163
	 * @param	string	$formatfunc		Call a specific function to output field
164
	 * @param	string	$paramid		Key of parameter for id ('id', 'socid')
165
	 * @return  string					HTML edit field
166
	 */
167
	function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=0, $formatfunc='', $paramid='id')
168
	{
169
		global $conf,$langs,$db;
170
171
		$ret='';
172
173
		// Check parameters
174
		if (empty($typeofdata)) return 'ErrorBadParameter';
175
176
		// When option to edit inline is activated
177
		if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! preg_match('/^select;|datehourpicker/',$typeofdata)) // TODO add jquery timepicker
178
		{
179
			$ret.=$this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
180
		}
181
		else
182
		{
183
			if (GETPOST('action','aZ09') == 'edit'.$htmlname)
184
			{
185
				$ret.="\n";
186
				$ret.='<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam?'?'.$moreparam:'').'">';
187
				$ret.='<input type="hidden" name="action" value="set'.$htmlname.'">';
188
				$ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
189
				$ret.='<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
190
				if (empty($notabletag)) $ret.='<table class="nobordernopadding centpercent" cellpadding="0" cellspacing="0">';
191
				if (empty($notabletag)) $ret.='<tr><td>';
192
				if (preg_match('/^(string|email)/',$typeofdata))
193
				{
194
					$tmp=explode(':',$typeofdata);
195
					$ret.='<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue?$editvalue:$value).'"'.($tmp[1]?' size="'.$tmp[1].'"':'').'>';
196
				}
197
				else if (preg_match('/^(numeric|amount)/',$typeofdata))
198
				{
199
					$tmp=explode(':',$typeofdata);
200
					$valuetoshow=price2num($editvalue?$editvalue:$value);
201
					$ret.='<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow!=''?price($valuetoshow):'').'"'.($tmp[1]?' size="'.$tmp[1].'"':'').'>';
202
				}
203
				else if (preg_match('/^text/',$typeofdata) || preg_match('/^note/',$typeofdata))
204
				{
205
					$tmp=explode(':',$typeofdata);
206
					$cols=$tmp[2];
207
					$morealt='';
208
					if (preg_match('/%/',$cols))
209
					{
210
						$morealt=' style="width: '.$cols.'"';
211
						$cols='';
212
					}
213
214
					$valuetoshow = ($editvalue?$editvalue:$value);
215
216
					$ret.='<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1]?$tmp[1]:'20').'"'.($cols?' cols="'.$cols.'"':'class="quatrevingtpercent"').$morealt.'">';
217
					$ret.=dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
218
					$ret.='</textarea>';
219
				}
220
				else if ($typeofdata == 'day' || $typeofdata == 'datepicker')
221
				{
222
					$ret.=$this->selectDate($value,$htmlname,0,0,1,'form'.$htmlname,1,0);
223
				}
224
				else if ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker')
225
				{
226
					$ret.=$this->selectDate($value,$htmlname,1,1,1,'form'.$htmlname,1,0);
227
				}
228
				else if (preg_match('/^select;/',$typeofdata))
229
				{
230
					 $arraydata=explode(',',preg_replace('/^select;/','',$typeofdata));
231
					 foreach($arraydata as $val)
232
					 {
233
						 $tmp=explode(':',$val);
234
						 $arraylist[$tmp[0]]=$tmp[1];
235
					 }
236
					 $ret.=$this->selectarray($htmlname,$arraylist,$value);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arraylist seems to be defined by a foreach iteration on line 231. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
237
				}
238
				else if (preg_match('/^ckeditor/',$typeofdata))
239
				{
240
					$tmp=explode(':',$typeofdata);		// Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols
241
					require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
242
					$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'));
243
					$ret.=$doleditor->Create(1);
244
				}
245
				if (empty($notabletag)) $ret.='</td>';
246
247
				if (empty($notabletag)) $ret.='<td align="left">';
248
				//else $ret.='<div class="clearboth"></div>';
249
			   	$ret.='<input type="submit" class="button'.(empty($notabletag)?'':' ').'" name="modify" value="'.$langs->trans("Modify").'">';
250
			   	if (preg_match('/ckeditor|textarea/',$typeofdata) && empty($notabletag)) $ret.='<br>'."\n";
251
			   	$ret.='<input type="submit" class="button'.(empty($notabletag)?'':' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
252
			   	if (empty($notabletag)) $ret.='</td>';
253
254
			   	if (empty($notabletag)) $ret.='</tr></table>'."\n";
255
				$ret.='</form>'."\n";
256
			}
257
			else
258
			{
259
				if (preg_match('/^(email)/',$typeofdata))              $ret.=dol_print_email($value,0,0,0,0,1);
260
				elseif (preg_match('/^(amount|numeric)/',$typeofdata)) $ret.=($value != '' ? price($value,'',$langs,0,-1,-1,$conf->currency) : '');
261
				elseif (preg_match('/^text/',$typeofdata) || preg_match('/^note/',$typeofdata))  $ret.=dol_htmlentitiesbr($value);
262
				elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret.=dol_print_date($value,'day');
263
				elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret.=dol_print_date($value,'dayhour');
264
				else if (preg_match('/^select;/',$typeofdata))
265
				{
266
					$arraydata=explode(',',preg_replace('/^select;/','',$typeofdata));
267
					foreach($arraydata as $val)
268
					{
269
						$tmp=explode(':',$val);
270
						$arraylist[$tmp[0]]=$tmp[1];
271
					}
272
					$ret.=$arraylist[$value];
273
				}
274
				else if (preg_match('/^ckeditor/',$typeofdata))
275
				{
276
					$tmpcontent=dol_htmlentitiesbr($value);
277
					if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB))
278
					{
279
						$firstline=preg_replace('/<br>.*/','',$tmpcontent);
280
						$firstline=preg_replace('/[\n\r].*/','',$firstline);
281
						$tmpcontent=$firstline.((strlen($firstline) != strlen($tmpcontent))?'...':'');
282
					}
283
					$ret.=$tmpcontent;
284
				}
285
				else $ret.=$value;
286
287
				if ($formatfunc && method_exists($object, $formatfunc))
288
				{
289
					$ret=$object->$formatfunc($ret);
290
				}
291
			}
292
		}
293
		return $ret;
294
	}
295
296
	/**
297
	 * Output edit in place form
298
	 *
299
	 * @param	object	$object			Object
300
	 * @param	string	$value			Value to show/edit
301
	 * @param	string	$htmlname		DIV ID (field name)
302
	 * @param	int		$condition		Condition to edit
303
	 * @param	string	$inputType		Type of input ('string', 'numeric', 'datepicker' ('day' do not work, don't know why), 'textarea:rows:cols', 'ckeditor:dolibarr_zzz:width:height:?:1:rows:cols', 'select:xxx')
304
	 * @param	string	$editvalue		When in edit mode, use this value as $value instead of value
305
	 * @param	object	$extObject		External object
306
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
307
	 * @return	string   		      	HTML edit in place
308
	 */
309
	private function editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
310
	{
311
		global $conf;
312
313
		$out='';
314
315
		// Check parameters
316
		if (preg_match('/^text/',$inputType)) $value = dol_nl2br($value);
317
		else if (preg_match('/^numeric/',$inputType)) $value = price($value);
318
		else if ($inputType == 'day' || $inputType == 'datepicker') $value = dol_print_date($value, 'day');
319
320
		if ($condition)
321
		{
322
			$element		= false;
323
			$table_element	= false;
324
			$fk_element		= false;
325
			$loadmethod		= false;
326
			$savemethod		= false;
327
			$ext_element	= false;
328
			$button_only	= false;
329
			$inputOption    = '';
330
331
			if (is_object($object))
332
			{
333
				$element = $object->element;
334
				$table_element = $object->table_element;
335
				$fk_element = $object->id;
336
			}
337
338
			if (is_object($extObject))
339
			{
340
				$ext_element = $extObject->element;
341
			}
342
343
			if (preg_match('/^(string|email|numeric)/',$inputType))
344
			{
345
				$tmp=explode(':',$inputType);
346
				$inputType=$tmp[0];
347
				if (! empty($tmp[1])) $inputOption=$tmp[1];
348
				if (! empty($tmp[2])) $savemethod=$tmp[2];
349
				$out.= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
350
			}
351
			else if ((preg_match('/^day$/',$inputType)) || (preg_match('/^datepicker/',$inputType)) || (preg_match('/^datehourpicker/',$inputType)))
352
			{
353
				$tmp=explode(':',$inputType);
354
				$inputType=$tmp[0];
355
				if (! empty($tmp[1])) $inputOption=$tmp[1];
356
				if (! empty($tmp[2])) $savemethod=$tmp[2];
357
358
				$out.= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
359
			}
360
			else if (preg_match('/^(select|autocomplete)/',$inputType))
361
			{
362
				$tmp=explode(':',$inputType);
363
				$inputType=$tmp[0]; $loadmethod=$tmp[1];
364
				if (! empty($tmp[2])) $savemethod=$tmp[2];
365
				if (! empty($tmp[3])) $button_only=true;
366
			}
367
			else if (preg_match('/^textarea/',$inputType))
368
			{
369
				$tmp=explode(':',$inputType);
370
				$inputType=$tmp[0];
371
				$rows=(empty($tmp[1])?'8':$tmp[1]);
372
				$cols=(empty($tmp[2])?'80':$tmp[2]);
373
			}
374
			else if (preg_match('/^ckeditor/',$inputType))
375
			{
376
				$tmp=explode(':',$inputType);
377
				$inputType=$tmp[0]; $toolbar=$tmp[1];
378
				if (! empty($tmp[2])) $width=$tmp[2];
379
				if (! empty($tmp[3])) $heigth=$tmp[3];
380
				if (! empty($tmp[4])) $savemethod=$tmp[4];
381
382
				if (! empty($conf->fckeditor->enabled))
383
				{
384
					$out.= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
385
				}
386
				else
387
				{
388
					$inputType = 'textarea';
389
				}
390
			}
391
392
			$out.= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
393
			$out.= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
394
			$out.= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
395
			$out.= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
396
			if (! empty($savemethod))	$out.= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
397
			if (! empty($ext_element))	$out.= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
398
			if (! empty($custommsg))
399
			{
400
				if (is_array($custommsg))
401
				{
402
					if (!empty($custommsg['success']))
403
						$out.= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
404
					if (!empty($custommsg['error']))
405
						$out.= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
406
				}
407
				else
408
					$out.= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
409
			}
410
			if ($inputType == 'textarea') {
411
				$out.= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n";
412
				$out.= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n";
413
			}
414
			$out.= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
415
			$out.= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(! empty($editvalue) ? $editvalue : $value).'</span>'."\n";
416
		}
417
		else
418
		{
419
			$out = $value;
420
		}
421
422
		return $out;
423
	}
424
425
	/**
426
	 *	Show a text and picto with tooltip on text or picto.
427
	 *  Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip
428
	 *
429
	 *	@param	string		$text				Text to show
430
	 *	@param	string		$htmltext			HTML content of tooltip. Must be HTML/UTF8 encoded.
431
	 *	@param	int			$tooltipon			1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2
432
	 *	@param	int			$direction			-1=image is before, 0=no image, 1=image is after
433
	 *	@param	string		$img				Html code for image (use img_xxx() function to get it)
434
	 *	@param	string		$extracss			Add a CSS style to td tags
435
	 *	@param	int			$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
436
	 *	@param	string		$incbefore			Include code before the text
437
	 *	@param	int			$noencodehtmltext	Do not encode into html entity the htmltext
438
	 *  @param  string      $tooltiptrigger		''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key)
439
	 *  @param	int			$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
440
	 *	@return	string							Code html du tooltip (texte+picto)
441
	 *	@see	Use function textwithpicto if you can.
442
	 *  TODO Move this as static as soon as everybody use textwithpicto or @Form::textwithtooltip
443
	 */
444
	function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 2, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger='', $forcenowrap=0)
445
	{
446
		global $conf;
447
448
		if ($incbefore) $text = $incbefore.$text;
449
		if (! $htmltext) return $text;
450
451
		$tag='td';
452
		if ($notabs == 2) $tag='div';
453
		if ($notabs == 3) $tag='span';
454
		// Sanitize tooltip
455
		$htmltext=str_replace("\\","\\\\",$htmltext);
456
		$htmltext=str_replace("\r","",$htmltext);
457
		$htmltext=str_replace("\n","",$htmltext);
458
459
		$extrastyle='';
460
		if ($direction < 0) { $extracss=($extracss?$extracss.' ':'').'inline-block'; $extrastyle='padding: 0px; padding-left: 3px !important;'; }
461
		if ($direction > 0) { $extracss=($extracss?$extracss.' ':'').'inline-block'; $extrastyle='padding: 0px; padding-right: 3px !important;'; }
462
463
		$classfortooltip='classfortooltip';
464
465
		$s='';$textfordialog='';
466
467
		if ($tooltiptrigger == '')
468
		{
469
			$htmltext=str_replace('"',"&quot;",$htmltext);
470
		}
471
		else
472
		{
473
			$classfortooltip='classfortooltiponclick';
474
			$textfordialog.='<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
475
		}
476
		if ($tooltipon == 2 || $tooltipon == 3)
477
		{
478
			$paramfortooltipimg=' class="'.$classfortooltip.' inline-block'.($extracss?' '.$extracss:'').'" style="padding: 0px;'.($extrastyle?' '.$extrastyle:'').'"';
479
			if ($tooltiptrigger == '') $paramfortooltipimg.=' title="'.($noencodehtmltext?$htmltext:dol_escape_htmltag($htmltext,1)).'"'; // Attribut to put on img tag to store tooltip
480
			else $paramfortooltipimg.=' dolid="'.$tooltiptrigger.'"';
481
		}
482
		else $paramfortooltipimg =($extracss?' class="'.$extracss.'"':'').($extrastyle?' style="'.$extrastyle.'"':''); // Attribut to put on td text tag
483
		if ($tooltipon == 1 || $tooltipon == 3)
484
		{
485
			$paramfortooltiptd=' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss?' '.$extracss:'').'" style="padding: 0px;'.($extrastyle?' '.$extrastyle:'').'" ';
486
			if ($tooltiptrigger == '') $paramfortooltiptd.=' title="'.($noencodehtmltext?$htmltext:dol_escape_htmltag($htmltext,1)).'"'; // Attribut to put on td tag to store tooltip
487
			else $paramfortooltiptd.=' dolid="'.$tooltiptrigger.'"';
488
		}
489
		else $paramfortooltiptd =($extracss?' class="'.$extracss.'"':'').($extrastyle?' style="'.$extrastyle.'"':''); // Attribut to put on td text tag
490
		if (empty($notabs)) $s.='<table class="nobordernopadding" summary=""><tr style="height: auto;">';
491
		elseif ($notabs == 2) $s.='<div class="inline-block'.($forcenowrap?' nowrap':'').'">';
492
		// Define value if value is before
493
		if ($direction < 0) {
494
			$s.='<'.$tag.$paramfortooltipimg;
495
			if ($tag == 'td') {
496
				$s .= ' valign="top" width="14"';
497
			}
498
			$s.= '>'.$textfordialog.$img.'</'.$tag.'>';
499
		}
500
		// Use another method to help avoid having a space in value in order to use this value with jquery
501
		// Define label
502
		if ((string) $text != '') $s.='<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
503
		// Define value if value is after
504
		if ($direction > 0) {
505
			$s.='<'.$tag.$paramfortooltipimg;
506
			if ($tag == 'td') $s .= ' valign="middle" width="14"';
507
			$s.= '>'.$textfordialog.$img.'</'.$tag.'>';
508
		}
509
		if (empty($notabs)) $s.='</tr></table>';
510
		elseif ($notabs == 2) $s.='</div>';
511
512
		return $s;
513
	}
514
515
	/**
516
	 *	Show a text with a picto and a tooltip on picto
517
	 *
518
	 *	@param	string	$text				Text to show
519
	 *	@param  string	$htmltext	     	Content of tooltip
520
	 *	@param	int		$direction			1=Icon is after text, -1=Icon is before text, 0=no icon
521
	 * 	@param	string	$type				Type of picto ('info', 'help', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath
522
	 *  @param  string	$extracss           Add a CSS style to td, div or span tag
523
	 *  @param  int		$noencodehtmltext   Do not encode into html entity the htmltext
524
	 *  @param	int		$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
525
	 *  @param  string  $tooltiptrigger     ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key)
526
	 *  @param	int		$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
527
	 * 	@return	string						HTML code of text, picto, tooltip
528
	 */
529
	function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 2, $tooltiptrigger='', $forcenowrap=0)
530
	{
531
		global $conf, $langs;
532
533
		$alt = '';
534
		if ($tooltiptrigger) $alt=$langs->transnoentitiesnoconv("ClickToShowHelp");
535
536
		//For backwards compatibility
537
		if ($type == '0') $type = 'info';
538
		elseif ($type == '1') $type = 'help';
539
540
		// If info or help with no javascript, show only text
541
		if (empty($conf->use_javascript_ajax))
542
		{
543
			if ($type == 'info' || $type == 'help')	return $text;
544
			else
545
			{
546
				$alt = $htmltext;
547
				$htmltext = '';
548
			}
549
		}
550
551
		// If info or help with smartphone, show only text (tooltip hover can't works)
552
		if (! empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger))
553
		{
554
			if ($type == 'info' || $type == 'help') return $text;
555
		}
556
		// If info or help with smartphone, show only text (tooltip on lick does not works with dialog on smaprtphone)
557
		if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
558
		{
559
			if ($type == 'info' || $type == 'help') return $text;
560
		}
561
562
		if ($type == 'info') $img = img_help(0, $alt);
563
		elseif ($type == 'help') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
564
		elseif ($type == 'superadmin') $img = img_picto($alt, 'redstar');
565
		elseif ($type == 'admin') $img = img_picto($alt, 'star');
566
		elseif ($type == 'warning') $img = img_warning($alt);
567
		else $img = img_picto($alt, $type);
568
569
		return $this->textwithtooltip($text, $htmltext, (($tooltiptrigger && ! $img)?3:2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
570
	}
571
572
	/**
573
	 * Generate select HTML to choose massaction
574
	 *
575
	 * @param	string	$selected		Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default.
576
	 * @param	int		$arrayofaction	array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action.
577
	 * @param   int     $alwaysvisible  1=select button always visible
578
	 * @return	string					Select list
579
	 */
580
	function selectMassAction($selected, $arrayofaction, $alwaysvisible=0)
581
	{
582
		global $conf,$langs,$hookmanager;
583
584
		if (count($arrayofaction) == 0) return;
585
586
		$disabled=0;
587
		$ret='<div class="centpercent center">';
588
		$ret.='<select class="flat'.(empty($conf->use_javascript_ajax)?'':' hideobject').' massaction massactionselect" name="massaction"'.($disabled?' disabled="disabled"':'').'>';
589
590
		// 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.
591
		$parameters=array();
592
		$reshook=$hookmanager->executeHooks('addMoreMassActions',$parameters);    // Note that $action and $object may have been modified by hook
593
		if (empty($reshook))
594
		{
595
			$ret.='<option value="0"'.($disabled?' disabled="disabled"':'').'>-- '.$langs->trans("SelectAction").' --</option>';
596
			foreach($arrayofaction as $code => $label)
0 ignored issues
show
Bug introduced by
The expression $arrayofaction of type integer is not traversable.
Loading history...
597
			{
598
				$ret.='<option value="'.$code.'"'.($disabled?' disabled="disabled"':'').'>'.$label.'</option>';
599
			}
600
		}
601
		$ret.=$hookmanager->resPrint;
602
603
		$ret.='</select>';
604
		// 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
605
		$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.
606
		$ret.='<input type="submit" disabled name="confirmmassaction" class="button'.(empty($conf->use_javascript_ajax)?'':' hideobject').' massaction massactionconfirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
607
		$ret.='</div>';
608
609
		if (! empty($conf->use_javascript_ajax))
610
		{
611
			$ret.='<!-- JS CODE TO ENABLE mass action select -->
612
    		<script type="text/javascript">
613
        		function initCheckForSelect(mode)	/* mode is 0 during init of page or click all, 1 when we click on 1 checkbox */
614
        		{
615
        			atleastoneselected=0;
616
    	    		jQuery(".checkforselect").each(function( index ) {
617
    	  				/* console.log( index + ": " + $( this ).text() ); */
618
    	  				if ($(this).is(\':checked\')) atleastoneselected++;
619
    	  			});
620
					console.log("initCheckForSelect mode="+mode+" atleastoneselected="+atleastoneselected);
621
    	  			if (atleastoneselected || '.$alwaysvisible.')
622
    	  			{
623
    	  				jQuery(".massaction").show();
624
        			    '.($selected ? 'if (atleastoneselected) { jQuery(".massactionselect").val("'.$selected.'"); jQuery(".massactionconfirmed").prop(\'disabled\', false); }' : '').'
625
        			    '.($selected ? 'if (! atleastoneselected) { jQuery(".massactionselect").val("0"); jQuery(".massactionconfirmed").prop(\'disabled\', true); } ' : '').'
626
    	  			}
627
    	  			else
628
    	  			{
629
    	  				jQuery(".massaction").hide();
630
    	            }
631
        		}
632
633
        	jQuery(document).ready(function () {
634
        		initCheckForSelect(0);
635
        		jQuery(".checkforselect").click(function() {
636
        			initCheckForSelect(1);
637
    	  		});
638
    	  		jQuery(".massactionselect").change(function() {
639
        			var massaction = $( this ).val();
640
        			var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
641
        			if (massaction == "builddoc")
642
                    {
643
                        urlform = urlform + "#show_files";
644
    	            }
645
        			$( this ).closest("form").attr("action", urlform);
646
                    console.log("we select a mass action "+massaction+" - "+urlform);
647
        	        /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
648
        			if ($(this).val() != \'0\')
649
    	  			{
650
    	  				jQuery(".massactionconfirmed").prop(\'disabled\', false);
651
    	  			}
652
    	  			else
653
    	  			{
654
    	  				jQuery(".massactionconfirmed").prop(\'disabled\', true);
655
    	  			}
656
    	        });
657
        	});
658
    		</script>
659
        	';
660
		}
661
662
		return $ret;
663
	}
664
665
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
666
	/**
667
	 *  Return combo list of activated countries, into language of user
668
	 *
669
	 *  @param	string	$selected       	Id or Code or Label of preselected country
670
	 *  @param  string	$htmlname       	Name of html select object
671
	 *  @param  string	$htmloption     	Options html on select object
672
	 *  @param	integer	$maxlength			Max length for labels (0=no limit)
673
	 *  @param	string	$morecss			More css class
674
	 *  @param	string	$usecodeaskey		''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
675
	 *  @param	int		$showempty			Show empty choice
676
	 *  @param	int		$disablefavorites	1=Disable favorites,
677
	 *  @param	int		$addspecialentries	1=Add dedicated entries for group of countries (like 'European Economic Community', ...)
678
	 *  @return string           			HTML string with select
679
	 */
680
	function select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0)
681
	{
682
        // phpcs:enable
683
		global $conf,$langs,$mysoc;
684
685
		$langs->load("dict");
686
687
		$out='';
688
		$countryArray=array();
689
		$favorite=array();
690
		$label=array();
691
		$atleastonefavorite=0;
692
693
		$sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
694
		$sql.= " FROM ".MAIN_DB_PREFIX."c_country";
695
		$sql.= " WHERE active > 0";
696
		//$sql.= " ORDER BY code ASC";
697
698
		dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
699
		$resql=$this->db->query($sql);
700
		if ($resql)
701
		{
702
			$out.= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'" '.$htmloption.'>';
703
			$num = $this->db->num_rows($resql);
704
			$i = 0;
705
			if ($num)
706
			{
707
				$foundselected=false;
708
709
				while ($i < $num)
710
				{
711
					$obj = $this->db->fetch_object($resql);
712
					$countryArray[$i]['rowid'] 		= $obj->rowid;
713
					$countryArray[$i]['code_iso'] 	= $obj->code_iso;
714
					$countryArray[$i]['code_iso3'] 	= $obj->code_iso3;
715
					$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:''));
716
					$countryArray[$i]['favorite']   = $obj->favorite;
717
					$favorite[$i]					= $obj->favorite;
718
					$label[$i] = dol_string_unaccent($countryArray[$i]['label']);
719
					$i++;
720
				}
721
722
				if (empty($disablefavorites)) array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
723
				else $countryArray = dol_sort_array($countryArray, 'label');
724
725
				if ($showempty)
726
				{
727
					$out.='<option value="">&nbsp;</option>'."\n";
728
				}
729
730
				if ($addspecialentries)	// Add dedicated entries for groups of countries
731
				{
732
					//if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
733
					$out.= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
734
					$out.= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
735
					if ($mysoc->isInEEC()) $out.= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
736
					$out.= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
737
					$out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
738
				}
739
740
				foreach ($countryArray as $row)
741
				{
742
					//if (empty($showempty) && empty($row['rowid'])) continue;
743
					if (empty($row['rowid'])) continue;
744
745
					if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) $atleastonefavorite++;
746
					if (empty($row['favorite']) && $atleastonefavorite)
747
					{
748
						$atleastonefavorite=0;
749
						$out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
750
					}
751
					if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label']) )
752
					{
753
						$foundselected=true;
754
						$out.= '<option value="'.($usecodeaskey?($usecodeaskey=='code2'?$row['code_iso']:$row['code_iso3']):$row['rowid']).'" selected>';
755
					}
756
					else
757
					{
758
						$out.= '<option value="'.($usecodeaskey?($usecodeaskey=='code2'?$row['code_iso']:$row['code_iso3']):$row['rowid']).'">';
759
					}
760
					if ($row['label']) $out.= dol_trunc($row['label'],$maxlength,'middle');
761
					else $out.= '&nbsp;';
762
					if ($row['code_iso']) $out.= ' ('.$row['code_iso'] . ')';
763
					$out.= '</option>';
764
				}
765
			}
766
			$out.= '</select>';
767
		}
768
		else
769
		{
770
			dol_print_error($this->db);
771
		}
772
773
		// Make select dynamic
774
		include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
775
		$out .= ajax_combobox('select'.$htmlname);
776
777
		return $out;
778
	}
779
780
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
781
	/**
782
	 *  Return select list of incoterms
783
	 *
784
	 *  @param	string	$selected       		Id or Code of preselected incoterm
785
	 *  @param	string	$location_incoterms     Value of input location
786
	 *  @param	string	$page       			Defined the form action
787
	 *  @param  string	$htmlname       		Name of html select object
788
	 *  @param  string	$htmloption     		Options html on select object
789
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
790
	 *  @param	array	$events					Event options to run on change. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled')))
791
	 *  @return string           				HTML string with select and input
792
	 */
793
	function select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array())
794
	{
795
        // phpcs:enable
796
		global $conf,$langs;
797
798
		$langs->load("dict");
799
800
		$out='';
801
		$incotermArray=array();
802
803
		$sql = "SELECT rowid, code";
804
		$sql.= " FROM ".MAIN_DB_PREFIX."c_incoterms";
805
		$sql.= " WHERE active > 0";
806
		$sql.= " ORDER BY code ASC";
807
808
		dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
809
		$resql=$this->db->query($sql);
810
		if ($resql)
811
		{
812
			if ($conf->use_javascript_ajax && ! $forcecombo)
813
			{
814
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
815
				$out .= ajax_combobox($htmlname, $events);
816
			}
817
818
			if (!empty($page))
819
			{
820
				$out .= '<form method="post" action="'.$page.'">';
821
				$out .= '<input type="hidden" name="action" value="set_incoterms">';
822
				$out .= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
823
			}
824
825
			$out.= '<select id="'.$htmlname.'" class="flat selectincoterm minwidth100imp noenlargeonsmartphone" name="'.$htmlname.'" '.$htmloption.'>';
826
			$out.= '<option value="0">&nbsp;</option>';
827
			$num = $this->db->num_rows($resql);
828
			$i = 0;
829
			if ($num)
830
			{
831
				$foundselected=false;
832
833
				while ($i < $num)
834
				{
835
					$obj = $this->db->fetch_object($resql);
836
					$incotermArray[$i]['rowid'] = $obj->rowid;
837
					$incotermArray[$i]['code'] = $obj->code;
838
					$i++;
839
				}
840
841
				foreach ($incotermArray as $row)
842
				{
843
					if ($selected && ($selected == $row['rowid'] || $selected == $row['code']))
844
					{
845
						$out.= '<option value="'.$row['rowid'].'" selected>';
846
					}
847
					else
848
					{
849
						$out.= '<option value="'.$row['rowid'].'">';
850
					}
851
852
					if ($row['code']) $out.= $row['code'];
853
854
					$out.= '</option>';
855
				}
856
			}
857
			$out.= '</select>';
858
859
			$out .= '<input id="location_incoterms" class="maxwidth100onsmartphone" name="location_incoterms" value="'.$location_incoterms.'">';
860
861
			if (!empty($page))
862
			{
863
				$out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'"></form>';
864
			}
865
		}
866
		else
867
		{
868
			dol_print_error($this->db);
869
		}
870
871
		return $out;
872
	}
873
874
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
875
	/**
876
	 *	Return list of types of lines (product or service)
877
	 * 	Example: 0=product, 1=service, 9=other (for external module)
878
	 *
879
	 *	@param  string	$selected       Preselected type
880
	 *	@param  string	$htmlname       Name of field in html form
881
	 * 	@param	int		$showempty		Add an empty field
882
	 * 	@param	int		$hidetext		Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
883
	 * 	@param	integer	$forceall		1=Force to show products and services in combo list, whatever are activated modules, 0=No force, 2=Force to show only Products, 3=Force to show only services, -1=Force none (and set hidden field to 'service')
884
	 *  @return	void
885
	 */
886
	function select_type_of_lines($selected='',$htmlname='type',$showempty=0,$hidetext=0,$forceall=0)
887
	{
888
        // phpcs:enable
889
		global $db,$langs,$user,$conf;
890
891
		// If product & services are enabled or both disabled.
892
		if ($forceall == 1 || (empty($forceall) && ! empty($conf->product->enabled) && ! empty($conf->service->enabled))
893
		|| (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled)) )
894
		{
895
			if (empty($hidetext)) print $langs->trans("Type").': ';
896
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
897
			if ($showempty)
898
			{
899
				print '<option value="-1"';
900
				if ($selected == -1) print ' selected';
901
				print '>&nbsp;</option>';
902
			}
903
904
			print '<option value="0"';
905
			if (0 == $selected) print ' selected';
906
			print '>'.$langs->trans("Product");
907
908
			print '<option value="1"';
909
			if (1 == $selected) print ' selected';
910
			print '>'.$langs->trans("Service");
911
912
			print '</select>';
913
			//if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
914
		}
915
		if ((empty($forceall) && empty($conf->product->enabled) && ! empty($conf->service->enabled)) || $forceall == 3)
916
		{
917
			print $langs->trans("Service");
918
			print '<input type="hidden" name="'.$htmlname.'" value="1">';
919
		}
920
		if ((empty($forceall) && ! empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2)
921
		{
922
			print $langs->trans("Product");
923
			print '<input type="hidden" name="'.$htmlname.'" value="0">';
924
		}
925
		if ($forceall < 0)	// This should happened only for contracts when both predefined product and service are disabled.
926
		{
927
			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
928
		}
929
	}
930
931
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
932
	/**
933
	 *	Load into cache cache_types_fees, array of types of fees
934
	 *
935
	 *	@return     int             Nb of lines loaded, <0 if KO
936
	 */
937
	function load_cache_types_fees()
938
	{
939
        // phpcs:enable
940
		global $langs;
941
942
		$num = count($this->cache_types_fees);
943
		if ($num > 0) return 0;    // Cache already loaded
944
945
		dol_syslog(__METHOD__, LOG_DEBUG);
946
947
		$langs->load("trips");
948
949
		$sql = "SELECT c.code, c.label";
950
		$sql.= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
951
		$sql.= " WHERE active > 0";
952
953
		$resql=$this->db->query($sql);
954
		if ($resql)
955
		{
956
			$num = $this->db->num_rows($resql);
957
			$i = 0;
958
959
			while ($i < $num)
960
			{
961
				$obj = $this->db->fetch_object($resql);
962
963
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
964
				$label=($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
965
				$this->cache_types_fees[$obj->code] = $label;
966
				$i++;
967
			}
968
969
			asort($this->cache_types_fees);
970
971
			return $num;
972
		}
973
		else
974
		{
975
			dol_print_error($this->db);
976
			return -1;
977
		}
978
	}
979
980
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
981
	/**
982
	 *	Return list of types of notes
983
	 *
984
	 *	@param	string		$selected		Preselected type
985
	 *	@param  string		$htmlname		Name of field in form
986
	 * 	@param	int			$showempty		Add an empty field
987
	 * 	@return	void
988
	 */
989
	function select_type_fees($selected='',$htmlname='type',$showempty=0)
990
	{
991
        // phpcs:enable
992
		global $user, $langs;
993
994
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
995
996
		$this->load_cache_types_fees();
997
998
		print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
999
		if ($showempty)
1000
		{
1001
			print '<option value="-1"';
1002
			if ($selected == -1) print ' selected';
1003
			print '>&nbsp;</option>';
1004
		}
1005
1006
		foreach($this->cache_types_fees as $key => $value)
1007
		{
1008
			print '<option value="'.$key.'"';
1009
			if ($key == $selected) print ' selected';
1010
			print '>';
1011
			print $value;
1012
			print '</option>';
1013
		}
1014
1015
		print '</select>';
1016
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1017
	}
1018
1019
1020
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1021
	/**
1022
	 *  Return HTML code to select a company.
1023
	 *
1024
	 *  @param		int			$selected				Preselected products
1025
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page)
1026
	 *  @param		int			$filter					Filter on thirdparty
1027
	 *  @param		int			$limit					Limit on number of returned lines
1028
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
1029
	 * 	@param		int			$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1030
	 *  @return		string								Return select box for thirdparty.
1031
	 *  @deprecated	3.8 Use select_company instead. For exemple $form->select_thirdparty(GETPOST('socid'),'socid','',0) => $form->select_company(GETPOST('socid'),'socid','',1,0,0,array(),0)
1032
	 */
1033
	function select_thirdparty($selected='', $htmlname='socid', $filter='', $limit=20, $ajaxoptions=array(), $forcecombo=0)
1034
	{
1035
        // phpcs:enable
1036
   		return $this->select_thirdparty_list($selected,$htmlname,$filter,1,0,$forcecombo,array(),'',0, $limit);
1037
	}
1038
1039
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1040
	/**
1041
	 *  Output html form to select a third party
1042
	 *
1043
	 *	@param	string	$selected       		Preselected type
1044
	 *	@param  string	$htmlname       		Name of field in form
1045
	 *  @param  string	$filter         		optional filters criteras (example: 's.rowid <> x', 's.client IN (1,3)')
1046
	 *	@param	string	$showempty				Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty')
1047
	 * 	@param	int		$showtype				Show third party type in combolist (customer, prospect or supplier)
1048
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1049
	 *  @param	array	$events					Ajax event options to run on change. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled')))
1050
	 *	@param	int		$limit					Maximum number of elements
1051
	 *  @param	string	$morecss				Add more css styles to the SELECT component
1052
	 *	@param  string	$moreparam      		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1053
	 *	@param	string	$selected_input_value	Value of preselected input text (for use with ajax)
1054
	 *  @param	int		$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1055
	 *  @param	array	$ajaxoptions			Options for ajax_autocompleter
1056
	 * 	@param  bool	$multiple				add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
1057
	 * 	@return	string							HTML string with select box for thirdparty.
1058
	 */
1059
	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)
1060
	{
1061
        // phpcs:enable
1062
		global $conf,$user,$langs;
1063
1064
		$out='';
1065
1066
		if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && ! $forcecombo)
1067
		{
1068
			// No immediate load of all database
1069
			$placeholder='';
1070
			if ($selected && empty($selected_input_value))
1071
			{
1072
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1073
				$societetmp = new Societe($this->db);
1074
				$societetmp->fetch($selected);
1075
				$selected_input_value=$societetmp->name;
1076
				unset($societetmp);
1077
			}
1078
			// mode 1
1079
			$urloption='htmlname='.$htmlname.'&outjson=1&filter='.$filter.($showtype?'&showtype='.$showtype:'');
1080
			$out.=  ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1081
			$out.='<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
1082
			if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1083
			else if ($hidelabel > 1) {
1084
				$placeholder=' placeholder="'.$langs->trans("RefOrLabel").'"';
1085
				if ($hidelabel == 2) {
1086
					$out.=  img_picto($langs->trans("Search"), 'search');
1087
				}
1088
			}
1089
			$out.= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1090
			if ($hidelabel == 3) {
1091
				$out.=  img_picto($langs->trans("Search"), 'search');
1092
			}
1093
		}
1094
		else
1095
		{
1096
			// Immediate load of all database
1097
			$out.=$this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple);
1098
		}
1099
1100
		return $out;
1101
	}
1102
1103
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1104
	/**
1105
	 *  Output html form to select a third party.
1106
	 *  Note, you must use the select_company to get the component to select a third party. This function must only be called by select_company.
1107
	 *
1108
	 *	@param	string	$selected       Preselected type
1109
	 *	@param  string	$htmlname       Name of field in form
1110
	 *  @param  string	$filter         Optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)')
1111
	 *	@param	string	$showempty		Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty')
1112
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
1113
	 * 	@param	int		$forcecombo		Force to use standard HTML select component without beautification
1114
	 *  @param	array	$events			Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled')))
1115
	 *  @param	string	$filterkey		Filter on key value
1116
	 *  @param	int		$outputmode		0=HTML select string, 1=Array
1117
	 *  @param	int		$limit			Limit number of answers
1118
	 *  @param	string	$morecss		Add more css styles to the SELECT component
1119
	 *	@param  string	$moreparam      Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1120
	 *	@param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1121
	 * 	@return	string					HTML string with
1122
	 */
1123
	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)
1124
	{
1125
        // phpcs:enable
1126
		global $conf,$user,$langs;
1127
1128
		$out='';
1129
		$num=0;
1130
		$outarray=array();
1131
1132
		if ($selected === '') $selected = array();
1133
		else if (!is_array($selected)) $selected = array($selected);
1134
1135
		// Clean $filter that may contains sql conditions so sql code
1136
		if (function_exists('testSqlAndScriptInject')) {
1137
			if (testSqlAndScriptInject($filter, 3)>0) {
1138
				$filter ='';
1139
			}
1140
		}
1141
1142
		// On recherche les societes
1143
		$sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1144
1145
		if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1146
			$sql .= " ,s.address, s.zip, s.town";
1147
		 	$sql .= " , dictp.code as country_code";
1148
		}
1149
1150
		$sql.= " FROM (".MAIN_DB_PREFIX ."societe as s";
1151
		if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1152
		$sql.= " )";
1153
		if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1154
			$sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid=s.fk_pays";
1155
		}
1156
		$sql.= " WHERE s.entity IN (".getEntity('societe').")";
1157
		if (! empty($user->socid)) $sql.= " AND s.rowid = ".$user->socid;
1158
		if ($filter) $sql.= " AND (".$filter.")";
1159
		if (!$user->rights->societe->client->voir && !$user->socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
1160
		if (! empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) $sql.= " AND s.status <> 0";
1161
		// Add criteria
1162
		if ($filterkey && $filterkey != '')
1163
		{
1164
			$sql.=" AND (";
1165
			$prefix=empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE)?'%':'';	// Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1166
			// For natural search
1167
			$scrit = explode(' ', $filterkey);
1168
			$i=0;
1169
			if (count($scrit) > 1) $sql.="(";
1170
			foreach ($scrit as $crit) {
1171
				if ($i > 0) $sql.=" AND ";
1172
				$sql.="(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1173
				$i++;
1174
			}
1175
			if (count($scrit) > 1) $sql.=")";
1176
			if (! empty($conf->barcode->enabled))
1177
			{
1178
				$sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1179
			}
1180
			$sql.= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1181
			$sql.=")";
1182
		}
1183
		$sql.=$this->db->order("nom","ASC");
1184
		$sql.=$this->db->plimit($limit, 0);
1185
1186
		// Build output string
1187
		dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1188
		$resql=$this->db->query($sql);
1189
		if ($resql)
1190
		{
1191
		   	if (! $forcecombo)
1192
			{
1193
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1194
				$out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
1195
			}
1196
1197
			// Construct $out and $outarray
1198
			$out.= '<select id="'.$htmlname.'" class="flat'.($morecss?' '.$morecss:'').'"'.($moreparam?' '.$moreparam:'').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1199
1200
			$textifempty='';
1201
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1202
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1203
			if (! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT))
1204
			{
1205
				if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
1206
				else $textifempty.=$langs->trans("All");
1207
			}
1208
			if ($showempty) $out.= '<option value="-1">'.$textifempty.'</option>'."\n";
1209
1210
			$num = $this->db->num_rows($resql);
1211
			$i = 0;
1212
			if ($num)
1213
			{
1214
				while ($i < $num)
1215
				{
1216
					$obj = $this->db->fetch_object($resql);
1217
					$label='';
1218
					if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1219
						if (($obj->client) && (!empty($obj->code_client))) {
1220
							$label = $obj->code_client. ' - ';
1221
						}
1222
						if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1223
							$label .= $obj->code_fournisseur. ' - ';
1224
						}
1225
						$label.=' '.$obj->name;
1226
					}
1227
					else
1228
					{
1229
						$label=$obj->name;
1230
					}
1231
1232
					if(!empty($obj->name_alias)) {
1233
						$label.=' ('.$obj->name_alias.')';
1234
					}
1235
1236
					if ($showtype)
1237
					{
1238
						if ($obj->client || $obj->fournisseur) $label.=' (';
1239
						if ($obj->client == 1 || $obj->client == 3) $label.=$langs->trans("Customer");
1240
						if ($obj->client == 2 || $obj->client == 3) $label.=($obj->client==3?', ':'').$langs->trans("Prospect");
1241
						if ($obj->fournisseur) $label.=($obj->client?', ':'').$langs->trans("Supplier");
1242
						if ($obj->client || $obj->fournisseur) $label.=')';
1243
					}
1244
1245
					if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1246
						$label.='-'.$obj->address.'-'. $obj->zip.' '. $obj->town;
1247
						if (!empty($obj->country_code)) {
1248
							$label.= ' '. $langs->trans('Country'.$obj->country_code);
1249
						}
1250
					}
1251
1252
					if (empty($outputmode))
1253
					{
1254
						if (in_array($obj->rowid,$selected))
1255
						{
1256
							$out.= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1257
						}
1258
						else
1259
						{
1260
							$out.= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1261
						}
1262
					}
1263
					else
1264
					{
1265
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1266
					}
1267
1268
					$i++;
1269
					if (($i % 10) == 0) $out.="\n";
1270
				}
1271
			}
1272
			$out.= '</select>'."\n";
1273
		}
1274
		else
1275
		{
1276
			dol_print_error($this->db);
1277
		}
1278
1279
		$this->result=array('nbofthirdparties'=>$num);
1280
1281
		if ($outputmode) return $outarray;
1282
		return $out;
1283
	}
1284
1285
1286
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1287
	/**
1288
	 *    	Return HTML combo list of absolute discounts
1289
	 *
1290
	 *    	@param	string	$selected       Id remise fixe pre-selectionnee
1291
	 *    	@param  string	$htmlname       Nom champ formulaire
1292
	 *    	@param  string	$filter         Criteres optionnels de filtre
1293
	 * 		@param	int		$socid			Id of thirdparty
1294
	 * 		@param	int		$maxvalue		Max value for lines that can be selected
1295
	 * 		@return	int						Return number of qualifed lines in list
1296
	 */
1297
	function select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
1298
	{
1299
        // phpcs:enable
1300
		global $langs,$conf;
1301
1302
		// On recherche les remises
1303
		$sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1304
		$sql.= " re.description, re.fk_facture_source";
1305
		$sql.= " FROM ".MAIN_DB_PREFIX ."societe_remise_except as re";
1306
		$sql.= " WHERE re.fk_soc = ".(int) $socid;
1307
		$sql.= " AND re.entity = " . $conf->entity;
1308
		if ($filter) $sql.= " AND ".$filter;
1309
		$sql.= " ORDER BY re.description ASC";
1310
1311
		dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1312
		$resql=$this->db->query($sql);
1313
		if ($resql)
1314
		{
1315
			print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1316
			$num = $this->db->num_rows($resql);
1317
1318
			$qualifiedlines=$num;
1319
1320
			$i = 0;
1321
			if ($num)
1322
			{
1323
				print '<option value="0">&nbsp;</option>';
1324
				while ($i < $num)
1325
				{
1326
					$obj = $this->db->fetch_object($resql);
1327
					$desc=dol_trunc($obj->description,40);
1328
					if (preg_match('/\(CREDIT_NOTE\)/', $desc)) $desc=preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1329
					if (preg_match('/\(DEPOSIT\)/', $desc)) $desc=preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1330
					if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) $desc=preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1331
					if (preg_match('/\(EXCESS PAID\)/', $desc)) $desc=preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1332
1333
					$selectstring='';
1334
					if ($selected > 0 && $selected == $obj->rowid) $selectstring=' selected';
1335
1336
					$disabled='';
1337
					if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue)
1338
					{
1339
						$qualifiedlines--;
1340
						$disabled=' disabled';
1341
					}
1342
1343
					if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source))
1344
					{
1345
						$tmpfac = new Facture($this->db);
1346
						if ($tmpfac->fetch($obj->fk_facture_source) > 0) $desc=$desc.' - '.$tmpfac->ref;
1347
					}
1348
1349
					print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1350
					$i++;
1351
				}
1352
			}
1353
			print '</select>';
1354
			return $qualifiedlines;
1355
		}
1356
		else
1357
		{
1358
			dol_print_error($this->db);
1359
			return -1;
1360
		}
1361
	}
1362
1363
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1364
	/**
1365
	 *	Return list of all contacts (for a third party or all)
1366
	 *
1367
	 *	@param	int		$socid      	Id ot third party or 0 for all
1368
	 *	@param  string	$selected   	Id contact pre-selectionne
1369
	 *	@param  string	$htmlname  	    Name of HTML field ('none' for a not editable field)
1370
	 *	@param  int		$showempty      0=no empty value, 1=add an empty value, 2=add line 'Internal' (used by user edit), 3=add an empty value only if more than one record into list
1371
	 *	@param  string	$exclude        List of contacts id to exclude
1372
	 *	@param	string	$limitto		Disable answers that are not id in this array list
1373
	 *	@param	integer	$showfunction   Add function into label
1374
	 *	@param	string	$moreclass		Add more class to class style
1375
	 *	@param	integer	$showsoc	    Add company into label
1376
	 * 	@param	int		$forcecombo		Force to use combo box
1377
	 *  @param	array	$events			Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled')))
1378
	 *  @param	bool	$options_only	Return options only (for ajax treatment)
1379
	 *  @param	string	$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1380
	 *  @param	string	$htmlid			Html id to use instead of htmlname
1381
	 *	@return	int						<0 if KO, Nb of contact in list if OK
1382
	 *  @deprected						You can use selectcontacts directly (warning order of param was changed)
1383
	 */
1384
	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='')
1385
	{
1386
        // phpcs:enable
1387
		print $this->selectcontacts($socid,$selected,$htmlname,$showempty,$exclude,$limitto,$showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1388
		return $this->num;
1389
	}
1390
1391
	/**
1392
	 *	Return HTML code of the SELECT of list of all contacts (for a third party or all).
1393
	 *  This also set the number of contacts found into $this->num
1394
	 *
1395
	 * @since 9.0 Add afterSelectContactOptions hook
1396
	 *
1397
	 *	@param	int			$socid      	Id ot third party or 0 for all or -1 for empty list
1398
	 *	@param  array|int	$selected   	Array of ID of pre-selected contact id
1399
	 *	@param  string		$htmlname  	    Name of HTML field ('none' for a not editable field)
1400
	 *	@param  int			$showempty     	0=no empty value, 1=add an empty value, 2=add line 'Internal' (used by user edit), 3=add an empty value only if more than one record into list
1401
	 *	@param  string		$exclude        List of contacts id to exclude
1402
	 *	@param	string		$limitto		Disable answers that are not id in this array list
1403
	 *	@param	integer		$showfunction   Add function into label
1404
	 *	@param	string		$moreclass		Add more class to class style
1405
	 *	@param	bool		$options_only	Return options only (for ajax treatment)
1406
	 *	@param	integer		$showsoc	    Add company into label
1407
	 * 	@param	int			$forcecombo		Force to use combo box (so no ajax beautify effect)
1408
	 *  @param	array		$events			Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled')))
1409
	 *  @param	string		$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1410
	 *  @param	string		$htmlid			Html id to use instead of htmlname
1411
	 *  @param	bool		$multiple		add [] in the name of element and add 'multiple' attribut
1412
	 *	@return	 int						<0 if KO, Nb of contact in list if OK
1413
	 */
1414
	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)
1415
	{
1416
		global $conf,$langs,$hookmanager,$action;
1417
1418
		$langs->load('companies');
1419
1420
		if (empty($htmlid)) $htmlid = $htmlname;
1421
1422
		if ($selected === '') $selected = array();
1423
		else if (!is_array($selected)) $selected = array($selected);
1424
		$out='';
1425
1426
		if (! is_object($hookmanager))
1427
		{
1428
			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1429
			$hookmanager=new HookManager($this->db);
1430
		}
1431
1432
		// We search third parties
1433
		$sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste";
1434
		if ($showsoc > 0) $sql.= " , s.nom as company";
1435
		$sql.= " FROM ".MAIN_DB_PREFIX ."socpeople as sp";
1436
		if ($showsoc > 0) $sql.= " LEFT OUTER JOIN  ".MAIN_DB_PREFIX ."societe as s ON s.rowid=sp.fk_soc";
1437
		$sql.= " WHERE sp.entity IN (".getEntity('socpeople').")";
1438
		if ($socid > 0 || $socid == -1) $sql.= " AND sp.fk_soc=".$socid;
1439
		if (! empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) $sql.= " AND sp.statut <> 0";
1440
		$sql.= " ORDER BY sp.lastname ASC";
1441
1442
		dol_syslog(get_class($this)."::select_contacts", LOG_DEBUG);
1443
		$resql=$this->db->query($sql);
1444
		if ($resql)
1445
		{
1446
			$num=$this->db->num_rows($resql);
1447
1448
			if ($conf->use_javascript_ajax && ! $forcecombo && ! $options_only)
1449
			{
1450
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1451
				$out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
1452
			}
1453
1454
			if ($htmlname != 'none' || $options_only) $out.= '<select class="flat'.($moreclass?' '.$moreclass:'').'" id="'.$htmlid.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1455
			if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) $out.= '<option value="0"'.(in_array(0,$selected)?' selected':'').'>&nbsp;</option>';
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($showempty == 1 || $sho...num > 1) && ! $multiple, Probably Intended Meaning: $showempty == 1 || ($sho...num > 1 && ! $multiple)
Loading history...
1456
			if ($showempty == 2) $out.= '<option value="0"'.(in_array(0,$selected)?' selected':'').'>'.$langs->trans("Internal").'</option>';
1457
			$num = $this->db->num_rows($resql);
1458
			$i = 0;
1459
			if ($num)
1460
			{
1461
				include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1462
				$contactstatic=new Contact($this->db);
1463
1464
				while ($i < $num)
1465
				{
1466
					$obj = $this->db->fetch_object($resql);
1467
1468
					$contactstatic->id=$obj->rowid;
1469
					$contactstatic->lastname=$obj->lastname;
1470
					$contactstatic->firstname=$obj->firstname;
1471
					if ($obj->statut == 1){
1472
					if ($htmlname != 'none')
1473
					{
1474
						$disabled=0;
1475
						if (is_array($exclude) && count($exclude) && in_array($obj->rowid,$exclude)) $disabled=1;
1476
						if (is_array($limitto) && count($limitto) && ! in_array($obj->rowid,$limitto)) $disabled=1;
1477
						if (!empty($selected) && in_array($obj->rowid, $selected))
1478
						{
1479
							$out.= '<option value="'.$obj->rowid.'"';
1480
							if ($disabled) $out.= ' disabled';
1481
							$out.= ' selected>';
1482
							$out.= $contactstatic->getFullName($langs);
1483
							if ($showfunction && $obj->poste) $out.= ' ('.$obj->poste.')';
1484
							if (($showsoc > 0) && $obj->company) $out.= ' - ('.$obj->company.')';
1485
							$out.= '</option>';
1486
						}
1487
						else
1488
						{
1489
							$out.= '<option value="'.$obj->rowid.'"';
1490
							if ($disabled) $out.= ' disabled';
1491
							$out.= '>';
1492
							$out.= $contactstatic->getFullName($langs);
1493
							if ($showfunction && $obj->poste) $out.= ' ('.$obj->poste.')';
1494
							if (($showsoc > 0) && $obj->company) $out.= ' - ('.$obj->company.')';
1495
							$out.= '</option>';
1496
						}
1497
					}
1498
					else
1499
					{
1500
						if (in_array($obj->rowid, $selected))
1501
						{
1502
							$out.= $contactstatic->getFullName($langs);
1503
							if ($showfunction && $obj->poste) $out.= ' ('.$obj->poste.')';
1504
							if (($showsoc > 0) && $obj->company) $out.= ' - ('.$obj->company.')';
1505
						}
1506
					}
1507
				}
1508
					$i++;
1509
				}
1510
			}
1511
			else
1512
			{
1513
				$out.= '<option value="-1"'.(($showempty==2 || $multiple) ? '' : ' selected').' disabled>';
1514
				$out.= ($socid != -1) ? ($langs->trans($socid?"NoContactDefinedForThirdParty":"NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1515
				$out.= '</option>';
1516
			}
1517
1518
			$parameters = array(
1519
				'socid'=>$socid,
1520
				'htmlname'=>$htmlname,
1521
				'resql'=>$resql,
1522
				'out'=>&$out,
1523
				'showfunction'=>$showfunction,
1524
				'showsoc'=>$showsoc,
1525
			);
1526
1527
			$reshook = $hookmanager->executeHooks( 'afterSelectContactOptions', $parameters, $this, $action );    // Note that $action and $object may have been modified by some hooks
1528
1529
			if ($htmlname != 'none' || $options_only)
1530
			{
1531
				$out.= '</select>';
1532
			}
1533
1534
			$this->num = $num;
1535
			return $out;
1536
		}
1537
		else
1538
		{
1539
			dol_print_error($this->db);
1540
			return -1;
1541
		}
1542
	}
1543
1544
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1545
	/**
1546
	 *	Return select list of users
1547
	 *
1548
	 *  @param	string	$selected       Id user preselected
1549
	 *  @param  string	$htmlname       Field name in form
1550
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
1551
	 *  @param  array	$exclude        Array list of users id to exclude
1552
	 * 	@param	int		$disabled		If select list must be disabled
1553
	 *  @param  array	$include        Array list of users id to include
1554
	 * 	@param	int		$enableonly		Array list of users id to be enabled. All other must be disabled
1555
	 *  @param	string	$force_entity	'0' or Ids of environment to force
1556
	 * 	@return	void
1557
	 *  @deprecated		Use select_dolusers instead
1558
	 *  @see select_dolusers()
1559
	 */
1560
	function select_users($selected='',$htmlname='userid',$show_empty=0,$exclude=null,$disabled=0,$include='',$enableonly='',$force_entity='0')
1561
	{
1562
        // phpcs:enable
1563
		print $this->select_dolusers($selected,$htmlname,$show_empty,$exclude,$disabled,$include,$enableonly,$force_entity);
1564
	}
1565
1566
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1567
	/**
1568
	 *	Return select list of users
1569
	 *
1570
	 *  @param	string	$selected       User id or user object of user preselected. If 0 or < -2, we use id of current user. If -1, keep unselected (if empty is allowed)
1571
	 *  @param  string	$htmlname       Field name in form
1572
	 *  @param  int		$show_empty     0=list with no empty value, 1=add also an empty value into list
1573
	 *  @param  array	$exclude        Array list of users id to exclude
1574
	 * 	@param	int		$disabled		If select list must be disabled
1575
	 *  @param  array|string	$include        Array list of users id to include or 'hierarchy' to have only supervised users or 'hierarchyme' to have supervised + me
1576
	 * 	@param	array	$enableonly		Array list of users id to be enabled. If defined, it means that others will be disabled
1577
	 *  @param	string	$force_entity	'0' or Ids of environment to force
1578
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
1579
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1580
	 *  @param	string	$morefilter		Add more filters into sql request (Example: 'employee = 1')
1581
	 *  @param	integer	$show_every		0=default list, 1=add also a value "Everybody" at beginning of list
1582
	 *  @param	string	$enableonlytext	If option $enableonlytext is set, we use this text to explain into label why record is disabled. Not used if enableonly is empty.
1583
	 *  @param	string	$morecss		More css
1584
	 *  @param  int     $noactive       Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
1585
	 *  @param  int		$outputmode     0=HTML select string, 1=Array
1586
	 *  @param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1587
	 * 	@return	string					HTML select string
1588
	 *  @see select_dolgroups
1589
	 */
1590
	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)
1591
	{
1592
        // phpcs:enable
1593
		global $conf,$user,$langs;
1594
1595
		// If no preselected user defined, we take current user
1596
		if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) $selected=$user->id;
1597
1598
		if ($selected === '') $selected = array();
1599
		else if (!is_array($selected)) $selected = array($selected);
1600
1601
		$excludeUsers=null;
1602
		$includeUsers=null;
1603
1604
		// Permettre l'exclusion d'utilisateurs
1605
		if (is_array($exclude))	$excludeUsers = implode(",",$exclude);
1606
		// Permettre l'inclusion d'utilisateurs
1607
		if (is_array($include))	$includeUsers = implode(",",$include);
1608
		else if ($include == 'hierarchy')
1609
		{
1610
			// Build list includeUsers to have only hierarchy
1611
			$includeUsers = implode(",",$user->getAllChildIds(0));
1612
		}
1613
		else if ($include == 'hierarchyme')
1614
		{
1615
			// Build list includeUsers to have only hierarchy and current user
1616
			$includeUsers = implode(",",$user->getAllChildIds(1));
1617
		}
1618
1619
		$out='';
1620
		$outarray = array();
1621
1622
		// Forge request to select users
1623
		$sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut, u.login, u.admin, u.entity";
1624
		if (! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
1625
		{
1626
			$sql.= ", e.label";
1627
		}
1628
		$sql.= " FROM ".MAIN_DB_PREFIX ."user as u";
1629
		if (! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
1630
		{
1631
			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX ."entity as e ON e.rowid=u.entity";
1632
			if ($force_entity) $sql.= " WHERE u.entity IN (0,".$force_entity.")";
1633
			else $sql.= " WHERE u.entity IS NOT NULL";
1634
		}
1635
		else
1636
		{
1637
			if (! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
1638
			{
1639
				$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
1640
				$sql.= " ON ug.fk_user = u.rowid";
1641
				$sql.= " WHERE ug.entity = ".$conf->entity;
1642
			}
1643
			else
1644
			{
1645
				$sql.= " WHERE u.entity IN (0,".$conf->entity.")";
1646
			}
1647
		}
1648
		if (! empty($user->societe_id)) $sql.= " AND u.fk_soc = ".$user->societe_id;
1649
		if (is_array($exclude) && $excludeUsers) $sql.= " AND u.rowid NOT IN (".$excludeUsers.")";
1650
		if ($includeUsers) $sql.= " AND u.rowid IN (".$includeUsers.")";
1651
		if (! empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) $sql.= " AND u.statut <> 0";
1652
		if (! empty($morefilter)) $sql.=" ".$morefilter;
1653
1654
		if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))	// MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1655
		{
1656
			$sql.= " ORDER BY u.firstname ASC";
1657
		}
1658
		else
1659
		{
1660
			$sql.= " ORDER BY u.lastname ASC";
1661
		}
1662
1663
		dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1664
		$resql=$this->db->query($sql);
1665
		if ($resql)
1666
		{
1667
			$num = $this->db->num_rows($resql);
1668
			$i = 0;
1669
			if ($num)
1670
			{
1671
		   		// Enhance with select2
1672
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1673
				$out .= ajax_combobox($htmlname);
1674
1675
				// do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1676
				$out.= '<select class="flat'.($morecss?' minwidth100 '.$morecss:' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled?' disabled':'').'>';
1677
				if ($show_empty && !$multiple) $out.= '<option value="-1"'.((empty($selected) || in_array(-1,$selected))?' selected':'').'>&nbsp;</option>'."\n";
1678
				if ($show_every) $out.= '<option value="-2"'.((in_array(-2,$selected))?' selected':'').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
1679
1680
				$userstatic=new User($this->db);
1681
1682
				while ($i < $num)
1683
				{
1684
					$obj = $this->db->fetch_object($resql);
1685
1686
					$userstatic->id=$obj->rowid;
1687
					$userstatic->lastname=$obj->lastname;
1688
					$userstatic->firstname=$obj->firstname;
1689
1690
					$disableline='';
1691
					if (is_array($enableonly) && count($enableonly) && ! in_array($obj->rowid,$enableonly)) $disableline=($enableonlytext?$enableonlytext:'1');
1692
1693
					if ((is_object($selected) && $selected->id == $obj->rowid) || (! is_object($selected) && in_array($obj->rowid,$selected) ))
1694
					{
1695
						$out.= '<option value="'.$obj->rowid.'"';
1696
						if ($disableline) $out.= ' disabled';
1697
						$out.= ' selected>';
1698
					}
1699
					else
1700
					{
1701
						$out.= '<option value="'.$obj->rowid.'"';
1702
						if ($disableline) $out.= ' disabled';
1703
						$out.= '>';
1704
					}
1705
1706
					// $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
1707
					$fullNameMode = 0;
1708
					if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))
1709
					{
1710
						$fullNameMode = 1; //Firstname+lastname
1711
					}
1712
					$out.= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1713
1714
					// Complete name with more info
1715
					$moreinfo=0;
1716
					if (! empty($conf->global->MAIN_SHOW_LOGIN))
1717
					{
1718
						$out.= ($moreinfo?' - ':' (').$obj->login;
1719
						$moreinfo++;
1720
					}
1721
					if ($showstatus >= 0)
1722
					{
1723
						if ($obj->statut == 1 && $showstatus == 1)
1724
						{
1725
							$out.=($moreinfo?' - ':' (').$langs->trans('Enabled');
1726
							$moreinfo++;
1727
						}
1728
						if ($obj->statut == 0)
1729
						{
1730
							$out.=($moreinfo?' - ':' (').$langs->trans('Disabled');
1731
							$moreinfo++;
1732
						}
1733
					}
1734
					if (! empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && ! $user->entity)
1735
					{
1736
						if (! $obj->entity)
1737
						{
1738
							$out.=($moreinfo?' - ':' (').$langs->trans("AllEntities");
1739
							$moreinfo++;
1740
						}
1741
						else
1742
						{
1743
							$out.=($moreinfo?' - ':' (').($obj->label?$obj->label:$langs->trans("EntityNameNotDefined"));
1744
							$moreinfo++;
1745
					 	}
1746
					}
1747
					$out.=($moreinfo?')':'');
1748
					if ($disableline && $disableline != '1')
1749
					{
1750
						$out.=' - '.$disableline;	// This is text from $enableonlytext parameter
1751
					}
1752
					$out.= '</option>';
1753
					$outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1754
1755
					$i++;
1756
				}
1757
			}
1758
			else
1759
			{
1760
				$out.= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
1761
				$out.= '<option value="">'.$langs->trans("None").'</option>';
1762
			}
1763
			$out.= '</select>';
1764
		}
1765
		else
1766
		{
1767
			dol_print_error($this->db);
1768
		}
1769
1770
		if ($outputmode) return $outarray;
1771
		return $out;
1772
	}
1773
1774
1775
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1776
	/**
1777
	 *	Return select list of users. Selected users are stored into session.
1778
	 *  List of users are provided into $_SESSION['assignedtouser'].
1779
	 *
1780
	 *  @param  string	$action         Value for $action
1781
	 *  @param  string	$htmlname       Field name in form
1782
	 *  @param  int		$show_empty     0=list without the empty value, 1=add empty value
1783
	 *  @param  array	$exclude        Array list of users id to exclude
1784
	 * 	@param	int		$disabled		If select list must be disabled
1785
	 *  @param  array	$include        Array list of users id to include or 'hierarchy' to have only supervised users
1786
	 * 	@param	array	$enableonly		Array list of users id to be enabled. All other must be disabled
1787
	 *  @param	int		$force_entity	'0' or Ids of environment to force
1788
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
1789
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1790
	 *  @param	string	$morefilter		Add more filters into sql request
1791
	 *  @param	int		$showproperties		Show properties of each attendees
1792
	 *  @param	array	$listofuserid		Array with properties of each user
1793
	 *  @param	array	$listofcontactid	Array with properties of each contact
1794
	 *  @param	array	$listofotherid		Array with properties of each other contact
1795
	 * 	@return	string					HTML select string
1796
	 *  @see select_dolgroups
1797
	 */
1798
	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())
1799
	{
1800
        // phpcs:enable
1801
		global $conf, $user, $langs;
1802
1803
		$userstatic=new User($this->db);
1804
		$out='';
1805
1806
		// Method with no ajax
1807
		//$out.='<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
1808
		if ($action == 'view')
1809
		{
1810
			$out.='';
1811
		}
1812
		else
1813
		{
1814
			$out.='<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
1815
			$out.='<script type="text/javascript" language="javascript">jQuery(document).ready(function () {    jQuery(".removedassigned").click(function() {        jQuery(".removedassignedhidden").val(jQuery(this).val());    });})</script>';
1816
			$out.=$this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
1817
			$out.=' <input type="submit" class="button valignmiddle" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
1818
			$out.='<br>';
1819
		}
1820
		$assignedtouser=array();
1821
		if (!empty($_SESSION['assignedtouser']))
1822
		{
1823
			$assignedtouser=json_decode($_SESSION['assignedtouser'], true);
1824
		}
1825
		$nbassignetouser=count($assignedtouser);
1826
1827
		if ($nbassignetouser && $action != 'view') $out.='<br>';
1828
		if ($nbassignetouser) $out.='<ul class="attendees">';
1829
		$i=0; $ownerid=0;
1830
		foreach($assignedtouser as $key => $value)
1831
		{
1832
			if ($value['id'] == $ownerid) continue;
1833
1834
			$out.='<li>';
1835
			$userstatic->fetch($value['id']);
1836
			$out.= $userstatic->getNomUrl(-1);
1837
			if ($i == 0) { $ownerid = $value['id']; $out.=' ('.$langs->trans("Owner").')'; }
1838
			if ($nbassignetouser > 1 && $action != 'view')
1839
			{
1840
				$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.'">';
1841
			}
1842
			// Show my availability
1843
			if ($showproperties)
1844
			{
1845
				if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid)))
1846
				{
1847
					$out.='<div class="myavailability inline-block">';
1848
					$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");
1849
					$out.='</div>';
1850
				}
1851
			}
1852
			//$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
1853
			//$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
1854
1855
			$out.='</li>';
1856
			$i++;
1857
		}
1858
		if ($nbassignetouser) $out.='</ul>';
1859
1860
		//$out.='</form>';
1861
		return $out;
1862
	}
1863
1864
1865
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
1866
	/**
1867
	 *  Return list of products for customer in Ajax if Ajax activated or go to select_produits_list
1868
	 *
1869
	 *  @param		int			$selected				Preselected products
1870
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page)
1871
	 *  @param		int			$filtertype				Filter on product type (''=nofilter, 0=product, 1=service)
1872
	 *  @param		int			$limit					Limit on number of returned lines
1873
	 *  @param		int			$price_level			Level of price to show
1874
	 *  @param		int			$status					Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell
1875
	 *  @param		int			$finished				2=all, 1=finished, 0=raw material
1876
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
1877
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1878
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
1879
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
1880
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
1881
	 * 	@param		int			$forcecombo				Force to use combo box
1882
	 *  @param      string      $morecss                Add more css on select
1883
	 *  @param      int         $hidepriceinlabel       1=Hide prices in label
1884
	 *  @param      string      $warehouseStatus        warehouse status filter, following comma separated filter options can be used
1885
	 *										            'warehouseopen' = select products from open warehouses,
1886
	 *										            'warehouseclosed' = select products from closed warehouses,
1887
	 *										            'warehouseinternal' = select products from warehouses for internal correct/transfer only
1888
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
1889
	 *  @return		void
1890
	 */
1891
	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())
1892
	{
1893
        // phpcs:enable
1894
		global $langs,$conf;
1895
1896
		$price_level = (! empty($price_level) ? $price_level : 0);
1897
1898
		if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
1899
		{
1900
			$placeholder='';
1901
1902
			if ($selected && empty($selected_input_value))
1903
			{
1904
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1905
				$producttmpselect = new Product($this->db);
1906
				$producttmpselect->fetch($selected);
1907
				$selected_input_value=$producttmpselect->ref;
1908
				unset($producttmpselect);
1909
			}
1910
			// mode=1 means customers products
1911
			$urloption='htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
1912
			//Price by customer
1913
			if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
1914
				$urloption.='&socid='.$socid;
1915
			}
1916
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1917
1918
			if (!empty($conf->variants->enabled)) {
1919
				?>
1920
				<script>
1921
1922
					selected = <?php echo json_encode($selected_combinations) ?>;
1923
					combvalues = {};
1924
1925
					jQuery(document).ready(function () {
1926
1927
						jQuery("input[name='prod_entry_mode']").change(function () {
1928
							if (jQuery(this).val() == 'free') {
1929
								jQuery('div#attributes_box').empty();
1930
							}
1931
						});
1932
1933
						jQuery("input#<?php echo $htmlname ?>").change(function () {
1934
1935
							if (!jQuery(this).val()) {
1936
								jQuery('div#attributes_box').empty();
1937
								return;
1938
							}
1939
1940
							jQuery.getJSON("<?php echo dol_buildpath('/variants/ajax/getCombinations.php', 2) ?>", {
1941
								id: jQuery(this).val()
1942
							}, function (data) {
1943
								jQuery('div#attributes_box').empty();
1944
1945
								jQuery.each(data, function (key, val) {
1946
1947
									combvalues[val.id] = val.values;
1948
1949
									var span = jQuery(document.createElement('div')).css({
1950
										'display': 'table-row'
1951
									});
1952
1953
									span.append(
1954
										jQuery(document.createElement('div')).text(val.label).css({
1955
											'font-weight': 'bold',
1956
											'display': 'table-cell',
1957
											'text-align': 'right'
1958
										})
1959
									);
1960
1961
									var html = jQuery(document.createElement('select')).attr('name', 'combinations[' + val.id + ']').css({
1962
										'margin-left': '15px',
1963
										'white-space': 'pre'
1964
									}).append(
1965
										jQuery(document.createElement('option')).val('')
1966
									);
1967
1968
									jQuery.each(combvalues[val.id], function (key, val) {
1969
										var tag = jQuery(document.createElement('option')).val(val.id).html(val.value);
1970
1971
										if (selected[val.fk_product_attribute] == val.id) {
1972
											tag.attr('selected', 'selected');
1973
										}
1974
1975
										html.append(tag);
1976
									});
1977
1978
									span.append(html);
1979
									jQuery('div#attributes_box').append(span);
1980
								});
1981
							})
1982
						});
1983
1984
						<?php if ($selected): ?>
1985
						jQuery("input#<?php echo $htmlname ?>").change();
1986
						<?php endif ?>
1987
					});
1988
				</script>
1989
                <?php
1990
			}
1991
			if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1992
			else if ($hidelabel > 1) {
1993
				$placeholder=' placeholder="'.$langs->trans("RefOrLabel").'"';
1994
				if ($hidelabel == 2) {
1995
					print img_picto($langs->trans("Search"), 'search');
1996
				}
1997
			}
1998
			print '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1999
			if ($hidelabel == 3) {
2000
				print img_picto($langs->trans("Search"), 'search');
2001
			}
2002
		}
2003
		else
2004
		{
2005
			print $this->select_produits_list($selected,$htmlname,$filtertype,$limit,$price_level,'',$status,$finished,0,$socid,$showempty,$forcecombo,$morecss,$hidepriceinlabel, $warehouseStatus);
2006
		}
2007
	}
2008
2009
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2010
	/**
2011
	 *	Return list of products for a customer
2012
	 *
2013
	 *	@param      int		$selected           Preselected product
2014
	 *	@param      string	$htmlname           Name of select html
2015
	 *  @param		string	$filtertype         Filter on product type (''=nofilter, 0=product, 1=service)
2016
	 *	@param      int		$limit              Limit on number of returned lines
2017
	 *	@param      int		$price_level        Level of price to show
2018
	 * 	@param      string	$filterkey          Filter on product
2019
	 *	@param		int		$status             -1=Return all products, 0=Products not on sell, 1=Products on sell
2020
	 *  @param      int		$finished           Filter on finished field: 2=No filter
2021
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
2022
	 *  @param      int		$socid     		    Thirdparty Id (to get also price dedicated to this customer)
2023
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2024
	 * 	@param		int		$forcecombo		    Force to use combo box
2025
	 *  @param      string  $morecss            Add more css on select
2026
	 *  @param      int     $hidepriceinlabel   1=Hide prices in label
2027
	 *  @param      string  $warehouseStatus    warehouse status filter, following comma separated filter options can be used
2028
	 *										    'warehouseopen' = select products from open warehouses,
2029
	 *										    'warehouseclosed' = select products from closed warehouses,
2030
	 *										    'warehouseinternal' = select products from warehouses for internal correct/transfer only
2031
	 *  @return     array    				    Array of keys for json
2032
	 */
2033
	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='')
2034
	{
2035
        // phpcs:enable
2036
		global $langs,$conf,$user,$db;
2037
2038
		$out='';
2039
		$outarray=array();
2040
2041
		$warehouseStatusArray = array();
2042
		if (! empty($warehouseStatus))
2043
		{
2044
			require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2045
			if (preg_match('/warehouseclosed/', $warehouseStatus))
2046
			{
2047
				$warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2048
			}
2049
			if (preg_match('/warehouseopen/', $warehouseStatus))
2050
			{
2051
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2052
			}
2053
			if (preg_match('/warehouseinternal/', $warehouseStatus))
2054
			{
2055
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2056
			}
2057
		}
2058
2059
		$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";
2060
		(count($warehouseStatusArray)) ? $selectFieldsGrouped = ", sum(ps.reel) as stock" : $selectFieldsGrouped = ", p.stock";
2061
2062
		$sql = "SELECT ";
2063
		$sql.= $selectFields . $selectFieldsGrouped;
2064
2065
		if (! empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2066
		{
2067
			//Product category
2068
			$sql.= ", (SELECT ".MAIN_DB_PREFIX."categorie_product.fk_categorie
2069
						FROM ".MAIN_DB_PREFIX."categorie_product
2070
						WHERE ".MAIN_DB_PREFIX."categorie_product.fk_product=p.rowid
2071
						LIMIT 1
2072
				) AS categorie_product_id ";
2073
		}
2074
2075
		//Price by customer
2076
		if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid))
2077
		{
2078
			$sql.=', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2079
			$sql.=' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx';
2080
			$selectFields.= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx";
2081
		}
2082
2083
		// Multilang : we add translation
2084
		if (! empty($conf->global->MAIN_MULTILANGS))
2085
		{
2086
			$sql.= ", pl.label as label_translated";
2087
			$selectFields.= ", label_translated";
2088
		}
2089
		// Price by quantity
2090
		if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
2091
		{
2092
			$sql.= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
2093
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql.= " AND price_level=".$price_level;
2094
			$sql.= " ORDER BY date_price";
2095
			$sql.= " DESC LIMIT 1) as price_rowid";
2096
			$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
2097
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql.= " AND price_level=".$price_level;
2098
			$sql.= " ORDER BY date_price";
2099
			$sql.= " DESC LIMIT 1) as price_by_qty";
2100
			$selectFields.= ", price_rowid, price_by_qty";
2101
		}
2102
		$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
2103
		if (count($warehouseStatusArray))
2104
		{
2105
			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
2106
			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid";
2107
		}
2108
2109
		// include search in supplier ref
2110
		if(!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
2111
		{
2112
            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2113
		}
2114
2115
		//Price by customer
2116
		if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2117
			$sql.=" LEFT JOIN  ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".$socid." AND pcp.fk_product=p.rowid";
2118
		}
2119
		// Multilang : we add translation
2120
		if (! empty($conf->global->MAIN_MULTILANGS))
2121
		{
2122
			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='". $langs->getDefaultLang() ."'";
2123
		}
2124
2125
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2126
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2127
		}
2128
2129
		$sql.= ' WHERE p.entity IN ('.getEntity('product').')';
2130
		if (count($warehouseStatusArray))
2131
		{
2132
			$sql.= ' AND (p.fk_product_type = 1 OR e.statut IN ('.$this->db->escape(implode(',',$warehouseStatusArray)).'))';
2133
		}
2134
2135
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2136
			$sql .= " AND pac.rowid IS NULL";
2137
		}
2138
2139
		if ($finished == 0)
2140
		{
2141
			$sql.= " AND p.finished = ".$finished;
2142
		}
2143
		elseif ($finished == 1)
2144
		{
2145
			$sql.= " AND p.finished = ".$finished;
2146
			if ($status >= 0)  $sql.= " AND p.tosell = ".$status;
2147
		}
2148
		elseif ($status >= 0)
2149
		{
2150
			$sql.= " AND p.tosell = ".$status;
2151
		}
2152
		if (strval($filtertype) != '') $sql.=" AND p.fk_product_type=".$filtertype;
2153
		// Add criteria on ref/label
2154
		if ($filterkey != '')
2155
		{
2156
			$sql.=' AND (';
2157
			$prefix=empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE)?'%':'';	// Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2158
			// For natural search
2159
			$scrit = explode(' ', $filterkey);
2160
			$i=0;
2161
			if (count($scrit) > 1) $sql.="(";
2162
			foreach ($scrit as $crit)
2163
			{
2164
				if ($i > 0) $sql.=" AND ";
2165
				$sql.="(p.ref LIKE '".$db->escape($prefix.$crit)."%' OR p.label LIKE '".$db->escape($prefix.$crit)."%'";
2166
				if (! empty($conf->global->MAIN_MULTILANGS)) $sql.=" OR pl.label LIKE '".$db->escape($prefix.$crit)."%'";
2167
				if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION))
2168
				{
2169
					$sql.=" OR p.description LIKE '".$db->escape($prefix.$crit)."%'";
2170
					if (! empty($conf->global->MAIN_MULTILANGS)) $sql.=" OR pl.description LIKE '".$db->escape($prefix.$crit)."%'";
2171
				}
2172
				if (! empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) $sql.=" OR pfp.ref_fourn LIKE '".$db->escape($prefix.$crit)."%'";
2173
				$sql.=")";
2174
				$i++;
2175
			}
2176
			if (count($scrit) > 1) $sql.=")";
2177
		  	if (! empty($conf->barcode->enabled)) $sql.= " OR p.barcode LIKE '".$db->escape($prefix.$filterkey)."%'";
2178
			$sql.=')';
2179
		}
2180
		if (count($warehouseStatusArray))
2181
		{
2182
			$sql.= ' GROUP BY'.$selectFields;
2183
		}
2184
2185
		//Sort by category
2186
		if(! empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2187
		{
2188
			$sql .= " ORDER BY categorie_product_id ";
2189
			//ASC OR DESC order
2190
			($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .="ASC" : $sql .="DESC";
2191
		}
2192
		else
2193
		{
2194
			$sql.= $db->order("p.ref");
2195
		}
2196
2197
		$sql.= $db->plimit($limit, 0);
2198
2199
		// Build output string
2200
		dol_syslog(get_class($this)."::select_produits_list search product", LOG_DEBUG);
2201
		$result=$this->db->query($sql);
2202
		if ($result)
2203
		{
2204
			require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2205
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2206
			$num = $this->db->num_rows($result);
2207
2208
			$events=null;
2209
2210
			if (! $forcecombo)
2211
			{
2212
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2213
				$out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT);
2214
			}
2215
2216
			$out.='<select class="flat'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2217
2218
			$textifempty='';
2219
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2220
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2221
			if (! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2222
			{
2223
				if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
2224
				else $textifempty.=$langs->trans("All");
2225
			}
2226
			if ($showempty) $out.='<option value="0" selected>'.$textifempty.'</option>';
2227
2228
			$i = 0;
2229
			while ($num && $i < $num)
2230
			{
2231
				$opt = '';
2232
				$optJson = array();
2233
				$objp = $this->db->fetch_object($result);
2234
2235
				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)
2236
				{ // Price by quantity will return many prices for the same product
2237
					$sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2238
					$sql.= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
2239
					$sql.= " WHERE fk_product_price=".$objp->price_rowid;
2240
					$sql.= " ORDER BY quantity ASC";
2241
2242
					dol_syslog(get_class($this)."::select_produits_list search price by qty", LOG_DEBUG);
2243
					$result2 = $this->db->query($sql);
2244
					if ($result2)
2245
					{
2246
						$nb_prices = $this->db->num_rows($result2);
2247
						$j = 0;
2248
						while ($nb_prices && $j < $nb_prices) {
2249
							$objp2 = $this->db->fetch_object($result2);
2250
2251
							$objp->price_by_qty_rowid = $objp2->rowid;
2252
							$objp->price_by_qty_price_base_type = $objp2->price_base_type;
2253
							$objp->price_by_qty_quantity = $objp2->quantity;
2254
							$objp->price_by_qty_unitprice = $objp2->unitprice;
2255
							$objp->price_by_qty_remise_percent = $objp2->remise_percent;
2256
							// For backward compatibility
2257
							$objp->quantity = $objp2->quantity;
2258
							$objp->price = $objp2->price;
2259
							$objp->unitprice = $objp2->unitprice;
2260
							$objp->remise_percent = $objp2->remise_percent;
2261
							$objp->remise = $objp2->remise;
2262
2263
							$this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel);
2264
2265
							$j++;
2266
2267
							// Add new entry
2268
							// "key" value of json key array is used by jQuery automatically as selected value
2269
							// "label" value of json key array is used by jQuery automatically as text for combo box
2270
							$out.=$opt;
2271
							array_push($outarray, $optJson);
2272
						}
2273
					}
2274
				}
2275
				else
2276
				{
2277
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2278
						$price_product = new Product($this->db);
2279
						$price_product->fetch($objp->rowid, '', '', 1);
2280
						$priceparser = new PriceParser($this->db);
2281
						$price_result = $priceparser->parseProduct($price_product);
2282
						if ($price_result >= 0) {
2283
							$objp->price = $price_result;
2284
							$objp->unitprice = $price_result;
2285
							//Calculate the VAT
2286
							$objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2287
							$objp->price_ttc = price2num($objp->price_ttc,'MU');
2288
						}
2289
					}
2290
					$this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel);
2291
					// Add new entry
2292
					// "key" value of json key array is used by jQuery automatically as selected value
2293
					// "label" value of json key array is used by jQuery automatically as text for combo box
2294
					$out.=$opt;
2295
					array_push($outarray, $optJson);
2296
				}
2297
2298
				$i++;
2299
			}
2300
2301
			$out.='</select>';
2302
2303
			$this->db->free($result);
2304
2305
			if (empty($outputmode)) return $out;
2306
			return $outarray;
2307
		}
2308
		else
2309
		{
2310
			dol_print_error($db);
2311
		}
2312
	}
2313
2314
	/**
2315
	 * constructProductListOption
2316
	 *
2317
	 * @param 	resultset	$objp			    Resultset of fetch
2318
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
2319
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
2320
	 * @param 	int			$price_level	    Price level
2321
	 * @param 	string		$selected		    Preselected value
2322
	 * @param   int         $hidepriceinlabel   Hide price in label
2323
	 * @return	void
2324
	 */
2325
	private function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0)
2326
	{
2327
		global $langs,$conf,$user,$db;
2328
2329
		$outkey='';
2330
		$outval='';
2331
		$outref='';
2332
		$outlabel='';
2333
		$outdesc='';
2334
		$outbarcode='';
2335
		$outtype='';
2336
		$outprice_ht='';
2337
		$outprice_ttc='';
2338
		$outpricebasetype='';
2339
		$outtva_tx='';
2340
		$outqty=1;
2341
		$outdiscount=0;
2342
2343
		$maxlengtharticle=(empty($conf->global->PRODUCT_MAX_LENGTH_COMBO)?48:$conf->global->PRODUCT_MAX_LENGTH_COMBO);
2344
2345
		$label=$objp->label;
2346
		if (! empty($objp->label_translated)) $label=$objp->label_translated;
2347
		if (! empty($filterkey) && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$label,1);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $filterkey seems to never exist and therefore empty should always be true.
Loading history...
2348
2349
		$outkey=$objp->rowid;
2350
		$outref=$objp->ref;
2351
		$outlabel=$objp->label;
2352
		$outdesc=$objp->description;
2353
		$outbarcode=$objp->barcode;
2354
2355
		$outtype=$objp->fk_product_type;
2356
		$outdurationvalue=$outtype == Product::TYPE_SERVICE?substr($objp->duration,0,dol_strlen($objp->duration)-1):'';
2357
		$outdurationunit=$outtype == Product::TYPE_SERVICE?substr($objp->duration,-1):'';
2358
2359
		$opt = '<option value="'.$objp->rowid.'"';
2360
		$opt.= ($objp->rowid == $selected)?' selected':'';
2361
		if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)
2362
		{
2363
			$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.'"';
2364
		}
2365
		if (! empty($conf->stock->enabled) && $objp->fk_product_type == 0 && isset($objp->stock))
2366
		{
2367
			if ($objp->stock > 0) $opt.= ' class="product_line_stock_ok"';
2368
			else if ($objp->stock <= 0) $opt.= ' class="product_line_stock_too_low"';
2369
		}
2370
		$opt.= '>';
2371
		$opt.= $objp->ref;
2372
		if ($outbarcode) $opt.=' ('.$outbarcode.')';
2373
		$opt.=' - '.dol_trunc($label,$maxlengtharticle);
2374
2375
		$objRef = $objp->ref;
2376
		if (! empty($filterkey) && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
2377
		$outval.=$objRef;
2378
		if ($outbarcode) $outval.=' ('.$outbarcode.')';
2379
		$outval.=' - '.dol_trunc($label,$maxlengtharticle);
2380
2381
		$found=0;
2382
2383
		// Multiprice
2384
		// If we need a particular price level (from 1 to 6)
2385
		if (empty($hidepriceinlabel) && $price_level >= 1 && (! empty($conf->global->PRODUIT_MULTIPRICES) || ! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)))
2386
		{
2387
			$sql = "SELECT price, price_ttc, price_base_type, tva_tx";
2388
			$sql.= " FROM ".MAIN_DB_PREFIX."product_price";
2389
			$sql.= " WHERE fk_product='".$objp->rowid."'";
2390
			$sql.= " AND entity IN (".getEntity('productprice').")";
2391
			$sql.= " AND price_level=".$price_level;
2392
			$sql.= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2393
			$sql.= " LIMIT 1";
2394
2395
			dol_syslog(get_class($this).'::constructProductListOption search price for level '.$price_level.'', LOG_DEBUG);
2396
			$result2 = $this->db->query($sql);
2397
			if ($result2)
2398
			{
2399
				$objp2 = $this->db->fetch_object($result2);
2400
				if ($objp2)
2401
				{
2402
					$found=1;
2403
					if ($objp2->price_base_type == 'HT')
2404
					{
2405
						$opt.= ' - '.price($objp2->price,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("HT");
2406
						$outval.= ' - '.price($objp2->price,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("HT");
2407
					}
2408
					else
2409
					{
2410
						$opt.= ' - '.price($objp2->price_ttc,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("TTC");
2411
						$outval.= ' - '.price($objp2->price_ttc,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("TTC");
2412
					}
2413
					$outprice_ht=price($objp2->price);
2414
					$outprice_ttc=price($objp2->price_ttc);
2415
					$outpricebasetype=$objp2->price_base_type;
2416
					$outtva_tx=$objp2->tva_tx;
2417
				}
2418
			}
2419
			else
2420
			{
2421
				dol_print_error($this->db);
2422
			}
2423
		}
2424
2425
		// Price by quantity
2426
		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)))
2427
		{
2428
			$found = 1;
2429
			$outqty=$objp->quantity;
2430
			$outdiscount=$objp->remise_percent;
2431
			if ($objp->quantity == 1)
2432
			{
2433
				$opt.= ' - '.price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/";
2434
				$outval.= ' - '.price($objp->unitprice,0,$langs,0,0,-1,$conf->currency)."/";
2435
				$opt.= $langs->trans("Unit");	// Do not use strtolower because it breaks utf8 encoding
2436
				$outval.=$langs->transnoentities("Unit");
2437
			}
2438
			else
2439
			{
2440
				$opt.= ' - '.price($objp->price,1,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2441
				$outval.= ' - '.price($objp->price,0,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2442
				$opt.= $langs->trans("Units");	// Do not use strtolower because it breaks utf8 encoding
2443
				$outval.=$langs->transnoentities("Units");
2444
			}
2445
2446
			$outprice_ht=price($objp->unitprice);
2447
			$outprice_ttc=price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
2448
			$outpricebasetype=$objp->price_base_type;
2449
			$outtva_tx=$objp->tva_tx;
2450
		}
2451
		if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1)
2452
		{
2453
			$opt.=" (".price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/".$langs->trans("Unit").")";	// Do not use strtolower because it breaks utf8 encoding
2454
			$outval.=" (".price($objp->unitprice,0,$langs,0,0,-1,$conf->currency)."/".$langs->transnoentities("Unit").")";	// Do not use strtolower because it breaks utf8 encoding
2455
		}
2456
		if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1)
2457
		{
2458
			$opt.=" - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2459
			$outval.=" - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2460
		}
2461
2462
		// Price by customer
2463
		if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES))
2464
		{
2465
			if (!empty($objp->idprodcustprice))
2466
			{
2467
				$found = 1;
2468
2469
				if ($objp->custprice_base_type == 'HT')
2470
				{
2471
					$opt.= ' - '.price($objp->custprice,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("HT");
2472
					$outval.= ' - '.price($objp->custprice,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("HT");
2473
				}
2474
				else
2475
				{
2476
					$opt.= ' - '.price($objp->custprice_ttc,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("TTC");
2477
					$outval.= ' - '.price($objp->custprice_ttc,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("TTC");
2478
				}
2479
2480
				$outprice_ht=price($objp->custprice);
2481
				$outprice_ttc=price($objp->custprice_ttc);
2482
				$outpricebasetype=$objp->custprice_base_type;
2483
				$outtva_tx=$objp->custtva_tx;
2484
			}
2485
		}
2486
2487
		// If level no defined or multiprice not found, we used the default price
2488
		if (empty($hidepriceinlabel) && ! $found)
2489
		{
2490
			if ($objp->price_base_type == 'HT')
2491
			{
2492
				$opt.= ' - '.price($objp->price,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("HT");
2493
				$outval.= ' - '.price($objp->price,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("HT");
2494
			}
2495
			else
2496
			{
2497
				$opt.= ' - '.price($objp->price_ttc,1,$langs,0,0,-1,$conf->currency).' '.$langs->trans("TTC");
2498
				$outval.= ' - '.price($objp->price_ttc,0,$langs,0,0,-1,$conf->currency).' '.$langs->transnoentities("TTC");
2499
			}
2500
			$outprice_ht=price($objp->price);
2501
			$outprice_ttc=price($objp->price_ttc);
2502
			$outpricebasetype=$objp->price_base_type;
2503
			$outtva_tx=$objp->tva_tx;
2504
		}
2505
2506
		if (! empty($conf->stock->enabled) && isset($objp->stock) && $objp->fk_product_type == 0)
2507
		{
2508
			$opt.= ' - '.$langs->trans("Stock").':'.$objp->stock;
2509
2510
			if ($objp->stock > 0) {
2511
				$outval.= ' - <span class="product_line_stock_ok">'.$langs->transnoentities("Stock").':'.$objp->stock.'</span>';
2512
			}elseif ($objp->stock <= 0) {
2513
				$outval.= ' - <span class="product_line_stock_too_low">'.$langs->transnoentities("Stock").':'.$objp->stock.'</span>';
2514
			}
2515
		}
2516
2517
		if ($outdurationvalue && $outdurationunit)
2518
		{
2519
			$da=array("h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
2520
			if (isset($da[$outdurationunit]))
2521
			{
2522
				$key = $da[$outdurationunit].($outdurationvalue > 1?'s':'');
2523
				$opt.= ' - '.$outdurationvalue.' '.$langs->trans($key);
2524
				$outval.=' - '.$outdurationvalue.' '.$langs->transnoentities($key);
2525
			}
2526
		}
2527
2528
		$opt.= "</option>\n";
2529
		$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);
2530
	}
2531
2532
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2533
	/**
2534
	 *	Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list)
2535
	 *
2536
	 *	@param	int		$socid			Id third party
2537
	 *	@param  string	$selected       Preselected product
2538
	 *	@param  string	$htmlname       Name of HTML Select
2539
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
2540
	 *	@param  string	$filtre			For a SQL filter
2541
	 *	@param	array	$ajaxoptions	Options for ajax_autocompleter
2542
	 *  @param	int		$hidelabel		Hide label (0=no, 1=yes)
2543
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
2544
	 *	@return	void
2545
	 */
2546
	function select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0)
2547
	{
2548
        // phpcs:enable
2549
		global $langs,$conf;
2550
		global $price_level, $status, $finished;
2551
2552
		$selected_input_value='';
2553
		if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2554
		{
2555
			if ($selected > 0)
2556
			{
2557
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2558
				$producttmpselect = new Product($this->db);
2559
				$producttmpselect->fetch($selected);
2560
				$selected_input_value=$producttmpselect->ref;
2561
				unset($producttmpselect);
2562
			}
2563
2564
			// mode=2 means suppliers products
2565
			$urloption=($socid > 0?'socid='.$socid.'&':'').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
2566
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
2567
			print ($hidelabel?'':$langs->trans("RefOrLabel").' : ').'<input type="text" size="20" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'">';
2568
		}
2569
		else
2570
		{
2571
			print $this->select_produits_fournisseurs_list($socid,$selected,$htmlname,$filtertype,$filtre,'',-1,0,0,$alsoproductwithnosupplierprice);
2572
		}
2573
	}
2574
2575
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2576
	/**
2577
	 *	Return list of suppliers products
2578
	 *
2579
	 *	@param	int		$socid   		Id societe fournisseur (0 pour aucun filtre)
2580
	 *	@param  int		$selected       Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD')
2581
	 *	@param  string	$htmlname       Nom de la zone select
2582
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
2583
	 *	@param  string	$filtre         Pour filtre sql
2584
	 *	@param  string	$filterkey      Filtre des produits
2585
	 *  @param  int		$statut         -1=Return all products, 0=Products not on sell, 1=Products on sell (not used here, a filter on tobuy is already hard coded in request)
2586
	 *  @param  int		$outputmode     0=HTML select string, 1=Array
2587
	 *  @param  int     $limit          Limit of line number
2588
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
2589
	 *  @return array           		Array of keys for json
2590
	 */
2591
	function select_produits_fournisseurs_list($socid,$selected='',$htmlname='productid',$filtertype='',$filtre='',$filterkey='',$statut=-1,$outputmode=0,$limit=100,$alsoproductwithnosupplierprice=0)
2592
	{
2593
        // phpcs:enable
2594
		global $langs,$conf,$db;
2595
2596
		$out='';
2597
		$outarray=array();
2598
2599
		$langs->load('stocks');
2600
2601
		$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration, p.fk_product_type,";
2602
		$sql.= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
2603
		$sql.= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,";
2604
		$sql.= " pfp.supplier_reputation";
2605
		$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
2606
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2607
		if ($socid) $sql.= " AND pfp.fk_soc = ".$socid;
2608
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2609
		$sql.= " WHERE p.entity IN (".getEntity('product').")";
2610
		$sql.= " AND p.tobuy = 1";
2611
		if (strval($filtertype) != '') $sql.=" AND p.fk_product_type=".$this->db->escape($filtertype);
2612
		if (! empty($filtre)) $sql.=" ".$filtre;
2613
		// Add criteria on ref/label
2614
		if ($filterkey != '')
2615
		{
2616
			$sql.=' AND (';
2617
			$prefix=empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE)?'%':'';	// Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2618
			// For natural search
2619
			$scrit = explode(' ', $filterkey);
2620
			$i=0;
2621
			if (count($scrit) > 1) $sql.="(";
2622
			foreach ($scrit as $crit)
2623
			{
2624
				if ($i > 0) $sql.=" AND ";
2625
				$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)."%')";
2626
				$i++;
2627
			}
2628
			if (count($scrit) > 1) $sql.=")";
2629
			if (! empty($conf->barcode->enabled)) $sql.= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2630
			$sql.=')';
2631
		}
2632
		$sql.= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
2633
		$sql.= $db->plimit($limit, 0);
2634
2635
		// Build output string
2636
2637
		dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
2638
		$result=$this->db->query($sql);
2639
		if ($result)
2640
		{
2641
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2642
2643
			$num = $this->db->num_rows($result);
2644
2645
			//$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">';	// remove select to have id same with combo and ajax
2646
			$out.='<select class="flat maxwidthonsmartphone" id="'.$htmlname.'" name="'.$htmlname.'">';
2647
			if (! $selected) $out.='<option value="0" selected>&nbsp;</option>';
2648
			else $out.='<option value="0">&nbsp;</option>';
2649
2650
			$i = 0;
2651
			while ($i < $num)
2652
			{
2653
				$objp = $this->db->fetch_object($result);
2654
2655
				$outkey=$objp->idprodfournprice;                                                    // id in table of price
2656
				if (! $outkey && $alsoproductwithnosupplierprice) $outkey='idprod_'.$objp->rowid;   // id of product
2657
2658
				$outref=$objp->ref;
2659
				$outval='';
2660
				$outqty=1;
2661
				$outdiscount=0;
2662
				$outtype=$objp->fk_product_type;
2663
				$outdurationvalue=$outtype == Product::TYPE_SERVICE?substr($objp->duration,0,dol_strlen($objp->duration)-1):'';
2664
				$outdurationunit=$outtype == Product::TYPE_SERVICE?substr($objp->duration,-1):'';
2665
2666
				$opt = '<option value="'.$outkey.'"';
2667
				if ($selected && $selected == $objp->idprodfournprice) $opt.= ' selected';
2668
				if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) $opt.=' disabled';
2669
				if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0)
2670
				{
2671
					$opt.= ' pbq="'.$objp->idprodfournprice.'" data-pbq="'.$objp->idprodfournprice.'" data-pbqqty="'.$objp->quantity.'" data-pbqpercent="'.$objp->remise_percent.'"';
2672
				}
2673
				$opt.= '>';
2674
2675
				$objRef = $objp->ref;
2676
				if ($filterkey && $filterkey != '') $objRef=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRef,1);
2677
				$objRefFourn = $objp->ref_fourn;
2678
				if ($filterkey && $filterkey != '') $objRefFourn=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$objRefFourn,1);
2679
				$label = $objp->label;
2680
				if ($filterkey && $filterkey != '') $label=preg_replace('/('.preg_quote($filterkey).')/i','<strong>$1</strong>',$label,1);
2681
2682
				$opt.=$objp->ref;
2683
				if (! empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn))
2684
					$opt.=' ('.$objp->ref_fourn.')';
2685
				$opt.=' - ';
2686
				$outval.=$objRef;
2687
				if (! empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn))
2688
					$outval.=' ('.$objRefFourn.')';
2689
				$outval.=' - ';
2690
				$opt.=dol_trunc($label, 72).' - ';
2691
				$outval.=dol_trunc($label, 72).' - ';
2692
2693
				if (! empty($objp->idprodfournprice))
2694
				{
2695
					$outqty=$objp->quantity;
2696
					$outdiscount=$objp->remise_percent;
2697
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2698
						$prod_supplier = new ProductFournisseur($this->db);
2699
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2700
						$prod_supplier->id = $objp->fk_product;
2701
						$prod_supplier->fourn_qty = $objp->quantity;
2702
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
2703
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2704
						$priceparser = new PriceParser($this->db);
2705
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
2706
						if ($price_result >= 0) {
2707
							$objp->fprice = $price_result;
2708
							if ($objp->quantity >= 1)
2709
							{
2710
								$objp->unitprice = $objp->fprice / $objp->quantity;
2711
							}
2712
						}
2713
					}
2714
					if ($objp->quantity == 1)
2715
					{
2716
						$opt.= price($objp->fprice,1,$langs,0,0,-1,$conf->currency)."/";
2717
						$outval.= price($objp->fprice,0,$langs,0,0,-1,$conf->currency)."/";
2718
						$opt.= $langs->trans("Unit");	// Do not use strtolower because it breaks utf8 encoding
2719
						$outval.=$langs->transnoentities("Unit");
2720
					}
2721
					else
2722
					{
2723
						$opt.= price($objp->fprice,1,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2724
						$outval.= price($objp->fprice,0,$langs,0,0,-1,$conf->currency)."/".$objp->quantity;
2725
						$opt.= ' '.$langs->trans("Units");	// Do not use strtolower because it breaks utf8 encoding
2726
						$outval.= ' '.$langs->transnoentities("Units");
2727
					}
2728
2729
					if ($objp->quantity >= 1)
2730
					{
2731
						$opt.=" (".price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/".$langs->trans("Unit").")";	// Do not use strtolower because it breaks utf8 encoding
2732
						$outval.=" (".price($objp->unitprice,0,$langs,0,0,-1,$conf->currency)."/".$langs->transnoentities("Unit").")";	// Do not use strtolower because it breaks utf8 encoding
2733
					}
2734
					if ($objp->remise_percent >= 1)
2735
					{
2736
						$opt.=" - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2737
						$outval.=" - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2738
					}
2739
					if ($objp->duration)
2740
					{
2741
						$opt .= " - ".$objp->duration;
2742
						$outval.=" - ".$objp->duration;
2743
					}
2744
					if (! $socid)
2745
					{
2746
						$opt .= " - ".dol_trunc($objp->name,8);
2747
						$outval.=" - ".dol_trunc($objp->name,8);
2748
					}
2749
					if ($objp->supplier_reputation)
2750
					{
2751
						//TODO dictionary
2752
						$reputations=array(''=>$langs->trans('Standard'),'FAVORITE'=>$langs->trans('Favorite'),'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
2753
2754
						$opt .= " - ".$reputations[$objp->supplier_reputation];
2755
						$outval.=" - ".$reputations[$objp->supplier_reputation];
2756
					}
2757
				}
2758
				else
2759
				{
2760
					if (empty($alsoproductwithnosupplierprice))     // No supplier price defined for couple product/supplier
2761
					{
2762
						$opt.= $langs->trans("NoPriceDefinedForThisSupplier");
2763
						$outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier");
2764
					}
2765
					else                                            // No supplier price defined for product, even on other suppliers
2766
					{
2767
						$opt.= $langs->trans("NoPriceDefinedForThisSupplier");
2768
						$outval.=$langs->transnoentities("NoPriceDefinedForThisSupplier");
2769
					}
2770
				}
2771
				$opt .= "</option>\n";
2772
2773
2774
				// Add new entry
2775
				// "key" value of json key array is used by jQuery automatically as selected value
2776
				// "label" value of json key array is used by jQuery automatically as text for combo box
2777
				$out.=$opt;
2778
				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)));
2779
				// Exemple of var_dump $outarray
2780
				// array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
2781
				//           ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
2782
				//      	 ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
2783
				//}
2784
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2785
				//$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
2786
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2787
2788
				$i++;
2789
			}
2790
			$out.='</select>';
2791
2792
			$this->db->free($result);
2793
2794
			include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2795
			$out.=ajax_combobox($htmlname);
2796
2797
			if (empty($outputmode)) return $out;
2798
			return $outarray;
2799
		}
2800
		else
2801
		{
2802
			dol_print_error($this->db);
2803
		}
2804
	}
2805
2806
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2807
	/**
2808
	 *	Return list of suppliers prices for a product
2809
	 *
2810
	 *  @param	    int		$productid       	Id of product
2811
	 *  @param      string	$htmlname        	Name of HTML field
2812
	 *  @param      int		$selected_supplier  Pre-selected supplier if more than 1 result
2813
	 *  @return	    void
2814
	 */
2815
	function select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier='')
2816
	{
2817
        // phpcs:enable
2818
		global $langs,$conf;
2819
2820
		$langs->load('stocks');
2821
2822
		$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration, pfp.fk_soc,";
2823
		$sql.= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.unitprice,";
2824
		$sql.= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
2825
		$sql.= " FROM ".MAIN_DB_PREFIX."product as p";
2826
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2827
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2828
		$sql.= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
2829
		$sql.= " AND p.tobuy = 1";
2830
		$sql.= " AND s.fournisseur = 1";
2831
		$sql.= " AND p.rowid = ".$productid;
2832
		$sql.= " ORDER BY s.nom, pfp.ref_fourn DESC";
2833
2834
		dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
2835
		$result=$this->db->query($sql);
2836
2837
		if ($result)
2838
		{
2839
			$num = $this->db->num_rows($result);
2840
2841
			$form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
2842
2843
			if (! $num)
2844
			{
2845
				$form.= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
2846
			}
2847
			else
2848
			{
2849
				require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2850
				$form.= '<option value="0">&nbsp;</option>';
2851
2852
				$i = 0;
2853
				while ($i < $num)
2854
				{
2855
					$objp = $this->db->fetch_object($result);
2856
2857
					$opt = '<option value="'.$objp->idprodfournprice.'"';
2858
					//if there is only one supplier, preselect it
2859
					if($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
2860
						$opt .= ' selected';
2861
					}
2862
					$opt.= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
2863
2864
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2865
						$prod_supplier = new ProductFournisseur($this->db);
2866
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2867
						$prod_supplier->id = $productid;
2868
						$prod_supplier->fourn_qty = $objp->quantity;
2869
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
2870
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2871
						$priceparser = new PriceParser($this->db);
2872
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
2873
						if ($price_result >= 0) {
2874
							$objp->fprice = $price_result;
2875
							if ($objp->quantity >= 1)
2876
							{
2877
								$objp->unitprice = $objp->fprice / $objp->quantity;
2878
							}
2879
						}
2880
					}
2881
					if ($objp->quantity == 1)
2882
					{
2883
						$opt.= price($objp->fprice,1,$langs,0,0,-1,$conf->currency)."/";
2884
					}
2885
2886
					$opt.= $objp->quantity.' ';
2887
2888
					if ($objp->quantity == 1)
2889
					{
2890
						$opt.= $langs->trans("Unit");
2891
					}
2892
					else
2893
					{
2894
						$opt.= $langs->trans("Units");
2895
					}
2896
					if ($objp->quantity > 1)
2897
					{
2898
						$opt.=" - ";
2899
						$opt.= price($objp->unitprice,1,$langs,0,0,-1,$conf->currency)."/".$langs->trans("Unit");
2900
					}
2901
					if ($objp->duration) $opt .= " - ".$objp->duration;
2902
					$opt .= "</option>\n";
2903
2904
					$form.= $opt;
2905
					$i++;
2906
				}
2907
			}
2908
2909
			$form.= '</select>';
2910
			$this->db->free($result);
2911
			return $form;
2912
		}
2913
		else
2914
		{
2915
			dol_print_error($this->db);
2916
		}
2917
	}
2918
2919
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2920
	/**
2921
	 *    Return list of delivery address
2922
	 *
2923
	 *    @param    string	$selected          	Id contact pre-selectionn
2924
	 *    @param    int		$socid				Id of company
2925
	 *    @param    string	$htmlname          	Name of HTML field
2926
	 *    @param    int		$showempty         	Add an empty field
2927
	 *    @return	integer|null
2928
	 */
2929
	function select_address($selected, $socid, $htmlname='address_id',$showempty=0)
2930
	{
2931
        // phpcs:enable
2932
		// looking for users
2933
		$sql = "SELECT a.rowid, a.label";
2934
		$sql .= " FROM ".MAIN_DB_PREFIX ."societe_address as a";
2935
		$sql .= " WHERE a.fk_soc = ".$socid;
2936
		$sql .= " ORDER BY a.label ASC";
2937
2938
		dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
2939
		$resql=$this->db->query($sql);
2940
		if ($resql)
2941
		{
2942
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
2943
			if ($showempty) print '<option value="0">&nbsp;</option>';
2944
			$num = $this->db->num_rows($resql);
2945
			$i = 0;
2946
			if ($num)
2947
			{
2948
				while ($i < $num)
2949
				{
2950
					$obj = $this->db->fetch_object($resql);
2951
2952
					if ($selected && $selected == $obj->rowid)
2953
					{
2954
						print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
2955
					}
2956
					else
2957
					{
2958
						print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
2959
					}
2960
					$i++;
2961
				}
2962
			}
2963
			print '</select>';
2964
			return $num;
2965
		}
2966
		else
2967
		{
2968
			dol_print_error($this->db);
2969
		}
2970
	}
2971
2972
2973
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
2974
	/**
2975
	 *      Load into cache list of payment terms
2976
	 *
2977
	 *      @return     int             Nb of lines loaded, <0 if KO
2978
	 */
2979
	function load_cache_conditions_paiements()
2980
	{
2981
        // phpcs:enable
2982
		global $langs;
2983
2984
		$num = count($this->cache_conditions_paiements);
2985
		if ($num > 0) return 0;    // Cache already loaded
2986
2987
		dol_syslog(__METHOD__, LOG_DEBUG);
2988
2989
		$sql = "SELECT rowid, code, libelle as label";
2990
		$sql.= " FROM ".MAIN_DB_PREFIX.'c_payment_term';
2991
		$sql.= " WHERE entity IN (".getEntity('c_payment_term').")";
2992
		$sql.= " AND active > 0";
2993
		$sql.= " ORDER BY sortorder";
2994
2995
		$resql = $this->db->query($sql);
2996
		if ($resql)
2997
		{
2998
			$num = $this->db->num_rows($resql);
2999
			$i = 0;
3000
			while ($i < $num)
3001
			{
3002
				$obj = $this->db->fetch_object($resql);
3003
3004
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3005
				$label=($langs->trans("PaymentConditionShort".$obj->code)!=("PaymentConditionShort".$obj->code)?$langs->trans("PaymentConditionShort".$obj->code):($obj->label!='-'?$obj->label:''));
3006
				$this->cache_conditions_paiements[$obj->rowid]['code'] =$obj->code;
3007
				$this->cache_conditions_paiements[$obj->rowid]['label']=$label;
3008
				$i++;
3009
			}
3010
3011
			//$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1);		// We use the field sortorder of table
3012
3013
			return $num;
3014
		}
3015
		else
3016
		{
3017
			dol_print_error($this->db);
3018
			return -1;
3019
		}
3020
	}
3021
3022
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3023
	/**
3024
	 *      Charge dans cache la liste des délais de livraison possibles
3025
	 *
3026
	 *      @return     int             Nb of lines loaded, <0 if KO
3027
	 */
3028
	function load_cache_availability()
3029
	{
3030
        // phpcs:enable
3031
		global $langs;
3032
3033
		$num = count($this->cache_availability);
3034
		if ($num > 0) return 0;    // Cache already loaded
3035
3036
		dol_syslog(__METHOD__, LOG_DEBUG);
3037
3038
		$langs->load('propal');
3039
3040
		$sql = "SELECT rowid, code, label";
3041
		$sql.= " FROM ".MAIN_DB_PREFIX.'c_availability';
3042
		$sql.= " WHERE active > 0";
3043
3044
		$resql = $this->db->query($sql);
3045
		if ($resql)
3046
		{
3047
			$num = $this->db->num_rows($resql);
3048
			$i = 0;
3049
			while ($i < $num)
3050
			{
3051
				$obj = $this->db->fetch_object($resql);
3052
3053
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3054
				$label=($langs->trans("AvailabilityType".$obj->code)!=("AvailabilityType".$obj->code)?$langs->trans("AvailabilityType".$obj->code):($obj->label!='-'?$obj->label:''));
3055
				$this->cache_availability[$obj->rowid]['code'] =$obj->code;
3056
				$this->cache_availability[$obj->rowid]['label']=$label;
3057
				$i++;
3058
			}
3059
3060
			$this->cache_availability = dol_sort_array($this->cache_availability, 'label', 'asc', 0, 0, 1);
3061
3062
			return $num;
3063
		}
3064
		else
3065
		{
3066
			dol_print_error($this->db);
3067
			return -1;
3068
		}
3069
	}
3070
3071
	/**
3072
	 *      Retourne la liste des types de delais de livraison possibles
3073
	 *
3074
	 *      @param	int		$selected        Id du type de delais pre-selectionne
3075
	 *      @param  string	$htmlname        Nom de la zone select
3076
	 *      @param  string	$filtertype      To add a filter
3077
	 *		@param	int		$addempty		Add empty entry
3078
	 *		@return	void
3079
	 */
3080
	function selectAvailabilityDelay($selected='',$htmlname='availid',$filtertype='',$addempty=0)
3081
	{
3082
		global $langs,$user;
3083
3084
		$this->load_cache_availability();
3085
3086
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3087
3088
		print '<select id="'.$htmlname.'" class="flat" name="'.$htmlname.'">';
3089
		if ($addempty) print '<option value="0">&nbsp;</option>';
3090
		foreach($this->cache_availability as $id => $arrayavailability)
3091
		{
3092
			if ($selected == $id)
3093
			{
3094
				print '<option value="'.$id.'" selected>';
3095
			}
3096
			else
3097
			{
3098
				print '<option value="'.$id.'">';
3099
			}
3100
			print $arrayavailability['label'];
3101
			print '</option>';
3102
		}
3103
		print '</select>';
3104
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3105
	}
3106
3107
	/**
3108
	 *      Load into cache cache_demand_reason, array of input reasons
3109
	 *
3110
	 *      @return     int             Nb of lines loaded, <0 if KO
3111
	 */
3112
	function loadCacheInputReason()
3113
	{
3114
		global $langs;
3115
3116
		$num = count($this->cache_demand_reason);
3117
		if ($num > 0) return 0;    // Cache already loaded
3118
3119
		$sql = "SELECT rowid, code, label";
3120
		$sql.= " FROM ".MAIN_DB_PREFIX.'c_input_reason';
3121
		$sql.= " WHERE active > 0";
3122
3123
		$resql = $this->db->query($sql);
3124
		if ($resql)
3125
		{
3126
			$num = $this->db->num_rows($resql);
3127
			$i = 0;
3128
			$tmparray=array();
3129
			while ($i < $num)
3130
			{
3131
				$obj = $this->db->fetch_object($resql);
3132
3133
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3134
				$label=($obj->label!='-'?$obj->label:'');
3135
				if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3136
				if ($langs->trans($obj->code) != $obj->code) $label=$langs->trans($obj->code);																// So translation key SRC_XXX will work
3137
3138
				$tmparray[$obj->rowid]['id']   =$obj->rowid;
3139
				$tmparray[$obj->rowid]['code'] =$obj->code;
3140
				$tmparray[$obj->rowid]['label']=$label;
3141
				$i++;
3142
			}
3143
3144
			$this->cache_demand_reason=dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3145
3146
			unset($tmparray);
3147
			return $num;
3148
		}
3149
		else
3150
		{
3151
			dol_print_error($this->db);
3152
			return -1;
3153
		}
3154
	}
3155
3156
	/**
3157
	 *	Return list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
3158
	 *  List found into table c_input_reason loaded by loadCacheInputReason
3159
	 *
3160
	 *  @param	int		$selected        Id or code of type origin to select by default
3161
	 *  @param  string	$htmlname        Nom de la zone select
3162
	 *  @param  string	$exclude         To exclude a code value (Example: SRC_PROP)
3163
	 *	@param	int		$addempty		 Add an empty entry
3164
	 *	@return	void
3165
	 */
3166
	function selectInputReason($selected='',$htmlname='demandreasonid',$exclude='',$addempty=0)
3167
	{
3168
		global $langs,$user;
3169
3170
		$this->loadCacheInputReason();
3171
3172
		print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3173
		if ($addempty) print '<option value="0"'.(empty($selected)?' selected':'').'>&nbsp;</option>';
3174
		foreach($this->cache_demand_reason as $id => $arraydemandreason)
3175
		{
3176
			if ($arraydemandreason['code']==$exclude) continue;
3177
3178
			if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code']))
3179
			{
3180
				print '<option value="'.$arraydemandreason['id'].'" selected>';
3181
			}
3182
			else
3183
			{
3184
				print '<option value="'.$arraydemandreason['id'].'">';
3185
			}
3186
			$label=$arraydemandreason['label'];	// Translation of label was already done into the ->loadCacheInputReason
3187
			print $langs->trans($label);
3188
			print '</option>';
3189
		}
3190
		print '</select>';
3191
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3192
	}
3193
3194
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3195
	/**
3196
	 *      Charge dans cache la liste des types de paiements possibles
3197
	 *
3198
	 *      @return     int                 Nb of lines loaded, <0 if KO
3199
	 */
3200
	function load_cache_types_paiements()
3201
	{
3202
        // phpcs:enable
3203
		global $langs;
3204
3205
		$num=count($this->cache_types_paiements);
3206
		if ($num > 0) return $num;    // Cache already loaded
3207
3208
		dol_syslog(__METHOD__, LOG_DEBUG);
3209
3210
		$this->cache_types_paiements = array();
3211
3212
		$sql = "SELECT id, code, libelle as label, type, active";
3213
		$sql.= " FROM ".MAIN_DB_PREFIX."c_paiement";
3214
		$sql.= " WHERE entity IN (".getEntity('c_paiement').")";
3215
		//if ($active >= 0) $sql.= " AND active = ".$active;
3216
3217
		$resql = $this->db->query($sql);
3218
		if ($resql)
3219
		{
3220
			$num = $this->db->num_rows($resql);
3221
			$i = 0;
3222
			while ($i < $num)
3223
			{
3224
				$obj = $this->db->fetch_object($resql);
3225
3226
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3227
				$label=($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code)!=("PaymentTypeShort".$obj->code)?$langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code):($obj->label!='-'?$obj->label:''));
3228
				$this->cache_types_paiements[$obj->id]['id'] =$obj->id;
3229
				$this->cache_types_paiements[$obj->id]['code'] =$obj->code;
3230
				$this->cache_types_paiements[$obj->id]['label']=$label;
3231
				$this->cache_types_paiements[$obj->id]['type'] =$obj->type;
3232
				$this->cache_types_paiements[$obj->id]['active'] =$obj->active;
3233
				$i++;
3234
			}
3235
3236
			$this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3237
3238
			return $num;
3239
		}
3240
		else
3241
		{
3242
			dol_print_error($this->db);
3243
			return -1;
3244
		}
3245
	}
3246
3247
3248
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3249
	/**
3250
	 *      Return list of payment modes.
3251
	 *      Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
3252
	 *      See instead to force the default value by the caller.
3253
	 *
3254
	 *      @param	int		$selected		Id of payment term to preselect by default
3255
	 *      @param	string	$htmlname		Nom de la zone select
3256
	 *      @param	int		$filtertype		Not used
3257
	 *		@param	int		$addempty		Add an empty entry
3258
	 * 		@param	int		$noinfoadmin		0=Add admin info, 1=Disable admin info
3259
	 * 		@param	string	$morecss			Add more CSS on select tag
3260
	 *		@return	void
3261
	 */
3262
	function select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='')
3263
	{
3264
        // phpcs:enable
3265
		global $langs, $user, $conf;
3266
3267
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3268
3269
		$this->load_cache_conditions_paiements();
3270
3271
		// Set default value if not already set by caller
3272
		if (empty($selected) && ! empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
3273
3274
		print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'">';
3275
		if ($addempty) print '<option value="0">&nbsp;</option>';
3276
		foreach($this->cache_conditions_paiements as $id => $arrayconditions)
3277
		{
3278
			if ($selected == $id)
3279
			{
3280
				print '<option value="'.$id.'" selected>';
3281
			}
3282
			else
3283
			{
3284
				print '<option value="'.$id.'">';
3285
			}
3286
			print $arrayconditions['label'];
3287
			print '</option>';
3288
		}
3289
		print '</select>';
3290
		if ($user->admin && empty($noinfoadmin)) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3291
	}
3292
3293
3294
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3295
	/**
3296
	 *      Return list of payment methods
3297
	 *
3298
	 *      @param	string	$selected       Id du mode de paiement pre-selectionne
3299
	 *      @param  string	$htmlname       Nom de la zone select
3300
	 *      @param  string	$filtertype     To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz))
3301
	 *      @param  int		$format         0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code
3302
	 *      @param  int		$empty			1=peut etre vide, 0 sinon
3303
	 * 		@param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
3304
	 *      @param  int		$maxlength      Max length of label
3305
	 *      @param  int     $active         Active or not, -1 = all
3306
	 *      @param  string  $morecss        Add more CSS on select tag
3307
	 * 		@return	void
3308
	 */
3309
	function select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
3310
	{
3311
        // phpcs:enable
3312
		global $langs,$user;
3313
3314
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
3315
3316
		$filterarray=array();
3317
		if ($filtertype == 'CRDT')  	$filterarray=array(0,2,3);
3318
		elseif ($filtertype == 'DBIT') 	$filterarray=array(1,2,3);
3319
		elseif ($filtertype != '' && $filtertype != '-1') $filterarray=explode(',',$filtertype);
3320
3321
		$this->load_cache_types_paiements();
3322
3323
		print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'">';
3324
		if ($empty) print '<option value="">&nbsp;</option>';
3325
		foreach($this->cache_types_paiements as $id => $arraytypes)
3326
		{
3327
			// If not good status
3328
			if ($active >= 0 && $arraytypes['active'] != $active) continue;
3329
3330
			// On passe si on a demande de filtrer sur des modes de paiments particuliers
3331
			if (count($filterarray) && ! in_array($arraytypes['type'],$filterarray)) continue;
3332
3333
			// We discard empty line if showempty is on because an empty line has already been output.
3334
			if ($empty && empty($arraytypes['code'])) continue;
3335
3336
			if ($format == 0) print '<option value="'.$id.'"';
3337
			elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3338
			elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3339
			elseif ($format == 3) print '<option value="'.$id.'"';
3340
			// Si selected est text, on compare avec code, sinon avec id
3341
			if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) print ' selected';
3342
			elseif ($selected == $id) print ' selected';
3343
			print '>';
3344
			if ($format == 0) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
3345
			elseif ($format == 1) $value=$arraytypes['code'];
3346
			elseif ($format == 2) $value=($maxlength?dol_trunc($arraytypes['label'],$maxlength):$arraytypes['label']);
3347
			elseif ($format == 3) $value=$arraytypes['code'];
3348
			print $value?$value:'&nbsp;';
3349
			print '</option>';
3350
		}
3351
		print '</select>';
3352
		if ($user->admin && ! $noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3353
	}
3354
3355
3356
	/**
3357
	 *  Selection HT or TTC
3358
	 *
3359
	 *  @param	string	$selected       Id pre-selectionne
3360
	 *  @param  string	$htmlname       Nom de la zone select
3361
	 * 	@return	string					Code of HTML select to chose tax or not
3362
	 */
3363
	function selectPriceBaseType($selected='',$htmlname='price_base_type')
3364
	{
3365
		global $langs;
3366
3367
		$return='';
3368
3369
		$return.= '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3370
		$options = array(
3371
			'HT'=>$langs->trans("HT"),
3372
			'TTC'=>$langs->trans("TTC")
3373
		);
3374
		foreach($options as $id => $value)
3375
		{
3376
			if ($selected == $id)
3377
			{
3378
				$return.= '<option value="'.$id.'" selected>'.$value;
3379
			}
3380
			else
3381
			{
3382
				$return.= '<option value="'.$id.'">'.$value;
3383
			}
3384
			$return.= '</option>';
3385
		}
3386
		$return.= '</select>';
3387
3388
		return $return;
3389
	}
3390
3391
	/**
3392
	 *  Return a HTML select list of shipping mode
3393
	 *
3394
	 *  @param	string	$selected          Id shipping mode pre-selected
3395
	 *  @param  string	$htmlname          Name of select zone
3396
	 *  @param  string	$filtre            To filter list
3397
	 *  @param  int		$useempty          1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
3398
	 *  @param  string	$moreattrib        To add more attribute on select
3399
	 * 	@return	void
3400
	 */
3401
	function selectShippingMethod($selected='',$htmlname='shipping_method_id',$filtre='',$useempty=0,$moreattrib='')
3402
	{
3403
		global $langs, $conf, $user;
3404
3405
		$langs->load("admin");
3406
		$langs->load("deliveries");
3407
3408
		$sql = "SELECT rowid, code, libelle as label";
3409
		$sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode";
3410
		$sql.= " WHERE active > 0";
3411
		if ($filtre) $sql.=" AND ".$filtre;
3412
		$sql.= " ORDER BY libelle ASC";
3413
3414
		dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
3415
		$result = $this->db->query($sql);
3416
		if ($result) {
3417
			$num = $this->db->num_rows($result);
3418
			$i = 0;
3419
			if ($num) {
3420
				print '<select id="select'.$htmlname.'" class="flat selectshippingmethod" name="'.$htmlname.'"'.($moreattrib?' '.$moreattrib:'').'>';
3421
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
3422
					print '<option value="-1">&nbsp;</option>';
3423
				}
3424
				while ($i < $num) {
3425
					$obj = $this->db->fetch_object($result);
3426
					if ($selected == $obj->rowid) {
3427
						print '<option value="'.$obj->rowid.'" selected>';
3428
					} else {
3429
						print '<option value="'.$obj->rowid.'">';
3430
					}
3431
					print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
3432
					print '</option>';
3433
					$i++;
3434
				}
3435
				print "</select>";
3436
				if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
3437
			} else {
3438
				print $langs->trans("NoShippingMethodDefined");
3439
			}
3440
		} else {
3441
			dol_print_error($this->db);
3442
		}
3443
	}
3444
3445
	/**
3446
	 *    Display form to select shipping mode
3447
	 *
3448
	 *    @param	string	$page        Page
3449
	 *    @param    int		$selected    Id of shipping mode
3450
	 *    @param    string	$htmlname    Name of select html field
3451
	 *    @param    int		$addempty    1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
3452
	 *    @return	void
3453
	 */
3454
	function formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
3455
	{
3456
		global $langs, $db;
3457
3458
		$langs->load("deliveries");
3459
3460
		if ($htmlname != "none") {
3461
			print '<form method="POST" action="'.$page.'">';
3462
			print '<input type="hidden" name="action" value="setshippingmethod">';
3463
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
3464
			$this->selectShippingMethod($selected, $htmlname, '', $addempty);
3465
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3466
			print '</form>';
3467
		} else {
3468
			if ($selected) {
3469
				$code=$langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code');
3470
				print $langs->trans("SendingMethod".strtoupper($code));
3471
			} else {
3472
				print "&nbsp;";
3473
			}
3474
		}
3475
	}
3476
3477
	/**
3478
	 * Creates HTML last in cycle situation invoices selector
3479
	 *
3480
	 * @param     string  $selected   		Preselected ID
3481
	 * @param     int     $socid      		Company ID
3482
	 *
3483
	 * @return    string                     HTML select
3484
	 */
3485
	function selectSituationInvoices($selected = '', $socid = 0)
3486
	{
3487
		global $langs;
3488
3489
		$langs->load('bills');
3490
3491
		$opt = '<option value ="" selected></option>';
3492
		$sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc FROM ' . MAIN_DB_PREFIX . 'facture WHERE situation_counter>=1';
3493
		$sql.= ' ORDER by situation_cycle_ref, situation_counter desc';
3494
		$resql = $this->db->query($sql);
3495
		if ($resql && $this->db->num_rows($resql) > 0) {
3496
			// Last seen cycle
3497
			$ref = 0;
3498
			while ($obj = $this->db->fetch_object($resql)){
3499
				//Same company ?
3500
			    if ($socid == $obj->fk_soc) {
3501
					//Same cycle ?
3502
			        if ($obj->situation_cycle_ref != $ref) {
3503
						// Just seen this cycle
3504
			            $ref = $obj->situation_cycle_ref;
3505
						//not final ?
3506
			            if ($obj->situation_final != 1) {
3507
							//Not prov?
3508
			                if (substr($obj->ref, 1, 4) != 'PROV') {
3509
			                    if ($selected == $obj->rowid) {
3510
			                        $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
3511
								} else {
3512
								    $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
3513
								}
3514
							}
3515
						}
3516
					}
3517
				}
3518
			}
3519
		}
3520
		else
3521
		{
3522
				dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
3523
		}
3524
		if ($opt == '<option value ="" selected></option>')
3525
		{
3526
			$opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
3527
		}
3528
		return $opt;
3529
	}
3530
3531
	/**
3532
	 *      Creates HTML units selector (code => label)
3533
	 *
3534
	 *      @param	string	$selected       Preselected Unit ID
3535
	 *      @param  string	$htmlname       Select name
3536
	 *      @param	int		$showempty		Add a nempty line
3537
	 * 		@return	string                  HTML select
3538
	 */
3539
	function selectUnits($selected = '', $htmlname = 'units', $showempty=0)
3540
	{
3541
		global $langs;
3542
3543
		$langs->load('products');
3544
3545
		$return= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
3546
3547
		$sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units';
3548
		$sql.= ' WHERE active > 0';
3549
3550
		$resql = $this->db->query($sql);
3551
		if($resql && $this->db->num_rows($resql) > 0)
3552
		{
3553
			if ($showempty) $return .= '<option value="none"></option>';
3554
3555
			while($res = $this->db->fetch_object($resql))
3556
			{
3557
			    $unitLabel = $res->label;
3558
			    if (! empty($langs->tab_translate['unit'.$res->code]))	// check if Translation is available before
3559
			    {
3560
			        $unitLabel = $langs->trans('unit'.$res->code)!=$res->label?$langs->trans('unit'.$res->code):$res->label;
3561
			    }
3562
3563
				if ($selected == $res->rowid)
3564
				{
3565
				    $return.='<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
3566
				}
3567
				else
3568
				{
3569
				    $return.='<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
3570
				}
3571
			}
3572
			$return.='</select>';
3573
		}
3574
		return $return;
3575
	}
3576
3577
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3578
	/**
3579
	 *  Return a HTML select list of bank accounts
3580
	 *
3581
	 *  @param	string	$selected           Id account pre-selected
3582
	 *  @param  string	$htmlname           Name of select zone
3583
	 *  @param  int		$statut             Status of searched accounts (0=open, 1=closed, 2=both)
3584
	 *  @param  string	$filtre             To filter list
3585
	 *  @param  int		$useempty           1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
3586
	 *  @param  string	$moreattrib         To add more attribute on select
3587
	 *  @param	int		$showcurrency		Show currency in label
3588
	 * 	@return	int							<0 if error, Num of bank account found if OK (0, 1, 2, ...)
3589
	 */
3590
	function select_comptes($selected='',$htmlname='accountid',$statut=0,$filtre='',$useempty=0,$moreattrib='',$showcurrency=0)
3591
	{
3592
        // phpcs:enable
3593
		global $langs, $conf;
3594
3595
		$langs->load("admin");
3596
		$num = 0;
3597
3598
		$sql = "SELECT rowid, label, bank, clos as status, currency_code";
3599
		$sql.= " FROM ".MAIN_DB_PREFIX."bank_account";
3600
		$sql.= " WHERE entity IN (".getEntity('bank_account').")";
3601
		if ($statut != 2) $sql.= " AND clos = '".$statut."'";
3602
		if ($filtre) $sql.=" AND ".$filtre;
3603
		$sql.= " ORDER BY label";
3604
3605
		dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
3606
		$result = $this->db->query($sql);
3607
		if ($result)
3608
		{
3609
			$num = $this->db->num_rows($result);
3610
			$i = 0;
3611
			if ($num)
3612
			{
3613
				print '<select id="select'.$htmlname.'" class="flat selectbankaccount" name="'.$htmlname.'"'.($moreattrib?' '.$moreattrib:'').'>';
3614
				if ($useempty == 1 || ($useempty == 2 && $num > 1))
3615
				{
3616
					print '<option value="-1">&nbsp;</option>';
3617
				}
3618
3619
				while ($i < $num)
3620
				{
3621
					$obj = $this->db->fetch_object($result);
3622
					if ($selected == $obj->rowid)
3623
					{
3624
						print '<option value="'.$obj->rowid.'" selected>';
3625
					}
3626
					else
3627
					{
3628
						print '<option value="'.$obj->rowid.'">';
3629
					}
3630
					print trim($obj->label);
3631
					if ($showcurrency) print ' ('.$obj->currency_code.')';
3632
					if ($statut == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
3633
					print '</option>';
3634
					$i++;
3635
				}
3636
				print "</select>";
3637
			}
3638
			else
3639
			{
3640
				if ($statut == 0) print '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
3641
				else print '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
3642
			}
3643
		}
3644
		else {
3645
			dol_print_error($this->db);
3646
		}
3647
3648
		return $num;
3649
	}
3650
3651
	/**
3652
	 *    Display form to select bank account
3653
	 *
3654
	 *    @param	string	$page        Page
3655
	 *    @param    int		$selected    Id of bank account
3656
	 *    @param    string	$htmlname    Name of select html field
3657
	 *    @param    int		$addempty    1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
3658
	 *    @return	void
3659
	 */
3660
	function formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
3661
	{
3662
		global $langs;
3663
		if ($htmlname != "none") {
3664
			print '<form method="POST" action="'.$page.'">';
3665
			print '<input type="hidden" name="action" value="setbankaccount">';
3666
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
3667
			$nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
3668
			if ($nbaccountfound > 0) print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3669
			print '</form>';
3670
		} else {
3671
3672
			$langs->load('banks');
3673
3674
			if ($selected) {
3675
				require_once DOL_DOCUMENT_ROOT .'/compta/bank/class/account.class.php';
3676
				$bankstatic=new Account($this->db);
3677
				$result = $bankstatic->fetch($selected);
3678
				if ($result) print $bankstatic->getNomUrl(1);
3679
			} else {
3680
				print "&nbsp;";
3681
			}
3682
		}
3683
	}
3684
3685
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3686
	/**
3687
	 *    Return list of categories having choosed type
3688
	 *
3689
	 *    @param	string|int	$type				Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
3690
	 *    @param    string		$selected    		Id of category preselected or 'auto' (autoselect category if there is only one element)
3691
	 *    @param    string		$htmlname			HTML field name
3692
	 *    @param    int			$maxlength      	Maximum length for labels
3693
	 *    @param    int			$excludeafterid 	Exclude all categories after this leaf in category tree.
3694
	 *    @param	int			$outputmode			0=HTML select string, 1=Array
3695
	 *    @return	string
3696
	 *    @see select_categories
3697
	 */
3698
	function select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $excludeafterid=0, $outputmode=0)
3699
	{
3700
        // phpcs:enable
3701
		global $conf, $langs;
3702
		$langs->load("categories");
3703
3704
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
3705
3706
		// For backward compatibility
3707
		if (is_numeric($type))
3708
		{
3709
			dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
3710
		}
3711
3712
		if ($type === Categorie::TYPE_BANK_LINE)
3713
		{
3714
			// TODO Move this into common category feature
3715
			$categids=array();
3716
			$sql = "SELECT c.label, c.rowid";
3717
			$sql.= " FROM ".MAIN_DB_PREFIX."bank_categ as c";
3718
			$sql.= " WHERE entity = ".$conf->entity;
3719
			$sql.= " ORDER BY c.label";
3720
			$result = $this->db->query($sql);
3721
			if ($result)
3722
			{
3723
				$num = $this->db->num_rows($result);
3724
				$i = 0;
3725
				while ($i < $num)
3726
				{
3727
					$objp = $this->db->fetch_object($result);
3728
					if ($objp) $cate_arbo[$objp->rowid]=array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
3729
					$i++;
3730
				}
3731
				$this->db->free($result);
3732
			}
3733
			else dol_print_error($this->db);
3734
		}
3735
		else
3736
		{
3737
			$cat = new Categorie($this->db);
3738
			$cate_arbo = $cat->get_full_arbo($type, $excludeafterid);
3739
		}
3740
3741
		$output = '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
3742
		$outarray=array();
3743
		if (is_array($cate_arbo))
3744
		{
3745
			if (! count($cate_arbo)) $output.= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
3746
			else
3747
			{
3748
				$output.= '<option value="-1">&nbsp;</option>';
3749
				foreach($cate_arbo as $key => $value)
3750
				{
3751
					if ($cate_arbo[$key]['id'] == $selected || ($selected == 'auto' && count($cate_arbo) == 1))
3752
					{
3753
						$add = 'selected ';
3754
					}
3755
					else
3756
					{
3757
						$add = '';
3758
					}
3759
					$output.= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'],$maxlength,'middle').'</option>';
3760
3761
					$outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
3762
				}
3763
			}
3764
		}
3765
		$output.= '</select>';
3766
		$output.= "\n";
3767
3768
		if ($outputmode) return $outarray;
3769
		return $output;
3770
	}
3771
3772
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
3773
	/**
3774
	 *     Show a confirmation HTML form or AJAX popup
3775
	 *
3776
	 *     @param	string		$page        	   	Url of page to call if confirmation is OK
3777
	 *     @param	string		$title       	   	Title
3778
	 *     @param	string		$question    	   	Question
3779
	 *     @param 	string		$action      	   	Action
3780
	 *	   @param	array		$formquestion	   	An array with forms complementary inputs
3781
	 * 	   @param	string		$selectedchoice		"" or "no" or "yes"
3782
	 * 	   @param	int			$useajax		   	0=No, 1=Yes, 2=Yes but submit page with &confirm=no if choice is No, 'xxx'=preoutput confirm box with div id=dialog-confirm-xxx
3783
	 *     @param	int			$height          	Force height of box
3784
	 *     @param	int			$width				Force width of box
3785
	 *     @return 	void
3786
	 *     @deprecated
3787
	 *     @see formconfirm()
3788
	 */
3789
	function form_confirm($page, $title, $question, $action, $formquestion='', $selectedchoice="", $useajax=0, $height=170, $width=500)
3790
	{
3791
        // phpcs:enable
3792
        dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
3793
		print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
3794
	}
3795
3796
	/**
3797
	 *     Show a confirmation HTML form or AJAX popup.
3798
	 *     Easiest way to use this is with useajax=1.
3799
	 *     If you use useajax='xxx', you must also add jquery code to trigger opening of box (with correct parameters)
3800
	 *     just after calling this method. For example:
3801
	 *       print '<script type="text/javascript">'."\n";
3802
	 *       print 'jQuery(document).ready(function() {'."\n";
3803
	 *       print 'jQuery(".xxxlink").click(function(e) { jQuery("#aparamid").val(jQuery(this).attr("rel")); jQuery("#dialog-confirm-xxx").dialog("open"); return false; });'."\n";
3804
	 *       print '});'."\n";
3805
	 *       print '</script>'."\n";
3806
	 *
3807
	 *     @param  	string		$page        	   	Url of page to call if confirmation is OK. Can contains paramaters (param 'action' and 'confirm' will be reformated)
3808
	 *     @param	string		$title       	   	Title
3809
	 *     @param	string		$question    	   	Question
3810
	 *     @param 	string		$action      	   	Action
3811
	 *	   @param  	array		$formquestion	   	An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , ))
3812
	 *												type can be 'hidden', 'text', 'password', 'checkbox', 'radio', 'date', 'morecss', ...
3813
	 * 	   @param  	string		$selectedchoice  	'' or 'no', or 'yes' or '1' or '0'
3814
	 * 	   @param  	int			$useajax		   	0=No, 1=Yes, 2=Yes but submit page with &confirm=no if choice is No, 'xxx'=Yes and preoutput confirm box with div id=dialog-confirm-xxx
3815
	 *     @param  	int			$height          	Force height of box
3816
	 *     @param	int			$width				Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones.
3817
	 *     @param	int			$disableformtag		1=Disable form tag. Can be used if we are already inside a <form> section.
3818
	 *     @return 	string      	    			HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form
3819
	 */
3820
	function formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=210, $width=500, $disableformtag=0)
3821
	{
3822
		global $langs,$conf;
3823
		global $useglobalvars;
3824
3825
		$more='';
3826
		$formconfirm='';
3827
		$inputok=array();
3828
		$inputko=array();
3829
3830
		// Clean parameters
3831
		$newselectedchoice=empty($selectedchoice)?"no":$selectedchoice;
3832
		if ($conf->browser->layout == 'phone') $width='95%';
3833
3834
		if (is_array($formquestion) && ! empty($formquestion))
3835
		{
3836
			// First add hidden fields and value
3837
			foreach ($formquestion as $key => $input)
3838
			{
3839
				if (is_array($input) && ! empty($input))
3840
				{
3841
					if ($input['type'] == 'hidden')
3842
					{
3843
						$more.='<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
3844
					}
3845
				}
3846
			}
3847
3848
			// Now add questions
3849
			$more.='<table class="paddingtopbottomonly" width="100%">'."\n";
3850
			if (! empty($formquestion['text'])) $more.='<tr><td colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
3851
			foreach ($formquestion as $key => $input)
3852
			{
3853
				if (is_array($input) && ! empty($input))
3854
				{
3855
					$size=(! empty($input['size'])?' size="'.$input['size'].'"':'');
3856
					$moreattr=(! empty($input['moreattr'])?' '.$input['moreattr']:'');
3857
					$morecss=(! empty($input['morecss'])?' '.$input['morecss']:'');
3858
3859
					if ($input['type'] == 'text')
3860
					{
3861
						$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";
3862
					}
3863
					elseif ($input['type'] == 'password')
3864
					{
3865
						$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";
3866
					}
3867
					elseif ($input['type'] == 'select')
3868
					{
3869
						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>';
3870
						if (! empty($input['label'])) $more.=$input['label'].'</td><td class="tdtop" align="left">';
3871
						$more.=$this->selectarray($input['name'],$input['values'],$input['default'],1,0,0,$moreattr,0,0,0,'',$morecss);
3872
						$more.='</td></tr>'."\n";
3873
					}
3874
					elseif ($input['type'] == 'checkbox')
3875
					{
3876
						$more.='<tr>';
3877
						$more.='<td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].' </td><td align="left">';
3878
						$more.='<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr;
3879
						if (! is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') $more.=' checked';
3880
						if (is_bool($input['value']) && $input['value']) $more.=' checked';
3881
						if (isset($input['disabled'])) $more.=' disabled';
3882
						$more.=' /></td>';
3883
						$more.='</tr>'."\n";
3884
					}
3885
					elseif ($input['type'] == 'radio')
3886
					{
3887
						$i=0;
3888
						foreach($input['values'] as $selkey => $selval)
3889
						{
3890
							$more.='<tr>';
3891
							if ($i==0) $more.='<td'.(empty($input['tdclass'])?' class="tdtop"':(' class="tdtop '.$input['tdclass'].'"')).'>'.$input['label'].'</td>';
3892
							else $more.='<td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>&nbsp;</td>';
3893
							$more.='<td><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr;
3894
							if ($input['disabled']) $more.=' disabled';
3895
							$more.=' /> ';
3896
							$more.=$selval;
3897
							$more.='</td></tr>'."\n";
3898
							$i++;
3899
						}
3900
					}
3901
					elseif ($input['type'] == 'date')
3902
					{
3903
						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>'.$input['label'].'</td>';
3904
						$more.='<td align="left">';
3905
						$more.=$this->selectDate($input['value'],$input['name'],0,0,0,'',1,0);
3906
						$more.='</td></tr>'."\n";
3907
						$formquestion[] = array('name'=>$input['name'].'day');
3908
						$formquestion[] = array('name'=>$input['name'].'month');
3909
						$formquestion[] = array('name'=>$input['name'].'year');
3910
						$formquestion[] = array('name'=>$input['name'].'hour');
3911
						$formquestion[] = array('name'=>$input['name'].'min');
3912
					}
3913
					elseif ($input['type'] == 'other')
3914
					{
3915
						$more.='<tr><td'.(empty($input['tdclass'])?'':(' class="'.$input['tdclass'].'"')).'>';
3916
						if (! empty($input['label'])) $more.=$input['label'].'</td><td align="left">';
3917
						$more.=$input['value'];
3918
						$more.='</td></tr>'."\n";
3919
					}
3920
3921
					elseif ($input['type'] == 'onecolumn')
3922
					{
3923
						$more.='<tr><td colspan="2" align="left">';
3924
						$more.=$input['value'];
3925
						$more.='</td></tr>'."\n";
3926
					}
3927
				}
3928
			}
3929
			$more.='</table>'."\n";
3930
		}
3931
3932
		// JQUI method dialog is broken with jmobile, we use standard HTML.
3933
		// 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
3934
		// See page product/card.php for example
3935
		if (! empty($conf->dol_use_jmobile)) $useajax=0;
3936
		if (empty($conf->use_javascript_ajax)) $useajax=0;
3937
3938
		if ($useajax)
3939
		{
3940
			$autoOpen=true;
3941
			$dialogconfirm='dialog-confirm';
3942
			$button='';
3943
			if (! is_numeric($useajax))
3944
			{
3945
				$button=$useajax;
3946
				$useajax=1;
3947
				$autoOpen=false;
3948
				$dialogconfirm.='-'.$button;
3949
			}
3950
			$pageyes=$page.(preg_match('/\?/',$page)?'&':'?').'action='.$action.'&confirm=yes';
3951
			$pageno=($useajax == 2 ? $page.(preg_match('/\?/',$page)?'&':'?').'confirm=no':'');
3952
			// Add input fields into list of fields to read during submit (inputok and inputko)
3953
			if (is_array($formquestion))
3954
			{
3955
				foreach ($formquestion as $key => $input)
3956
				{
3957
					//print "xx ".$key." rr ".is_array($input)."<br>\n";
3958
					if (is_array($input) && isset($input['name'])) array_push($inputok,$input['name']);
3959
					if (isset($input['inputko']) && $input['inputko'] == 1) array_push($inputko,$input['name']);
3960
				}
3961
			}
3962
			// Show JQuery confirm box. Note that global var $useglobalvars is used inside this template
3963
			$formconfirm.= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
3964
			if (! empty($more)) {
3965
				$formconfirm.= '<div class="confirmquestions">'.$more.'</div>';
3966
			}
3967
			$formconfirm.= ($question ? '<div class="confirmmessage">'.img_help('','').' '.$question . '</div>': '');
3968
			$formconfirm.= '</div>'."\n";
3969
3970
			$formconfirm.= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
3971
			$formconfirm.= '<script type="text/javascript">'."\n";
3972
			$formconfirm.= 'jQuery(document).ready(function() {
3973
            $(function() {
3974
            	$( "#'.$dialogconfirm.'" ).dialog(
3975
            	{
3976
                    autoOpen: '.($autoOpen ? "true" : "false").',';
3977
			if ($newselectedchoice == 'no')
3978
			{
3979
				$formconfirm.='
3980
						open: function() {
3981
            				$(this).parent().find("button.ui-button:eq(2)").focus();
3982
						},';
3983
			}
3984
			$formconfirm.='
3985
                    resizable: false,
3986
                    height: "'.$height.'",
3987
                    width: "'.$width.'",
3988
                    modal: true,
3989
                    closeOnEscape: false,
3990
                    buttons: {
3991
                        "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
3992
                        	var options="";
3993
                        	var inputok = '.json_encode($inputok).';
3994
                         	var pageyes = "'.dol_escape_js(! empty($pageyes)?$pageyes:'').'";
3995
                         	if (inputok.length>0) {
3996
                         		$.each(inputok, function(i, inputname) {
3997
                         			var more = "";
3998
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
3999
                         		    if ($("#" + inputname).attr("type") == "radio") { more = ":checked"; }
4000
                         			var inputvalue = $("#" + inputname + more).val();
4001
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4002
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4003
                         		});
4004
                         	}
4005
                         	var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
4006
                         	//alert(urljump);
4007
            				if (pageyes.length > 0) { location.href = urljump; }
4008
                            $(this).dialog("close");
4009
                        },
4010
                        "'.dol_escape_js($langs->transnoentities("No")).'": function() {
4011
                        	var options = "";
4012
                         	var inputko = '.json_encode($inputko).';
4013
                         	var pageno="'.dol_escape_js(! empty($pageno)?$pageno:'').'";
4014
                         	if (inputko.length>0) {
4015
                         		$.each(inputko, function(i, inputname) {
4016
                         			var more = "";
4017
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4018
                         			var inputvalue = $("#" + inputname + more).val();
4019
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4020
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4021
                         		});
4022
                         	}
4023
                         	var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
4024
                         	//alert(urljump);
4025
            				if (pageno.length > 0) { location.href = urljump; }
4026
                            $(this).dialog("close");
4027
                        }
4028
                    }
4029
                }
4030
                );
4031
4032
            	var button = "'.$button.'";
4033
            	if (button.length > 0) {
4034
                	$( "#" + button ).click(function() {
4035
                		$("#'.$dialogconfirm.'").dialog("open");
4036
        			});
4037
                }
4038
            });
4039
            });
4040
            </script>';
4041
			$formconfirm.= "<!-- end ajax formconfirm -->\n";
4042
		}
4043
		else
4044
		{
4045
			$formconfirm.= "\n<!-- begin formconfirm page=".$page." -->\n";
4046
4047
			if (empty($disableformtag)) $formconfirm.= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
4048
4049
			$formconfirm.= '<input type="hidden" name="action" value="'.$action.'">'."\n";
4050
			if (empty($disableformtag)) $formconfirm.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'."\n";
4051
4052
			$formconfirm.= '<table width="100%" class="valid">'."\n";
4053
4054
			// Line title
4055
			$formconfirm.= '<tr class="validtitre"><td class="validtitre" colspan="3">'.img_picto('','recent').' '.$title.'</td></tr>'."\n";
4056
4057
			// Line form fields
4058
			if ($more)
4059
			{
4060
				$formconfirm.='<tr class="valid"><td class="valid" colspan="3">'."\n";
4061
				$formconfirm.=$more;
4062
				$formconfirm.='</td></tr>'."\n";
4063
			}
4064
4065
			// Line with question
4066
			$formconfirm.= '<tr class="valid">';
4067
			$formconfirm.= '<td class="valid">'.$question.'</td>';
4068
			$formconfirm.= '<td class="valid">';
4069
			$formconfirm.= $this->selectyesno("confirm",$newselectedchoice);
4070
			$formconfirm.= '</td>';
4071
			$formconfirm.= '<td class="valid" align="center"><input class="button valignmiddle" type="submit" value="'.$langs->trans("Validate").'"></td>';
4072
			$formconfirm.= '</tr>'."\n";
4073
4074
			$formconfirm.= '</table>'."\n";
4075
4076
			if (empty($disableformtag)) $formconfirm.= "</form>\n";
4077
			$formconfirm.= '<br>';
4078
4079
			$formconfirm.= "<!-- end formconfirm -->\n";
4080
		}
4081
4082
		return $formconfirm;
4083
	}
4084
4085
4086
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4087
	/**
4088
	 *    Show a form to select a project
4089
	 *
4090
	 *    @param	int		$page        		Page
4091
	 *    @param	int		$socid       		Id third party (-1=all, 0=only projects not linked to a third party, id=projects not linked or linked to third party id)
4092
	 *    @param    int		$selected    		Id pre-selected project
4093
	 *    @param    string	$htmlname    		Name of select field
4094
	 *    @param	int		$discard_closed		Discard closed projects (0=Keep,1=hide completely except $selected,2=Disable)
4095
	 *    @param	int		$maxlength			Max length
4096
	 *    @param	int		$forcefocus			Force focus on field (works with javascript only)
4097
	 *    @param    int     $nooutput           No print is done. String is returned.
4098
	 *    @return	string                      Return html content
4099
	 */
4100
	function form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0)
4101
	{
4102
        // phpcs:enable
4103
		global $langs;
4104
4105
		require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
4106
		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
4107
4108
		$out='';
4109
4110
		$formproject=new FormProjets($this->db);
4111
4112
		$langs->load("project");
4113
		if ($htmlname != "none")
4114
		{
4115
			$out.="\n";
4116
			$out.='<form method="post" action="'.$page.'">';
4117
			$out.='<input type="hidden" name="action" value="classin">';
4118
			$out.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4119
			$out.=$formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
4120
			$out.='<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4121
			$out.='</form>';
4122
		}
4123
		else
4124
		{
4125
			if ($selected)
4126
			{
4127
				$projet = new Project($this->db);
4128
				$projet->fetch($selected);
4129
				//print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
4130
				$out.=$projet->getNomUrl(0,'',1);
4131
			}
4132
			else
4133
			{
4134
				$out.="&nbsp;";
4135
			}
4136
		}
4137
4138
		if (empty($nooutput))
4139
		{
4140
			print $out;
4141
			return '';
4142
		}
4143
		return $out;
4144
	}
4145
4146
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4147
	/**
4148
	 *	Show a form to select payment conditions
4149
	 *
4150
	 *  @param	int		$page        	Page
4151
	 *  @param  string	$selected    	Id condition pre-selectionne
4152
	 *  @param  string	$htmlname    	Name of select html field
4153
	 *	@param	int		$addempty		Add empty entry
4154
	 *  @return	void
4155
	 */
4156
	function form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0)
4157
	{
4158
        // phpcs:enable
4159
		global $langs;
4160
		if ($htmlname != "none")
4161
		{
4162
			print '<form method="post" action="'.$page.'">';
4163
			print '<input type="hidden" name="action" value="setconditions">';
4164
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4165
			$this->select_conditions_paiements($selected,$htmlname,-1,$addempty);
4166
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4167
			print '</form>';
4168
		}
4169
		else
4170
		{
4171
			if ($selected)
4172
			{
4173
				$this->load_cache_conditions_paiements();
4174
				print $this->cache_conditions_paiements[$selected]['label'];
4175
			} else {
4176
				print "&nbsp;";
4177
			}
4178
		}
4179
	}
4180
4181
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4182
	/**
4183
	 *  Show a form to select a delivery delay
4184
	 *
4185
	 *  @param  int		$page        	Page
4186
	 *  @param  string	$selected    	Id condition pre-selectionne
4187
	 *  @param  string	$htmlname    	Name of select html field
4188
	 *	@param	int		$addempty		Ajoute entree vide
4189
	 *  @return	void
4190
	 */
4191
	function form_availability($page, $selected='', $htmlname='availability', $addempty=0)
4192
	{
4193
        // phpcs:enable
4194
		global $langs;
4195
		if ($htmlname != "none")
4196
		{
4197
			print '<form method="post" action="'.$page.'">';
4198
			print '<input type="hidden" name="action" value="setavailability">';
4199
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4200
			$this->selectAvailabilityDelay($selected,$htmlname,-1,$addempty);
4201
			print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4202
			print '</form>';
4203
		}
4204
		else
4205
		{
4206
			if ($selected)
4207
			{
4208
				$this->load_cache_availability();
4209
				print $this->cache_availability[$selected]['label'];
4210
			} else {
4211
				print "&nbsp;";
4212
			}
4213
		}
4214
	}
4215
4216
	/**
4217
	 *	Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
4218
	 *  List found into table c_input_reason loaded by loadCacheInputReason
4219
	 *
4220
	 *  @param  string	$page        	Page
4221
	 *  @param  string	$selected    	Id condition pre-selectionne
4222
	 *  @param  string	$htmlname    	Name of select html field
4223
	 *	@param	int		$addempty		Add empty entry
4224
	 *  @return	void
4225
	 */
4226
	function formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
4227
	{
4228
		global $langs;
4229
		if ($htmlname != "none")
4230
		{
4231
			print '<form method="post" action="'.$page.'">';
4232
			print '<input type="hidden" name="action" value="setdemandreason">';
4233
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4234
			$this->selectInputReason($selected,$htmlname,-1,$addempty);
4235
			print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4236
			print '</form>';
4237
		}
4238
		else
4239
		{
4240
			if ($selected)
4241
			{
4242
				$this->loadCacheInputReason();
4243
				foreach ($this->cache_demand_reason as $key => $val)
4244
				{
4245
					if ($val['id'] == $selected)
4246
					{
4247
						print $val['label'];
4248
						break;
4249
					}
4250
				}
4251
			} else {
4252
				print "&nbsp;";
4253
			}
4254
		}
4255
	}
4256
4257
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4258
	/**
4259
	 *    Show a form + html select a date
4260
	 *
4261
	 *    @param	string		$page        	Page
4262
	 *    @param	string		$selected    	Date preselected
4263
	 *    @param    string		$htmlname    	Html name of date input fields or 'none'
4264
	 *    @param    int			$displayhour 	Display hour selector
4265
	 *    @param    int			$displaymin		Display minutes selector
4266
	 *    @param	int			$nooutput		1=No print output, return string
4267
	 *    @return	string
4268
	 *    @see		selectDate
4269
	 */
4270
	function form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0)
4271
	{
4272
        // phpcs:enable
4273
		global $langs;
4274
4275
		$ret='';
4276
4277
		if ($htmlname != "none")
4278
		{
4279
			$ret.='<form method="post" action="'.$page.'" name="form'.$htmlname.'">';
4280
			$ret.='<input type="hidden" name="action" value="set'.$htmlname.'">';
4281
			$ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4282
			$ret.='<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4283
			$ret.='<tr><td>';
4284
			$ret.=$this->selectDate($selected,$htmlname,$displayhour,$displaymin,1,'form'.$htmlname,1,0);
4285
			$ret.='</td>';
4286
			$ret.='<td align="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4287
			$ret.='</tr></table></form>';
4288
		}
4289
		else
4290
		{
4291
			if ($displayhour) $ret.=dol_print_date($selected,'dayhour');
4292
			else $ret.=dol_print_date($selected,'day');
4293
		}
4294
4295
		if (empty($nooutput)) print $ret;
4296
		return $ret;
4297
	}
4298
4299
4300
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4301
	/**
4302
	 *  Show a select form to choose a user
4303
	 *
4304
	 *  @param	string	$page        	Page
4305
	 *  @param  string	$selected    	Id of user preselected
4306
	 *  @param  string	$htmlname    	Name of input html field. If 'none', we just output the user link.
4307
	 *  @param  array	$exclude		List of users id to exclude
4308
	 *  @param  array	$include        List of users id to include
4309
	 *  @return	void
4310
	 */
4311
	function form_users($page, $selected='', $htmlname='userid', $exclude='', $include='')
4312
	{
4313
        // phpcs:enable
4314
		global $langs;
4315
4316
		if ($htmlname != "none")
4317
		{
4318
			print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
4319
			print '<input type="hidden" name="action" value="set'.$htmlname.'">';
4320
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4321
			print $this->select_dolusers($selected,$htmlname,1,$exclude,0,$include);
4322
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4323
			print '</form>';
4324
		}
4325
		else
4326
		{
4327
			if ($selected)
4328
			{
4329
				require_once DOL_DOCUMENT_ROOT .'/user/class/user.class.php';
4330
				$theuser=new User($this->db);
4331
				$theuser->fetch($selected);
4332
				print $theuser->getNomUrl(1);
4333
			} else {
4334
				print "&nbsp;";
4335
			}
4336
		}
4337
	}
4338
4339
4340
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4341
	/**
4342
	 *    Show form with payment mode
4343
	 *
4344
	 *    @param	string	$page        	Page
4345
	 *    @param    int		$selected    	Id mode pre-selectionne
4346
	 *    @param    string	$htmlname    	Name of select html field
4347
	 *    @param  	string	$filtertype		To filter on field type in llx_c_paiement (array('code'=>xx,'label'=>zz))
4348
	 *    @param    int     $active         Active or not, -1 = all
4349
	 *    @return	void
4350
	 */
4351
	function form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1)
4352
	{
4353
        // phpcs:enable
4354
		global $langs;
4355
		if ($htmlname != "none")
4356
		{
4357
			print '<form method="POST" action="'.$page.'">';
4358
			print '<input type="hidden" name="action" value="setmode">';
4359
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4360
			$this->select_types_paiements($selected,$htmlname,$filtertype,0,0,0,0,$active);
4361
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4362
			print '</form>';
4363
		}
4364
		else
4365
		{
4366
			if ($selected)
4367
			{
4368
				$this->load_cache_types_paiements();
4369
				print $this->cache_types_paiements[$selected]['label'];
4370
			} else {
4371
				print "&nbsp;";
4372
			}
4373
		}
4374
	}
4375
4376
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4377
	/**
4378
	 *    Show form with multicurrency code
4379
	 *
4380
	 *    @param	string	$page        	Page
4381
	 *    @param    string	$selected    	code pre-selectionne
4382
	 *    @param    string	$htmlname    	Name of select html field
4383
	 *    @return	void
4384
	 */
4385
	function form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
4386
	{
4387
        // phpcs:enable
4388
		global $langs;
4389
		if ($htmlname != "none")
4390
		{
4391
			print '<form method="POST" action="'.$page.'">';
4392
			print '<input type="hidden" name="action" value="setmulticurrencycode">';
4393
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4394
			print $this->selectMultiCurrency($selected, $htmlname, 0);
4395
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4396
			print '</form>';
4397
		}
4398
		else
4399
		{
4400
			dol_include_once('/core/lib/company.lib.php');
4401
			print !empty($selected) ? currency_name($selected,1) : '&nbsp;';
4402
		}
4403
	}
4404
4405
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4406
	/**
4407
	 *    Show form with multicurrency rate
4408
	 *
4409
	 *    @param	string	$page        	Page
4410
	 *    @param    double	$rate	    	Current rate
4411
	 *    @param    string	$htmlname    	Name of select html field
4412
	 *    @param    string  $currency       Currency code to explain the rate
4413
	 *    @return	void
4414
	 */
4415
	function form_multicurrency_rate($page, $rate='', $htmlname='multicurrency_tx', $currency='')
4416
	{
4417
        // phpcs:enable
4418
		global $langs, $mysoc, $conf;
4419
4420
		if ($htmlname != "none")
4421
		{
4422
			print '<form method="POST" action="'.$page.'">';
4423
			print '<input type="hidden" name="action" value="setmulticurrencyrate">';
4424
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4425
			print '<input type="text" name="'.$htmlname.'" value="'.(!empty($rate) ? price($rate) : 1).'" size="10" /> ';
4426
			print '<select name="calculation_mode">';
4427
			print '<option value="1">'.$currency.' > '.$conf->currency.'</option>';
4428
			print '<option value="2">'.$conf->currency.' > '.$currency.'</option>';
4429
			print '</select> ';
4430
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4431
			print '</form>';
4432
		}
4433
		else
4434
		{
4435
			if (! empty($rate))
4436
			{
4437
				print price($rate, 1, $langs, 1, 0);
4438
				if ($currency && $rate != 1) print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
4439
			}
4440
			else
4441
			{
4442
				print 1;
4443
			}
4444
		}
4445
	}
4446
4447
4448
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4449
	/**
4450
	 *	Show a select box with available absolute discounts
4451
	 *
4452
	 *  @param  string	$page        	Page URL where form is shown
4453
	 *  @param  int		$selected    	Value pre-selected
4454
	 *	@param  string	$htmlname    	Name of SELECT component. If 'none', not changeable. Example 'remise_id'.
4455
	 *	@param	int		$socid			Third party id
4456
	 * 	@param	float	$amount			Total amount available
4457
	 * 	@param	string	$filter			SQL filter on discounts
4458
	 * 	@param	int		$maxvalue		Max value for lines that can be selected
4459
	 *  @param  string	$more           More string to add
4460
	 *  @param  int     $hidelist       1=Hide list
4461
	 *  @param	int		$discount_type	0 => customer discount, 1 => supplier discount
4462
	 *  @return	void
4463
	 */
4464
	function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
4465
	{
4466
        // phpcs:enable
4467
		global $conf,$langs;
4468
		if ($htmlname != "none")
4469
		{
4470
			print '<form method="post" action="'.$page.'">';
4471
			print '<input type="hidden" name="action" value="setabsolutediscount">';
4472
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4473
			print '<div class="inline-block">';
4474
			if(! empty($discount_type)) {
4475
				if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4476
				{
4477
					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
4478
					else $translationKey = 'HasCreditNoteFromSupplier';
4479
				}
4480
				else
4481
				{
4482
					if (! $filter || $filter=="fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") $translationKey = 'HasAbsoluteDiscountFromSupplier';
4483
					else $translationKey = 'HasCreditNoteFromSupplier';
4484
				}
4485
			} else {
4486
				if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4487
				{
4488
					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
4489
					else $translationKey = 'CompanyHasCreditNote';
4490
				}
4491
				else
4492
				{
4493
					if (! $filter || $filter=="fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") $translationKey = 'CompanyHasAbsoluteDiscount';
4494
					else $translationKey = 'CompanyHasCreditNote';
4495
				}
4496
			}
4497
			print $langs->trans($translationKey,price($amount,0,$langs,0,0,-1,$conf->currency));
4498
			if (empty($hidelist)) print ': ';
4499
			print '</div>';
4500
			if (empty($hidelist))
4501
			{
4502
				print '<div class="inline-block" style="padding-right: 10px">';
4503
				$newfilter = 'discount_type='.intval($discount_type);
4504
				if(! empty($discount_type)) {
4505
					$newfilter.= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
4506
				} else {
4507
					$newfilter.= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
4508
				}
4509
				if ($filter) $newfilter.=' AND ('.$filter.')';
4510
				$nbqualifiedlines=$this->select_remises($selected,$htmlname,$newfilter,$socid,$maxvalue);
4511
				if ($nbqualifiedlines > 0)
4512
				{
4513
					print ' &nbsp; <input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
4514
					if(! empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')")
4515
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4516
					if(empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')")
4517
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4518
4519
					print '>';
4520
				}
4521
				print '</div>';
4522
			}
4523
			if ($more)
4524
			{
4525
				print '<div class="inline-block">';
4526
				print $more;
4527
				print '</div>';
4528
			}
4529
			print '</form>';
4530
		}
4531
		else
4532
		{
4533
			if ($selected)
4534
			{
4535
				print $selected;
4536
			}
4537
			else
4538
			{
4539
				print "0";
4540
			}
4541
		}
4542
	}
4543
4544
4545
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4546
	/**
4547
	 *    Show forms to select a contact
4548
	 *
4549
	 *    @param	string		$page        	Page
4550
	 *    @param	Societe		$societe		Filter on third party
4551
	 *    @param    int			$selected    	Id contact pre-selectionne
4552
	 *    @param    string		$htmlname    	Name of HTML select. If 'none', we just show contact link.
4553
	 *    @return	void
4554
	 */
4555
	function form_contacts($page, $societe, $selected='', $htmlname='contactid')
4556
	{
4557
        // phpcs:enable
4558
		global $langs, $conf;
4559
4560
		if ($htmlname != "none")
4561
		{
4562
			print '<form method="post" action="'.$page.'">';
4563
			print '<input type="hidden" name="action" value="set_contact">';
4564
			print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4565
			print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4566
			print '<tr><td>';
4567
			$num=$this->select_contacts($societe->id, $selected, $htmlname);
4568
			if ($num==0)
4569
			{
4570
				$addcontact = (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
4571
				print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
4572
			}
4573
			print '</td>';
4574
			print '<td align="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4575
			print '</tr></table></form>';
4576
		}
4577
		else
4578
		{
4579
			if ($selected)
4580
			{
4581
				require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php';
4582
				$contact=new Contact($this->db);
4583
				$contact->fetch($selected);
4584
				print $contact->getFullName($langs);
4585
			} else {
4586
				print "&nbsp;";
4587
			}
4588
		}
4589
	}
4590
4591
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4592
	/**
4593
	 *  Output html select to select thirdparty
4594
	 *
4595
	 *  @param	string	$page       	Page
4596
	 *  @param  string	$selected   	Id preselected
4597
	 *  @param  string	$htmlname		Name of HTML select
4598
	 *  @param  string	$filter         optional filters criteras
4599
	 *	@param	int		$showempty		Add an empty field
4600
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
4601
	 * 	@param	int		$forcecombo		Force to use combo box
4602
	 *  @param	array	$events			Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled')))
4603
	 *  @param  int     $nooutput       No print output. Return it only.
4604
	 *  @return	void
4605
	 */
4606
	function form_thirdparty($page, $selected='', $htmlname='socid', $filter='',$showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0)
4607
	{
4608
        // phpcs:enable
4609
		global $langs;
4610
4611
		$out = '';
4612
		if ($htmlname != "none")
4613
		{
4614
			$out.='<form method="post" action="'.$page.'">';
4615
			$out.= '<input type="hidden" name="action" value="set_thirdparty">';
4616
			$out.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
4617
			$out.= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events);
4618
			$out.= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4619
			$out.= '</form>';
4620
		}
4621
		else
4622
		{
4623
			if ($selected)
4624
			{
4625
				require_once DOL_DOCUMENT_ROOT .'/societe/class/societe.class.php';
4626
				$soc = new Societe($this->db);
4627
				$soc->fetch($selected);
4628
				$out.= $soc->getNomUrl($langs);
4629
			}
4630
			else
4631
			{
4632
				$out.= "&nbsp;";
4633
			}
4634
		}
4635
4636
		if ($nooutput) return $out;
4637
		else print $out;
4638
	}
4639
4640
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4641
	/**
4642
	 *    Retourne la liste des devises, dans la langue de l'utilisateur
4643
	 *
4644
	 *    @param	string	$selected    preselected currency code
4645
	 *    @param    string	$htmlname    name of HTML select list
4646
     *    @deprecated
4647
	 *    @return	void
4648
	 */
4649
	function select_currency($selected='',$htmlname='currency_id')
4650
	{
4651
        // phpcs:enable
4652
		print $this->selectCurrency($selected,$htmlname);
4653
	}
4654
4655
	/**
4656
	 *  Retourne la liste des devises, dans la langue de l'utilisateur
4657
	 *
4658
	 *  @param	string	$selected    preselected currency code
4659
	 *  @param  string	$htmlname    name of HTML select list
4660
	 * 	@return	string
4661
	 */
4662
	function selectCurrency($selected='',$htmlname='currency_id')
4663
	{
4664
		global $conf,$langs,$user;
4665
4666
		$langs->loadCacheCurrencies('');
4667
4668
		$out='';
4669
4670
		if ($selected=='euro' || $selected=='euros') $selected='EUR';   // Pour compatibilite
4671
4672
		$out.= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
4673
		foreach ($langs->cache_currencies as $code_iso => $currency)
4674
		{
4675
			if ($selected && $selected == $code_iso)
4676
			{
4677
				$out.= '<option value="'.$code_iso.'" selected>';
4678
			}
4679
			else
4680
			{
4681
				$out.= '<option value="'.$code_iso.'">';
4682
			}
4683
			$out.= $currency['label'];
4684
			$out.= ' ('.$langs->getCurrencySymbol($code_iso).')';
4685
			$out.= '</option>';
4686
		}
4687
		$out.= '</select>';
4688
		if ($user->admin) $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
4689
4690
		// Make select dynamic
4691
		include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4692
		$out .= ajax_combobox($htmlname);
4693
4694
		return $out;
4695
	}
4696
4697
	/**
4698
	 *	Return array of currencies in user language
4699
	 *
4700
	 *  @param	string	$selected    preselected currency code
4701
	 *  @param  string	$htmlname    name of HTML select list
4702
	 *  @param  integer	$useempty    1=Add empty line
4703
	 * 	@return	string
4704
	 */
4705
	function selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0)
4706
	{
4707
		global $db,$conf,$langs,$user;
4708
4709
		$langs->loadCacheCurrencies('');        // Load ->cache_currencies
4710
4711
		$TCurrency = array();
4712
4713
		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
4714
		$sql.= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
4715
		$resql = $db->query($sql);
4716
		if ($resql)
4717
		{
4718
			while ($obj = $db->fetch_object($resql)) $TCurrency[$obj->code] = $obj->code;
4719
		}
4720
4721
		$out='';
4722
		$out.= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
4723
		if ($useempty) $out .= '<option value=""></option>';
4724
		// If company current currency not in table, we add it into list. Should always be available.
4725
		if (! in_array($conf->currency, $TCurrency))
4726
		{
4727
			$TCurrency[$conf->currency] = $conf->currency;
4728
		}
4729
		if (count($TCurrency) > 0)
4730
		{
4731
			foreach ($langs->cache_currencies as $code_iso => $currency)
4732
			{
4733
				if (isset($TCurrency[$code_iso]))
4734
				{
4735
					if (!empty($selected) && $selected == $code_iso) $out.= '<option value="'.$code_iso.'" selected="selected">';
4736
					else $out.= '<option value="'.$code_iso.'">';
4737
4738
					$out.= $currency['label'];
4739
					$out.= ' ('.$langs->getCurrencySymbol($code_iso).')';
4740
					$out.= '</option>';
4741
				}
4742
			}
4743
		}
4744
4745
		$out.= '</select>';
4746
		// Make select dynamic
4747
		include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4748
		$out.= ajax_combobox($htmlname);
4749
4750
		return $out;
4751
	}
4752
4753
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4754
	/**
4755
	 *	Load into the cache vat rates of a country
4756
	 *
4757
	 *	@param	string	$country_code		Country code with quotes ("'CA'", or "'CA,IN,...'")
4758
	 *	@return	int							Nb of loaded lines, 0 if already loaded, <0 if KO
4759
	 */
4760
	function load_cache_vatrates($country_code)
4761
	{
4762
        // phpcs:enable
4763
		global $langs;
4764
4765
		$num = count($this->cache_vatrates);
4766
		if ($num > 0) return $num;    // Cache already loaded
4767
4768
		dol_syslog(__METHOD__, LOG_DEBUG);
4769
4770
		$sql  = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
4771
		$sql.= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
4772
		$sql.= " WHERE t.fk_pays = c.rowid";
4773
		$sql.= " AND t.active > 0";
4774
		$sql.= " AND c.code IN (".$country_code.")";
4775
		$sql.= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
4776
4777
		$resql=$this->db->query($sql);
4778
		if ($resql)
4779
		{
4780
			$num = $this->db->num_rows($resql);
4781
			if ($num)
4782
			{
4783
				for ($i = 0; $i < $num; $i++)
4784
				{
4785
					$obj = $this->db->fetch_object($resql);
4786
					$this->cache_vatrates[$i]['rowid']	= $obj->rowid;
4787
					$this->cache_vatrates[$i]['code']	= $obj->code;
4788
					$this->cache_vatrates[$i]['txtva']	= $obj->taux;
4789
					$this->cache_vatrates[$i]['nprtva']	= $obj->recuperableonly;
4790
					$this->cache_vatrates[$i]['localtax1']	    = $obj->localtax1;
4791
					$this->cache_vatrates[$i]['localtax1_type']	= $obj->localtax1_type;
4792
					$this->cache_vatrates[$i]['localtax2']	    = $obj->localtax2;
4793
					$this->cache_vatrates[$i]['localtax2_type']	= $obj->localtax1_type;
4794
4795
					$this->cache_vatrates[$i]['label']	= $obj->taux.'%'.($obj->code?' ('.$obj->code.')':'');   // Label must contains only 0-9 , . % or *
4796
					$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
4797
					$positiverates='';
4798
					if ($obj->taux) $positiverates.=($positiverates?'/':'').$obj->taux;
4799
					if ($obj->localtax1) $positiverates.=($positiverates?'/':'').$obj->localtax1;
4800
					if ($obj->localtax2) $positiverates.=($positiverates?'/':'').$obj->localtax2;
4801
					if (empty($positiverates)) $positiverates='0';
4802
					$this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code?' ('.$obj->code.')':'');	// Must never be used as key, only label
4803
				}
4804
4805
				return $num;
4806
			}
4807
			else
4808
			{
4809
				$this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry",$country_code).'</font>';
4810
				return -1;
4811
			}
4812
		}
4813
		else
4814
		{
4815
			$this->error = '<font class="error">'.$this->db->error().'</font>';
4816
			return -2;
4817
		}
4818
	}
4819
4820
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
4821
	/**
4822
	 *  Output an HTML select vat rate.
4823
	 *  The name of this function should be selectVat. We keep bad name for compatibility purpose.
4824
	 *
4825
	 *  @param	string	      $htmlname           Name of HTML select field
4826
	 *  @param  float|string  $selectedrate       Force preselected vat rate. Can be '8.5' or '8.5 (NOO)' for example. Use '' for no forcing.
4827
	 *  @param  Societe	      $societe_vendeuse   Thirdparty seller
4828
	 *  @param  Societe	      $societe_acheteuse  Thirdparty buyer
4829
	 *  @param  int		      $idprod             Id product. O if unknown of NA.
4830
	 *  @param  int		      $info_bits          Miscellaneous information on line (1 for NPR)
4831
	 *  @param  int|string    $type               ''=Unknown, 0=Product, 1=Service (Used if idprod not defined)
4832
	 *                  		                  Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle.
4833
	 *                  					      Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle.
4834
	 *                  					      Si (vendeur et acheteur dans Communaute europeenne) et bien vendu = moyen de transports neuf (auto, bateau, avion), TVA par defaut=0 (La TVA doit etre paye par l'acheteur au centre d'impots de son pays et non au vendeur). Fin de regle.
4835
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= particulier alors TVA par défaut=TVA du produit vendu. Fin de règle.
4836
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= entreprise alors TVA par défaut=0. Fin de règle.
4837
	 *                  					      Sinon la TVA proposee par defaut=0. Fin de regle.
4838
	 *  @param	bool	     $options_only		  Return HTML options lines only (for ajax treatment)
4839
	 *  @param  int          $mode                0=Use vat rate as key in combo list, 1=Add VAT code after vat rate into key, -1=Use id of vat line as key
4840
	 *  @return	string
4841
	 */
4842
	function load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse='', $societe_acheteuse='', $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0)
4843
	{
4844
        // phpcs:enable
4845
		global $langs,$conf,$mysoc;
4846
4847
		$langs->load('errors');
4848
4849
		$return='';
4850
4851
		// Define defaultnpr, defaultttx and defaultcode
4852
		$defaultnpr=($info_bits & 0x01);
4853
		$defaultnpr=(preg_match('/\*/',$selectedrate) ? 1 : $defaultnpr);
4854
		$defaulttx=str_replace('*','',$selectedrate);
4855
		$defaultcode='';
4856
		if (preg_match('/\((.*)\)/', $defaulttx, $reg))
4857
		{
4858
			$defaultcode=$reg[1];
4859
			$defaulttx=preg_replace('/\s*\(.*\)/','',$defaulttx);
4860
		}
4861
		//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
4862
4863
		// Check parameters
4864
		if (is_object($societe_vendeuse) && ! $societe_vendeuse->country_code)
4865
		{
4866
			if ($societe_vendeuse->id == $mysoc->id)
4867
			{
4868
				$return.= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</div>';
4869
			}
4870
			else
4871
			{
4872
				$return.= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</div>';
4873
			}
4874
			return $return;
4875
		}
4876
4877
		//var_dump($societe_acheteuse);
4878
		//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";
4879
		//exit;
4880
4881
		// Define list of countries to use to search VAT rates to show
4882
		// First we defined code_country to use to find list
4883
		if (is_object($societe_vendeuse))
4884
		{
4885
			$code_country="'".$societe_vendeuse->country_code."'";
4886
		}
4887
		else
4888
		{
4889
			$code_country="'".$mysoc->country_code."'";   // Pour compatibilite ascendente
4890
		}
4891
		if (! empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC))    // If option to have vat for end customer for services is on
4892
		{
4893
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
4894
			if (! isInEEC($societe_vendeuse) && (! is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && ! $societe_acheteuse->isACompany())))
4895
			{
4896
				// We also add the buyer
4897
				if (is_numeric($type))
4898
				{
4899
					if ($type == 1) // We know product is a service
4900
					{
4901
						$code_country.=",'".$societe_acheteuse->country_code."'";
4902
					}
4903
				}
4904
				else if (! $idprod)  // We don't know type of product
4905
				{
4906
					$code_country.=",'".$societe_acheteuse->country_code."'";
4907
				}
4908
				else
4909
				{
4910
					$prodstatic=new Product($this->db);
4911
					$prodstatic->fetch($idprod);
4912
					if ($prodstatic->type == Product::TYPE_SERVICE)   // We know product is a service
4913
					{
4914
						$code_country.=",'".$societe_acheteuse->country_code."'";
4915
					}
4916
				}
4917
			}
4918
		}
4919
4920
		// Now we get list
4921
		$num = $this->load_cache_vatrates($code_country);   // If no vat defined, return -1 with message into this->error
4922
4923
		if ($num > 0)
4924
		{
4925
			// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
4926
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
4927
			{
4928
				$tmpthirdparty=new Societe($this->db);
4929
				$defaulttx=get_default_tva($societe_vendeuse, (is_object($societe_acheteuse)?$societe_acheteuse:$tmpthirdparty), $idprod);
4930
				$defaultnpr=get_default_npr($societe_vendeuse, (is_object($societe_acheteuse)?$societe_acheteuse:$tmpthirdparty), $idprod);
4931
		        if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
4932
			        $defaultcode=$reg[1];
4933
			        $defaulttx=preg_replace('/\s*\(.*\)/','',$defaulttx);
4934
		        }
4935
				if (empty($defaulttx)) $defaultnpr=0;
4936
			}
4937
4938
			// Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
4939
			// Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
4940
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
4941
			{
4942
				if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) $defaulttx = $this->cache_vatrates[$num-1]['txtva'];
4943
				else $defaulttx=($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
4944
			}
4945
4946
			// Disabled if seller is not subject to VAT
4947
			$disabled=false; $title='';
4948
			if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0")
4949
			{
4950
				// Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses
4951
				if (empty($conf->global->OVERRIDE_VAT_FOR_EXPENSE_REPORT))
4952
				{
4953
					$title=' title="'.$langs->trans('VATIsNotUsed').'"';
4954
					$disabled=true;
4955
				}
4956
			}
4957
4958
			if (! $options_only) $return.= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled?' disabled':'').$title.'>';
4959
4960
			$selectedfound=false;
4961
			foreach ($this->cache_vatrates as $rate)
4962
			{
4963
				// Keep only 0 if seller is not subject to VAT
4964
				if ($disabled && $rate['txtva'] != 0) continue;
4965
4966
				// Define key to use into select list
4967
				$key = $rate['txtva'];
4968
				$key.= $rate['nprtva'] ? '*': '';
4969
				if ($mode > 0 && $rate['code']) $key.=' ('.$rate['code'].')';
4970
				if ($mode < 0) $key = $rate['rowid'];
4971
4972
				$return.= '<option value="'.$key.'"';
4973
				if (! $selectedfound)
4974
				{
4975
					if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
4976
					{
4977
						if ($defaultcode == $rate['code'])
4978
						{
4979
							$return.= ' selected';
4980
							$selectedfound=true;
4981
						}
4982
					}
4983
					elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
4984
			   		{
4985
			   			$return.= ' selected';
4986
			   			$selectedfound=true;
4987
					}
4988
				}
4989
				$return.= '>';
4990
				//if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
4991
				if ($mysoc->country_code == 'IN' || ! empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES))
4992
				{
4993
					$return.= $rate['labelpositiverates'];
4994
				}
4995
				else
4996
				{
4997
					$return.= vatrate($rate['label']);
4998
				}
4999
				//$return.=($rate['code']?' '.$rate['code']:'');
5000
				$return.= (empty($rate['code']) && $rate['nprtva']) ? ' *': '';         // We show the *  (old behaviour only if new vat code is not used)
5001
5002
				$return.= '</option>';
5003
			}
5004
5005
			if (! $options_only) $return.= '</select>';
5006
		}
5007
		else
5008
		{
5009
			$return.= $this->error;
5010
		}
5011
5012
		$this->num = $num;
5013
		return $return;
5014
	}
5015
5016
5017
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
5018
    /**
5019
     *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5020
	 *  Fields are preselected with :
5021
	 *            	- set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5022
	 *            	- local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5023
	 *            	- Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5024
	 *
5025
	 *	@param	timestamp	$set_time 		Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2).
5026
	 *	@param	string		$prefix			Prefix for fields name
5027
	 *	@param	int			$h				1 or 2=Show also hours (2=hours on a new line), -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show hour always empty
5028
	 *	@param	int			$m				1=Show also minutes, -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show minutes always empty
5029
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5030
	 *	@param	string		$form_name 		Not used
5031
	 *	@param	int			$d				1=Show days, month, years
5032
	 * 	@param	int			$addnowlink		Add a link "Now"
5033
	 * 	@param	int			$nooutput		Do not output html string but return it
5034
	 * 	@param 	int			$disabled		Disable input fields
5035
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
5036
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another select_date field.
5037
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
5038
	 *  @return	string|void					Nothing or string if nooutput is 1
5039
     *  @deprecated
5040
	 *  @see    form_date, select_month, select_year, select_dayofweek
5041
	 */
5042
    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='')
5043
    {
5044
        // phpcs:enable
5045
        $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
5046
        if (! empty($nooutput)) {
5047
            return $retstring;
5048
        }
5049
        print $retstring;
5050
        return;
5051
    }
5052
5053
    /**
5054
     *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5055
	 *  Fields are preselected with :
5056
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5057
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5058
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5059
	 *
5060
	 *  @param  timestamp   $set_time       Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2).
5061
	 *  @param	string		$prefix			Prefix for fields name
5062
	 *  @param	int			$h				1 or 2=Show also hours (2=hours on a new line), -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show hour always empty
5063
	 *	@param	int			$m				1=Show also minutes, -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show minutes always empty
5064
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5065
	 *	@param	string		$form_name 		Not used
5066
	 *	@param	int			$d				1=Show days, month, years
5067
	 * 	@param	int			$addnowlink		Add a link "Now"
5068
	 * 	@param 	int			$disabled		Disable input fields
5069
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
5070
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another selectDate field.
5071
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
5072
	 * 	@return string                      Html for selectDate
5073
	 *  @see    form_date, select_month, select_year, select_dayofweek
5074
	 */
5075
	function selectDate($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $disabled=0, $fullday='', $addplusone='', $adddateof='')
5076
	{
5077
		global $conf,$langs;
5078
5079
		$retstring='';
5080
5081
		if ($prefix=='') $prefix='re';
5082
		if ($h == '') $h=0;
5083
		if ($m == '') $m=0;
5084
		$emptydate=0;
5085
		$emptyhours=0;
5086
		if ($empty == 1) { $emptydate=1; $emptyhours=1; }
5087
		if ($empty == 2) { $emptydate=0; $emptyhours=1; }
5088
		$orig_set_time=$set_time;
5089
5090
		if ($set_time === '' && $emptydate == 0)
5091
		{
5092
			include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5093
			$set_time = dol_now('tzuser')-(getServerTimeZoneInt('now')*3600); // set_time must be relative to PHP server timezone
5094
		}
5095
5096
		// Analysis of the pre-selection date
5097
		if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/',$set_time,$reg))	// deprecated usage
5098
		{
5099
			// Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
5100
			$syear	= (! empty($reg[1])?$reg[1]:'');
5101
			$smonth	= (! empty($reg[2])?$reg[2]:'');
5102
			$sday	= (! empty($reg[3])?$reg[3]:'');
5103
			$shour	= (! empty($reg[4])?$reg[4]:'');
5104
			$smin	= (! empty($reg[5])?$reg[5]:'');
5105
		}
5106
		elseif (strval($set_time) != '' && $set_time != -1)
5107
		{
5108
			// set_time est un timestamps (0 possible)
5109
			$syear = dol_print_date($set_time, "%Y");
5110
			$smonth = dol_print_date($set_time, "%m");
5111
			$sday = dol_print_date($set_time, "%d");
5112
			if ($orig_set_time != '')
5113
			{
5114
				$shour = dol_print_date($set_time, "%H");
5115
				$smin = dol_print_date($set_time, "%M");
5116
				$ssec = dol_print_date($set_time, "%S");
5117
			}
5118
			else
5119
			{
5120
				$shour = '';
5121
				$smin = '';
5122
				$ssec = '';
5123
			}
5124
		}
5125
		else
5126
		{
5127
			// Date est '' ou vaut -1
5128
			$syear = '';
5129
			$smonth = '';
5130
			$sday = '';
5131
			$shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
5132
			$smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
5133
			$ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
5134
		}
5135
		if ($h == 3) $shour = '';
5136
		if ($m == 3) $smin = '';
5137
5138
		// You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
5139
		$usecalendar='combo';
5140
		if (! empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
5141
			$usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy')?'jquery':$conf->global->MAIN_POPUP_CALENDAR);
5142
		}
5143
5144
		if ($d)
5145
		{
5146
			// Show date with popup
5147
			if ($usecalendar != 'combo')
5148
			{
5149
				$formated_date='';
5150
				//print "e".$set_time." t ".$conf->format_date_short;
5151
				if (strval($set_time) != '' && $set_time != -1)
5152
				{
5153
					//$formated_date=dol_print_date($set_time,$conf->format_date_short);
5154
					$formated_date=dol_print_date($set_time,$langs->trans("FormatDateShortInput"));  // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5155
				}
5156
5157
				// Calendrier popup version eldy
5158
				if ($usecalendar == "eldy")
5159
				{
5160
					// Zone de saisie manuelle de la date
5161
					$retstring.='<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidth75" maxlength="11" value="'.$formated_date.'"';
5162
					$retstring.=($disabled?' disabled':'');
5163
					$retstring.=' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "';  // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5164
					$retstring.='>';
5165
5166
					// Icone calendrier
5167
					if (! $disabled)
5168
					{
5169
						$retstring.='<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
5170
						$base=DOL_URL_ROOT.'/core/';
5171
						$retstring.=' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
5172
						$retstring.='>'.img_object($langs->trans("SelectDate"),'calendarday','class="datecallink"').'</button>';
5173
					}
5174
					else $retstring.='<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"),'calendarday','class="datecallink"').'</button>';
5175
5176
					$retstring.='<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
5177
					$retstring.='<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5178
					$retstring.='<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
5179
				}
5180
				elseif ($usecalendar == 'jquery')
5181
				{
5182
					if (! $disabled)
5183
					{
5184
						// Output javascript for datepicker
5185
						$retstring.="<script type='text/javascript'>";
5186
						$retstring.="$(function(){ $('#".$prefix."').datepicker({
5187
							dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
5188
							autoclose: true,
5189
							todayHighlight: true,";
5190
							if (! empty($conf->dol_use_jmobile))
5191
							{
5192
								$retstring.="
5193
								beforeShow: function (input, datePicker) {
5194
									input.disabled = true;
5195
								},
5196
								onClose: function (dateText, datePicker) {
5197
									this.disabled = false;
5198
								},
5199
								";
5200
							}
5201
							// Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
5202
							if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS))
5203
							{
5204
							$retstring.="
5205
								showOn: 'button',
5206
								buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png',
5207
								buttonImageOnly: true";
5208
							}
5209
							$retstring.="
5210
							}) });";
5211
						$retstring.="</script>";
5212
					}
5213
5214
					// Zone de saisie manuelle de la date
5215
					$retstring.='<div class="nowrap inline-block">';
5216
					$retstring.='<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidth75" maxlength="11" value="'.$formated_date.'"';
5217
					$retstring.=($disabled?' disabled':'');
5218
					$retstring.=' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "';  // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5219
					$retstring.='>';
5220
5221
					// Icone calendrier
5222
					if (! $disabled)
5223
					{
5224
						/* Not required. Managed by option buttonImage of jquery
5225
                		$retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
5226
                		$retstring.="<script type='text/javascript'>";
5227
                		$retstring.="jQuery(document).ready(function() {";
5228
                		$retstring.='	jQuery("#'.$prefix.'id").click(function() {';
5229
                		$retstring.="    	jQuery('#".$prefix."').focus();";
5230
                		$retstring.='    });';
5231
                		$retstring.='});';
5232
                		$retstring.="</script>";*/
5233
					}
5234
					else
5235
					{
5236
						$retstring.='<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"),'calendarday','class="datecallink"').'</button>';
5237
					}
5238
5239
					$retstring.='</div>';
5240
					$retstring.='<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
5241
					$retstring.='<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5242
					$retstring.='<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
5243
				}
5244
				else
5245
				{
5246
					$retstring.="Bad value of MAIN_POPUP_CALENDAR";
5247
				}
5248
			}
5249
			// Show date with combo selects
5250
			else
5251
			{
5252
				//$retstring.='<div class="inline-block">';
5253
				// Day
5254
				$retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
5255
5256
				if ($emptydate || $set_time == -1)
5257
				{
5258
					$retstring.='<option value="0" selected>&nbsp;</option>';
5259
				}
5260
5261
				for ($day = 1 ; $day <= 31; $day++)
5262
				{
5263
					$retstring.='<option value="'.$day.'"'.($day == $sday ? ' selected':'').'>'.$day.'</option>';
5264
				}
5265
5266
				$retstring.="</select>";
5267
5268
				$retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
5269
				if ($emptydate || $set_time == -1)
5270
				{
5271
					$retstring.='<option value="0" selected>&nbsp;</option>';
5272
				}
5273
5274
				// Month
5275
				for ($month = 1 ; $month <= 12 ; $month++)
5276
				{
5277
					$retstring.='<option value="'.$month.'"'.($month == $smonth?' selected':'').'>';
5278
					$retstring.=dol_print_date(mktime(12,0,0,$month,1,2000),"%b");
5279
					$retstring.="</option>";
5280
				}
5281
				$retstring.="</select>";
5282
5283
				// Year
5284
				if ($emptydate || $set_time == -1)
5285
				{
5286
					$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.'">';
5287
				}
5288
				else
5289
				{
5290
					$retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
5291
5292
					for ($year = $syear - 10; $year < $syear + 10 ; $year++)
5293
					{
5294
						$retstring.='<option value="'.$year.'"'.($year == $syear ? ' selected':'').'>'.$year.'</option>';
5295
					}
5296
					$retstring.="</select>\n";
5297
				}
5298
				//$retstring.='</div>';
5299
			}
5300
		}
5301
5302
		if ($d && $h) $retstring.=($h==2?'<br>':' ');
5303
5304
		if ($h)
5305
		{
5306
			// Show hour
5307
			$retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth50 '.($fullday?$fullday.'hour':'').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
5308
			if ($emptyhours) $retstring.='<option value="-1">&nbsp;</option>';
5309
			for ($hour = 0; $hour < 24; $hour++)
5310
			{
5311
				if (strlen($hour) < 2) $hour = "0" . $hour;
5312
				$retstring.='<option value="'.$hour.'"'.(($hour == $shour)?' selected':'').'>'.$hour.(empty($conf->dol_optimize_smallscreen)?'':'H').'</option>';
5313
			}
5314
			$retstring.='</select>';
5315
			if ($m && empty($conf->dol_optimize_smallscreen)) $retstring.=":";
5316
		}
5317
5318
		if ($m)
5319
		{
5320
			// Show minutes
5321
			$retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth50 '.($fullday?$fullday.'min':'').'" id="'.$prefix.'min" name="'.$prefix.'min">';
5322
			if ($emptyhours) $retstring.='<option value="-1">&nbsp;</option>';
5323
			for ($min = 0; $min < 60 ; $min++)
5324
			{
5325
				if (strlen($min) < 2) $min = "0" . $min;
5326
				$retstring.='<option value="'.$min.'"'.(($min == $smin)?' selected':'').'>'.$min.(empty($conf->dol_optimize_smallscreen)?'':'').'</option>';
5327
			}
5328
			$retstring.='</select>';
5329
5330
			$retstring.='<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
5331
		}
5332
5333
		// Add a "Now" link
5334
		if ($conf->use_javascript_ajax && $addnowlink)
5335
		{
5336
			// Script which will be inserted in the onClick of the "Now" link
5337
			$reset_scripts = "";
5338
5339
			// Generate the date part, depending on the use or not of the javascript calendar
5340
			$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');';
5341
			$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');';
5342
			$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');';
5343
			$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');';
5344
			/*if ($usecalendar == "eldy")
5345
            {
5346
                $base=DOL_URL_ROOT.'/core/';
5347
                $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
5348
            }
5349
            else
5350
            {
5351
                $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
5352
                $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
5353
                $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
5354
            }*/
5355
			// Update the hour part
5356
			if ($h)
5357
			{
5358
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5359
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
5360
				$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');';
5361
				if ($fullday) $reset_scripts .= ' } ';
5362
			}
5363
			// Update the minute part
5364
			if ($m)
5365
			{
5366
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5367
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
5368
				$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');';
5369
				if ($fullday) $reset_scripts .= ' } ';
5370
			}
5371
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5372
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5373
			{
5374
				$retstring.=' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
5375
				$retstring.=$langs->trans("Now");
5376
				$retstring.='</button> ';
5377
			}
5378
		}
5379
5380
		// Add a "Plus one hour" link
5381
		if ($conf->use_javascript_ajax && $addplusone)
5382
		{
5383
			// Script which will be inserted in the onClick of the "Add plusone" link
5384
			$reset_scripts = "";
5385
5386
			// Generate the date part, depending on the use or not of the javascript calendar
5387
			$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(),'day').'\');';
5388
			$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(),'%d').'\');';
5389
			$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(),'%m').'\');';
5390
			$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(),'%Y').'\');';
5391
			// Update the hour part
5392
			if ($h)
5393
			{
5394
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5395
				$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(),'%H').'\');';
5396
				if ($fullday) $reset_scripts .= ' } ';
5397
			}
5398
			// Update the minute part
5399
			if ($m)
5400
			{
5401
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5402
				$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(),'%M').'\');';
5403
				if ($fullday) $reset_scripts .= ' } ';
5404
			}
5405
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5406
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5407
			{
5408
				$retstring.=' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
5409
				$retstring.=$langs->trans("DateStartPlusOne");
5410
				$retstring.='</button> ';
5411
			}
5412
		}
5413
5414
		// Add a "Plus one hour" link
5415
		if ($conf->use_javascript_ajax && $adddateof)
5416
		{
5417
			$tmparray=dol_getdate($adddateof);
5418
			$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>';
5419
		}
5420
5421
		return $retstring;
5422
	}
5423
5424
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
5425
	/**
5426
	 *	Function to show a form to select a duration on a page
5427
	 *
5428
	 *	@param	string	$prefix   		Prefix for input fields
5429
	 *	@param  int	$iSecond  		    Default preselected duration (number of seconds or '')
5430
	 * 	@param	int	$disabled           Disable the combo box
5431
	 * 	@param	string	$typehour		If 'select' then input hour and input min is a combo,
5432
	 *						            if 'text' input hour is in text and input min is a text,
5433
	 *						            if 'textselect' input hour is in text and input min is a combo
5434
	 *  @param	integer	$minunderhours	If 1, show minutes selection under the hours
5435
	 * 	@param	int	$nooutput		    Do not output html string but return it
5436
	 *  @return	string|void
5437
	 */
5438
	function select_duration($prefix, $iSecond='', $disabled=0, $typehour='select', $minunderhours=0, $nooutput=0)
5439
	{
5440
        // phpcs:enable
5441
		global $langs;
5442
5443
		$retstring='';
5444
5445
		$hourSelected=0; $minSelected=0;
5446
5447
		// Hours
5448
		if ($iSecond != '')
5449
		{
5450
			require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5451
5452
			$hourSelected = convertSecondToTime($iSecond,'allhour');
5453
			$minSelected = convertSecondToTime($iSecond,'min');
5454
		}
5455
5456
		if ($typehour=='select' )
5457
		{
5458
			$retstring.='<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled?' disabled':'').'>';
5459
			for ($hour = 0; $hour < 25; $hour++)	// For a duration, we allow 24 hours
5460
			{
5461
				$retstring.='<option value="'.$hour.'"';
5462
				if ($hourSelected == $hour)
5463
				{
5464
					$retstring.=" selected";
5465
				}
5466
				$retstring.=">".$hour."</option>";
5467
			}
5468
			$retstring.="</select>";
5469
		}
5470
		elseif ($typehour=='text' || $typehour=='textselect')
5471
		{
5472
			$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):'').'">';
5473
		}
5474
		else return 'BadValueForParameterTypeHour';
5475
5476
		if ($typehour!='text') $retstring.=' '.$langs->trans('HourShort');
5477
		else $retstring.='<span class="hideonsmartphone">:</span>';
5478
5479
		// Minutes
5480
		if ($minunderhours) $retstring.='<br>';
5481
		else $retstring.='<span class="hideonsmartphone">&nbsp;</span>';
5482
5483
		if ($typehour=='select' || $typehour=='textselect')
5484
		{
5485
			$retstring.='<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled?' disabled':'').'>';
5486
			for ($min = 0; $min <= 55; $min=$min+5)
5487
			{
5488
				$retstring.='<option value="'.$min.'"';
5489
				if ($minSelected == $min) $retstring.=' selected';
5490
				$retstring.='>'.$min.'</option>';
5491
			}
5492
			$retstring.="</select>";
5493
		}
5494
		elseif ($typehour=='text' )
5495
		{
5496
			$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):'').'">';
5497
		}
5498
5499
		if ($typehour!='text') $retstring.=' '.$langs->trans('MinuteShort');
5500
5501
		//$retstring.="&nbsp;";
5502
5503
		if (! empty($nooutput)) return $retstring;
5504
5505
		print $retstring;
5506
		return;
5507
	}
5508
5509
5510
	/**
5511
	 * Generic method to select a component from a combo list.
5512
	 * This is the generic method that will replace all specific existing methods.
5513
	 *
5514
	 * @param 	string			$objectdesc			Objectclassname:Objectclasspath
5515
	 * @param	string			$htmlname			Name of HTML select component
5516
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
5517
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
5518
	 * @param	string			$searchkey			Search criteria
5519
	 * @param	string			$placeholder		Place holder
5520
	 * @param	string			$morecss			More CSS
5521
	 * @param	string			$moreparams			More params provided to ajax call
5522
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
5523
	 * @return	string								Return HTML string
5524
	 * @see selectForFormsList select_thirdparty
5525
	 */
5526
	function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0)
5527
	{
5528
		global $conf, $user;
5529
5530
		$objecttmp = null;
5531
5532
		$InfoFieldList = explode(":", $objectdesc);
5533
		$classname=$InfoFieldList[0];
5534
		$classpath=$InfoFieldList[1];
5535
		if (! empty($classpath))
5536
		{
5537
			dol_include_once($classpath);
5538
			if ($classname && class_exists($classname))
5539
			{
5540
				$objecttmp = new $classname($this->db);
5541
			}
5542
		}
5543
		if (! is_object($objecttmp))
5544
		{
5545
			dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
5546
			return 'Error bad setup of type for field '.join(',', $InfoFieldList);
5547
		}
5548
5549
		$prefixforautocompletemode=$objecttmp->element;
5550
		if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode='company';
5551
		$confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT';	// For example COMPANY_USE_SEARCH_TO_SELECT
5552
5553
		dol_syslog(get_class($this)."::selectForForms", LOG_DEBUG);
5554
5555
		$out='';
5556
		if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->$confkeyforautocompletemode) && ! $forcecombo)
5557
		{
5558
			$objectdesc=$classname.':'.$classpath;
5559
			$urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
5560
			//if ($objecttmp->element == 'societe') $urlforajaxcall = DOL_URL_ROOT.'/societe/ajax/company.php';
5561
5562
			// No immediate load of all database
5563
			$urloption='htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.($moreparams?$moreparams:'');
5564
			// Activate the auto complete using ajax call.
5565
			$out.=  ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
5566
			$out.= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
5567
			if ($placeholder) $placeholder=' placeholder="'.$placeholder.'"';
5568
			$out.= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$preselectedvalue.'"'.$placeholder.' />';
5569
		}
5570
		else
5571
		{
5572
			// Immediate load of all database
5573
			$out.=$this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo);
5574
		}
5575
5576
		return $out;
5577
	}
5578
5579
	/**
5580
	 * Output html form to select an object.
5581
	 * Note, this function is called by selectForForms or by ajax selectobject.php
5582
	 *
5583
	 * @param 	Object			$objecttmp			Object
5584
	 * @param	string			$htmlname			Name of HTML select component
5585
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
5586
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
5587
	 * @param	string			$searchkey			Search value
5588
	 * @param	string			$placeholder		Place holder
5589
	 * @param	string			$morecss			More CSS
5590
	 * @param	string			$moreparams			More params provided to ajax call
5591
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
5592
	 * @param	int				$outputmode			0=HTML select string, 1=Array
5593
	 * @return	string								Return HTML string
5594
	 * @see selectForForms
5595
	 */
5596
	function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty='', $searchkey='', $placeholder='', $morecss='', $moreparams='', $forcecombo=0, $outputmode=0)
5597
	{
5598
		global $conf, $langs, $user;
5599
5600
		$prefixforautocompletemode=$objecttmp->element;
5601
		if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode='company';
5602
		$confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT';	// For example COMPANY_USE_SEARCH_TO_SELECT
5603
5604
		$fieldstoshow='t.ref';
5605
		if (! empty($objecttmp->fields))	// For object that declare it, it is better to use declared fields ( like societe, contact, ...)
5606
		{
5607
			$tmpfieldstoshow='';
5608
			foreach($objecttmp->fields as $key => $val)
5609
			{
5610
				if ($val['showoncombobox']) $tmpfieldstoshow.=($tmpfieldstoshow?',':'').'t.'.$key;
5611
			}
5612
			if ($tmpfieldstoshow) $fieldstoshow = $tmpfieldstoshow;
5613
		}
5614
5615
		$out='';
5616
		$outarray=array();
5617
5618
		$num=0;
5619
5620
		// Search data
5621
		$sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX .$objecttmp->table_element." as t";
5622
		if ($objecttmp->ismultientitymanaged == 2)
5623
			if (!$user->rights->societe->client->voir && !$user->societe_id) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
5624
		$sql.= " WHERE 1=1";
5625
		if(! empty($objecttmp->ismultientitymanaged)) $sql.= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
5626
		if ($objecttmp->ismultientitymanaged == 1 && ! empty($user->societe_id))
5627
		{
5628
			if ($objecttmp->element == 'societe') $sql.= " AND t.rowid = ".$user->societe_id;
5629
				else $sql.= " AND t.fk_soc = ".$user->societe_id;
5630
		}
5631
		if ($searchkey != '') $sql.=natural_search(explode(',',$fieldstoshow), $searchkey);
5632
		if ($objecttmp->ismultientitymanaged == 2)
5633
			if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND t.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
5634
		$sql.=$this->db->order($fieldstoshow,"ASC");
5635
		//$sql.=$this->db->plimit($limit, 0);
5636
5637
		// Build output string
5638
		$resql=$this->db->query($sql);
5639
		if ($resql)
5640
		{
5641
			if (! $forcecombo)
5642
			{
5643
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5644
				$out .= ajax_combobox($htmlname, null, $conf->global->$confkeyforautocompletemode);
5645
			}
5646
5647
			// Construct $out and $outarray
5648
			$out.= '<select id="'.$htmlname.'" class="flat'.($morecss?' '.$morecss:'').'"'.($moreparams?' '.$moreparams:'').' name="'.$htmlname.'">'."\n";
5649
5650
			// 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
5651
			$textifempty='&nbsp;';
5652
5653
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
5654
			if (! empty($conf->global->$confkeyforautocompletemode))
5655
			{
5656
				if ($showempty && ! is_numeric($showempty)) $textifempty=$langs->trans($showempty);
5657
				else $textifempty.=$langs->trans("All");
5658
			}
5659
			if ($showempty) $out.= '<option value="-1">'.$textifempty.'</option>'."\n";
5660
5661
			$num = $this->db->num_rows($resql);
5662
			$i = 0;
5663
			if ($num)
5664
			{
5665
				while ($i < $num)
5666
				{
5667
					$obj = $this->db->fetch_object($resql);
5668
					$label='';
5669
					$tmparray=explode(',', $fieldstoshow);
5670
					foreach($tmparray as $key => $val)
5671
					{
5672
						$val = preg_replace('/t\./','',$val);
5673
						$label .= (($label && $obj->$val)?' - ':'').$obj->$val;
5674
					}
5675
					if (empty($outputmode))
5676
					{
5677
						if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid)
5678
						{
5679
							$out.= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
5680
						}
5681
						else
5682
						{
5683
							$out.= '<option value="'.$obj->rowid.'">'.$label.'</option>';
5684
						}
5685
					}
5686
					else
5687
					{
5688
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
5689
					}
5690
5691
					$i++;
5692
					if (($i % 10) == 0) $out.="\n";
5693
				}
5694
			}
5695
5696
			$out.= '</select>'."\n";
5697
		}
5698
		else
5699
		{
5700
			dol_print_error($this->db);
5701
		}
5702
5703
		$this->result=array('nbofelement'=>$num);
5704
5705
		if ($outputmode) return $outarray;
5706
		return $out;
5707
	}
5708
5709
5710
	/**
5711
	 *	Return a HTML select string, built from an array of key+value.
5712
	 *  Note: Do not apply langs->trans function on returned content, content may be entity encoded twice.
5713
	 *
5714
	 *	@param	string			$htmlname			Name of html select area. Must start with "multi" if this is a multiselect
5715
	 *	@param	array			$array				Array (key => value)
5716
	 *	@param	string|string[]	$id					Preselected key or preselected keys for multiselect
5717
	 *	@param	int|string		$show_empty			0 no empty value allowed, 1 or string to add an empty value into list (key is -1 and value is '' or '&nbsp;' if 1, key is -1 and value is text if string), <0 to add an empty value with key that is this value.
5718
	 *	@param	int				$key_in_label		1 to show key into label with format "[key] value"
5719
	 *	@param	int				$value_as_key		1 to use value as key
5720
	 *	@param  string			$moreparam			Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
5721
	 *	@param  int				$translate			1=Translate and encode value
5722
	 * 	@param	int				$maxlen				Length maximum for labels
5723
	 * 	@param	int				$disabled			Html select box is disabled
5724
	 *  @param	string			$sort				'ASC' or 'DESC' = Sort on label, '' or 'NONE' or 'POS' = Do not sort, we keep original order
5725
	 *  @param	string			$morecss			Add more class to css styles
5726
	 *  @param	int				$addjscombo			Add js combo
5727
	 *  @param  string          $moreparamonempty	Add more param on the empty option line. Not used if show_empty not set
5728
	 *  @param  int             $disablebademail	Check if an email is found into value and if not disable and colorize entry
5729
	 *  @param  int             $nohtmlescape		No html escaping.
5730
	 * 	@return	string								HTML select string.
5731
	 *  @see multiselectarray
5732
	 */
5733
	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)
5734
	{
5735
		global $conf, $langs;
5736
5737
		// Do we want a multiselect ?
5738
		//$jsbeautify = 0;
5739
		//if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
5740
		$jsbeautify = 1;
5741
5742
		if ($value_as_key) $array=array_combine($array, $array);
5743
5744
		$out='';
5745
5746
		// Add code for jquery to use multiselect
5747
		if ($addjscombo && $jsbeautify)
5748
		{
5749
			$minLengthToAutocomplete=0;
5750
			$tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?(constant('REQUIRE_JQUERY_MULTISELECT')?constant('REQUIRE_JQUERY_MULTISELECT'):'select2'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
5751
5752
			// Enhance with select2
5753
			include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
5754
			$out .= ajax_combobox($htmlname);
5755
		}
5756
5757
		$out.='<select id="'.preg_replace('/^\./','',$htmlname).'" '.($disabled?'disabled ':'').'class="flat '.(preg_replace('/^\./','',$htmlname)).($morecss?' '.$morecss:'').'"';
5758
		$out.=' name="'.preg_replace('/^\./','',$htmlname).'" '.($moreparam?$moreparam:'');
5759
		$out.='>';
5760
5761
		if ($show_empty)
5762
		{
5763
			$textforempty=' ';
5764
			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.
5765
			if (! is_numeric($show_empty)) $textforempty=$show_empty;
5766
			$out.='<option class="optiongrey" '.($moreparamonempty?$moreparamonempty.' ':'').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ?' selected':'').'>'.$textforempty.'</option>'."\n";
5767
		}
5768
5769
		if (is_array($array))
5770
		{
5771
			// Translate
5772
			if ($translate)
5773
			{
5774
				foreach($array as $key => $value)
5775
				{
5776
					$array[$key]=$langs->trans($value);
5777
				}
5778
			}
5779
5780
			// Sort
5781
			if ($sort == 'ASC') asort($array);
5782
			elseif ($sort == 'DESC') arsort($array);
5783
5784
			foreach($array as $key => $value)
5785
			{
5786
				$disabled=''; $style='';
5787
				if (! empty($disablebademail))
5788
				{
5789
					if (! preg_match('/&lt;.+@.+&gt;/', $value))
5790
					{
5791
						//$value=preg_replace('/'.preg_quote($a,'/').'/', $b, $value);
5792
						$disabled=' disabled';
5793
						$style=' class="warning"';
5794
					}
5795
				}
5796
5797
				if ($key_in_label)
5798
				{
5799
					if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen?dol_trunc($value,$maxlen):$value));
5800
					else $selectOptionValue = $key.' - '.($maxlen?dol_trunc($value,$maxlen):$value);
5801
				}
5802
				else
5803
				{
5804
					if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($maxlen?dol_trunc($value,$maxlen):$value);
5805
					else $selectOptionValue = $maxlen?dol_trunc($value,$maxlen):$value;
5806
					if ($value == '' || $value == '-') $selectOptionValue='&nbsp;';
5807
				}
5808
5809
				$out.='<option value="'.$key.'"';
5810
				$out.=$style.$disabled;
5811
				if ($id != '' && $id == $key && ! $disabled) $out.=' selected';		// To preselect a value
5812
				if ($nohtmlescape) $out.=' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
5813
				$out.='>';
5814
				//var_dump($selectOptionValue);
5815
				$out.=$selectOptionValue;
5816
				$out.="</option>\n";
5817
			}
5818
		}
5819
5820
		$out.="</select>";
5821
		return $out;
5822
	}
5823
5824
5825
	/**
5826
	 *	Return a HTML select string, built from an array of key+value, but content returned into select come from an Ajax call of an URL.
5827
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
5828
	 *
5829
	 *	@param	string	$htmlname       		Name of html select area
5830
	 *	@param	string	$url					Url. Must return a json_encode of array(key=>array('text'=>'A text', 'url'=>'An url'), ...)
5831
	 *	@param	string	$id             		Preselected key
5832
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
5833
	 *	@param  string	$moreparamtourl 		Add more parameters onto the Ajax called URL
5834
	 * 	@param	int		$disabled				Html select box is disabled
5835
	 *  @param	int		$minimumInputLength		Minimum Input Length
5836
	 *  @param	string	$morecss				Add more class to css styles
5837
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
5838
	 *  @param  string  $placeholder            String to use as placeholder
5839
	 *  @param  integer $acceptdelayedhtml      1 = caller is requesting to have html js content not returned but saved into global $delayedhtmlcontent (so caller can show it at end of page to avoid flash FOUC effect)
5840
	 * 	@return	string   						HTML select string
5841
	 *  @see selectArrayFilter, ajax_combobox in ajax.lib.php
5842
	 */
5843
	static function selectArrayAjax($htmlname, $url, $id='', $moreparam='', $moreparamtourl='', $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0)
5844
	{
5845
		global $conf, $langs;
5846
		global $delayedhtmlcontent;
5847
5848
		// TODO Use an internal dolibarr component instead of select2
5849
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && ! defined('REQUIRE_JQUERY_MULTISELECT')) return '';
5850
5851
		$out='<select type="text" class="'.$htmlname.($morecss?' '.$morecss:'').'" '.($moreparam?$moreparam.' ':'').'name="'.$htmlname.'"></select>';
5852
5853
		$tmpplugin='select2';
5854
		$outdelayed="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
5855
	    	<script type="text/javascript">
5856
	    	$(document).ready(function () {
5857
5858
    	        '.($callurlonselect ? 'var saveRemoteData = [];':'').'
5859
5860
                $(".'.$htmlname.'").select2({
5861
			    	ajax: {
5862
				    	dir: "ltr",
5863
				    	url: "'.$url.'",
5864
				    	dataType: \'json\',
5865
				    	delay: 250,
5866
				    	data: function (params) {
5867
				    		return {
5868
						    	q: params.term, 	// search term
5869
				    			page: params.page
5870
				    		};
5871
			    		},
5872
			    		processResults: function (data) {
5873
			    			// parse the results into the format expected by Select2.
5874
			    			// since we are using custom formatting functions we do not need to alter the remote JSON data
5875
			    			//console.log(data);
5876
							saveRemoteData = data;
5877
				    	    /* format json result for select2 */
5878
				    	    result = []
5879
				    	    $.each( data, function( key, value ) {
5880
				    	       result.push({id: key, text: value.text});
5881
                            });
5882
			    			//return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
5883
			    			//console.log(result);
5884
			    			return {results: result, more: false}
5885
			    		},
5886
			    		cache: true
5887
			    	},
5888
	 				language: select2arrayoflanguage,
5889
					containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
5890
				    placeholder: "'.dol_escape_js($placeholder).'",
5891
			    	escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
5892
			    	minimumInputLength: '.$minimumInputLength.',
5893
			        formatResult: function(result, container, query, escapeMarkup) {
5894
                        return escapeMarkup(result.text);
5895
                    },
5896
			    });
5897
5898
                '.($callurlonselect ? '
5899
                /* Code to execute a GET when we select a value */
5900
                $(".'.$htmlname.'").change(function() {
5901
			    	var selected = $(".'.$htmlname.'").val();
5902
                	console.log("We select in selectArrayAjax the entry "+selected)
5903
			        $(".'.$htmlname.'").val("");  /* reset visible combo value */
5904
    			    $.each( saveRemoteData, function( key, value ) {
5905
    				        if (key == selected)
5906
    			            {
5907
    			                 console.log("selectArrayAjax - Do a redirect to "+value.url)
5908
    			                 location.assign(value.url);
5909
    			            }
5910
                    });
5911
    			});' : '' ) . '
5912
5913
    	   });
5914
	       </script>';
5915
5916
		if ($acceptdelayedhtml)
5917
		{
5918
			$delayedhtmlcontent.=$outdelayed;
5919
		}
5920
		else
5921
		{
5922
			$out.=$outdelayed;
5923
		}
5924
		return $out;
5925
	}
5926
5927
	/**
5928
	 *	Return a HTML select string, built from an array of key+value, but content returned into select is defined into $array parameter.
5929
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
5930
	 *
5931
	 *	@param	string	$htmlname       		Name of html select area
5932
	 *	@param	string	$array					Array (key=>array('text'=>'A text', 'url'=>'An url'), ...)
5933
	 *	@param	string	$id             		Preselected key
5934
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
5935
	 *	@param	int		$disableFiltering		If set to 1, results are not filtered with searched string
5936
	 * 	@param	int		$disabled				Html select box is disabled
5937
	 *  @param	int		$minimumInputLength		Minimum Input Length
5938
	 *  @param	string	$morecss				Add more class to css styles
5939
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
5940
	 *  @param  string  $placeholder            String to use as placeholder
5941
	 *  @param  integer $acceptdelayedhtml      1 = caller is requesting to have html js content not returned but saved into global $delayedhtmlcontent (so caller can show it at end of page to avoid flash FOUC effect)
5942
	 * 	@return	string   						HTML select string
5943
	 *  @see selectArrayAjax, ajax_combobox in ajax.lib.php
5944
	 */
5945
	static function selectArrayFilter($htmlname, $array, $id='', $moreparam='', $disableFiltering=0, $disabled=0, $minimumInputLength=1, $morecss='', $callurlonselect=0, $placeholder='', $acceptdelayedhtml=0)
5946
	{
5947
		global $conf, $langs;
5948
		global $delayedhtmlcontent;
5949
5950
		// TODO Use an internal dolibarr component instead of select2
5951
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && ! defined('REQUIRE_JQUERY_MULTISELECT')) return '';
5952
5953
		$out='<select type="text" class="'.$htmlname.($morecss?' '.$morecss:'').'" '.($moreparam?$moreparam.' ':'').'name="'.$htmlname.'"><option></option></select>';
5954
5955
		$formattedarrayresult = array();
5956
5957
		foreach($array as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $array of type string is not traversable.
Loading history...
5958
			$o = new stdClass();
5959
			$o->id = $key;
5960
			$o->text = $value['text'];
5961
			$o->url = $value['url'];
5962
			$formattedarrayresult[] = $o;
5963
		}
5964
5965
		$tmpplugin='select2';
5966
		$outdelayed="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
5967
			<script type="text/javascript">
5968
			$(document).ready(function () {
5969
				var data = '.json_encode($formattedarrayresult).';
5970
5971
				'.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';':'').'
5972
5973
				$(".'.$htmlname.'").select2({
5974
					data: data,
5975
					language: select2arrayoflanguage,
5976
					containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
5977
					placeholder: "'.dol_escape_js($placeholder).'",
5978
					escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
5979
					minimumInputLength: '.$minimumInputLength.',
5980
					formatResult: function(result, container, query, escapeMarkup) {
5981
						return escapeMarkup(result.text);
5982
					},
5983
					matcher: function (params, data) {
5984
5985
						if(! data.id) return null;';
5986
5987
		if($callurlonselect) {
5988
			$outdelayed.='
5989
5990
						var urlBase = data.url;
5991
						var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
5992
						/* console.log("params.term="+params.term); */
5993
						/* console.log("params.term encoded="+encodeURIComponent(params.term)); */
5994
						saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term);';
5995
		}
5996
5997
		if(! $disableFiltering) {
5998
			$outdelayed.='
5999
6000
						if(data.text.match(new RegExp(params.term))) {
6001
							return data;
6002
						}
6003
6004
						return null;';
6005
		} else {
6006
			$outdelayed.='
6007
6008
						return data;';
6009
		}
6010
6011
		$outdelayed.='
6012
					}
6013
				});
6014
6015
				'.($callurlonselect ? '
6016
				/* Code to execute a GET when we select a value */
6017
				$(".'.$htmlname.'").change(function() {
6018
					var selected = $(".'.$htmlname.'").val();
6019
					console.log("We select "+selected)
6020
6021
					$(".'.$htmlname.'").val("");  /* reset visible combo value */
6022
					$.each( saveRemoteData, function( key, value ) {
6023
						if (key == selected)
6024
						{
6025
							console.log("selectArrayAjax - Do a redirect to "+value.url)
6026
							location.assign(value.url);
6027
						}
6028
					});
6029
				});' : '' ) . '
6030
6031
			});
6032
			</script>';
6033
6034
		if ($acceptdelayedhtml)
6035
		{
6036
			$delayedhtmlcontent.=$outdelayed;
6037
		}
6038
		else
6039
		{
6040
			$out.=$outdelayed;
6041
		}
6042
		return $out;
6043
	}
6044
6045
	/**
6046
	 *	Show a multiselect form from an array.
6047
	 *
6048
	 *	@param	string	$htmlname		Name of select
6049
	 *	@param	array	$array			Array with key+value
6050
	 *	@param	array	$selected		Array with key+value preselected
6051
	 *	@param	int		$key_in_label   1 pour afficher la key dans la valeur "[key] value"
6052
	 *	@param	int		$value_as_key   1 to use value as key
6053
	 *	@param  string	$morecss        Add more css style
6054
	 *	@param  int		$translate		Translate and encode value
6055
	 *  @param	int		$width			Force width of select box. May be used only when using jquery couch. Example: 250, 95%
6056
	 *  @param	string	$moreattrib		Add more options on select component. Example: 'disabled'
6057
	 *  @param	string	$elemtype		Type of element we show ('category', ...)
6058
	 *  @param	string	$placeholder	String to use as placeholder
6059
	 *  @param	int		$addjscombo		Add js combo
6060
	 *	@return	string					HTML multiselect string
6061
	 *  @see selectarray
6062
	 */
6063
	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)
6064
	{
6065
		global $conf, $langs;
6066
6067
		$out = '';
6068
6069
6070
		// Add code for jquery to use multiselect
6071
		if (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))
6072
		{
6073
			$out.="\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmpplugin seems to be never defined.
Loading history...
6074
						<script type="text/javascript">'."\n";
6075
			if ($addjscombo == 1)
6076
			{
6077
				$tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
6078
				$out.=	'function formatResult(record) {'."\n";
6079
				if ($elemtype == 'category')
6080
				{
6081
					$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>\';
6082
									  	return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> \'+record.text+\'</span>\';';
6083
				}
6084
				else
6085
				{
6086
					$out.='return record.text;';
6087
				}
6088
				$out.=	'};'."\n";
6089
				$out.=	'function formatSelection(record) {'."\n";
6090
				if ($elemtype == 'category')
6091
				{
6092
					$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>\';
6093
									  	return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> \'+record.text+\'</span>\';';
6094
				}
6095
				else
6096
				{
6097
					$out.='return record.text;';
6098
				}
6099
				$out.=	'};'."\n";
6100
				$out.=	'$(document).ready(function () {
6101
							$(\'#'.$htmlname.'\').'.$tmpplugin.'({
6102
								dir: \'ltr\',
6103
								// Specify format function for dropdown item
6104
								formatResult: formatResult,
6105
							 	templateResult: formatResult,		/* For 4.0 */
6106
								// Specify format function for selected item
6107
								formatSelection: formatSelection,
6108
							 	templateResult: formatSelection		/* For 4.0 */
6109
							});
6110
						});'."\n";
6111
			}
6112
			elseif ($addjscombo == 2)
6113
			{
6114
				// Add other js lib
6115
				// ...
6116
				$out.= '$(document).ready(function () {
6117
							$(\'#'.$htmlname.'\').multiSelect({
6118
								containerHTML: \'<div class="multi-select-container">\',
6119
								menuHTML: \'<div class="multi-select-menu">\',
6120
								buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
6121
								menuItemHTML: \'<label class="multi-select-menuitem">\',
6122
								activeClass: \'multi-select-container--open\',
6123
								noneText: \''.$placeholder.'\'
6124
							});
6125
						})';
6126
			}
6127
			$out.=	'</script>';
6128
		}
6129
6130
		// Try also magic suggest
6131
6132
		$out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss?' '.$morecss:'').'" multiple name="'.$htmlname.'[]"'.($moreattrib?' '.$moreattrib:'').($width?' style="width: '.(preg_match('/%/',$width)?$width:$width.'px').'"':'').'>'."\n";
6133
		if (is_array($array) && ! empty($array))
6134
		{
6135
			if ($value_as_key) $array=array_combine($array, $array);
6136
6137
			if (! empty($array))
6138
			{
6139
				foreach ($array as $key => $value)
6140
				{
6141
					$out.= '<option value="'.$key.'"';
6142
					if (is_array($selected) && ! empty($selected) && in_array($key, $selected) && !empty($key))
6143
					{
6144
						$out.= ' selected';
6145
					}
6146
					$out.= '>';
6147
6148
					$newval = ($translate ? $langs->trans($value) : $value);
6149
					$newval = ($key_in_label ? $key.' - '.$newval : $newval);
6150
					$out.= dol_htmlentitiesbr($newval);
6151
					$out.= '</option>'."\n";
6152
				}
6153
			}
6154
		}
6155
		$out.= '</select>'."\n";
6156
6157
		return $out;
6158
	}
6159
6160
6161
	/**
6162
	 *	Show a multiselect dropbox from an array.
6163
	 *
6164
	 *	@param	string	$htmlname		Name of HTML field
6165
	 *	@param	array	$array			Array with array of fields we could show. This array may be modified according to setup of user.
6166
	 *  @param  string  $varpage        Id of context for page. Can be set by caller with $varpage=(empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage);
6167
	 *	@return	string					HTML multiselect string
6168
	 *  @see selectarray
6169
	 */
6170
	static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
6171
	{
6172
		global $conf,$langs,$user;
6173
6174
		if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) return '';
6175
6176
		$tmpvar="MAIN_SELECTEDFIELDS_".$varpage;
6177
		if (! empty($user->conf->$tmpvar))
6178
		{
6179
			$tmparray=explode(',', $user->conf->$tmpvar);
6180
			foreach($array as $key => $val)
6181
			{
6182
				//var_dump($key);
6183
				//var_dump($tmparray);
6184
				if (in_array($key, $tmparray)) $array[$key]['checked']=1;
6185
				else $array[$key]['checked']=0;
6186
			}
6187
		}
6188
		//var_dump($array);
6189
6190
		$lis='';
6191
		$listcheckedstring='';
6192
6193
		foreach($array as $key => $val)
6194
		{
6195
		   /* var_dump($val);
6196
            var_dump(array_key_exists('enabled', $val));
6197
            var_dump(!$val['enabled']);*/
6198
		   if (array_key_exists('enabled', $val) && isset($val['enabled']) && ! $val['enabled'])
6199
		   {
6200
			   unset($array[$key]);     // We don't want this field
6201
			   continue;
6202
		   }
6203
		   if ($val['label'])
6204
		   {
6205
		   	$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>';
6206
			   $listcheckedstring.=(empty($val['checked'])?'':$key.',');
6207
		   }
6208
		}
6209
6210
		$out ='<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
6211
6212
        <dl class="dropdown">
6213
            <dt>
6214
            <a href="#">
6215
              '.img_picto('','list').'
6216
            </a>
6217
            <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
6218
            </dt>
6219
            <dd class="dropdowndd">
6220
                <div class="multiselectcheckbox'.$htmlname.'">
6221
                    <ul class="ul'.$htmlname.'">
6222
                    '.$lis.'
6223
                    </ul>
6224
                </div>
6225
            </dd>
6226
        </dl>
6227
6228
        <script type="text/javascript">
6229
          jQuery(document).ready(function () {
6230
              $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
6231
                  console.log("A new field was added/removed")
6232
                  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\')
6233
                  var title = $(this).val() + ",";
6234
                  if ($(this).is(\':checked\')) {
6235
                      $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
6236
                  }
6237
                  else {
6238
                      $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
6239
                  }
6240
                  // Now, we submit page
6241
                  $(this).parents(\'form:first\').submit();
6242
              });
6243
           });
6244
        </script>
6245
6246
        ';
6247
		return $out;
6248
	}
6249
6250
	/**
6251
	 * 	Render list of categories linked to object with id $id and type $type
6252
	 *
6253
	 * 	@param		int		$id				Id of object
6254
	 * 	@param		string	$type			Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
6255
	 *  @param		int		$rendermode		0=Default, use multiselect. 1=Emulate multiselect (recommended)
6256
	 * 	@return		string					String with categories
6257
	 */
6258
	function showCategories($id, $type, $rendermode=0)
6259
	{
6260
		global $db;
6261
6262
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
6263
6264
		$cat = new Categorie($db);
6265
		$categories = $cat->containing($id, $type);
6266
6267
		if ($rendermode == 1)
6268
		{
6269
			$toprint = array();
6270
			foreach($categories as $c)
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
6271
			{
6272
				$ways = $c->print_all_ways();       // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
6273
				foreach($ways as $way)
6274
				{
6275
					$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color?' style="background: #'.$c->color.';"':' style="background: #aaa"').'>'.img_object('','category').' '.$way.'</li>';
6276
				}
6277
			}
6278
			return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6279
		}
6280
6281
		if ($rendermode == 0)
6282
		{
6283
			$cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
6284
			foreach($categories as $c) {
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
6285
				$arrayselected[] = $c->id;
6286
			}
6287
6288
			return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arrayselected seems to be defined by a foreach iteration on line 6284. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
6289
		}
6290
6291
		return 'ErrorBadValueForParameterRenderMode';	// Should not happened
6292
	}
6293
6294
6295
	/**
6296
	 *  Show linked object block.
6297
	 *
6298
	 *  @param	CommonObject	$object		      Object we want to show links to
6299
	 *  @param  string          $morehtmlright    More html to show on right of title
6300
	 *  @param  array           $compatibleImportElementsList  Array of compatibles elements object for "import from" action
6301
	 *  @return	int							      <0 if KO, >=0 if OK
6302
	 */
6303
	function showLinkedObjectBlock($object, $morehtmlright='',$compatibleImportElementsList=false)
6304
	{
6305
		global $conf,$langs,$hookmanager;
6306
		global $bc;
6307
6308
		$object->fetchObjectLinked();
6309
6310
		// Bypass the default method
6311
		$hookmanager->initHooks(array('commonobject'));
6312
		$parameters=array(
6313
			'morehtmlright' => $morehtmlright,
6314
		    'compatibleImportElementsList' =>& $compatibleImportElementsList,
6315
		);
6316
		$reshook=$hookmanager->executeHooks('showLinkedObjectBlock',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $action seems to be never defined.
Loading history...
6317
6318
		if (empty($reshook))
6319
		{
6320
			$nbofdifferenttypes = count($object->linkedObjects);
6321
6322
			print '<!-- showLinkedObjectBlock -->';
6323
			print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
6324
6325
6326
			print '<div class="div-table-responsive-no-min">';
6327
			print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'"  data-elementid="'.$object->id.'"   >';
6328
6329
			print '<tr class="liste_titre">';
6330
			print '<td>'.$langs->trans("Type").'</td>';
6331
			print '<td>'.$langs->trans("Ref").'</td>';
6332
			print '<td align="center"></td>';
6333
			print '<td align="center">'.$langs->trans("Date").'</td>';
6334
			print '<td align="right">'.$langs->trans("AmountHTShort").'</td>';
6335
			print '<td align="right">'.$langs->trans("Status").'</td>';
6336
			print '<td></td>';
6337
			print '</tr>';
6338
6339
			$nboftypesoutput=0;
6340
6341
			foreach($object->linkedObjects as $objecttype => $objects)
6342
			{
6343
				$tplpath = $element = $subelement = $objecttype;
6344
6345
				// to display inport button on tpl
6346
				$showImportButton=false;
6347
				if(!empty($compatibleImportElementsList) && in_array($element,$compatibleImportElementsList)){
6348
				    $showImportButton=true;
6349
				}
6350
6351
				if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i',$objecttype,$regs))
6352
				{
6353
					$element = $regs[1];
6354
					$subelement = $regs[2];
6355
					$tplpath = $element.'/'.$subelement;
6356
				}
6357
				$tplname='linkedobjectblock';
6358
6359
				// To work with non standard path
6360
				if ($objecttype == 'facture')          {
6361
					$tplpath = 'compta/'.$element;
6362
					if (empty($conf->facture->enabled)) continue;	// Do not show if module disabled
6363
				}
6364
				else if ($objecttype == 'facturerec')          {
6365
					$tplpath = 'compta/facture';
6366
					$tplname = 'linkedobjectblockForRec';
6367
					if (empty($conf->facture->enabled)) continue;	// Do not show if module disabled
6368
				}
6369
				else if ($objecttype == 'propal')           {
6370
					$tplpath = 'comm/'.$element;
6371
					if (empty($conf->propal->enabled)) continue;	// Do not show if module disabled
6372
				}
6373
				else if ($objecttype == 'supplier_proposal')           {
6374
					if (empty($conf->supplier_proposal->enabled)) continue;	// Do not show if module disabled
6375
				}
6376
				else if ($objecttype == 'shipping' || $objecttype == 'shipment') {
6377
					$tplpath = 'expedition';
6378
					if (empty($conf->expedition->enabled)) continue;	// Do not show if module disabled
6379
				}
6380
        		else if ($objecttype == 'reception') {
6381
        			$tplpath = 'reception';
6382
        			if (empty($conf->reception->enabled)) continue;	// Do not show if module disabled
6383
        		}
6384
				else if ($objecttype == 'delivery')         {
6385
					$tplpath = 'livraison';
6386
					if (empty($conf->expedition->enabled)) continue;	// Do not show if module disabled
6387
				}
6388
				else if ($objecttype == 'invoice_supplier') {
6389
					$tplpath = 'fourn/facture';
6390
				}
6391
				else if ($objecttype == 'order_supplier')   {
6392
					$tplpath = 'fourn/commande';
6393
				}
6394
				else if ($objecttype == 'expensereport')   {
6395
					$tplpath = 'expensereport';
6396
				}
6397
				else if ($objecttype == 'subscription')   {
6398
					$tplpath = 'adherents';
6399
				}
6400
6401
				global $linkedObjectBlock;
6402
				$linkedObjectBlock = $objects;
6403
6404
6405
				// Output template part (modules that overwrite templates must declare this into descriptor)
6406
				$dirtpls=array_merge($conf->modules_parts['tpl'],array('/'.$tplpath.'/tpl'));
6407
				foreach($dirtpls as $reldir)
6408
				{
6409
					if ($nboftypesoutput == ($nbofdifferenttypes - 1))    // No more type to show after
6410
					{
6411
						global $noMoreLinkedObjectBlockAfter;
6412
						$noMoreLinkedObjectBlockAfter=1;
6413
					}
6414
6415
					$res=@include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
6416
					if ($res)
6417
					{
6418
						$nboftypesoutput++;
6419
						break;
6420
					}
6421
				}
6422
			}
6423
6424
			if (! $nboftypesoutput)
6425
			{
6426
				print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>';
6427
			}
6428
6429
			print '</table>';
6430
6431
			if(!empty($compatibleImportElementsList))
6432
			{
6433
			    $res=@include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
6434
			}
6435
6436
6437
			print '</div>';
6438
6439
			return $nbofdifferenttypes;
6440
		}
6441
	}
6442
6443
	/**
6444
	 *  Show block with links to link to other objects.
6445
	 *
6446
	 *  @param	CommonObject	$object				Object we want to show links to
6447
	 *  @param	array			$restrictlinksto	Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction.
6448
	 *  @param	array			$excludelinksto		Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion.
6449
	 *  @return	string								<0 if KO, >0 if OK
6450
	 */
6451
	function showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array())
6452
	{
6453
		global $conf, $langs, $hookmanager;
6454
		global $bc;
6455
6456
		$linktoelem='';
6457
		$linktoelemlist='';
6458
		$listofidcompanytoscan='';
6459
6460
		if (! is_object($object->thirdparty)) $object->fetch_thirdparty();
6461
6462
		$possiblelinks=array();
6463
		if (is_object($object->thirdparty) && ! empty($object->thirdparty->id) && $object->thirdparty->id > 0)
6464
		{
6465
			$listofidcompanytoscan=$object->thirdparty->id;
6466
			if (($object->thirdparty->parent > 0) && ! empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) $listofidcompanytoscan.=','.$object->thirdparty->parent;
6467
			if (($object->fk_project > 0) && ! empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO))
6468
			{
6469
				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
6470
				$tmpproject=new Project($this->db);
6471
				$tmpproject->fetch($object->fk_project);
6472
				if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) $listofidcompanytoscan.=','.$tmpproject->socid;
6473
				unset($tmpproject);
6474
			}
6475
6476
			$possiblelinks=array(
6477
				'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').')'),
6478
				'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').')'),
6479
				'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'),
6480
				'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'),
6481
				'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').')'),
6482
				'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').')'),
6483
				'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').')'),
6484
				'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').')'),
6485
				'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').')')
6486
			);
6487
		}
6488
6489
		global $action;
6490
6491
		// Can complete the possiblelink array
6492
		$hookmanager->initHooks(array('commonobject'));
6493
		$parameters=array('listofidcompanytoscan' => $listofidcompanytoscan);
6494
		$reshook=$hookmanager->executeHooks('showLinkToObjectBlock',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
6495
		if (empty($reshook))
6496
		{
6497
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6498
			{
6499
				$possiblelinks=array_merge($possiblelinks, $hookmanager->resArray);
6500
			}
6501
		}
6502
		else if ($reshook > 0)
6503
		{
6504
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6505
			{
6506
				$possiblelinks=$hookmanager->resArray;
6507
			}
6508
		}
6509
6510
		foreach($possiblelinks as $key => $possiblelink)
6511
		{
6512
			$num = 0;
6513
6514
			if (empty($possiblelink['enabled'])) continue;
6515
6516
			if (! empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || ! in_array($key, $excludelinksto)))
6517
			{
6518
				print '<div id="'.$key.'list"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)?' style="display:none"':'').'>';
6519
				$sql = $possiblelink['sql'];
6520
6521
				$resqllist = $this->db->query($sql);
6522
				if ($resqllist)
6523
				{
6524
					$num = $this->db->num_rows($resqllist);
6525
					$i = 0;
6526
6527
					print '<br><form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
6528
					print '<input type="hidden" name="id" value="'.$object->id.'">';
6529
					print '<input type="hidden" name="action" value="addlink">';
6530
					print '<input type="hidden" name="addlink" value="'.$key.'">';
6531
					print '<table class="noborder">';
6532
					print '<tr class="liste_titre">';
6533
					print '<td class="nowrap"></td>';
6534
					print '<td align="center">' . $langs->trans("Ref") . '</td>';
6535
					print '<td align="left">' . $langs->trans("RefCustomer") . '</td>';
6536
					print '<td align="right">' . $langs->trans("AmountHTShort") . '</td>';
6537
					print '<td align="left">' . $langs->trans("Company") . '</td>';
6538
					print '</tr>';
6539
					while ($i < $num)
6540
					{
6541
						$objp = $this->db->fetch_object($resqllist);
6542
6543
						print '<tr class="oddeven">';
6544
						print '<td aling="left">';
6545
						print '<input type="radio" name="idtolinkto" value=' . $objp->rowid . '>';
6546
						print '</td>';
6547
						print '<td align="center">' . $objp->ref . '</td>';
6548
						print '<td>' . $objp->ref_client . '</td>';
6549
						print '<td align="right">' . price($objp->total_ht) . '</td>';
6550
						print '<td>' . $objp->name . '</td>';
6551
						print '</tr>';
6552
						$i++;
6553
					}
6554
					print '</table>';
6555
					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>';
6556
6557
					print '</form>';
6558
					$this->db->free($resqllist);
6559
				} else {
6560
					dol_print_error($this->db);
6561
				}
6562
				print '</div>';
6563
				if ($num > 0)
6564
				{
6565
				}
6566
6567
				//$linktoelem.=($linktoelem?' &nbsp; ':'');
6568
				if ($num > 0) $linktoelemlist.='<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">' . $langs->trans($possiblelink['label']) .' ('.$num.')</a></li>';
6569
				//else $linktoelem.=$langs->trans($possiblelink['label']);
6570
				else $linktoelemlist.='<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
6571
			}
6572
		}
6573
6574
		if ($linktoelemlist)
6575
		{
6576
			$linktoelem='
6577
    		<dl class="dropdown" id="linktoobjectname">
6578
    		<dt><a href="#linktoobjectname">'.$langs->trans("LinkTo").'...</a></dt>
6579
    		<dd>
6580
    		<div class="multiselectlinkto">
6581
    		<ul class="ulselectedfields">'.$linktoelemlist.'
6582
    		</ul>
6583
    		</div>
6584
    		</dd>
6585
    		</dl>';
6586
		}
6587
		else
6588
		{
6589
			$linktoelem='';
6590
		}
6591
6592
		print '<!-- Add js to show linkto box -->
6593
				<script type="text/javascript" language="javascript">
6594
				jQuery(document).ready(function() {
6595
					jQuery(".linkto").click(function() {
6596
						console.log("We choose to show/hide link for rel="+jQuery(this).attr(\'rel\'));
6597
					    jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
6598
						jQuery(this).toggle();
6599
					});
6600
				});
6601
				</script>
6602
		';
6603
6604
		return $linktoelem;
6605
	}
6606
6607
	/**
6608
	 *	Return an html string with a select combo box to choose yes or no
6609
	 *
6610
	 *	@param	string		$htmlname		Name of html select field
6611
	 *	@param	string		$value			Pre-selected value
6612
	 *	@param	int			$option			0 return yes/no, 1 return 1/0
6613
	 *	@param	bool		$disabled		true or false
6614
	 *  @param	int      	$useempty		1=Add empty line
6615
	 *	@return	string						See option
6616
	 */
6617
	function selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0)
6618
	{
6619
		global $langs;
6620
6621
		$yes="yes"; $no="no";
6622
		if ($option)
6623
		{
6624
			$yes="1";
6625
			$no="0";
6626
		}
6627
6628
		$disabled = ($disabled ? ' disabled' : '');
6629
6630
		$resultyesno = '<select class="flat width75" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
6631
		if ($useempty) $resultyesno .= '<option value="-1"'.(($value < 0)?' selected':'').'>&nbsp;</option>'."\n";
6632
		if (("$value" == 'yes') || ($value == 1))
6633
		{
6634
			$resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
6635
			$resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
6636
		}
6637
		else
6638
	   {
6639
	   		$selected=(($useempty && $value != '0' && $value != 'no')?'':' selected');
6640
			$resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
6641
			$resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
6642
		}
6643
		$resultyesno .= '</select>'."\n";
6644
		return $resultyesno;
6645
	}
6646
6647
6648
6649
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
6650
	/**
6651
	 *  Return list of export templates
6652
	 *
6653
	 *  @param	string	$selected          Id modele pre-selectionne
6654
	 *  @param  string	$htmlname          Name of HTML select
6655
	 *  @param  string	$type              Type of searched templates
6656
	 *  @param  int		$useempty          Affiche valeur vide dans liste
6657
	 *  @return	void
6658
	 */
6659
	function select_export_model($selected='',$htmlname='exportmodelid',$type='',$useempty=0)
6660
	{
6661
        // phpcs:enable
6662
		$sql = "SELECT rowid, label";
6663
		$sql.= " FROM ".MAIN_DB_PREFIX."export_model";
6664
		$sql.= " WHERE type = '".$type."'";
6665
		$sql.= " ORDER BY rowid";
6666
		$result = $this->db->query($sql);
6667
		if ($result)
6668
		{
6669
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
6670
			if ($useempty)
6671
			{
6672
				print '<option value="-1">&nbsp;</option>';
6673
			}
6674
6675
			$num = $this->db->num_rows($result);
6676
			$i = 0;
6677
			while ($i < $num)
6678
			{
6679
				$obj = $this->db->fetch_object($result);
6680
				if ($selected == $obj->rowid)
6681
				{
6682
					print '<option value="'.$obj->rowid.'" selected>';
6683
				}
6684
				else
6685
				{
6686
					print '<option value="'.$obj->rowid.'">';
6687
				}
6688
				print $obj->label;
6689
				print '</option>';
6690
				$i++;
6691
			}
6692
			print "</select>";
6693
		}
6694
		else {
6695
			dol_print_error($this->db);
6696
		}
6697
	}
6698
6699
	/**
6700
	 *    Return a HTML area with the reference of object and a navigation bar for a business object
6701
	 *    Note: To complete search with a particular filter on select, you can set $object->next_prev_filter set to define SQL criterias.
6702
	 *
6703
	 *    @param	object	$object			Object to show.
6704
	 *    @param	string	$paramid   		Name of parameter to use to name the id into the URL next/previous link.
6705
	 *    @param	string	$morehtml  		More html content to output just before the nav bar.
6706
	 *    @param	int		$shownav	  	Show Condition (navigation is shown if value is 1).
6707
	 *    @param	string	$fieldid   		Name of field id into database to use for select next and previous (we make the select max and min on this field compared to $object->ref). Use 'none' to disable next/prev.
6708
	 *    @param	string	$fieldref   	Name of field ref of object (object->ref) to show or 'none' to not show ref.
6709
	 *    @param	string	$morehtmlref  	More html to show after ref.
6710
	 *    @param	string	$moreparam  	More param to add in nav link url. Must start with '&...'.
6711
	 *	  @param	int		$nodbprefix		Do not include DB prefix to forge table name.
6712
	 *	  @param	string	$morehtmlleft	More html code to show before ref.
6713
	 *	  @param	string	$morehtmlstatus	More html code to show under navigation arrows (status place).
6714
	 *	  @param	string	$morehtmlright	More html code to show after ref.
6715
	 * 	  @return	string    				Portion HTML with ref + navigation buttons
6716
	 */
6717
	function showrefnav($object,$paramid,$morehtml='',$shownav=1,$fieldid='rowid',$fieldref='ref',$morehtmlref='',$moreparam='',$nodbprefix=0,$morehtmlleft='',$morehtmlstatus='',$morehtmlright='')
6718
	{
6719
		global $langs,$conf,$hookmanager;
6720
6721
		$ret='';
6722
		if (empty($fieldid))  $fieldid='rowid';
6723
		if (empty($fieldref)) $fieldref='ref';
6724
6725
		// Add where from hooks
6726
		if (is_object($hookmanager))
6727
		{
6728
			$parameters=array();
6729
			$reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters, $object);    // Note that $action and $object may have been modified by hook
6730
			$object->next_prev_filter.=$hookmanager->resPrint;
6731
		}
6732
		$previous_ref = $next_ref = '';
6733
		if ($shownav)
6734
		{
6735
			//print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
6736
			$object->load_previous_next_ref((isset($object->next_prev_filter)?$object->next_prev_filter:''), $fieldid, $nodbprefix);
6737
6738
			$navurl = $_SERVER["PHP_SELF"];
6739
			// Special case for project/task page
6740
			if ($paramid == 'project_ref')
6741
			{
6742
				$navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/','/tasks.php',$navurl);
6743
				$paramid='ref';
6744
			}
6745
6746
			// accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
6747
			// accesskey is for Mac:               CTRL + key for all browsers
6748
			$stringforfirstkey = $langs->trans("KeyboardShortcut");
6749
			if ($conf->browser->name == 'chrome')
6750
			{
6751
				$stringforfirstkey .= ' ALT +';
6752
			}
6753
			elseif ($conf->browser->name == 'firefox')
6754
			{
6755
				$stringforfirstkey .= ' ALT + SHIFT +';
6756
			}
6757
			else
6758
			{
6759
				$stringforfirstkey .= ' CTL +';
6760
			}
6761
6762
			$previous_ref = $object->ref_previous?'<a accesskey="p" title="'.$stringforfirstkey.' p" class="classfortooltip" href="'.$navurl.'?'.$paramid.'='.urlencode($object->ref_previous).$moreparam.'"><i class="fa fa-chevron-left"></i></a>':'<span class="inactive"><i class="fa fa-chevron-left opacitymedium"></i></span>';
6763
			$next_ref     = $object->ref_next?'<a accesskey="n" title="'.$stringforfirstkey.' n" class="classfortooltip" href="'.$navurl.'?'.$paramid.'='.urlencode($object->ref_next).$moreparam.'"><i class="fa fa-chevron-right"></i></a>':'<span class="inactive"><i class="fa fa-chevron-right opacitymedium"></i></span>';
6764
		}
6765
6766
		//print "xx".$previous_ref."x".$next_ref;
6767
		$ret.='<!-- Start banner content --><div style="vertical-align: middle">';
6768
6769
		// Right part of banner
6770
		if ($morehtmlright) $ret.='<div class="inline-block floatleft">'.$morehtmlright.'</div>';
6771
6772
		if ($previous_ref || $next_ref || $morehtml)
6773
		{
6774
			$ret.='<div class="pagination paginationref"><ul class="right">';
6775
		}
6776
		if ($morehtml)
6777
		{
6778
			$ret.='<li class="noborder litext">'.$morehtml.'</li>';
6779
		}
6780
		if ($shownav && ($previous_ref || $next_ref))
6781
		{
6782
			$ret.='<li class="pagination">'.$previous_ref.'</li>';
6783
			$ret.='<li class="pagination">'.$next_ref.'</li>';
6784
		}
6785
		if ($previous_ref || $next_ref || $morehtml)
6786
		{
6787
			$ret.='</ul></div>';
6788
		}
6789
6790
		$parameters=array();
6791
		$reshook=$hookmanager->executeHooks('moreHtmlStatus',$parameters, $object);    // Note that $action and $object may have been modified by hook
6792
		if (empty($reshook)) $morehtmlstatus.=$hookmanager->resPrint;
6793
		else $morehtmlstatus=$hookmanager->resPrint;
6794
		if ($morehtmlstatus) $ret.='<div class="statusref">'.$morehtmlstatus.'</div>';
6795
6796
		$parameters = array();
6797
		$reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
6798
		if (empty($reshook)) $morehtmlref.=$hookmanager->resPrint;
6799
		elseif ($reshook > 0) $morehtmlref=$hookmanager->resPrint;
6800
6801
		// Left part of banner
6802
		if ($morehtmlleft)
6803
		{
6804
			if ($conf->browser->layout == 'phone') $ret.='<div class="floatleft">'.$morehtmlleft.'</div>';    // class="center" to have photo in middle
6805
			else $ret.='<div class="inline-block floatleft">'.$morehtmlleft.'</div>';
6806
		}
6807
6808
		//if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
6809
		$ret.='<div class="inline-block floatleft valignmiddle refid'.(($shownav && ($previous_ref || $next_ref))?' refidpadding':'').'">';
6810
6811
		// For thirdparty, contact, user, member, the ref is the id, so we show something else
6812
		if ($object->element == 'societe')
6813
		{
6814
			$ret.=dol_htmlentities($object->name);
6815
		}
6816
		else if ($object->element == 'member')
6817
		{
6818
			$ret.=$object->ref.'<br>';
6819
			$fullname=$object->getFullName($langs);
6820
			if ($object->morphy == 'mor' && $object->societe) {
6821
				$ret.= dol_htmlentities($object->societe) . ((! empty($fullname) && $object->societe != $fullname)?' ('.dol_htmlentities($fullname).')':'');
6822
			} else {
6823
				$ret.= dol_htmlentities($fullname) . ((! empty($object->societe) && $object->societe != $fullname)?' ('.dol_htmlentities($object->societe).')':'');
6824
			}
6825
		}
6826
		else if (in_array($object->element, array('contact', 'user', 'usergroup')))
6827
		{
6828
			$ret.=dol_htmlentities($object->getFullName($langs));
6829
		}
6830
		else if (in_array($object->element, array('action', 'agenda')))
6831
		{
6832
			$ret.=$object->ref.'<br>'.$object->label;
6833
		}
6834
		else if (in_array($object->element, array('adherent_type')))
6835
		{
6836
			$ret.=$object->label;
6837
		}
6838
		else if ($object->element == 'ecm_directories')
6839
		{
6840
			$ret.='';
6841
		}
6842
		else if ($fieldref != 'none') $ret.=dol_htmlentities($object->$fieldref);
6843
6844
6845
		if ($morehtmlref)
6846
		{
6847
			$ret.=' '.$morehtmlref;
6848
		}
6849
		$ret.='</div>';
6850
6851
		$ret.='</div><!-- End banner content -->';
6852
6853
		return $ret;
6854
	}
6855
6856
6857
	/**
6858
	 *    	Return HTML code to output a barcode
6859
	 *
6860
	 *     	@param	Object	$object		Object containing data to retrieve file name
6861
	 * 		@param	int		$width			Width of photo
6862
	 * 	  	@return string    				HTML code to output barcode
6863
	 */
6864
	function showbarcode(&$object,$width=100)
6865
	{
6866
		global $conf;
6867
6868
		//Check if barcode is filled in the card
6869
		if (empty($object->barcode)) return '';
6870
6871
		// Complete object if not complete
6872
		if (empty($object->barcode_type_code) || empty($object->barcode_type_coder))
6873
		{
6874
			$result = $object->fetch_barcode();
6875
			//Check if fetch_barcode() failed
6876
			if ($result < 1) return '<!-- ErrorFetchBarcode -->';
6877
		}
6878
6879
		// Barcode image
6880
		$url=DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
6881
		$out ='<!-- url barcode = '.$url.' -->';
6882
		$out.='<img src="'.$url.'">';
6883
		return $out;
6884
	}
6885
6886
	/**
6887
	 *    	Return HTML code to output a photo
6888
	 *
6889
	 *    	@param	string		$modulepart			Key to define module concerned ('societe', 'userphoto', 'memberphoto')
6890
	 *     	@param  object		$object				Object containing data to retrieve file name
6891
	 * 		@param	int			$width				Width of photo
6892
	 * 		@param	int			$height				Height of photo (auto if 0)
6893
	 * 		@param	int			$caneditfield		Add edit fields
6894
	 * 		@param	string		$cssclass			CSS name to use on img for photo
6895
	 * 		@param	string		$imagesize		    'mini', 'small' or '' (original)
6896
	 *      @param  int         $addlinktofullsize  Add link to fullsize image
6897
	 *      @param  int         $cache              1=Accept to use image in cache
6898
	 *      @param	string		$forcecapture		Force parameter capture on HTML input file element to ask a smartphone to allow to open camera to take photo. Auto if empty.
6899
	 * 	  	@return string    						HTML code to output photo
6900
	 */
6901
	static function showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='')
6902
	{
6903
		global $conf,$langs;
6904
6905
		$entity = (! empty($object->entity) ? $object->entity : $conf->entity);
6906
		$id = (! empty($object->id) ? $object->id : $object->rowid);
6907
6908
		$ret='';$dir='';$file='';$originalfile='';$altfile='';$email='';$capture='';
6909
		if ($modulepart=='societe')
6910
		{
6911
			$dir=$conf->societe->multidir_output[$entity];
6912
			if (! empty($object->logo))
6913
			{
6914
				if ((string) $imagesize == 'mini') $file=get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.getImageFileNameForSize($object->logo, '_mini');             // getImageFileNameForSize include the thumbs
6915
				else if ((string) $imagesize == 'small') $file=get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.getImageFileNameForSize($object->logo, '_small');
6916
				else $file=get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.$object->logo;
6917
				$originalfile=get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.$object->logo;
6918
			}
6919
			$email=$object->email;
6920
		}
6921
		else if ($modulepart=='contact')
6922
		{
6923
			$dir=$conf->societe->multidir_output[$entity].'/contact';
6924
			if (! empty($object->photo))
6925
			{
6926
				if ((string) $imagesize == 'mini') $file=get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.getImageFileNameForSize($object->photo, '_mini');
6927
				else if ((string) $imagesize == 'small') $file=get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.getImageFileNameForSize($object->photo, '_small');
6928
				else $file=get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.$object->photo;
6929
				$originalfile=get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.$object->photo;
6930
			}
6931
			$email=$object->email;
6932
			$capture='user';
6933
		}
6934
		else if ($modulepart=='userphoto')
6935
		{
6936
			$dir=$conf->user->dir_output;
6937
			if (! empty($object->photo))
6938
			{
6939
				if ((string) $imagesize == 'mini') $file=get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_mini');
6940
				else if ((string) $imagesize == 'small') $file=get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_small');
6941
				else $file=get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
6942
				$originalfile=get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
6943
			}
6944
			if (! empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile=$object->id.".jpg";	// For backward compatibility
6945
			$email=$object->email;
6946
			$capture='user';
6947
		}
6948
		else if ($modulepart=='memberphoto')
6949
		{
6950
			$dir=$conf->adherent->dir_output;
6951
			if (! empty($object->photo))
6952
			{
6953
				if ((string) $imagesize == 'mini') $file=get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
6954
				else if ((string) $imagesize == 'small') $file=get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
6955
				else $file=get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
6956
				$originalfile=get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
6957
			}
6958
			if (! empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile=$object->id.".jpg";	// For backward compatibility
6959
			$email=$object->email;
6960
			$capture='user';
6961
		}
6962
		else
6963
		{
6964
			// Generic case to show photos
6965
			$dir=$conf->$modulepart->dir_output;
6966
			if (! empty($object->photo))
6967
			{
6968
				if ((string) $imagesize == 'mini') $file=get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
6969
				else if ((string) $imagesize == 'small') $file=get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
6970
				else $file=get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
6971
				$originalfile=get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
6972
			}
6973
			if (! empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile=$object->id.".jpg";	// For backward compatibility
6974
			$email=$object->email;
6975
		}
6976
6977
		if ($forcecapture) $capture = $forcecapture;
6978
6979
		if ($dir)
6980
		{
6981
			if ($file && file_exists($dir."/".$file))
6982
			{
6983
				if ($addlinktofullsize)
6984
				{
6985
					$urladvanced=getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
6986
					if ($urladvanced) $ret.='<a href="'.$urladvanced.'">';
6987
					else $ret.='<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
6988
				}
6989
				$ret.='<img class="photo'.$modulepart.($cssclass?' '.$cssclass:'').'" alt="Photo" id="photologo'.(preg_replace('/[^a-z]/i','_',$file)).'" '.($width?' width="'.$width.'"':'').($height?' height="'.$height.'"':'').' src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($file).'&cache='.$cache.'">';
6990
				if ($addlinktofullsize) $ret.='</a>';
6991
			}
6992
			else if ($altfile && file_exists($dir."/".$altfile))
6993
			{
6994
				if ($addlinktofullsize)
6995
				{
6996
					$urladvanced=getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
6997
					if ($urladvanced) $ret.='<a href="'.$urladvanced.'">';
6998
					else $ret.='<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
6999
				}
7000
				$ret.='<img class="photo'.$modulepart.($cssclass?' '.$cssclass:'').'" alt="Photo alt" id="photologo'.(preg_replace('/[^a-z]/i','_',$file)).'" class="'.$cssclass.'" '.($width?' width="'.$width.'"':'').($height?' height="'.$height.'"':'').' src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($altfile).'&cache='.$cache.'">';
7001
				if ($addlinktofullsize) $ret.='</a>';
7002
			}
7003
			else
7004
			{
7005
				$nophoto='/public/theme/common/nophoto.png';
7006
				if (in_array($modulepart,array('userphoto','contact')))	// For module that are "physical" users
7007
				{
7008
					$nophoto='/public/theme/common/user_anonymous.png';
7009
					if ($object->gender == 'man') $nophoto='/public/theme/common/user_man.png';
7010
					if ($object->gender == 'woman') $nophoto='/public/theme/common/user_woman.png';
7011
				}
7012
7013
				if (! empty($conf->gravatar->enabled) && $email)
7014
				{
7015
					/**
7016
					 * @see https://gravatar.com/site/implement/images/php/
7017
					 */
7018
					global $dolibarr_main_url_root;
7019
					$ret.='<!-- Put link to gravatar -->';
7020
					//$defaultimg=urlencode(dol_buildpath($nophoto,3));
7021
					$defaultimg='mm';
7022
					$ret.='<img class="photo'.$modulepart.($cssclass?' '.$cssclass:'').'" alt="Gravatar avatar" title="'.$email.' Gravatar avatar" '.($width?' width="'.$width.'"':'').($height?' height="'.$height.'"':'').' src="https://www.gravatar.com/avatar/'.dol_hash(strtolower(trim($email)),3).'?s='.$width.'&d='.$defaultimg.'">';	// gravatar need md5 hash
7023
				}
7024
				else
7025
				{
7026
					$ret.='<img class="photo'.$modulepart.($cssclass?' '.$cssclass:'').'" alt="No photo" '.($width?' width="'.$width.'"':'').($height?' height="'.$height.'"':'').' src="'.DOL_URL_ROOT.$nophoto.'">';
7027
				}
7028
			}
7029
7030
			if ($caneditfield)
7031
			{
7032
				if ($object->photo) $ret.="<br>\n";
7033
				$ret.='<table class="nobordernopadding centpercent">';
7034
				if ($object->photo) $ret.='<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> '.$langs->trans("Delete").'<br><br></td></tr>';
7035
				$ret.='<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput"'.($capture?' capture="'.$capture.'"':'').'></td></tr>';
7036
				$ret.='</table>';
7037
			}
7038
		}
7039
		else dol_print_error('','Call of showphoto with wrong parameters modulepart='.$modulepart);
7040
7041
		return $ret;
7042
	}
7043
7044
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
7045
	/**
7046
	 *	Return select list of groups
7047
	 *
7048
	 *  @param	string	$selected       Id group preselected
7049
	 *  @param  string	$htmlname       Field name in form
7050
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
7051
	 *  @param  string	$exclude        Array list of groups id to exclude
7052
	 * 	@param	int		$disabled		If select list must be disabled
7053
	 *  @param  string	$include        Array list of groups id to include
7054
	 * 	@param	int		$enableonly		Array list of groups id to be enabled. All other must be disabled
7055
	 * 	@param	string	$force_entity	'0' or Ids of environment to force
7056
	 * 	@param	bool	$multiple		add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
7057
	 *  @return	string
7058
	 *  @see select_dolusers
7059
	 */
7060
	function select_dolgroups($selected='', $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly='', $force_entity='0', $multiple=false)
7061
	{
7062
        // phpcs:enable
7063
		global $conf,$user,$langs;
7064
7065
		// Permettre l'exclusion de groupes
7066
		if (is_array($exclude))	$excludeGroups = implode("','",$exclude);
7067
		// Permettre l'inclusion de groupes
7068
		if (is_array($include))	$includeGroups = implode("','",$include);
7069
7070
		if (!is_array($selected)) $selected = array($selected);
7071
7072
		$out='';
7073
7074
		// On recherche les groupes
7075
		$sql = "SELECT ug.rowid, ug.nom as name";
7076
		if (! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
7077
		{
7078
			$sql.= ", e.label";
7079
		}
7080
		$sql.= " FROM ".MAIN_DB_PREFIX."usergroup as ug ";
7081
		if (! empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && ! $user->entity)
7082
		{
7083
			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=ug.entity";
7084
			if ($force_entity) $sql.= " WHERE ug.entity IN (0,".$force_entity.")";
7085
			else $sql.= " WHERE ug.entity IS NOT NULL";
7086
		}
7087
		else
7088
		{
7089
			$sql.= " WHERE ug.entity IN (0,".$conf->entity.")";
7090
		}
7091
		if (is_array($exclude) && $excludeGroups) $sql.= " AND ug.rowid NOT IN ('".$excludeGroups."')";
7092
		if (is_array($include) && $includeGroups) $sql.= " AND ug.rowid IN ('".$includeGroups."')";
7093
		$sql.= " ORDER BY ug.nom ASC";
7094
7095
		dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
7096
		$resql=$this->db->query($sql);
7097
		if ($resql)
7098
		{
7099
			// Enhance with select2
7100
			include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7101
		   	$out .= ajax_combobox($htmlname);
7102
7103
			$out.= '<select class="flat minwidth200" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled?' disabled':'').'>';
7104
7105
			$num = $this->db->num_rows($resql);
7106
			$i = 0;
7107
			if ($num)
7108
			{
7109
				if ($show_empty && !$multiple) $out.= '<option value="-1"'.(in_array(-1,$selected)?' selected':'').'>&nbsp;</option>'."\n";
7110
7111
				while ($i < $num)
7112
				{
7113
					$obj = $this->db->fetch_object($resql);
7114
					$disableline=0;
7115
					if (is_array($enableonly) && count($enableonly) && ! in_array($obj->rowid,$enableonly)) $disableline=1;
7116
7117
					$out.= '<option value="'.$obj->rowid.'"';
7118
					if ($disableline) $out.= ' disabled';
7119
					if ((is_object($selected[0]) && $selected[0]->id == $obj->rowid) || (! is_object($selected[0]) && in_array($obj->rowid,$selected) ))
7120
					{
7121
						$out.= ' selected';
7122
					}
7123
					$out.= '>';
7124
7125
					$out.= $obj->name;
7126
					if (! empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1)
7127
					{
7128
						$out.= " (".$obj->label.")";
7129
					}
7130
7131
					$out.= '</option>';
7132
					$i++;
7133
				}
7134
			}
7135
			else
7136
			{
7137
				if ($show_empty) $out.= '<option value="-1"'.(in_array(-1,$selected)?' selected':'').'></option>'."\n";
7138
				$out.= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
7139
			}
7140
			$out.= '</select>';
7141
		}
7142
		else
7143
		{
7144
			dol_print_error($this->db);
7145
		}
7146
7147
		return $out;
7148
	}
7149
7150
7151
	/**
7152
	 *	Return HTML to show the search and clear seach button
7153
	 *
7154
	 *  @return	string
7155
	 */
7156
	function showFilterButtons()
7157
	{
7158
		global $conf, $langs;
7159
7160
		$out='<div class="nowrap">';
7161
		$out.='<input type="image" class="liste_titre" name="button_search" src="'.img_picto($langs->trans("Search"),'search.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("Search")).'" title="'.dol_escape_htmltag($langs->trans("Search")).'">';
7162
		$out.='<input type="image" class="liste_titre" name="button_removefilter" src="'.img_picto($langs->trans("Search"),'searchclear.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'" title="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'">';
7163
		$out.='</div>';
7164
7165
		return $out;
7166
	}
7167
7168
	/**
7169
	 *	Return HTML to show the search and clear seach button
7170
	 *
7171
	 *  @param  string  $cssclass                  CSS class
7172
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
7173
	 *  @return	string
7174
	 */
7175
	function showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0)
7176
	{
7177
		global $conf, $langs;
7178
7179
		$out='';
7180
		if (! empty($conf->use_javascript_ajax)) $out.='<div class="inline-block checkallactions"><input type="checkbox" id="checkallactions" name="checkallactions" class="checkallactions"></div>';
7181
		$out.='<script type="text/javascript">
7182
            $(document).ready(function() {
7183
            	$("#checkallactions").click(function() {
7184
                    if($(this).is(\':checked\')){
7185
                        console.log("We check all");
7186
                		$(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
7187
                    }
7188
                    else
7189
                    {
7190
                        console.log("We uncheck all");
7191
                		$(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
7192
                    }'."\n";
7193
		if ($calljsfunction) $out.='if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
7194
		$out.='         });
7195
7196
        	$(".checkforselect").change(function() {
7197
				$(this).closest("tr").toggleClass("highlight", this.checked);
7198
			});
7199
7200
 	});
7201
    </script>';
7202
7203
		return $out;
7204
	}
7205
7206
	/**
7207
	 *	Return HTML to show the search and clear seach button
7208
	 *
7209
	 *  @param	int  	$addcheckuncheckall        Add the check all/uncheck all checkbox (use javascript) and code to manage this
7210
	 *  @param  string  $cssclass                  CSS class
7211
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
7212
	 *  @return	string
7213
	 */
7214
	function showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0)
7215
	{
7216
		$out.=$this->showFilterButtons();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $out seems to be never defined.
Loading history...
7217
		if ($addcheckuncheckall)
7218
		{
7219
			$out.=$this->showCheckAddButtons($cssclass, $calljsfunction);
7220
		}
7221
		return $out;
7222
	}
7223
7224
	/**
7225
	 * Return HTML to show the select of expense categories
7226
	 *
7227
	 * @param	string	$selected              preselected category
7228
	 * @param	string	$htmlname              name of HTML select list
7229
	 * @param	integer	$useempty              1=Add empty line
7230
	 * @param	array	$excludeid             id to exclude
7231
	 * @param	string	$target                htmlname of target select to bind event
7232
	 * @param	int		$default_selected      default category to select if fk_c_type_fees change = EX_KME
7233
	 * @param	array	$params                param to give
7234
	 * @return	string
7235
	 */
7236
	function selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array())
7237
	{
7238
		global $db, $conf, $langs, $user;
7239
7240
		$sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1';
7241
		$sql.= ' AND entity IN (0,'.getEntity('exp_tax_cat').')';
7242
		if (!empty($excludeid)) $sql.= ' AND rowid NOT IN ('.implode(',', $excludeid).')';
7243
		$sql.= ' ORDER BY label';
7244
7245
		$resql = $db->query($sql);
7246
		if ($resql)
7247
		{
7248
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7249
			if ($useempty) $out.= '<option value="0">&nbsp;</option>';
7250
7251
			while ($obj = $db->fetch_object($resql))
7252
			{
7253
				$out.= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
7254
			}
7255
			$out.= '</select>';
7256
			if (! empty($htmlname) && $user->admin) $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
7257
7258
			if (!empty($target))
7259
			{
7260
				$sql = "SELECT c.id FROM ".MAIN_DB_PREFIX."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
7261
				$resql = $db->query($sql);
7262
				if ($resql)
7263
				{
7264
					if ($db->num_rows($resql) > 0)
7265
					{
7266
						$obj = $db->fetch_object($resql);
7267
						$out.= '<script type="text/javascript">
7268
							$(function() {
7269
								$("select[name='.$target.']").on("change", function() {
7270
									var current_val = $(this).val();
7271
									if (current_val == '.$obj->id.') {';
7272
						if (!empty($default_selected) || !empty($selected)) $out.= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
7273
7274
						$out.= '
7275
										$("select[name='.$htmlname.']").change();
7276
									}
7277
								});
7278
7279
								$("select[name='.$htmlname.']").change(function() {
7280
7281
									if ($("select[name='.$target.']").val() == '.$obj->id.') {
7282
										// get price of kilometer to fill the unit price
7283
										var data = '.json_encode($params).';
7284
										data.fk_c_exp_tax_cat = $(this).val();
7285
7286
										$.ajax({
7287
											method: "POST",
7288
											dataType: "json",
7289
											data: data,
7290
											url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php').'",
7291
										}).done(function( data, textStatus, jqXHR ) {
7292
											console.log(data);
7293
											if (typeof data.up != "undefined") {
7294
												$("input[name=value_unit]").val(data.up);
7295
												$("select[name='.$htmlname.']").attr("title", data.title);
7296
											} else {
7297
												$("input[name=value_unit]").val("");
7298
												$("select[name='.$htmlname.']").attr("title", "");
7299
											}
7300
										});
7301
									}
7302
								});
7303
							});
7304
						</script>';
7305
					}
7306
				}
7307
			}
7308
		}
7309
		else
7310
		{
7311
			dol_print_error($db);
7312
		}
7313
7314
		return $out;
7315
	}
7316
7317
	/**
7318
	 * Return HTML to show the select ranges of expense range
7319
	 *
7320
	 * @param	string	$selected    preselected category
7321
	 * @param	string	$htmlname    name of HTML select list
7322
	 * @param	integer	$useempty    1=Add empty line
7323
	 * @return	string
7324
	 */
7325
	function selectExpenseRanges($selected='', $htmlname='fk_range', $useempty=0)
7326
	{
7327
		global $db,$conf,$langs;
7328
7329
		$sql = 'SELECT rowid, range_ik FROM '.MAIN_DB_PREFIX.'c_exp_tax_range';
7330
		$sql.= ' WHERE entity = '.$conf->entity.' AND active = 1';
7331
7332
		$resql = $db->query($sql);
7333
		if ($resql)
7334
		{
7335
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7336
			if ($useempty) $out.= '<option value="0"></option>';
7337
7338
			while ($obj = $db->fetch_object($resql))
7339
			{
7340
				$out.= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
7341
			}
7342
			$out.= '</select>';
7343
		}
7344
		else
7345
		{
7346
			dol_print_error($db);
7347
		}
7348
7349
		return $out;
7350
	}
7351
7352
	/**
7353
	 * Return HTML to show a select of expense
7354
	 *
7355
	 * @param	string	$selected    preselected category
7356
	 * @param	string	$htmlname    name of HTML select list
7357
	 * @param	integer	$useempty    1=Add empty choice
7358
	 * @param	integer	$allchoice   1=Add all choice
7359
	 * @param	integer	$useid       0=use 'code' as key, 1=use 'id' as key
7360
	 * @return	string
7361
	 */
7362
	function selectExpense($selected='', $htmlname='fk_c_type_fees', $useempty=0, $allchoice=1, $useid=0)
7363
	{
7364
		global $db,$langs;
7365
7366
		$sql = 'SELECT id, code, label FROM '.MAIN_DB_PREFIX.'c_type_fees';
7367
		$sql.= ' WHERE active = 1';
7368
7369
		$resql = $db->query($sql);
7370
		if ($resql)
7371
		{
7372
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7373
			if ($useempty) $out.= '<option value="0"></option>';
7374
			if ($allchoice) $out.= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
7375
7376
			$field = 'code';
7377
			if ($useid) $field = 'id';
7378
7379
			while ($obj = $db->fetch_object($resql))
7380
			{
7381
				$key = $langs->trans($obj->code);
7382
				$out.= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
7383
			}
7384
			$out.= '</select>';
7385
		}
7386
		else
7387
		{
7388
			dol_print_error($db);
7389
		}
7390
7391
		return $out;
7392
	}
7393
}
7394