Passed
Branch develop (aaf83e)
by
unknown
26:06
created

Form::showphoto()   D

Complexity

Conditions 60

Size

Total Lines 146
Code Lines 90

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 60
eloc 90
nop 10
dl 0
loc 146
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-2019  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-2019  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 <https://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
	 * @param	string	$help			Tooltip help
104
	 * @return	string					HTML edit field
105
	 */
106
    public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
107
    {
108
		global $conf, $langs;
109
110
		$ret = '';
111
112
		// TODO change for compatibility
113
		if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata))
114
		{
115
			if (!empty($perm))
116
			{
117
				$tmp = explode(':', $typeofdata);
118
				$ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
119
				if ($fieldrequired) $ret .= '<span class="fieldrequired">';
120
				if ($help) {
121
					$ret .= $this->textwithpicto($langs->trans($text), $help);
122
				} else {
123
					$ret .= $langs->trans($text);
124
				}
125
				if ($fieldrequired) $ret .= '</span>';
126
				$ret .= '</div>'."\n";
127
			}
128
			else
129
			{
130
				if ($fieldrequired) $ret .= '<span class="fieldrequired">';
131
				if ($help) {
132
					$ret .= $this->textwithpicto($langs->trans($text), $help);
133
				} else {
134
					$ret .= $langs->trans($text);
135
				}
136
				if ($fieldrequired) $ret .= '</span>';
137
			}
138
		}
139
		else
140
		{
141
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
142
			if ($fieldrequired) $ret .= '<span class="fieldrequired">';
143
			if ($help) {
144
				$ret .= $this->textwithpicto($langs->trans($text), $help);
145
			} else {
146
				$ret .= $langs->trans($text);
147
			}
148
			if ($fieldrequired) $ret .= '</span>';
149
			if (!empty($notabletag)) $ret .= ' ';
150
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</td>';
151
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<td class="right">';
152
			if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&amp;'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
153
			if (!empty($notabletag) && $notabletag == 1) $ret .= ' : ';
154
			if (!empty($notabletag) && $notabletag == 3) $ret .= ' ';
155
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</td>';
156
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</tr></table>';
157
		}
158
159
		return $ret;
160
    }
161
162
	/**
163
	 * Output value of a field for an editable field
164
	 *
165
	 * @param	string	$text			Text of label (not used in this function)
166
	 * @param	string	$htmlname		Name of select field
167
	 * @param	string	$value			Value to show/edit
168
	 * @param	object	$object			Object
169
	 * @param	boolean	$perm			Permission to allow button to edit parameter
170
	 * @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;xkey:xval,ykey:yval,...')
171
	 * @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
172
	 * @param	object	$extObject		External object
173
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
174
	 * @param	string	$moreparam		More param to add on the form action href URL
175
	 * @param   int     $notabletag     Do no output table tags
176
	 * @param	string	$formatfunc		Call a specific function to output field
177
	 * @param	string	$paramid		Key of parameter for id ('id', 'socid')
178
	 * @return  string					HTML edit field
179
	 */
180
    public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id')
181
	{
182
		global $conf, $langs, $db;
183
184
		$ret = '';
185
186
		// Check parameters
187
		if (empty($typeofdata)) return 'ErrorBadParameter';
188
189
		// When option to edit inline is activated
190
		if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|datehourpicker/', $typeofdata)) // TODO add jquery timepicker and support select
191
		{
192
			$ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
193
		}
194
		else
195
		{
196
			if (GETPOST('action', 'aZ09') == 'edit'.$htmlname)
197
			{
198
				$ret .= "\n";
199
				$ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">';
200
				$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
201
				$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
202
				$ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
203
				if (empty($notabletag)) $ret .= '<table class="nobordernopadding centpercent" cellpadding="0" cellspacing="0">';
204
				if (empty($notabletag)) $ret .= '<tr><td>';
205
				if (preg_match('/^(string|email)/', $typeofdata))
206
				{
207
					$tmp = explode(':', $typeofdata);
208
					$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').'>';
209
				}
210
				elseif (preg_match('/^(numeric|amount)/', $typeofdata))
211
				{
212
					$tmp = explode(':', $typeofdata);
213
					$valuetoshow = price2num($editvalue ? $editvalue : $value);
214
					$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ?price($valuetoshow) : '').'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').'>';
215
				}
216
				elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata))	// if wysiwyg is enabled $typeofdata = 'ckeditor'
217
				{
218
					$tmp = explode(':', $typeofdata);
219
					$cols = $tmp[2];
220
					$morealt = '';
221
					if (preg_match('/%/', $cols))
222
					{
223
						$morealt = ' style="width: '.$cols.'"';
224
						$cols = '';
225
					}
226
227
					$valuetoshow = ($editvalue ? $editvalue : $value);
228
					$ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1] ? $tmp[1] : '20').'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'">';
229
					// textarea convert automatically entities chars into simple chars.
230
					// So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwig is off.
231
					$valuetoshow = str_replace('&', '&amp;', $valuetoshow);
232
					$ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
233
					$ret .= '</textarea>';
234
				}
235
				elseif ($typeofdata == 'day' || $typeofdata == 'datepicker')
236
				{
237
					$ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0);
238
				}
239
				elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker')
240
				{
241
					$ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0);
242
				}
243
				elseif (preg_match('/^select;/', $typeofdata))
244
				{
245
					$arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
246
                    $arraylist = array();
247
					foreach ($arraydata as $val)
248
					{
249
						$tmp = explode(':', $val);
250
						$tmpkey = str_replace('|', ':', $tmp[0]);
251
						$arraylist[$tmpkey] = $tmp[1];
252
					}
253
					$ret .= $this->selectarray($htmlname, $arraylist, $value);
254
				}
255
				elseif (preg_match('/^ckeditor/', $typeofdata))
256
				{
257
				    $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
258
					require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
259
					$doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), ($tmp[2] ? $tmp[2] : ''), ($tmp[3] ? $tmp[3] : '100'), ($tmp[1] ? $tmp[1] : 'dolibarr_notes'), 'In', ($tmp[5] ? $tmp[5] : 0), (isset($tmp[8]) ? ($tmp[8] ?true:false) : true), true, ($tmp[6] ? $tmp[6] : '20'), ($tmp[7] ? $tmp[7] : '100'));
260
					$ret .= $doleditor->Create(1);
261
				}
262
				if (empty($notabletag)) $ret .= '</td>';
263
264
				if (empty($notabletag)) $ret .= '<td class="left">';
265
				//else $ret.='<div class="clearboth"></div>';
266
			   	$ret .= '<input type="submit" class="button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
267
			   	if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) $ret .= '<br>'."\n";
268
			   	$ret .= '<input type="submit" class="button'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
269
			   	if (empty($notabletag)) $ret .= '</td>';
270
271
			   	if (empty($notabletag)) $ret .= '</tr></table>'."\n";
272
				$ret .= '</form>'."\n";
273
			}
274
			else
275
			{
276
				if (preg_match('/^(email)/', $typeofdata))              $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
277
				elseif (preg_match('/^(amount|numeric)/', $typeofdata)) $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
278
				elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata))  $ret .= dol_htmlentitiesbr($value);
279
				elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret .= dol_print_date($value, 'day');
280
				elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret .= dol_print_date($value, 'dayhour');
281
				elseif (preg_match('/^select;/', $typeofdata))
282
				{
283
					$arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
284
                    $arraylist = array();
285
					foreach ($arraydata as $val)
286
					{
287
						$tmp = explode(':', $val);
288
						$arraylist[$tmp[0]] = $tmp[1];
289
					}
290
					$ret .= $arraylist[$value];
291
				}
292
				elseif (preg_match('/^ckeditor/', $typeofdata))
293
				{
294
					$tmpcontent = dol_htmlentitiesbr($value);
295
					if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB))
296
					{
297
						$firstline = preg_replace('/<br>.*/', '', $tmpcontent);
298
						$firstline = preg_replace('/[\n\r].*/', '', $firstline);
299
						$tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
300
					}
301
					$ret .= $tmpcontent;
302
				}
303
				else $ret .= dol_escape_htmltag($value);
304
305
				if ($formatfunc && method_exists($object, $formatfunc))
306
				{
307
					$ret = $object->$formatfunc($ret);
308
				}
309
			}
310
		}
311
		return $ret;
312
	}
313
314
	/**
315
	 * Output edit in place form
316
	 *
317
	 * @param	object	$object			Object
318
	 * @param	string	$value			Value to show/edit
319
	 * @param	string	$htmlname		DIV ID (field name)
320
	 * @param	int		$condition		Condition to edit
321
	 * @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:loadmethod:savemethod:buttononly')
322
	 * @param	string	$editvalue		When in edit mode, use this value as $value instead of value
323
	 * @param	object	$extObject		External object
324
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
325
	 * @return	string   		      	HTML edit in place
326
	 */
327
	protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
328
	{
329
		global $conf;
330
331
		$out = '';
332
333
		// Check parameters
334
		if (preg_match('/^text/', $inputType)) $value = dol_nl2br($value);
335
		elseif (preg_match('/^numeric/', $inputType)) $value = price($value);
336
		elseif ($inputType == 'day' || $inputType == 'datepicker') $value = dol_print_date($value, 'day');
337
338
		if ($condition)
339
		{
340
			$element = false;
341
			$table_element = false;
342
			$fk_element		= false;
343
			$loadmethod		= false;
344
			$savemethod		= false;
345
			$ext_element	= false;
346
			$button_only	= false;
347
			$inputOption = '';
348
349
			if (is_object($object))
350
			{
351
				$element = $object->element;
352
				$table_element = $object->table_element;
353
				$fk_element = $object->id;
354
			}
355
356
			if (is_object($extObject))
357
			{
358
				$ext_element = $extObject->element;
359
			}
360
361
			if (preg_match('/^(string|email|numeric)/', $inputType))
362
			{
363
				$tmp = explode(':', $inputType);
364
				$inputType = $tmp[0];
365
				if (!empty($tmp[1])) $inputOption = $tmp[1];
366
				if (!empty($tmp[2])) $savemethod = $tmp[2];
367
				$out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
368
			}
369
			elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType)))
370
			{
371
				$tmp = explode(':', $inputType);
372
				$inputType = $tmp[0];
373
				if (!empty($tmp[1])) $inputOption = $tmp[1];
374
				if (!empty($tmp[2])) $savemethod = $tmp[2];
375
376
				$out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
377
			}
378
			elseif (preg_match('/^(select|autocomplete)/', $inputType))
379
			{
380
				$tmp = explode(':', $inputType);
381
				$inputType = $tmp[0]; $loadmethod = $tmp[1];
382
				if (!empty($tmp[2])) $savemethod = $tmp[2];
383
				if (!empty($tmp[3])) $button_only = true;
384
			}
385
			elseif (preg_match('/^textarea/', $inputType))
386
			{
387
				$tmp = explode(':', $inputType);
388
				$inputType = $tmp[0];
389
				$rows = (empty($tmp[1]) ? '8' : $tmp[1]);
390
				$cols = (empty($tmp[2]) ? '80' : $tmp[2]);
391
			}
392
			elseif (preg_match('/^ckeditor/', $inputType))
393
			{
394
				$tmp = explode(':', $inputType);
395
				$inputType = $tmp[0]; $toolbar = $tmp[1];
396
				if (!empty($tmp[2])) $width = $tmp[2];
397
				if (!empty($tmp[3])) $heigth = $tmp[3];
398
				if (!empty($tmp[4])) $savemethod = $tmp[4];
399
400
				if (!empty($conf->fckeditor->enabled))
401
				{
402
					$out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
403
				}
404
				else
405
				{
406
					$inputType = 'textarea';
407
				}
408
			}
409
410
			$out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
411
			$out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
412
			$out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
413
			$out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
414
			if (!empty($savemethod))	$out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
415
			if (!empty($ext_element))	$out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
416
			if (!empty($custommsg))
417
			{
418
				if (is_array($custommsg))
419
				{
420
					if (!empty($custommsg['success']))
421
						$out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
422
					if (!empty($custommsg['error']))
423
						$out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
424
				}
425
				else
426
					$out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
427
			}
428
			if ($inputType == 'textarea') {
429
				$out .= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rows does not seem to be defined for all execution paths leading up to this point.
Loading history...
430
				$out .= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $cols does not seem to be defined for all execution paths leading up to this point.
Loading history...
431
			}
432
			$out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
433
			$out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n";
434
		}
435
		else
436
		{
437
			$out = $value;
438
		}
439
440
		return $out;
441
	}
442
443
	/**
444
	 *	Show a text and picto with tooltip on text or picto.
445
	 *  Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip
446
	 *
447
	 *	@param	string		$text				Text to show
448
	 *	@param	string		$htmltext			HTML content of tooltip. Must be HTML/UTF8 encoded.
449
	 *	@param	int			$tooltipon			1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2
450
	 *	@param	int			$direction			-1=image is before, 0=no image, 1=image is after
451
	 *	@param	string		$img				Html code for image (use img_xxx() function to get it)
452
	 *	@param	string		$extracss			Add a CSS style to td tags
453
	 *	@param	int			$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
454
	 *	@param	string		$incbefore			Include code before the text
455
	 *	@param	int			$noencodehtmltext	Do not encode into html entity the htmltext
456
	 *  @param  string      $tooltiptrigger		''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key)
457
	 *  @param	int			$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
458
	 *	@return	string							Code html du tooltip (texte+picto)
459
	 *	@see	textwithpicto() Use thisfunction if you can.
460
	 *  TODO Move this as static as soon as everybody use textwithpicto or @Form::textwithtooltip
461
	 */
462
    public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
463
	{
464
		global $conf;
465
466
		if ($incbefore) $text = $incbefore.$text;
467
		if (!$htmltext) return $text;
468
469
		$tag = 'td';
470
		if ($notabs == 2) $tag = 'div';
471
		if ($notabs == 3) $tag = 'span';
472
		// Sanitize tooltip
473
		//$htmltext=str_replace("\\","\\\\",$htmltext);
474
		$htmltext = str_replace("\r", "", $htmltext);
475
		$htmltext = str_replace("\n", "", $htmltext);
476
477
		$extrastyle = '';
478
		if ($direction < 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-left: 3px !important;'; }
479
		if ($direction > 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-right: 3px !important;'; }
480
481
		$classfortooltip = 'classfortooltip';
482
483
		$s = ''; $textfordialog = '';
484
485
		if ($tooltiptrigger == '')
486
		{
487
			$htmltext = str_replace('"', "&quot;", $htmltext);
488
		}
489
		else
490
		{
491
			$classfortooltip = 'classfortooltiponclick';
492
			$textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
493
		}
494
		if ($tooltipon == 2 || $tooltipon == 3)
495
		{
496
			$paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
497
			if ($tooltiptrigger == '') $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
498
			else $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
499
		}
500
		else $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
501
		if ($tooltipon == 1 || $tooltipon == 3)
502
		{
503
			$paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
504
			if ($tooltiptrigger == '') $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
505
			else $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
506
		}
507
		else $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
508
		if (empty($notabs)) $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
509
		elseif ($notabs == 2) $s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">';
510
		// Define value if value is before
511
		if ($direction < 0) {
512
			$s .= '<'.$tag.$paramfortooltipimg;
513
			if ($tag == 'td') {
514
				$s .= ' class=valigntop" width="14"';
515
			}
516
			$s .= '>'.$textfordialog.$img.'</'.$tag.'>';
517
		}
518
		// Use another method to help avoid having a space in value in order to use this value with jquery
519
		// Define label
520
		if ((string) $text != '') $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
521
		// Define value if value is after
522
		if ($direction > 0) {
523
			$s .= '<'.$tag.$paramfortooltipimg;
524
			if ($tag == 'td') $s .= ' class="valignmiddle" width="14"';
525
			$s .= '>'.$textfordialog.$img.'</'.$tag.'>';
526
		}
527
		if (empty($notabs)) $s .= '</tr></table>';
528
		elseif ($notabs == 2) $s .= '</div>';
529
530
		return $s;
531
	}
532
533
	/**
534
	 *	Show a text with a picto and a tooltip on picto
535
	 *
536
	 *	@param	string	$text				Text to show
537
	 *	@param  string	$htmltext	     	Content of tooltip
538
	 *	@param	int		$direction			1=Icon is after text, -1=Icon is before text, 0=no icon
539
	 * 	@param	string	$type				Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none'
540
	 *  @param  string	$extracss           Add a CSS style to td, div or span tag
541
	 *  @param  int		$noencodehtmltext   Do not encode into html entity the htmltext
542
	 *  @param	int		$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
543
	 *  @param  string  $tooltiptrigger     ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key, clickable link is on image or on link if param $type='none' or on both if $type='xxxclickable')
544
	 *  @param	int		$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
545
	 * 	@return	string						HTML code of text, picto, tooltip
546
	 */
547
    public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
548
	{
549
		global $conf, $langs;
550
551
		$alt = '';
552
		if ($tooltiptrigger) $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
553
554
		//For backwards compatibility
555
		if ($type == '0') $type = 'info';
556
		elseif ($type == '1') $type = 'help';
557
558
		// If info or help with no javascript, show only text
559
		if (empty($conf->use_javascript_ajax))
560
		{
561
			if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable')	return $text;
562
			else
563
			{
564
				$alt = $htmltext;
565
				$htmltext = '';
566
			}
567
		}
568
569
		// If info or help with smartphone, show only text (tooltip hover can't works)
570
		if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger))
571
		{
572
			if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') return $text;
573
		}
574
		// If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
575
		//if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
576
		//{
577
			//if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>';
578
		//}
579
580
		$img = '';
581
		if ($type == 'info') $img = img_help(0, $alt);
582
		elseif ($type == 'help') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
583
		elseif ($type == 'helpclickable') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
584
		elseif ($type == 'superadmin') $img = img_picto($alt, 'redstar');
585
		elseif ($type == 'admin') $img = img_picto($alt, 'star');
586
		elseif ($type == 'warning') $img = img_warning($alt);
587
		elseif ($type != 'none') $img = img_picto($alt, $type); // $type can be an image path
588
589
		return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
590
	}
591
592
	/**
593
	 * Generate select HTML to choose massaction
594
	 *
595
	 * @param	string	$selected		Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default.
596
	 * @param	array		$arrayofaction	array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action.
597
	 * @param   int     $alwaysvisible  1=select button always visible
598
	 * @return	string|void					Select list
599
	 */
600
    public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0)
601
	{
602
		global $conf, $langs, $hookmanager;
603
604
605
		$disabled = 0;
606
		$ret = '<div class="centpercent center">';
607
		$ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' massaction massactionselect valignmiddle" name="massaction"'.($disabled ? ' disabled="disabled"' : '').'>';
608
609
		// 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.
610
		$parameters = array();
611
		$reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
612
		// check if there is a mass action
613
		if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) return;
614
		if (empty($reshook))
615
		{
616
			$ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
617
			foreach ($arrayofaction as $code => $label)
618
			{
619
				$ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
620
			}
621
		}
622
		$ret .= $hookmanager->resPrint;
623
624
		$ret .= '</select>';
625
626
		if (empty($conf->dol_optimize_smallscreen)) $ret .= ajax_combobox('.massactionselect');
627
628
		// 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
629
		$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.
630
		$ret .= '<input type="submit" disabled name="confirmmassaction" class="button'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' massaction massactionconfirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
631
		$ret .= '</div>';
632
633
		if (!empty($conf->use_javascript_ajax))
634
		{
635
			$ret .= '<!-- JS CODE TO ENABLE mass action select -->
636
    		<script>
637
        		function initCheckForSelect(mode)	/* mode is 0 during init of page or click all, 1 when we click on 1 checkbox */
638
        		{
639
        			atleastoneselected=0;
640
    	    		jQuery(".checkforselect").each(function( index ) {
641
    	  				/* console.log( index + ": " + $( this ).text() ); */
642
    	  				if ($(this).is(\':checked\')) atleastoneselected++;
643
    	  			});
644
					console.log("initCheckForSelect mode="+mode+" atleastoneselected="+atleastoneselected);
645
    	  			if (atleastoneselected || '.$alwaysvisible.')
646
    	  			{
647
    	  				jQuery(".massaction").show();
648
        			    '.($selected ? 'if (atleastoneselected) { jQuery(".massactionselect").val("'.$selected.'"); jQuery(".massactionconfirmed").prop(\'disabled\', false); }' : '').'
649
        			    '.($selected ? 'if (! atleastoneselected) { jQuery(".massactionselect").val("0"); jQuery(".massactionconfirmed").prop(\'disabled\', true); } ' : '').'
650
    	  			}
651
    	  			else
652
    	  			{
653
    	  				jQuery(".massaction").hide();
654
    	            }
655
        		}
656
657
        	jQuery(document).ready(function () {
658
        		initCheckForSelect(0);
659
        		jQuery(".checkforselect").click(function() {
660
        			initCheckForSelect(1);
661
    	  		});
662
    	  		jQuery(".massactionselect").change(function() {
663
        			var massaction = $( this ).val();
664
        			var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
665
        			if (massaction == "builddoc")
666
                    {
667
                        urlform = urlform + "#show_files";
668
    	            }
669
        			$( this ).closest("form").attr("action", urlform);
670
                    console.log("we select a mass action "+massaction+" - "+urlform);
671
        	        /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
672
        			if ($(this).val() != \'0\')
673
    	  			{
674
    	  				jQuery(".massactionconfirmed").prop(\'disabled\', false);
675
    	  			}
676
    	  			else
677
    	  			{
678
    	  				jQuery(".massactionconfirmed").prop(\'disabled\', true);
679
    	  			}
680
    	        });
681
        	});
682
    		</script>
683
        	';
684
		}
685
686
		return $ret;
687
	}
688
689
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
690
	/**
691
	 *  Return combo list of activated countries, into language of user
692
	 *
693
	 *  @param	string	$selected       		Id or Code or Label of preselected country
694
	 *  @param  string	$htmlname       		Name of html select object
695
	 *  @param  string	$htmloption     		More html options on select object
696
	 *  @param	integer	$maxlength				Max length for labels (0=no limit)
697
	 *  @param	string	$morecss				More css class
698
	 *  @param	string	$usecodeaskey			''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
699
	 *  @param	int		$showempty				Show empty choice
700
	 *  @param	int		$disablefavorites		1=Disable favorites,
701
	 *  @param	int		$addspecialentries		1=Add dedicated entries for group of countries (like 'European Economic Community', ...)
702
	 *  @param	array	$exclude_country_code	Array of country code (iso2) to exclude
703
	 *  @return string           				HTML string with select
704
	 */
705
    public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array())
706
	{
707
        // phpcs:enable
708
		global $conf, $langs, $mysoc;
709
710
		$langs->load("dict");
711
712
		$out = '';
713
		$countryArray = array();
714
		$favorite = array();
715
		$label = array();
716
		$atleastonefavorite = 0;
717
718
		$sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
719
		$sql .= " FROM ".MAIN_DB_PREFIX."c_country";
720
		$sql .= " WHERE active > 0";
721
		//$sql.= " ORDER BY code ASC";
722
723
		dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
724
		$resql = $this->db->query($sql);
725
		if ($resql)
726
		{
727
			$out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
728
			$num = $this->db->num_rows($resql);
729
			$i = 0;
730
			if ($num)
731
			{
732
				$foundselected = false;
733
734
				while ($i < $num)
735
				{
736
					$obj = $this->db->fetch_object($resql);
737
738
					$countryArray[$i]['rowid'] = $obj->rowid;
739
					$countryArray[$i]['code_iso'] = $obj->code_iso;
740
					$countryArray[$i]['code_iso3'] 	= $obj->code_iso3;
741
					$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 : ''));
742
					$countryArray[$i]['favorite']   = $obj->favorite;
743
					$favorite[$i] = $obj->favorite;
744
					$label[$i] = dol_string_unaccent($countryArray[$i]['label']);
745
					$i++;
746
				}
747
748
				if (empty($disablefavorites)) array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
749
				else $countryArray = dol_sort_array($countryArray, 'label');
750
751
				if ($showempty)
752
				{
753
					$out .= '<option value="">&nbsp;</option>'."\n";
754
				}
755
756
				if ($addspecialentries)	// Add dedicated entries for groups of countries
757
				{
758
					//if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
759
					$out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
760
					$out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
761
					if ($mysoc->isInEEC()) $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
762
					$out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
763
					$out .= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
764
				}
765
766
				foreach ($countryArray as $row)
767
				{
768
					//if (empty($showempty) && empty($row['rowid'])) continue;
769
					if (empty($row['rowid'])) continue;
770
					if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) continue; // exclude some countries
771
772
					if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) $atleastonefavorite++;
773
					if (empty($row['favorite']) && $atleastonefavorite)
774
					{
775
						$atleastonefavorite = 0;
776
						$out .= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
777
					}
778
					if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label']))
779
					{
780
						$foundselected = true;
781
						$out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" selected>';
782
					}
783
					else
784
					{
785
						$out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'">';
786
					}
787
					if ($row['label']) $out .= dol_trunc($row['label'], $maxlength, 'middle');
788
					else $out .= '&nbsp;';
789
					if ($row['code_iso']) $out .= ' ('.$row['code_iso'].')';
790
					$out .= '</option>';
791
				}
792
			}
793
			$out .= '</select>';
794
		}
795
		else
796
		{
797
			dol_print_error($this->db);
798
		}
799
800
		// Make select dynamic
801
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
802
		$out .= ajax_combobox('select'.$htmlname);
803
804
		return $out;
805
	}
806
807
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
808
	/**
809
	 *  Return select list of incoterms
810
	 *
811
	 *  @param	string	$selected       		Id or Code of preselected incoterm
812
	 *  @param	string	$location_incoterms     Value of input location
813
	 *  @param	string	$page       			Defined the form action
814
	 *  @param  string	$htmlname       		Name of html select object
815
	 *  @param  string	$htmloption     		Options html on select object
816
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
817
	 *  @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')))
818
	 *  @return string           				HTML string with select and input
819
	 */
820
    public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array())
821
	{
822
        // phpcs:enable
823
		global $conf, $langs;
824
825
		$langs->load("dict");
826
827
		$out = '';
828
		$incotermArray = array();
829
830
		$sql = "SELECT rowid, code";
831
		$sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms";
832
		$sql .= " WHERE active > 0";
833
		$sql .= " ORDER BY code ASC";
834
835
		dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
836
		$resql = $this->db->query($sql);
837
		if ($resql)
838
		{
839
			if ($conf->use_javascript_ajax && !$forcecombo)
840
			{
841
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
842
				$out .= ajax_combobox($htmlname, $events);
843
			}
844
845
			if (!empty($page))
846
			{
847
				$out .= '<form method="post" action="'.$page.'">';
848
				$out .= '<input type="hidden" name="action" value="set_incoterms">';
849
				$out .= '<input type="hidden" name="token" value="'.newToken().'">';
850
			}
851
852
			$out .= '<select id="'.$htmlname.'" class="flat selectincoterm minwidth100imp noenlargeonsmartphone" name="'.$htmlname.'" '.$htmloption.'>';
853
			$out .= '<option value="0">&nbsp;</option>';
854
			$num = $this->db->num_rows($resql);
855
			$i = 0;
856
			if ($num)
857
			{
858
				$foundselected = false;
859
860
				while ($i < $num)
861
				{
862
					$obj = $this->db->fetch_object($resql);
863
					$incotermArray[$i]['rowid'] = $obj->rowid;
864
					$incotermArray[$i]['code'] = $obj->code;
865
					$i++;
866
				}
867
868
				foreach ($incotermArray as $row)
869
				{
870
					if ($selected && ($selected == $row['rowid'] || $selected == $row['code']))
871
					{
872
						$out .= '<option value="'.$row['rowid'].'" selected>';
873
					}
874
					else
875
					{
876
						$out .= '<option value="'.$row['rowid'].'">';
877
					}
878
879
					if ($row['code']) $out .= $row['code'];
880
881
					$out .= '</option>';
882
				}
883
			}
884
			$out .= '</select>';
885
886
			$out .= '<input id="location_incoterms" class="maxwidth100onsmartphone" name="location_incoterms" value="'.$location_incoterms.'">';
887
888
			if (!empty($page))
889
			{
890
				$out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'"></form>';
891
			}
892
		}
893
		else
894
		{
895
			dol_print_error($this->db);
896
		}
897
898
		return $out;
899
	}
900
901
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
902
	/**
903
	 *	Return list of types of lines (product or service)
904
	 * 	Example: 0=product, 1=service, 9=other (for external module)
905
	 *
906
	 *	@param  string	$selected       Preselected type
907
	 *	@param  string	$htmlname       Name of field in html form
908
	 * 	@param	int		$showempty		Add an empty field
909
	 * 	@param	int		$hidetext		Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
910
	 * 	@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')
911
	 *  @return	void
912
	 */
913
    public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
914
	{
915
        // phpcs:enable
916
		global $db, $langs, $user, $conf;
917
918
		// If product & services are enabled or both disabled.
919
		if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
920
		|| (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled)))
921
		{
922
			if (empty($hidetext)) print $langs->trans("Type").': ';
923
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
924
			if ($showempty)
925
			{
926
				print '<option value="-1"';
927
				if ($selected == -1) print ' selected';
928
				print '>&nbsp;</option>';
929
			}
930
931
			print '<option value="0"';
932
			if (0 == $selected) print ' selected';
933
			print '>'.$langs->trans("Product");
934
935
			print '<option value="1"';
936
			if (1 == $selected) print ' selected';
937
			print '>'.$langs->trans("Service");
938
939
			print '</select>';
940
			//if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
941
		}
942
		if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3)
943
		{
944
			print $langs->trans("Service");
945
			print '<input type="hidden" name="'.$htmlname.'" value="1">';
946
		}
947
		if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2)
948
		{
949
			print $langs->trans("Product");
950
			print '<input type="hidden" name="'.$htmlname.'" value="0">';
951
		}
952
		if ($forceall < 0)	// This should happened only for contracts when both predefined product and service are disabled.
953
		{
954
			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
955
		}
956
	}
957
958
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
959
	/**
960
	 *	Load into cache cache_types_fees, array of types of fees
961
	 *
962
	 *	@return     int             Nb of lines loaded, <0 if KO
963
	 */
964
    public function load_cache_types_fees()
965
	{
966
        // phpcs:enable
967
		global $langs;
968
969
		$num = count($this->cache_types_fees);
970
		if ($num > 0) return 0; // Cache already loaded
971
972
		dol_syslog(__METHOD__, LOG_DEBUG);
973
974
		$langs->load("trips");
975
976
		$sql = "SELECT c.code, c.label";
977
		$sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
978
		$sql .= " WHERE active > 0";
979
980
		$resql = $this->db->query($sql);
981
		if ($resql)
982
		{
983
			$num = $this->db->num_rows($resql);
984
			$i = 0;
985
986
			while ($i < $num)
987
			{
988
				$obj = $this->db->fetch_object($resql);
989
990
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
991
				$label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
992
				$this->cache_types_fees[$obj->code] = $label;
993
				$i++;
994
			}
995
996
			asort($this->cache_types_fees);
997
998
			return $num;
999
		}
1000
		else
1001
		{
1002
			dol_print_error($this->db);
1003
			return -1;
1004
		}
1005
	}
1006
1007
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1008
	/**
1009
	 *	Return list of types of notes
1010
	 *
1011
	 *	@param	string		$selected		Preselected type
1012
	 *	@param  string		$htmlname		Name of field in form
1013
	 * 	@param	int			$showempty		Add an empty field
1014
	 * 	@return	void
1015
	 */
1016
    public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1017
	{
1018
        // phpcs:enable
1019
		global $user, $langs;
1020
1021
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1022
1023
		$this->load_cache_types_fees();
1024
1025
		print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1026
		if ($showempty)
1027
		{
1028
			print '<option value="-1"';
1029
			if ($selected == -1) print ' selected';
1030
			print '>&nbsp;</option>';
1031
		}
1032
1033
		foreach ($this->cache_types_fees as $key => $value)
1034
		{
1035
			print '<option value="'.$key.'"';
1036
			if ($key == $selected) print ' selected';
1037
			print '>';
1038
			print $value;
1039
			print '</option>';
1040
		}
1041
1042
		print '</select>';
1043
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1044
	}
1045
1046
1047
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1048
	/**
1049
	 *  Return HTML code to select a company.
1050
	 *
1051
	 *  @param		int			$selected				Preselected products
1052
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page)
1053
	 *  @param		int			$filter					Filter on thirdparty
1054
	 *  @param		int			$limit					Limit on number of returned lines
1055
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
1056
	 * 	@param		int			$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1057
	 *  @return		string								Return select box for thirdparty.
1058
	 *  @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)
1059
	 */
1060
    public function select_thirdparty($selected = '', $htmlname = 'socid', $filter = '', $limit = 20, $ajaxoptions = array(), $forcecombo = 0)
1061
	{
1062
        // phpcs:enable
1063
   		return $this->select_thirdparty_list($selected, $htmlname, $filter, 1, 0, $forcecombo, array(), '', 0, $limit);
1064
	}
1065
1066
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1067
	/**
1068
	 *  Output html form to select a third party
1069
	 *
1070
	 *	@param	string	$selected       		Preselected type
1071
	 *	@param  string	$htmlname       		Name of field in form
1072
	 *  @param  string	$filter         		Optional filters criteras. WARNING: To avoid SQL injection, only few chars [.a-z0-9 =<>] are allowed here (example: 's.rowid <> x', 's.client IN (1,3)')
1073
	 *	@param	string	$showempty				Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty')
1074
	 * 	@param	int		$showtype				Show third party type in combolist (customer, prospect or supplier)
1075
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1076
	 *  @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')))
1077
	 *	@param	int		$limit					Maximum number of elements
1078
	 *  @param	string	$morecss				Add more css styles to the SELECT component
1079
	 *	@param  string	$moreparam      		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1080
	 *	@param	string	$selected_input_value	Value of preselected input text (for use with ajax)
1081
	 *  @param	int		$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1082
	 *  @param	array	$ajaxoptions			Options for ajax_autocompleter
1083
	 * 	@param  bool	$multiple				add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
1084
	 * 	@return	string							HTML string with select box for thirdparty.
1085
	 */
1086
    public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false)
1087
	{
1088
        // phpcs:enable
1089
		global $conf, $user, $langs;
1090
1091
		$out = '';
1092
1093
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo)
1094
		{
1095
			// No immediate load of all database
1096
			$placeholder = '';
1097
			if ($selected && empty($selected_input_value))
1098
			{
1099
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1100
				$societetmp = new Societe($this->db);
1101
				$societetmp->fetch($selected);
1102
				$selected_input_value = $societetmp->name;
1103
				unset($societetmp);
1104
			}
1105
			// mode 1
1106
			$urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).($showtype ? '&showtype='.urlencode($showtype) : '');
1107
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1108
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
1109
			if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1110
			elseif ($hidelabel > 1) {
1111
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
1112
				if ($hidelabel == 2) {
1113
					$out .= img_picto($langs->trans("Search"), 'search');
1114
				}
1115
			}
1116
			$out .= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1117
			if ($hidelabel == 3) {
1118
				$out .= img_picto($langs->trans("Search"), 'search');
1119
			}
1120
		}
1121
		else
1122
		{
1123
			// Immediate load of all database
1124
			$out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple);
1125
		}
1126
1127
		return $out;
1128
	}
1129
1130
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1131
	/**
1132
	 *  Output html form to select a third party.
1133
	 *  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.
1134
	 *
1135
	 *	@param	string	$selected       Preselected type
1136
	 *	@param  string	$htmlname       Name of field in form
1137
	 *  @param  string	$filter         Optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)')
1138
	 *	@param	string	$showempty		Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty')
1139
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
1140
	 * 	@param	int		$forcecombo		Force to use standard HTML select component without beautification
1141
	 *  @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')))
1142
	 *  @param	string	$filterkey		Filter on key value
1143
	 *  @param	int		$outputmode		0=HTML select string, 1=Array
1144
	 *  @param	int		$limit			Limit number of answers
1145
	 *  @param	string	$morecss		Add more css styles to the SELECT component
1146
	 *	@param  string	$moreparam      Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1147
	 *	@param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1148
	 * 	@return	string					HTML string with
1149
	 */
1150
    public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false)
1151
	{
1152
        // phpcs:enable
1153
		global $conf, $user, $langs;
1154
1155
		$out = '';
1156
		$num = 0;
1157
		$outarray = array();
1158
1159
		if ($selected === '') $selected = array();
1160
		elseif (!is_array($selected)) $selected = array($selected);
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
1161
1162
		// Clean $filter that may contains sql conditions so sql code
1163
		if (function_exists('testSqlAndScriptInject')) {
1164
			if (testSqlAndScriptInject($filter, 3) > 0) {
1165
				$filter = '';
1166
			}
1167
		}
1168
1169
		// On recherche les societes
1170
		$sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1171
1172
		if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1173
			$sql .= ", s.address, s.zip, s.town";
1174
		 	$sql .= ", dictp.code as country_code";
1175
		}
1176
1177
		$sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
1178
		if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1179
		if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1180
			$sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid=s.fk_pays";
1181
		}
1182
		$sql .= " WHERE s.entity IN (".getEntity('societe').")";
1183
		if (!empty($user->socid)) $sql .= " AND s.rowid = ".$user->socid;
1184
		if ($filter) $sql .= " AND (".$filter.")";
1185
		if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
1186
		if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND s.status <> 0";
1187
		// Add criteria
1188
		if ($filterkey && $filterkey != '')
1189
		{
1190
			$sql .= " AND (";
1191
			$prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1192
			// For natural search
1193
			$scrit = explode(' ', $filterkey);
1194
			$i = 0;
1195
			if (count($scrit) > 1) $sql .= "(";
1196
			foreach ($scrit as $crit) {
1197
				if ($i > 0) $sql .= " AND ";
1198
				$sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1199
				$i++;
1200
			}
1201
			if (count($scrit) > 1) $sql .= ")";
1202
			if (!empty($conf->barcode->enabled))
1203
			{
1204
				$sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1205
			}
1206
			$sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1207
			$sql .= ")";
1208
		}
1209
		$sql .= $this->db->order("nom", "ASC");
1210
		$sql .= $this->db->plimit($limit, 0);
1211
1212
		// Build output string
1213
		dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1214
		$resql = $this->db->query($sql);
1215
		if ($resql)
1216
		{
1217
		   	if (!$forcecombo)
1218
			{
1219
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1220
				$out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
1221
			}
1222
1223
			// Construct $out and $outarray
1224
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1225
1226
			$textifempty = '';
1227
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1228
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1229
			if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT))
1230
			{
1231
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
1232
				else $textifempty .= $langs->trans("All");
1233
			}
1234
			if ($showempty) $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
1235
1236
			$num = $this->db->num_rows($resql);
1237
			$i = 0;
1238
			if ($num)
1239
			{
1240
				while ($i < $num)
1241
				{
1242
					$obj = $this->db->fetch_object($resql);
1243
					$label = '';
1244
					if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1245
						if (($obj->client) && (!empty($obj->code_client))) {
1246
							$label = $obj->code_client.' - ';
1247
						}
1248
						if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1249
							$label .= $obj->code_fournisseur.' - ';
1250
						}
1251
						$label .= ' '.$obj->name;
1252
					}
1253
					else
1254
					{
1255
						$label = $obj->name;
1256
					}
1257
1258
					if (!empty($obj->name_alias)) {
1259
						$label .= ' ('.$obj->name_alias.')';
1260
					}
1261
1262
					if ($showtype)
1263
					{
1264
						if ($obj->client || $obj->fournisseur) $label .= ' (';
1265
						if ($obj->client == 1 || $obj->client == 3) $label .= $langs->trans("Customer");
1266
						if ($obj->client == 2 || $obj->client == 3) $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1267
						if ($obj->fournisseur) $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1268
						if ($obj->client || $obj->fournisseur) $label .= ')';
1269
					}
1270
1271
					if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1272
						$label .= '-'.$obj->address.'-'.$obj->zip.' '.$obj->town;
1273
						if (!empty($obj->country_code)) {
1274
							$label .= ' '.$langs->trans('Country'.$obj->country_code);
1275
						}
1276
					}
1277
1278
					if (empty($outputmode))
1279
					{
1280
						if (in_array($obj->rowid, $selected))
1281
						{
1282
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1283
						}
1284
						else
1285
						{
1286
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1287
						}
1288
					}
1289
					else
1290
					{
1291
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1292
					}
1293
1294
					$i++;
1295
					if (($i % 10) == 0) $out .= "\n";
1296
				}
1297
			}
1298
			$out .= '</select>'."\n";
1299
		}
1300
		else
1301
		{
1302
			dol_print_error($this->db);
1303
		}
1304
1305
		$this->result = array('nbofthirdparties'=>$num);
1306
1307
		if ($outputmode) return $outarray;
1308
		return $out;
1309
	}
1310
1311
1312
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1313
	/**
1314
	 *  Return HTML combo list of absolute discounts
1315
	 *
1316
	 *  @param	string	$selected       Id remise fixe pre-selectionnee
1317
	 *  @param  string	$htmlname       Nom champ formulaire
1318
	 *  @param  string	$filter         Criteres optionnels de filtre
1319
	 *  @param	int		$socid			Id of thirdparty
1320
	 *  @param	int		$maxvalue		Max value for lines that can be selected
1321
	 *  @return	int						Return number of qualifed lines in list
1322
	 */
1323
    public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1324
	{
1325
        // phpcs:enable
1326
		global $langs, $conf;
1327
1328
		// On recherche les remises
1329
		$sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1330
		$sql .= " re.description, re.fk_facture_source";
1331
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
1332
		$sql .= " WHERE re.fk_soc = ".(int) $socid;
1333
		$sql .= " AND re.entity = ".$conf->entity;
1334
		if ($filter) $sql .= " AND ".$filter;
1335
		$sql .= " ORDER BY re.description ASC";
1336
1337
		dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1338
		$resql = $this->db->query($sql);
1339
		if ($resql)
1340
		{
1341
			print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1342
			$num = $this->db->num_rows($resql);
1343
1344
			$qualifiedlines = $num;
1345
1346
			$i = 0;
1347
			if ($num)
1348
			{
1349
				print '<option value="0">&nbsp;</option>';
1350
				while ($i < $num)
1351
				{
1352
					$obj = $this->db->fetch_object($resql);
1353
					$desc = dol_trunc($obj->description, 40);
1354
					if (preg_match('/\(CREDIT_NOTE\)/', $desc)) $desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1355
					if (preg_match('/\(DEPOSIT\)/', $desc)) $desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1356
					if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) $desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1357
					if (preg_match('/\(EXCESS PAID\)/', $desc)) $desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1358
1359
					$selectstring = '';
1360
					if ($selected > 0 && $selected == $obj->rowid) $selectstring = ' selected';
1361
1362
					$disabled = '';
1363
					if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue)
1364
					{
1365
						$qualifiedlines--;
1366
						$disabled = ' disabled';
1367
					}
1368
1369
					if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source))
1370
					{
1371
						$tmpfac = new Facture($this->db);
1372
						if ($tmpfac->fetch($obj->fk_facture_source) > 0) $desc = $desc.' - '.$tmpfac->ref;
1373
					}
1374
1375
					print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1376
					$i++;
1377
				}
1378
			}
1379
			print '</select>';
1380
			return $qualifiedlines;
1381
		}
1382
		else
1383
		{
1384
			dol_print_error($this->db);
1385
			return -1;
1386
		}
1387
	}
1388
1389
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1390
	/**
1391
	 *  Return list of all contacts (for a third party or all)
1392
	 *
1393
	 *  @param	int		$socid      	Id ot third party or 0 for all
1394
	 *  @param  string	$selected   	Id contact pre-selectionne
1395
	 *  @param  string	$htmlname  	    Name of HTML field ('none' for a not editable field)
1396
	 *  @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
1397
	 *  @param  string	$exclude        List of contacts id to exclude
1398
	 *  @param	string	$limitto		Disable answers that are not id in this array list
1399
	 *  @param	integer	$showfunction   Add function into label
1400
	 *  @param	string	$moreclass		Add more class to class style
1401
	 *  @param	integer	$showsoc	    Add company into label
1402
	 *  @param	int		$forcecombo		Force to use combo box
1403
	 *  @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')))
1404
	 *  @param	bool	$options_only	Return options only (for ajax treatment)
1405
	 *  @param	string	$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1406
	 *  @param	string	$htmlid			Html id to use instead of htmlname
1407
	 *  @return	int						<0 if KO, Nb of contact in list if OK
1408
	 *  @deprected						You can use selectcontacts directly (warning order of param was changed)
1409
	 */
1410
    public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1411
    {
1412
        // phpcs:enable
1413
		print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1414
		return $this->num;
1415
    }
1416
1417
	/**
1418
	 *	Return HTML code of the SELECT of list of all contacts (for a third party or all).
1419
	 *  This also set the number of contacts found into $this->num
1420
	 *
1421
	 * @since 9.0 Add afterSelectContactOptions hook
1422
	 *
1423
	 *	@param	int			$socid      	Id ot third party or 0 for all or -1 for empty list
1424
	 *	@param  array|int	$selected   	Array of ID of pre-selected contact id
1425
	 *	@param  string		$htmlname  	    Name of HTML field ('none' for a not editable field)
1426
	 *	@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
1427
	 *	@param  string		$exclude        List of contacts id to exclude
1428
	 *	@param	string		$limitto		Disable answers that are not id in this array list
1429
	 *	@param	integer		$showfunction   Add function into label
1430
	 *	@param	string		$moreclass		Add more class to class style
1431
	 *	@param	bool		$options_only	Return options only (for ajax treatment)
1432
	 *	@param	integer		$showsoc	    Add company into label
1433
	 * 	@param	int			$forcecombo		Force to use combo box (so no ajax beautify effect)
1434
	 *  @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')))
1435
	 *  @param	string		$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1436
	 *  @param	string		$htmlid			Html id to use instead of htmlname
1437
	 *  @param	bool		$multiple		add [] in the name of element and add 'multiple' attribut
1438
	 *	@return	 int						<0 if KO, Nb of contact in list if OK
1439
	 */
1440
    public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false)
1441
    {
1442
		global $conf, $langs, $hookmanager, $action;
1443
1444
		$langs->load('companies');
1445
1446
		if (empty($htmlid)) $htmlid = $htmlname;
1447
1448
		if ($selected === '') $selected = array();
1449
		elseif (!is_array($selected)) $selected = array($selected);
1450
		$out = '';
1451
1452
		if (!is_object($hookmanager))
1453
		{
1454
			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1455
			$hookmanager = new HookManager($this->db);
1456
		}
1457
1458
		// We search third parties
1459
		$sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste";
1460
		if ($showsoc > 0) $sql .= " , s.nom as company";
1461
		$sql .= " FROM ".MAIN_DB_PREFIX."socpeople as sp";
1462
		if ($showsoc > 0) $sql .= " LEFT OUTER JOIN  ".MAIN_DB_PREFIX."societe as s ON s.rowid=sp.fk_soc";
1463
		$sql .= " WHERE sp.entity IN (".getEntity('socpeople').")";
1464
		if ($socid > 0 || $socid == -1) $sql .= " AND sp.fk_soc=".$socid;
1465
		if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND sp.statut <> 0";
1466
		$sql .= " ORDER BY sp.lastname ASC";
1467
1468
		dol_syslog(get_class($this)."::select_contacts", LOG_DEBUG);
1469
		$resql = $this->db->query($sql);
1470
		if ($resql)
1471
		{
1472
			$num = $this->db->num_rows($resql);
1473
1474
			if ($conf->use_javascript_ajax && !$forcecombo && !$options_only)
1475
			{
1476
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1477
				$out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
1478
			}
1479
1480
			if ($htmlname != 'none' && !$options_only) $out .= '<select class="flat'.($moreclass ? ' '.$moreclass : '').'" id="'.$htmlid.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1481
			if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1482
			if ($showempty == 2) $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>'.$langs->trans("Internal").'</option>';
1483
1484
			$num = $this->db->num_rows($resql);
1485
			$i = 0;
1486
			if ($num)
1487
			{
1488
				include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1489
				$contactstatic = new Contact($this->db);
1490
1491
				while ($i < $num)
1492
				{
1493
					$obj = $this->db->fetch_object($resql);
1494
1495
					$contactstatic->id = $obj->rowid;
1496
					$contactstatic->lastname = $obj->lastname;
1497
					$contactstatic->firstname = $obj->firstname;
1498
					if ($obj->statut == 1) {
1499
					    if ($htmlname != 'none')
1500
					    {
1501
						    $disabled = 0;
1502
						    if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) $disabled = 1;
1503
						    if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) $disabled = 1;
1504
						    if (!empty($selected) && in_array($obj->rowid, $selected))
1505
						    {
1506
							    $out .= '<option value="'.$obj->rowid.'"';
1507
							    if ($disabled) $out .= ' disabled';
1508
							    $out .= ' selected>';
1509
							    $out .= $contactstatic->getFullName($langs);
1510
							    if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1511
							    if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1512
							    $out .= '</option>';
1513
						    }
1514
						    else
1515
						    {
1516
							    $out .= '<option value="'.$obj->rowid.'"';
1517
							    if ($disabled) $out .= ' disabled';
1518
							    $out .= '>';
1519
							    $out .= $contactstatic->getFullName($langs);
1520
							    if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1521
							    if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1522
							    $out .= '</option>';
1523
						    }
1524
					    }
1525
					    else
1526
					    {
1527
						    if (in_array($obj->rowid, $selected))
1528
						    {
1529
							    $out .= $contactstatic->getFullName($langs);
1530
							    if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1531
							    if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1532
						    }
1533
					    }
1534
				    }
1535
					$i++;
1536
				}
1537
			}
1538
			else
1539
			{
1540
				$out .= '<option value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled>';
1541
				$out .= ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1542
				$out .= '</option>';
1543
			}
1544
1545
			$parameters = array(
1546
				'socid'=>$socid,
1547
				'htmlname'=>$htmlname,
1548
				'resql'=>$resql,
1549
				'out'=>&$out,
1550
				'showfunction'=>$showfunction,
1551
				'showsoc'=>$showsoc,
1552
			);
1553
1554
			$reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1555
1556
			if ($htmlname != 'none' && !$options_only)
1557
			{
1558
				$out .= '</select>';
1559
			}
1560
1561
			$this->num = $num;
1562
			return $out;
1563
		}
1564
		else
1565
		{
1566
			dol_print_error($this->db);
1567
			return -1;
1568
		}
1569
	}
1570
1571
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1572
	/**
1573
	 *	Return select list of users
1574
	 *
1575
	 *  @param	string	$selected       Id user preselected
1576
	 *  @param  string	$htmlname       Field name in form
1577
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
1578
	 *  @param  array	$exclude        Array list of users id to exclude
1579
	 * 	@param	int		$disabled		If select list must be disabled
1580
	 *  @param  array	$include        Array list of users id to include
1581
	 * 	@param	int		$enableonly		Array list of users id to be enabled. All other must be disabled
1582
	 *  @param	string	$force_entity	'0' or Ids of environment to force
1583
	 * 	@return	void
1584
	 *  @deprecated		Use select_dolusers instead
1585
	 *  @see select_dolusers()
1586
	 */
1587
    public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1588
	{
1589
        // phpcs:enable
1590
		print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1591
	}
1592
1593
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1594
	/**
1595
	 *	Return select list of users
1596
	 *
1597
	 *  @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)
1598
	 *  @param  string	$htmlname       Field name in form
1599
	 *  @param  int		$show_empty     0=list with no empty value, 1=add also an empty value into list
1600
	 *  @param  array	$exclude        Array list of users id to exclude
1601
	 * 	@param	int		$disabled		If select list must be disabled
1602
	 *  @param  array|string	$include        Array list of users id to include or 'hierarchy' to have only supervised users or 'hierarchyme' to have supervised + me
1603
	 * 	@param	array	$enableonly		Array list of users id to be enabled. If defined, it means that others will be disabled
1604
	 *  @param	string	$force_entity	'0' or Ids of environment to force
1605
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
1606
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1607
	 *  @param	string	$morefilter		Add more filters into sql request (Example: 'employee = 1')
1608
	 *  @param	integer	$show_every		0=default list, 1=add also a value "Everybody" at beginning of list
1609
	 *  @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.
1610
	 *  @param	string	$morecss		More css
1611
	 *  @param  int     $noactive       Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
1612
	 *  @param  int		$outputmode     0=HTML select string, 1=Array
1613
	 *  @param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1614
	 * 	@return	string					HTML select string
1615
	 *  @see select_dolgroups()
1616
	 */
1617
    public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $noactive = 0, $outputmode = 0, $multiple = false)
1618
	{
1619
        // phpcs:enable
1620
		global $conf, $user, $langs;
1621
1622
		// If no preselected user defined, we take current user
1623
		if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) $selected = $user->id;
1624
1625
		if ($selected === '') $selected = array();
1626
		elseif (!is_array($selected)) $selected = array($selected);
1627
1628
		$excludeUsers = null;
1629
		$includeUsers = null;
1630
1631
		// Permettre l'exclusion d'utilisateurs
1632
		if (is_array($exclude))	$excludeUsers = implode(",", $exclude);
1633
		// Permettre l'inclusion d'utilisateurs
1634
		if (is_array($include))	$includeUsers = implode(",", $include);
1635
		elseif ($include == 'hierarchy')
1636
		{
1637
			// Build list includeUsers to have only hierarchy
1638
			$includeUsers = implode(",", $user->getAllChildIds(0));
1639
		}
1640
		elseif ($include == 'hierarchyme')
1641
		{
1642
			// Build list includeUsers to have only hierarchy and current user
1643
			$includeUsers = implode(",", $user->getAllChildIds(1));
1644
		}
1645
1646
		$out = '';
1647
		$outarray = array();
1648
1649
		// Forge request to select users
1650
		$sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut, u.login, u.admin, u.entity";
1651
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
1652
		{
1653
			$sql .= ", e.label";
1654
		}
1655
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
1656
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
1657
		{
1658
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=u.entity";
1659
			if ($force_entity) $sql .= " WHERE u.entity IN (0,".$force_entity.")";
1660
			else $sql .= " WHERE u.entity IS NOT NULL";
1661
		}
1662
		else
1663
		{
1664
			if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
1665
			{
1666
				$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
1667
				$sql .= " ON ug.fk_user = u.rowid";
1668
				$sql .= " WHERE ug.entity = ".$conf->entity;
1669
			}
1670
			else
1671
			{
1672
				$sql .= " WHERE u.entity IN (0,".$conf->entity.")";
1673
			}
1674
		}
1675
		if (!empty($user->socid)) $sql .= " AND u.fk_soc = ".$user->socid;
1676
		if (is_array($exclude) && $excludeUsers) $sql .= " AND u.rowid NOT IN (".$excludeUsers.")";
1677
		if ($includeUsers) $sql .= " AND u.rowid IN (".$includeUsers.")";
1678
		if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) $sql .= " AND u.statut <> 0";
1679
		if (!empty($morefilter)) $sql .= " ".$morefilter;
1680
1681
		if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))	// MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1682
		{
1683
			$sql .= " ORDER BY u.firstname ASC";
1684
		}
1685
		else
1686
		{
1687
			$sql .= " ORDER BY u.lastname ASC";
1688
		}
1689
1690
		dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1691
		$resql = $this->db->query($sql);
1692
		if ($resql)
1693
		{
1694
			$num = $this->db->num_rows($resql);
1695
			$i = 0;
1696
			if ($num)
1697
			{
1698
		   		// Enhance with select2
1699
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1700
				$out .= ajax_combobox($htmlname);
1701
1702
				// do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1703
				$out .= '<select class="flat'.($morecss ? ' minwidth100imp '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
1704
				if ($show_empty && !$multiple) $out .= '<option value="-1"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>&nbsp;</option>'."\n";
1705
				if ($show_every) $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
1706
1707
				$userstatic = new User($this->db);
1708
1709
				while ($i < $num)
1710
				{
1711
					$obj = $this->db->fetch_object($resql);
1712
1713
					$userstatic->id = $obj->rowid;
1714
					$userstatic->lastname = $obj->lastname;
1715
					$userstatic->firstname = $obj->firstname;
1716
1717
					$disableline = '';
1718
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) $disableline = ($enableonlytext ? $enableonlytext : '1');
1719
1720
					if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected)))
1721
					{
1722
						$out .= '<option value="'.$obj->rowid.'"';
1723
						if ($disableline) $out .= ' disabled';
1724
						$out .= ' selected>';
1725
					}
1726
					else
1727
					{
1728
						$out .= '<option value="'.$obj->rowid.'"';
1729
						if ($disableline) $out .= ' disabled';
1730
						$out .= '>';
1731
					}
1732
1733
					// $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
1734
					$fullNameMode = 0;
1735
					if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))
1736
					{
1737
						$fullNameMode = 1; //Firstname+lastname
1738
					}
1739
					$out .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1740
1741
					// Complete name with more info
1742
					$moreinfo = 0;
1743
					if (!empty($conf->global->MAIN_SHOW_LOGIN))
1744
					{
1745
						$out .= ($moreinfo ? ' - ' : ' (').$obj->login;
1746
						$moreinfo++;
1747
					}
1748
					if ($showstatus >= 0)
1749
					{
1750
						if ($obj->statut == 1 && $showstatus == 1)
1751
						{
1752
							$out .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
1753
							$moreinfo++;
1754
						}
1755
						if ($obj->statut == 0)
1756
						{
1757
							$out .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
1758
							$moreinfo++;
1759
						}
1760
					}
1761
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity)
1762
					{
1763
						if (!$obj->entity)
1764
						{
1765
							$out .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
1766
							$moreinfo++;
1767
						}
1768
						else
1769
						{
1770
							$out .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
1771
							$moreinfo++;
1772
					 	}
1773
					}
1774
					$out .= ($moreinfo ? ')' : '');
1775
					if ($disableline && $disableline != '1')
1776
					{
1777
						$out .= ' - '.$disableline; // This is text from $enableonlytext parameter
1778
					}
1779
					$out .= '</option>';
1780
					$outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1781
1782
					$i++;
1783
				}
1784
			}
1785
			else
1786
			{
1787
				$out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
1788
				$out .= '<option value="">'.$langs->trans("None").'</option>';
1789
			}
1790
			$out .= '</select>';
1791
		}
1792
		else
1793
		{
1794
			dol_print_error($this->db);
1795
		}
1796
1797
		if ($outputmode) return $outarray;
1798
		return $out;
1799
	}
1800
1801
1802
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1803
	/**
1804
	 *	Return select list of users. Selected users are stored into session.
1805
	 *  List of users are provided into $_SESSION['assignedtouser'].
1806
	 *
1807
	 *  @param  string	$action         Value for $action
1808
	 *  @param  string	$htmlname       Field name in form
1809
	 *  @param  int		$show_empty     0=list without the empty value, 1=add empty value
1810
	 *  @param  array	$exclude        Array list of users id to exclude
1811
	 * 	@param	int		$disabled		If select list must be disabled
1812
	 *  @param  array	$include        Array list of users id to include or 'hierarchy' to have only supervised users
1813
	 * 	@param	array	$enableonly		Array list of users id to be enabled. All other must be disabled
1814
	 *  @param	int		$force_entity	'0' or Ids of environment to force
1815
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
1816
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1817
	 *  @param	string	$morefilter		Add more filters into sql request
1818
	 *  @param	int		$showproperties		Show properties of each attendees
1819
	 *  @param	array	$listofuserid		Array with properties of each user
1820
	 *  @param	array	$listofcontactid	Array with properties of each contact
1821
	 *  @param	array	$listofotherid		Array with properties of each other contact
1822
	 * 	@return	string					HTML select string
1823
	 *  @see select_dolgroups()
1824
	 */
1825
    public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array())
1826
	{
1827
        // phpcs:enable
1828
		global $conf, $user, $langs;
1829
1830
		$userstatic = new User($this->db);
1831
		$out = '';
1832
1833
		// Method with no ajax
1834
		//$out.='<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
1835
		if ($action == 'view')
1836
		{
1837
			$out .= '';
1838
		}
1839
		else
1840
		{
1841
			$out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
1842
			$out .= '<script type="text/javascript" language="javascript">jQuery(document).ready(function () {    jQuery(".removedassigned").click(function() {        jQuery(".removedassignedhidden").val(jQuery(this).val());    });})</script>';
1843
			$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
1844
			$out .= ' <input type="submit" class="button valignmiddle" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
1845
			$out .= '<br>';
1846
		}
1847
		$assignedtouser = array();
1848
		if (!empty($_SESSION['assignedtouser']))
1849
		{
1850
			$assignedtouser = json_decode($_SESSION['assignedtouser'], true);
1851
		}
1852
		$nbassignetouser = count($assignedtouser);
1853
1854
		if ($nbassignetouser && $action != 'view') $out .= '<br>';
1855
		if ($nbassignetouser) $out .= '<ul class="attendees">';
1856
		$i = 0; $ownerid = 0;
1857
		foreach ($assignedtouser as $key => $value)
1858
		{
1859
			if ($value['id'] == $ownerid) continue;
1860
1861
			$out .= '<li>';
1862
			$userstatic->fetch($value['id']);
1863
			$out .= $userstatic->getNomUrl(-1);
1864
			if ($i == 0) { $ownerid = $value['id']; $out .= ' ('.$langs->trans("Owner").')'; }
1865
			if ($nbassignetouser > 1 && $action != 'view')
1866
			{
1867
				$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.'">';
1868
			}
1869
			// Show my availability
1870
			if ($showproperties)
1871
			{
1872
				if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid)))
1873
				{
1874
					$out .= '<div class="myavailability inline-block">';
1875
					$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");
1876
					$out .= '</div>';
1877
				}
1878
			}
1879
			//$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
1880
			//$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
1881
1882
			$out .= '</li>';
1883
			$i++;
1884
		}
1885
		if ($nbassignetouser) $out .= '</ul>';
1886
1887
		//$out.='</form>';
1888
		return $out;
1889
	}
1890
1891
1892
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1893
	/**
1894
	 *  Return list of products for customer in Ajax if Ajax activated or go to select_produits_list
1895
	 *
1896
	 *  @param		int			$selected				Preselected products
1897
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page)
1898
	 *  @param		int			$filtertype				Filter on product type (''=nofilter, 0=product, 1=service)
1899
	 *  @param		int			$limit					Limit on number of returned lines
1900
	 *  @param		int			$price_level			Level of price to show
1901
	 *  @param		int			$status					Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell
1902
	 *  @param		int			$finished				2=all, 1=finished, 0=raw material
1903
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
1904
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1905
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
1906
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
1907
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
1908
	 * 	@param		int			$forcecombo				Force to use combo box
1909
	 *  @param      string      $morecss                Add more css on select
1910
	 *  @param      int         $hidepriceinlabel       1=Hide prices in label
1911
	 *  @param      string      $warehouseStatus        Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used
1912
	 *										            'warehouseopen' = count products from open warehouses,
1913
	 *										            'warehouseclosed' = count products from closed warehouses,
1914
	 *										            'warehouseinternal' = count products from warehouses for internal correct/transfer only
1915
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
1916
	 *  @return		void
1917
	 */
1918
    public 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())
1919
	{
1920
        // phpcs:enable
1921
		global $langs, $conf;
1922
1923
		// check parameters
1924
		$price_level = (!empty($price_level) ? $price_level : 0);
1925
		if (is_null($ajaxoptions)) $ajaxoptions = array();
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
1926
1927
		if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
1928
			if (!empty($conf->product->enabled) && empty($conf->service->enabled)) {
1929
				$filtertype = '0';
1930
			}
1931
			elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) {
1932
				$filtertype = '1';
1933
			}
1934
		}
1935
1936
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
1937
		{
1938
			$placeholder = '';
1939
1940
			if ($selected && empty($selected_input_value))
1941
			{
1942
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1943
				$producttmpselect = new Product($this->db);
1944
				$producttmpselect->fetch($selected);
1945
				$selected_input_value = $producttmpselect->ref;
1946
				unset($producttmpselect);
1947
			}
1948
			// handle case where product or service module is disabled + no filter specified
1949
			if ($filtertype == '')
1950
			{
1951
				if (empty($conf->product->enabled)) { // when product module is disabled, show services only
1952
					$filtertype = 1;
1953
				}
1954
				elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
1955
					$filtertype = 0;
1956
				}
1957
			}
1958
			// mode=1 means customers products
1959
			$urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
1960
			//Price by customer
1961
			if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
1962
				$urloption .= '&socid='.$socid;
1963
			}
1964
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1965
1966
			if (!empty($conf->variants->enabled)) {
1967
				?>
1968
				<script>
1969
1970
					selected = <?php echo json_encode($selected_combinations) ?>;
1971
					combvalues = {};
1972
1973
					jQuery(document).ready(function () {
1974
1975
						jQuery("input[name='prod_entry_mode']").change(function () {
1976
							if (jQuery(this).val() == 'free') {
1977
								jQuery('div#attributes_box').empty();
1978
							}
1979
						});
1980
1981
						jQuery("input#<?php echo $htmlname ?>").change(function () {
1982
1983
							if (!jQuery(this).val()) {
1984
								jQuery('div#attributes_box').empty();
1985
								return;
1986
							}
1987
1988
							jQuery.getJSON("<?php echo dol_buildpath('/variants/ajax/getCombinations.php', 2) ?>", {
1989
								id: jQuery(this).val()
1990
							}, function (data) {
1991
								jQuery('div#attributes_box').empty();
1992
1993
								jQuery.each(data, function (key, val) {
1994
1995
									combvalues[val.id] = val.values;
1996
1997
									var span = jQuery(document.createElement('div')).css({
1998
										'display': 'table-row'
1999
									});
2000
2001
									span.append(
2002
										jQuery(document.createElement('div')).text(val.label).css({
2003
											'font-weight': 'bold',
2004
											'display': 'table-cell',
2005
											'text-align': 'right'
2006
										})
2007
									);
2008
2009
									var html = jQuery(document.createElement('select')).attr('name', 'combinations[' + val.id + ']').css({
2010
										'margin-left': '15px',
2011
										'white-space': 'pre'
2012
									}).append(
2013
										jQuery(document.createElement('option')).val('')
2014
									);
2015
2016
									jQuery.each(combvalues[val.id], function (key, val) {
2017
										var tag = jQuery(document.createElement('option')).val(val.id).html(val.value);
2018
2019
										if (selected[val.fk_product_attribute] == val.id) {
2020
											tag.attr('selected', 'selected');
2021
										}
2022
2023
										html.append(tag);
2024
									});
2025
2026
									span.append(html);
2027
									jQuery('div#attributes_box').append(span);
2028
								});
2029
							})
2030
						});
2031
2032
						<?php if ($selected): ?>
2033
						jQuery("input#<?php echo $htmlname ?>").change();
2034
						<?php endif ?>
2035
					});
2036
				</script>
2037
                <?php
2038
			}
2039
			if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
2040
			elseif ($hidelabel > 1) {
2041
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2042
				if ($hidelabel == 2) {
2043
					print img_picto($langs->trans("Search"), 'search');
2044
				}
2045
			}
2046
			print '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
2047
			if ($hidelabel == 3) {
2048
				print img_picto($langs->trans("Search"), 'search');
2049
			}
2050
		}
2051
		else
2052
		{
2053
			print $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
0 ignored issues
show
Bug introduced by
Are you sure $this->select_produits_l...abel, $warehouseStatus) of type array can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2053
			print /** @scrutinizer ignore-type */ $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
Loading history...
2054
		}
2055
	}
2056
2057
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2058
	/**
2059
	 *	Return list of products for a customer
2060
	 *
2061
	 *	@param      int		$selected           Preselected product
2062
	 *	@param      string	$htmlname           Name of select html
2063
	 *  @param		string	$filtertype         Filter on product type (''=nofilter, 0=product, 1=service)
2064
	 *	@param      int		$limit              Limit on number of returned lines
2065
	 *	@param      int		$price_level        Level of price to show
2066
	 * 	@param      string	$filterkey          Filter on product
2067
	 *	@param		int		$status             -1=Return all products, 0=Products not on sell, 1=Products on sell
2068
	 *  @param      int		$finished           Filter on finished field: 2=No filter
2069
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
2070
	 *  @param      int		$socid     		    Thirdparty Id (to get also price dedicated to this customer)
2071
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2072
	 * 	@param		int		$forcecombo		    Force to use combo box
2073
	 *  @param      string  $morecss            Add more css on select
2074
	 *  @param      int     $hidepriceinlabel   1=Hide prices in label
2075
	 *  @param      string  $warehouseStatus    Warehouse status filter to group/count stock. Following comma separated filter options can be used.
2076
	 *										    'warehouseopen' = count products from open warehouses,
2077
	 *										    'warehouseclosed' = count products from closed warehouses,
2078
	 *										    'warehouseinternal' = count products from warehouses for internal correct/transfer only
2079
	 *  @return     array    				    Array of keys for json
2080
	 */
2081
    public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '')
2082
	{
2083
        // phpcs:enable
2084
		global $langs, $conf, $user, $db;
2085
2086
		$out = '';
2087
		$outarray = array();
2088
2089
        // Units
2090
        if ($conf->global->PRODUCT_USE_UNITS) {
2091
            $langs->load('other');
2092
        }
2093
2094
		$warehouseStatusArray = array();
2095
		if (!empty($warehouseStatus))
2096
		{
2097
			require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2098
			if (preg_match('/warehouseclosed/', $warehouseStatus))
2099
			{
2100
				$warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2101
			}
2102
			if (preg_match('/warehouseopen/', $warehouseStatus))
2103
			{
2104
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2105
			}
2106
			if (preg_match('/warehouseinternal/', $warehouseStatus))
2107
			{
2108
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2109
			}
2110
		}
2111
2112
		$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";
2113
		if (count($warehouseStatusArray))
2114
		{
2115
		    $selectFieldsGrouped = ", sum(".$db->ifsql("e.statut IS NULL", "0", "ps.reel").") as stock"; // e.statut is null if there is no record in stock
2116
		}
2117
		else
2118
		{
2119
		    $selectFieldsGrouped = ", ".$db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2120
		}
2121
2122
		$sql = "SELECT ";
2123
		$sql .= $selectFields.$selectFieldsGrouped;
2124
2125
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2126
		{
2127
			//Product category
2128
			$sql .= ", (SELECT ".MAIN_DB_PREFIX."categorie_product.fk_categorie
2129
						FROM ".MAIN_DB_PREFIX."categorie_product
2130
						WHERE ".MAIN_DB_PREFIX."categorie_product.fk_product=p.rowid
2131
						LIMIT 1
2132
				) AS categorie_product_id ";
2133
		}
2134
2135
		//Price by customer
2136
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid))
2137
		{
2138
			$sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2139
			$sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx';
2140
			$selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx";
2141
		}
2142
        // Units
2143
        if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2144
            $sql .= ", u.label as unit_long, u.short_label as unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units";
2145
            $selectFields .= ', unit_long, unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units';
2146
        }
2147
2148
		// Multilang : we add translation
2149
		if (!empty($conf->global->MAIN_MULTILANGS))
2150
		{
2151
			$sql .= ", pl.label as label_translated";
2152
			$selectFields .= ", label_translated";
2153
		}
2154
		// Price by quantity
2155
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
2156
		{
2157
			$sql .= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
2158
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql .= " AND price_level=".$price_level;
2159
			$sql .= " ORDER BY date_price";
2160
			$sql .= " DESC LIMIT 1) as price_rowid";
2161
			$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
2162
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql .= " AND price_level=".$price_level;
2163
			$sql .= " ORDER BY date_price";
2164
			$sql .= " DESC LIMIT 1) as price_by_qty";
2165
			$selectFields .= ", price_rowid, price_by_qty";
2166
		}
2167
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2168
		if (count($warehouseStatusArray))
2169
		{
2170
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
2171
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2172
			$sql .= ' AND e.statut IN ('.$this->db->escape(implode(',', $warehouseStatusArray)).')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0.
2173
		}
2174
2175
		// include search in supplier ref
2176
		if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
2177
		{
2178
            $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2179
		}
2180
2181
		//Price by customer
2182
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2183
			$sql .= " LEFT JOIN  ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".$socid." AND pcp.fk_product=p.rowid";
2184
		}
2185
        // Units
2186
        if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2187
            $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2188
        }
2189
		// Multilang : we add translation
2190
		if (!empty($conf->global->MAIN_MULTILANGS))
2191
		{
2192
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='".$langs->getDefaultLang()."'";
2193
		}
2194
2195
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2196
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2197
		}
2198
2199
		$sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2200
2201
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2202
			$sql .= " AND pac.rowid IS NULL";
2203
		}
2204
2205
		if ($finished == 0)
2206
		{
2207
			$sql .= " AND p.finished = ".$finished;
2208
		}
2209
		elseif ($finished == 1)
2210
		{
2211
			$sql .= " AND p.finished = ".$finished;
2212
			if ($status >= 0)  $sql .= " AND p.tosell = ".$status;
2213
		}
2214
		elseif ($status >= 0)
2215
		{
2216
			$sql .= " AND p.tosell = ".$status;
2217
		}
2218
		// Filter by product type
2219
		if (strval($filtertype) != '') $sql .= " AND p.fk_product_type = ".$filtertype;
2220
		elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only
2221
			$sql .= " AND p.fk_product_type = 1";
2222
		}
2223
		elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2224
			$sql .= " AND p.fk_product_type = 0";
2225
		}
2226
		// Add criteria on ref/label
2227
		if ($filterkey != '')
2228
		{
2229
			$sql .= ' AND (';
2230
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2231
			// For natural search
2232
			$scrit = explode(' ', $filterkey);
2233
			$i = 0;
2234
			if (count($scrit) > 1) $sql .= "(";
2235
			foreach ($scrit as $crit)
2236
			{
2237
				if ($i > 0) $sql .= " AND ";
2238
				$sql .= "(p.ref LIKE '".$db->escape($prefix.$crit)."%' OR p.label LIKE '".$db->escape($prefix.$crit)."%'";
2239
				if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " OR pl.label LIKE '".$db->escape($prefix.$crit)."%'";
2240
				if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION))
2241
				{
2242
					$sql .= " OR p.description LIKE '".$db->escape($prefix.$crit)."%'";
2243
					if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " OR pl.description LIKE '".$db->escape($prefix.$crit)."%'";
2244
				}
2245
				if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) $sql .= " OR pfp.ref_fourn LIKE '".$db->escape($prefix.$crit)."%'";
2246
				$sql .= ")";
2247
				$i++;
2248
			}
2249
			if (count($scrit) > 1) $sql .= ")";
2250
		  	if (!empty($conf->barcode->enabled)) $sql .= " OR p.barcode LIKE '".$db->escape($prefix.$filterkey)."%'";
2251
			$sql .= ')';
2252
		}
2253
		if (count($warehouseStatusArray))
2254
		{
2255
			$sql .= ' GROUP BY'.$selectFields;
2256
		}
2257
2258
		//Sort by category
2259
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2260
		{
2261
			$sql .= " ORDER BY categorie_product_id ";
2262
			//ASC OR DESC order
2263
			($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2264
		}
2265
		else
2266
		{
2267
			$sql .= $db->order("p.ref");
2268
		}
2269
2270
		$sql .= $db->plimit($limit, 0);
2271
2272
		// Build output string
2273
		dol_syslog(get_class($this)."::select_produits_list search product", LOG_DEBUG);
2274
		$result = $this->db->query($sql);
2275
		if ($result)
2276
		{
2277
			require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2278
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2279
			$num = $this->db->num_rows($result);
2280
2281
			$events = null;
2282
2283
			if (!$forcecombo)
2284
			{
2285
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2286
				$out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT);
2287
			}
2288
2289
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2290
2291
			$textifempty = '';
2292
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2293
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2294
			if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2295
			{
2296
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
2297
				else $textifempty .= $langs->trans("All");
2298
			}
2299
			else
2300
			{
2301
			    if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
2302
			}
2303
			if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
2304
2305
			$i = 0;
2306
			while ($num && $i < $num)
2307
			{
2308
				$opt = '';
2309
				$optJson = array();
2310
				$objp = $this->db->fetch_object($result);
2311
2312
				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)
2313
				{ // Price by quantity will return many prices for the same product
2314
					$sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2315
					$sql .= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
2316
					$sql .= " WHERE fk_product_price=".$objp->price_rowid;
2317
					$sql .= " ORDER BY quantity ASC";
2318
2319
					dol_syslog(get_class($this)."::select_produits_list search price by qty", LOG_DEBUG);
2320
					$result2 = $this->db->query($sql);
2321
					if ($result2)
2322
					{
2323
						$nb_prices = $this->db->num_rows($result2);
2324
						$j = 0;
2325
						while ($nb_prices && $j < $nb_prices) {
2326
							$objp2 = $this->db->fetch_object($result2);
2327
2328
							$objp->price_by_qty_rowid = $objp2->rowid;
2329
							$objp->price_by_qty_price_base_type = $objp2->price_base_type;
2330
							$objp->price_by_qty_quantity = $objp2->quantity;
2331
							$objp->price_by_qty_unitprice = $objp2->unitprice;
2332
							$objp->price_by_qty_remise_percent = $objp2->remise_percent;
2333
							// For backward compatibility
2334
							$objp->quantity = $objp2->quantity;
2335
							$objp->price = $objp2->price;
2336
							$objp->unitprice = $objp2->unitprice;
2337
							$objp->remise_percent = $objp2->remise_percent;
2338
							$objp->remise = $objp2->remise;
2339
2340
							$this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2341
2342
							$j++;
2343
2344
							// Add new entry
2345
							// "key" value of json key array is used by jQuery automatically as selected value
2346
							// "label" value of json key array is used by jQuery automatically as text for combo box
2347
							$out .= $opt;
2348
							array_push($outarray, $optJson);
2349
						}
2350
					}
2351
				}
2352
				else
2353
				{
2354
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2355
						$price_product = new Product($this->db);
2356
						$price_product->fetch($objp->rowid, '', '', 1);
2357
						$priceparser = new PriceParser($this->db);
2358
						$price_result = $priceparser->parseProduct($price_product);
2359
						if ($price_result >= 0) {
2360
							$objp->price = $price_result;
2361
							$objp->unitprice = $price_result;
2362
							//Calculate the VAT
2363
							$objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2364
							$objp->price_ttc = price2num($objp->price_ttc, 'MU');
2365
						}
2366
					}
2367
2368
					$this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2369
					// Add new entry
2370
					// "key" value of json key array is used by jQuery automatically as selected value
2371
					// "label" value of json key array is used by jQuery automatically as text for combo box
2372
					$out .= $opt;
2373
					array_push($outarray, $optJson);
2374
				}
2375
2376
				$i++;
2377
			}
2378
2379
			$out .= '</select>';
2380
2381
			$this->db->free($result);
2382
2383
			if (empty($outputmode)) return $out;
2384
			return $outarray;
2385
		}
2386
		else
2387
		{
2388
			dol_print_error($db);
2389
		}
2390
	}
2391
2392
	/**
2393
	 * constructProductListOption.
2394
	 * This define value for &$opt and &$optJson.
2395
	 *
2396
	 * @param 	resource	$objp			    Resultset of fetch
2397
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
2398
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
2399
	 * @param 	int			$price_level	    Price level
2400
	 * @param 	string		$selected		    Preselected value
2401
	 * @param   int         $hidepriceinlabel   Hide price in label
2402
	 * @param   string      $filterkey          Filter key to highlight
2403
	 * @return	void
2404
	 */
2405
	protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '')
2406
	{
2407
		global $langs, $conf, $user, $db;
2408
2409
		$outkey = '';
2410
		$outval = '';
2411
		$outref = '';
2412
		$outlabel = '';
2413
		$outdesc = '';
2414
		$outbarcode = '';
2415
		$outtype = '';
2416
		$outprice_ht = '';
2417
		$outprice_ttc = '';
2418
		$outpricebasetype = '';
2419
		$outtva_tx = '';
2420
		$outqty = 1;
2421
		$outdiscount = 0;
2422
2423
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2424
2425
		$label = $objp->label;
2426
		if (!empty($objp->label_translated)) $label = $objp->label_translated;
2427
		if (!empty($filterkey) && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey).')/i', '<strong>$1</strong>', $label, 1);
2428
2429
		$outkey = $objp->rowid;
2430
		$outref = $objp->ref;
2431
		$outlabel = $objp->label;
2432
		$outdesc = $objp->description;
2433
		$outbarcode = $objp->barcode;
2434
2435
		$outtype = $objp->fk_product_type;
2436
		$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2437
		$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2438
2439
        // Units
2440
        $outvalUnits = '';
2441
        if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2442
            if (!empty($objp->unit_short)) {
2443
                $outvalUnits .= ' - '.$objp->unit_short;
2444
            }
2445
        }
2446
        if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2447
            if (!empty($objp->weight) && $objp->weight_units !== null) {
2448
                $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2449
                $outvalUnits .= ' - '.$unitToShow;
2450
            }
2451
            if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2452
            	$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2453
                $outvalUnits .= ' - '.$unitToShow;
2454
            }
2455
            if (!empty($objp->surface) && $objp->surface_units !== null) {
2456
                $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2457
                $outvalUnits .= ' - '.$unitToShow;
2458
            }
2459
            if (!empty($objp->volume) && $objp->volume_units !== null) {
2460
                $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2461
                $outvalUnits .= ' - '.$unitToShow;
2462
            }
2463
        }
2464
        if ($outdurationvalue && $outdurationunit) {
2465
            $da = array(
2466
                'h' => $langs->trans('Hour'),
2467
                'd' => $langs->trans('Day'),
2468
                'w' => $langs->trans('Week'),
2469
                'm' => $langs->trans('Month'),
2470
                'y' => $langs->trans('Year')
2471
            );
2472
            if (isset($da[$outdurationunit])) {
2473
                $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2474
            }
2475
        }
2476
2477
		$opt = '<option value="'.$objp->rowid.'"';
2478
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
2479
		if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)
2480
		{
2481
			$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.'"';
2482
		}
2483
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2484
		{
2485
		    if (!empty($user->rights->stock->lire)) {
2486
    			if ($objp->stock > 0) $opt .= ' class="product_line_stock_ok"';
2487
	       		elseif ($objp->stock <= 0) $opt .= ' class="product_line_stock_too_low"';
2488
		    }
2489
		}
2490
		$opt .= '>';
2491
		$opt .= $objp->ref;
2492
		if ($outbarcode) $opt .= ' ('.$outbarcode.')';
2493
		$opt .= ' - '.dol_trunc($label, $maxlengtharticle);
2494
2495
		$objRef = $objp->ref;
2496
		if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey).')/i', '<strong>$1</strong>', $objRef, 1);
2497
		$outval .= $objRef;
2498
		if ($outbarcode) $outval .= ' ('.$outbarcode.')';
2499
		$outval .= ' - '.dol_trunc($label, $maxlengtharticle);
2500
        // Units
2501
        $opt .= $outvalUnits;
2502
        $outval .= $outvalUnits;
2503
2504
		$found = 0;
2505
2506
		// Multiprice
2507
		// If we need a particular price level (from 1 to 6)
2508
		if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)))
2509
		{
2510
			$sql = "SELECT price, price_ttc, price_base_type, tva_tx";
2511
			$sql .= " FROM ".MAIN_DB_PREFIX."product_price";
2512
			$sql .= " WHERE fk_product='".$objp->rowid."'";
2513
			$sql .= " AND entity IN (".getEntity('productprice').")";
2514
			$sql .= " AND price_level=".$price_level;
2515
			$sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2516
			$sql .= " LIMIT 1";
2517
2518
			dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
2519
			$result2 = $this->db->query($sql);
2520
			if ($result2)
2521
			{
2522
				$objp2 = $this->db->fetch_object($result2);
2523
				if ($objp2)
2524
				{
2525
					$found = 1;
2526
					if ($objp2->price_base_type == 'HT')
2527
					{
2528
						$opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2529
						$outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2530
					}
2531
					else
2532
					{
2533
						$opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2534
						$outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2535
					}
2536
					$outprice_ht = price($objp2->price);
2537
					$outprice_ttc = price($objp2->price_ttc);
2538
					$outpricebasetype = $objp2->price_base_type;
2539
					$outtva_tx = $objp2->tva_tx;
2540
				}
2541
			}
2542
			else
2543
			{
2544
				dol_print_error($this->db);
2545
			}
2546
		}
2547
2548
		// Price by quantity
2549
		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)))
2550
		{
2551
			$found = 1;
2552
			$outqty = $objp->quantity;
2553
			$outdiscount = $objp->remise_percent;
2554
			if ($objp->quantity == 1)
2555
			{
2556
				$opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
2557
				$outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
2558
				$opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2559
				$outval .= $langs->transnoentities("Unit");
2560
			}
2561
			else
2562
			{
2563
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2564
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2565
				$opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2566
				$outval .= $langs->transnoentities("Units");
2567
			}
2568
2569
			$outprice_ht = price($objp->unitprice);
2570
			$outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
2571
			$outpricebasetype = $objp->price_base_type;
2572
			$outtva_tx = $objp->tva_tx;
2573
		}
2574
		if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1)
2575
		{
2576
			$opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2577
			$outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2578
		}
2579
		if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1)
2580
		{
2581
			$opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2582
			$outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2583
		}
2584
2585
		// Price by customer
2586
		if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES))
2587
		{
2588
			if (!empty($objp->idprodcustprice))
2589
			{
2590
				$found = 1;
2591
2592
				if ($objp->custprice_base_type == 'HT')
2593
				{
2594
					$opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2595
					$outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2596
				}
2597
				else
2598
				{
2599
					$opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2600
					$outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2601
				}
2602
2603
				$outprice_ht = price($objp->custprice);
2604
				$outprice_ttc = price($objp->custprice_ttc);
2605
				$outpricebasetype = $objp->custprice_base_type;
2606
				$outtva_tx = $objp->custtva_tx;
2607
			}
2608
		}
2609
2610
		// If level no defined or multiprice not found, we used the default price
2611
		if (empty($hidepriceinlabel) && !$found)
2612
		{
2613
			if ($objp->price_base_type == 'HT')
2614
			{
2615
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2616
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2617
			}
2618
			else
2619
			{
2620
				$opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2621
				$outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2622
			}
2623
			$outprice_ht = price($objp->price);
2624
			$outprice_ttc = price($objp->price_ttc);
2625
			$outpricebasetype = $objp->price_base_type;
2626
			$outtva_tx = $objp->tva_tx;
2627
		}
2628
2629
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2630
		{
2631
	        if (!empty($user->rights->stock->lire)) {
2632
                $opt .= ' - '.$langs->trans("Stock").':'.$objp->stock;
2633
2634
    			if ($objp->stock > 0) {
2635
    				$outval .= ' - <span class="product_line_stock_ok">';
2636
    			}elseif ($objp->stock <= 0) {
2637
    				$outval .= ' - <span class="product_line_stock_too_low">';
2638
    			}
2639
    			$outval .= $langs->transnoentities("Stock").':'.$objp->stock;
2640
    			$outval .= '</span>';
2641
    			if (!empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO))  // Warning, this option may slow down combo list generation
2642
    			{
2643
    			    $langs->load("stocks");
2644
2645
    			    $tmpproduct = new Product($this->db);
2646
    			    $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
2647
    			    $tmpproduct->load_virtual_stock();
2648
    			    $virtualstock = $tmpproduct->stock_theorique;
2649
2650
    			    $opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
2651
2652
    			    $outval .= ' - '.$langs->transnoentities("VirtualStock").':';
2653
    			    if ($virtualstock > 0) {
2654
    			        $outval .= ' - <span class="product_line_stock_ok">';
2655
    			    }elseif ($virtualstock <= 0) {
2656
    			        $outval .= ' - <span class="product_line_stock_too_low">';
2657
    			    }
2658
    			    $outval .= $virtualstock;
2659
    			    $outval .= '</span>';
2660
2661
    			    unset($tmpproduct);
2662
    			}
2663
	        }
2664
		}
2665
2666
		$opt .= "</option>\n";
2667
		$optJson = array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>price2num($outprice_ht), 'price_ttc'=>price2num($outprice_ttc), 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit);
2668
	}
2669
2670
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2671
	/**
2672
	 *	Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list)
2673
	 *
2674
	 *	@param	int		$socid			Id third party
2675
	 *	@param  string	$selected       Preselected product
2676
	 *	@param  string	$htmlname       Name of HTML Select
2677
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
2678
	 *	@param  string	$filtre			For a SQL filter
2679
	 *	@param	array	$ajaxoptions	Options for ajax_autocompleter
2680
	 *  @param	int		$hidelabel		Hide label (0=no, 1=yes)
2681
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
2682
	 *  @param	string	$morecss		More CSS
2683
	 *	@return	void
2684
	 */
2685
    public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '')
2686
	{
2687
        // phpcs:enable
2688
		global $langs, $conf;
2689
		global $price_level, $status, $finished;
2690
2691
		$selected_input_value = '';
2692
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2693
		{
2694
			if ($selected > 0)
2695
			{
2696
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2697
				$producttmpselect = new Product($this->db);
2698
				$producttmpselect->fetch($selected);
2699
				$selected_input_value = $producttmpselect->ref;
2700
				unset($producttmpselect);
2701
			}
2702
2703
			// mode=2 means suppliers products
2704
			$urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
2705
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
2706
			print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" size="20" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'">';
2707
		}
2708
		else
2709
		{
2710
			print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', -1, 0, 0, $alsoproductwithnosupplierprice, $morecss);
0 ignored issues
show
Bug introduced by
Are you sure $this->select_produits_f...upplierprice, $morecss) of type array can be used in print()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2710
			print /** @scrutinizer ignore-type */ $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', -1, 0, 0, $alsoproductwithnosupplierprice, $morecss);
Loading history...
2711
		}
2712
	}
2713
2714
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2715
	/**
2716
	 *	Return list of suppliers products
2717
	 *
2718
	 *	@param	int		$socid   		Id societe fournisseur (0 pour aucun filtre)
2719
	 *	@param  int		$selected       Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD')
2720
	 *	@param  string	$htmlname       Nom de la zone select
2721
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
2722
	 *	@param  string	$filtre         Pour filtre sql
2723
	 *	@param  string	$filterkey      Filtre des produits
2724
	 *  @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)
2725
	 *  @param  int		$outputmode     0=HTML select string, 1=Array
2726
	 *  @param  int     $limit          Limit of line number
2727
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
2728
	 *  @param	string	$morecss		Add more CSS
2729
	 *  @return array           		Array of keys for json
2730
	 */
2731
    public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '')
2732
	{
2733
        // phpcs:enable
2734
		global $langs, $conf, $db;
2735
2736
		$out = '';
2737
		$outarray = array();
2738
2739
		$langs->load('stocks');
2740
        // Units
2741
        if ($conf->global->PRODUCT_USE_UNITS) {
2742
            $langs->load('other');
2743
        }
2744
2745
		$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration, p.fk_product_type,";
2746
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
2747
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,";
2748
		$sql .= " pfp.supplier_reputation";
2749
        // Units
2750
        if ($conf->global->PRODUCT_USE_UNITS) {
2751
            $sql .= ", u.label as unit_long, u.short_label as unit_short, p.weight, p.weight_units, p.length, p.length_units, p.width, p.width_units, p.height, p.height_units, p.surface, p.surface_units, p.volume, p.volume_units";
2752
        }
2753
        if (!empty($conf->barcode->enabled)) $sql .= " ,pfp.barcode";
2754
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2755
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2756
		if ($socid) $sql .= " AND pfp.fk_soc = ".$socid;
2757
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2758
        // Units
2759
        if ($conf->global->PRODUCT_USE_UNITS) {
2760
            $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2761
        }
2762
		$sql .= " WHERE p.entity IN (".getEntity('product').")";
2763
		$sql .= " AND p.tobuy = 1";
2764
		if (strval($filtertype) != '') $sql .= " AND p.fk_product_type=".$this->db->escape($filtertype);
2765
		if (!empty($filtre)) $sql .= " ".$filtre;
2766
		// Add criteria on ref/label
2767
		if ($filterkey != '')
2768
		{
2769
			$sql .= ' AND (';
2770
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2771
			// For natural search
2772
			$scrit = explode(' ', $filterkey);
2773
			$i = 0;
2774
			if (count($scrit) > 1) $sql .= "(";
2775
			foreach ($scrit as $crit)
2776
			{
2777
				if ($i > 0) $sql .= " AND ";
2778
				$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)."%')";
2779
				$i++;
2780
			}
2781
			if (count($scrit) > 1) $sql .= ")";
2782
			if (!empty($conf->barcode->enabled)) {
2783
                $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2784
                $sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2785
            }
2786
			$sql .= ')';
2787
		}
2788
		$sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
2789
		$sql .= $db->plimit($limit, 0);
2790
2791
		// Build output string
2792
2793
		dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
2794
		$result = $this->db->query($sql);
2795
		if ($result)
2796
		{
2797
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2798
2799
			$num = $this->db->num_rows($result);
2800
2801
			//$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">';	// remove select to have id same with combo and ajax
2802
			$out .= '<select class="flat maxwidthonsmartphone'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
2803
			if (!$selected) $out .= '<option value="0" selected>&nbsp;</option>';
2804
			else $out .= '<option value="0">&nbsp;</option>';
2805
2806
			$i = 0;
2807
			while ($i < $num)
2808
			{
2809
				$objp = $this->db->fetch_object($result);
2810
2811
				$outkey = $objp->idprodfournprice; // id in table of price
2812
				if (!$outkey && $alsoproductwithnosupplierprice) $outkey = 'idprod_'.$objp->rowid; // id of product
2813
2814
				$outref = $objp->ref;
2815
				$outval = '';
2816
				$outqty = 1;
2817
				$outdiscount = 0;
2818
				$outtype = $objp->fk_product_type;
2819
				$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2820
				$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2821
2822
                // Units
2823
                $outvalUnits = '';
2824
                if ($conf->global->PRODUCT_USE_UNITS) {
2825
                    if (!empty($objp->unit_short)) {
2826
                        $outvalUnits .= ' - '.$objp->unit_short;
2827
                    }
2828
                    if (!empty($objp->weight) && $objp->weight_units !== null) {
2829
                        $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2830
                        $outvalUnits .= ' - '.$unitToShow;
2831
                    }
2832
                    if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2833
                    	$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2834
                        $outvalUnits .= ' - '.$unitToShow;
2835
                    }
2836
                    if (!empty($objp->surface) && $objp->surface_units !== null) {
2837
                        $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2838
                        $outvalUnits .= ' - '.$unitToShow;
2839
                    }
2840
                    if (!empty($objp->volume) && $objp->volume_units !== null) {
2841
                        $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2842
                        $outvalUnits .= ' - '.$unitToShow;
2843
                    }
2844
                    if ($outdurationvalue && $outdurationunit) {
2845
                        $da = array(
2846
                            'h' => $langs->trans('Hour'),
2847
                            'd' => $langs->trans('Day'),
2848
                            'w' => $langs->trans('Week'),
2849
                            'm' => $langs->trans('Month'),
2850
                            'y' => $langs->trans('Year')
2851
                        );
2852
                        if (isset($da[$outdurationunit])) {
2853
                            $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2854
                        }
2855
                    }
2856
                }
2857
2858
				$objRef = $objp->ref;
2859
				if ($filterkey && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey).')/i', '<strong>$1</strong>', $objRef, 1);
2860
				$objRefFourn = $objp->ref_fourn;
2861
				if ($filterkey && $filterkey != '') $objRefFourn = preg_replace('/('.preg_quote($filterkey).')/i', '<strong>$1</strong>', $objRefFourn, 1);
2862
				$label = $objp->label;
2863
				if ($filterkey && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey).')/i', '<strong>$1</strong>', $label, 1);
2864
2865
				$optlabel = $objp->ref;
2866
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn))
2867
					$optlabel .= ' <span class=\'opacitymedium\'>('.$objp->ref_fourn.')</span>';
2868
2869
				$outvallabel = $objRef;
2870
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn))
2871
					$outvallabel .= ' ('.$objRefFourn.')';
2872
2873
                // Units
2874
				$optlabel .= $outvalUnits;
2875
				$outvallabel .= $outvalUnits;
2876
2877
				if (!empty($objp->idprodfournprice))
2878
				{
2879
					$outqty = $objp->quantity;
2880
					$outdiscount = $objp->remise_percent;
2881
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2882
						$prod_supplier = new ProductFournisseur($this->db);
2883
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2884
						$prod_supplier->id = $objp->fk_product;
2885
						$prod_supplier->fourn_qty = $objp->quantity;
2886
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
2887
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2888
						$priceparser = new PriceParser($this->db);
2889
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
2890
						if ($price_result >= 0) {
2891
							$objp->fprice = $price_result;
2892
							if ($objp->quantity >= 1)
2893
							{
2894
								$objp->unitprice = $objp->fprice / $objp->quantity;
2895
							}
2896
						}
2897
					}
2898
					if ($objp->quantity == 1)
2899
					{
2900
						$optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
2901
						$outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
2902
						$optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2903
						$outvallabel .= $langs->transnoentities("Unit");
2904
					}
2905
					else
2906
					{
2907
						$optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2908
						$outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2909
						$optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2910
						$outvallabel .= ' '.$langs->transnoentities("Units");
2911
					}
2912
2913
					if ($objp->quantity > 1)
2914
					{
2915
						$optlabel .= " (".price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2916
						$outvallabel .= " (".price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2917
					}
2918
					if ($objp->remise_percent >= 1)
2919
					{
2920
						$optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2921
						$outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2922
					}
2923
					if ($objp->duration)
2924
					{
2925
						$optlabel .= " - ".$objp->duration;
2926
						$outvallabel .= " - ".$objp->duration;
2927
					}
2928
					if (!$socid)
2929
					{
2930
						$optlabel .= " - ".dol_trunc($objp->name, 8);
2931
						$outvallabel .= " - ".dol_trunc($objp->name, 8);
2932
					}
2933
                    if (!empty($conf->barcode->enabled) && !empty($objp->barcode))
2934
                    {
2935
                    	//$optlabel .= " - <span class='fa fa-barcode'></span>".$objp->barcode;
2936
                    	$optlabel .= " - ".$objp->barcode;
2937
                    	$outvallabel .= " - ".$objp->barcode;
2938
                    }
2939
					if ($objp->supplier_reputation)
2940
					{
2941
						//TODO dictionary
2942
						$reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
2943
2944
						$optlabel .= " - ".$reputations[$objp->supplier_reputation];
2945
						$outvallabel .= " - ".$reputations[$objp->supplier_reputation];
2946
					}
2947
				}
2948
				else
2949
				{
2950
					if (empty($alsoproductwithnosupplierprice))     // No supplier price defined for couple product/supplier
2951
					{
2952
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
2953
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
2954
					}
2955
					else                                            // No supplier price defined for product, even on other suppliers
2956
					{
2957
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
2958
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
2959
					}
2960
				}
2961
2962
				$opt = '<option value="'.$outkey.'"';
2963
				if ($selected && $selected == $objp->idprodfournprice) $opt .= ' selected';
2964
				if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) $opt .= ' disabled';
2965
				if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0)
2966
				{
2967
					$opt .= ' pbq="'.$objp->idprodfournprice.'" data-pbq="'.$objp->idprodfournprice.'" data-pbqqty="'.$objp->quantity.'" data-pbqpercent="'.$objp->remise_percent.'"';
2968
				}
2969
				$opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"';
2970
				$opt .= '>';
2971
2972
				$opt .= $optlabel;
2973
				$outval .= $outvallabel;
2974
2975
				$opt .= "</option>\n";
2976
2977
2978
				// Add new entry
2979
				// "key" value of json key array is used by jQuery automatically as selected value
2980
				// "label" value of json key array is used by jQuery automatically as text for combo box
2981
				$out .= $opt;
2982
				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)));
2983
				// Exemple of var_dump $outarray
2984
				// array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
2985
				//           ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
2986
				//      	 ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
2987
				//}
2988
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2989
				//$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
2990
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2991
2992
				$i++;
2993
			}
2994
			$out .= '</select>';
2995
2996
			$this->db->free($result);
2997
2998
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2999
			$out .= ajax_combobox($htmlname);
3000
3001
			if (empty($outputmode)) return $out;
3002
			return $outarray;
3003
		}
3004
		else
3005
		{
3006
			dol_print_error($this->db);
3007
		}
3008
	}
3009
3010
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3011
	/**
3012
	 *	Return list of suppliers prices for a product
3013
	 *
3014
	 *  @param	    int		$productid       	Id of product
3015
	 *  @param      string	$htmlname        	Name of HTML field
3016
	 *  @param      int		$selected_supplier  Pre-selected supplier if more than 1 result
3017
	 *  @return	    string
3018
	 */
3019
    public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3020
	{
3021
        // phpcs:enable
3022
		global $langs, $conf;
3023
3024
		$langs->load('stocks');
3025
3026
		$sql = "SELECT p.rowid, p.label, p.ref, p.price, p.duration, pfp.fk_soc,";
3027
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3028
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3029
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
3030
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3031
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
3032
		$sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3033
		$sql .= " AND p.tobuy = 1";
3034
		$sql .= " AND s.fournisseur = 1";
3035
		$sql .= " AND p.rowid = ".$productid;
3036
		$sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3037
3038
		dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3039
		$result = $this->db->query($sql);
3040
3041
		if ($result)
3042
		{
3043
			$num = $this->db->num_rows($result);
3044
3045
			$form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3046
3047
			if (!$num)
3048
			{
3049
				$form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3050
			}
3051
			else
3052
			{
3053
				require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3054
				$form .= '<option value="0">&nbsp;</option>';
3055
3056
				$i = 0;
3057
				while ($i < $num)
3058
				{
3059
					$objp = $this->db->fetch_object($result);
3060
3061
					$opt = '<option value="'.$objp->idprodfournprice.'"';
3062
					//if there is only one supplier, preselect it
3063
					if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
3064
						$opt .= ' selected';
3065
					}
3066
					$opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3067
3068
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3069
						$prod_supplier = new ProductFournisseur($this->db);
3070
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3071
						$prod_supplier->id = $productid;
3072
						$prod_supplier->fourn_qty = $objp->quantity;
3073
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
3074
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3075
						$priceparser = new PriceParser($this->db);
3076
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
3077
						if ($price_result >= 0) {
3078
							$objp->fprice = $price_result;
3079
							if ($objp->quantity >= 1)
3080
							{
3081
								$objp->unitprice = $objp->fprice / $objp->quantity;
3082
							}
3083
						}
3084
					}
3085
					if ($objp->quantity == 1)
3086
					{
3087
						$opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3088
					}
3089
3090
					$opt .= $objp->quantity.' ';
3091
3092
					if ($objp->quantity == 1)
3093
					{
3094
						$opt .= $langs->trans("Unit");
3095
					}
3096
					else
3097
					{
3098
						$opt .= $langs->trans("Units");
3099
					}
3100
					if ($objp->quantity > 1)
3101
					{
3102
						$opt .= " - ";
3103
						$opt .= price($objp->unitprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit");
3104
					}
3105
					if ($objp->duration) $opt .= " - ".$objp->duration;
3106
					$opt .= "</option>\n";
3107
3108
					$form .= $opt;
3109
					$i++;
3110
				}
3111
			}
3112
3113
			$form .= '</select>';
3114
			$this->db->free($result);
3115
			return $form;
3116
		}
3117
		else
3118
		{
3119
			dol_print_error($this->db);
3120
		}
3121
	}
3122
3123
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3124
	/**
3125
	 *    Return list of delivery address
3126
	 *
3127
	 *    @param    string	$selected          	Id contact pre-selectionn
3128
	 *    @param    int		$socid				Id of company
3129
	 *    @param    string	$htmlname          	Name of HTML field
3130
	 *    @param    int		$showempty         	Add an empty field
3131
	 *    @return	integer|null
3132
	 */
3133
    public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3134
	{
3135
        // phpcs:enable
3136
		// looking for users
3137
		$sql = "SELECT a.rowid, a.label";
3138
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_address as a";
3139
		$sql .= " WHERE a.fk_soc = ".$socid;
3140
		$sql .= " ORDER BY a.label ASC";
3141
3142
		dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3143
		$resql = $this->db->query($sql);
3144
		if ($resql)
3145
		{
3146
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3147
			if ($showempty) print '<option value="0">&nbsp;</option>';
3148
			$num = $this->db->num_rows($resql);
3149
			$i = 0;
3150
			if ($num)
3151
			{
3152
				while ($i < $num)
3153
				{
3154
					$obj = $this->db->fetch_object($resql);
3155
3156
					if ($selected && $selected == $obj->rowid)
3157
					{
3158
						print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3159
					}
3160
					else
3161
					{
3162
						print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3163
					}
3164
					$i++;
3165
				}
3166
			}
3167
			print '</select>';
3168
			return $num;
3169
		}
3170
		else
3171
		{
3172
			dol_print_error($this->db);
3173
		}
3174
	}
3175
3176
3177
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3178
	/**
3179
	 *      Load into cache list of payment terms
3180
	 *
3181
	 *      @return     int             Nb of lines loaded, <0 if KO
3182
	 */
3183
    public function load_cache_conditions_paiements()
3184
	{
3185
        // phpcs:enable
3186
		global $langs;
3187
3188
		$num = count($this->cache_conditions_paiements);
3189
		if ($num > 0) return 0; // Cache already loaded
3190
3191
		dol_syslog(__METHOD__, LOG_DEBUG);
3192
3193
		$sql = "SELECT rowid, code, libelle as label";
3194
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_payment_term';
3195
		$sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3196
		$sql .= " AND active > 0";
3197
		$sql .= " ORDER BY sortorder";
3198
3199
		$resql = $this->db->query($sql);
3200
		if ($resql)
3201
		{
3202
			$num = $this->db->num_rows($resql);
3203
			$i = 0;
3204
			while ($i < $num)
3205
			{
3206
				$obj = $this->db->fetch_object($resql);
3207
3208
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3209
				$label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3210
				$this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3211
				$this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3212
				$i++;
3213
			}
3214
3215
			//$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1);		// We use the field sortorder of table
3216
3217
			return $num;
3218
		}
3219
		else
3220
		{
3221
			dol_print_error($this->db);
3222
			return -1;
3223
		}
3224
	}
3225
3226
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3227
	/**
3228
	 *      Charge dans cache la liste des délais de livraison possibles
3229
	 *
3230
	 *      @return     int             Nb of lines loaded, <0 if KO
3231
	 */
3232
    public function load_cache_availability()
3233
	{
3234
        // phpcs:enable
3235
		global $langs;
3236
3237
		$num = count($this->cache_availability);
3238
		if ($num > 0) return 0; // Cache already loaded
3239
3240
		dol_syslog(__METHOD__, LOG_DEBUG);
3241
3242
		$langs->load('propal');
3243
3244
		$sql = "SELECT rowid, code, label";
3245
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_availability';
3246
		$sql .= " WHERE active > 0";
3247
3248
		$resql = $this->db->query($sql);
3249
		if ($resql)
3250
		{
3251
			$num = $this->db->num_rows($resql);
3252
			$i = 0;
3253
			while ($i < $num)
3254
			{
3255
				$obj = $this->db->fetch_object($resql);
3256
3257
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3258
				$label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3259
				$this->cache_availability[$obj->rowid]['code'] = $obj->code;
3260
				$this->cache_availability[$obj->rowid]['label'] = $label;
3261
				$i++;
3262
			}
3263
3264
			$this->cache_availability = dol_sort_array($this->cache_availability, 'label', 'asc', 0, 0, 1);
3265
3266
			return $num;
3267
		}
3268
		else
3269
		{
3270
			dol_print_error($this->db);
3271
			return -1;
3272
		}
3273
	}
3274
3275
	/**
3276
	 *      Retourne la liste des types de delais de livraison possibles
3277
	 *
3278
	 *      @param	int		$selected        Id du type de delais pre-selectionne
3279
	 *      @param  string	$htmlname        Nom de la zone select
3280
	 *      @param  string	$filtertype      To add a filter
3281
	 *		@param	int		$addempty		Add empty entry
3282
	 *		@return	void
3283
	 */
3284
    public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0)
3285
	{
3286
		global $langs, $user;
3287
3288
		$this->load_cache_availability();
3289
3290
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3291
3292
		print '<select id="'.$htmlname.'" class="flat" name="'.$htmlname.'">';
3293
		if ($addempty) print '<option value="0">&nbsp;</option>';
3294
		foreach ($this->cache_availability as $id => $arrayavailability)
3295
		{
3296
			if ($selected == $id)
3297
			{
3298
				print '<option value="'.$id.'" selected>';
3299
			}
3300
			else
3301
			{
3302
				print '<option value="'.$id.'">';
3303
			}
3304
			print $arrayavailability['label'];
3305
			print '</option>';
3306
		}
3307
		print '</select>';
3308
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3309
	}
3310
3311
	/**
3312
	 *      Load into cache cache_demand_reason, array of input reasons
3313
	 *
3314
	 *      @return     int             Nb of lines loaded, <0 if KO
3315
	 */
3316
    public function loadCacheInputReason()
3317
	{
3318
		global $langs;
3319
3320
		$num = count($this->cache_demand_reason);
3321
		if ($num > 0) return 0; // Cache already loaded
3322
3323
		$sql = "SELECT rowid, code, label";
3324
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_input_reason';
3325
		$sql .= " WHERE active > 0";
3326
3327
		$resql = $this->db->query($sql);
3328
		if ($resql)
3329
		{
3330
			$num = $this->db->num_rows($resql);
3331
			$i = 0;
3332
			$tmparray = array();
3333
			while ($i < $num)
3334
			{
3335
				$obj = $this->db->fetch_object($resql);
3336
3337
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3338
				$label = ($obj->label != '-' ? $obj->label : '');
3339
				if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3340
				if ($langs->trans($obj->code) != $obj->code) $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3341
3342
				$tmparray[$obj->rowid]['id']   = $obj->rowid;
3343
				$tmparray[$obj->rowid]['code'] = $obj->code;
3344
				$tmparray[$obj->rowid]['label'] = $label;
3345
				$i++;
3346
			}
3347
3348
			$this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3349
3350
			unset($tmparray);
3351
			return $num;
3352
		}
3353
		else
3354
		{
3355
			dol_print_error($this->db);
3356
			return -1;
3357
		}
3358
	}
3359
3360
	/**
3361
	 *	Return list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
3362
	 *  List found into table c_input_reason loaded by loadCacheInputReason
3363
	 *
3364
	 *  @param	int		$selected        Id or code of type origin to select by default
3365
	 *  @param  string	$htmlname        Nom de la zone select
3366
	 *  @param  string	$exclude         To exclude a code value (Example: SRC_PROP)
3367
	 *	@param	int		$addempty		 Add an empty entry
3368
	 *	@return	void
3369
	 */
3370
    public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0)
3371
	{
3372
		global $langs, $user;
3373
3374
		$this->loadCacheInputReason();
3375
3376
		print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3377
		if ($addempty) print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
3378
		foreach ($this->cache_demand_reason as $id => $arraydemandreason)
3379
		{
3380
			if ($arraydemandreason['code'] == $exclude) continue;
3381
3382
			if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code']))
3383
			{
3384
				print '<option value="'.$arraydemandreason['id'].'" selected>';
3385
			}
3386
			else
3387
			{
3388
				print '<option value="'.$arraydemandreason['id'].'">';
3389
			}
3390
			$label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3391
			print $langs->trans($label);
3392
			print '</option>';
3393
		}
3394
		print '</select>';
3395
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3396
	}
3397
3398
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3399
	/**
3400
	 *      Charge dans cache la liste des types de paiements possibles
3401
	 *
3402
	 *      @return     int                 Nb of lines loaded, <0 if KO
3403
	 */
3404
    public function load_cache_types_paiements()
3405
	{
3406
        // phpcs:enable
3407
		global $langs;
3408
3409
		$num = count($this->cache_types_paiements);
3410
		if ($num > 0) return $num; // Cache already loaded
3411
3412
		dol_syslog(__METHOD__, LOG_DEBUG);
3413
3414
		$this->cache_types_paiements = array();
3415
3416
		$sql = "SELECT id, code, libelle as label, type, active";
3417
		$sql .= " FROM ".MAIN_DB_PREFIX."c_paiement";
3418
		$sql .= " WHERE entity IN (".getEntity('c_paiement').")";
3419
		//if ($active >= 0) $sql.= " AND active = ".$active;
3420
3421
		$resql = $this->db->query($sql);
3422
		if ($resql)
3423
		{
3424
			$num = $this->db->num_rows($resql);
3425
			$i = 0;
3426
			while ($i < $num)
3427
			{
3428
				$obj = $this->db->fetch_object($resql);
3429
3430
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3431
				$label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3432
				$this->cache_types_paiements[$obj->id]['id'] = $obj->id;
3433
				$this->cache_types_paiements[$obj->id]['code'] = $obj->code;
3434
				$this->cache_types_paiements[$obj->id]['label'] = $label;
3435
				$this->cache_types_paiements[$obj->id]['type'] = $obj->type;
3436
				$this->cache_types_paiements[$obj->id]['active'] = $obj->active;
3437
				$i++;
3438
			}
3439
3440
			$this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3441
3442
			return $num;
3443
		}
3444
		else
3445
		{
3446
			dol_print_error($this->db);
3447
			return -1;
3448
		}
3449
	}
3450
3451
3452
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3453
	/**
3454
	 *      Return list of payment modes.
3455
	 *      Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
3456
	 *      See instead to force the default value by the caller.
3457
	 *
3458
	 *      @param	int		$selected		Id of payment term to preselect by default
3459
	 *      @param	string	$htmlname		Nom de la zone select
3460
	 *      @param	int		$filtertype		Not used
3461
	 *		@param	int		$addempty		Add an empty entry
3462
	 * 		@param	int		$noinfoadmin		0=Add admin info, 1=Disable admin info
3463
	 * 		@param	string	$morecss			Add more CSS on select tag
3464
	 *		@return	void
3465
	 */
3466
    public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
3467
	{
3468
        // phpcs:enable
3469
		global $langs, $user, $conf;
3470
3471
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3472
3473
		$this->load_cache_conditions_paiements();
3474
3475
		// Set default value if not already set by caller
3476
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
3477
3478
		print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3479
		if ($addempty) print '<option value="0">&nbsp;</option>';
3480
		foreach ($this->cache_conditions_paiements as $id => $arrayconditions)
3481
		{
3482
			if ($selected == $id)
3483
			{
3484
				print '<option value="'.$id.'" selected>';
3485
			}
3486
			else
3487
			{
3488
				print '<option value="'.$id.'">';
3489
			}
3490
			print $arrayconditions['label'];
3491
			print '</option>';
3492
		}
3493
		print '</select>';
3494
		if ($user->admin && empty($noinfoadmin)) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3495
	}
3496
3497
3498
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3499
	/**
3500
	 *      Return list of payment methods
3501
	 *
3502
	 *      @param	string	$selected       Id du mode de paiement pre-selectionne
3503
	 *      @param  string	$htmlname       Nom de la zone select
3504
	 *      @param  string	$filtertype     To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz))
3505
	 *      @param  int		$format         0=id+libelle, 1=code+code, 2=code+libelle, 3=id+code
3506
	 *      @param  int		$empty			1=peut etre vide, 0 sinon
3507
	 * 		@param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
3508
	 *      @param  int		$maxlength      Max length of label
3509
	 *      @param  int     $active         Active or not, -1 = all
3510
	 *      @param  string  $morecss        Add more CSS on select tag
3511
	 * 		@return	void
3512
	 */
3513
    public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
3514
	{
3515
        // phpcs:enable
3516
		global $langs, $user;
3517
3518
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
3519
3520
		$filterarray = array();
3521
		if ($filtertype == 'CRDT')  	$filterarray = array(0, 2, 3);
3522
		elseif ($filtertype == 'DBIT') 	$filterarray = array(1, 2, 3);
3523
		elseif ($filtertype != '' && $filtertype != '-1') $filterarray = explode(',', $filtertype);
3524
3525
		$this->load_cache_types_paiements();
3526
3527
		print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3528
		if ($empty) print '<option value="">&nbsp;</option>';
3529
		foreach ($this->cache_types_paiements as $id => $arraytypes)
3530
		{
3531
			// If not good status
3532
			if ($active >= 0 && $arraytypes['active'] != $active) continue;
3533
3534
			// On passe si on a demande de filtrer sur des modes de paiments particuliers
3535
			if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) continue;
3536
3537
			// We discard empty line if showempty is on because an empty line has already been output.
3538
			if ($empty && empty($arraytypes['code'])) continue;
3539
3540
			if ($format == 0) print '<option value="'.$id.'"';
3541
			elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3542
			elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3543
			elseif ($format == 3) print '<option value="'.$id.'"';
3544
			// Si selected est text, on compare avec code, sinon avec id
3545
			if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) print ' selected';
3546
			elseif ($selected == $id) print ' selected';
3547
			print '>';
3548
			if ($format == 0) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3549
			elseif ($format == 1) $value = $arraytypes['code'];
3550
			elseif ($format == 2) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3551
			elseif ($format == 3) $value = $arraytypes['code'];
3552
			print $value ? $value : '&nbsp;';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $value does not seem to be defined for all execution paths leading up to this point.
Loading history...
3553
			print '</option>';
3554
		}
3555
		print '</select>';
3556
		if ($user->admin && !$noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3557
	}
3558
3559
3560
	/**
3561
	 *  Selection HT or TTC
3562
	 *
3563
	 *  @param	string	$selected       Id pre-selectionne
3564
	 *  @param  string	$htmlname       Nom de la zone select
3565
	 * 	@return	string					Code of HTML select to chose tax or not
3566
	 */
3567
    public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type')
3568
	{
3569
		global $langs;
3570
3571
		$return = '';
3572
3573
		$return .= '<select class="flat maxwidth75" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3574
		$options = array(
3575
			'HT'=>$langs->trans("HT"),
3576
			'TTC'=>$langs->trans("TTC")
3577
		);
3578
		foreach ($options as $id => $value)
3579
		{
3580
			if ($selected == $id)
3581
			{
3582
				$return .= '<option value="'.$id.'" selected>'.$value;
3583
			}
3584
			else
3585
			{
3586
				$return .= '<option value="'.$id.'">'.$value;
3587
			}
3588
			$return .= '</option>';
3589
		}
3590
		$return .= '</select>';
3591
3592
		return $return;
3593
	}
3594
3595
	/**
3596
	 *  Return a HTML select list of shipping mode
3597
	 *
3598
	 *  @param	string	$selected          Id shipping mode pre-selected
3599
	 *  @param  string	$htmlname          Name of select zone
3600
	 *  @param  string	$filtre            To filter list
3601
	 *  @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.
3602
	 *  @param  string	$moreattrib        To add more attribute on select
3603
	 * 	@return	void
3604
	 */
3605
    public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '')
3606
	{
3607
		global $langs, $conf, $user;
3608
3609
		$langs->load("admin");
3610
		$langs->load("deliveries");
3611
3612
		$sql = "SELECT rowid, code, libelle as label";
3613
		$sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode";
3614
		$sql .= " WHERE active > 0";
3615
		if ($filtre) $sql .= " AND ".$filtre;
3616
		$sql .= " ORDER BY libelle ASC";
3617
3618
		dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
3619
		$result = $this->db->query($sql);
3620
		if ($result) {
3621
			$num = $this->db->num_rows($result);
3622
			$i = 0;
3623
			if ($num) {
3624
				print '<select id="select'.$htmlname.'" class="flat selectshippingmethod" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3625
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
3626
					print '<option value="-1">&nbsp;</option>';
3627
				}
3628
				while ($i < $num) {
3629
					$obj = $this->db->fetch_object($result);
3630
					if ($selected == $obj->rowid) {
3631
						print '<option value="'.$obj->rowid.'" selected>';
3632
					} else {
3633
						print '<option value="'.$obj->rowid.'">';
3634
					}
3635
					print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
3636
					print '</option>';
3637
					$i++;
3638
				}
3639
				print "</select>";
3640
				if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3641
			} else {
3642
				print $langs->trans("NoShippingMethodDefined");
3643
			}
3644
		} else {
3645
			dol_print_error($this->db);
3646
		}
3647
	}
3648
3649
	/**
3650
	 *    Display form to select shipping mode
3651
	 *
3652
	 *    @param	string	$page        Page
3653
	 *    @param    int		$selected    Id of shipping mode
3654
	 *    @param    string	$htmlname    Name of select html field
3655
	 *    @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.
3656
	 *    @return	void
3657
	 */
3658
    public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
3659
	{
3660
		global $langs, $db;
3661
3662
		$langs->load("deliveries");
3663
3664
		if ($htmlname != "none") {
3665
			print '<form method="POST" action="'.$page.'">';
3666
			print '<input type="hidden" name="action" value="setshippingmethod">';
3667
			print '<input type="hidden" name="token" value="'.newToken().'">';
3668
			$this->selectShippingMethod($selected, $htmlname, '', $addempty);
3669
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3670
			print '</form>';
3671
		} else {
3672
			if ($selected) {
3673
				$code = $langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code');
3674
				print $langs->trans("SendingMethod".strtoupper($code));
3675
			} else {
3676
				print "&nbsp;";
3677
			}
3678
		}
3679
	}
3680
3681
	/**
3682
	 * Creates HTML last in cycle situation invoices selector
3683
	 *
3684
	 * @param     string  $selected   		Preselected ID
3685
	 * @param     int     $socid      		Company ID
3686
	 *
3687
	 * @return    string                     HTML select
3688
	 */
3689
    public function selectSituationInvoices($selected = '', $socid = 0)
3690
	{
3691
		global $langs;
3692
3693
		$langs->load('bills');
3694
3695
		$opt = '<option value ="" selected></option>';
3696
		$sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc';
3697
		$sql .= ' FROM '.MAIN_DB_PREFIX.'facture';
3698
		$sql .= ' WHERE entity IN ('.getEntity('invoice').')';
3699
		$sql .= ' AND situation_counter>=1';
3700
		$sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
3701
		$resql = $this->db->query($sql);
3702
		if ($resql && $this->db->num_rows($resql) > 0) {
3703
			// Last seen cycle
3704
			$ref = 0;
3705
			while ($obj = $this->db->fetch_object($resql)) {
3706
				//Same company ?
3707
			    if ($socid == $obj->fk_soc) {
3708
					//Same cycle ?
3709
			        if ($obj->situation_cycle_ref != $ref) {
3710
						// Just seen this cycle
3711
			            $ref = $obj->situation_cycle_ref;
3712
						//not final ?
3713
			            if ($obj->situation_final != 1) {
3714
							//Not prov?
3715
			                if (substr($obj->ref, 1, 4) != 'PROV') {
3716
			                    if ($selected == $obj->rowid) {
3717
			                        $opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
3718
								} else {
3719
								    $opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
3720
								}
3721
							}
3722
						}
3723
					}
3724
				}
3725
			}
3726
		}
3727
		else
3728
		{
3729
				dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
3730
		}
3731
		if ($opt == '<option value ="" selected></option>')
1 ignored issue
show
introduced by
The condition $opt == '<option value ="" selected></option>' is always true.
Loading history...
3732
		{
3733
			$opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
3734
		}
3735
		return $opt;
3736
	}
3737
3738
	/**
3739
	 *      Creates HTML units selector (code => label)
3740
	 *
3741
	 *      @param	string	$selected       Preselected Unit ID
3742
	 *      @param  string	$htmlname       Select name
3743
	 *      @param	int		$showempty		Add a nempty line
3744
	 * 		@return	string                  HTML select
3745
	 */
3746
    public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0)
3747
	{
3748
		global $langs;
3749
3750
		$langs->load('products');
3751
3752
		$return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
3753
3754
		$sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units';
3755
		$sql .= ' WHERE active > 0';
3756
3757
		$resql = $this->db->query($sql);
3758
		if ($resql && $this->db->num_rows($resql) > 0)
3759
		{
3760
			if ($showempty) $return .= '<option value="none"></option>';
3761
3762
			while ($res = $this->db->fetch_object($resql))
3763
			{
3764
			    $unitLabel = $res->label;
3765
			    if (!empty($langs->tab_translate['unit'.$res->code]))	// check if Translation is available before
3766
			    {
3767
			        $unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
3768
			    }
3769
3770
				if ($selected == $res->rowid)
3771
				{
3772
				    $return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
3773
				}
3774
				else
3775
				{
3776
				    $return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
3777
				}
3778
			}
3779
			$return .= '</select>';
3780
		}
3781
		return $return;
3782
	}
3783
3784
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3785
	/**
3786
	 *  Return a HTML select list of bank accounts
3787
	 *
3788
	 *  @param	string	$selected           Id account pre-selected
3789
	 *  @param  string	$htmlname           Name of select zone
3790
	 *  @param  int		$status             Status of searched accounts (0=open, 1=closed, 2=both)
3791
	 *  @param  string	$filtre             To filter list
3792
	 *  @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.
3793
	 *  @param  string	$moreattrib         To add more attribute on select
3794
	 *  @param	int		$showcurrency		Show currency in label
3795
	 *  @param	string	$morecss			More CSS
3796
	 * 	@return	int							<0 if error, Num of bank account found if OK (0, 1, 2, ...)
3797
	 */
3798
    public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '')
3799
	{
3800
        // phpcs:enable
3801
		global $langs, $conf;
3802
3803
		$langs->load("admin");
3804
		$num = 0;
3805
3806
		$sql = "SELECT rowid, label, bank, clos as status, currency_code";
3807
		$sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
3808
		$sql .= " WHERE entity IN (".getEntity('bank_account').")";
3809
		if ($status != 2) $sql .= " AND clos = ".(int) $status;
3810
		if ($filtre) $sql .= " AND ".$filtre;
3811
		$sql .= " ORDER BY label";
3812
3813
		dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
3814
		$result = $this->db->query($sql);
3815
		if ($result)
3816
		{
3817
			$num = $this->db->num_rows($result);
3818
			$i = 0;
3819
			if ($num)
3820
			{
3821
				print '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3822
				if ($useempty == 1 || ($useempty == 2 && $num > 1))
3823
				{
3824
					print '<option value="-1">&nbsp;</option>';
3825
				}
3826
3827
				while ($i < $num)
3828
				{
3829
					$obj = $this->db->fetch_object($result);
3830
					if ($selected == $obj->rowid)
3831
					{
3832
						print '<option value="'.$obj->rowid.'" selected>';
3833
					}
3834
					else
3835
					{
3836
						print '<option value="'.$obj->rowid.'">';
3837
					}
3838
					print trim($obj->label);
3839
					if ($showcurrency) print ' ('.$obj->currency_code.')';
3840
					if ($status == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
3841
					print '</option>';
3842
					$i++;
3843
				}
3844
				print "</select>";
3845
			}
3846
			else
3847
			{
3848
				if ($status == 0) print '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
3849
				else print '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
3850
			}
3851
		}
3852
		else {
3853
			dol_print_error($this->db);
3854
		}
3855
3856
		return $num;
3857
	}
3858
3859
	/**
3860
	 *  Return a HTML select list of establishment
3861
	 *
3862
	 *  @param	string	$selected           Id establishment pre-selected
3863
	 *  @param  string	$htmlname           Name of select zone
3864
	 *  @param  int		$status             Status of searched establishment (0=open, 1=closed, 2=both)
3865
	 *  @param  string	$filtre             To filter list
3866
	 *  @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.
3867
	 *  @param  string	$moreattrib         To add more attribute on select
3868
	 * 	@return	int							<0 if error, Num of establishment found if OK (0, 1, 2, ...)
3869
	 */
3870
	public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
3871
	{
3872
        // phpcs:enable
3873
		global $langs, $conf;
3874
3875
		$langs->load("admin");
3876
		$num = 0;
3877
3878
		$sql = "SELECT rowid, name, fk_country, status, entity";
3879
		$sql .= " FROM ".MAIN_DB_PREFIX."establishment";
3880
		$sql .= " WHERE 1=1";
3881
		if ($status != 2) $sql .= " AND status = ".(int) $status;
3882
		if ($filtre) $sql .= " AND ".$filtre;
3883
		$sql .= " ORDER BY name";
3884
3885
		dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
3886
		$result = $this->db->query($sql);
3887
		if ($result)
3888
		{
3889
			$num = $this->db->num_rows($result);
3890
			$i = 0;
3891
			if ($num)
3892
			{
3893
				print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3894
				if ($useempty == 1 || ($useempty == 2 && $num > 1))
3895
				{
3896
					print '<option value="-1">&nbsp;</option>';
3897
				}
3898
3899
				while ($i < $num)
3900
				{
3901
					$obj = $this->db->fetch_object($result);
3902
					if ($selected == $obj->rowid)
3903
					{
3904
						print '<option value="'.$obj->rowid.'" selected>';
3905
					}
3906
					else
3907
					{
3908
						print '<option value="'.$obj->rowid.'">';
3909
					}
3910
					print trim($obj->name);
3911
					if ($status == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
3912
					print '</option>';
3913
					$i++;
3914
				}
3915
				print "</select>";
3916
			}
3917
			else
3918
			{
3919
				if ($status == 0) print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
3920
				else print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
3921
			}
3922
		}
3923
		else {
3924
			dol_print_error($this->db);
3925
		}
3926
	}
3927
3928
	/**
3929
	 *    Display form to select bank account
3930
	 *
3931
	 *    @param	string	$page        Page
3932
	 *    @param    int		$selected    Id of bank account
3933
	 *    @param    string	$htmlname    Name of select html field
3934
	 *    @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.
3935
	 *    @return	void
3936
	 */
3937
    public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
3938
	{
3939
		global $langs;
3940
		if ($htmlname != "none") {
3941
			print '<form method="POST" action="'.$page.'">';
3942
			print '<input type="hidden" name="action" value="setbankaccount">';
3943
			print '<input type="hidden" name="token" value="'.newToken().'">';
3944
			$nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
3945
			if ($nbaccountfound > 0) print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3946
			print '</form>';
3947
		} else {
3948
			$langs->load('banks');
3949
3950
			if ($selected) {
3951
				require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
3952
				$bankstatic = new Account($this->db);
3953
				$result = $bankstatic->fetch($selected);
3954
				if ($result) print $bankstatic->getNomUrl(1);
3955
			} else {
3956
				print "&nbsp;";
3957
			}
3958
		}
3959
	}
3960
3961
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3962
	/**
3963
	 *    Return list of categories having choosed type
3964
	 *
3965
	 *    @param	string|int	            $type				Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
3966
	 *    @param    string		            $selected    		Id of category preselected or 'auto' (autoselect category if there is only one element)
3967
	 *    @param    string		            $htmlname			HTML field name
3968
	 *    @param    int			            $maxlength      	Maximum length for labels
3969
     *    @param    int|string|array    	$markafterid        Keep only or removed all categories including the leaf $markafterid in category tree (exclude) or Keep only of category is inside the leaf starting with this id.
3970
     *                                                          $markafterid can be an :
3971
     *                                                          - int (id of category)
3972
     *                                                          - string (categories ids seprated by comma)
3973
     *                                                          - array (list of categories ids)
3974
	 *    @param	int			            $outputmode			0=HTML select string, 1=Array
3975
     *    @param	int			            $include			[=0] Removed or 1=Keep only
3976
     *    @param	string					$morecss			More CSS
3977
	 *    @return	string
3978
	 *    @see select_categories()
3979
	 */
3980
    public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
3981
	{
3982
        // phpcs:enable
3983
		global $conf, $langs;
3984
		$langs->load("categories");
3985
3986
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
3987
3988
		// For backward compatibility
3989
		if (is_numeric($type))
3990
		{
3991
			dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
3992
		}
3993
3994
		if ($type === Categorie::TYPE_BANK_LINE)
3995
		{
3996
			// TODO Move this into common category feature
3997
			$cate_arbo = array();
3998
			$sql = "SELECT c.label, c.rowid";
3999
			$sql .= " FROM ".MAIN_DB_PREFIX."bank_categ as c";
4000
			$sql .= " WHERE entity = ".$conf->entity;
4001
			$sql .= " ORDER BY c.label";
4002
			$result = $this->db->query($sql);
4003
			if ($result)
4004
			{
4005
				$num = $this->db->num_rows($result);
4006
				$i = 0;
4007
				while ($i < $num)
4008
				{
4009
					$objp = $this->db->fetch_object($result);
4010
					if ($objp) $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
4011
					$i++;
4012
				}
4013
				$this->db->free($result);
4014
			}
4015
			else dol_print_error($this->db);
4016
		}
4017
		else
4018
		{
4019
			$cat = new Categorie($this->db);
4020
            $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4021
		}
4022
4023
		$output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4024
		$outarray = array();
4025
		if (is_array($cate_arbo))
4026
		{
4027
			if (!count($cate_arbo)) $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4028
			else
4029
			{
4030
				$output .= '<option value="-1">&nbsp;</option>';
4031
				foreach ($cate_arbo as $key => $value)
4032
				{
4033
					if ($cate_arbo[$key]['id'] == $selected || ($selected == 'auto' && count($cate_arbo) == 1))
4034
					{
4035
						$add = 'selected ';
4036
					}
4037
					else
4038
					{
4039
						$add = '';
4040
					}
4041
					$output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>';
4042
4043
					$outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4044
				}
4045
			}
4046
		}
4047
		$output .= '</select>';
4048
		$output .= "\n";
4049
4050
		if ($outputmode) return $outarray;
4051
		return $output;
4052
	}
4053
4054
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4055
	/**
4056
	 *     Show a confirmation HTML form or AJAX popup
4057
	 *
4058
	 *     @param	string		$page        	   	Url of page to call if confirmation is OK
4059
	 *     @param	string		$title       	   	Title
4060
	 *     @param	string		$question    	   	Question
4061
	 *     @param 	string		$action      	   	Action
4062
	 *	   @param	array		$formquestion	   	An array with forms complementary inputs
4063
	 * 	   @param	string		$selectedchoice		"" or "no" or "yes"
4064
	 * 	   @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
4065
	 *     @param	int			$height          	Force height of box
4066
	 *     @param	int			$width				Force width of box
4067
	 *     @return 	void
4068
	 *     @deprecated
4069
	 *     @see formconfirm()
4070
	 */
4071
    public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4072
	{
4073
        // phpcs:enable
4074
        dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4075
		print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4076
	}
4077
4078
	/**
4079
	 *     Show a confirmation HTML form or AJAX popup.
4080
	 *     Easiest way to use this is with useajax=1.
4081
	 *     If you use useajax='xxx', you must also add jquery code to trigger opening of box (with correct parameters)
4082
	 *     just after calling this method. For example:
4083
	 *       print '<script type="text/javascript">'."\n";
4084
	 *       print 'jQuery(document).ready(function() {'."\n";
4085
	 *       print 'jQuery(".xxxlink").click(function(e) { jQuery("#aparamid").val(jQuery(this).attr("rel")); jQuery("#dialog-confirm-xxx").dialog("open"); return false; });'."\n";
4086
	 *       print '});'."\n";
4087
	 *       print '</script>'."\n";
4088
	 *
4089
	 *     @param  	string		$page        	   	Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated)
4090
	 *     @param	string		$title       	   	Title
4091
	 *     @param	string		$question    	   	Question
4092
	 *     @param 	string		$action      	   	Action
4093
	 *	   @param  	array		$formquestion	   	An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , ))
4094
	 *												type can be 'hidden', 'text', 'password', 'checkbox', 'radio', 'date', 'morecss', ...
4095
	 * 	   @param  	string		$selectedchoice  	'' or 'no', or 'yes' or '1' or '0'
4096
	 * 	   @param  	int|string	$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
4097
	 *     @param  	int			$height          	Force height of box (0 = auto)
4098
	 *     @param	int			$width				Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones.
4099
	 *     @param	int			$disableformtag		1=Disable form tag. Can be used if we are already inside a <form> section.
4100
	 *     @return 	string      	    			HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form
4101
	 */
4102
    public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0)
4103
	{
4104
		global $langs, $conf;
4105
		global $useglobalvars;
4106
4107
		$more = '<!-- formconfirm -->';
4108
		$formconfirm = '';
4109
		$inputok = array();
4110
		$inputko = array();
4111
4112
		// Clean parameters
4113
		$newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
4114
		if ($conf->browser->layout == 'phone') $width = '95%';
4115
4116
		// Set height automatically if not defined
4117
		if (empty($height)) {
4118
			$height = 210;
4119
			if (is_array($formquestion) && count($formquestion) > 2) {
4120
				$height += ((count($formquestion) - 2) * 24);
4121
			}
4122
		}
4123
4124
		if (is_array($formquestion) && !empty($formquestion))
4125
		{
4126
			// First add hidden fields and value
4127
			foreach ($formquestion as $key => $input)
4128
			{
4129
				if (is_array($input) && !empty($input))
4130
				{
4131
					if ($input['type'] == 'hidden')
4132
					{
4133
						$more .= '<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
4134
					}
4135
				}
4136
			}
4137
4138
			// Now add questions
4139
			$moreonecolumn = '';
4140
			$more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
4141
			foreach ($formquestion as $key => $input)
4142
			{
4143
				if (is_array($input) && !empty($input))
4144
				{
4145
					$size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : '');
4146
					$moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4147
					$morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4148
4149
					if ($input['type'] == 'text')
4150
					{
4151
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="text" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4152
					}
4153
					elseif ($input['type'] == 'password')
4154
					{
4155
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="password" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4156
					}
4157
					elseif ($input['type'] == 'select')
4158
					{
4159
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4160
						if (!empty($input['label'])) $more .= $input['label'].'</div><div class="tagtd tdtop left">';
4161
						$more .= $this->selectarray($input['name'], $input['values'], $input['default'], 1, 0, 0, $moreattr, 0, 0, 0, '', $morecss);
4162
						$more .= '</div></div>'."\n";
4163
					}
4164
					elseif ($input['type'] == 'checkbox')
4165
					{
4166
						$more .= '<div class="tagtr">';
4167
						$more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
4168
						$more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr;
4169
						if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') $more .= ' checked';
4170
						if (is_bool($input['value']) && $input['value']) $more .= ' checked';
4171
						if (isset($input['disabled'])) $more .= ' disabled';
4172
						$more .= ' /></div>';
4173
						$more .= '</div>'."\n";
4174
					}
4175
					elseif ($input['type'] == 'radio')
4176
					{
4177
						$i = 0;
4178
						foreach ($input['values'] as $selkey => $selval)
4179
						{
4180
							$more .= '<div class="tagtr">';
4181
							if ($i == 0) $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
4182
							else $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
4183
							$more .= '<div class="tagtd"><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr;
4184
							if ($input['disabled']) $more .= ' disabled';
4185
							$more .= ' /> ';
4186
							$more .= $selval;
4187
							$more .= '</div></div>'."\n";
4188
							$i++;
4189
						}
4190
					}
4191
					elseif ($input['type'] == 'date')
4192
					{
4193
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
4194
						$more .= '<div class="tagtd">';
4195
						$more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, 0);
4196
						$more .= '</div></div>'."\n";
4197
						$formquestion[] = array('name'=>$input['name'].'day');
4198
						$formquestion[] = array('name'=>$input['name'].'month');
4199
						$formquestion[] = array('name'=>$input['name'].'year');
4200
						$formquestion[] = array('name'=>$input['name'].'hour');
4201
						$formquestion[] = array('name'=>$input['name'].'min');
4202
					}
4203
					elseif ($input['type'] == 'other')
4204
					{
4205
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4206
						if (!empty($input['label'])) $more .= $input['label'].'</div><div class="tagtd">';
4207
						$more .= $input['value'];
4208
						$more .= '</div></div>'."\n";
4209
					}
4210
4211
					elseif ($input['type'] == 'onecolumn')
4212
					{
4213
						$moreonecolumn .= '<div class="margintoponly">';
4214
						$moreonecolumn .= $input['value'];
4215
						$moreonecolumn .= '</div>'."\n";
4216
					}
4217
				}
4218
			}
4219
			$more .= '</div>'."\n";
4220
			$more .= $moreonecolumn;
4221
		}
4222
4223
		// JQUI method dialog is broken with jmobile, we use standard HTML.
4224
		// 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
4225
		// See page product/card.php for example
4226
		if (!empty($conf->dol_use_jmobile)) $useajax = 0;
4227
		if (empty($conf->use_javascript_ajax)) $useajax = 0;
4228
4229
		if ($useajax)
4230
		{
4231
			$autoOpen = true;
4232
			$dialogconfirm = 'dialog-confirm';
4233
			$button = '';
4234
			if (!is_numeric($useajax))
4235
			{
4236
				$button = $useajax;
4237
				$useajax = 1;
4238
				$autoOpen = false;
4239
				$dialogconfirm .= '-'.$button;
4240
			}
4241
			$pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.$action.'&confirm=yes';
4242
			$pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'confirm=no' : '');
4243
			// Add input fields into list of fields to read during submit (inputok and inputko)
4244
			if (is_array($formquestion))
4245
			{
4246
				foreach ($formquestion as $key => $input)
4247
				{
4248
					//print "xx ".$key." rr ".is_array($input)."<br>\n";
4249
					if (is_array($input) && isset($input['name'])) array_push($inputok, $input['name']);
4250
					if (isset($input['inputko']) && $input['inputko'] == 1) array_push($inputko, $input['name']);
4251
				}
4252
			}
4253
			// Show JQuery confirm box. Note that global var $useglobalvars is used inside this template
4254
			$formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
4255
			if (!empty($formquestion['text'])) {
4256
				$formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
4257
			}
4258
			if (!empty($more)) {
4259
				$formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
4260
			}
4261
			$formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
4262
			$formconfirm .= '</div>'."\n";
4263
4264
			$formconfirm .= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
4265
			$formconfirm .= '<script type="text/javascript">'."\n";
4266
			$formconfirm .= 'jQuery(document).ready(function() {
4267
            $(function() {
4268
            	$( "#'.$dialogconfirm.'" ).dialog(
4269
            	{
4270
                    autoOpen: '.($autoOpen ? "true" : "false").',';
4271
			if ($newselectedchoice == 'no')
4272
			{
4273
				$formconfirm .= '
4274
						open: function() {
4275
            				$(this).parent().find("button.ui-button:eq(2)").focus();
4276
						},';
4277
			}
4278
			$formconfirm .= '
4279
                    resizable: false,
4280
                    height: "'.$height.'",
4281
                    width: "'.$width.'",
4282
                    modal: true,
4283
                    closeOnEscape: false,
4284
                    buttons: {
4285
                        "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
4286
                        	var options = "&token='.urlencode(newToken()).'";
4287
                        	var inputok = '.json_encode($inputok).';
4288
                         	var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
4289
                         	if (inputok.length>0) {
4290
                         		$.each(inputok, function(i, inputname) {
4291
                         			var more = "";
4292
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4293
                         		    if ($("#" + inputname).attr("type") == "radio") { more = ":checked"; }
4294
                         			var inputvalue = $("#" + inputname + more).val();
4295
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4296
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4297
                         		});
4298
                         	}
4299
                         	var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
4300
                         	//alert(urljump);
4301
            				if (pageyes.length > 0) { location.href = urljump; }
4302
                            $(this).dialog("close");
4303
                        },
4304
                        "'.dol_escape_js($langs->transnoentities("No")).'": function() {
4305
                        	var options = "&token='.urlencode(newToken()).'";
4306
                         	var inputko = '.json_encode($inputko).';
4307
                         	var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
4308
                         	if (inputko.length>0) {
4309
                         		$.each(inputko, function(i, inputname) {
4310
                         			var more = "";
4311
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4312
                         			var inputvalue = $("#" + inputname + more).val();
4313
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4314
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4315
                         		});
4316
                         	}
4317
                         	var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
4318
                         	//alert(urljump);
4319
            				if (pageno.length > 0) { location.href = urljump; }
4320
                            $(this).dialog("close");
4321
                        }
4322
                    }
4323
                }
4324
                );
4325
4326
            	var button = "'.$button.'";
4327
            	if (button.length > 0) {
4328
                	$( "#" + button ).click(function() {
4329
                		$("#'.$dialogconfirm.'").dialog("open");
4330
        			});
4331
                }
4332
            });
4333
            });
4334
            </script>';
4335
			$formconfirm .= "<!-- end ajax formconfirm -->\n";
4336
		}
4337
		else
4338
		{
4339
			$formconfirm .= "\n<!-- begin formconfirm page=".$page." -->\n";
4340
4341
			if (empty($disableformtag)) $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
4342
4343
			$formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
4344
			$formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
4345
4346
			$formconfirm .= '<table class="valid centpercent">'."\n";
4347
4348
			// Line title
4349
			$formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="3">'.img_picto('', 'recent').' '.$title.'</td></tr>'."\n";
4350
4351
			// Line text
4352
			if (!empty($formquestion['text'])) {
4353
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="3">'.$formquestion['text'].'</td></tr>'."\n";
4354
			}
4355
4356
			// Line form fields
4357
			if ($more)
4358
			{
4359
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="3">'."\n";
4360
				$formconfirm .= $more;
4361
				$formconfirm .= '</td></tr>'."\n";
4362
			}
4363
4364
			// Line with question
4365
			$formconfirm .= '<tr class="valid">';
4366
			$formconfirm .= '<td class="valid">'.$question.'</td>';
4367
			$formconfirm .= '<td class="valid">';
4368
			$formconfirm .= $this->selectyesno("confirm", $newselectedchoice);
4369
			$formconfirm .= '</td>';
4370
			$formconfirm .= '<td class="valid center"><input class="button valignmiddle" type="submit" value="'.$langs->trans("Validate").'"></td>';
4371
			$formconfirm .= '</tr>'."\n";
4372
4373
			$formconfirm .= '</table>'."\n";
4374
4375
			if (empty($disableformtag)) $formconfirm .= "</form>\n";
4376
			$formconfirm .= '<br>';
4377
4378
			$formconfirm .= "<!-- end formconfirm -->\n";
4379
		}
4380
4381
		return $formconfirm;
4382
	}
4383
4384
4385
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4386
	/**
4387
	 *    Show a form to select a project
4388
	 *
4389
	 *    @param	int		$page        		Page
4390
	 *    @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)
4391
	 *    @param    int		$selected    		Id pre-selected project
4392
	 *    @param    string	$htmlname    		Name of select field
4393
	 *    @param	int		$discard_closed		Discard closed projects (0=Keep,1=hide completely except $selected,2=Disable)
4394
	 *    @param	int		$maxlength			Max length
4395
	 *    @param	int		$forcefocus			Force focus on field (works with javascript only)
4396
	 *    @param    int     $nooutput           No print is done. String is returned.
4397
	 *    @return	string                      Return html content
4398
	 */
4399
    public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0)
4400
	{
4401
        // phpcs:enable
4402
		global $langs;
4403
4404
		require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
4405
		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
4406
4407
		$out = '';
4408
4409
		$formproject = new FormProjets($this->db);
4410
4411
		$langs->load("project");
4412
		if ($htmlname != "none")
4413
		{
4414
			$out .= "\n";
4415
			$out .= '<form method="post" action="'.$page.'">';
4416
			$out .= '<input type="hidden" name="action" value="classin">';
4417
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
4418
			$out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
4419
			$out .= '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4420
			$out .= '</form>';
4421
		}
4422
		else
4423
		{
4424
			if ($selected)
4425
			{
4426
				$projet = new Project($this->db);
4427
				$projet->fetch($selected);
4428
				//print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
4429
				$out .= $projet->getNomUrl(0, '', 1);
4430
			}
4431
			else
4432
			{
4433
				$out .= "&nbsp;";
4434
			}
4435
		}
4436
4437
		if (empty($nooutput))
4438
		{
4439
			print $out;
4440
			return '';
4441
		}
4442
		return $out;
4443
	}
4444
4445
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4446
	/**
4447
	 *	Show a form to select payment conditions
4448
	 *
4449
	 *  @param	int		$page        	Page
4450
	 *  @param  string	$selected    	Id condition pre-selectionne
4451
	 *  @param  string	$htmlname    	Name of select html field
4452
	 *	@param	int		$addempty		Add empty entry
4453
	 *  @return	void
4454
	 */
4455
    public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0)
4456
	{
4457
        // phpcs:enable
4458
		global $langs;
4459
		if ($htmlname != "none")
4460
		{
4461
			print '<form method="post" action="'.$page.'">';
4462
			print '<input type="hidden" name="action" value="setconditions">';
4463
			print '<input type="hidden" name="token" value="'.newToken().'">';
4464
			$this->select_conditions_paiements($selected, $htmlname, -1, $addempty);
4465
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4466
			print '</form>';
4467
		}
4468
		else
4469
		{
4470
			if ($selected)
4471
			{
4472
				$this->load_cache_conditions_paiements();
4473
				print $this->cache_conditions_paiements[$selected]['label'];
4474
			} else {
4475
				print "&nbsp;";
4476
			}
4477
		}
4478
	}
4479
4480
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4481
	/**
4482
	 *  Show a form to select a delivery delay
4483
	 *
4484
	 *  @param  int		$page        	Page
4485
	 *  @param  string	$selected    	Id condition pre-selectionne
4486
	 *  @param  string	$htmlname    	Name of select html field
4487
	 *	@param	int		$addempty		Ajoute entree vide
4488
	 *  @return	void
4489
	 */
4490
    public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
4491
	{
4492
        // phpcs:enable
4493
		global $langs;
4494
		if ($htmlname != "none")
4495
		{
4496
			print '<form method="post" action="'.$page.'">';
4497
			print '<input type="hidden" name="action" value="setavailability">';
4498
			print '<input type="hidden" name="token" value="'.newToken().'">';
4499
			$this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
4500
			print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4501
			print '</form>';
4502
		}
4503
		else
4504
		{
4505
			if ($selected)
4506
			{
4507
				$this->load_cache_availability();
4508
				print $this->cache_availability[$selected]['label'];
4509
			} else {
4510
				print "&nbsp;";
4511
			}
4512
		}
4513
	}
4514
4515
	/**
4516
	 *  Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
4517
	 *  List found into table c_input_reason loaded by loadCacheInputReason
4518
	 *
4519
	 *  @param  string	$page        	Page
4520
	 *  @param  string	$selected    	Id condition pre-selectionne
4521
	 *  @param  string	$htmlname    	Name of select html field
4522
	 *  @param	int		$addempty		Add empty entry
4523
	 *  @return	void
4524
     */
4525
    public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
4526
    {
4527
		global $langs;
4528
		if ($htmlname != "none")
4529
		{
4530
			print '<form method="post" action="'.$page.'">';
4531
			print '<input type="hidden" name="action" value="setdemandreason">';
4532
			print '<input type="hidden" name="token" value="'.newToken().'">';
4533
			$this->selectInputReason($selected, $htmlname, -1, $addempty);
4534
			print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4535
			print '</form>';
4536
		}
4537
		else
4538
		{
4539
			if ($selected)
4540
			{
4541
				$this->loadCacheInputReason();
4542
				foreach ($this->cache_demand_reason as $key => $val)
4543
				{
4544
					if ($val['id'] == $selected)
4545
					{
4546
						print $val['label'];
4547
						break;
4548
					}
4549
				}
4550
			} else {
4551
				print "&nbsp;";
4552
			}
4553
		}
4554
	}
4555
4556
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4557
	/**
4558
	 *    Show a form + html select a date
4559
	 *
4560
	 *    @param	string		$page        	Page
4561
	 *    @param	string		$selected    	Date preselected
4562
	 *    @param    string		$htmlname    	Html name of date input fields or 'none'
4563
	 *    @param    int			$displayhour 	Display hour selector
4564
	 *    @param    int			$displaymin		Display minutes selector
4565
	 *    @param	int			$nooutput		1=No print output, return string
4566
	 *    @return	string
4567
	 *    @see		selectDate()
4568
	 */
4569
    public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0)
4570
	{
4571
        // phpcs:enable
4572
		global $langs;
4573
4574
		$ret = '';
4575
4576
		if ($htmlname != "none")
4577
		{
4578
			$ret .= '<form method="post" action="'.$page.'" name="form'.$htmlname.'">';
4579
			$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
4580
			$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
4581
			$ret .= '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4582
			$ret .= '<tr><td>';
4583
			$ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
4584
			$ret .= '</td>';
4585
			$ret .= '<td class="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4586
			$ret .= '</tr></table></form>';
4587
		}
4588
		else
4589
		{
4590
			if ($displayhour) $ret .= dol_print_date($selected, 'dayhour');
4591
			else $ret .= dol_print_date($selected, 'day');
4592
		}
4593
4594
		if (empty($nooutput)) print $ret;
4595
		return $ret;
4596
	}
4597
4598
4599
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4600
	/**
4601
	 *  Show a select form to choose a user
4602
	 *
4603
	 *  @param	string	$page        	Page
4604
	 *  @param  string	$selected    	Id of user preselected
4605
	 *  @param  string	$htmlname    	Name of input html field. If 'none', we just output the user link.
4606
	 *  @param  array	$exclude		List of users id to exclude
4607
	 *  @param  array	$include        List of users id to include
4608
	 *  @return	void
4609
	 */
4610
    public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
4611
	{
4612
        // phpcs:enable
4613
		global $langs;
4614
4615
		if ($htmlname != "none")
4616
		{
4617
			print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
4618
			print '<input type="hidden" name="action" value="set'.$htmlname.'">';
4619
			print '<input type="hidden" name="token" value="'.newToken().'">';
4620
			print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
4621
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4622
			print '</form>';
4623
		}
4624
		else
4625
		{
4626
			if ($selected)
4627
			{
4628
				require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
4629
				$theuser = new User($this->db);
4630
				$theuser->fetch($selected);
4631
				print $theuser->getNomUrl(1);
4632
			} else {
4633
				print "&nbsp;";
4634
			}
4635
		}
4636
	}
4637
4638
4639
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4640
	/**
4641
	 *    Show form with payment mode
4642
	 *
4643
	 *    @param	string	$page        	Page
4644
	 *    @param    int		$selected    	Id mode pre-selectionne
4645
	 *    @param    string	$htmlname    	Name of select html field
4646
	 *    @param  	string	$filtertype		To filter on field type in llx_c_paiement (array('code'=>xx,'label'=>zz))
4647
	 *    @param    int     $active         Active or not, -1 = all
4648
	 *    @param   int     $addempty       1=Add empty entry
4649
	 *    @return	void
4650
	 */
4651
    public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0)
4652
	{
4653
        // phpcs:enable
4654
		global $langs;
4655
		if ($htmlname != "none")
4656
		{
4657
			print '<form method="POST" action="'.$page.'">';
4658
			print '<input type="hidden" name="action" value="setmode">';
4659
			print '<input type="hidden" name="token" value="'.newToken().'">';
4660
			$this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active);
4661
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4662
			print '</form>';
4663
		}
4664
		else
4665
		{
4666
			if ($selected)
4667
			{
4668
				$this->load_cache_types_paiements();
4669
				print $this->cache_types_paiements[$selected]['label'];
4670
			} else {
4671
				print "&nbsp;";
4672
			}
4673
		}
4674
	}
4675
4676
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4677
	/**
4678
	 *    Show form with multicurrency code
4679
	 *
4680
	 *    @param	string	$page        	Page
4681
	 *    @param    string	$selected    	code pre-selectionne
4682
	 *    @param    string	$htmlname    	Name of select html field
4683
	 *    @return	void
4684
	 */
4685
    public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
4686
	{
4687
        // phpcs:enable
4688
		global $langs;
4689
		if ($htmlname != "none")
4690
		{
4691
			print '<form method="POST" action="'.$page.'">';
4692
			print '<input type="hidden" name="action" value="setmulticurrencycode">';
4693
			print '<input type="hidden" name="token" value="'.newToken().'">';
4694
			print $this->selectMultiCurrency($selected, $htmlname, 0);
4695
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4696
			print '</form>';
4697
		}
4698
		else
4699
		{
4700
			dol_include_once('/core/lib/company.lib.php');
4701
			print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
4702
		}
4703
	}
4704
4705
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4706
	/**
4707
	 *    Show form with multicurrency rate
4708
	 *
4709
	 *    @param	string	$page        	Page
4710
	 *    @param    double	$rate	    	Current rate
4711
	 *    @param    string	$htmlname    	Name of select html field
4712
	 *    @param    string  $currency       Currency code to explain the rate
4713
	 *    @return	void
4714
	 */
4715
    public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
4716
	{
4717
        // phpcs:enable
4718
		global $langs, $mysoc, $conf;
4719
4720
		if ($htmlname != "none")
4721
		{
4722
			print '<form method="POST" action="'.$page.'">';
4723
			print '<input type="hidden" name="action" value="setmulticurrencyrate">';
4724
			print '<input type="hidden" name="token" value="'.newToken().'">';
4725
			print '<input type="text" name="'.$htmlname.'" value="'.(!empty($rate) ? price($rate) : 1).'" size="10" /> ';
4726
			print '<select name="calculation_mode">';
4727
			print '<option value="1">'.$currency.' > '.$conf->currency.'</option>';
4728
			print '<option value="2">'.$conf->currency.' > '.$currency.'</option>';
4729
			print '</select> ';
4730
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4731
			print '</form>';
4732
		}
4733
		else
4734
		{
4735
			if (!empty($rate))
4736
			{
4737
				print price($rate, 1, $langs, 1, 0);
4738
				if ($currency && $rate != 1) print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
4739
			}
4740
			else
4741
			{
4742
				print 1;
4743
			}
4744
		}
4745
	}
4746
4747
4748
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4749
	/**
4750
	 *	Show a select box with available absolute discounts
4751
	 *
4752
	 *  @param  string	$page        	Page URL where form is shown
4753
	 *  @param  int		$selected    	Value pre-selected
4754
	 *	@param  string	$htmlname    	Name of SELECT component. If 'none', not changeable. Example 'remise_id'.
4755
	 *	@param	int		$socid			Third party id
4756
	 * 	@param	float	$amount			Total amount available
4757
	 * 	@param	string	$filter			SQL filter on discounts
4758
	 * 	@param	int		$maxvalue		Max value for lines that can be selected
4759
	 *  @param  string	$more           More string to add
4760
	 *  @param  int     $hidelist       1=Hide list
4761
	 *  @param	int		$discount_type	0 => customer discount, 1 => supplier discount
4762
	 *  @return	void
4763
	 */
4764
    public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
4765
	{
4766
        // phpcs:enable
4767
		global $conf, $langs;
4768
		if ($htmlname != "none")
4769
		{
4770
			print '<form method="post" action="'.$page.'">';
4771
			print '<input type="hidden" name="action" value="setabsolutediscount">';
4772
			print '<input type="hidden" name="token" value="'.newToken().'">';
4773
			print '<div class="inline-block">';
4774
			if (!empty($discount_type)) {
4775
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4776
				{
4777
					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
4778
					else $translationKey = 'HasCreditNoteFromSupplier';
4779
				}
4780
				else
4781
				{
4782
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") $translationKey = 'HasAbsoluteDiscountFromSupplier';
4783
					else $translationKey = 'HasCreditNoteFromSupplier';
4784
				}
4785
			} else {
4786
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4787
				{
4788
					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
4789
					else $translationKey = 'CompanyHasCreditNote';
4790
				}
4791
				else
4792
				{
4793
					if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") $translationKey = 'CompanyHasAbsoluteDiscount';
4794
					else $translationKey = 'CompanyHasCreditNote';
4795
				}
4796
			}
4797
			print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
4798
			if (empty($hidelist)) print ': ';
4799
			print '</div>';
4800
			if (empty($hidelist))
4801
			{
4802
				print '<div class="inline-block" style="padding-right: 10px">';
4803
				$newfilter = 'discount_type='.intval($discount_type);
4804
				if (!empty($discount_type)) {
4805
					$newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
4806
				} else {
4807
					$newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
4808
				}
4809
				if ($filter) $newfilter .= ' AND ('.$filter.')';
4810
				$nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
4811
				if ($nbqualifiedlines > 0)
4812
				{
4813
					print ' &nbsp; <input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
4814
					if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')")
4815
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4816
					if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')")
4817
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4818
4819
					print '>';
4820
				}
4821
				print '</div>';
4822
			}
4823
			if ($more)
4824
			{
4825
				print '<div class="inline-block">';
4826
				print $more;
4827
				print '</div>';
4828
			}
4829
			print '</form>';
4830
		}
4831
		else
4832
		{
4833
			if ($selected)
4834
			{
4835
				print $selected;
4836
			}
4837
			else
4838
			{
4839
				print "0";
4840
			}
4841
		}
4842
	}
4843
4844
4845
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4846
    /**
4847
     *  Show forms to select a contact
4848
     *
4849
     *  @param	string		$page        	Page
4850
     *  @param	Societe		$societe		Filter on third party
4851
     *  @param    int			$selected    	Id contact pre-selectionne
4852
     *  @param    string		$htmlname    	Name of HTML select. If 'none', we just show contact link.
4853
     *  @return	void
4854
     */
4855
    public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
4856
    {
4857
        // phpcs:enable
4858
		global $langs, $conf;
4859
4860
		if ($htmlname != "none")
4861
		{
4862
			print '<form method="post" action="'.$page.'">';
4863
			print '<input type="hidden" name="action" value="set_contact">';
4864
			print '<input type="hidden" name="token" value="'.newToken().'">';
4865
			print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4866
			print '<tr><td>';
4867
			$num = $this->select_contacts($societe->id, $selected, $htmlname);
4868
			if ($num == 0)
4869
			{
4870
				$addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
4871
				print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
4872
			}
4873
			print '</td>';
4874
			print '<td class="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4875
			print '</tr></table></form>';
4876
		}
4877
		else
4878
		{
4879
			if ($selected)
4880
			{
4881
				require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
4882
				$contact = new Contact($this->db);
4883
				$contact->fetch($selected);
4884
				print $contact->getFullName($langs);
4885
			} else {
4886
				print "&nbsp;";
4887
			}
4888
		}
4889
	}
4890
4891
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4892
	/**
4893
	 *  Output html select to select thirdparty
4894
	 *
4895
	 *  @param	string	$page       	Page
4896
	 *  @param  string	$selected   	Id preselected
4897
	 *  @param  string	$htmlname		Name of HTML select
4898
	 *  @param  string	$filter         optional filters criteras
4899
	 *	@param	int		$showempty		Add an empty field
4900
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
4901
	 * 	@param	int		$forcecombo		Force to use combo box
4902
	 *  @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')))
4903
	 *  @param  int     $nooutput       No print output. Return it only.
4904
	 *  @return	void|string
4905
	 */
4906
    public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0)
4907
	{
4908
        // phpcs:enable
4909
		global $langs;
4910
4911
		$out = '';
4912
		if ($htmlname != "none")
4913
		{
4914
			$out .= '<form method="post" action="'.$page.'">';
4915
			$out .= '<input type="hidden" name="action" value="set_thirdparty">';
4916
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
4917
			$out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events);
4918
			$out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4919
			$out .= '</form>';
4920
		}
4921
		else
4922
		{
4923
			if ($selected)
4924
			{
4925
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
4926
				$soc = new Societe($this->db);
4927
				$soc->fetch($selected);
4928
				$out .= $soc->getNomUrl($langs);
4929
			}
4930
			else
4931
			{
4932
				$out .= "&nbsp;";
4933
			}
4934
		}
4935
4936
		if ($nooutput) return $out;
4937
		else print $out;
4938
	}
4939
4940
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4941
	/**
4942
	 *    Retourne la liste des devises, dans la langue de l'utilisateur
4943
	 *
4944
	 *    @param	string	$selected    preselected currency code
4945
	 *    @param    string	$htmlname    name of HTML select list
4946
     *    @deprecated
4947
	 *    @return	void
4948
	 */
4949
    public function select_currency($selected = '', $htmlname = 'currency_id')
4950
	{
4951
        // phpcs:enable
4952
		print $this->selectCurrency($selected, $htmlname);
4953
	}
4954
4955
	/**
4956
	 *  Retourne la liste des devises, dans la langue de l'utilisateur
4957
	 *
4958
	 *  @param	string	$selected    preselected currency code
4959
	 *  @param  string	$htmlname    name of HTML select list
4960
	 *  @param  string  $mode        0 = Add currency symbol into label, 1 = Add 3 letter iso code
4961
	 * 	@return	string
4962
	 */
4963
    public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0)
4964
	{
4965
		global $conf, $langs, $user;
4966
4967
		$langs->loadCacheCurrencies('');
4968
4969
		$out = '';
4970
4971
		if ($selected == 'euro' || $selected == 'euros') $selected = 'EUR'; // Pour compatibilite
4972
4973
		$out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
4974
		foreach ($langs->cache_currencies as $code_iso => $currency)
4975
		{
4976
			if ($selected && $selected == $code_iso)
4977
			{
4978
				$out .= '<option value="'.$code_iso.'" selected>';
4979
			}
4980
			else
4981
			{
4982
				$out .= '<option value="'.$code_iso.'">';
4983
			}
4984
			$out .= $currency['label'];
4985
			if ($mode == 1)
4986
			{
4987
			    $out .= ' ('.$code_iso.')';
4988
			}
4989
			else
4990
			{
4991
                $out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
4992
			}
4993
			$out .= '</option>';
4994
		}
4995
		$out .= '</select>';
4996
		if ($user->admin) $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4997
4998
		// Make select dynamic
4999
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5000
		$out .= ajax_combobox($htmlname);
5001
5002
		return $out;
5003
	}
5004
5005
	/**
5006
	 *	Return array of currencies in user language
5007
	 *
5008
	 *  @param	string	$selected    preselected currency code
5009
	 *  @param  string	$htmlname    name of HTML select list
5010
	 *  @param  integer	$useempty    1=Add empty line
5011
	 * 	@return	string
5012
	 */
5013
    public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0)
5014
	{
5015
		global $db, $conf, $langs, $user;
5016
5017
		$langs->loadCacheCurrencies(''); // Load ->cache_currencies
5018
5019
		$TCurrency = array();
5020
5021
		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
5022
		$sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
5023
		$resql = $db->query($sql);
5024
		if ($resql)
5025
		{
5026
			while ($obj = $db->fetch_object($resql)) $TCurrency[$obj->code] = $obj->code;
5027
		}
5028
5029
		$out = '';
5030
		$out .= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
5031
		if ($useempty) $out .= '<option value="">&nbsp;</option>';
5032
		// If company current currency not in table, we add it into list. Should always be available.
5033
		if (!in_array($conf->currency, $TCurrency))
5034
		{
5035
			$TCurrency[$conf->currency] = $conf->currency;
5036
		}
5037
		if (count($TCurrency) > 0)
5038
		{
5039
			foreach ($langs->cache_currencies as $code_iso => $currency)
5040
			{
5041
				if (isset($TCurrency[$code_iso]))
5042
				{
5043
					if (!empty($selected) && $selected == $code_iso) $out .= '<option value="'.$code_iso.'" selected="selected">';
5044
					else $out .= '<option value="'.$code_iso.'">';
5045
5046
					$out .= $currency['label'];
5047
					$out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5048
					$out .= '</option>';
5049
				}
5050
			}
5051
		}
5052
5053
		$out .= '</select>';
5054
		// Make select dynamic
5055
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5056
		$out .= ajax_combobox($htmlname);
5057
5058
		return $out;
5059
	}
5060
5061
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5062
	/**
5063
	 *  Load into the cache vat rates of a country
5064
	 *
5065
	 *  @param	string	$country_code		Country code with quotes ("'CA'", or "'CA,IN,...'")
5066
	 *  @return	int							Nb of loaded lines, 0 if already loaded, <0 if KO
5067
	 */
5068
    public function load_cache_vatrates($country_code)
5069
	{
5070
        // phpcs:enable
5071
		global $langs;
5072
5073
		$num = count($this->cache_vatrates);
5074
		if ($num > 0) return $num; // Cache already loaded
5075
5076
		dol_syslog(__METHOD__, LOG_DEBUG);
5077
5078
		$sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
5079
		$sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
5080
		$sql .= " WHERE t.fk_pays = c.rowid";
5081
		$sql .= " AND t.active > 0";
5082
		$sql .= " AND c.code IN (".$country_code.")";
5083
		$sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
5084
5085
		$resql = $this->db->query($sql);
5086
		if ($resql)
5087
		{
5088
			$num = $this->db->num_rows($resql);
5089
			if ($num)
5090
			{
5091
				for ($i = 0; $i < $num; $i++)
5092
				{
5093
					$obj = $this->db->fetch_object($resql);
5094
					$this->cache_vatrates[$i]['rowid']	= $obj->rowid;
5095
					$this->cache_vatrates[$i]['code'] = $obj->code;
5096
					$this->cache_vatrates[$i]['txtva']	= $obj->taux;
5097
					$this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
5098
					$this->cache_vatrates[$i]['localtax1']	    = $obj->localtax1;
5099
					$this->cache_vatrates[$i]['localtax1_type']	= $obj->localtax1_type;
5100
					$this->cache_vatrates[$i]['localtax2']	    = $obj->localtax2;
5101
					$this->cache_vatrates[$i]['localtax2_type']	= $obj->localtax1_type;
5102
5103
					$this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
5104
					$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
5105
					$positiverates = '';
5106
					if ($obj->taux) $positiverates .= ($positiverates ? '/' : '').$obj->taux;
5107
					if ($obj->localtax1) $positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
5108
					if ($obj->localtax2) $positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
5109
					if (empty($positiverates)) $positiverates = '0';
5110
					$this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
5111
				}
5112
5113
				return $num;
5114
			}
5115
			else
5116
			{
5117
				$this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</font>';
5118
				return -1;
5119
			}
5120
		}
5121
		else
5122
		{
5123
			$this->error = '<font class="error">'.$this->db->error().'</font>';
5124
			return -2;
5125
		}
5126
	}
5127
5128
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5129
	/**
5130
	 *  Output an HTML select vat rate.
5131
	 *  The name of this function should be selectVat. We keep bad name for compatibility purpose.
5132
	 *
5133
	 *  @param	string	      $htmlname           Name of HTML select field
5134
	 *  @param  float|string  $selectedrate       Force preselected vat rate. Can be '8.5' or '8.5 (NOO)' for example. Use '' for no forcing.
5135
	 *  @param  Societe	      $societe_vendeuse   Thirdparty seller
5136
	 *  @param  Societe	      $societe_acheteuse  Thirdparty buyer
5137
	 *  @param  int		      $idprod             Id product. O if unknown of NA.
5138
	 *  @param  int		      $info_bits          Miscellaneous information on line (1 for NPR)
5139
	 *  @param  int|string    $type               ''=Unknown, 0=Product, 1=Service (Used if idprod not defined)
5140
	 *                  		                  Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle.
5141
	 *                  					      Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle.
5142
	 *                  					      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.
5143
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= particulier alors TVA par défaut=TVA du produit vendu. Fin de règle.
5144
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= entreprise alors TVA par défaut=0. Fin de règle.
5145
	 *                  					      Sinon la TVA proposee par defaut=0. Fin de regle.
5146
	 *  @param	bool	     $options_only		  Return HTML options lines only (for ajax treatment)
5147
	 *  @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
5148
	 *  @return	string
5149
	 */
5150
    public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
5151
	{
5152
        // phpcs:enable
5153
		global $langs, $conf, $mysoc;
5154
5155
		$langs->load('errors');
5156
5157
		$return = '';
5158
5159
		// Define defaultnpr, defaultttx and defaultcode
5160
		$defaultnpr = ($info_bits & 0x01);
5161
		$defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
5162
		$defaulttx = str_replace('*', '', $selectedrate);
5163
		$defaultcode = '';
5164
		if (preg_match('/\((.*)\)/', $defaulttx, $reg))
5165
		{
5166
			$defaultcode = $reg[1];
5167
			$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5168
		}
5169
		//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
5170
5171
		// Check parameters
5172
		if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code)
5173
		{
5174
			if ($societe_vendeuse->id == $mysoc->id)
5175
			{
5176
				$return .= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</font>';
5177
			}
5178
			else
5179
			{
5180
				$return .= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</font>';
5181
			}
5182
			return $return;
5183
		}
5184
5185
		//var_dump($societe_acheteuse);
5186
		//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";
5187
		//exit;
5188
5189
		// Define list of countries to use to search VAT rates to show
5190
		// First we defined code_country to use to find list
5191
		if (is_object($societe_vendeuse))
5192
		{
5193
			$code_country = "'".$societe_vendeuse->country_code."'";
5194
		}
5195
		else
5196
		{
5197
			$code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
5198
		}
5199
		if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC))    // If option to have vat for end customer for services is on
5200
		{
5201
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
5202
			if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany())))
5203
			{
5204
				// We also add the buyer
5205
				if (is_numeric($type))
5206
				{
5207
					if ($type == 1) // We know product is a service
5208
					{
5209
						$code_country .= ",'".$societe_acheteuse->country_code."'";
5210
					}
5211
				}
5212
				elseif (!$idprod)  // We don't know type of product
5213
				{
5214
					$code_country .= ",'".$societe_acheteuse->country_code."'";
5215
				}
5216
				else
5217
				{
5218
					$prodstatic = new Product($this->db);
5219
					$prodstatic->fetch($idprod);
5220
					if ($prodstatic->type == Product::TYPE_SERVICE)   // We know product is a service
5221
					{
5222
						$code_country .= ",'".$societe_acheteuse->country_code."'";
5223
					}
5224
				}
5225
			}
5226
		}
5227
5228
		// Now we get list
5229
		$num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
5230
5231
		if ($num > 0)
5232
		{
5233
			// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
5234
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
5235
			{
5236
				$tmpthirdparty = new Societe($this->db);
5237
				$defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5238
				$defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5239
		        if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
5240
			        $defaultcode = $reg[1];
5241
			        $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5242
		        }
5243
				if (empty($defaulttx)) $defaultnpr = 0;
5244
			}
5245
5246
			// Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
5247
			// Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
5248
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
5249
			{
5250
				if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
5251
				else $defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
5252
			}
5253
5254
			// Disabled if seller is not subject to VAT
5255
			$disabled = false; $title = '';
5256
			if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0")
5257
			{
5258
				// Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses
5259
				if (empty($conf->global->OVERRIDE_VAT_FOR_EXPENSE_REPORT))
5260
				{
5261
					$title = ' title="'.$langs->trans('VATIsNotUsed').'"';
5262
					$disabled = true;
5263
				}
5264
			}
5265
5266
			if (!$options_only) $return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
5267
5268
			$selectedfound = false;
5269
			foreach ($this->cache_vatrates as $rate)
5270
			{
5271
				// Keep only 0 if seller is not subject to VAT
5272
				if ($disabled && $rate['txtva'] != 0) continue;
5273
5274
				// Define key to use into select list
5275
				$key = $rate['txtva'];
5276
				$key .= $rate['nprtva'] ? '*' : '';
5277
				if ($mode > 0 && $rate['code']) $key .= ' ('.$rate['code'].')';
5278
				if ($mode < 0) $key = $rate['rowid'];
5279
5280
				$return .= '<option value="'.$key.'"';
5281
				if (!$selectedfound)
5282
				{
5283
					if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
5284
					{
5285
						if ($defaultcode == $rate['code'])
5286
						{
5287
							$return .= ' selected';
5288
							$selectedfound = true;
5289
						}
5290
					}
5291
					elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
5292
			   		{
5293
			   			$return .= ' selected';
5294
			   			$selectedfound = true;
5295
					}
5296
				}
5297
				$return .= '>';
5298
				//if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
5299
				if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES))
5300
				{
5301
					$return .= $rate['labelpositiverates'];
5302
				}
5303
				else
5304
				{
5305
					$return .= vatrate($rate['label']);
5306
				}
5307
				//$return.=($rate['code']?' '.$rate['code']:'');
5308
				$return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the *  (old behaviour only if new vat code is not used)
5309
5310
				$return .= '</option>';
5311
			}
5312
5313
			if (!$options_only) $return .= '</select>';
5314
		}
5315
		else
5316
		{
5317
			$return .= $this->error;
5318
		}
5319
5320
		$this->num = $num;
5321
		return $return;
5322
	}
5323
5324
5325
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5326
    /**
5327
     *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5328
	 *  Fields are preselected with :
5329
	 *            	- set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5330
	 *            	- local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5331
	 *            	- Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5332
	 *
5333
	 *	@param	integer	    $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).
5334
	 *	@param	string		$prefix			Prefix for fields name
5335
	 *	@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
5336
	 *	@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
5337
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5338
	 *	@param	string		$form_name 		Not used
5339
	 *	@param	int			$d				1=Show days, month, years
5340
	 * 	@param	int			$addnowlink		Add a link "Now"
5341
	 * 	@param	int			$nooutput		Do not output html string but return it
5342
	 * 	@param 	int			$disabled		Disable input fields
5343
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
5344
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another select_date field.
5345
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
5346
	 *  @return	string|void					Nothing or string if nooutput is 1
5347
     *  @deprecated
5348
	 *  @see    selectDate(), form_date(), select_month(), select_year(), select_dayofweek()
5349
	 */
5350
    public function select_date($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $nooutput = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '')
5351
    {
5352
        // phpcs:enable
5353
        $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
5354
        if (!empty($nooutput)) {
5355
            return $retstring;
5356
        }
5357
        print $retstring;
5358
        return;
5359
    }
5360
5361
    /**
5362
     *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5363
	 *  Fields are preselected with :
5364
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5365
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5366
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5367
	 *
5368
	 *  @param  integer     $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).
5369
	 *  @param	string		$prefix			Prefix for fields name
5370
	 *  @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
5371
	 *	@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
5372
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5373
	 *	@param	string		$form_name 		Not used
5374
	 *	@param	int			$d				1=Show days, month, years
5375
	 * 	@param	int			$addnowlink		Add a link "Now", 1 with server time, 2 with local computer time
5376
	 * 	@param 	int			$disabled		Disable input fields
5377
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
5378
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another selectDate field.
5379
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date. See also $labeladddateof for the label used.
5380
     *  @param  string      $openinghours   Specify hour start and hour end for the select ex 8,20
5381
     *  @param  int         $stepminutes    Specify step for minutes between 1 and 30
5382
     *  @param	string		$labeladddateof Label to use for the $adddateof parameter.
5383
	 * 	@return string                      Html for selectDate
5384
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
5385
	 */
5386
    public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '')
5387
	{
5388
		global $conf, $langs;
5389
5390
		$retstring = '';
5391
5392
		if ($prefix == '') $prefix = 're';
5393
		if ($h == '') $h = 0;
5394
		if ($m == '') $m = 0;
5395
		$emptydate = 0;
5396
		$emptyhours = 0;
5397
        if ($stepminutes <= 0 || $stepminutes > 30) $stepminutes = 1;
5398
		if ($empty == 1) { $emptydate = 1; $emptyhours = 1; }
5399
		if ($empty == 2) { $emptydate = 0; $emptyhours = 1; }
5400
		$orig_set_time = $set_time;
5401
5402
		if ($set_time === '' && $emptydate == 0)
5403
		{
5404
			include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5405
			$set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
5406
		}
5407
5408
		// Analysis of the pre-selection date
5409
		if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg))	// deprecated usage
5410
		{
5411
			// Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
5412
			$syear	= (!empty($reg[1]) ? $reg[1] : '');
5413
			$smonth = (!empty($reg[2]) ? $reg[2] : '');
5414
			$sday	= (!empty($reg[3]) ? $reg[3] : '');
5415
			$shour	= (!empty($reg[4]) ? $reg[4] : '');
5416
			$smin	= (!empty($reg[5]) ? $reg[5] : '');
5417
		}
5418
		elseif (strval($set_time) != '' && $set_time != -1)
5419
		{
5420
			// set_time est un timestamps (0 possible)
5421
			$syear = dol_print_date($set_time, "%Y");
5422
			$smonth = dol_print_date($set_time, "%m");
5423
			$sday = dol_print_date($set_time, "%d");
5424
			if ($orig_set_time != '')
5425
			{
5426
				$shour = dol_print_date($set_time, "%H");
5427
				$smin = dol_print_date($set_time, "%M");
5428
				$ssec = dol_print_date($set_time, "%S");
5429
			}
5430
			else
5431
			{
5432
				$shour = '';
5433
				$smin = '';
5434
				$ssec = '';
5435
			}
5436
		}
5437
		else
5438
		{
5439
			// Date est '' ou vaut -1
5440
			$syear = '';
5441
			$smonth = '';
5442
			$sday = '';
5443
			$shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
5444
			$smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
5445
			$ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
5446
		}
5447
		if ($h == 3) $shour = '';
5448
		if ($m == 3) $smin = '';
5449
5450
		// You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
5451
		$usecalendar = 'combo';
5452
		if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
5453
			$usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
5454
		}
5455
5456
		if ($d)
5457
		{
5458
			// Show date with popup
5459
			if ($usecalendar != 'combo')
5460
			{
5461
				$formated_date = '';
5462
				//print "e".$set_time." t ".$conf->format_date_short;
5463
				if (strval($set_time) != '' && $set_time != -1)
5464
				{
5465
					//$formated_date=dol_print_date($set_time,$conf->format_date_short);
5466
					$formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput")); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5467
				}
5468
5469
				// Calendrier popup version eldy
5470
				if ($usecalendar == "eldy")
5471
				{
5472
					// Zone de saisie manuelle de la date
5473
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidth75" maxlength="11" value="'.$formated_date.'"';
5474
					$retstring .= ($disabled ? ' disabled' : '');
5475
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5476
					$retstring .= '>';
5477
5478
					// Icone calendrier
5479
					if (!$disabled)
5480
					{
5481
						$retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
5482
						$base = DOL_URL_ROOT.'/core/';
5483
						$retstring .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
5484
						$retstring .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
5485
					}
5486
					else $retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
5487
5488
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
5489
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5490
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
5491
				}
5492
				elseif ($usecalendar == 'jquery')
5493
				{
5494
					if (!$disabled)
5495
					{
5496
						// Output javascript for datepicker
5497
						$retstring .= "<script type='text/javascript'>";
5498
						$retstring .= "$(function(){ $('#".$prefix."').datepicker({
5499
							dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
5500
							autoclose: true,
5501
							todayHighlight: true,";
5502
						if (!empty($conf->dol_use_jmobile))
5503
						{
5504
							$retstring .= "
5505
								beforeShow: function (input, datePicker) {
5506
									input.disabled = true;
5507
								},
5508
								onClose: function (dateText, datePicker) {
5509
									this.disabled = false;
5510
								},
5511
								";
5512
						}
5513
						// Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
5514
						if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS))
5515
						{
5516
							$retstring .= "
5517
								showOn: 'button',
5518
								buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png',
5519
								buttonImageOnly: true";
5520
						}
5521
						$retstring .= "
5522
							}) });";
5523
						$retstring .= "</script>";
5524
					}
5525
5526
					// Zone de saisie manuelle de la date
5527
					$retstring .= '<div class="nowrap inline-block">';
5528
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidth75" maxlength="11" value="'.$formated_date.'"';
5529
					$retstring .= ($disabled ? ' disabled' : '');
5530
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5531
					$retstring .= '>';
5532
5533
					// Icone calendrier
5534
					if (!$disabled)
5535
					{
5536
						/* Not required. Managed by option buttonImage of jquery
5537
                		$retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
5538
                		$retstring.="<script type='text/javascript'>";
5539
                		$retstring.="jQuery(document).ready(function() {";
5540
                		$retstring.='	jQuery("#'.$prefix.'id").click(function() {';
5541
                		$retstring.="    	jQuery('#".$prefix."').focus();";
5542
                		$retstring.='    });';
5543
                		$retstring.='});';
5544
                		$retstring.="</script>";*/
5545
					}
5546
					else
5547
					{
5548
						$retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
5549
					}
5550
5551
					$retstring .= '</div>';
5552
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
5553
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5554
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
5555
				}
5556
				else
5557
				{
5558
					$retstring .= "Bad value of MAIN_POPUP_CALENDAR";
5559
				}
5560
			}
5561
			// Show date with combo selects
5562
			else
5563
			{
5564
				//$retstring.='<div class="inline-block">';
5565
				// Day
5566
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
5567
5568
				if ($emptydate || $set_time == -1)
5569
				{
5570
					$retstring .= '<option value="0" selected>&nbsp;</option>';
5571
				}
5572
5573
				for ($day = 1; $day <= 31; $day++)
5574
				{
5575
					$retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
5576
				}
5577
5578
				$retstring .= "</select>";
5579
5580
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
5581
				if ($emptydate || $set_time == -1)
5582
				{
5583
					$retstring .= '<option value="0" selected>&nbsp;</option>';
5584
				}
5585
5586
				// Month
5587
				for ($month = 1; $month <= 12; $month++)
5588
				{
5589
					$retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
5590
					$retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
5591
					$retstring .= "</option>";
5592
				}
5593
				$retstring .= "</select>";
5594
5595
				// Year
5596
				if ($emptydate || $set_time == -1)
5597
				{
5598
					$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.'">';
5599
				}
5600
				else
5601
				{
5602
					$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
5603
5604
					for ($year = $syear - 10; $year < $syear + 10; $year++)
5605
					{
5606
						$retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
5607
					}
5608
					$retstring .= "</select>\n";
5609
				}
5610
				//$retstring.='</div>';
5611
			}
5612
		}
5613
5614
		if ($d && $h) $retstring .= ($h == 2 ? '<br>' : ' ');
5615
5616
		if ($h)
5617
		{
5618
			$hourstart = 0;
5619
			$hourend = 24;
5620
			if ($openinghours != '') {
5621
				$openinghours = explode(',', $openinghours);
5622
				$hourstart = $openinghours[0];
5623
				$hourend = $openinghours[1];
5624
				if ($hourend < $hourstart) $hourend = $hourstart;
5625
			}
5626
			// Show hour
5627
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
5628
			if ($emptyhours) $retstring .= '<option value="-1">&nbsp;</option>';
5629
			for ($hour = $hourstart; $hour < $hourend; $hour++)
5630
			{
5631
				if (strlen($hour) < 2) $hour = "0".$hour;
5632
				$retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour.(empty($conf->dol_optimize_smallscreen) ? '' : 'H').'</option>';
5633
			}
5634
			$retstring .= '</select>';
5635
			if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
5636
		}
5637
5638
		if ($m)
5639
		{
5640
			// Show minutes
5641
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
5642
			if ($emptyhours) $retstring .= '<option value="-1">&nbsp;</option>';
5643
			for ($min = 0; $min < 60; $min += $stepminutes)
5644
			{
5645
				if (strlen($min) < 2) $min = "0".$min;
5646
				$retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
5647
			}
5648
			$retstring .= '</select>';
5649
5650
			$retstring .= '<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ssec does not seem to be defined for all execution paths leading up to this point.
Loading history...
5651
		}
5652
5653
		// Add a "Now" link
5654
		if ($conf->use_javascript_ajax && $addnowlink)
5655
		{
5656
			// Script which will be inserted in the onClick of the "Now" link
5657
			$reset_scripts = "";
5658
            if ($addnowlink == 2) // local computer time
5659
            {
5660
                // pad add leading 0 on numbers
5661
                $reset_scripts .= "Number.prototype.pad = function(size) {
5662
                        var s = String(this);
5663
                        while (s.length < (size || 2)) {s = '0' + s;}
5664
                        return s;
5665
                    };
5666
                    var d = new Date();";
5667
            }
5668
5669
			// Generate the date part, depending on the use or not of the javascript calendar
5670
            if ($addnowlink == 1) // server time expressed in user time setup
5671
            {
5672
                $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(), 'day', 'tzuser').'\');';
5673
                $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(), '%d', 'tzuser').'\');';
5674
                $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(), '%m', 'tzuser').'\');';
5675
                $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(), '%Y', 'tzuser').'\');';
5676
            }
5677
            elseif ($addnowlink == 2)
5678
            {
5679
                $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
5680
                $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
5681
                $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
5682
                $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
5683
            }
5684
			/*if ($usecalendar == "eldy")
5685
            {
5686
                $base=DOL_URL_ROOT.'/core/';
5687
                $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
5688
            }
5689
            else
5690
            {
5691
                $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
5692
                $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
5693
                $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
5694
            }*/
5695
			// Update the hour part
5696
			if ($h)
5697
			{
5698
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5699
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
5700
                if ($addnowlink == 1)
5701
                {
5702
                    $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(), '%H', 'tzuser').'\');';
5703
                }
5704
                elseif ($addnowlink == 2)
5705
                {
5706
                    $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
5707
                }
5708
5709
				if ($fullday) $reset_scripts .= ' } ';
5710
			}
5711
			// Update the minute part
5712
			if ($m)
5713
			{
5714
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5715
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
5716
                if ($addnowlink == 1)
5717
                {
5718
                    $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(), '%M', 'tzuser').'\');';
5719
                }
5720
                elseif ($addnowlink == 2)
5721
                {
5722
                    $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
5723
                }
5724
				if ($fullday) $reset_scripts .= ' } ';
5725
			}
5726
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5727
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5728
			{
5729
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
5730
				$retstring .= $langs->trans("Now");
5731
				$retstring .= '</button> ';
5732
			}
5733
		}
5734
5735
		// Add a "Plus one hour" link
5736
		if ($conf->use_javascript_ajax && $addplusone)
5737
		{
5738
			// Script which will be inserted in the onClick of the "Add plusone" link
5739
			$reset_scripts = "";
5740
5741
			// Generate the date part, depending on the use or not of the javascript calendar
5742
			$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(), 'day').'\');';
5743
			$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(), '%d').'\');';
5744
			$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(), '%m').'\');';
5745
			$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(), '%Y').'\');';
5746
			// Update the hour part
5747
			if ($h)
5748
			{
5749
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5750
				$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(), '%H').'\');';
5751
				if ($fullday) $reset_scripts .= ' } ';
5752
			}
5753
			// Update the minute part
5754
			if ($m)
5755
			{
5756
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5757
				$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(), '%M').'\');';
5758
				if ($fullday) $reset_scripts .= ' } ';
5759
			}
5760
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5761
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5762
			{
5763
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
5764
				$retstring .= $langs->trans("DateStartPlusOne");
5765
				$retstring .= '</button> ';
5766
			}
5767
		}
5768
5769
		// Add a "Plus one hour" link
5770
		if ($conf->use_javascript_ajax && $adddateof)
5771
		{
5772
			$tmparray = dol_getdate($adddateof);
5773
			if (empty($labeladddateof)) $labeladddateof = $langs->trans("DateInvoice");
5774
			$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'].'\');">'.$labeladddateof.'</a>';
5775
		}
5776
5777
		return $retstring;
5778
	}
5779
5780
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5781
    /**
5782
     *  Function to show a form to select a duration on a page
5783
	 *
5784
	 *	@param	string		$prefix   		Prefix for input fields
5785
	 *	@param  int			$iSecond  		Default preselected duration (number of seconds or '')
5786
	 * 	@param	int			$disabled       Disable the combo box
5787
	 * 	@param	string		$typehour		If 'select' then input hour and input min is a combo,
5788
	 *						            	If 'text' input hour is in text and input min is a text,
5789
	 *						            	If 'textselect' input hour is in text and input min is a combo
5790
	 *  @param	integer		$minunderhours	If 1, show minutes selection under the hours
5791
	 * 	@param	int			$nooutput		Do not output html string but return it
5792
	 *  @return	string|void
5793
	 */
5794
    public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
5795
	{
5796
        // phpcs:enable
5797
		global $langs;
5798
5799
		$retstring = '';
5800
5801
		$hourSelected = 0; $minSelected = 0;
5802
5803
		// Hours
5804
		if ($iSecond != '')
5805
		{
5806
			require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5807
5808
			$hourSelected = convertSecondToTime($iSecond, 'allhour');
5809
			$minSelected = convertSecondToTime($iSecond, 'min');
5810
		}
5811
5812
		if ($typehour == 'select')
5813
		{
5814
			$retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
5815
			for ($hour = 0; $hour < 25; $hour++)	// For a duration, we allow 24 hours
5816
			{
5817
				$retstring .= '<option value="'.$hour.'"';
5818
				if ($hourSelected == $hour)
5819
				{
5820
					$retstring .= " selected";
5821
				}
5822
				$retstring .= ">".$hour."</option>";
5823
			}
5824
			$retstring .= "</select>";
5825
		}
5826
		elseif ($typehour == 'text' || $typehour == 'textselect')
5827
		{
5828
			$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) : '').'">';
5829
		}
5830
		else return 'BadValueForParameterTypeHour';
5831
5832
		if ($typehour != 'text') $retstring .= ' '.$langs->trans('HourShort');
5833
		else $retstring .= '<span class="hideonsmartphone">:</span>';
5834
5835
		// Minutes
5836
		if ($minunderhours) $retstring .= '<br>';
5837
		else $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
5838
5839
		if ($typehour == 'select' || $typehour == 'textselect')
5840
		{
5841
			$retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
5842
			for ($min = 0; $min <= 55; $min = $min + 5)
5843
			{
5844
				$retstring .= '<option value="'.$min.'"';
5845
				if ($minSelected == $min) $retstring .= ' selected';
5846
				$retstring .= '>'.$min.'</option>';
5847
			}
5848
			$retstring .= "</select>";
5849
		}
5850
		elseif ($typehour == 'text')
5851
		{
5852
			$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) : '').'">';
5853
		}
5854
5855
		if ($typehour != 'text') $retstring .= ' '.$langs->trans('MinuteShort');
5856
5857
		//$retstring.="&nbsp;";
5858
5859
		if (!empty($nooutput)) return $retstring;
5860
5861
		print $retstring;
5862
		return;
5863
	}
5864
5865
5866
	/**
5867
	 * Generic method to select a component from a combo list.
5868
	 * This is the generic method that will replace all specific existing methods.
5869
	 *
5870
	 * @param 	string			$objectdesc			ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]
5871
	 * @param	string			$htmlname			Name of HTML select component
5872
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
5873
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
5874
	 * @param	string			$searchkey			Search criteria
5875
	 * @param	string			$placeholder		Place holder
5876
	 * @param	string			$morecss			More CSS
5877
	 * @param	string			$moreparams			More params provided to ajax call
5878
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
5879
	 * @param	int				$disabled			1=Html component is disabled
5880
	 * @param	string	        $selected_input_value	Value of preselected input text (for use with ajax)
5881
	 * @return	string								Return HTML string
5882
	 * @see selectForFormsList() select_thirdparty
5883
	 */
5884
	public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
5885
	{
5886
		global $conf, $user;
5887
5888
		$objecttmp = null;
5889
5890
		$InfoFieldList = explode(":", $objectdesc);
5891
		$classname = $InfoFieldList[0];
5892
		$classpath = $InfoFieldList[1];
5893
		$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
5894
		$filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
5895
5896
		if (!empty($classpath))
5897
		{
5898
			dol_include_once($classpath);
5899
			if ($classname && class_exists($classname))
5900
			{
5901
				$objecttmp = new $classname($this->db);
5902
				// Make some replacement
5903
				$sharedentities = getEntity(strtolower($classname));
5904
				$objecttmp->filter = str_replace(
5905
					array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
5906
					array($conf->entity, $sharedentities, $user->id),
5907
					$filter);
5908
			}
5909
		}
5910
		if (!is_object($objecttmp))
5911
		{
5912
			dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
5913
			return 'Error bad setup of type for field '.join(',', $InfoFieldList);
5914
		}
5915
5916
		//var_dump($objecttmp->filter);
5917
		$prefixforautocompletemode = $objecttmp->element;
5918
		if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode = 'company';
5919
		if ($prefixforautocompletemode == 'product') $prefixforautocompletemode = 'produit';
5920
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
5921
5922
		dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG);
5923
		$out = '';
5924
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo)
5925
		{
5926
		    // No immediate load of all database
5927
		    $placeholder = '';
5928
		    if ($preselectedvalue && empty($selected_input_value))
5929
		    {
5930
		        $objecttmp->fetch($preselectedvalue);
5931
		        $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
5932
		        //unset($objecttmp);
5933
		    }
5934
5935
		    $objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
5936
			$urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
5937
5938
			// No immediate load of all database
5939
			$urloption = 'htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.'&filter='.urlencode($objecttmp->filter).($moreparams ? $moreparams : '');
5940
			// Activate the auto complete using ajax call.
5941
			$out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
5942
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
5943
			if ($placeholder) $placeholder = ' placeholder="'.$placeholder.'"';
5944
			$out .= '<input type="text" class="'.$morecss.'"'.($disabled ? ' disabled="disabled"' : '').' name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' />';
5945
		}
5946
		else
5947
		{
5948
			// Immediate load of table record. Note: filter is inside $objecttmp->filter
5949
			$out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled);
5950
		}
5951
5952
		return $out;
5953
	}
5954
5955
	/**
5956
	 * Function to forge a SQL criteria
5957
	 *
5958
	 * @param  array    $matches       Array of found string by regex search. Example: "t.ref:like:'SO-%'" or "t.date_creation:<:'20160101'" or "t.nature:is:NULL"
5959
	 * @return string                  Forged criteria. Example: "t.field like 'abc%'"
5960
	 */
5961
	protected static function forgeCriteriaCallback($matches)
5962
	{
5963
		global $db;
5964
5965
		//dol_syslog("Convert matches ".$matches[1]);
5966
		if (empty($matches[1])) return '';
5967
		$tmp = explode(':', $matches[1]);
5968
		if (count($tmp) < 3) return '';
5969
5970
		$tmpescaped = $tmp[2];
5971
		$regbis = array();
5972
		if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis))
5973
		{
5974
			$tmpescaped = "'".$db->escape($regbis[1])."'";
5975
		}
5976
		else
5977
		{
5978
			$tmpescaped = $db->escape($tmpescaped);
5979
		}
5980
		return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
5981
	}
5982
5983
	/**
5984
	 * Output html form to select an object.
5985
	 * Note, this function is called by selectForForms or by ajax selectobject.php
5986
	 *
5987
	 * @param 	Object			$objecttmp			Object to knwo the table to scan for combo.
5988
	 * @param	string			$htmlname			Name of HTML select component
5989
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
5990
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
5991
	 * @param	string			$searchkey			Search value
5992
	 * @param	string			$placeholder		Place holder
5993
	 * @param	string			$morecss			More CSS
5994
	 * @param	string			$moreparams			More params provided to ajax call
5995
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
5996
	 * @param	int				$outputmode			0=HTML select string, 1=Array
5997
	 * @param	int				$disabled			1=Html component is disabled
5998
	 * @return	string|array						Return HTML string
5999
	 * @see selectForForms()
6000
	 */
6001
    public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0)
6002
	{
6003
		global $conf, $langs, $user;
6004
6005
		//print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled";
6006
6007
		$prefixforautocompletemode = $objecttmp->element;
6008
		if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode = 'company';
6009
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
6010
6011
		if (!empty($objecttmp->fields))	// For object that declare it, it is better to use declared fields (like societe, contact, ...)
6012
		{
6013
			$tmpfieldstoshow = '';
6014
			foreach ($objecttmp->fields as $key => $val)
6015
			{
6016
				if ($val['showoncombobox']) $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
6017
			}
6018
			if ($tmpfieldstoshow) $fieldstoshow = $tmpfieldstoshow;
6019
		}
6020
		if (empty($fieldstoshow))
6021
		{
6022
			if (isset($objecttmp->fields['ref'])) {
6023
				$fieldstoshow = 't.ref';
6024
			}
6025
			else
6026
			{
6027
				$langs->load("errors");
6028
				$this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
6029
				return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
6030
			}
6031
		}
6032
6033
		$out = '';
6034
		$outarray = array();
6035
6036
		$num = 0;
6037
6038
		// Search data
6039
		$sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX.$objecttmp->table_element." as t";
6040
		if ($objecttmp->ismultientitymanaged == 2)
6041
			if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
6042
		$sql .= " WHERE 1=1";
6043
		if (!empty($objecttmp->ismultientitymanaged)) $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
6044
		if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
6045
			if ($objecttmp->element == 'societe') $sql .= " AND t.rowid = ".$user->socid;
6046
			else $sql .= " AND t.fk_soc = ".$user->socid;
6047
		}
6048
		if ($searchkey != '') $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
6049
		if ($objecttmp->ismultientitymanaged == 2) {
6050
			if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
6051
		}
6052
		if ($objecttmp->filter) {	 // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
6053
			/*if (! DolibarrApi::_checkFilters($objecttmp->filter))
6054
			{
6055
				throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter);
6056
			}*/
6057
			$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
6058
			$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")";
6059
		}
6060
		$sql .= $this->db->order($fieldstoshow, "ASC");
6061
		//$sql.=$this->db->plimit($limit, 0);
6062
		//print $sql;
6063
6064
		// Build output string
6065
		$resql = $this->db->query($sql);
6066
		if ($resql)
6067
		{
6068
			if (!$forcecombo)
6069
			{
6070
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6071
				$out .= ajax_combobox($htmlname, null, $conf->global->$confkeyforautocompletemode);
6072
			}
6073
6074
			// Construct $out and $outarray
6075
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
6076
6077
			// 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
6078
			$textifempty = '&nbsp;';
6079
6080
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
6081
			if (!empty($conf->global->$confkeyforautocompletemode))
6082
			{
6083
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6084
				else $textifempty .= $langs->trans("All");
6085
			}
6086
			if ($showempty) $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
6087
6088
			$num = $this->db->num_rows($resql);
6089
			$i = 0;
6090
			if ($num)
6091
			{
6092
				while ($i < $num)
6093
				{
6094
					$obj = $this->db->fetch_object($resql);
6095
					$label = '';
6096
					$tmparray = explode(',', $fieldstoshow);
6097
					foreach ($tmparray as $key => $val)
6098
					{
6099
						$val = preg_replace('/t\./', '', $val);
6100
						$label .= (($label && $obj->$val) ? ' - ' : '').$obj->$val;
6101
					}
6102
					if (empty($outputmode))
6103
					{
6104
						if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid)
6105
						{
6106
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
6107
						}
6108
						else
6109
						{
6110
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
6111
						}
6112
					}
6113
					else
6114
					{
6115
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
6116
					}
6117
6118
					$i++;
6119
					if (($i % 10) == 0) $out .= "\n";
6120
				}
6121
			}
6122
6123
			$out .= '</select>'."\n";
6124
		}
6125
		else
6126
		{
6127
			dol_print_error($this->db);
6128
		}
6129
6130
		$this->result = array('nbofelement'=>$num);
6131
6132
		if ($outputmode) return $outarray;
6133
		return $out;
6134
	}
6135
6136
6137
	/**
6138
	 *	Return a HTML select string, built from an array of key+value.
6139
	 *  Note: Do not apply langs->trans function on returned content, content may be entity encoded twice.
6140
	 *
6141
	 *	@param	string			$htmlname			Name of html select area. Must start with "multi" if this is a multiselect
6142
	 *	@param	array			$array				Array like array(key => value) or array(key=>array('label'=>..., 'data-...'=>...))
6143
	 *	@param	string|string[]	$id					Preselected key or preselected keys for multiselect
6144
	 *	@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.
6145
	 *	@param	int				$key_in_label		1 to show key into label with format "[key] value"
6146
	 *	@param	int				$value_as_key		1 to use value as key
6147
	 *	@param  string			$moreparam			Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
6148
	 *	@param  int				$translate			1=Translate and encode value
6149
	 * 	@param	int				$maxlen				Length maximum for labels
6150
	 * 	@param	int				$disabled			Html select box is disabled
6151
	 *  @param	string			$sort				'ASC' or 'DESC' = Sort on label, '' or 'NONE' or 'POS' = Do not sort, we keep original order
6152
	 *  @param	string			$morecss			Add more class to css styles
6153
	 *  @param	int				$addjscombo			Add js combo
6154
	 *  @param  string          $moreparamonempty	Add more param on the empty option line. Not used if show_empty not set
6155
	 *  @param  int             $disablebademail	1=Check if a not valid email, 2=Check string '---', and if found into value, disable and colorize entry
6156
	 *  @param  int             $nohtmlescape		No html escaping.
6157
	 * 	@return	string								HTML select string.
6158
	 *  @see multiselectarray(), selectArrayAjax(), selectArrayFilter()
6159
	 */
6160
	public static function selectarray($htmlname, $array, $id = '', $show_empty = 0, $key_in_label = 0, $value_as_key = 0, $moreparam = '', $translate = 0, $maxlen = 0, $disabled = 0, $sort = '', $morecss = '', $addjscombo = 0, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
6161
	{
6162
		global $conf, $langs;
6163
6164
		// Do we want a multiselect ?
6165
		//$jsbeautify = 0;
6166
		//if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
6167
		$jsbeautify = 1;
6168
6169
		if ($value_as_key) $array = array_combine($array, $array);
6170
6171
		$out = '';
6172
6173
		// Add code for jquery to use multiselect
6174
		if ($addjscombo && $jsbeautify)
6175
		{
6176
			$minLengthToAutocomplete = 0;
6177
			$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ? (constant('REQUIRE_JQUERY_MULTISELECT') ?constant('REQUIRE_JQUERY_MULTISELECT') : 'select2') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
6178
6179
			// Enhance with select2
6180
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6181
			$out .= ajax_combobox($htmlname);
6182
		}
6183
6184
		$out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
6185
		$out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
6186
		$out .= '>';
6187
6188
		if ($show_empty)
6189
		{
6190
			$textforempty = ' ';
6191
			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.
6192
			if (!is_numeric($show_empty)) $textforempty = $show_empty;
6193
			$out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
6194
		}
6195
6196
		if (is_array($array))
6197
		{
6198
			// Translate
6199
			if ($translate)
6200
			{
6201
				foreach ($array as $key => $value)
6202
				{
6203
				    if (!is_array($value)) $array[$key] = $langs->trans($value);
6204
				    else $array[$key]['label'] = $langs->trans($value['label']);
6205
				}
6206
			}
6207
6208
			// Sort
6209
			if ($sort == 'ASC') asort($array);
6210
			elseif ($sort == 'DESC') arsort($array);
6211
6212
			foreach ($array as $key => $tmpvalue)
6213
			{
6214
			    if (is_array($tmpvalue)) $value = $tmpvalue['label'];
6215
			    else $value = $tmpvalue;
6216
6217
				$disabled = ''; $style = '';
6218
				if (!empty($disablebademail))
6219
				{
6220
				    if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
6221
				        || ($disablebademail == 2 && preg_match('/---/', $value)))
6222
					{
6223
						$disabled = ' disabled';
6224
						$style = ' class="warning"';
6225
					}
6226
				}
6227
6228
				if ($key_in_label)
6229
				{
6230
					if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
6231
					else $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
6232
				}
6233
				else
6234
				{
6235
					if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
6236
					else $selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value;
6237
					if ($value == '' || $value == '-') $selectOptionValue = '&nbsp;';
6238
				}
6239
6240
				$out .= '<option value="'.$key.'"';
6241
				$out .= $style.$disabled;
6242
				if (is_array($id)) {
6243
					if (in_array($key, $id) && !$disabled) $out .= ' selected'; // To preselect a value
6244
				} else {
6245
					$id = (string) $id; // if $id = 0, then $id = '0'
6246
					if ($id != '' && $id == $key && !$disabled) $out .= ' selected'; // To preselect a value
6247
				}
6248
				if ($nohtmlescape) $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
6249
				if (is_array($tmpvalue))
6250
				{
6251
				    foreach ($tmpvalue as $keyforvalue => $valueforvalue)
6252
				    {
6253
				        if (preg_match('/^data-/', $keyforvalue)) $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
6254
				    }
6255
				}
6256
				$out .= '>';
6257
				//var_dump($selectOptionValue);
6258
				$out .= $selectOptionValue;
6259
				$out .= "</option>\n";
6260
			}
6261
		}
6262
6263
		$out .= "</select>";
6264
		return $out;
6265
	}
6266
6267
6268
	/**
6269
	 *	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.
6270
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
6271
	 *
6272
	 *	@param	string	$htmlname       		Name of html select area
6273
	 *	@param	string	$url					Url. Must return a json_encode of array(key=>array('text'=>'A text', 'url'=>'An url'), ...)
6274
	 *	@param	string	$id             		Preselected key
6275
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
6276
	 *	@param  string	$moreparamtourl 		Add more parameters onto the Ajax called URL
6277
	 * 	@param	int		$disabled				Html select box is disabled
6278
	 *  @param	int		$minimumInputLength		Minimum Input Length
6279
	 *  @param	string	$morecss				Add more class to css styles
6280
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
6281
	 *  @param  string  $placeholder            String to use as placeholder
6282
	 *  @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)
6283
	 * 	@return	string   						HTML select string
6284
	 *  @see selectArrayFilter(), ajax_combobox() in ajax.lib.php
6285
	 */
6286
	public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
6287
	{
6288
		global $conf, $langs;
6289
		global $delayedhtmlcontent;
6290
6291
		// TODO Use an internal dolibarr component instead of select2
6292
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) return '';
6293
6294
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
6295
6296
		$tmpplugin = 'select2';
6297
		$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6298
	    	<script>
6299
	    	$(document).ready(function () {
6300
6301
    	        '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
6302
6303
                $(".'.$htmlname.'").select2({
6304
			    	ajax: {
6305
				    	dir: "ltr",
6306
				    	url: "'.$url.'",
6307
				    	dataType: \'json\',
6308
				    	delay: 250,
6309
				    	data: function (params) {
6310
				    		return {
6311
						    	q: params.term, 	// search term
6312
				    			page: params.page
6313
				    		};
6314
			    		},
6315
			    		processResults: function (data) {
6316
			    			// parse the results into the format expected by Select2.
6317
			    			// since we are using custom formatting functions we do not need to alter the remote JSON data
6318
			    			//console.log(data);
6319
							saveRemoteData = data;
6320
				    	    /* format json result for select2 */
6321
				    	    result = []
6322
				    	    $.each( data, function( key, value ) {
6323
				    	       result.push({id: key, text: value.text});
6324
                            });
6325
			    			//return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
6326
			    			//console.log(result);
6327
			    			return {results: result, more: false}
6328
			    		},
6329
			    		cache: true
6330
			    	},
6331
	 				language: select2arrayoflanguage,
6332
					containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
6333
				    placeholder: "'.dol_escape_js($placeholder).'",
6334
			    	escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
6335
			    	minimumInputLength: '.$minimumInputLength.',
6336
			        formatResult: function(result, container, query, escapeMarkup) {
6337
                        return escapeMarkup(result.text);
6338
                    },
6339
			    });
6340
6341
                '.($callurlonselect ? '
6342
                /* Code to execute a GET when we select a value */
6343
                $(".'.$htmlname.'").change(function() {
6344
			    	var selected = $(".'.$htmlname.'").val();
6345
                	console.log("We select in selectArrayAjax the entry "+selected)
6346
			        $(".'.$htmlname.'").val("");  /* reset visible combo value */
6347
    			    $.each( saveRemoteData, function( key, value ) {
6348
    				        if (key == selected)
6349
    			            {
6350
    			                 console.log("selectArrayAjax - Do a redirect to "+value.url)
6351
    			                 location.assign(value.url);
6352
    			            }
6353
                    });
6354
    			});' : '').'
6355
6356
    	   });
6357
	       </script>';
6358
6359
		if ($acceptdelayedhtml)
6360
		{
6361
			$delayedhtmlcontent .= $outdelayed;
6362
		}
6363
		else
6364
		{
6365
			$out .= $outdelayed;
6366
		}
6367
		return $out;
6368
	}
6369
6370
    /**
6371
     *  Return a HTML select string, built from an array of key+value, but content returned into select is defined into $array parameter.
6372
     *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
6373
     *
6374
     *  @param  string	$htmlname               Name of html select area
6375
	 *	@param	string	$array					Array (key=>array('text'=>'A text', 'url'=>'An url'), ...)
6376
	 *	@param	string	$id             		Preselected key
6377
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
6378
	 *	@param	int		$disableFiltering		If set to 1, results are not filtered with searched string
6379
	 * 	@param	int		$disabled				Html select box is disabled
6380
	 *  @param	int		$minimumInputLength		Minimum Input Length
6381
	 *  @param	string	$morecss				Add more class to css styles
6382
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
6383
	 *  @param  string  $placeholder            String to use as placeholder
6384
	 *  @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)
6385
	 *  @return	string   						HTML select string
6386
	 *  @see selectArrayAjax(), ajax_combobox() in ajax.lib.php
6387
	 */
6388
	public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
6389
	{
6390
		global $conf, $langs;
6391
		global $delayedhtmlcontent;
6392
6393
		// TODO Use an internal dolibarr component instead of select2
6394
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) return '';
6395
6396
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
6397
6398
		$formattedarrayresult = array();
6399
6400
		foreach ($array as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $array of type string is not traversable.
Loading history...
6401
			$o = new stdClass();
6402
			$o->id = $key;
6403
			$o->text = $value['text'];
6404
			$o->url = $value['url'];
6405
			$formattedarrayresult[] = $o;
6406
		}
6407
6408
		$tmpplugin = 'select2';
6409
		$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6410
			<script>
6411
			$(document).ready(function () {
6412
				var data = '.json_encode($formattedarrayresult).';
6413
6414
				'.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
6415
6416
				$(".'.$htmlname.'").select2({
6417
					data: data,
6418
					language: select2arrayoflanguage,
6419
					containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
6420
					placeholder: "'.dol_escape_js($placeholder).'",
6421
					escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
6422
					minimumInputLength: '.$minimumInputLength.',
6423
					formatResult: function(result, container, query, escapeMarkup) {
6424
						return escapeMarkup(result.text);
6425
					},
6426
					matcher: function (params, data) {
6427
6428
						if(! data.id) return null;';
6429
6430
		if ($callurlonselect) {
6431
			$outdelayed .= '
6432
6433
						var urlBase = data.url;
6434
						var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
6435
						/* console.log("params.term="+params.term); */
6436
						/* console.log("params.term encoded="+encodeURIComponent(params.term)); */
6437
						saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term);';
6438
		}
6439
6440
		if (!$disableFiltering) {
6441
			$outdelayed .= '
6442
6443
						if(data.text.match(new RegExp(params.term))) {
6444
							return data;
6445
						}
6446
6447
						return null;';
6448
		} else {
6449
			$outdelayed .= '
6450
6451
						return data;';
6452
		}
6453
6454
		$outdelayed .= '
6455
					}
6456
				});
6457
6458
				'.($callurlonselect ? '
6459
				/* Code to execute a GET when we select a value */
6460
				$(".'.$htmlname.'").change(function() {
6461
					var selected = $(".'.$htmlname.'").val();
6462
					console.log("We select "+selected)
6463
6464
					$(".'.$htmlname.'").val("");  /* reset visible combo value */
6465
					$.each( saveRemoteData, function( key, value ) {
6466
						if (key == selected)
6467
						{
6468
							console.log("selectArrayAjax - Do a redirect to "+value.url)
6469
							location.assign(value.url);
6470
						}
6471
					});
6472
				});' : '').'
6473
6474
			});
6475
			</script>';
6476
6477
		if ($acceptdelayedhtml)
6478
		{
6479
			$delayedhtmlcontent .= $outdelayed;
6480
		}
6481
		else
6482
		{
6483
			$out .= $outdelayed;
6484
		}
6485
		return $out;
6486
	}
6487
6488
	/**
6489
	 *	Show a multiselect form from an array.
6490
	 *
6491
	 *	@param	string	$htmlname		Name of select
6492
	 *	@param	array	$array			Array with key+value
6493
	 *	@param	array	$selected		Array with key+value preselected
6494
	 *	@param	int		$key_in_label   1 pour afficher la key dans la valeur "[key] value"
6495
	 *	@param	int		$value_as_key   1 to use value as key
6496
	 *	@param  string	$morecss        Add more css style
6497
	 *	@param  int		$translate		Translate and encode value
6498
	 *  @param	int		$width			Force width of select box. May be used only when using jquery couch. Example: 250, 95%
6499
	 *  @param	string	$moreattrib		Add more options on select component. Example: 'disabled'
6500
	 *  @param	string	$elemtype		Type of element we show ('category', ...). Will execute a formating function on it. To use in readonly mode if js component support HTML formatting.
6501
	 *  @param	string	$placeholder	String to use as placeholder
6502
	 *  @param	int		$addjscombo		Add js combo
6503
	 *	@return	string					HTML multiselect string
6504
	 *  @see selectarray(), selectArrayAjax(), selectArrayFilter()
6505
	 */
6506
	public static function multiselectarray($htmlname, $array, $selected = array(), $key_in_label = 0, $value_as_key = 0, $morecss = '', $translate = 0, $width = 0, $moreattrib = '', $elemtype = '', $placeholder = '', $addjscombo = -1)
6507
	{
6508
		global $conf, $langs;
6509
6510
		$out = '';
6511
6512
		if ($addjscombo < 0) {
6513
		    if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $addjscombo = 1;
6514
		    else $addjscombo = 0;
6515
		}
6516
6517
		// Add code for jquery to use multiselect
6518
		if (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))
6519
		{
6520
			$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...
6521
						<script>'."\n";
6522
			if ($addjscombo == 1)
6523
			{
6524
				$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
6525
				$out .= 'function formatResult(record) {'."\n";
6526
				if ($elemtype == 'category')
6527
				{
6528
					$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>\';
6529
									  	return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> \'+record.text+\'</span>\';';
6530
				}
6531
				else
6532
				{
6533
					$out .= 'return record.text;';
6534
				}
6535
				$out .= '};'."\n";
6536
				$out .= 'function formatSelection(record) {'."\n";
6537
				if ($elemtype == 'category')
6538
				{
6539
					$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>\';
6540
									  	return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png'.'"> \'+record.text+\'</span>\';';
6541
				}
6542
				else
6543
				{
6544
					$out .= 'return record.text;';
6545
				}
6546
				$out .= '};'."\n";
6547
				$out .= '$(document).ready(function () {
6548
							$(\'#'.$htmlname.'\').'.$tmpplugin.'({
6549
								dir: \'ltr\',
6550
								// Specify format function for dropdown item
6551
								formatResult: formatResult,
6552
							 	templateResult: formatResult,		/* For 4.0 */
6553
								// Specify format function for selected item
6554
								formatSelection: formatSelection,
6555
							 	templateSelection: formatSelection		/* For 4.0 */
6556
							});
6557
						});'."\n";
6558
			}
6559
			elseif ($addjscombo == 2)
6560
			{
6561
				// Add other js lib
6562
				// TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
6563
				// ...
6564
				$out .= '$(document).ready(function () {
6565
							$(\'#'.$htmlname.'\').multiSelect({
6566
								containerHTML: \'<div class="multi-select-container">\',
6567
								menuHTML: \'<div class="multi-select-menu">\',
6568
								buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
6569
								menuItemHTML: \'<label class="multi-select-menuitem">\',
6570
								activeClass: \'multi-select-container--open\',
6571
								noneText: \''.$placeholder.'\'
6572
							});
6573
						})';
6574
			}
6575
			$out .= '</script>';
6576
		}
6577
6578
		// Try also magic suggest
6579
		$out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
6580
		if (is_array($array) && !empty($array))
6581
		{
6582
			if ($value_as_key) $array = array_combine($array, $array);
6583
6584
			if (!empty($array))
6585
			{
6586
				foreach ($array as $key => $value)
6587
				{
6588
					$out .= '<option value="'.$key.'"';
6589
                    if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != ''))
6590
					{
6591
						$out .= ' selected';
6592
					}
6593
					$out .= '>';
6594
6595
					$newval = ($translate ? $langs->trans($value) : $value);
6596
					$newval = ($key_in_label ? $key.' - '.$newval : $newval);
6597
					$out .= dol_htmlentitiesbr($newval);
6598
					$out .= '</option>'."\n";
6599
				}
6600
			}
6601
		}
6602
		$out .= '</select>'."\n";
6603
6604
		return $out;
6605
	}
6606
6607
6608
	/**
6609
	 *	Show a multiselect dropbox from an array.
6610
	 *
6611
	 *	@param	string	$htmlname		Name of HTML field
6612
	 *	@param	array	$array			Array with array of fields we could show. This array may be modified according to setup of user.
6613
	 *  @param  string  $varpage        Id of context for page. Can be set by caller with $varpage=(empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage);
6614
	 *	@return	string					HTML multiselect string
6615
	 *  @see selectarray()
6616
	 */
6617
	public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
6618
	{
6619
		global $conf, $langs, $user;
6620
6621
		if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) return '';
6622
6623
		$tmpvar = "MAIN_SELECTEDFIELDS_".$varpage;
6624
		if (!empty($user->conf->$tmpvar))
6625
		{
6626
			$tmparray = explode(',', $user->conf->$tmpvar);
6627
			foreach ($array as $key => $val)
6628
			{
6629
				//var_dump($key);
6630
				//var_dump($tmparray);
6631
				if (in_array($key, $tmparray)) $array[$key]['checked'] = 1;
6632
				else $array[$key]['checked'] = 0;
6633
			}
6634
		}
6635
6636
		$lis = '';
6637
		$listcheckedstring = '';
6638
6639
		foreach ($array as $key => $val)
6640
		{
6641
		    /* var_dump($val);
6642
            var_dump(array_key_exists('enabled', $val));
6643
            var_dump(!$val['enabled']);*/
6644
		    if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled'])
6645
		    {
6646
			    unset($array[$key]); // We don't want this field
6647
			    continue;
6648
		    }
6649
		    if ($val['label'])
6650
		    {
6651
		        $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>';
6652
			    $listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
6653
		    }
6654
		}
6655
6656
		$out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
6657
6658
        <dl class="dropdown">
6659
            <dt>
6660
            <a href="#'.$htmlname.'">
6661
              '.img_picto('', 'list').'
6662
            </a>
6663
            <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
6664
            </dt>
6665
            <dd class="dropdowndd">
6666
                <div class="multiselectcheckbox'.$htmlname.'">
6667
                    <ul class="ul'.$htmlname.'">
6668
                    '.$lis.'
6669
                    </ul>
6670
                </div>
6671
            </dd>
6672
        </dl>
6673
6674
        <script type="text/javascript">
6675
          jQuery(document).ready(function () {
6676
              $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
6677
                  console.log("A new field was added/removed")
6678
                  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\')
6679
                  var title = $(this).val() + ",";
6680
                  if ($(this).is(\':checked\')) {
6681
                      $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
6682
                  }
6683
                  else {
6684
                      $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
6685
                  }
6686
                  // Now, we submit page
6687
                  $(this).parents(\'form:first\').submit();
6688
              });
6689
           });
6690
        </script>
6691
6692
        ';
6693
		return $out;
6694
	}
6695
6696
	/**
6697
	 * 	Render list of categories linked to object with id $id and type $type
6698
	 *
6699
	 * 	@param		int		$id				Id of object
6700
	 * 	@param		string	$type			Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
6701
	 *  @param		int		$rendermode		0=Default, use multiselect. 1=Emulate multiselect (recommended)
6702
	 * 	@return		string					String with categories
6703
	 */
6704
    public function showCategories($id, $type, $rendermode = 0)
6705
	{
6706
		global $db;
6707
6708
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
6709
6710
		$cat = new Categorie($db);
6711
		$categories = $cat->containing($id, $type);
6712
6713
		if ($rendermode == 1)
6714
		{
6715
			$toprint = array();
6716
			foreach ($categories as $c)
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
6717
			{
6718
				$ways = $c->print_all_ways(); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
6719
				foreach ($ways as $way)
6720
				{
6721
					$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #aaa"').'>'.img_object('', 'category').' '.$way.'</li>';
6722
				}
6723
			}
6724
			return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6725
		}
6726
6727
		if ($rendermode == 0)
6728
		{
6729
			$arrayselected = array();
6730
			$cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
6731
			foreach ($categories as $c) {
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
6732
				$arrayselected[] = $c->id;
6733
			}
6734
6735
			return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
6736
		}
6737
6738
		return 'ErrorBadValueForParameterRenderMode'; // Should not happened
6739
	}
6740
6741
	/**
6742
	 *  Show linked object block.
6743
	 *
6744
	 *  @param	CommonObject	$object		      Object we want to show links to
6745
	 *  @param  string          $morehtmlright    More html to show on right of title
6746
	 *  @param  array           $compatibleImportElementsList  Array of compatibles elements object for "import from" action
6747
	 *  @return	int							      <0 if KO, >=0 if OK
6748
	 */
6749
    public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false)
6750
	{
6751
		global $conf, $langs, $hookmanager;
6752
		global $bc, $action;
6753
6754
		$object->fetchObjectLinked();
6755
6756
		// Bypass the default method
6757
		$hookmanager->initHooks(array('commonobject'));
6758
		$parameters = array(
6759
			'morehtmlright' => $morehtmlright,
6760
		    'compatibleImportElementsList' => &$compatibleImportElementsList,
6761
		);
6762
		$reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
6763
6764
		if (empty($reshook))
6765
		{
6766
			$nbofdifferenttypes = count($object->linkedObjects);
6767
6768
			print '<!-- showLinkedObjectBlock -->';
6769
			print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
6770
6771
6772
			print '<div class="div-table-responsive-no-min">';
6773
			print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'"  data-elementid="'.$object->id.'"   >';
6774
6775
			print '<tr class="liste_titre">';
6776
			print '<td>'.$langs->trans("Type").'</td>';
6777
			print '<td>'.$langs->trans("Ref").'</td>';
6778
			print '<td class="center"></td>';
6779
			print '<td class="center">'.$langs->trans("Date").'</td>';
6780
			print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
6781
			print '<td class="right">'.$langs->trans("Status").'</td>';
6782
			print '<td></td>';
6783
			print '</tr>';
6784
6785
			$nboftypesoutput = 0;
6786
6787
			foreach ($object->linkedObjects as $objecttype => $objects)
6788
			{
6789
				$tplpath = $element = $subelement = $objecttype;
6790
6791
				// to display inport button on tpl
6792
				$showImportButton = false;
6793
				if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
6794
				    $showImportButton = true;
6795
				}
6796
6797
				$regs = array();
6798
				if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs))
6799
				{
6800
					$element = $regs[1];
6801
					$subelement = $regs[2];
6802
					$tplpath = $element.'/'.$subelement;
6803
				}
6804
				$tplname = 'linkedobjectblock';
6805
6806
				// To work with non standard path
6807
				if ($objecttype == 'facture') {
6808
					$tplpath = 'compta/'.$element;
6809
					if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
6810
				}
6811
				elseif ($objecttype == 'facturerec') {
6812
					$tplpath = 'compta/facture';
6813
					$tplname = 'linkedobjectblockForRec';
6814
					if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
6815
				}
6816
				elseif ($objecttype == 'propal') {
6817
					$tplpath = 'comm/'.$element;
6818
					if (empty($conf->propal->enabled)) continue; // Do not show if module disabled
6819
				}
6820
				elseif ($objecttype == 'supplier_proposal') {
6821
					if (empty($conf->supplier_proposal->enabled)) continue; // Do not show if module disabled
6822
				}
6823
				elseif ($objecttype == 'shipping' || $objecttype == 'shipment') {
6824
					$tplpath = 'expedition';
6825
					if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
6826
				}
6827
        		elseif ($objecttype == 'reception') {
6828
        			$tplpath = 'reception';
6829
        			if (empty($conf->reception->enabled)) continue; // Do not show if module disabled
6830
        		}
6831
				elseif ($objecttype == 'delivery') {
6832
					$tplpath = 'livraison';
6833
					if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
6834
				}
6835
				elseif ($objecttype == 'invoice_supplier') {
6836
					$tplpath = 'fourn/facture';
6837
				}
6838
				elseif ($objecttype == 'order_supplier') {
6839
					$tplpath = 'fourn/commande';
6840
				}
6841
				elseif ($objecttype == 'expensereport') {
6842
					$tplpath = 'expensereport';
6843
				}
6844
				elseif ($objecttype == 'subscription') {
6845
					$tplpath = 'adherents';
6846
				}
6847
6848
				global $linkedObjectBlock;
6849
				$linkedObjectBlock = $objects;
6850
6851
6852
				// Output template part (modules that overwrite templates must declare this into descriptor)
6853
				$dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
6854
				foreach ($dirtpls as $reldir)
6855
				{
6856
					if ($nboftypesoutput == ($nbofdifferenttypes - 1))    // No more type to show after
6857
					{
6858
						global $noMoreLinkedObjectBlockAfter;
6859
						$noMoreLinkedObjectBlockAfter = 1;
6860
					}
6861
6862
					$res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
6863
					if ($res)
6864
					{
6865
						$nboftypesoutput++;
6866
						break;
6867
					}
6868
				}
6869
			}
6870
6871
			if (!$nboftypesoutput)
6872
			{
6873
				print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>';
6874
			}
6875
6876
			print '</table>';
6877
6878
			if (!empty($compatibleImportElementsList))
6879
			{
6880
			    $res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
6881
			}
6882
6883
6884
			print '</div>';
6885
6886
			return $nbofdifferenttypes;
6887
		}
6888
	}
6889
6890
	/**
6891
	 *  Show block with links to link to other objects.
6892
	 *
6893
	 *  @param	CommonObject	$object				Object we want to show links to
6894
	 *  @param	array			$restrictlinksto	Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction.
6895
	 *  @param	array			$excludelinksto		Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion.
6896
	 *  @return	string								<0 if KO, >0 if OK
6897
	 */
6898
    public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
6899
	{
6900
		global $conf, $langs, $hookmanager;
6901
		global $bc, $action;
6902
6903
		$linktoelem = '';
6904
		$linktoelemlist = '';
6905
		$listofidcompanytoscan = '';
6906
6907
		if (!is_object($object->thirdparty)) $object->fetch_thirdparty();
6908
6909
		$possiblelinks = array();
6910
		if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0)
6911
		{
6912
			$listofidcompanytoscan = $object->thirdparty->id;
6913
			if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) $listofidcompanytoscan .= ','.$object->thirdparty->parent;
6914
			if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO))
6915
			{
6916
				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
6917
				$tmpproject = new Project($this->db);
6918
				$tmpproject->fetch($object->fk_project);
6919
				if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) $listofidcompanytoscan .= ','.$tmpproject->socid;
6920
				unset($tmpproject);
6921
			}
6922
6923
			$possiblelinks = array(
6924
				'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').')'),
6925
				'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').')'),
6926
				'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').')'),
6927
				'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').')'),
6928
				'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').')'),
6929
				'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').')'),
6930
				'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').')'),
6931
				'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').')'),
6932
				'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').')'),
6933
				'ticket'=>array('enabled'=>$conf->ticket->enabled, 'perms'=>1, 'label'=>'LinkToTicket', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('ticket').')')
6934
			);
6935
		}
6936
6937
		// Can complete the possiblelink array
6938
		$hookmanager->initHooks(array('commonobject'));
6939
		$parameters = array('listofidcompanytoscan' => $listofidcompanytoscan);
6940
6941
		if (!empty($listofidcompanytoscan))  // If empty, we don't have criteria to scan the object we can link to
6942
		{
6943
            $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
6944
		}
6945
6946
		if (empty($reshook))
6947
		{
6948
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6949
			{
6950
				$possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
6951
			}
6952
		}
6953
		elseif ($reshook > 0)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $reshook does not seem to be defined for all execution paths leading up to this point.
Loading history...
6954
		{
6955
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6956
			{
6957
				$possiblelinks = $hookmanager->resArray;
6958
			}
6959
		}
6960
6961
		foreach ($possiblelinks as $key => $possiblelink)
6962
		{
6963
			$num = 0;
6964
6965
			if (empty($possiblelink['enabled'])) continue;
6966
6967
			if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto)))
6968
			{
6969
				print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
6970
				$sql = $possiblelink['sql'];
6971
6972
				$resqllist = $this->db->query($sql);
6973
				if ($resqllist)
6974
				{
6975
					$num = $this->db->num_rows($resqllist);
6976
					$i = 0;
6977
6978
					print '<br>';
6979
					print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
6980
					print '<input type="hidden" name="action" value="addlink">';
6981
					print '<input type="hidden" name="token" value="'.newToken().'">';
6982
					print '<input type="hidden" name="id" value="'.$object->id.'">';
6983
					print '<input type="hidden" name="addlink" value="'.$key.'">';
6984
					print '<table class="noborder">';
6985
					print '<tr class="liste_titre">';
6986
					print '<td class="nowrap"></td>';
6987
					print '<td class="center">'.$langs->trans("Ref").'</td>';
6988
					print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
6989
					print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
6990
					print '<td class="left">'.$langs->trans("Company").'</td>';
6991
					print '</tr>';
6992
					while ($i < $num)
6993
					{
6994
						$objp = $this->db->fetch_object($resqllist);
6995
6996
						print '<tr class="oddeven">';
6997
						print '<td class="left">';
6998
						print '<input type="radio" name="idtolinkto" value='.$objp->rowid.'>';
6999
						print '</td>';
7000
						print '<td class="center">'.$objp->ref.'</td>';
7001
						print '<td>'.$objp->ref_client.'</td>';
7002
						print '<td class="right">'.price($objp->total_ht).'</td>';
7003
						print '<td>'.$objp->name.'</td>';
7004
						print '</tr>';
7005
						$i++;
7006
					}
7007
					print '</table>';
7008
					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>';
7009
7010
					print '</form>';
7011
					$this->db->free($resqllist);
7012
				} else {
7013
					dol_print_error($this->db);
7014
				}
7015
				print '</div>';
7016
				if ($num > 0)
7017
				{
7018
				}
7019
7020
				//$linktoelem.=($linktoelem?' &nbsp; ':'');
7021
				if ($num > 0) $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
7022
				//else $linktoelem.=$langs->trans($possiblelink['label']);
7023
				else $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
7024
			}
7025
		}
7026
7027
		if ($linktoelemlist)
7028
		{
7029
			$linktoelem = '
7030
    		<dl class="dropdown" id="linktoobjectname">
7031
    		';
7032
			if (!empty($conf->use_javascript_ajax)) $linktoelem .= '<dt><a href="#linktoobjectname">'.$langs->trans("LinkTo").'...</a></dt>';
7033
			$linktoelem .= '<dd>
7034
    		<div class="multiselectlinkto">
7035
    		<ul class="ulselectedfields">'.$linktoelemlist.'
7036
    		</ul>
7037
    		</div>
7038
    		</dd>
7039
    		</dl>';
7040
		}
7041
		else
7042
		{
7043
			$linktoelem = '';
7044
		}
7045
7046
		if (!empty($conf->use_javascript_ajax))
7047
		{
7048
		    print '<!-- Add js to show linkto box -->
7049
				<script>
7050
				jQuery(document).ready(function() {
7051
					jQuery(".linkto").click(function() {
7052
						console.log("We choose to show/hide link for rel="+jQuery(this).attr(\'rel\'));
7053
					    jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
7054
						jQuery(this).toggle();
7055
					});
7056
				});
7057
				</script>
7058
		    ';
7059
		}
7060
7061
		return $linktoelem;
7062
	}
7063
7064
	/**
7065
	 *	Return an html string with a select combo box to choose yes or no
7066
	 *
7067
	 *	@param	string		$htmlname		Name of html select field
7068
	 *	@param	string		$value			Pre-selected value
7069
	 *	@param	int			$option			0 return yes/no, 1 return 1/0
7070
	 *	@param	bool		$disabled		true or false
7071
	 *  @param	int      	$useempty		1=Add empty line
7072
	 *	@return	string						See option
7073
	 */
7074
    public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0)
7075
	{
7076
		global $langs;
7077
7078
		$yes = "yes"; $no = "no";
7079
		if ($option)
7080
		{
7081
			$yes = "1";
7082
			$no = "0";
7083
		}
7084
7085
		$disabled = ($disabled ? ' disabled' : '');
7086
7087
		$resultyesno = '<select class="flat width75" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
7088
		if ($useempty) $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
7089
		if (("$value" == 'yes') || ($value == 1))
7090
		{
7091
			$resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
7092
			$resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
7093
		}
7094
		else
7095
	    {
7096
	   		$selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
7097
			$resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
7098
			$resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
7099
		}
7100
		$resultyesno .= '</select>'."\n";
7101
		return $resultyesno;
7102
	}
7103
7104
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7105
	/**
7106
	 *  Return list of export templates
7107
	 *
7108
	 *  @param	string	$selected          Id modele pre-selectionne
7109
	 *  @param  string	$htmlname          Name of HTML select
7110
	 *  @param  string	$type              Type of searched templates
7111
	 *  @param  int		$useempty          Affiche valeur vide dans liste
7112
	 *  @return	void
7113
	 */
7114
    public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
7115
	{
7116
        // phpcs:enable
7117
		$sql = "SELECT rowid, label";
7118
		$sql .= " FROM ".MAIN_DB_PREFIX."export_model";
7119
		$sql .= " WHERE type = '".$type."'";
7120
		$sql .= " ORDER BY rowid";
7121
		$result = $this->db->query($sql);
7122
		if ($result)
7123
		{
7124
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
7125
			if ($useempty)
7126
			{
7127
				print '<option value="-1">&nbsp;</option>';
7128
			}
7129
7130
			$num = $this->db->num_rows($result);
7131
			$i = 0;
7132
			while ($i < $num)
7133
			{
7134
				$obj = $this->db->fetch_object($result);
7135
				if ($selected == $obj->rowid)
7136
				{
7137
					print '<option value="'.$obj->rowid.'" selected>';
7138
				}
7139
				else
7140
				{
7141
					print '<option value="'.$obj->rowid.'">';
7142
				}
7143
				print $obj->label;
7144
				print '</option>';
7145
				$i++;
7146
			}
7147
			print "</select>";
7148
		}
7149
		else {
7150
			dol_print_error($this->db);
7151
		}
7152
	}
7153
7154
	/**
7155
	 *    Return a HTML area with the reference of object and a navigation bar for a business object
7156
	 *    Note: To complete search with a particular filter on select, you can set $object->next_prev_filter set to define SQL criterias.
7157
	 *
7158
	 *    @param	object	$object			Object to show.
7159
	 *    @param	string	$paramid   		Name of parameter to use to name the id into the URL next/previous link.
7160
	 *    @param	string	$morehtml  		More html content to output just before the nav bar.
7161
	 *    @param	int		$shownav	  	Show Condition (navigation is shown if value is 1).
7162
	 *    @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.
7163
	 *    @param	string	$fieldref   	Name of field ref of object (object->ref) to show or 'none' to not show ref.
7164
	 *    @param	string	$morehtmlref  	More html to show after ref.
7165
	 *    @param	string	$moreparam  	More param to add in nav link url. Must start with '&...'.
7166
	 *	  @param	int		$nodbprefix		Do not include DB prefix to forge table name.
7167
	 *	  @param	string	$morehtmlleft	More html code to show before ref.
7168
	 *	  @param	string	$morehtmlstatus	More html code to show under navigation arrows (status place).
7169
	 *	  @param	string	$morehtmlright	More html code to show after ref.
7170
	 * 	  @return	string    				Portion HTML with ref + navigation buttons
7171
	 */
7172
    public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
7173
	{
7174
		global $langs, $conf, $hookmanager;
7175
7176
		$ret = '';
7177
		if (empty($fieldid))  $fieldid = 'rowid';
7178
		if (empty($fieldref)) $fieldref = 'ref';
7179
7180
		// Add where from hooks
7181
		if (is_object($hookmanager))
7182
		{
7183
			$parameters = array();
7184
			$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
7185
			$object->next_prev_filter .= $hookmanager->resPrint;
7186
		}
7187
		$previous_ref = $next_ref = '';
7188
		if ($shownav)
7189
		{
7190
			//print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
7191
			$object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
7192
7193
			$navurl = $_SERVER["PHP_SELF"];
7194
			// Special case for project/task page
7195
			if ($paramid == 'project_ref')
7196
			{
7197
			    if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl))     // TODO Remove this when nav with project_ref on task pages are ok
7198
			    {
7199
				    $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
7200
    				$paramid = 'ref';
7201
			    }
7202
			}
7203
7204
			// accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
7205
			// accesskey is for Mac:               CTRL + key for all browsers
7206
			$stringforfirstkey = $langs->trans("KeyboardShortcut");
7207
			if ($conf->browser->name == 'chrome')
7208
			{
7209
				$stringforfirstkey .= ' ALT +';
7210
			}
7211
			elseif ($conf->browser->name == 'firefox')
7212
			{
7213
				$stringforfirstkey .= ' ALT + SHIFT +';
7214
			}
7215
			else
7216
			{
7217
				$stringforfirstkey .= ' CTL +';
7218
			}
7219
7220
			$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>';
7221
			$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>';
7222
		}
7223
7224
		//print "xx".$previous_ref."x".$next_ref;
7225
		$ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
7226
7227
		// Right part of banner
7228
		if ($morehtmlright) $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
7229
7230
		if ($previous_ref || $next_ref || $morehtml)
7231
		{
7232
			$ret .= '<div class="pagination paginationref"><ul class="right">';
7233
		}
7234
		if ($morehtml)
7235
		{
7236
			$ret .= '<li class="noborder litext">'.$morehtml.'</li>';
7237
		}
7238
		if ($shownav && ($previous_ref || $next_ref))
7239
		{
7240
			$ret .= '<li class="pagination">'.$previous_ref.'</li>';
7241
			$ret .= '<li class="pagination">'.$next_ref.'</li>';
7242
		}
7243
		if ($previous_ref || $next_ref || $morehtml)
7244
		{
7245
			$ret .= '</ul></div>';
7246
		}
7247
7248
		$parameters = array();
7249
		$reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
7250
		if (empty($reshook)) $morehtmlstatus .= $hookmanager->resPrint;
7251
		else $morehtmlstatus = $hookmanager->resPrint;
7252
		if ($morehtmlstatus) $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
7253
7254
		$parameters = array();
7255
		$reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
7256
		if (empty($reshook)) $morehtmlref .= $hookmanager->resPrint;
7257
		elseif ($reshook > 0) $morehtmlref = $hookmanager->resPrint;
7258
7259
		// Left part of banner
7260
		if ($morehtmlleft)
7261
		{
7262
			if ($conf->browser->layout == 'phone') $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
7263
			else $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
7264
		}
7265
7266
		//if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
7267
		$ret .= '<div class="inline-block floatleft valignmiddle refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
7268
7269
		// For thirdparty, contact, user, member, the ref is the id, so we show something else
7270
		if ($object->element == 'societe')
7271
		{
7272
			$ret .= dol_htmlentities($object->name);
7273
		}
7274
		elseif ($object->element == 'member')
7275
		{
7276
			$ret .= $object->ref.'<br>';
7277
			$fullname = $object->getFullName($langs);
7278
			if ($object->morphy == 'mor' && $object->societe) {
7279
				$ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).')' : '');
7280
			} else {
7281
				$ret .= dol_htmlentities($fullname).((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
7282
			}
7283
		}
7284
		elseif (in_array($object->element, array('contact', 'user', 'usergroup')))
7285
		{
7286
			$ret .= dol_htmlentities($object->getFullName($langs));
7287
		}
7288
		elseif (in_array($object->element, array('action', 'agenda')))
7289
		{
7290
			$ret .= $object->ref.'<br>'.$object->label;
7291
		}
7292
		elseif (in_array($object->element, array('adherent_type')))
7293
		{
7294
			$ret .= $object->label;
7295
		}
7296
		elseif ($object->element == 'ecm_directories')
7297
		{
7298
			$ret .= '';
7299
		}
7300
		elseif ($fieldref != 'none')
7301
		{
7302
			$ret.=dol_htmlentities($object->$fieldref);
7303
		}
7304
7305
		if ($morehtmlref)
7306
		{
7307
			// don't add a additional space, when "$morehtmlref" starts with a HTML div tag
7308
			if(substr($morehtmlref, 0, 4) != '<div')
7309
			{
7310
				$ret.=' ';
7311
			}
7312
7313
			$ret.=$morehtmlref;
7314
		}
7315
7316
		$ret.='</div>';
7317
7318
		$ret .= '</div><!-- End banner content -->';
7319
7320
		return $ret;
7321
	}
7322
7323
7324
	/**
7325
	 *    	Return HTML code to output a barcode
7326
	 *
7327
	 *     	@param	Object	$object		Object containing data to retrieve file name
7328
	 * 		@param	int		$width			Width of photo
7329
	 * 	  	@return string    				HTML code to output barcode
7330
	 */
7331
    public function showbarcode(&$object, $width = 100)
7332
	{
7333
		global $conf;
7334
7335
		//Check if barcode is filled in the card
7336
		if (empty($object->barcode)) return '';
7337
7338
		// Complete object if not complete
7339
		if (empty($object->barcode_type_code) || empty($object->barcode_type_coder))
7340
		{
7341
			$result = $object->fetch_barcode();
7342
			//Check if fetch_barcode() failed
7343
			if ($result < 1) return '<!-- ErrorFetchBarcode -->';
7344
		}
7345
7346
		// Barcode image
7347
		$url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
7348
		$out = '<!-- url barcode = '.$url.' -->';
7349
		$out .= '<img src="'.$url.'">';
7350
		return $out;
7351
	}
7352
7353
	/**
7354
	 *    	Return HTML code to output a photo
7355
	 *
7356
	 *    	@param	string		$modulepart			Key to define module concerned ('societe', 'userphoto', 'memberphoto')
7357
	 *     	@param  object		$object				Object containing data to retrieve file name
7358
	 * 		@param	int			$width				Width of photo
7359
	 * 		@param	int			$height				Height of photo (auto if 0)
7360
	 * 		@param	int			$caneditfield		Add edit fields
7361
	 * 		@param	string		$cssclass			CSS name to use on img for photo
7362
	 * 		@param	string		$imagesize		    'mini', 'small' or '' (original)
7363
	 *      @param  int         $addlinktofullsize  Add link to fullsize image
7364
	 *      @param  int         $cache              1=Accept to use image in cache
7365
	 *      @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.
7366
	 * 	  	@return string    						HTML code to output photo
7367
	 */
7368
	public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '')
7369
	{
7370
		global $conf, $langs;
7371
7372
		$entity = (!empty($object->entity) ? $object->entity : $conf->entity);
7373
		$id = (!empty($object->id) ? $object->id : $object->rowid);
7374
7375
		$ret = ''; $dir = ''; $file = ''; $originalfile = ''; $altfile = ''; $email = ''; $capture = '';
7376
		if ($modulepart == 'societe')
7377
		{
7378
			$dir = $conf->societe->multidir_output[$entity];
7379
			if (!empty($object->logo))
7380
			{
7381
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
7382
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.getImageFileNameForSize($object->logo, '_small');
7383
				else $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.$object->logo;
7384
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.$object->logo;
7385
			}
7386
			$email = $object->email;
7387
		}
7388
		elseif ($modulepart == 'contact')
7389
		{
7390
			$dir = $conf->societe->multidir_output[$entity].'/contact';
7391
			if (!empty($object->photo))
7392
			{
7393
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.getImageFileNameForSize($object->photo, '_mini');
7394
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.getImageFileNameForSize($object->photo, '_small');
7395
				else $file = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.$object->photo;
7396
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.$object->photo;
7397
			}
7398
			$email = $object->email;
7399
			$capture = 'user';
7400
		}
7401
		elseif ($modulepart == 'userphoto')
7402
		{
7403
			$dir = $conf->user->dir_output;
7404
			if (!empty($object->photo))
7405
			{
7406
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_mini');
7407
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_small');
7408
				else $file = get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
7409
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
7410
			}
7411
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7412
			$email = $object->email;
7413
			$capture = 'user';
7414
		}
7415
		elseif ($modulepart == 'memberphoto')
7416
		{
7417
			$dir = $conf->adherent->dir_output;
7418
			if (!empty($object->photo))
7419
			{
7420
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
7421
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
7422
				else $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
7423
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
7424
			}
7425
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7426
			$email = $object->email;
7427
			$capture = 'user';
7428
		}
7429
		else
7430
		{
7431
			// Generic case to show photos
7432
			$dir = $conf->$modulepart->dir_output;
7433
			if (!empty($object->photo))
7434
			{
7435
				if ((string) $imagesize == 'mini') $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
7436
				elseif ((string) $imagesize == 'small') $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
7437
				else $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
7438
				$originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
7439
			}
7440
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7441
			$email = $object->email;
7442
		}
7443
7444
		if ($forcecapture) $capture = $forcecapture;
7445
7446
		if ($dir)
7447
		{
7448
			if ($file && file_exists($dir."/".$file))
7449
			{
7450
				if ($addlinktofullsize)
7451
				{
7452
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
7453
					if ($urladvanced) $ret .= '<a href="'.$urladvanced.'">';
7454
					else $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
7455
				}
7456
				$ret .= '<img alt="Photo" class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').' photologo'.(preg_replace('/[^a-z]/i', '_', $file)).'" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($file).'&cache='.$cache.'">';
7457
				if ($addlinktofullsize) $ret .= '</a>';
7458
			}
7459
			elseif ($altfile && file_exists($dir."/".$altfile))
7460
			{
7461
				if ($addlinktofullsize)
7462
				{
7463
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
7464
					if ($urladvanced) $ret .= '<a href="'.$urladvanced.'">';
7465
					else $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
7466
				}
7467
				$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.'">';
7468
				if ($addlinktofullsize) $ret .= '</a>';
7469
			}
7470
			else
7471
			{
7472
				$nophoto = '/public/theme/common/nophoto.png';
7473
				if (in_array($modulepart, array('userphoto', 'contact', 'memberphoto')))	// For module that are "physical" users
7474
				{
7475
					if ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor') !== false) {
7476
						$nophoto = '/public/theme/common/company.png';
7477
					}
7478
					else {
7479
						$nophoto = '/public/theme/common/user_anonymous.png';
7480
						if ($object->gender == 'man') $nophoto = '/public/theme/common/user_man.png';
7481
						if ($object->gender == 'woman') $nophoto = '/public/theme/common/user_woman.png';
7482
					}
7483
				}
7484
7485
				if (!empty($conf->gravatar->enabled) && $email)
7486
				{
7487
					/**
7488
					 * @see https://gravatar.com/site/implement/images/php/
7489
					 */
7490
					global $dolibarr_main_url_root;
7491
					$ret .= '<!-- Put link to gravatar -->';
7492
					//$defaultimg=urlencode(dol_buildpath($nophoto,3));
7493
					$defaultimg = 'mm';
7494
					$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="Gravatar avatar" title="'.$email.' Gravatar avatar" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="https://www.gravatar.com/avatar/'.md5(strtolower(trim($email))).'?s='.$width.'&d='.$defaultimg.'">'; // gravatar need md5 hash
7495
				}
7496
				else
7497
				{
7498
					$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
7499
				}
7500
			}
7501
7502
			if ($caneditfield)
7503
			{
7504
				if ($object->photo) $ret .= "<br>\n";
7505
				$ret .= '<table class="nobordernopadding centpercent">';
7506
				if ($object->photo) $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> '.$langs->trans("Delete").'<br><br></td></tr>';
7507
				$ret .= '<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'></td></tr>';
7508
				$ret .= '</table>';
7509
			}
7510
		}
7511
		else dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
7512
7513
		return $ret;
7514
	}
7515
7516
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7517
	/**
7518
	 *	Return select list of groups
7519
	 *
7520
	 *  @param	string	$selected       Id group preselected
7521
	 *  @param  string	$htmlname       Field name in form
7522
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
7523
	 *  @param  string	$exclude        Array list of groups id to exclude
7524
	 * 	@param	int		$disabled		If select list must be disabled
7525
	 *  @param  string	$include        Array list of groups id to include
7526
	 * 	@param	int		$enableonly		Array list of groups id to be enabled. All other must be disabled
7527
	 * 	@param	string	$force_entity	'0' or Ids of environment to force
7528
	 * 	@param	bool	$multiple		add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
7529
	 *  @return	string
7530
	 *  @see select_dolusers()
7531
	 */
7532
    public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false)
7533
	{
7534
        // phpcs:enable
7535
		global $conf, $user, $langs;
7536
7537
		// Permettre l'exclusion de groupes
7538
		if (is_array($exclude))	$excludeGroups = implode("','", $exclude);
0 ignored issues
show
introduced by
The condition is_array($exclude) is always false.
Loading history...
7539
		// Permettre l'inclusion de groupes
7540
		if (is_array($include))	$includeGroups = implode("','", $include);
0 ignored issues
show
introduced by
The condition is_array($include) is always false.
Loading history...
7541
7542
		if (!is_array($selected)) $selected = array($selected);
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
7543
7544
		$out = '';
7545
7546
		// On recherche les groupes
7547
		$sql = "SELECT ug.rowid, ug.nom as name";
7548
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
7549
		{
7550
			$sql .= ", e.label";
7551
		}
7552
		$sql .= " FROM ".MAIN_DB_PREFIX."usergroup as ug ";
7553
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
7554
		{
7555
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=ug.entity";
7556
			if ($force_entity) $sql .= " WHERE ug.entity IN (0,".$force_entity.")";
7557
			else $sql .= " WHERE ug.entity IS NOT NULL";
7558
		}
7559
		else
7560
		{
7561
			$sql .= " WHERE ug.entity IN (0,".$conf->entity.")";
7562
		}
7563
		if (is_array($exclude) && $excludeGroups) $sql .= " AND ug.rowid NOT IN ('".$excludeGroups."')";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $excludeGroups does not seem to be defined for all execution paths leading up to this point.
Loading history...
introduced by
The condition is_array($exclude) is always false.
Loading history...
7564
		if (is_array($include) && $includeGroups) $sql .= " AND ug.rowid IN ('".$includeGroups."')";
0 ignored issues
show
introduced by
The condition is_array($include) is always false.
Loading history...
Comprehensibility Best Practice introduced by
The variable $includeGroups does not seem to be defined for all execution paths leading up to this point.
Loading history...
7565
		$sql .= " ORDER BY ug.nom ASC";
7566
7567
		dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
7568
		$resql = $this->db->query($sql);
7569
		if ($resql)
7570
		{
7571
			// Enhance with select2
7572
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7573
		   	$out .= ajax_combobox($htmlname);
7574
7575
			$out .= '<select class="flat minwidth200" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
7576
7577
			$num = $this->db->num_rows($resql);
7578
			$i = 0;
7579
			if ($num)
7580
			{
7581
				if ($show_empty && !$multiple) $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
7582
7583
				while ($i < $num)
7584
				{
7585
					$obj = $this->db->fetch_object($resql);
7586
					$disableline = 0;
7587
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) $disableline = 1;
7588
7589
					$out .= '<option value="'.$obj->rowid.'"';
7590
					if ($disableline) $out .= ' disabled';
7591
					if ((is_object($selected[0]) && $selected[0]->id == $obj->rowid) || (!is_object($selected[0]) && in_array($obj->rowid, $selected)))
7592
					{
7593
						$out .= ' selected';
7594
					}
7595
					$out .= '>';
7596
7597
					$out .= $obj->name;
7598
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1)
7599
					{
7600
						$out .= " (".$obj->label.")";
7601
					}
7602
7603
					$out .= '</option>';
7604
					$i++;
7605
				}
7606
			}
7607
			else
7608
			{
7609
				if ($show_empty) $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
7610
				$out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
7611
			}
7612
			$out .= '</select>';
7613
		}
7614
		else
7615
		{
7616
			dol_print_error($this->db);
7617
		}
7618
7619
		return $out;
7620
	}
7621
7622
7623
	/**
7624
	 *	Return HTML to show the search and clear seach button
7625
	 *
7626
	 *  @return	string
7627
	 */
7628
    public function showFilterButtons()
7629
	{
7630
		$out = '<div class="nowrap">';
7631
		$out .= '<button type="submit" class="liste_titre button_search" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
7632
		$out .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
7633
		$out .= '</div>';
7634
7635
		return $out;
7636
	}
7637
7638
	/**
7639
	 *	Return HTML to show the search and clear seach button
7640
	 *
7641
	 *  @param  string  $cssclass                  CSS class
7642
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
7643
	 *  @return	string
7644
	 */
7645
    public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0)
7646
	{
7647
		global $conf, $langs;
7648
7649
		$out = '';
7650
		if (!empty($conf->use_javascript_ajax)) $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="checkallactions" name="checkallactions" class="checkallactions"></div>';
7651
		$out .= '<script>
7652
            $(document).ready(function() {
7653
            	$("#checkallactions").click(function() {
7654
                    if($(this).is(\':checked\')){
7655
                        console.log("We check all");
7656
                		$(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
7657
                    }
7658
                    else
7659
                    {
7660
                        console.log("We uncheck all");
7661
                		$(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
7662
                    }'."\n";
7663
		if ($calljsfunction) $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
7664
		$out .= '         });
7665
7666
        	$(".checkforselect").change(function() {
7667
				$(this).closest("tr").toggleClass("highlight", this.checked);
7668
			});
7669
7670
 	});
7671
    </script>';
7672
7673
		return $out;
7674
	}
7675
7676
	/**
7677
	 *	Return HTML to show the search and clear seach button
7678
	 *
7679
	 *  @param	int  	$addcheckuncheckall        Add the check all/uncheck all checkbox (use javascript) and code to manage this
7680
	 *  @param  string  $cssclass                  CSS class
7681
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
7682
	 *  @return	string
7683
	 */
7684
    public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0)
7685
	{
7686
		$out = $this->showFilterButtons();
7687
		if ($addcheckuncheckall)
7688
		{
7689
			$out .= $this->showCheckAddButtons($cssclass, $calljsfunction);
7690
		}
7691
		return $out;
7692
	}
7693
7694
	/**
7695
	 * Return HTML to show the select of expense categories
7696
	 *
7697
	 * @param	string	$selected              preselected category
7698
	 * @param	string	$htmlname              name of HTML select list
7699
	 * @param	integer	$useempty              1=Add empty line
7700
	 * @param	array	$excludeid             id to exclude
7701
	 * @param	string	$target                htmlname of target select to bind event
7702
	 * @param	int		$default_selected      default category to select if fk_c_type_fees change = EX_KME
7703
	 * @param	array	$params                param to give
7704
	 * @return	string
7705
	 */
7706
    public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array())
7707
	{
7708
		global $db, $conf, $langs, $user;
7709
7710
        $out = '';
7711
        $sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1';
7712
		$sql .= ' AND entity IN (0,'.getEntity('exp_tax_cat').')';
7713
		if (!empty($excludeid)) $sql .= ' AND rowid NOT IN ('.implode(',', $excludeid).')';
7714
		$sql .= ' ORDER BY label';
7715
7716
		$resql = $db->query($sql);
7717
		if ($resql)
7718
		{
7719
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7720
			if ($useempty) $out .= '<option value="0">&nbsp;</option>';
7721
7722
			while ($obj = $db->fetch_object($resql))
7723
			{
7724
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
7725
			}
7726
			$out .= '</select>';
7727
			if (!empty($htmlname) && $user->admin) $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
7728
7729
			if (!empty($target))
7730
			{
7731
				$sql = "SELECT c.id FROM ".MAIN_DB_PREFIX."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
7732
				$resql = $db->query($sql);
7733
				if ($resql)
7734
				{
7735
					if ($db->num_rows($resql) > 0)
7736
					{
7737
						$obj = $db->fetch_object($resql);
7738
						$out .= '<script>
7739
							$(function() {
7740
								$("select[name='.$target.']").on("change", function() {
7741
									var current_val = $(this).val();
7742
									if (current_val == '.$obj->id.') {';
7743
						if (!empty($default_selected) || !empty($selected)) $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
7744
7745
						$out .= '
7746
										$("select[name='.$htmlname.']").change();
7747
									}
7748
								});
7749
7750
								$("select[name='.$htmlname.']").change(function() {
7751
7752
									if ($("select[name='.$target.']").val() == '.$obj->id.') {
7753
										// get price of kilometer to fill the unit price
7754
										var data = '.json_encode($params).';
7755
										data.fk_c_exp_tax_cat = $(this).val();
7756
7757
										$.ajax({
7758
											method: "POST",
7759
											dataType: "json",
7760
											data: data,
7761
											url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php').'",
7762
										}).done(function( data, textStatus, jqXHR ) {
7763
											console.log(data);
7764
											if (typeof data.up != "undefined") {
7765
												$("input[name=value_unit]").val(data.up);
7766
												$("select[name='.$htmlname.']").attr("title", data.title);
7767
											} else {
7768
												$("input[name=value_unit]").val("");
7769
												$("select[name='.$htmlname.']").attr("title", "");
7770
											}
7771
										});
7772
									}
7773
								});
7774
							});
7775
						</script>';
7776
					}
7777
				}
7778
			}
7779
		}
7780
		else
7781
		{
7782
			dol_print_error($db);
7783
		}
7784
7785
		return $out;
7786
	}
7787
7788
	/**
7789
	 * Return HTML to show the select ranges of expense range
7790
	 *
7791
	 * @param	string	$selected    preselected category
7792
	 * @param	string	$htmlname    name of HTML select list
7793
	 * @param	integer	$useempty    1=Add empty line
7794
	 * @return	string
7795
	 */
7796
    public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
7797
	{
7798
		global $db, $conf, $langs;
7799
7800
        $out = '';
7801
		$sql = 'SELECT rowid, range_ik FROM '.MAIN_DB_PREFIX.'c_exp_tax_range';
7802
		$sql .= ' WHERE entity = '.$conf->entity.' AND active = 1';
7803
7804
		$resql = $db->query($sql);
7805
		if ($resql)
7806
		{
7807
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7808
			if ($useempty) $out .= '<option value="0"></option>';
7809
7810
			while ($obj = $db->fetch_object($resql))
7811
			{
7812
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
7813
			}
7814
			$out .= '</select>';
7815
		}
7816
		else
7817
		{
7818
			dol_print_error($db);
7819
		}
7820
7821
		return $out;
7822
	}
7823
7824
	/**
7825
	 * Return HTML to show a select of expense
7826
	 *
7827
	 * @param	string	$selected    preselected category
7828
	 * @param	string	$htmlname    name of HTML select list
7829
	 * @param	integer	$useempty    1=Add empty choice
7830
	 * @param	integer	$allchoice   1=Add all choice
7831
	 * @param	integer	$useid       0=use 'code' as key, 1=use 'id' as key
7832
	 * @return	string
7833
	 */
7834
    public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
7835
	{
7836
		global $db, $langs;
7837
7838
        $out = '';
7839
		$sql = 'SELECT id, code, label FROM '.MAIN_DB_PREFIX.'c_type_fees';
7840
		$sql .= ' WHERE active = 1';
7841
7842
		$resql = $db->query($sql);
7843
		if ($resql)
7844
		{
7845
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7846
			if ($useempty) $out .= '<option value="0"></option>';
7847
			if ($allchoice) $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
7848
7849
			$field = 'code';
7850
			if ($useid) $field = 'id';
7851
7852
			while ($obj = $db->fetch_object($resql))
7853
			{
7854
				$key = $langs->trans($obj->code);
7855
				$out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
7856
			}
7857
			$out .= '</select>';
7858
		}
7859
		else
7860
		{
7861
			dol_print_error($db);
7862
		}
7863
7864
        return $out;
7865
    }
7866
7867
	/**
7868
	 *  Output a combo list with invoices qualified for a third party
7869
	 *
7870
	 *  @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)
7871
	 *  @param  int		$selected   	Id invoice preselected
7872
	 *  @param  string	$htmlname   	Name of HTML select
7873
	 *	@param	int		$maxlength		Maximum length of label
7874
	 *	@param	int		$option_only	Return only html options lines without the select tag
7875
	 *	@param	string	$show_empty		Add an empty line ('1' or string to show for empty line)
7876
	 *  @param	int		$discard_closed Discard closed projects (0=Keep,1=hide completely,2=Disable)
7877
     *  @param	int		$forcefocus		Force focus on field (works with javascript only)
7878
     *  @param	int		$disabled		Disabled
7879
	 *  @param	string	$morecss        More css added to the select component
7880
	 *  @param	string	$projectsListId ''=Automatic filter on project allowed. List of id=Filter on project ids.
7881
	 *  @param	string	$showproject	'all' = Show project info, ''=Hide project info
7882
	 *  @param	User	$usertofilter	User object to use for filtering
7883
	 *	@return int         			Nbr of project if OK, <0 if KO
7884
	 */
7885
    public function selectInvoice($socid = -1, $selected = '', $htmlname = 'invoiceid', $maxlength = 24, $option_only = 0, $show_empty = '1', $discard_closed = 0, $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500', $projectsListId = '', $showproject = 'all', $usertofilter = null)
7886
	{
7887
		global $user, $conf, $langs;
7888
7889
		require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7890
7891
		if (is_null($usertofilter))
7892
		{
7893
			$usertofilter = $user;
7894
		}
7895
7896
		$out = '';
7897
7898
		$hideunselectables = false;
7899
		if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) $hideunselectables = true;
7900
7901
		if (empty($projectsListId))
7902
		{
7903
			if (empty($usertofilter->rights->projet->all->lire))
7904
			{
7905
				$projectstatic = new Project($this->db);
7906
				$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
7907
			}
7908
		}
7909
7910
		// Search all projects
7911
        $sql = 'SELECT f.rowid, f.ref as fref, "nolabel" as flabel, p.rowid as pid, f.ref,
7912
            p.title, p.fk_soc, p.fk_statut, p.public,';
7913
		$sql .= ' s.nom as name';
7914
		$sql .= ' FROM '.MAIN_DB_PREFIX.'projet as p';
7915
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = p.fk_soc,';
7916
		$sql .= ' '.MAIN_DB_PREFIX.'facture as f';
7917
		$sql .= " WHERE p.entity IN (".getEntity('project').")";
7918
		$sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
7919
		//if ($projectsListId) $sql.= " AND p.rowid IN (".$projectsListId.")";
7920
		//if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
7921
		//if ($socid > 0)  $sql.= " AND (p.fk_soc=".$socid." OR p.fk_soc IS NULL)";
7922
		$sql .= " GROUP BY f.ref ORDER BY p.ref, f.ref ASC";
7923
7924
		$resql = $this->db->query($sql);
7925
		if ($resql)
7926
		{
7927
			// Use select2 selector
7928
			if (!empty($conf->use_javascript_ajax))
7929
			{
7930
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7931
	           	$comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
7932
            	$out .= $comboenhancement;
7933
            	$morecss = 'minwidth200imp maxwidth500';
7934
			}
7935
7936
			if (empty($option_only)) {
7937
				$out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
7938
			}
7939
			if (!empty($show_empty)) {
7940
				$out .= '<option value="0" class="optiongrey">';
7941
				if (!is_numeric($show_empty)) $out .= $show_empty;
7942
				else $out .= '&nbsp;';
7943
				$out .= '</option>';
7944
			}
7945
			$num = $this->db->num_rows($resql);
7946
			$i = 0;
7947
			if ($num)
7948
			{
7949
				while ($i < $num)
7950
				{
7951
					$obj = $this->db->fetch_object($resql);
7952
					// If we ask to filter on a company and user has no permission to see all companies and project is linked to another company, we hide project.
7953
					if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire))
7954
					{
7955
						// Do nothing
7956
					}
7957
					else
7958
					{
7959
						if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED)
7960
						{
7961
							$i++;
7962
							continue;
7963
						}
7964
7965
						$labeltoshow = '';
7966
7967
						if ($showproject == 'all')
7968
						{
7969
							$labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
7970
							if ($obj->name) $labeltoshow .= ' - '.$obj->name; // Soc name
7971
7972
							$disabled = 0;
7973
							if ($obj->fk_statut == Project::STATUS_DRAFT)
7974
							{
7975
								$disabled = 1;
7976
								$labeltoshow .= ' - '.$langs->trans("Draft");
7977
							}
7978
							elseif ($obj->fk_statut == Project::STATUS_CLOSED)
7979
							{
7980
								if ($discard_closed == 2) $disabled = 1;
7981
								$labeltoshow .= ' - '.$langs->trans("Closed");
7982
							}
7983
							elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid))
7984
							{
7985
								$disabled = 1;
7986
								$labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
7987
							}
7988
						}
7989
7990
						if (!empty($selected) && $selected == $obj->rowid)
7991
						{
7992
							$out .= '<option value="'.$obj->rowid.'" selected';
7993
							//if ($disabled) $out.=' disabled';						// with select2, field can't be preselected if disabled
7994
							$out .= '>'.$labeltoshow.'</option>';
7995
						}
7996
						else
7997
						{
7998
							if ($hideunselectables && $disabled && ($selected != $obj->rowid))
7999
							{
8000
								$resultat = '';
8001
							}
8002
							else
8003
							{
8004
								$resultat = '<option value="'.$obj->rowid.'"';
8005
								if ($disabled) $resultat .= ' disabled';
8006
								//if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
8007
								//else $labeltoshow.=' ('.$langs->trans("Private").')';
8008
								$resultat .= '>';
8009
								$resultat .= $labeltoshow;
8010
								$resultat .= '</option>';
8011
							}
8012
							$out .= $resultat;
8013
						}
8014
					}
8015
					$i++;
8016
				}
8017
			}
8018
			if (empty($option_only)) {
8019
				$out .= '</select>';
8020
			}
8021
8022
			print $out;
8023
8024
			$this->db->free($resql);
8025
			return $num;
8026
		}
8027
		else
8028
		{
8029
			dol_print_error($this->db);
8030
			return -1;
8031
		}
8032
	}
8033
8034
	/**
8035
	 * Output the component to make advanced search criteries
8036
	 *
8037
	 * @param	array		$arrayofcriterias			          Array of available search criterias. Example: array($object->element => $object->fields, 'otherfamily' => otherarrayoffields, ...)
8038
	 * @param	array		$search_component_params	          Array of selected search criterias
8039
	 * @param   array       $arrayofinputfieldsalreadyoutput      Array of input fields already inform. The component will not generate a hidden input field if it is in this list.
8040
	 * @return	string									          HTML component for advanced search
8041
	 */
8042
	public function searchComponent($arrayofcriterias, $search_component_params, $arrayofhiddenfieldstoadd = array())
8043
	{
8044
	    global $conf, $langs;
8045
8046
		$ret = '';
8047
8048
		$ret .= '<div class="nowrap centpercent">';
8049
		//$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
8050
		$ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor paddingright">';
8051
		$ret .= '<span class="fas fa-filter linkobject boxfilter" title="Filter" id="idsubimgproductdistribution"></span>';
8052
		$ret .= $langs->trans("Filters");
8053
		$ret .= '</a>';
8054
		//$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
8055
		$ret .= '<div name="search_component_params" class="search_component_params inline-block centpercent">';
8056
		$ret .= '<input type="text" name="search_component_params_input" class="search_component_params_input" placeholder="'.$langs->trans("Search").'" value="'.GETPOST("search_component_params_input").'">';
8057
		$ret .= '</div>';
8058
		foreach($arrayofcriterias as $criterias) {
8059
		    foreach($criterias as $criteriafamilykey => $criteriafamilyval) {
8060
		        if (in_array('search_'.$criteriafamilykey, $arrayofhiddenfieldstoadd)) continue;
8061
		        if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) continue;
8062
		        if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
8063
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
8064
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
8065
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
8066
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
8067
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
8068
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
8069
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
8070
		            $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
8071
		        }
8072
		        else {
8073
		          $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
8074
		        }
8075
		    }
8076
		}
8077
        $ret .= '</div>';
8078
8079
8080
		return $ret;
8081
	}
8082
}
8083