Passed
Branch develop (e2bf59)
by
unknown
29:11
created

Form::select_produits()   F

Complexity

Conditions 29
Paths > 20000

Size

Total Lines 143
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 29
eloc 48
c 0
b 0
f 0
nc 49184
nop 19
dl 0
loc 143
rs 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-2021  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-2020  Alexandre Spangaro      <[email protected]>
19
 * Copyright (C) 2018-2022  Ferran Marcet           <[email protected]>
20
 * Copyright (C) 2018-2021  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_transport_mode = array();
75
	public $cache_availability = array();
76
	public $cache_demand_reason = array();
77
	public $cache_types_fees = array();
78
	public $cache_vatrates = array();
79
80
81
	/**
82
	 * Constructor
83
	 *
84
	 * @param		DoliDB		$db      Database handler
85
	 */
86
	public function __construct($db)
87
	{
88
		$this->db = $db;
89
	}
90
91
	/**
92
	 * Output key field for an editable field
93
	 *
94
	 * @param   string	$text			Text of label or key to translate
95
	 * @param   string	$htmlname		Name of select field ('edit' prefix will be added)
96
	 * @param   string	$preselected    Value to show/edit (not used in this function)
97
	 * @param	object	$object			Object
98
	 * @param	boolean	$perm			Permission to allow button to edit parameter. Set it to 0 to have a not edited field.
99
	 * @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), 'checkbox:ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...)
100
	 * @param	string	$moreparam		More param to add on a href URL.
101
	 * @param   int     $fieldrequired  1 if we want to show field as mandatory using the "fieldrequired" CSS.
102
	 * @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 ' '
103
	 * @param	string	$paramid		Key of parameter for id ('id', 'socid')
104
	 * @param	string	$help			Tooltip help
105
	 * @return	string					HTML edit field
106
	 */
107
	public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
108
	{
109
		global $conf, $langs;
110
111
		$ret = '';
112
113
		// TODO change for compatibility
114
		if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) {
115
			if (!empty($perm)) {
116
				$tmp = explode(':', $typeofdata);
117
				$ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
118
				if ($fieldrequired) {
119
					$ret .= '<span class="fieldrequired">';
120
				}
121
				if ($help) {
122
					$ret .= $this->textwithpicto($langs->trans($text), $help);
123
				} else {
124
					$ret .= $langs->trans($text);
125
				}
126
				if ($fieldrequired) {
127
					$ret .= '</span>';
128
				}
129
				$ret .= '</div>'."\n";
130
			} else {
131
				if ($fieldrequired) {
132
					$ret .= '<span class="fieldrequired">';
133
				}
134
				if ($help) {
135
					$ret .= $this->textwithpicto($langs->trans($text), $help);
136
				} else {
137
					$ret .= $langs->trans($text);
138
				}
139
				if ($fieldrequired) {
140
					$ret .= '</span>';
141
				}
142
			}
143
		} else {
144
			if (empty($notabletag) && $perm) {
145
				$ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
146
			}
147
			if ($fieldrequired) {
148
				$ret .= '<span class="fieldrequired">';
149
			}
150
			if ($help) {
151
				$ret .= $this->textwithpicto($langs->trans($text), $help);
152
			} else {
153
				$ret .= $langs->trans($text);
154
			}
155
			if ($fieldrequired) {
156
				$ret .= '</span>';
157
			}
158
			if (!empty($notabletag)) {
159
				$ret .= ' ';
160
			}
161
			if (empty($notabletag) && $perm) {
162
				$ret .= '</td>';
163
			}
164
			if (empty($notabletag) && $perm) {
165
				$ret .= '<td class="right">';
166
			}
167
			if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) {
168
				$ret .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&token='.newToken().'&'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
169
			}
170
			if (!empty($notabletag) && $notabletag == 1) {
171
				$ret .= ' : ';
172
			}
173
			if (!empty($notabletag) && $notabletag == 3) {
174
				$ret .= ' ';
175
			}
176
			if (empty($notabletag) && $perm) {
177
				$ret .= '</td>';
178
			}
179
			if (empty($notabletag) && $perm) {
180
				$ret .= '</tr></table>';
181
			}
182
		}
183
184
		return $ret;
185
	}
186
187
	/**
188
	 * Output value of a field for an editable field
189
	 *
190
	 * @param	string	$text			Text of label (not used in this function)
191
	 * @param	string	$htmlname		Name of select field
192
	 * @param	string	$value			Value to show/edit
193
	 * @param	object	$object			Object
194
	 * @param	boolean	$perm			Permission to allow button to edit parameter
195
	 * @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,...')
196
	 * @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 numeric value). Use '' to use same than $value
197
	 * @param	object	$extObject		External object
198
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
199
	 * @param	string	$moreparam		More param to add on the form action href URL
200
	 * @param   int     $notabletag     Do no output table tags
201
	 * @param	string	$formatfunc		Call a specific function to output field in view mode (For example: 'dol_print_email')
202
	 * @param	string	$paramid		Key of parameter for id ('id', 'socid')
203
	 * @param	string	$gm				'auto' or 'tzuser' or 'tzserver' (when $typeofdata is a date)
204
	 * @return  string					HTML edit field
205
	 */
206
	public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id', $gm = 'auto')
207
	{
208
		global $conf, $langs;
209
210
		$ret = '';
211
212
		// Check parameters
213
		if (empty($typeofdata)) {
214
			return 'ErrorBadParameter';
215
		}
216
217
		// When option to edit inline is activated
218
		if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
219
			$ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
220
		} else {
221
			$editmode = (GETPOST('action', 'aZ09') == 'edit'.$htmlname);
222
			if ($editmode) {
223
				$ret .= "\n";
224
				$ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">';
225
				$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
226
				$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
227
				$ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
228
				if (empty($notabletag)) {
229
					$ret .= '<table class="nobordernopadding centpercent">';
230
				}
231
				if (empty($notabletag)) {
232
					$ret .= '<tr><td>';
233
				}
234
				if (preg_match('/^(string|safehtmlstring|email)/', $typeofdata)) {
235
					$tmp = explode(':', $typeofdata);
236
					$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>';
237
				} elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
238
					$tmp = explode(':', $typeofdata);
239
					$valuetoshow = price2num($editvalue ? $editvalue : $value);
240
					$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ? price($valuetoshow) : '').'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>';
241
				} elseif (preg_match('/^(checkbox)/', $typeofdata)) {
242
					$tmp = explode(':', $typeofdata);
243
					$ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($tmp[1] ? $tmp[1] : '') . '/>';
244
				} elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {	// if wysiwyg is enabled $typeofdata = 'ckeditor'
245
					$tmp = explode(':', $typeofdata);
246
					$cols = $tmp[2];
247
					$morealt = '';
248
					if (preg_match('/%/', $cols)) {
249
						$morealt = ' style="width: '.$cols.'"';
250
						$cols = '';
251
					}
252
253
					$valuetoshow = ($editvalue ? $editvalue : $value);
254
					$ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1] ? $tmp[1] : '20').'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'" autofocus>';
255
					// textarea convert automatically entities chars into simple chars.
256
					// 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.
257
					$valuetoshow = str_replace('&', '&amp;', $valuetoshow);
258
					$ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
259
					$ret .= '</textarea>';
260
				} elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
261
					$ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0, 0, '', '', '', '', 1, '', '', $gm);
262
				} elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
263
					$ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0, 0, '', '', '', '', 1, '', '', $gm);
264
				} elseif (preg_match('/^select;/', $typeofdata)) {
265
					$arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
266
					$arraylist = array();
267
					foreach ($arraydata as $val) {
268
						$tmp = explode(':', $val);
269
						$tmpkey = str_replace('|', ':', $tmp[0]);
270
						$arraylist[$tmpkey] = $tmp[1];
271
					}
272
					$ret .= $this->selectarray($htmlname, $arraylist, $value);
273
				} elseif (preg_match('/^ckeditor/', $typeofdata)) {
274
					$tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
275
					require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
276
					$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'));
277
					$ret .= $doleditor->Create(1);
278
				}
279
				if (empty($notabletag)) {
280
					$ret .= '</td>';
281
				}
282
283
				if (empty($notabletag)) {
284
					$ret .= '<td class="left">';
285
				}
286
				//else $ret.='<div class="clearboth"></div>';
287
				$ret .= '<input type="submit" class="smallpaddingimp button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
288
				if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
289
					$ret .= '<br>'."\n";
290
				}
291
				$ret .= '<input type="submit" class="smallpaddingimp button button-cancel'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
292
				if (empty($notabletag)) {
293
					$ret .= '</td>';
294
				}
295
296
				if (empty($notabletag)) {
297
					$ret .= '</tr></table>'."\n";
298
				}
299
				$ret .= '</form>'."\n";
300
			} else {
301
				if (preg_match('/^(email)/', $typeofdata)) {
302
					$ret .= dol_print_email($value, 0, 0, 0, 0, 1);
303
				} elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
304
					$ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
305
				} elseif (preg_match('/^(checkbox)/', $typeofdata)) {
306
					$tmp = explode(':', $typeofdata);
307
					$ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($tmp[1] ? $tmp[1] : '') . '/>';
308
				} elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
309
					$ret .= dol_htmlentitiesbr($value);
310
				} elseif (preg_match('/^safehtmlstring/', $typeofdata)) {
311
					$ret .= dol_string_onlythesehtmltags($value);
312
				} elseif (preg_match('/^restricthtml/', $typeofdata)) {
313
					$ret .= dol_string_onlythesehtmltags($value);
314
				} elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
315
					$ret .= '<span class="valuedate">'.dol_print_date($value, 'day', $gm).'</span>';
316
				} elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
317
					$ret .= '<span class="valuedate">'.dol_print_date($value, 'dayhour', $gm).'</span>';
318
				} elseif (preg_match('/^select;/', $typeofdata)) {
319
					$arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
320
					$arraylist = array();
321
					foreach ($arraydata as $val) {
322
						$tmp = explode(':', $val);
323
						$arraylist[$tmp[0]] = $tmp[1];
324
					}
325
					$ret .= $arraylist[$value];
326
					if ($htmlname == 'fk_product_type') {
327
						if ($value == 0) {
328
							$ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"').$ret;
329
						} else {
330
							$ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"').$ret;
331
						}
332
					}
333
				} elseif (preg_match('/^ckeditor/', $typeofdata)) {
334
					$tmpcontent = dol_htmlentitiesbr($value);
335
					if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) {
336
						$firstline = preg_replace('/<br>.*/', '', $tmpcontent);
337
						$firstline = preg_replace('/[\n\r].*/', '', $firstline);
338
						$tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
339
					}
340
					// We dont use dol_escape_htmltag to get the html formating active, but this need we must also
341
					// clean data from some dangerous html
342
					$ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent));
343
				} else {
344
					$ret .= dol_escape_htmltag($value);
345
				}
346
347
				if ($formatfunc && method_exists($object, $formatfunc)) {
348
					$ret = $object->$formatfunc($ret);
349
				}
350
			}
351
		}
352
		return $ret;
353
	}
354
355
	/**
356
	 * Output edit in place form
357
	 *
358
	 * @param   string	$fieldname		Name of the field
359
	 * @param	object	$object			Object
360
	 * @param	boolean	$perm			Permission to allow button to edit parameter. Set it to 0 to have a not edited field.
361
	 * @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]'...)
362
	 * @param	string	$check			Same coe than $check parameter of GETPOST()
363
	 * @param	string	$morecss		More CSS
364
	 * @return	string   		      	HTML code for the edit of alternative language
365
	 */
366
	public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
367
	{
368
		global $conf, $langs, $extralanguages;
369
370
		$result = '';
371
372
		// List of extra languages
373
		$arrayoflangcode = array();
374
		if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
375
			$arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
376
		}
377
378
		if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
379
			if (!is_object($extralanguages)) {
380
				include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
381
				$extralanguages = new ExtraLanguages($this->db);
382
			}
383
			$extralanguages->fetch_name_extralanguages('societe');
384
385
			if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
386
				return ''; // No extralang field to show
387
			}
388
389
			$result .= '<!-- Widget for translation -->'."\n";
390
			$result .= '<div class="inline-block paddingleft image-'.$object->element.'-'.$fieldname.'">';
391
			$s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
392
			$result .= $s;
393
			$result .= '</div>';
394
395
			$result .= '<div class="inline-block hidden field-'.$object->element.'-'.$fieldname.'">';
396
397
			$resultforextrlang = '';
398
			foreach ($arrayoflangcode as $langcode) {
399
				$valuetoshow = GETPOSTISSET('field-'.$object->element."-".$fieldname."-".$langcode) ? GETPOST('field-'.$object->element.'-'.$fieldname."-".$langcode, $check) : '';
400
				if (empty($valuetoshow)) {
401
					$object->fetchValuesForExtraLanguages();
402
					//var_dump($object->array_languages);
403
					$valuetoshow = $object->array_languages[$fieldname][$langcode];
404
				}
405
406
				$s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
407
				$resultforextrlang .= $s;
408
409
				// TODO Use the showInputField() method of ExtraLanguages object
410
				if ($typeofdata == 'textarea') {
411
					$resultforextrlang .= '<textarea name="field-'.$object->element."-".$fieldname."-".$langcode.'" id="'.$fieldname."-".$langcode.'" class="'.$morecss.'" rows="'.ROWS_2.'" wrap="soft">';
412
					$resultforextrlang .= $valuetoshow;
413
					$resultforextrlang .= '</textarea>';
414
				} else {
415
					$resultforextrlang .= '<input type="text" class="inputfieldforlang '.($morecss ? ' '.$morecss : '').'" name="field-'.$object->element.'-'.$fieldname.'-'.$langcode.'" value="'.$valuetoshow.'">';
416
				}
417
			}
418
			$result .= $resultforextrlang;
419
420
			$result .= '</div>';
421
			$result .= '<script>$(".image-'.$object->element.'-'.$fieldname.'").click(function() { console.log("Toggle lang widget"); jQuery(".field-'.$object->element.'-'.$fieldname.'").toggle(); });</script>';
422
		}
423
424
		return $result;
425
	}
426
427
	/**
428
	 * Output edit in place form
429
	 *
430
	 * @param	object	$object			Object
431
	 * @param	string	$value			Value to show/edit
432
	 * @param	string	$htmlname		DIV ID (field name)
433
	 * @param	int		$condition		Condition to edit
434
	 * @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')
435
	 * @param	string	$editvalue		When in edit mode, use this value as $value instead of value
436
	 * @param	object	$extObject		External object
437
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
438
	 * @return	string   		      	HTML edit in place
439
	 */
440
	protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
441
	{
442
		global $conf;
443
444
		$out = '';
445
446
		// Check parameters
447
		if (preg_match('/^text/', $inputType)) {
448
			$value = dol_nl2br($value);
449
		} elseif (preg_match('/^numeric/', $inputType)) {
450
			$value = price($value);
451
		} elseif ($inputType == 'day' || $inputType == 'datepicker') {
452
			$value = dol_print_date($value, 'day');
453
		}
454
455
		if ($condition) {
456
			$element = false;
457
			$table_element = false;
458
			$fk_element		= false;
459
			$loadmethod		= false;
460
			$savemethod		= false;
461
			$ext_element	= false;
462
			$button_only	= false;
463
			$inputOption = '';
464
465
			if (is_object($object)) {
466
				$element = $object->element;
467
				$table_element = $object->table_element;
468
				$fk_element = $object->id;
469
			}
470
471
			if (is_object($extObject)) {
472
				$ext_element = $extObject->element;
473
			}
474
475
			if (preg_match('/^(string|email|numeric)/', $inputType)) {
476
				$tmp = explode(':', $inputType);
477
				$inputType = $tmp[0];
478
				if (!empty($tmp[1])) {
479
					$inputOption = $tmp[1];
480
				}
481
				if (!empty($tmp[2])) {
482
					$savemethod = $tmp[2];
483
				}
484
				$out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
485
			} elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
486
				$tmp = explode(':', $inputType);
487
				$inputType = $tmp[0];
488
				if (!empty($tmp[1])) {
489
					$inputOption = $tmp[1];
490
				}
491
				if (!empty($tmp[2])) {
492
					$savemethod = $tmp[2];
493
				}
494
495
				$out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
496
			} elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
497
				$tmp = explode(':', $inputType);
498
				$inputType = $tmp[0];
499
				$loadmethod = $tmp[1];
500
				if (!empty($tmp[2])) {
501
					$savemethod = $tmp[2];
502
				}
503
				if (!empty($tmp[3])) {
504
					$button_only = true;
505
				}
506
			} elseif (preg_match('/^textarea/', $inputType)) {
507
				$tmp = explode(':', $inputType);
508
				$inputType = $tmp[0];
509
				$rows = (empty($tmp[1]) ? '8' : $tmp[1]);
510
				$cols = (empty($tmp[2]) ? '80' : $tmp[2]);
511
			} elseif (preg_match('/^ckeditor/', $inputType)) {
512
				$tmp = explode(':', $inputType);
513
				$inputType = $tmp[0];
514
				$toolbar = $tmp[1];
515
				if (!empty($tmp[2])) {
516
					$width = $tmp[2];
517
				}
518
				if (!empty($tmp[3])) {
519
					$heigth = $tmp[3];
520
				}
521
				if (!empty($tmp[4])) {
522
					$savemethod = $tmp[4];
523
				}
524
525
				if (!empty($conf->fckeditor->enabled)) {
526
					$out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
527
				} else {
528
					$inputType = 'textarea';
529
				}
530
			}
531
532
			$out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
533
			$out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
534
			$out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
535
			$out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
536
			if (!empty($savemethod)) {
537
				$out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
538
			}
539
			if (!empty($ext_element)) {
540
				$out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
541
			}
542
			if (!empty($custommsg)) {
543
				if (is_array($custommsg)) {
544
					if (!empty($custommsg['success'])) {
545
						$out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
546
					}
547
					if (!empty($custommsg['error'])) {
548
						$out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
549
					}
550
				} else {
551
					$out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
552
				}
553
			}
554
			if ($inputType == 'textarea') {
555
				$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...
556
				$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...
557
			}
558
			$out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
559
			$out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n";
560
		} else {
561
			$out = $value;
562
		}
563
564
		return $out;
565
	}
566
567
	/**
568
	 *	Show a text and picto with tooltip on text or picto.
569
	 *  Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip
570
	 *
571
	 *	@param	string		$text				Text to show
572
	 *	@param	string		$htmltext			HTML content of tooltip. Must be HTML/UTF8 encoded.
573
	 *	@param	int			$tooltipon			1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2
574
	 *	@param	int			$direction			-1=image is before, 0=no image, 1=image is after
575
	 *	@param	string		$img				Html code for image (use img_xxx() function to get it)
576
	 *	@param	string		$extracss			Add a CSS style to td tags
577
	 *	@param	int			$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
578
	 *	@param	string		$incbefore			Include code before the text
579
	 *	@param	int			$noencodehtmltext	Do not encode into html entity the htmltext
580
	 *  @param  string      $tooltiptrigger		''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key)
581
	 *  @param	int			$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
582
	 *	@return	string							Code html du tooltip (texte+picto)
583
	 *	@see	textwithpicto() Use thisfunction if you can.
584
	 */
585
	public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
586
	{
587
		if ($incbefore) {
588
			$text = $incbefore.$text;
589
		}
590
		if (!$htmltext) {
591
			return $text;
592
		}
593
		$direction = (int) $direction;	// For backward compatibility when $direction was set to '' instead of 0
594
595
		$tag = 'td';
596
		if ($notabs == 2) {
597
			$tag = 'div';
598
		}
599
		if ($notabs == 3) {
600
			$tag = 'span';
601
		}
602
		// Sanitize tooltip
603
		$htmltext = str_replace(array("\r", "\n"), '', $htmltext);
604
605
		$extrastyle = '';
606
		if ($direction < 0) {
607
			$extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : '');
608
			$extrastyle = 'padding: 0px; padding-left: 3px !important;';
609
		}
610
		if ($direction > 0) {
611
			$extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : '');
612
			$extrastyle = 'padding: 0px; padding-right: 3px !important;';
613
		}
614
615
		$classfortooltip = 'classfortooltip';
616
617
		$s = '';
618
		$textfordialog = '';
619
620
		if ($tooltiptrigger == '') {
621
			$htmltext = str_replace('"', '&quot;', $htmltext);
622
		} else {
623
			$classfortooltip = 'classfortooltiponclick';
624
			$textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
625
		}
626
		if ($tooltipon == 2 || $tooltipon == 3) {
627
			$paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
628
			if ($tooltiptrigger == '') {
629
				$paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
630
			} else {
631
				$paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
632
			}
633
		} else {
634
			$paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
635
		}
636
		if ($tooltipon == 1 || $tooltipon == 3) {
637
			$paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
638
			if ($tooltiptrigger == '') {
639
				$paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
640
			} else {
641
				$paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
642
			}
643
		} else {
644
			$paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
645
		}
646
		if (empty($notabs)) {
647
			$s .= '<table class="nobordernopadding"><tr style="height: auto;">';
648
		} elseif ($notabs == 2) {
649
			$s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">';
650
		}
651
		// Define value if value is before
652
		if ($direction < 0) {
653
			$s .= '<'.$tag.$paramfortooltipimg;
654
			if ($tag == 'td') {
655
				$s .= ' class=valigntop" width="14"';
656
			}
657
			$s .= '>'.$textfordialog.$img.'</'.$tag.'>';
658
		}
659
		// Use another method to help avoid having a space in value in order to use this value with jquery
660
		// Define label
661
		if ((string) $text != '') {
662
			$s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
663
		}
664
		// Define value if value is after
665
		if ($direction > 0) {
666
			$s .= '<'.$tag.$paramfortooltipimg;
667
			if ($tag == 'td') {
668
				$s .= ' class="valignmiddle" width="14"';
669
			}
670
			$s .= '>'.$textfordialog.$img.'</'.$tag.'>';
671
		}
672
		if (empty($notabs)) {
673
			$s .= '</tr></table>';
674
		} elseif ($notabs == 2) {
675
			$s .= '</div>';
676
		}
677
678
		return $s;
679
	}
680
681
	/**
682
	 *	Show a text with a picto and a tooltip on picto
683
	 *
684
	 *	@param	string	$text				Text to show
685
	 *	@param  string	$htmltext	     	Content of tooltip
686
	 *	@param	int		$direction			1=Icon is after text, -1=Icon is before text, 0=no icon
687
	 * 	@param	string	$type				Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none'
688
	 *  @param  string	$extracss           Add a CSS style to td, div or span tag
689
	 *  @param  int		$noencodehtmltext   Do not encode into html entity the htmltext
690
	 *  @param	int		$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
691
	 *  @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')
692
	 *  @param	int		$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
693
	 * 	@return	string						HTML code of text, picto, tooltip
694
	 */
695
	public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
696
	{
697
		global $conf, $langs;
698
699
		$alt = '';
700
		if ($tooltiptrigger) {
701
			$alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
702
		}
703
704
		//For backwards compatibility
705
		if ($type == '0') {
706
			$type = 'info';
707
		} elseif ($type == '1') {
708
			$type = 'help';
709
		}
710
711
		// If info or help with no javascript, show only text
712
		if (empty($conf->use_javascript_ajax)) {
713
			if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
714
				return $text;
715
			} else {
716
				$alt = $htmltext;
717
				$htmltext = '';
718
			}
719
		}
720
721
		// If info or help with smartphone, show only text (tooltip hover can't works)
722
		if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
723
			if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
724
				return $text;
725
			}
726
		}
727
		// If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
728
		//if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
729
		//{
730
		//if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>';
731
		//}
732
733
		$img = '';
734
		if ($type == 'info') {
735
			$img = img_help(0, $alt);
736
		} elseif ($type == 'help') {
737
			$img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
738
		} elseif ($type == 'helpclickable') {
739
			$img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
740
		} elseif ($type == 'superadmin') {
741
			$img = img_picto($alt, 'redstar');
742
		} elseif ($type == 'admin') {
743
			$img = img_picto($alt, 'star');
744
		} elseif ($type == 'warning') {
745
			$img = img_warning($alt);
746
		} elseif ($type != 'none') {
747
			$img = img_picto($alt, $type); // $type can be an image path
748
		}
749
750
		return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
751
	}
752
753
	/**
754
	 * Generate select HTML to choose massaction
755
	 *
756
	 * @param	string	$selected		Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default.
757
	 * @param	array	$arrayofaction	array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action.
758
	 * @param   int     $alwaysvisible  1=select button always visible
759
	 * @param   string  $name     		Name for massaction
760
	 * @param   string  $cssclass 		CSS class used to check for select
761
	 * @return	string|void				Select list
762
	 */
763
	public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
764
	{
765
		global $conf, $langs, $hookmanager;
766
767
768
		$disabled = 0;
769
		$ret = '<div class="centpercent center">';
770
		$ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>';
771
772
		// 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.
773
		$parameters = array();
774
		$reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
775
		// check if there is a mass action
776
		if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
777
			return;
778
		}
779
		if (empty($reshook)) {
780
			$ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
781
			foreach ($arrayofaction as $code => $label) {
782
				$ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
783
			}
784
		}
785
		$ret .= $hookmanager->resPrint;
786
787
		$ret .= '</select>';
788
789
		if (empty($conf->dol_optimize_smallscreen)) {
790
			$ret .= ajax_combobox('.'.$name.'select');
791
		}
792
793
		// 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
794
		$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.
795
		$ret .= '<input type="submit" disabled name="confirmmassaction"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display: none"').' class="button smallpaddingimp'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
796
		$ret .= '</div>';
797
798
		if (!empty($conf->use_javascript_ajax)) {
799
			$ret .= '<!-- JS CODE TO ENABLE mass action select -->
800
    		<script>
801
                        function initCheckForSelect(mode, name, cssclass)	/* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */
802
        		{
803
        			atleastoneselected=0;
804
                                jQuery("."+cssclass).each(function( index ) {
805
    	  				/* console.log( index + ": " + $( this ).text() ); */
806
    	  				if ($(this).is(\':checked\')) atleastoneselected++;
807
    	  			});
808
809
					console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
810
811
    	  			if (atleastoneselected || '.$alwaysvisible.')
812
    	  			{
813
                                    jQuery("."+name).show();
814
        			    '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').'
815
        			    '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').'
816
    	  			}
817
    	  			else
818
    	  			{
819
                                    jQuery("."+name).hide();
820
                                    jQuery("."+name+"other").hide();
821
    	            }
822
        		}
823
824
        	jQuery(document).ready(function () {
825
                    initCheckForSelect(0, "' . $name.'", "'.$cssclass.'");
826
                    jQuery(".' . $cssclass.'").click(function() {
827
                        initCheckForSelect(1, "'.$name.'", "'.$cssclass.'");
828
                    });
829
                        jQuery(".' . $name.'select").change(function() {
830
        			var massaction = $( this ).val();
831
        			var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
832
        			if (massaction == "builddoc")
833
                    {
834
                        urlform = urlform + "#show_files";
835
    	            }
836
        			$( this ).closest("form").attr("action", urlform);
837
                    console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform);
838
        	        /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
839
        			if ($(this).val() != \'0\')
840
    	  			{
841
                                        jQuery(".' . $name.'confirmed").prop(\'disabled\', false);
842
										jQuery(".' . $name.'other").hide();	/* To disable if another div was open */
843
                                        jQuery(".' . $name.'"+massaction).show();
844
    	  			}
845
    	  			else
846
    	  			{
847
                                        jQuery(".' . $name.'confirmed").prop(\'disabled\', true);
848
										jQuery(".' . $name.'other").hide();	/* To disable any div open */
849
    	  			}
850
    	        });
851
        	});
852
    		</script>
853
        	';
854
		}
855
856
		return $ret;
857
	}
858
859
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
860
	/**
861
	 *  Return combo list of activated countries, into language of user
862
	 *
863
	 *  @param	string	$selected       		Id or Code or Label of preselected country
864
	 *  @param  string	$htmlname       		Name of html select object
865
	 *  @param  string	$htmloption     		More html options on select object
866
	 *  @param	integer	$maxlength				Max length for labels (0=no limit)
867
	 *  @param	string	$morecss				More css class
868
	 *  @param	string	$usecodeaskey			''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
869
	 *  @param	int		$showempty				Show empty choice
870
	 *  @param	int		$disablefavorites		1=Disable favorites,
871
	 *  @param	int		$addspecialentries		1=Add dedicated entries for group of countries (like 'European Economic Community', ...)
872
	 *  @param	array	$exclude_country_code	Array of country code (iso2) to exclude
873
	 *  @param	int		$hideflags				Hide flags
874
	 *  @return string           				HTML string with select
875
	 */
876
	public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0)
877
	{
878
		// phpcs:enable
879
		global $conf, $langs, $mysoc;
880
881
		$langs->load("dict");
882
883
		$out = '';
884
		$countryArray = array();
885
		$favorite = array();
886
		$label = array();
887
		$atleastonefavorite = 0;
888
889
		$sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
890
		$sql .= " FROM ".$this->db->prefix()."c_country";
891
		$sql .= " WHERE active > 0";
892
		//$sql.= " ORDER BY code ASC";
893
894
		dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
895
		$resql = $this->db->query($sql);
896
		if ($resql) {
897
			$out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
898
			$num = $this->db->num_rows($resql);
899
			$i = 0;
900
			if ($num) {
901
				while ($i < $num) {
902
					$obj = $this->db->fetch_object($resql);
903
904
					$countryArray[$i]['rowid'] = $obj->rowid;
905
					$countryArray[$i]['code_iso'] = $obj->code_iso;
906
					$countryArray[$i]['code_iso3'] 	= $obj->code_iso3;
907
					$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 : ''));
908
					$countryArray[$i]['favorite'] = $obj->favorite;
909
					$countryArray[$i]['eec'] = $obj->eec;
910
					$favorite[$i] = $obj->favorite;
911
					$label[$i] = dol_string_unaccent($countryArray[$i]['label']);
912
					$i++;
913
				}
914
915
				if (empty($disablefavorites)) {
916
					array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
0 ignored issues
show
Bug introduced by
SORT_DESC cannot be passed to array_multisort() as the parameter $rest expects a reference. ( Ignorable by Annotation )

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

916
					array_multisort($favorite, /** @scrutinizer ignore-type */ SORT_DESC, $label, SORT_ASC, $countryArray);
Loading history...
Bug introduced by
SORT_ASC cannot be passed to array_multisort() as the parameter $rest expects a reference. ( Ignorable by Annotation )

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

916
					array_multisort($favorite, SORT_DESC, $label, /** @scrutinizer ignore-type */ SORT_ASC, $countryArray);
Loading history...
917
				} else {
918
					$countryArray = dol_sort_array($countryArray, 'label');
919
				}
920
921
				if ($showempty) {
922
					$out .= '<option value="">&nbsp;</option>'."\n";
923
				}
924
925
				if ($addspecialentries) {	// Add dedicated entries for groups of countries
926
					//if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
927
					$out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
928
					$out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
929
					if ($mysoc->isInEEC()) {
930
						$out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
931
					}
932
					$out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
933
					$out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
934
				}
935
936
				foreach ($countryArray as $row) {
937
					//if (empty($showempty) && empty($row['rowid'])) continue;
938
					if (empty($row['rowid'])) {
939
						continue;
940
					}
941
					if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
942
						continue; // exclude some countries
943
					}
944
945
					if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
946
						$atleastonefavorite++;
947
					}
948
					if (empty($row['favorite']) && $atleastonefavorite) {
949
						$atleastonefavorite = 0;
950
						$out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
951
					}
952
953
					$labeltoshow = '';
954
					if ($row['label']) {
955
						$labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
956
					} else {
957
						$labeltoshow .= '&nbsp;';
958
					}
959
					if ($row['code_iso']) {
960
						$labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>';
961
						if (empty($hideflags)) {
962
							$tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
963
							$labeltoshow = $tmpflag.' '.$labeltoshow;
964
						}
965
					}
966
967
					if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
968
						$out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" selected data-html="'.dol_escape_htmltag($labeltoshow).'" data-eec="'.((int) $row['eec']).'">';
969
					} else {
970
						$out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" data-html="'.dol_escape_htmltag($labeltoshow).'" data-eec="'.((int) $row['eec']).'">';
971
					}
972
					$out .= $labeltoshow;
973
					$out .= '</option>'."\n";
974
				}
975
			}
976
			$out .= '</select>';
977
		} else {
978
			dol_print_error($this->db);
979
		}
980
981
		// Make select dynamic
982
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
983
		$out .= ajax_combobox('select'.$htmlname, array(), 0, 0, 'resolve');
984
985
		return $out;
986
	}
987
988
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
989
	/**
990
	 *  Return select list of incoterms
991
	 *
992
	 *  @param	string	$selected       		Id or Code of preselected incoterm
993
	 *  @param	string	$location_incoterms     Value of input location
994
	 *  @param	string	$page       			Defined the form action
995
	 *  @param  string	$htmlname       		Name of html select object
996
	 *  @param  string	$htmloption     		Options html on select object
997
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
998
	 *  @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')))
999
	 *  @return string           				HTML string with select and input
1000
	 */
1001
	public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array())
1002
	{
1003
		// phpcs:enable
1004
		global $conf, $langs;
1005
1006
		$langs->load("dict");
1007
1008
		$out = '';
1009
		$moreattrib = '';
1010
		$incotermArray = array();
1011
1012
		$sql = "SELECT rowid, code";
1013
		$sql .= " FROM ".$this->db->prefix()."c_incoterms";
1014
		$sql .= " WHERE active > 0";
1015
		$sql .= " ORDER BY code ASC";
1016
1017
		dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
1018
		$resql = $this->db->query($sql);
1019
		if ($resql) {
1020
			if ($conf->use_javascript_ajax && !$forcecombo) {
1021
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1022
				$out .= ajax_combobox($htmlname, $events);
1023
			}
1024
1025
			if (!empty($page)) {
1026
				$out .= '<form method="post" action="'.$page.'">';
1027
				$out .= '<input type="hidden" name="action" value="set_incoterms">';
1028
				$out .= '<input type="hidden" name="token" value="'.newToken().'">';
1029
			}
1030
1031
			$out .= '<select id="'.$htmlname.'" class="flat selectincoterm width75" name="'.$htmlname.'" '.$htmloption.'>';
1032
			$out .= '<option value="0">&nbsp;</option>';
1033
			$num = $this->db->num_rows($resql);
1034
			$i = 0;
1035
			if ($num) {
1036
				$foundselected = false;
1037
1038
				while ($i < $num) {
1039
					$obj = $this->db->fetch_object($resql);
1040
					$incotermArray[$i]['rowid'] = $obj->rowid;
1041
					$incotermArray[$i]['code'] = $obj->code;
1042
					$i++;
1043
				}
1044
1045
				foreach ($incotermArray as $row) {
1046
					if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1047
						$out .= '<option value="'.$row['rowid'].'" selected>';
1048
					} else {
1049
						$out .= '<option value="'.$row['rowid'].'">';
1050
					}
1051
1052
					if ($row['code']) {
1053
						$out .= $row['code'];
1054
					}
1055
1056
					$out .= '</option>';
1057
				}
1058
			}
1059
			$out .= '</select>';
1060
1061
			if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $disableautocomplete seems to never exist and therefore empty should always be true.
Loading history...
1062
				$out .= ajax_multiautocompleter('location_incoterms', '', DOL_URL_ROOT.'/core/ajax/locationincoterms.php')."\n";
1063
				$moreattrib .= ' autocomplete="off"';
1064
			}
1065
			$out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="'.$location_incoterms.'">'."\n";
1066
1067
			if (!empty($page)) {
1068
				$out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="'.$langs->trans("Modify").'"></form>';
1069
			}
1070
		} else {
1071
			dol_print_error($this->db);
1072
		}
1073
1074
		return $out;
1075
	}
1076
1077
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1078
	/**
1079
	 *	Return list of types of lines (product or service)
1080
	 * 	Example: 0=product, 1=service, 9=other (for external module)
1081
	 *
1082
	 *	@param  string	$selected       Preselected type
1083
	 *	@param  string	$htmlname       Name of field in html form
1084
	 * 	@param	int		$showempty		Add an empty field
1085
	 * 	@param	int		$hidetext		Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
1086
	 * 	@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')
1087
	 *  @return	void
1088
	 */
1089
	public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1090
	{
1091
		// phpcs:enable
1092
		global $langs, $conf;
1093
1094
		// If product & services are enabled or both disabled.
1095
		if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
1096
			|| (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled))) {
1097
			if (empty($hidetext)) {
1098
				print $langs->trans("Type").': ';
1099
			}
1100
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
1101
			if ($showempty) {
1102
				print '<option value="-1"';
1103
				if ($selected == -1) {
1104
					print ' selected';
1105
				}
1106
				print '>&nbsp;</option>';
1107
			}
1108
1109
			print '<option value="0"';
1110
			if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1111
				print ' selected';
1112
			}
1113
			print '>'.$langs->trans("Product");
1114
1115
			print '<option value="1"';
1116
			if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1117
				print ' selected';
1118
			}
1119
			print '>'.$langs->trans("Service");
1120
1121
			print '</select>';
1122
			print ajax_combobox('select_'.$htmlname);
1123
			//if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1124
		}
1125
		if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3) {
1126
			print $langs->trans("Service");
1127
			print '<input type="hidden" name="'.$htmlname.'" value="1">';
1128
		}
1129
		if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2) {
1130
			print $langs->trans("Product");
1131
			print '<input type="hidden" name="'.$htmlname.'" value="0">';
1132
		}
1133
		if ($forceall < 0) {	// This should happened only for contracts when both predefined product and service are disabled.
1134
			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
1135
		}
1136
	}
1137
1138
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1139
	/**
1140
	 *	Load into cache cache_types_fees, array of types of fees
1141
	 *
1142
	 *	@return     int             Nb of lines loaded, <0 if KO
1143
	 */
1144
	public function load_cache_types_fees()
1145
	{
1146
		// phpcs:enable
1147
		global $langs;
1148
1149
		$num = count($this->cache_types_fees);
1150
		if ($num > 0) {
1151
			return 0; // Cache already loaded
1152
		}
1153
1154
		dol_syslog(__METHOD__, LOG_DEBUG);
1155
1156
		$langs->load("trips");
1157
1158
		$sql = "SELECT c.code, c.label";
1159
		$sql .= " FROM ".$this->db->prefix()."c_type_fees as c";
1160
		$sql .= " WHERE active > 0";
1161
1162
		$resql = $this->db->query($sql);
1163
		if ($resql) {
1164
			$num = $this->db->num_rows($resql);
1165
			$i = 0;
1166
1167
			while ($i < $num) {
1168
				$obj = $this->db->fetch_object($resql);
1169
1170
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1171
				$label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1172
				$this->cache_types_fees[$obj->code] = $label;
1173
				$i++;
1174
			}
1175
1176
			asort($this->cache_types_fees);
1177
1178
			return $num;
1179
		} else {
1180
			dol_print_error($this->db);
1181
			return -1;
1182
		}
1183
	}
1184
1185
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1186
	/**
1187
	 *	Return list of types of notes
1188
	 *
1189
	 *	@param	string		$selected		Preselected type
1190
	 *	@param  string		$htmlname		Name of field in form
1191
	 * 	@param	int			$showempty		Add an empty field
1192
	 * 	@return	void
1193
	 */
1194
	public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1195
	{
1196
		// phpcs:enable
1197
		global $user, $langs;
1198
1199
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1200
1201
		$this->load_cache_types_fees();
1202
1203
		print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1204
		if ($showempty) {
1205
			print '<option value="-1"';
1206
			if ($selected == -1) {
1207
				print ' selected';
1208
			}
1209
			print '>&nbsp;</option>';
1210
		}
1211
1212
		foreach ($this->cache_types_fees as $key => $value) {
1213
			print '<option value="'.$key.'"';
1214
			if ($key == $selected) {
1215
				print ' selected';
1216
			}
1217
			print '>';
1218
			print $value;
1219
			print '</option>';
1220
		}
1221
1222
		print '</select>';
1223
		if ($user->admin) {
1224
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1225
		}
1226
	}
1227
1228
1229
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1230
	/**
1231
	 *  Output html form to select a third party
1232
	 *
1233
	 *	@param	string	$selected       		Preselected type
1234
	 *	@param  string	$htmlname       		Name of field in form
1235
	 *  @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)')
1236
	 *	@param	string	$showempty				Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty')
1237
	 * 	@param	int		$showtype				Show third party type in combolist (customer, prospect or supplier)
1238
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1239
	 *  @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')))
1240
	 *	@param	int		$limit					Maximum number of elements
1241
	 *  @param	string	$morecss				Add more css styles to the SELECT component
1242
	 *	@param  string	$moreparam      		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1243
	 *	@param	string	$selected_input_value	Value of preselected input text (for use with ajax)
1244
	 *  @param	int		$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1245
	 *  @param	array	$ajaxoptions			Options for ajax_autocompleter
1246
	 * 	@param  bool	$multiple				add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
1247
	 *  @param	array	$excludeids				Exclude IDs from the select combo
1248
	 * 	@return	string							HTML string with select box for thirdparty.
1249
	 */
1250
	public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array())
1251
	{
1252
		// phpcs:enable
1253
		global $conf, $user, $langs;
1254
1255
		$out = '';
1256
1257
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1258
			if (is_null($ajaxoptions)) {
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
1259
				$ajaxoptions = array();
1260
			}
1261
1262
			require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1263
1264
			// No immediate load of all database
1265
			$placeholder = '';
1266
			if ($selected && empty($selected_input_value)) {
1267
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1268
				$societetmp = new Societe($this->db);
1269
				$societetmp->fetch($selected);
1270
				$selected_input_value = $societetmp->name;
1271
				unset($societetmp);
1272
			}
1273
1274
			// mode 1
1275
			$urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).(empty($excludeids) ? '' : '&excludeids='.join(',', $excludeids)).($showtype ? '&showtype='.urlencode($showtype) : '');
1276
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1277
1278
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
1279
			if (empty($hidelabel)) {
1280
				print $langs->trans("RefOrLabel").' : ';
1281
			} elseif ($hidelabel > 1) {
1282
				$placeholder = $langs->trans("RefOrLabel");
1283
				if ($hidelabel == 2) {
1284
					$out .= img_picto($langs->trans("Search"), 'search');
1285
				}
1286
			}
1287
			$out .= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '').' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1288
			if ($hidelabel == 3) {
1289
				$out .= img_picto($langs->trans("Search"), 'search');
1290
			}
1291
		} else {
1292
			// Immediate load of all database
1293
			$out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids);
1294
		}
1295
1296
		return $out;
1297
	}
1298
1299
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1300
	/**
1301
	 *  Output html form to select a third party.
1302
	 *  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.
1303
	 *
1304
	 *	@param	string	$selected       Preselected type
1305
	 *	@param  string	$htmlname       Name of field in form
1306
	 *  @param  string	$filter         Optional filters criteras (example: 's.rowid NOT IN (x)', 's.client IN (1,3)'). Do not use a filter coming from input of users.
1307
	 *	@param	string	$showempty		Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty')
1308
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
1309
	 * 	@param	int		$forcecombo		Force to use standard HTML select component without beautification
1310
	 *  @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')))
1311
	 *  @param	string	$filterkey		Filter on key value
1312
	 *  @param	int		$outputmode		0=HTML select string, 1=Array
1313
	 *  @param	int		$limit			Limit number of answers
1314
	 *  @param	string	$morecss		Add more css styles to the SELECT component
1315
	 *	@param  string	$moreparam      Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1316
	 *	@param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1317
	 *  @param	array	$excludeids		Exclude IDs from the select combo
1318
	 * 	@return	string					HTML string with
1319
	 */
1320
	public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array())
1321
	{
1322
		// phpcs:enable
1323
		global $conf, $user, $langs;
1324
		global $hookmanager;
1325
1326
		$out = '';
1327
		$num = 0;
1328
		$outarray = array();
1329
1330
		if ($selected === '') {
1331
			$selected = array();
1332
		} elseif (!is_array($selected)) {
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
1333
			$selected = array($selected);
1334
		}
1335
1336
		// Clean $filter that may contains sql conditions so sql code
1337
		if (function_exists('testSqlAndScriptInject')) {
1338
			if (testSqlAndScriptInject($filter, 3) > 0) {
1339
				$filter = '';
1340
			}
1341
		}
1342
1343
		// We search companies
1344
		$sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1345
		if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1346
			$sql .= ", s.address, s.zip, s.town";
1347
			$sql .= ", dictp.code as country_code";
1348
		}
1349
		$sql .= " FROM ".$this->db->prefix()."societe as s";
1350
		if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1351
			$sql .= " LEFT JOIN ".$this->db->prefix()."c_country as dictp ON dictp.rowid = s.fk_pays";
1352
		}
1353
		if (empty($user->rights->societe->client->voir) && !$user->socid) {
1354
			$sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
1355
		}
1356
		$sql .= " WHERE s.entity IN (".getEntity('societe').")";
1357
		if (!empty($user->socid)) {
1358
			$sql .= " AND s.rowid = ".((int) $user->socid);
1359
		}
1360
		if ($filter) {
1361
			$sql .= " AND (".$filter.")";
1362
		}
1363
		if (empty($user->rights->societe->client->voir) && !$user->socid) {
1364
			$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
1365
		}
1366
		if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1367
			$sql .= " AND s.status <> 0";
1368
		}
1369
		if (!empty($excludeids)) {
1370
			$sql .= " AND s.rowid NOT IN (".$this->db->sanitize(join(',', $excludeids)).")";
1371
		}
1372
		// Add where from hooks
1373
		$parameters = array();
1374
		$reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1375
		$sql .= $hookmanager->resPrint;
1376
		// Add criteria
1377
		if ($filterkey && $filterkey != '') {
1378
			$sql .= " AND (";
1379
			$prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1380
			// For natural search
1381
			$scrit = explode(' ', $filterkey);
1382
			$i = 0;
1383
			if (count($scrit) > 1) {
1384
				$sql .= "(";
1385
			}
1386
			foreach ($scrit as $crit) {
1387
				if ($i > 0) {
1388
					$sql .= " AND ";
1389
				}
1390
				$sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1391
				$i++;
1392
			}
1393
			if (count($scrit) > 1) {
1394
				$sql .= ")";
1395
			}
1396
			if (!empty($conf->barcode->enabled)) {
1397
				$sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1398
			}
1399
			$sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1400
			$sql .= " OR s.name_alias LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.tva_intra LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1401
			$sql .= ")";
1402
		}
1403
		$sql .= $this->db->order("nom", "ASC");
1404
		$sql .= $this->db->plimit($limit, 0);
1405
1406
		// Build output string
1407
		dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1408
		$resql = $this->db->query($sql);
1409
		if ($resql) {
1410
			if (!$forcecombo) {
1411
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1412
				$out .= ajax_combobox($htmlname, $events, getDolGlobalString("COMPANY_USE_SEARCH_TO_SELECT"));
1413
			}
1414
1415
			// Construct $out and $outarray
1416
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1417
1418
			$textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1419
			if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1420
				// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1421
				//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1422
				if ($showempty && !is_numeric($showempty)) {
1423
					$textifempty = $langs->trans($showempty);
1424
				} else {
1425
					$textifempty .= $langs->trans("All");
1426
				}
1427
			}
1428
			if ($showempty) {
1429
				$out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.($textifempty ? $textifempty : '&nbsp;').'</span>').'">'.$textifempty.'</option>'."\n";
1430
			}
1431
1432
			$num = $this->db->num_rows($resql);
1433
			$i = 0;
1434
			if ($num) {
1435
				while ($i < $num) {
1436
					$obj = $this->db->fetch_object($resql);
1437
					$label = '';
1438
					if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1439
						if (($obj->client) && (!empty($obj->code_client))) {
1440
							$label = $obj->code_client.' - ';
1441
						}
1442
						if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1443
							$label .= $obj->code_fournisseur.' - ';
1444
						}
1445
						$label .= ' '.$obj->name;
1446
					} else {
1447
						$label = $obj->name;
1448
					}
1449
1450
					if (!empty($obj->name_alias)) {
1451
						$label .= ' ('.$obj->name_alias.')';
1452
					}
1453
1454
					if (!empty($conf->global->SOCIETE_SHOW_VAT_IN_LIST) && !empty($obj->tva_intra)) {
1455
						$label .= ' - '.$obj->tva_intra.'';
1456
					}
1457
1458
					if ($showtype) {
1459
						if ($obj->client || $obj->fournisseur) {
1460
							$label .= ' (';
1461
						}
1462
						if ($obj->client == 1 || $obj->client == 3) {
1463
							$label .= $langs->trans("Customer");
1464
						}
1465
						if ($obj->client == 2 || $obj->client == 3) {
1466
							$label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1467
						}
1468
						if ($obj->fournisseur) {
1469
							$label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1470
						}
1471
						if ($obj->client || $obj->fournisseur) {
1472
							$label .= ')';
1473
						}
1474
					}
1475
1476
					if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1477
						$label .= ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : '');
1478
						if (!empty($obj->country_code)) {
1479
							$label .= ', '.$langs->trans('Country'.$obj->country_code);
1480
						}
1481
					}
1482
1483
					if (empty($outputmode)) {
1484
						if (in_array($obj->rowid, $selected)) {
1485
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1486
						} else {
1487
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1488
						}
1489
					} else {
1490
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1491
					}
1492
1493
					$i++;
1494
					if (($i % 10) == 0) {
1495
						$out .= "\n";
1496
					}
1497
				}
1498
			}
1499
			$out .= '</select>'."\n";
1500
		} else {
1501
			dol_print_error($this->db);
1502
		}
1503
1504
		$this->result = array('nbofthirdparties'=>$num);
1505
1506
		if ($outputmode) {
1507
			return $outarray;
1508
		}
1509
		return $out;
1510
	}
1511
1512
1513
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1514
	/**
1515
	 *  Return HTML combo list of absolute discounts
1516
	 *
1517
	 *  @param	string	$selected       Id remise fixe pre-selectionnee
1518
	 *  @param  string	$htmlname       Nom champ formulaire
1519
	 *  @param  string	$filter         Criteres optionnels de filtre
1520
	 *  @param	int		$socid			Id of thirdparty
1521
	 *  @param	int		$maxvalue		Max value for lines that can be selected
1522
	 *  @return	int						Return number of qualifed lines in list
1523
	 */
1524
	public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1525
	{
1526
		// phpcs:enable
1527
		global $langs, $conf;
1528
1529
		// On recherche les remises
1530
		$sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1531
		$sql .= " re.description, re.fk_facture_source";
1532
		$sql .= " FROM ".$this->db->prefix()."societe_remise_except as re";
1533
		$sql .= " WHERE re.fk_soc = ".(int) $socid;
1534
		$sql .= " AND re.entity = ".$conf->entity;
1535
		if ($filter) {
1536
			$sql .= " AND ".$filter;
1537
		}
1538
		$sql .= " ORDER BY re.description ASC";
1539
1540
		dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1541
		$resql = $this->db->query($sql);
1542
		if ($resql) {
1543
			print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1544
			$num = $this->db->num_rows($resql);
1545
1546
			$qualifiedlines = $num;
1547
1548
			$i = 0;
1549
			if ($num) {
1550
				print '<option value="0">&nbsp;</option>';
1551
				while ($i < $num) {
1552
					$obj = $this->db->fetch_object($resql);
1553
					$desc = dol_trunc($obj->description, 40);
1554
					if (preg_match('/\(CREDIT_NOTE\)/', $desc)) {
1555
						$desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1556
					}
1557
					if (preg_match('/\(DEPOSIT\)/', $desc)) {
1558
						$desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1559
					}
1560
					if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) {
1561
						$desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1562
					}
1563
					if (preg_match('/\(EXCESS PAID\)/', $desc)) {
1564
						$desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1565
					}
1566
1567
					$selectstring = '';
1568
					if ($selected > 0 && $selected == $obj->rowid) {
1569
						$selectstring = ' selected';
1570
					}
1571
1572
					$disabled = '';
1573
					if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1574
						$qualifiedlines--;
1575
						$disabled = ' disabled';
1576
					}
1577
1578
					if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1579
						$tmpfac = new Facture($this->db);
1580
						if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1581
							$desc = $desc.' - '.$tmpfac->ref;
1582
						}
1583
					}
1584
1585
					print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1586
					$i++;
1587
				}
1588
			}
1589
			print '</select>';
1590
			return $qualifiedlines;
1591
		} else {
1592
			dol_print_error($this->db);
1593
			return -1;
1594
		}
1595
	}
1596
1597
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1598
	/**
1599
	 *  Return list of all contacts (for a third party or all)
1600
	 *
1601
	 *  @param	int		$socid      	Id ot third party or 0 for all
1602
	 *  @param  string	$selected   	Id contact pre-selectionne
1603
	 *  @param  string	$htmlname  	    Name of HTML field ('none' for a not editable field)
1604
	 *  @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
1605
	 *  @param  string	$exclude        List of contacts id to exclude
1606
	 *  @param	string	$limitto		Disable answers that are not id in this array list
1607
	 *  @param	integer	$showfunction   Add function into label
1608
	 *  @param	string	$morecss		Add more class to class style
1609
	 *  @param	integer	$showsoc	    Add company into label
1610
	 *  @param	int		$forcecombo		Force to use combo box
1611
	 *  @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')))
1612
	 *  @param	bool	$options_only	Return options only (for ajax treatment)
1613
	 *  @param	string	$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1614
	 *  @param	string	$htmlid			Html id to use instead of htmlname
1615
	 *  @return	int						<0 if KO, Nb of contact in list if OK
1616
	 *  @deprecated						You can use selectcontacts directly (warning order of param was changed)
1617
	 */
1618
	public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1619
	{
1620
		// phpcs:enable
1621
		print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1622
		return $this->num;
1623
	}
1624
1625
	/**
1626
	 *	Return HTML code of the SELECT of list of all contacts (for a third party or all).
1627
	 *  This also set the number of contacts found into $this->num
1628
	 *
1629
	 * @since 9.0 Add afterSelectContactOptions hook
1630
	 *
1631
	 *	@param	int			$socid      	Id ot third party or 0 for all or -1 for empty list
1632
	 *	@param  array|int	$selected   	Array of ID of pre-selected contact id
1633
	 *	@param  string		$htmlname  	    Name of HTML field ('none' for a not editable field)
1634
	 *	@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
1635
	 *	@param  string		$exclude        List of contacts id to exclude
1636
	 *	@param	string		$limitto		Disable answers that are not id in this array list
1637
	 *	@param	integer		$showfunction   Add function into label
1638
	 *	@param	string		$morecss		Add more class to class style
1639
	 *	@param	bool		$options_only	Return options only (for ajax treatment)
1640
	 *	@param	integer		$showsoc	    Add company into label
1641
	 * 	@param	int			$forcecombo		Force to use combo box (so no ajax beautify effect)
1642
	 *  @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')))
1643
	 *  @param	string		$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1644
	 *  @param	string		$htmlid			Html id to use instead of htmlname
1645
	 *  @param	bool		$multiple		add [] in the name of element and add 'multiple' attribut
1646
	 *  @param	integer		$disableifempty Set tag 'disabled' on select if there is no choice
1647
	 *	@return	 int|string					<0 if KO, HTML with select string if OK.
1648
	 */
1649
	public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1650
	{
1651
		global $conf, $langs, $hookmanager, $action;
1652
1653
		$langs->load('companies');
1654
1655
		if (empty($htmlid)) {
1656
			$htmlid = $htmlname;
1657
		}
1658
		$num = 0;
1659
1660
		if ($selected === '') {
1661
			$selected = array();
1662
		} elseif (!is_array($selected)) {
1663
			$selected = array($selected);
1664
		}
1665
		$out = '';
1666
1667
		if (!is_object($hookmanager)) {
1668
			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1669
			$hookmanager = new HookManager($this->db);
1670
		}
1671
1672
		// We search third parties
1673
		$sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town";
1674
		if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1675
			$sql .= ", s.nom as company, s.town AS company_town";
1676
		}
1677
		$sql .= " FROM ".$this->db->prefix()."socpeople as sp";
1678
		if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1679
			$sql .= " LEFT OUTER JOIN  ".$this->db->prefix()."societe as s ON s.rowid=sp.fk_soc";
1680
		}
1681
		$sql .= " WHERE sp.entity IN (".getEntity('contact').")";
1682
		if ($socid > 0 || $socid == -1) {
1683
			$sql .= " AND sp.fk_soc = ".((int) $socid);
1684
		}
1685
		if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1686
			$sql .= " AND sp.statut <> 0";
1687
		}
1688
		// Add where from hooks
1689
		$parameters = array();
1690
		$reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1691
		$sql .= $hookmanager->resPrint;
1692
		$sql .= " ORDER BY sp.lastname ASC";
1693
1694
		dol_syslog(get_class($this)."::selectcontacts", LOG_DEBUG);
1695
		$resql = $this->db->query($sql);
1696
		if ($resql) {
1697
			$num = $this->db->num_rows($resql);
1698
1699
			if ($htmlname != 'none' && !$options_only) {
1700
				$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1701
			}
1702
1703
			if ($showempty && ! is_numeric($showempty)) {
1704
				$textforempty = $showempty;
1705
				$out .= '<option class="optiongrey" value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>'.$textforempty.'</option>';
1706
			} else {
1707
				if (($showempty == 1 || ($showempty == 3 && $num > 1)) && ! $multiple) {
1708
					$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1709
				}
1710
				if ($showempty == 2) {
1711
					$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1712
				}
1713
			}
1714
1715
			$i = 0;
1716
			if ($num) {
1717
				include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1718
				$contactstatic = new Contact($this->db);
1719
1720
				while ($i < $num) {
1721
					$obj = $this->db->fetch_object($resql);
1722
1723
					// Set email (or phones) and town extended infos
1724
					$extendedInfos = '';
1725
					if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1726
						$extendedInfos = array();
1727
						$email = trim($obj->email);
1728
						if (!empty($email)) {
1729
							$extendedInfos[] = $email;
1730
						} else {
1731
							$phone = trim($obj->phone);
1732
							$phone_perso = trim($obj->phone_perso);
1733
							$phone_mobile = trim($obj->phone_mobile);
1734
							if (!empty($phone)) {
1735
								$extendedInfos[] = $phone;
1736
							}
1737
							if (!empty($phone_perso)) {
1738
								$extendedInfos[] = $phone_perso;
1739
							}
1740
							if (!empty($phone_mobile)) {
1741
								$extendedInfos[] = $phone_mobile;
1742
							}
1743
						}
1744
						$contact_town = trim($obj->contact_town);
1745
						$company_town = trim($obj->company_town);
1746
						if (!empty($contact_town)) {
1747
							$extendedInfos[] = $contact_town;
1748
						} elseif (!empty($company_town)) {
1749
							$extendedInfos[] = $company_town;
1750
						}
1751
						$extendedInfos = implode(' - ', $extendedInfos);
1752
						if (!empty($extendedInfos)) {
1753
							$extendedInfos = ' - '.$extendedInfos;
1754
						}
1755
					}
1756
1757
					$contactstatic->id = $obj->rowid;
1758
					$contactstatic->lastname = $obj->lastname;
1759
					$contactstatic->firstname = $obj->firstname;
1760
					if ($obj->statut == 1) {
1761
						if ($htmlname != 'none') {
1762
							$disabled = 0;
1763
							if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1764
								$disabled = 1;
1765
							}
1766
							if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1767
								$disabled = 1;
1768
							}
1769
							if (!empty($selected) && in_array($obj->rowid, $selected)) {
1770
								$out .= '<option value="'.$obj->rowid.'"';
1771
								if ($disabled) {
1772
									$out .= ' disabled';
1773
								}
1774
								$out .= ' selected>';
1775
								$out .= $contactstatic->getFullName($langs).$extendedInfos;
1776
								if ($showfunction && $obj->poste) {
1777
									$out .= ' ('.$obj->poste.')';
1778
								}
1779
								if (($showsoc > 0) && $obj->company) {
1780
									$out .= ' - ('.$obj->company.')';
1781
								}
1782
								$out .= '</option>';
1783
							} else {
1784
								$out .= '<option value="'.$obj->rowid.'"';
1785
								if ($disabled) {
1786
									$out .= ' disabled';
1787
								}
1788
								$out .= '>';
1789
								$out .= $contactstatic->getFullName($langs).$extendedInfos;
1790
								if ($showfunction && $obj->poste) {
1791
									$out .= ' ('.$obj->poste.')';
1792
								}
1793
								if (($showsoc > 0) && $obj->company) {
1794
									$out .= ' - ('.$obj->company.')';
1795
								}
1796
								$out .= '</option>';
1797
							}
1798
						} else {
1799
							if (in_array($obj->rowid, $selected)) {
1800
								$out .= $contactstatic->getFullName($langs).$extendedInfos;
1801
								if ($showfunction && $obj->poste) {
1802
									$out .= ' ('.$obj->poste.')';
1803
								}
1804
								if (($showsoc > 0) && $obj->company) {
1805
									$out .= ' - ('.$obj->company.')';
1806
								}
1807
							}
1808
						}
1809
					}
1810
					$i++;
1811
				}
1812
			} else {
1813
				$labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1814
				$out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">';
1815
				$out .= $labeltoshow;
1816
				$out .= '</option>';
1817
			}
1818
1819
			$parameters = array(
1820
				'socid'=>$socid,
1821
				'htmlname'=>$htmlname,
1822
				'resql'=>$resql,
1823
				'out'=>&$out,
1824
				'showfunction'=>$showfunction,
1825
				'showsoc'=>$showsoc,
1826
			);
1827
1828
			$reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1829
1830
			if ($htmlname != 'none' && !$options_only) {
1831
				$out .= '</select>';
1832
			}
1833
1834
			if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1835
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1836
				$out .= ajax_combobox($htmlid, $events, getDolGlobalString("CONTACT_USE_SEARCH_TO_SELECT"));
1837
			}
1838
1839
			$this->num = $num;
1840
			return $out;
1841
		} else {
1842
			dol_print_error($this->db);
1843
			return -1;
1844
		}
1845
	}
1846
1847
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1848
	/**
1849
	 *	Return the HTML select list of users
1850
	 *
1851
	 *  @param	string			$selected       Id user preselected
1852
	 *  @param  string			$htmlname       Field name in form
1853
	 *  @param  int				$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
1854
	 *  @param  array			$exclude        Array list of users id to exclude
1855
	 * 	@param	int				$disabled		If select list must be disabled
1856
	 *  @param  array|string	$include        Array list of users id to include. User '' for all users or 'hierarchy' to have only supervised users or 'hierarchyme' to have supervised + me
1857
	 * 	@param	int				$enableonly		Array list of users id to be enabled. All other must be disabled
1858
	 *  @param	string			$force_entity	'0' or Ids of environment to force
1859
	 * 	@return	void
1860
	 *  @deprecated		Use select_dolusers instead
1861
	 *  @see select_dolusers()
1862
	 */
1863
	public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1864
	{
1865
		// phpcs:enable
1866
		print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1867
	}
1868
1869
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1870
	/**
1871
	 *	Return select list of users
1872
	 *
1873
	 *  @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)
1874
	 *  @param  string			$htmlname       Field name in form
1875
	 *  @param  int|string		$show_empty     0=list with no empty value, 1=add also an empty value into list
1876
	 *  @param  array			$exclude        Array list of users id to exclude
1877
	 * 	@param	int				$disabled		If select list must be disabled
1878
	 *  @param  array|string	$include        Array list of users id to include. User '' for all users or 'hierarchy' to have only supervised users or 'hierarchyme' to have supervised + me
1879
	 * 	@param	array			$enableonly		Array list of users id to be enabled. If defined, it means that others will be disabled
1880
	 *  @param	string			$force_entity	'0' or Ids of environment to force
1881
	 *  @param	int				$maxlength		Maximum length of string into list (0=no limit)
1882
	 *  @param	int				$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1883
	 *  @param	string			$morefilter		Add more filters into sql request (Example: 'employee = 1'). This value must not come from user input.
1884
	 *  @param	integer			$show_every		0=default list, 1=add also a value "Everybody" at beginning of list
1885
	 *  @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.
1886
	 *  @param	string			$morecss		More css
1887
	 *  @param  int     		$noactive       Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
1888
	 *  @param  int				$outputmode     0=HTML select string, 1=Array
1889
	 *  @param  bool			$multiple       add [] in the name of element and add 'multiple' attribut
1890
	 * 	@return	string							HTML select string
1891
	 *  @see select_dolgroups()
1892
	 */
1893
	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)
1894
	{
1895
		// phpcs:enable
1896
		global $conf, $user, $langs, $hookmanager;
1897
1898
		// If no preselected user defined, we take current user
1899
		if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
1900
			$selected = $user->id;
1901
		}
1902
1903
		if ($selected === '') {
1904
			$selected = array();
1905
		} elseif (!is_array($selected)) {
1906
			$selected = array($selected);
1907
		}
1908
1909
		$excludeUsers = null;
1910
		$includeUsers = null;
1911
1912
		// Permettre l'exclusion d'utilisateurs
1913
		if (is_array($exclude)) {
1914
			$excludeUsers = implode(",", $exclude);
1915
		}
1916
		// Permettre l'inclusion d'utilisateurs
1917
		if (is_array($include)) {
1918
			$includeUsers = implode(",", $include);
1919
		} elseif ($include == 'hierarchy') {
1920
			// Build list includeUsers to have only hierarchy
1921
			$includeUsers = implode(",", $user->getAllChildIds(0));
1922
		} elseif ($include == 'hierarchyme') {
1923
			// Build list includeUsers to have only hierarchy and current user
1924
			$includeUsers = implode(",", $user->getAllChildIds(1));
1925
		}
1926
1927
		$out = '';
1928
		$outarray = array();
1929
1930
		// Forge request to select users
1931
		$sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
1932
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
1933
			$sql .= ", e.label";
1934
		}
1935
		$sql .= " FROM ".$this->db->prefix()."user as u";
1936
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
1937
			$sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid = u.entity";
1938
			if ($force_entity) {
1939
				$sql .= " WHERE u.entity IN (0, ".$this->db->sanitize($force_entity).")";
1940
			} else {
1941
				$sql .= " WHERE u.entity IS NOT NULL";
1942
			}
1943
		} else {
1944
			if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1945
				$sql .= " LEFT JOIN ".$this->db->prefix()."usergroup_user as ug";
1946
				$sql .= " ON ug.fk_user = u.rowid";
1947
				$sql .= " WHERE ug.entity = ".$conf->entity;
1948
			} else {
1949
				$sql .= " WHERE u.entity IN (0, ".$conf->entity.")";
1950
			}
1951
		}
1952
		if (!empty($user->socid)) {
1953
			$sql .= " AND u.fk_soc = ".((int) $user->socid);
1954
		}
1955
		if (is_array($exclude) && $excludeUsers) {
1956
			$sql .= " AND u.rowid NOT IN (".$this->db->sanitize($excludeUsers).")";
1957
		}
1958
		if ($includeUsers) {
1959
			$sql .= " AND u.rowid IN (".$this->db->sanitize($includeUsers).")";
1960
		}
1961
		if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) {
1962
			$sql .= " AND u.statut <> 0";
1963
		}
1964
		if (!empty($morefilter)) {
1965
			$sql .= " ".$morefilter;
1966
		}
1967
1968
		//Add hook to filter on user (for exemple on usergroup define in custom modules)
1969
		$reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $action seems to be never defined.
Loading history...
1970
		if (!empty($reshook)) {
1971
			$sql .= $hookmanager->resPrint;
1972
		}
1973
1974
		if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {	// MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1975
			$sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
1976
		} else {
1977
			$sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
1978
		}
1979
1980
		dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1981
1982
		$resql = $this->db->query($sql);
1983
		if ($resql) {
1984
			$num = $this->db->num_rows($resql);
1985
			$i = 0;
1986
			if ($num) {
1987
				// do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1988
				$out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
1989
				if ($show_empty && !$multiple) {
1990
					$textforempty = ' ';
1991
					if (!empty($conf->use_javascript_ajax)) {
1992
						$textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
1993
					}
1994
					if (!is_numeric($show_empty)) {
1995
						$textforempty = $show_empty;
1996
					}
1997
					$out .= '<option class="optiongrey" value="'.($show_empty < 0 ? $show_empty : -1).'"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
1998
				}
1999
				if ($show_every) {
2000
					$out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
2001
				}
2002
2003
				$userstatic = new User($this->db);
2004
2005
				while ($i < $num) {
2006
					$obj = $this->db->fetch_object($resql);
2007
2008
					$userstatic->id = $obj->rowid;
2009
					$userstatic->lastname = $obj->lastname;
2010
					$userstatic->firstname = $obj->firstname;
2011
					$userstatic->photo = $obj->photo;
2012
					$userstatic->statut = $obj->status;
2013
					$userstatic->entity = $obj->entity;
2014
					$userstatic->admin = $obj->admin;
2015
2016
					$disableline = '';
2017
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2018
						$disableline = ($enableonlytext ? $enableonlytext : '1');
2019
					}
2020
2021
					$labeltoshow = '';
2022
2023
					// $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2024
					$fullNameMode = 0;
2025
					if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2026
						$fullNameMode = 1; //Firstname+lastname
2027
					}
2028
					$labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2029
					if (empty($obj->firstname) && empty($obj->lastname)) {
2030
						$labeltoshow .= $obj->login;
2031
					}
2032
2033
					// Complete name with more info
2034
					$moreinfo = '';
2035
					if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2036
						$moreinfo .= ($moreinfo ? ' - ' : ' (').$obj->login;
2037
					}
2038
					if ($showstatus >= 0) {
2039
						if ($obj->status == 1 && $showstatus == 1) {
2040
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
2041
						}
2042
						if ($obj->status == 0 && $showstatus == 1) {
2043
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
2044
						}
2045
					}
2046
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2047
						if (!$obj->entity) {
2048
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
2049
						} else {
2050
							if ($obj->entity != $conf->entity) {
2051
								$moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2052
							}
2053
						}
2054
					}
2055
					$moreinfo .= ($moreinfo ? ')' : '');
2056
					if ($disableline && $disableline != '1') {
2057
						$moreinfo .= ' - '.$disableline; // This is text from $enableonlytext parameter
2058
					}
2059
					$labeltoshow .= $moreinfo;
2060
2061
					$out .= '<option value="'.$obj->rowid.'"';
2062
					if ($disableline) {
2063
						$out .= ' disabled';
2064
					}
2065
					if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2066
						$out .= ' selected';
2067
					}
2068
					$out .= ' data-html="';
2069
					$outhtml = '';
2070
					// if (!empty($obj->photo)) {
2071
					$outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
2072
					// }
2073
					if ($showstatus >= 0 && $obj->status == 0) {
2074
						$outhtml .= '<strike class="opacitymediumxxx">';
2075
					}
2076
					$outhtml .= $labeltoshow;
2077
					if ($showstatus >= 0 && $obj->status == 0) {
2078
						$outhtml .= '</strike>';
2079
					}
2080
					$out .= dol_escape_htmltag($outhtml);
2081
					$out .= '">';
2082
					$out .= $labeltoshow;
2083
					$out .= '</option>';
2084
2085
					$outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
2086
2087
					$i++;
2088
				}
2089
			} else {
2090
				$out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
2091
				$out .= '<option value="">'.$langs->trans("None").'</option>';
2092
			}
2093
			$out .= '</select>';
2094
2095
			if ($num) {
2096
				// Enhance with select2
2097
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2098
				$out .= ajax_combobox($htmlname);
2099
			}
2100
		} else {
2101
			dol_print_error($this->db);
2102
		}
2103
2104
		if ($outputmode) {
2105
			return $outarray;
2106
		}
2107
2108
		return $out;
2109
	}
2110
2111
2112
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2113
	/**
2114
	 *	Return select list of users. Selected users are stored into session.
2115
	 *  List of users are provided into $_SESSION['assignedtouser'].
2116
	 *
2117
	 *  @param  string	$action         Value for $action
2118
	 *  @param  string	$htmlname       Field name in form
2119
	 *  @param  int		$show_empty     0=list without the empty value, 1=add empty value
2120
	 *  @param  array	$exclude        Array list of users id to exclude
2121
	 * 	@param	int		$disabled		If select list must be disabled
2122
	 *  @param  array	$include        Array list of users id to include or 'hierarchy' to have only supervised users
2123
	 * 	@param	array	$enableonly		Array list of users id to be enabled. All other must be disabled
2124
	 *  @param	int		$force_entity	'0' or Ids of environment to force
2125
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
2126
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
2127
	 *  @param	string	$morefilter		Add more filters into sql request
2128
	 *  @param	int		$showproperties		Show properties of each attendees
2129
	 *  @param	array	$listofuserid		Array with properties of each user
2130
	 *  @param	array	$listofcontactid	Array with properties of each contact
2131
	 *  @param	array	$listofotherid		Array with properties of each other contact
2132
	 * 	@return	string					HTML select string
2133
	 *  @see select_dolgroups()
2134
	 */
2135
	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())
2136
	{
2137
		// phpcs:enable
2138
		global $conf, $user, $langs;
2139
2140
		$userstatic = new User($this->db);
2141
		$out = '';
2142
2143
2144
		$assignedtouser = array();
2145
		if (!empty($_SESSION['assignedtouser'])) {
2146
			$assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2147
		}
2148
		$nbassignetouser = count($assignedtouser);
2149
2150
		//if ($nbassignetouser && $action != 'view') $out .= '<br>';
2151
		if ($nbassignetouser) {
2152
			$out .= '<ul class="attendees">';
2153
		}
2154
		$i = 0;
2155
		$ownerid = 0;
2156
		foreach ($assignedtouser as $key => $value) {
2157
			if ($value['id'] == $ownerid) {
2158
				continue;
2159
			}
2160
2161
			$out .= '<li>';
2162
			$userstatic->fetch($value['id']);
2163
			$out .= $userstatic->getNomUrl(-1);
2164
			if ($i == 0) {
2165
				$ownerid = $value['id'];
2166
				$out .= ' ('.$langs->trans("Owner").')';
2167
			}
2168
			if ($nbassignetouser > 1 && $action != 'view') {
2169
				$out .= ' <input type="image" style="border: 0px;" src="'.img_picto($langs->trans("Remove"), 'delete', '', 0, 1).'" value="'.$userstatic->id.'" class="removedassigned reposition" id="removedassigned_'.$userstatic->id.'" name="removedassigned_'.$userstatic->id.'">';
2170
			}
2171
			// Show my availability
2172
			if ($showproperties) {
2173
				if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2174
					$out .= '<div class="myavailability inline-block">';
2175
					$out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">'.$langs->trans("Availability").':</span>  </span><input id="transparency" class="paddingrightonly" '.($action == 'view' ? 'disabled' : '').' type="checkbox" name="transparency"'.($listofuserid[$ownerid]['transparency'] ? ' checked' : '').'><label for="transparency">'.$langs->trans("Busy").'</label>';
2176
					$out .= '</div>';
2177
				}
2178
			}
2179
			//$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2180
			//$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2181
2182
			$out .= '</li>';
2183
			$i++;
2184
		}
2185
		if ($nbassignetouser) {
2186
			$out .= '</ul>';
2187
		}
2188
2189
		// Method with no ajax
2190
		if ($action != 'view') {
2191
			$out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2192
			$out .= '<script type="text/javascript">jQuery(document).ready(function () {';
2193
			$out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2194
			$out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2195
			$out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }';
2196
			$out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }';
2197
			$out .= '});';
2198
			$out .= '})</script>';
2199
			$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2200
			$out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
2201
			$out .= '<br>';
2202
		}
2203
2204
		return $out;
2205
	}
2206
2207
2208
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2209
	/**
2210
	 *  Return list of products for customer in Ajax if Ajax activated or go to select_produits_list
2211
	 *
2212
	 *  @param		int			$selected				Preselected products
2213
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page).
2214
	 *  @param		int|string	$filtertype				Filter on product type (''=nofilter, 0=product, 1=service)
2215
	 *  @param		int			$limit					Limit on number of returned lines
2216
	 *  @param		int			$price_level			Level of price to show
2217
	 *  @param		int			$status					Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell
2218
	 *  @param		int			$finished				2=all, 1=finished, 0=raw material
2219
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
2220
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
2221
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
2222
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
2223
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2224
	 * 	@param		int			$forcecombo				Force to use combo box
2225
	 *  @param      string      $morecss                Add more css on select
2226
	 *  @param      int         $hidepriceinlabel       1=Hide prices in label
2227
	 *  @param      string      $warehouseStatus        Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used
2228
	 *										            'warehouseopen' = count products from open warehouses,
2229
	 *										            'warehouseclosed' = count products from closed warehouses,
2230
	 *										            'warehouseinternal' = count products from warehouses for internal correct/transfer only
2231
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
2232
	 *  @param		string		$nooutput				No print, return the output into a string
2233
	 *  @param		int			$status_purchase		Purchase status -1=Return all products, 0=Products not on purchase, 1=Products on purchase
2234
	 *  @return		void|string
2235
	 */
2236
	public function select_produits($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0, $status_purchase = -1)
2237
	{
2238
		// phpcs:enable
2239
		global $langs, $conf;
2240
2241
		$out = '';
2242
2243
		// check parameters
2244
		$price_level = (!empty($price_level) ? $price_level : 0);
2245
		if (is_null($ajaxoptions)) {
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
2246
			$ajaxoptions = array();
2247
		}
2248
2249
		if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
2250
			if (!empty($conf->product->enabled) && empty($conf->service->enabled)) {
2251
				$filtertype = '0';
2252
			} elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) {
2253
				$filtertype = '1';
2254
			}
2255
		}
2256
2257
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2258
			$placeholder = '';
2259
2260
			if ($selected && empty($selected_input_value)) {
2261
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2262
				$producttmpselect = new Product($this->db);
2263
				$producttmpselect->fetch($selected);
2264
				$selected_input_value = $producttmpselect->ref;
2265
				unset($producttmpselect);
2266
			}
2267
			// handle case where product or service module is disabled + no filter specified
2268
			if ($filtertype == '') {
2269
				if (empty($conf->product->enabled)) { // when product module is disabled, show services only
2270
					$filtertype = 1;
2271
				} elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2272
					$filtertype = 0;
2273
				}
2274
			}
2275
			// mode=1 means customers products
2276
			$urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&status_purchase='.$status_purchase.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
2277
			//Price by customer
2278
			if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2279
				$urloption .= '&socid='.$socid;
2280
			}
2281
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2282
2283
			if (!empty($conf->variants->enabled) && is_array($selected_combinations)) {
2284
				// Code to automatically insert with javascript the select of attributes under the select of product
2285
				// when a parent of variant has been selected.
2286
				$out .= '
2287
				<!-- script to auto show attributes select tags if a variant was selected -->
2288
				<script>
2289
					// auto show attributes fields
2290
					selected = '.json_encode($selected_combinations).';
2291
					combvalues = {};
2292
2293
					jQuery(document).ready(function () {
2294
2295
						jQuery("input[name=\'prod_entry_mode\']").change(function () {
2296
							if (jQuery(this).val() == \'free\') {
2297
								jQuery(\'div#attributes_box\').empty();
2298
							}
2299
						});
2300
2301
						jQuery("input#'.$htmlname.'").change(function () {
2302
2303
							if (!jQuery(this).val()) {
2304
								jQuery(\'div#attributes_box\').empty();
2305
								return;
2306
							}
2307
2308
							console.log("A change has started. We get variants fields to inject html select");
2309
2310
							jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
2311
								id: jQuery(this).val()
2312
							}, function (data) {
2313
								jQuery(\'div#attributes_box\').empty();
2314
2315
								jQuery.each(data, function (key, val) {
2316
2317
									combvalues[val.id] = val.values;
2318
2319
									var span = jQuery(document.createElement(\'div\')).css({
2320
										\'display\': \'table-row\'
2321
									});
2322
2323
									span.append(
2324
										jQuery(document.createElement(\'div\')).text(val.label).css({
2325
											\'font-weight\': \'bold\',
2326
											\'display\': \'table-cell\'
2327
										})
2328
									);
2329
2330
									var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2331
										\'margin-left\': \'15px\',
2332
										\'white-space\': \'pre\'
2333
									}).append(
2334
										jQuery(document.createElement(\'option\')).val(\'\')
2335
									);
2336
2337
									jQuery.each(combvalues[val.id], function (key, val) {
2338
										var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2339
2340
										if (selected[val.fk_product_attribute] == val.id) {
2341
											tag.attr(\'selected\', \'selected\');
2342
										}
2343
2344
										html.append(tag);
2345
									});
2346
2347
									span.append(html);
2348
									jQuery(\'div#attributes_box\').append(span);
2349
								});
2350
							})
2351
						});
2352
2353
						'.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2354
					});
2355
				</script>
2356
                ';
2357
			}
2358
2359
			if (empty($hidelabel)) {
2360
				$out .= $langs->trans("RefOrLabel").' : ';
2361
			} elseif ($hidelabel > 1) {
2362
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2363
				if ($hidelabel == 2) {
2364
					$out .= img_picto($langs->trans("Search"), 'search');
2365
				}
2366
			}
2367
			$out .= '<input type="text" class="minwidth100'.($morecss ? ' '.$morecss : '').'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
2368
			if ($hidelabel == 3) {
2369
				$out .= img_picto($langs->trans("Search"), 'search');
2370
			}
2371
		} else {
2372
			$out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2373
		}
2374
2375
		if (empty($nooutput)) {
2376
			print $out;
2377
		} else {
2378
			return $out;
2379
		}
2380
	}
2381
2382
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2383
2384
	/**
2385
	 *  Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list
2386
	 *
2387
	 * @param int $selected Preselected BOM id
2388
	 * @param string $htmlname Name of HTML select field (must be unique in page).
2389
	 * @param int $limit Limit on number of returned lines
2390
	 * @param int $status Sell status -1=Return all bom, 0=Draft BOM, 1=Validated BOM
2391
	 * @param int $type type of the BOM (-1=Return all BOM, 0=Return disassemble BOM, 1=Return manufacturing BOM)
2392
	 * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2393
	 * @param string $morecss Add more css on select
2394
	 * @param string $nooutput No print, return the output into a string
2395
	 * @param int $forcecombo Force to use combo box
2396
	 * @return        void|string
2397
	 */
2398
	public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 1, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0)
2399
	{
2400
		// phpcs:enable
2401
		global $conf, $user, $langs, $db;
2402
2403
		require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2404
2405
		$error = 0;
2406
		$out = '';
2407
2408
		if (!$forcecombo) {
2409
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2410
			$out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $events seems to be never defined.
Loading history...
2411
		}
2412
2413
		$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2414
2415
		$sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2416
		$sql.= ' FROM '.MAIN_DB_PREFIX.'bom_bom as b';
2417
		$sql.= ' WHERE b.entity IN ('.getEntity('bom').')';
2418
		if (!empty($status)) $sql.= ' AND status = '. (int) $status;
2419
		if (!empty($type)) $sql.= ' AND status = '. (int) $type;
2420
		if (!empty($limit)) $sql.= 'LIMIT '. (int) $limit;
2421
		$resql = $db->query($sql);
2422
		if ($resql) {
2423
			if ($showempty)	{
2424
				$out .= '<option value="-1"';
2425
				if (empty($selected)) $out .= ' selected';
2426
				$out .= '>&nbsp;</option>';
2427
			}
2428
			while ($obj = $db->fetch_object($resql)) {
2429
				$product = new Product($db);
2430
				$res = $product->fetch($obj->fk_product);
2431
				if ($obj->rowid == $selected) $out .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.' - '. $product->label .' - '.$obj->label.'</option>';
2432
				$out .= '<option value="'.$obj->rowid.'">'.$obj->ref.' - '.$product->label .' - '. $obj->label.'</option>';
2433
			}
2434
		} else {
2435
			$error++;
2436
			dol_print_error($db);
2437
		}
2438
		if (empty($nooutput)) {
2439
			print $out;
2440
		} else {
2441
			return $out;
2442
		}
2443
	}
2444
2445
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2446
	/**
2447
	 *	Return list of products for a customer.
2448
	 *  Called by select_produits.
2449
	 *
2450
	 *	@param      int		$selected           Preselected product
2451
	 *	@param      string	$htmlname           Name of select html
2452
	 *  @param		string	$filtertype         Filter on product type (''=nofilter, 0=product, 1=service)
2453
	 *	@param      int		$limit              Limit on number of returned lines
2454
	 *	@param      int		$price_level        Level of price to show
2455
	 * 	@param      string	$filterkey          Filter on product
2456
	 *	@param		int		$status             -1=Return all products, 0=Products not on sell, 1=Products on sell
2457
	 *  @param      int		$finished           Filter on finished field: 2=No filter
2458
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
2459
	 *  @param      int		$socid     		    Thirdparty Id (to get also price dedicated to this customer)
2460
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2461
	 * 	@param		int		$forcecombo		    Force to use combo box
2462
	 *  @param      string  $morecss            Add more css on select
2463
	 *  @param      int     $hidepriceinlabel   1=Hide prices in label
2464
	 *  @param      string  $warehouseStatus    Warehouse status filter to group/count stock. Following comma separated filter options can be used.
2465
	 *										    'warehouseopen' = count products from open warehouses,
2466
	 *										    'warehouseclosed' = count products from closed warehouses,
2467
	 *										    'warehouseinternal' = count products from warehouses for internal correct/transfer only
2468
	 *  @param		int		$status_purchase	Purchase status -1=Return all products, 0=Products not on purchase, 1=Products on purchase
2469
	 *  @return     array    				    Array of keys for json
2470
	 */
2471
	public function select_produits_list($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1)
2472
	{
2473
		// phpcs:enable
2474
		global $langs, $conf;
2475
		global $hookmanager;
2476
2477
		$out = '';
2478
		$outarray = array();
2479
2480
		// Units
2481
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2482
			$langs->load('other');
2483
		}
2484
2485
		$warehouseStatusArray = array();
2486
		if (!empty($warehouseStatus)) {
2487
			require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2488
			if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2489
				$warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2490
			}
2491
			if (preg_match('/warehouseopen/', $warehouseStatus)) {
2492
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2493
			}
2494
			if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2495
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2496
			}
2497
		}
2498
2499
		$selectFields = " p.rowid, p.ref, p.label, p.description, p.barcode, p.fk_country, p.fk_product_type, p.price, p.price_ttc, p.price_base_type, p.tva_tx, p.default_vat_code, p.duration, p.fk_price_expression";
2500
		if (count($warehouseStatusArray)) {
2501
			$selectFieldsGrouped = ", sum(".$this->db->ifsql("e.statut IS NULL", "0", "ps.reel").") as stock"; // e.statut is null if there is no record in stock
2502
		} else {
2503
			$selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2504
		}
2505
2506
		$sql = "SELECT ";
2507
		$sql .= $selectFields.$selectFieldsGrouped;
2508
2509
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2510
			//Product category
2511
			$sql .= ", (SELECT ".$this->db->prefix()."categorie_product.fk_categorie
2512
						FROM ".$this->db->prefix()."categorie_product
2513
						WHERE ".$this->db->prefix()."categorie_product.fk_product=p.rowid
2514
						LIMIT 1
2515
				) AS categorie_product_id ";
2516
		}
2517
2518
		//Price by customer
2519
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2520
			$sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2521
			$sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref';
2522
			$selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2523
		}
2524
		// Units
2525
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2526
			$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";
2527
			$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';
2528
		}
2529
2530
		// Multilang : we add translation
2531
		if (!empty($conf->global->MAIN_MULTILANGS)) {
2532
			$sql .= ", pl.label as label_translated";
2533
			$sql .= ", pl.description as description_translated";
2534
			$selectFields .= ", label_translated";
2535
			$selectFields .= ", description_translated";
2536
		}
2537
		// Price by quantity
2538
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2539
			$sql .= ", (SELECT pp.rowid FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid";
2540
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2541
				$sql .= " AND price_level = ".((int) $price_level);
2542
			}
2543
			$sql .= " ORDER BY date_price";
2544
			$sql .= " DESC LIMIT 1) as price_rowid";
2545
			$sql .= ", (SELECT pp.price_by_qty FROM ".$this->db->prefix()."product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable
2546
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2547
				$sql .= " AND price_level = ".((int) $price_level);
2548
			}
2549
			$sql .= " ORDER BY date_price";
2550
			$sql .= " DESC LIMIT 1) as price_by_qty";
2551
			$selectFields .= ", price_rowid, price_by_qty";
2552
		}
2553
		$sql .= " FROM ".$this->db->prefix()."product as p";
2554
		if (count($warehouseStatusArray)) {
2555
			$sql .= " LEFT JOIN ".$this->db->prefix()."product_stock as ps on ps.fk_product = p.rowid";
2556
			$sql .= " LEFT JOIN ".$this->db->prefix()."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2557
			$sql .= ' AND e.statut IN ('.$this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))).')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0.
2558
		}
2559
2560
		// include search in supplier ref
2561
		if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2562
			$sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2563
		}
2564
2565
		//Price by customer
2566
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2567
			$sql .= " LEFT JOIN  ".$this->db->prefix()."product_customer_price as pcp ON pcp.fk_soc=".((int) $socid)." AND pcp.fk_product=p.rowid";
2568
		}
2569
		// Units
2570
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2571
			$sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
2572
		}
2573
		// Multilang : we add translation
2574
		if (!empty($conf->global->MAIN_MULTILANGS)) {
2575
			$sql .= " LEFT JOIN ".$this->db->prefix()."product_lang as pl ON pl.fk_product = p.rowid ";
2576
			if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2577
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
2578
				$soc = new Societe($this->db);
2579
				$result = $soc->fetch($socid);
2580
				if ($result > 0 && !empty($soc->default_lang)) {
2581
					$sql .= " AND pl.lang = '".$this->db->escape($soc->default_lang)."'";
2582
				} else {
2583
					$sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2584
				}
2585
			} else {
2586
				$sql .= " AND pl.lang = '".$this->db->escape($langs->getDefaultLang())."'";
2587
			}
2588
		}
2589
2590
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2591
			$sql .= " LEFT JOIN ".$this->db->prefix()."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2592
		}
2593
2594
		$sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2595
2596
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2597
			$sql .= " AND pac.rowid IS NULL";
2598
		}
2599
2600
		if ($finished == 0) {
2601
			$sql .= " AND p.finished = ".((int) $finished);
2602
		} elseif ($finished == 1) {
2603
			$sql .= " AND p.finished = ".((int) $finished);
2604
			if ($status >= 0) {
2605
				$sql .= " AND p.tosell = ".((int) $status);
2606
			}
2607
		} elseif ($status >= 0) {
2608
			$sql .= " AND p.tosell = ".((int) $status);
2609
		}
2610
		if ($status_purchase >= 0) {
2611
			$sql .= " AND p.tobuy = ".((int) $status_purchase);
2612
		}
2613
		// Filter by product type
2614
		if (strval($filtertype) != '') {
2615
			$sql .= " AND p.fk_product_type = ".((int) $filtertype);
2616
		} elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only
2617
			$sql .= " AND p.fk_product_type = 1";
2618
		} elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2619
			$sql .= " AND p.fk_product_type = 0";
2620
		}
2621
		// Add where from hooks
2622
		$parameters = array();
2623
		$reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
2624
		$sql .= $hookmanager->resPrint;
2625
		// Add criteria on ref/label
2626
		if ($filterkey != '') {
2627
			$sql .= ' AND (';
2628
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2629
			// For natural search
2630
			$scrit = explode(' ', $filterkey);
2631
			$i = 0;
2632
			if (count($scrit) > 1) {
2633
				$sql .= "(";
2634
			}
2635
			foreach ($scrit as $crit) {
2636
				if ($i > 0) {
2637
					$sql .= " AND ";
2638
				}
2639
				$sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2640
				if (!empty($conf->global->MAIN_MULTILANGS)) {
2641
					$sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2642
				}
2643
				if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && ! empty($socid)) {
2644
					$sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'";
2645
				}
2646
				if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2647
					$sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2648
					if (!empty($conf->global->MAIN_MULTILANGS)) {
2649
						$sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2650
					}
2651
				}
2652
				if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2653
					$sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2654
				}
2655
				$sql .= ")";
2656
				$i++;
2657
			}
2658
			if (count($scrit) > 1) {
2659
				$sql .= ")";
2660
			}
2661
			if (!empty($conf->barcode->enabled)) {
2662
				$sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2663
			}
2664
			$sql .= ')';
2665
		}
2666
		if (count($warehouseStatusArray)) {
2667
			$sql .= " GROUP BY ".$selectFields;
2668
		}
2669
2670
		//Sort by category
2671
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2672
			$sql .= " ORDER BY categorie_product_id ";
2673
			//ASC OR DESC order
2674
			($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2675
		} else {
2676
			$sql .= $this->db->order("p.ref");
2677
		}
2678
2679
		$sql .= $this->db->plimit($limit, 0);
2680
2681
		// Build output string
2682
		dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2683
		$result = $this->db->query($sql);
2684
		if ($result) {
2685
			require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2686
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2687
			require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2688
2689
			$num = $this->db->num_rows($result);
2690
2691
			$events = null;
2692
2693
			if (!$forcecombo) {
2694
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2695
				$out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2696
			}
2697
2698
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2699
2700
			$textifempty = '';
2701
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2702
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2703
			if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2704
				if ($showempty && !is_numeric($showempty)) {
2705
					$textifempty = $langs->trans($showempty);
2706
				} else {
2707
					$textifempty .= $langs->trans("All");
2708
				}
2709
			} else {
2710
				if ($showempty && !is_numeric($showempty)) {
2711
					$textifempty = $langs->trans($showempty);
2712
				}
2713
			}
2714
			if ($showempty) {
2715
				$out .= '<option value="-1" selected>'.($textifempty ? $textifempty : '&nbsp;').'</option>';
2716
			}
2717
2718
			$i = 0;
2719
			while ($num && $i < $num) {
2720
				$opt = '';
2721
				$optJson = array();
2722
				$objp = $this->db->fetch_object($result);
2723
2724
				if ((!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product
2725
					$sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2726
					$sql .= " FROM ".$this->db->prefix()."product_price_by_qty";
2727
					$sql .= " WHERE fk_product_price = ".((int) $objp->price_rowid);
2728
					$sql .= " ORDER BY quantity ASC";
2729
2730
					dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2731
					$result2 = $this->db->query($sql);
2732
					if ($result2) {
2733
						$nb_prices = $this->db->num_rows($result2);
2734
						$j = 0;
2735
						while ($nb_prices && $j < $nb_prices) {
2736
							$objp2 = $this->db->fetch_object($result2);
2737
2738
							$objp->price_by_qty_rowid = $objp2->rowid;
2739
							$objp->price_by_qty_price_base_type = $objp2->price_base_type;
2740
							$objp->price_by_qty_quantity = $objp2->quantity;
2741
							$objp->price_by_qty_unitprice = $objp2->unitprice;
2742
							$objp->price_by_qty_remise_percent = $objp2->remise_percent;
2743
							// For backward compatibility
2744
							$objp->quantity = $objp2->quantity;
2745
							$objp->price = $objp2->price;
2746
							$objp->unitprice = $objp2->unitprice;
2747
							$objp->remise_percent = $objp2->remise_percent;
2748
							$objp->remise = $objp2->remise;
2749
2750
							//$objp->tva_tx is not overwritten by $objp2 value
2751
							//$objp->default_vat_code is not overwritten by $objp2 value
2752
2753
							$this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2754
2755
							$j++;
2756
2757
							// Add new entry
2758
							// "key" value of json key array is used by jQuery automatically as selected value
2759
							// "label" value of json key array is used by jQuery automatically as text for combo box
2760
							$out .= $opt;
2761
							array_push($outarray, $optJson);
2762
						}
2763
					}
2764
				} else {
2765
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2766
						$price_product = new Product($this->db);
2767
						$price_product->fetch($objp->rowid, '', '', 1);
2768
						$priceparser = new PriceParser($this->db);
2769
						$price_result = $priceparser->parseProduct($price_product);
2770
						if ($price_result >= 0) {
2771
							$objp->price = $price_result;
2772
							$objp->unitprice = $price_result;
2773
							//Calculate the VAT
2774
							$objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2775
							$objp->price_ttc = price2num($objp->price_ttc, 'MU');
2776
						}
2777
					}
2778
2779
					$this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2780
					// Add new entry
2781
					// "key" value of json key array is used by jQuery automatically as selected value
2782
					// "label" value of json key array is used by jQuery automatically as text for combo box
2783
					$out .= $opt;
2784
					array_push($outarray, $optJson);
2785
				}
2786
2787
				$i++;
2788
			}
2789
2790
			$out .= '</select>';
2791
2792
			$this->db->free($result);
2793
2794
			if (empty($outputmode)) {
2795
				return $out;
2796
			}
2797
			return $outarray;
2798
		} else {
2799
			dol_print_error($this->db);
2800
		}
2801
	}
2802
2803
	/**
2804
	 * Function to forge the string with OPTIONs of SELECT.
2805
	 * This define value for &$opt and &$optJson.
2806
	 * This function is called by select_produits_list().
2807
	 *
2808
	 * @param 	resource	$objp			    Resultset of fetch
2809
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
2810
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
2811
	 * @param 	int			$price_level	    Price level
2812
	 * @param 	string		$selected		    Preselected value
2813
	 * @param   int         $hidepriceinlabel   Hide price in label
2814
	 * @param   string      $filterkey          Filter key to highlight
2815
	 * @param	int			$novirtualstock 	Do not load virtual stock, even if slow option STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO is on.
2816
	 * @return	void
2817
	 */
2818
	protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2819
	{
2820
		global $langs, $conf, $user;
2821
2822
		$outkey = '';
2823
		$outval = '';
2824
		$outref = '';
2825
		$outlabel = '';
2826
		$outlabel_translated = '';
2827
		$outdesc = '';
2828
		$outdesc_translated = '';
2829
		$outbarcode = '';
2830
		$outorigin = '';
2831
		$outtype = '';
2832
		$outprice_ht = '';
2833
		$outprice_ttc = '';
2834
		$outpricebasetype = '';
2835
		$outtva_tx = '';
2836
		$outdefault_vat_code = '';
2837
		$outqty = 1;
2838
		$outdiscount = 0;
2839
2840
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2841
2842
		$label = $objp->label;
2843
		if (!empty($objp->label_translated)) {
2844
			$label = $objp->label_translated;
2845
		}
2846
		if (!empty($filterkey) && $filterkey != '') {
2847
			$label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2848
		}
2849
2850
		$outkey = $objp->rowid;
2851
		$outref = $objp->ref;
2852
		$outrefcust = empty($objp->custref) ? '' : $objp->custref;
2853
		$outlabel = $objp->label;
2854
		$outdesc = $objp->description;
2855
		if (!empty($conf->global->MAIN_MULTILANGS)) {
2856
			$outlabel_translated = $objp->label_translated;
2857
			$outdesc_translated = $objp->description_translated;
2858
		}
2859
		$outbarcode = $objp->barcode;
2860
		$outorigin = $objp->fk_country;
2861
		$outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
2862
2863
		$outtype = $objp->fk_product_type;
2864
		$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2865
		$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2866
2867
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2868
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
2869
		}
2870
2871
		// Units
2872
		$outvalUnits = '';
2873
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2874
			if (!empty($objp->unit_short)) {
2875
				$outvalUnits .= ' - '.$objp->unit_short;
2876
			}
2877
		}
2878
		if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2879
			if (!empty($objp->weight) && $objp->weight_units !== null) {
2880
				$unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2881
				$outvalUnits .= ' - '.$unitToShow;
2882
			}
2883
			if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2884
				$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2885
				$outvalUnits .= ' - '.$unitToShow;
2886
			}
2887
			if (!empty($objp->surface) && $objp->surface_units !== null) {
2888
				$unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2889
				$outvalUnits .= ' - '.$unitToShow;
2890
			}
2891
			if (!empty($objp->volume) && $objp->volume_units !== null) {
2892
				$unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2893
				$outvalUnits .= ' - '.$unitToShow;
2894
			}
2895
		}
2896
		if ($outdurationvalue && $outdurationunit) {
2897
			$da = array(
2898
				'h' => $langs->trans('Hour'),
2899
				'd' => $langs->trans('Day'),
2900
				'w' => $langs->trans('Week'),
2901
				'm' => $langs->trans('Month'),
2902
				'y' => $langs->trans('Year')
2903
			);
2904
			if (isset($da[$outdurationunit])) {
2905
				$outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2906
			}
2907
		}
2908
2909
		$opt = '<option value="'.$objp->rowid.'"';
2910
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
2911
		if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
2912
			$opt .= ' pbq="'.$objp->price_by_qty_rowid.'" data-pbq="'.$objp->price_by_qty_rowid.'" data-pbqup="'.$objp->price_by_qty_unitprice.'" data-pbqbase="'.$objp->price_by_qty_price_base_type.'" data-pbqqty="'.$objp->price_by_qty_quantity.'" data-pbqpercent="'.$objp->price_by_qty_remise_percent.'"';
2913
		}
2914
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
2915
			if (!empty($user->rights->stock->lire)) {
2916
				if ($objp->stock > 0) {
2917
					$opt .= ' class="product_line_stock_ok"';
2918
				} elseif ($objp->stock <= 0) {
2919
					$opt .= ' class="product_line_stock_too_low"';
2920
				}
2921
			}
2922
		}
2923
		if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2924
			$opt .= ' data-labeltrans="'.$outlabel_translated.'"';
2925
			$opt .= ' data-desctrans="'.dol_escape_htmltag($outdesc_translated).'"';
2926
		}
2927
		$opt .= '>';
2928
		$opt .= $objp->ref;
2929
		if (! empty($objp->custref)) {
2930
			$opt.= ' (' . $objp->custref . ')';
2931
		}
2932
		if ($outbarcode) {
2933
			$opt .= ' ('.$outbarcode.')';
2934
		}
2935
		$opt .= ' - '.dol_trunc($label, $maxlengtharticle);
2936
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2937
			$opt .= ' ('.getCountry($outorigin, 1).')';
2938
		}
2939
2940
		$objRef = $objp->ref;
2941
		if (! empty($objp->custref)) {
2942
			$objRef .= ' (' . $objp->custref . ')';
2943
		}
2944
		if (!empty($filterkey) && $filterkey != '') {
2945
			$objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2946
		}
2947
		$outval .= $objRef;
2948
		if ($outbarcode) {
2949
			$outval .= ' ('.$outbarcode.')';
2950
		}
2951
		$outval .= ' - '.dol_trunc($label, $maxlengtharticle);
2952
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2953
			$outval .= ' ('.getCountry($outorigin, 1).')';
2954
		}
2955
2956
		// Units
2957
		$opt .= $outvalUnits;
2958
		$outval .= $outvalUnits;
2959
2960
		$found = 0;
2961
2962
		// Multiprice
2963
		// If we need a particular price level (from 1 to n)
2964
		if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
2965
			$sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
2966
			$sql .= " FROM ".$this->db->prefix()."product_price";
2967
			$sql .= " WHERE fk_product = ".((int) $objp->rowid);
2968
			$sql .= " AND entity IN (".getEntity('productprice').")";
2969
			$sql .= " AND price_level = ".((int) $price_level);
2970
			$sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2971
			$sql .= " LIMIT 1";
2972
2973
			dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
2974
			$result2 = $this->db->query($sql);
2975
			if ($result2) {
2976
				$objp2 = $this->db->fetch_object($result2);
2977
				if ($objp2) {
2978
					$found = 1;
2979
					if ($objp2->price_base_type == 'HT') {
2980
						$opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2981
						$outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2982
					} else {
2983
						$opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2984
						$outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2985
					}
2986
					$outprice_ht = price($objp2->price);
2987
					$outprice_ttc = price($objp2->price_ttc);
2988
					$outpricebasetype = $objp2->price_base_type;
2989
					if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) {  // using this option is a bug. kept for backward compatibility
2990
						$outtva_tx = $objp2->tva_tx;						// We use the vat rate on line of multiprice
2991
						$outdefault_vat_code = $objp2->default_vat_code;	// We use the vat code on line of multiprice
2992
					} else {
2993
						$outtva_tx = $objp->tva_tx;							// We use the vat rate of product, not the one on line of multiprice
2994
						$outdefault_vat_code = $objp->default_vat_code;		// We use the vat code or product, not the one on line of multiprice
2995
					}
2996
				}
2997
			} else {
2998
				dol_print_error($this->db);
2999
			}
3000
		}
3001
3002
		// Price by quantity
3003
		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))) {
3004
			$found = 1;
3005
			$outqty = $objp->quantity;
3006
			$outdiscount = $objp->remise_percent;
3007
			if ($objp->quantity == 1) {
3008
				$opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
3009
				$outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
3010
				$opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3011
				$outval .= $langs->transnoentities("Unit");
3012
			} else {
3013
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
3014
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
3015
				$opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3016
				$outval .= $langs->transnoentities("Units");
3017
			}
3018
3019
			$outprice_ht = price($objp->unitprice);
3020
			$outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3021
			$outpricebasetype = $objp->price_base_type;
3022
			$outtva_tx = $objp->tva_tx;							// This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3023
			$outdefault_vat_code = $objp->default_vat_code;		// This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3024
		}
3025
		if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3026
			$opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
3027
			$outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
3028
		}
3029
		if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3030
			$opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3031
			$outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3032
		}
3033
3034
		// Price by customer
3035
		if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
3036
			if (!empty($objp->idprodcustprice)) {
3037
				$found = 1;
3038
3039
				if ($objp->custprice_base_type == 'HT') {
3040
					$opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3041
					$outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3042
				} else {
3043
					$opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3044
					$outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3045
				}
3046
3047
				$outprice_ht = price($objp->custprice);
3048
				$outprice_ttc = price($objp->custprice_ttc);
3049
				$outpricebasetype = $objp->custprice_base_type;
3050
				$outtva_tx = $objp->custtva_tx;
3051
				$outdefault_vat_code = $objp->custdefault_vat_code;
3052
			}
3053
		}
3054
3055
		// If level no defined or multiprice not found, we used the default price
3056
		if (empty($hidepriceinlabel) && !$found) {
3057
			if ($objp->price_base_type == 'HT') {
3058
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
3059
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
3060
			} else {
3061
				$opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
3062
				$outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
3063
			}
3064
			$outprice_ht = price($objp->price);
3065
			$outprice_ttc = price($objp->price_ttc);
3066
			$outpricebasetype = $objp->price_base_type;
3067
			$outtva_tx = $objp->tva_tx;
3068
			$outdefault_vat_code = $objp->default_vat_code;
3069
		}
3070
3071
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3072
			if (!empty($user->rights->stock->lire)) {
3073
				$opt .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3074
3075
				if ($objp->stock > 0) {
3076
					$outval .= ' - <span class="product_line_stock_ok">';
3077
				} elseif ($objp->stock <= 0) {
3078
					$outval .= ' - <span class="product_line_stock_too_low">';
3079
				}
3080
				$outval .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS'));
3081
				$outval .= '</span>';
3082
				if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) {  // Warning, this option may slow down combo list generation
3083
					$langs->load("stocks");
3084
3085
					$tmpproduct = new Product($this->db);
3086
					$tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3087
					$tmpproduct->load_virtual_stock();
3088
					$virtualstock = $tmpproduct->stock_theorique;
3089
3090
					$opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3091
3092
					$outval .= ' - '.$langs->transnoentities("VirtualStock").':';
3093
					if ($virtualstock > 0) {
3094
						$outval .= '<span class="product_line_stock_ok">';
3095
					} elseif ($virtualstock <= 0) {
3096
						$outval .= '<span class="product_line_stock_too_low">';
3097
					}
3098
					$outval .= $virtualstock;
3099
					$outval .= '</span>';
3100
3101
					unset($tmpproduct);
3102
				}
3103
			}
3104
		}
3105
3106
		$opt .= "</option>\n";
3107
		$optJson = array(
3108
			'key'=>$outkey,
3109
			'value'=>$outref,
3110
			'label'=>$outval,
3111
			'label2'=>$outlabel,
3112
			'desc'=>$outdesc,
3113
			'type'=>$outtype,
3114
			'price_ht'=>price2num($outprice_ht),
3115
			'price_ttc'=>price2num($outprice_ttc),
3116
			'pricebasetype'=>$outpricebasetype,
3117
			'tva_tx'=>$outtva_tx,
3118
			'default_vat_code'=>$outdefault_vat_code,
3119
			'qty'=>$outqty,
3120
			'discount'=>$outdiscount,
3121
			'duration_value'=>$outdurationvalue,
3122
			'duration_unit'=>$outdurationunit,
3123
			'pbq'=>$outpbq,
3124
			'labeltrans'=>$outlabel_translated,
3125
			'desctrans'=>$outdesc_translated,
3126
			'ref_customer'=>$outrefcust
3127
		);
3128
	}
3129
3130
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3131
	/**
3132
	 *	Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list)
3133
	 *
3134
	 *	@param	int		$socid			Id third party
3135
	 *	@param  string	$selected       Preselected product
3136
	 *	@param  string	$htmlname       Name of HTML Select
3137
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
3138
	 *	@param  string	$filtre			For a SQL filter
3139
	 *	@param	array	$ajaxoptions	Options for ajax_autocompleter
3140
	 *  @param	int		$hidelabel		Hide label (0=no, 1=yes)
3141
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
3142
	 *  @param	string	$morecss		More CSS
3143
	 *  @param	string	$placeholder	Placeholder
3144
	 *	@return	void
3145
	 */
3146
	public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3147
	{
3148
		// phpcs:enable
3149
		global $langs, $conf;
3150
		global $price_level, $status, $finished;
3151
3152
		if (!isset($status)) {
3153
			$status = 1;
3154
		}
3155
3156
		$selected_input_value = '';
3157
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
3158
			if ($selected > 0) {
3159
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
3160
				$producttmpselect = new Product($this->db);
3161
				$producttmpselect->fetch($selected);
3162
				$selected_input_value = $producttmpselect->ref;
3163
				unset($producttmpselect);
3164
			}
3165
3166
			// mode=2 means suppliers products
3167
			$urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
3168
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3169
			print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" class="minwidth300" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.$placeholder.'"' : '').'>';
3170
		} else {
3171
			print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3172
		}
3173
	}
3174
3175
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3176
	/**
3177
	 *	Return list of suppliers products
3178
	 *
3179
	 *	@param	int		$socid   			Id of supplier thirdparty (0 = no filter)
3180
	 *	@param  int		$selected       	Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD')
3181
	 *	@param  string	$htmlname       	Name of HTML select
3182
	 *  @param	string	$filtertype     	Filter on product type (''=nofilter, 0=product, 1=service)
3183
	 *	@param  string	$filtre         	Generic filter. Data must not come from user input.
3184
	 *	@param  string	$filterkey      	Filter of produdts
3185
	 *  @param  int		$statut         	-1=Return all products, 0=Products not on buy, 1=Products on buy
3186
	 *  @param  int		$outputmode     	0=HTML select string, 1=Array
3187
	 *  @param  int     $limit          	Limit of line number
3188
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
3189
	 *  @param	string	$morecss			Add more CSS
3190
	 *  @param	int		$showstockinlist	Show stock information (slower).
3191
	 *  @param	string	$placeholder		Placeholder
3192
	 *  @return array           			Array of keys for json
3193
	 */
3194
	public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0, $placeholder = '')
3195
	{
3196
		// phpcs:enable
3197
		global $langs, $conf, $user;
3198
		global $hookmanager;
3199
3200
		$out = '';
3201
		$outarray = array();
3202
3203
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3204
3205
		$langs->load('stocks');
3206
		// Units
3207
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3208
			$langs->load('other');
3209
		}
3210
3211
		$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock,";
3212
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
3213
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name,";
3214
		$sql .= " pfp.supplier_reputation";
3215
		// if we use supplier description of the products
3216
		if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3217
			$sql .= " ,pfp.desc_fourn as description";
3218
		} else {
3219
			$sql .= " ,p.description";
3220
		}
3221
		// Units
3222
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3223
			$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";
3224
		}
3225
		if (!empty($conf->barcode->enabled)) {
3226
			$sql .= ", pfp.barcode";
3227
		}
3228
		$sql .= " FROM ".$this->db->prefix()."product as p";
3229
		$sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )";
3230
		if ($socid > 0) {
3231
			$sql .= " AND pfp.fk_soc = ".((int) $socid);
3232
		}
3233
		$sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid";
3234
		// Units
3235
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3236
			$sql .= " LEFT JOIN ".$this->db->prefix()."c_units u ON u.rowid = p.fk_unit";
3237
		}
3238
		$sql .= " WHERE p.entity IN (".getEntity('product').")";
3239
		if ($statut != -1) {
3240
			$sql .= " AND p.tobuy = ".((int) $statut);
3241
		}
3242
		if (strval($filtertype) != '') {
3243
			$sql .= " AND p.fk_product_type = ".((int) $filtertype);
3244
		}
3245
		if (!empty($filtre)) {
3246
			$sql .= " ".$filtre;
3247
		}
3248
		// Add where from hooks
3249
		$parameters = array();
3250
		$reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3251
		$sql .= $hookmanager->resPrint;
3252
		// Add criteria on ref/label
3253
		if ($filterkey != '') {
3254
			$sql .= ' AND (';
3255
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3256
			// For natural search
3257
			$scrit = explode(' ', $filterkey);
3258
			$i = 0;
3259
			if (count($scrit) > 1) {
3260
				$sql .= "(";
3261
			}
3262
			foreach ($scrit as $crit) {
3263
				if ($i > 0) {
3264
					$sql .= " AND ";
3265
				}
3266
				$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)."%'";
3267
				if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3268
					$sql .= " OR pfp.desc_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
3269
				}
3270
				$sql .= ")";
3271
				$i++;
3272
			}
3273
			if (count($scrit) > 1) {
3274
				$sql .= ")";
3275
			}
3276
			if (!empty($conf->barcode->enabled)) {
3277
				$sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3278
				$sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3279
			}
3280
			$sql .= ')';
3281
		}
3282
		$sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3283
		$sql .= $this->db->plimit($limit, 0);
3284
3285
		// Build output string
3286
3287
		dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
3288
		$result = $this->db->query($sql);
3289
		if ($result) {
3290
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3291
			require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
3292
3293
			$num = $this->db->num_rows($result);
3294
3295
			//$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">';	// remove select to have id same with combo and ajax
3296
			$out .= '<select class="flat '.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
3297
			if (!$selected) {
3298
				$out .= '<option value="-1" selected>'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3299
			} else {
3300
				$out .= '<option value="-1">'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3301
			}
3302
3303
			$i = 0;
3304
			while ($i < $num) {
3305
				$objp = $this->db->fetch_object($result);
3306
3307
				$outkey = $objp->idprodfournprice; // id in table of price
3308
				if (!$outkey && $alsoproductwithnosupplierprice) {
3309
					$outkey = 'idprod_'.$objp->rowid; // id of product
3310
				}
3311
3312
				$outref = $objp->ref;
3313
				$outval = '';
3314
				$outbarcode = $objp->barcode;
3315
				$outqty = 1;
3316
				$outdiscount = 0;
3317
				$outtype = $objp->fk_product_type;
3318
				$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3319
				$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
3320
3321
				// Units
3322
				$outvalUnits = '';
3323
				if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3324
					if (!empty($objp->unit_short)) {
3325
						$outvalUnits .= ' - '.$objp->unit_short;
3326
					}
3327
					if (!empty($objp->weight) && $objp->weight_units !== null) {
3328
						$unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3329
						$outvalUnits .= ' - '.$unitToShow;
3330
					}
3331
					if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3332
						$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
3333
						$outvalUnits .= ' - '.$unitToShow;
3334
					}
3335
					if (!empty($objp->surface) && $objp->surface_units !== null) {
3336
						$unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3337
						$outvalUnits .= ' - '.$unitToShow;
3338
					}
3339
					if (!empty($objp->volume) && $objp->volume_units !== null) {
3340
						$unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3341
						$outvalUnits .= ' - '.$unitToShow;
3342
					}
3343
					if ($outdurationvalue && $outdurationunit) {
3344
						$da = array(
3345
							'h' => $langs->trans('Hour'),
3346
							'd' => $langs->trans('Day'),
3347
							'w' => $langs->trans('Week'),
3348
							'm' => $langs->trans('Month'),
3349
							'y' => $langs->trans('Year')
3350
						);
3351
						if (isset($da[$outdurationunit])) {
3352
							$outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
3353
						}
3354
					}
3355
				}
3356
3357
				$objRef = $objp->ref;
3358
				if ($filterkey && $filterkey != '') {
3359
					$objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
3360
				}
3361
				$objRefFourn = $objp->ref_fourn;
3362
				if ($filterkey && $filterkey != '') {
3363
					$objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1);
3364
				}
3365
				$label = $objp->label;
3366
				if ($filterkey && $filterkey != '') {
3367
					$label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
3368
				}
3369
3370
				$optlabel = $objp->ref;
3371
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3372
					$optlabel .= ' <span class="opacitymedium">('.$objp->ref_fourn.')</span>';
3373
				}
3374
				if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
3375
					$optlabel .= ' ('.$outbarcode.')';
3376
				}
3377
				$optlabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3378
3379
				$outvallabel = $objRef;
3380
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3381
					$outvallabel .= ' ('.$objRefFourn.')';
3382
				}
3383
				if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
3384
					$outvallabel .= ' ('.$outbarcode.')';
3385
				}
3386
				$outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3387
3388
				// Units
3389
				$optlabel .= $outvalUnits;
3390
				$outvallabel .= $outvalUnits;
3391
3392
				if (!empty($objp->idprodfournprice)) {
3393
					$outqty = $objp->quantity;
3394
					$outdiscount = $objp->remise_percent;
3395
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3396
						$prod_supplier = new ProductFournisseur($this->db);
3397
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3398
						$prod_supplier->id = $objp->fk_product;
3399
						$prod_supplier->fourn_qty = $objp->quantity;
3400
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
3401
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3402
						$priceparser = new PriceParser($this->db);
3403
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
3404
						if ($price_result >= 0) {
3405
							$objp->fprice = $price_result;
3406
							if ($objp->quantity >= 1) {
3407
								$objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3408
							}
3409
						}
3410
					}
3411
					if ($objp->quantity == 1) {
3412
						$optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3413
						$outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
3414
						$optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3415
						$outvallabel .= $langs->transnoentities("Unit");
3416
					} else {
3417
						$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;
3418
						$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;
3419
						$optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3420
						$outvallabel .= ' '.$langs->transnoentities("Units");
3421
					}
3422
3423
					if ($objp->quantity > 1) {
3424
						$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
3425
						$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
3426
					}
3427
					if ($objp->remise_percent >= 1) {
3428
						$optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3429
						$outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3430
					}
3431
					if ($objp->duration) {
3432
						$optlabel .= " - ".$objp->duration;
3433
						$outvallabel .= " - ".$objp->duration;
3434
					}
3435
					if (!$socid) {
3436
						$optlabel .= " - ".dol_trunc($objp->name, 8);
3437
						$outvallabel .= " - ".dol_trunc($objp->name, 8);
3438
					}
3439
					if ($objp->supplier_reputation) {
3440
						//TODO dictionary
3441
						$reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
3442
3443
						$optlabel .= " - ".$reputations[$objp->supplier_reputation];
3444
						$outvallabel .= " - ".$reputations[$objp->supplier_reputation];
3445
					}
3446
				} else {
3447
					if (empty($alsoproductwithnosupplierprice)) {     // No supplier price defined for couple product/supplier
3448
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3449
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3450
					} else // No supplier price defined for product, even on other suppliers
3451
					{
3452
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3453
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3454
					}
3455
				}
3456
3457
				if (!empty($conf->stock->enabled) && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3458
					$novirtualstock = ($showstockinlist == 2);
3459
3460
					if (!empty($user->rights->stock->lire)) {
3461
						$outvallabel .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3462
3463
						if ($objp->stock > 0) {
3464
							$optlabel .= ' - <span class="product_line_stock_ok">';
3465
						} elseif ($objp->stock <= 0) {
3466
							$optlabel .= ' - <span class="product_line_stock_too_low">';
3467
						}
3468
						$optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS'));
3469
						$optlabel .= '</span>';
3470
						if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) {  // Warning, this option may slow down combo list generation
3471
							$langs->load("stocks");
3472
3473
							$tmpproduct = new Product($this->db);
3474
							$tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3475
							$tmpproduct->load_virtual_stock();
3476
							$virtualstock = $tmpproduct->stock_theorique;
3477
3478
							$outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3479
3480
							$optlabel .= ' - '.$langs->transnoentities("VirtualStock").':';
3481
							if ($virtualstock > 0) {
3482
								$optlabel .= '<span class="product_line_stock_ok">';
3483
							} elseif ($virtualstock <= 0) {
3484
								$optlabel .= '<span class="product_line_stock_too_low">';
3485
							}
3486
							$optlabel .= $virtualstock;
3487
							$optlabel .= '</span>';
3488
3489
							unset($tmpproduct);
3490
						}
3491
					}
3492
				}
3493
3494
				$opt = '<option value="'.$outkey.'"';
3495
				if ($selected && $selected == $objp->idprodfournprice) {
3496
					$opt .= ' selected';
3497
				}
3498
				if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3499
					$opt .= ' disabled';
3500
				}
3501
				if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3502
					$opt .= ' data-product-id="'.$objp->rowid.'" data-price-id="'.$objp->idprodfournprice.'" data-qty="'.$objp->quantity.'" data-up="'.$objp->unitprice.'" data-discount="'.$outdiscount.'"';
3503
				}
3504
				$opt .= ' data-description="'.dol_escape_htmltag($objp->description, 0, 1).'"';
3505
				$opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"';
3506
				$opt .= '>';
3507
3508
				$opt .= $optlabel;
3509
				$outval .= $outvallabel;
3510
3511
				$opt .= "</option>\n";
3512
3513
				// Add new entry
3514
				// "key" value of json key array is used by jQuery automatically as selected value. Example: 'type' = product or service, 'price_ht' = unit price without tax
3515
				// "label" value of json key array is used by jQuery automatically as text for combo box
3516
				$out .= $opt;
3517
				array_push(
3518
					$outarray,
3519
					array('key'=>$outkey,
3520
						'value'=>$outref,
3521
						'label'=>$outval,
3522
						'qty'=>$outqty,
3523
						'price_qty_ht'=>price2num($objp->fprice, 'MU'),	// Keep higher resolution for price for the min qty
3524
						'price_unit_ht'=>price2num($objp->unitprice, 'MU'),	// This is used to fill the Unit Price
3525
						'price_ht'=>price2num($objp->unitprice, 'MU'),		// This is used to fill the Unit Price (for compatibility)
3526
						'tva_tx'=>$objp->tva_tx,
3527
						'default_vat_code'=>$objp->default_vat_code,
3528
						'discount'=>$outdiscount,
3529
						'type'=>$outtype,
3530
						'duration_value'=>$outdurationvalue,
3531
						'duration_unit'=>$outdurationunit,
3532
						'disabled'=>(empty($objp->idprodfournprice) ? true : false),
3533
						'description'=>$objp->description
3534
					)
3535
				);
3536
				// Exemple of var_dump $outarray
3537
				// array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3538
				//           ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3539
				//      	 ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3540
				//}
3541
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3542
				//$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3543
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3544
3545
				$i++;
3546
			}
3547
			$out .= '</select>';
3548
3549
			$this->db->free($result);
3550
3551
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3552
			$out .= ajax_combobox($htmlname);
3553
3554
			if (empty($outputmode)) {
3555
				return $out;
3556
			}
3557
			return $outarray;
3558
		} else {
3559
			dol_print_error($this->db);
3560
		}
3561
	}
3562
3563
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3564
	/**
3565
	 *	Return list of suppliers prices for a product
3566
	 *
3567
	 *  @param	    int		$productid       	Id of product
3568
	 *  @param      string	$htmlname        	Name of HTML field
3569
	 *  @param      int		$selected_supplier  Pre-selected supplier if more than 1 result
3570
	 *  @return	    string
3571
	 */
3572
	public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3573
	{
3574
		// phpcs:enable
3575
		global $langs, $conf;
3576
3577
		$langs->load('stocks');
3578
3579
		$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3580
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3581
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3582
		$sql .= " FROM ".$this->db->prefix()."product as p";
3583
		$sql .= " LEFT JOIN ".$this->db->prefix()."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3584
		$sql .= " LEFT JOIN ".$this->db->prefix()."societe as s ON pfp.fk_soc = s.rowid";
3585
		$sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3586
		$sql .= " AND p.tobuy = 1";
3587
		$sql .= " AND s.fournisseur = 1";
3588
		$sql .= " AND p.rowid = ".((int) $productid);
3589
		$sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3590
3591
		dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3592
		$result = $this->db->query($sql);
3593
3594
		if ($result) {
3595
			$num = $this->db->num_rows($result);
3596
3597
			$form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3598
3599
			if (!$num) {
3600
				$form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3601
			} else {
3602
				require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3603
				$form .= '<option value="0">&nbsp;</option>';
3604
3605
				$i = 0;
3606
				while ($i < $num) {
3607
					$objp = $this->db->fetch_object($result);
3608
3609
					$opt = '<option value="'.$objp->idprodfournprice.'"';
3610
					//if there is only one supplier, preselect it
3611
					if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
3612
						$opt .= ' selected';
3613
					}
3614
					$opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3615
3616
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3617
						$prod_supplier = new ProductFournisseur($this->db);
3618
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3619
						$prod_supplier->id = $productid;
3620
						$prod_supplier->fourn_qty = $objp->quantity;
3621
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
3622
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3623
						$priceparser = new PriceParser($this->db);
3624
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
3625
						if ($price_result >= 0) {
3626
							$objp->fprice = $price_result;
3627
							if ($objp->quantity >= 1) {
3628
								$objp->unitprice = $objp->fprice / $objp->quantity;
3629
							}
3630
						}
3631
					}
3632
					if ($objp->quantity == 1) {
3633
						$opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3634
					}
3635
3636
					$opt .= $objp->quantity.' ';
3637
3638
					if ($objp->quantity == 1) {
3639
						$opt .= $langs->trans("Unit");
3640
					} else {
3641
						$opt .= $langs->trans("Units");
3642
					}
3643
					if ($objp->quantity > 1) {
3644
						$opt .= " - ";
3645
						$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");
3646
					}
3647
					if ($objp->duration) {
3648
						$opt .= " - ".$objp->duration;
3649
					}
3650
					$opt .= "</option>\n";
3651
3652
					$form .= $opt;
3653
					$i++;
3654
				}
3655
			}
3656
3657
			$form .= '</select>';
3658
			$this->db->free($result);
3659
			return $form;
3660
		} else {
3661
			dol_print_error($this->db);
3662
		}
3663
	}
3664
3665
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3666
	/**
3667
	 *    Return list of delivery address
3668
	 *
3669
	 *    @param    string	$selected          	Id contact pre-selectionn
3670
	 *    @param    int		$socid				Id of company
3671
	 *    @param    string	$htmlname          	Name of HTML field
3672
	 *    @param    int		$showempty         	Add an empty field
3673
	 *    @return	integer|null
3674
	 */
3675
	public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3676
	{
3677
		// phpcs:enable
3678
		// looking for users
3679
		$sql = "SELECT a.rowid, a.label";
3680
		$sql .= " FROM ".$this->db->prefix()."societe_address as a";
3681
		$sql .= " WHERE a.fk_soc = ".((int) $socid);
3682
		$sql .= " ORDER BY a.label ASC";
3683
3684
		dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3685
		$resql = $this->db->query($sql);
3686
		if ($resql) {
3687
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3688
			if ($showempty) {
3689
				print '<option value="0">&nbsp;</option>';
3690
			}
3691
			$num = $this->db->num_rows($resql);
3692
			$i = 0;
3693
			if ($num) {
3694
				while ($i < $num) {
3695
					$obj = $this->db->fetch_object($resql);
3696
3697
					if ($selected && $selected == $obj->rowid) {
3698
						print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3699
					} else {
3700
						print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3701
					}
3702
					$i++;
3703
				}
3704
			}
3705
			print '</select>';
3706
			return $num;
3707
		} else {
3708
			dol_print_error($this->db);
3709
		}
3710
	}
3711
3712
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3713
	/**
3714
	 *      Load into cache list of payment terms
3715
	 *
3716
	 *      @return     int             Nb of lines loaded, <0 if KO
3717
	 */
3718
	public function load_cache_conditions_paiements()
3719
	{
3720
		// phpcs:enable
3721
		global $langs;
3722
3723
		$num = count($this->cache_conditions_paiements);
3724
		if ($num > 0) {
3725
			return 0; // Cache already loaded
3726
		}
3727
3728
		dol_syslog(__METHOD__, LOG_DEBUG);
3729
3730
		$sql = "SELECT rowid, code, libelle as label";
3731
		$sql .= " FROM ".$this->db->prefix().'c_payment_term';
3732
		$sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3733
		$sql .= " AND active > 0";
3734
		$sql .= " ORDER BY sortorder";
3735
3736
		$resql = $this->db->query($sql);
3737
		if ($resql) {
3738
			$num = $this->db->num_rows($resql);
3739
			$i = 0;
3740
			while ($i < $num) {
3741
				$obj = $this->db->fetch_object($resql);
3742
3743
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3744
				$label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3745
				$this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3746
				$this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3747
				$i++;
3748
			}
3749
3750
			//$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1);		// We use the field sortorder of table
3751
3752
			return $num;
3753
		} else {
3754
			dol_print_error($this->db);
3755
			return -1;
3756
		}
3757
	}
3758
3759
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3760
	/**
3761
	 *      Load int a cache property th elist of possible delivery delays.
3762
	 *
3763
	 *      @return     int             Nb of lines loaded, <0 if KO
3764
	 */
3765
	public function load_cache_availability()
3766
	{
3767
		// phpcs:enable
3768
		global $langs;
3769
3770
		$num = count($this->cache_availability);	// TODO Use $conf->cache['availability'] instead of $this->cache_availability
3771
		if ($num > 0) {
3772
			return 0; // Cache already loaded
3773
		}
3774
3775
		dol_syslog(__METHOD__, LOG_DEBUG);
3776
3777
		$langs->load('propal');
3778
3779
		$sql = "SELECT rowid, code, label, position";
3780
		$sql .= " FROM ".$this->db->prefix().'c_availability';
3781
		$sql .= " WHERE active > 0";
3782
3783
		$resql = $this->db->query($sql);
3784
		if ($resql) {
3785
			$num = $this->db->num_rows($resql);
3786
			$i = 0;
3787
			while ($i < $num) {
3788
				$obj = $this->db->fetch_object($resql);
3789
3790
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3791
				$label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3792
				$this->cache_availability[$obj->rowid]['code'] = $obj->code;
3793
				$this->cache_availability[$obj->rowid]['label'] = $label;
3794
				$this->cache_availability[$obj->rowid]['position'] = $obj->position;
3795
				$i++;
3796
			}
3797
3798
			$this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
3799
3800
			return $num;
3801
		} else {
3802
			dol_print_error($this->db);
3803
			return -1;
3804
		}
3805
	}
3806
3807
	/**
3808
	 *      Retourne la liste des types de delais de livraison possibles
3809
	 *
3810
	 *      @param	int		$selected       Id du type de delais pre-selectionne
3811
	 *      @param  string	$htmlname       Nom de la zone select
3812
	 *      @param  string	$filtertype     To add a filter
3813
	 *		@param	int		$addempty		Add empty entry
3814
	 * 		@param	string	$morecss		More CSS
3815
	 *		@return	void
3816
	 */
3817
	public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
3818
	{
3819
		global $langs, $user;
3820
3821
		$this->load_cache_availability();
3822
3823
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3824
3825
		print '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3826
		if ($addempty) {
3827
			print '<option value="0">&nbsp;</option>';
3828
		}
3829
		foreach ($this->cache_availability as $id => $arrayavailability) {
3830
			if ($selected == $id) {
3831
				print '<option value="'.$id.'" selected>';
3832
			} else {
3833
				print '<option value="'.$id.'">';
3834
			}
3835
			print dol_escape_htmltag($arrayavailability['label']);
3836
			print '</option>';
3837
		}
3838
		print '</select>';
3839
		if ($user->admin) {
3840
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3841
		}
3842
		print ajax_combobox($htmlname);
3843
	}
3844
3845
	/**
3846
	 *      Load into cache cache_demand_reason, array of input reasons
3847
	 *
3848
	 *      @return     int             Nb of lines loaded, <0 if KO
3849
	 */
3850
	public function loadCacheInputReason()
3851
	{
3852
		global $langs;
3853
3854
		$num = count($this->cache_demand_reason);	// TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
3855
		if ($num > 0) {
3856
			return 0; // Cache already loaded
3857
		}
3858
3859
		$sql = "SELECT rowid, code, label";
3860
		$sql .= " FROM ".$this->db->prefix().'c_input_reason';
3861
		$sql .= " WHERE active > 0";
3862
3863
		$resql = $this->db->query($sql);
3864
		if ($resql) {
3865
			$num = $this->db->num_rows($resql);
3866
			$i = 0;
3867
			$tmparray = array();
3868
			while ($i < $num) {
3869
				$obj = $this->db->fetch_object($resql);
3870
3871
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3872
				$label = ($obj->label != '-' ? $obj->label : '');
3873
				if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) {
3874
					$label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3875
				}
3876
				if ($langs->trans($obj->code) != $obj->code) {
3877
					$label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3878
				}
3879
3880
				$tmparray[$obj->rowid]['id']   = $obj->rowid;
3881
				$tmparray[$obj->rowid]['code'] = $obj->code;
3882
				$tmparray[$obj->rowid]['label'] = $label;
3883
				$i++;
3884
			}
3885
3886
			$this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3887
3888
			unset($tmparray);
3889
			return $num;
3890
		} else {
3891
			dol_print_error($this->db);
3892
			return -1;
3893
		}
3894
	}
3895
3896
	/**
3897
	 *	Return list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
3898
	 *  List found into table c_input_reason loaded by loadCacheInputReason
3899
	 *
3900
	 *  @param	int		$selected        Id or code of type origin to select by default
3901
	 *  @param  string	$htmlname        Nom de la zone select
3902
	 *  @param  string	$exclude         To exclude a code value (Example: SRC_PROP)
3903
	 *	@param	int		$addempty		 Add an empty entry
3904
	 *  @param  string	$morecss		 Add more css to the HTML select component
3905
	 *  @param	int		$notooltip		 Do not show the tooltip for admin
3906
	 *	@return	void
3907
	 */
3908
	public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
3909
	{
3910
		global $langs, $user;
3911
3912
		$this->loadCacheInputReason();
3913
3914
		print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3915
		if ($addempty) {
3916
			print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
3917
		}
3918
		foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
3919
			if ($arraydemandreason['code'] == $exclude) {
3920
				continue;
3921
			}
3922
3923
			if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
3924
				print '<option value="'.$arraydemandreason['id'].'" selected>';
3925
			} else {
3926
				print '<option value="'.$arraydemandreason['id'].'">';
3927
			}
3928
			$label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3929
			print $langs->trans($label);
3930
			print '</option>';
3931
		}
3932
		print '</select>';
3933
		if ($user->admin && empty($notooltip)) {
3934
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3935
		}
3936
		print ajax_combobox('select_'.$htmlname);
3937
	}
3938
3939
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3940
	/**
3941
	 *      Charge dans cache la liste des types de paiements possibles
3942
	 *
3943
	 *      @return     int                 Nb of lines loaded, <0 if KO
3944
	 */
3945
	public function load_cache_types_paiements()
3946
	{
3947
		// phpcs:enable
3948
		global $langs;
3949
3950
		$num = count($this->cache_types_paiements);		// TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
3951
		if ($num > 0) {
3952
			return $num; // Cache already loaded
3953
		}
3954
3955
		dol_syslog(__METHOD__, LOG_DEBUG);
3956
3957
		$this->cache_types_paiements = array();
3958
3959
		$sql = "SELECT id, code, libelle as label, type, active";
3960
		$sql .= " FROM ".$this->db->prefix()."c_paiement";
3961
		$sql .= " WHERE entity IN (".getEntity('c_paiement').")";
3962
3963
		$resql = $this->db->query($sql);
3964
		if ($resql) {
3965
			$num = $this->db->num_rows($resql);
3966
			$i = 0;
3967
			while ($i < $num) {
3968
				$obj = $this->db->fetch_object($resql);
3969
3970
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3971
				$label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3972
				$this->cache_types_paiements[$obj->id]['id'] = $obj->id;
3973
				$this->cache_types_paiements[$obj->id]['code'] = $obj->code;
3974
				$this->cache_types_paiements[$obj->id]['label'] = $label;
3975
				$this->cache_types_paiements[$obj->id]['type'] = $obj->type;
3976
				$this->cache_types_paiements[$obj->id]['active'] = $obj->active;
3977
				$i++;
3978
			}
3979
3980
			$this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3981
3982
			return $num;
3983
		} else {
3984
			dol_print_error($this->db);
3985
			return -1;
3986
		}
3987
	}
3988
3989
3990
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3991
	/**
3992
	 *      print list of payment modes.
3993
	 *      Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
3994
	 *      See instead to force the default value by the caller.
3995
	 *
3996
	 *      @param	int		$selected		Id of payment term to preselect by default
3997
	 *      @param	string	$htmlname		Nom de la zone select
3998
	 *      @param	int		$filtertype		Not used
3999
	 *		@param	int		$addempty		Add an empty entry
4000
	 * 		@param	int		$noinfoadmin	0=Add admin info, 1=Disable admin info
4001
	 * 		@param	string	$morecss		Add more CSS on select tag
4002
	 *		@return	void
4003
	 */
4004
	public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
4005
	{
4006
		// phpcs:enable
4007
		print $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getSelectConditio...$noinfoadmin, $morecss) targeting Form::getSelectConditionsPaiements() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
4008
	}
4009
4010
4011
	/**
4012
	 *      Return list of payment modes.
4013
	 *      Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
4014
	 *      See instead to force the default value by the caller.
4015
	 *
4016
	 *      @param	int		$selected		Id of payment term to preselect by default
4017
	 *      @param	string	$htmlname		Nom de la zone select
4018
	 *      @param	int		$filtertype		Not used
4019
	 *		@param	int		$addempty		Add an empty entry
4020
	 * 		@param	int		$noinfoadmin	0=Add admin info, 1=Disable admin info
4021
	 * 		@param	string	$morecss		Add more CSS on select tag
4022
	 *		@return	void
4023
	 */
4024
	public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
4025
	{
4026
4027
		global $langs, $user, $conf;
4028
		$out = '';
4029
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
4030
4031
		$this->load_cache_conditions_paiements();
4032
4033
		// Set default value if not already set by caller
4034
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
4035
			$selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
4036
		}
4037
4038
		$out.=  '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4039
		if ($addempty) {
4040
			$out.=  '<option value="0">&nbsp;</option>';
4041
		}
4042
		foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4043
			if ($selected == $id) {
4044
				$out.=  '<option value="'.$id.'" selected>';
4045
			} else {
4046
				$out.=  '<option value="'.$id.'">';
4047
			}
4048
			$out.=  $arrayconditions['label'];
4049
			$out.=  '</option>';
4050
		}
4051
		$out.=  '</select>';
4052
		if ($user->admin && empty($noinfoadmin)) {
4053
			$out.=  info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4054
		}
4055
		$out.=  ajax_combobox($htmlname);
4056
		return $out;
4057
	}
4058
4059
4060
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4061
	/**
4062
	 *      Return list of payment methods
4063
	 *      Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value but scope is all application, probably not what you want.
4064
	 *
4065
	 *      @param	string	$selected       Id or code or preselected payment mode
4066
	 *      @param  string	$htmlname       Name of select field
4067
	 *      @param  string	$filtertype     To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz))
4068
	 *      @param  int		$format         0=id+label, 1=code+code, 2=code+label, 3=id+code
4069
	 *      @param  int		$empty			1=can be empty, 0 otherwise
4070
	 * 		@param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
4071
	 *      @param  int		$maxlength      Max length of label
4072
	 *      @param  int     $active         Active or not, -1 = all
4073
	 *      @param  string  $morecss        Add more CSS on select tag
4074
	 *      @param	int		$nooutput		1=Return string, do not send to output
4075
	 * 		@return	void
4076
	 */
4077
	public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4078
	{
4079
		// phpcs:enable
4080
		global $langs, $user, $conf;
4081
4082
		$out = '';
4083
4084
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
4085
4086
		$filterarray = array();
4087
		if ($filtertype == 'CRDT') {
4088
			$filterarray = array(0, 2, 3);
4089
		} elseif ($filtertype == 'DBIT') {
4090
			$filterarray = array(1, 2, 3);
4091
		} elseif ($filtertype != '' && $filtertype != '-1') {
4092
			$filterarray = explode(',', $filtertype);
4093
		}
4094
4095
		$this->load_cache_types_paiements();
4096
4097
		// Set default value if not already set by caller
4098
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
4099
			$selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
4100
		}
4101
4102
		$out .= '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4103
		if ($empty) {
4104
			$out .= '<option value="">&nbsp;</option>';
4105
		}
4106
		foreach ($this->cache_types_paiements as $id => $arraytypes) {
4107
			// If not good status
4108
			if ($active >= 0 && $arraytypes['active'] != $active) {
4109
				continue;
4110
			}
4111
4112
			// On passe si on a demande de filtrer sur des modes de paiments particuliers
4113
			if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4114
				continue;
4115
			}
4116
4117
			// We discard empty line if showempty is on because an empty line has already been output.
4118
			if ($empty && empty($arraytypes['code'])) {
4119
				continue;
4120
			}
4121
4122
			if ($format == 0) {
4123
				$out .= '<option value="'.$id.'"';
4124
			} elseif ($format == 1) {
4125
				$out .= '<option value="'.$arraytypes['code'].'"';
4126
			} elseif ($format == 2) {
4127
				$out .= '<option value="'.$arraytypes['code'].'"';
4128
			} elseif ($format == 3) {
4129
				$out .= '<option value="'.$id.'"';
4130
			}
4131
			// Print attribute selected or not
4132
			if ($format == 1 || $format == 2) {
4133
				if ($selected == $arraytypes['code']) {
4134
					$out .= ' selected';
4135
				}
4136
			} else {
4137
				if ($selected == $id) {
4138
					$out .= ' selected';
4139
				}
4140
			}
4141
			$out .= '>';
4142
			if ($format == 0) {
4143
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4144
			} elseif ($format == 1) {
4145
				$value = $arraytypes['code'];
4146
			} elseif ($format == 2) {
4147
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4148
			} elseif ($format == 3) {
4149
				$value = $arraytypes['code'];
4150
			}
4151
			$out .= $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...
4152
			$out .= '</option>';
4153
		}
4154
		$out .= '</select>';
4155
		if ($user->admin && !$noadmininfo) {
4156
			$out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4157
		}
4158
		$out .= ajax_combobox('select'.$htmlname);
4159
4160
		if (empty($nooutput)) {
4161
			print $out;
4162
		} else {
4163
			return $out;
4164
		}
4165
	}
4166
4167
4168
	/**
4169
	 *  Selection HT or TTC
4170
	 *
4171
	 *  @param	string	$selected       Id pre-selectionne
4172
	 *  @param  string	$htmlname       Nom de la zone select
4173
	 *  @param	string	$addjscombo		Add js combo
4174
	 * 	@return	string					Code of HTML select to chose tax or not
4175
	 */
4176
	public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4177
	{
4178
		global $langs;
4179
4180
		$return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4181
		$options = array(
4182
			'HT'=>$langs->trans("HT"),
4183
			'TTC'=>$langs->trans("TTC")
4184
		);
4185
		foreach ($options as $id => $value) {
4186
			if ($selected == $id) {
4187
				$return .= '<option value="'.$id.'" selected>'.$value;
4188
			} else {
4189
				$return .= '<option value="'.$id.'">'.$value;
4190
			}
4191
			$return .= '</option>';
4192
		}
4193
		$return .= '</select>';
4194
		if ($addjscombo) {
4195
			$return .= ajax_combobox('select_'.$htmlname);
4196
		}
4197
4198
		return $return;
4199
	}
4200
4201
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4202
	/**
4203
	 *      Load in cache list of transport mode
4204
	 *
4205
	 *      @return     int                 Nb of lines loaded, <0 if KO
4206
	 */
4207
	public function load_cache_transport_mode()
4208
	{
4209
		// phpcs:enable
4210
		global $langs;
4211
4212
		$num = count($this->cache_transport_mode);		// TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4213
		if ($num > 0) {
4214
			return $num; // Cache already loaded
4215
		}
4216
4217
		dol_syslog(__METHOD__, LOG_DEBUG);
4218
4219
		$this->cache_transport_mode = array();
4220
4221
		$sql = "SELECT rowid, code, label, active";
4222
		$sql .= " FROM ".$this->db->prefix()."c_transport_mode";
4223
		$sql .= " WHERE entity IN (".getEntity('c_transport_mode').")";
4224
4225
		$resql = $this->db->query($sql);
4226
		if ($resql) {
4227
			$num = $this->db->num_rows($resql);
4228
			$i = 0;
4229
			while ($i < $num) {
4230
				$obj = $this->db->fetch_object($resql);
4231
4232
				// If traduction exist, we use it else we take the default label
4233
				$label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4234
				$this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4235
				$this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4236
				$this->cache_transport_mode[$obj->rowid]['label'] = $label;
4237
				$this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4238
				$i++;
4239
			}
4240
4241
			$this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4242
4243
			return $num;
4244
		} else {
4245
			dol_print_error($this->db);
4246
			return -1;
4247
		}
4248
	}
4249
4250
	/**
4251
	 *      Return list of transport mode for intracomm report
4252
	 *
4253
	 *      @param	string	$selected       Id of the transport mode pre-selected
4254
	 *      @param  string	$htmlname       Name of the select field
4255
	 *      @param  int		$format         0=id+label, 1=code+code, 2=code+label, 3=id+code
4256
	 *      @param  int		$empty			1=can be empty, 0 else
4257
	 *      @param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
4258
	 *      @param  int		$maxlength      Max length of label
4259
	 *      @param  int     $active         Active or not, -1 = all
4260
	 *      @param  string  $morecss        Add more CSS on select tag
4261
	 * 		@return	void
4262
	 */
4263
	public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4264
	{
4265
		global $langs, $user;
4266
4267
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
4268
4269
		$this->load_cache_transport_mode();
4270
4271
		print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4272
		if ($empty) {
4273
			print '<option value="">&nbsp;</option>';
4274
		}
4275
		foreach ($this->cache_transport_mode as $id => $arraytypes) {
4276
			// If not good status
4277
			if ($active >= 0 && $arraytypes['active'] != $active) {
4278
				continue;
4279
			}
4280
4281
			// We discard empty line if showempty is on because an empty line has already been output.
4282
			if ($empty && empty($arraytypes['code'])) {
4283
				continue;
4284
			}
4285
4286
			if ($format == 0) {
4287
				print '<option value="'.$id.'"';
4288
			} elseif ($format == 1) {
4289
				print '<option value="'.$arraytypes['code'].'"';
4290
			} elseif ($format == 2) {
4291
				print '<option value="'.$arraytypes['code'].'"';
4292
			} elseif ($format == 3) {
4293
				print '<option value="'.$id.'"';
4294
			}
4295
			// If text is selected, we compare with code, else with id
4296
			if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4297
				print ' selected';
4298
			} elseif ($selected == $id) {
4299
				print ' selected';
4300
			}
4301
			print '>';
4302
			if ($format == 0) {
4303
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4304
			} elseif ($format == 1) {
4305
				$value = $arraytypes['code'];
4306
			} elseif ($format == 2) {
4307
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4308
			} elseif ($format == 3) {
4309
				$value = $arraytypes['code'];
4310
			}
4311
			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...
4312
			print '</option>';
4313
		}
4314
		print '</select>';
4315
		if ($user->admin && !$noadmininfo) {
4316
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4317
		}
4318
	}
4319
4320
	/**
4321
	 *  Return a HTML select list of shipping mode
4322
	 *
4323
	 *  @param	string	$selected           Id shipping mode pre-selected
4324
	 *  @param  string	$htmlname           Name of select zone
4325
	 *  @param  string	$filtre             To filter list. This parameter must not come from input of users
4326
	 *  @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.
4327
	 *  @param  string	$moreattrib         To add more attribute on select
4328
	 *	@param	int		$noinfoadmin		0=Add admin info, 1=Disable admin info
4329
	 *  @param	string	$morecss			More CSS
4330
	 * 	@return	void
4331
	 */
4332
	public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4333
	{
4334
		global $langs, $conf, $user;
4335
4336
		$langs->load("admin");
4337
		$langs->load("deliveries");
4338
4339
		$sql = "SELECT rowid, code, libelle as label";
4340
		$sql .= " FROM ".$this->db->prefix()."c_shipment_mode";
4341
		$sql .= " WHERE active > 0";
4342
		if ($filtre) {
4343
			$sql .= " AND ".$filtre;
4344
		}
4345
		$sql .= " ORDER BY libelle ASC";
4346
4347
		dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
4348
		$result = $this->db->query($sql);
4349
		if ($result) {
4350
			$num = $this->db->num_rows($result);
4351
			$i = 0;
4352
			if ($num) {
4353
				print '<select id="select'.$htmlname.'" class="flat selectshippingmethod'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4354
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4355
					print '<option value="-1">&nbsp;</option>';
4356
				}
4357
				while ($i < $num) {
4358
					$obj = $this->db->fetch_object($result);
4359
					if ($selected == $obj->rowid) {
4360
						print '<option value="'.$obj->rowid.'" selected>';
4361
					} else {
4362
						print '<option value="'.$obj->rowid.'">';
4363
					}
4364
					print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
4365
					print '</option>';
4366
					$i++;
4367
				}
4368
				print "</select>";
4369
				if ($user->admin  && empty($noinfoadmin)) {
4370
					print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4371
				}
4372
4373
				print ajax_combobox('select'.$htmlname);
4374
			} else {
4375
				print $langs->trans("NoShippingMethodDefined");
4376
			}
4377
		} else {
4378
			dol_print_error($this->db);
4379
		}
4380
	}
4381
4382
	/**
4383
	 *    Display form to select shipping mode
4384
	 *
4385
	 *    @param	string	$page        Page
4386
	 *    @param    int		$selected    Id of shipping mode
4387
	 *    @param    string	$htmlname    Name of select html field
4388
	 *    @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.
4389
	 *    @return	void
4390
	 */
4391
	public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4392
	{
4393
		global $langs;
4394
4395
		$langs->load("deliveries");
4396
4397
		if ($htmlname != "none") {
4398
			print '<form method="POST" action="'.$page.'">';
4399
			print '<input type="hidden" name="action" value="setshippingmethod">';
4400
			print '<input type="hidden" name="token" value="'.newToken().'">';
4401
			$this->selectShippingMethod($selected, $htmlname, '', $addempty);
4402
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4403
			print '</form>';
4404
		} else {
4405
			if ($selected) {
4406
				$code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4407
				print $langs->trans("SendingMethod".strtoupper($code));
4408
			} else {
4409
				print "&nbsp;";
4410
			}
4411
		}
4412
	}
4413
4414
	/**
4415
	 * Creates HTML last in cycle situation invoices selector
4416
	 *
4417
	 * @param     string  $selected   		Preselected ID
4418
	 * @param     int     $socid      		Company ID
4419
	 *
4420
	 * @return    string                     HTML select
4421
	 */
4422
	public function selectSituationInvoices($selected = '', $socid = 0)
4423
	{
4424
		global $langs;
4425
4426
		$langs->load('bills');
4427
4428
		$opt = '<option value="" selected></option>';
4429
		$sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4430
		$sql .= ' FROM '.$this->db->prefix().'facture';
4431
		$sql .= ' WHERE entity IN ('.getEntity('invoice').')';
4432
		$sql .= ' AND situation_counter >= 1';
4433
		$sql .= ' AND fk_soc = '.(int) $socid;
4434
		$sql .= ' AND type <> 2';
4435
		$sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4436
		$resql = $this->db->query($sql);
4437
4438
		if ($resql && $this->db->num_rows($resql) > 0) {
4439
			// Last seen cycle
4440
			$ref = 0;
4441
			while ($obj = $this->db->fetch_object($resql)) {
4442
				//Same cycle ?
4443
				if ($obj->situation_cycle_ref != $ref) {
4444
					// Just seen this cycle
4445
					$ref = $obj->situation_cycle_ref;
4446
					//not final ?
4447
					if ($obj->situation_final != 1) {
4448
						//Not prov?
4449
						if (substr($obj->ref, 1, 4) != 'PROV') {
4450
							if ($selected == $obj->rowid) {
4451
								$opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
4452
							} else {
4453
								$opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
4454
							}
4455
						}
4456
					}
4457
				}
4458
			}
4459
		} else {
4460
				dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
4461
		}
4462
		if ($opt == '<option value ="" selected></option>') {
4463
			$opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
4464
		}
4465
		return $opt;
4466
	}
4467
4468
	/**
4469
	 *      Creates HTML units selector (code => label)
4470
	 *
4471
	 *      @param	string	$selected       Preselected Unit ID
4472
	 *      @param  string	$htmlname       Select name
4473
	 *      @param	int		$showempty		Add a nempty line
4474
	 *      @param  string  $unit_type      Restrict to one given unit type
4475
	 * 		@return	string                  HTML select
4476
	 */
4477
	public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4478
	{
4479
		global $langs;
4480
4481
		$langs->load('products');
4482
4483
		$return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
4484
4485
		$sql = "SELECT rowid, label, code FROM ".$this->db->prefix()."c_units";
4486
		$sql .= ' WHERE active > 0';
4487
		if (!empty($unit_type)) {
4488
			$sql .= " AND unit_type = '".$this->db->escape($unit_type)."'";
4489
		}
4490
		$sql .= " ORDER BY sortorder";
4491
4492
		$resql = $this->db->query($sql);
4493
		if ($resql && $this->db->num_rows($resql) > 0) {
4494
			if ($showempty) {
4495
				$return .= '<option value="none"></option>';
4496
			}
4497
4498
			while ($res = $this->db->fetch_object($resql)) {
4499
				$unitLabel = $res->label;
4500
				if (!empty($langs->tab_translate['unit'.$res->code])) {	// check if Translation is available before
4501
					$unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
4502
				}
4503
4504
				if ($selected == $res->rowid) {
4505
					$return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
4506
				} else {
4507
					$return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
4508
				}
4509
			}
4510
			$return .= '</select>';
4511
		}
4512
		return $return;
4513
	}
4514
4515
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4516
	/**
4517
	 *  Return a HTML select list of bank accounts
4518
	 *
4519
	 *  @param	string	$selected           Id account pre-selected
4520
	 *  @param  string	$htmlname           Name of select zone
4521
	 *  @param  int		$status             Status of searched accounts (0=open, 1=closed, 2=both)
4522
	 *  @param  string	$filtre             To filter list. This parameter must not come from input of users
4523
	 *  @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.
4524
	 *  @param  string	$moreattrib         To add more attribute on select
4525
	 *  @param	int		$showcurrency		Show currency in label
4526
	 *  @param	string	$morecss			More CSS
4527
	 *  @param	int		$nooutput			1=Return string, do not send to output
4528
	 * 	@return	int							<0 if error, Num of bank account found if OK (0, 1, 2, ...)
4529
	 */
4530
	public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4531
	{
4532
		// phpcs:enable
4533
		global $langs, $conf;
4534
4535
		$out = '';
4536
4537
		$langs->load("admin");
4538
		$num = 0;
4539
4540
		$sql = "SELECT rowid, label, bank, clos as status, currency_code";
4541
		$sql .= " FROM ".$this->db->prefix()."bank_account";
4542
		$sql .= " WHERE entity IN (".getEntity('bank_account').")";
4543
		if ($status != 2) {
4544
			$sql .= " AND clos = ".(int) $status;
4545
		}
4546
		if ($filtre) {
4547
			$sql .= " AND ".$filtre;
4548
		}
4549
		$sql .= " ORDER BY label";
4550
4551
		dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
4552
		$result = $this->db->query($sql);
4553
		if ($result) {
4554
			$num = $this->db->num_rows($result);
4555
			$i = 0;
4556
			if ($num) {
4557
				$out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4558
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4559
					$out .= '<option value="-1">&nbsp;</option>';
4560
				}
4561
4562
				while ($i < $num) {
4563
					$obj = $this->db->fetch_object($result);
4564
					if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4565
						$out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'" selected>';
4566
					} else {
4567
						$out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'">';
4568
					}
4569
					$out .= trim($obj->label);
4570
					if ($showcurrency) {
4571
						$out .= ' ('.$obj->currency_code.')';
4572
					}
4573
					if ($status == 2 && $obj->status == 1) {
4574
						$out .= ' ('.$langs->trans("Closed").')';
4575
					}
4576
					$out .= '</option>';
4577
					$i++;
4578
				}
4579
				$out .= "</select>";
4580
				$out .= ajax_combobox('select'.$htmlname);
4581
			} else {
4582
				if ($status == 0) {
4583
					$out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
4584
				} else {
4585
					$out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
4586
				}
4587
			}
4588
		} else {
4589
			dol_print_error($this->db);
4590
		}
4591
4592
		// Output or return
4593
		if (empty($nooutput)) {
4594
			print $out;
4595
		} else {
4596
			return $out;
4597
		}
4598
4599
		return $num;
4600
	}
4601
4602
	/**
4603
	 *  Return a HTML select list of establishment
4604
	 *
4605
	 *  @param	string	$selected           Id establishment pre-selected
4606
	 *  @param  string	$htmlname           Name of select zone
4607
	 *  @param  int		$status             Status of searched establishment (0=open, 1=closed, 2=both)
4608
	 *  @param  string	$filtre             To filter list. This parameter must not come from input of users
4609
	 *  @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.
4610
	 *  @param  string	$moreattrib         To add more attribute on select
4611
	 * 	@return	int							<0 if error, Num of establishment found if OK (0, 1, 2, ...)
4612
	 */
4613
	public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4614
	{
4615
		global $langs, $conf;
4616
4617
		$langs->load("admin");
4618
		$num = 0;
4619
4620
		$sql = "SELECT rowid, name, fk_country, status, entity";
4621
		$sql .= " FROM ".$this->db->prefix()."establishment";
4622
		$sql .= " WHERE 1=1";
4623
		if ($status != 2) {
4624
			$sql .= " AND status = ".(int) $status;
4625
		}
4626
		if ($filtre) {
4627
			$sql .= " AND ".$filtre;
4628
		}
4629
		$sql .= " ORDER BY name";
4630
4631
		dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
4632
		$result = $this->db->query($sql);
4633
		if ($result) {
4634
			$num = $this->db->num_rows($result);
4635
			$i = 0;
4636
			if ($num) {
4637
				print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4638
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4639
					print '<option value="-1">&nbsp;</option>';
4640
				}
4641
4642
				while ($i < $num) {
4643
					$obj = $this->db->fetch_object($result);
4644
					if ($selected == $obj->rowid) {
4645
						print '<option value="'.$obj->rowid.'" selected>';
4646
					} else {
4647
						print '<option value="'.$obj->rowid.'">';
4648
					}
4649
					print trim($obj->name);
4650
					if ($status == 2 && $obj->status == 1) {
4651
						print ' ('.$langs->trans("Closed").')';
4652
					}
4653
					print '</option>';
4654
					$i++;
4655
				}
4656
				print "</select>";
4657
			} else {
4658
				if ($status == 0) {
4659
					print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
4660
				} else {
4661
					print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
4662
				}
4663
			}
4664
		} else {
4665
			dol_print_error($this->db);
4666
		}
4667
	}
4668
4669
	/**
4670
	 *    Display form to select bank account
4671
	 *
4672
	 *    @param	string	$page        Page
4673
	 *    @param    int		$selected    Id of bank account
4674
	 *    @param    string	$htmlname    Name of select html field
4675
	 *    @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.
4676
	 *    @return	void
4677
	 */
4678
	public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4679
	{
4680
		global $langs;
4681
		if ($htmlname != "none") {
4682
			print '<form method="POST" action="'.$page.'">';
4683
			print '<input type="hidden" name="action" value="setbankaccount">';
4684
			print '<input type="hidden" name="token" value="'.newToken().'">';
4685
			print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4686
			$nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4687
			if ($nbaccountfound > 0) {
4688
				print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4689
			}
4690
			print '</form>';
4691
		} else {
4692
			$langs->load('banks');
4693
4694
			if ($selected) {
4695
				require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
4696
				$bankstatic = new Account($this->db);
4697
				$result = $bankstatic->fetch($selected);
4698
				if ($result) {
4699
					print $bankstatic->getNomUrl(1);
4700
				}
4701
			} else {
4702
				print "&nbsp;";
4703
			}
4704
		}
4705
	}
4706
4707
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4708
	/**
4709
	 *    Return list of categories having choosed type
4710
	 *
4711
	 *    @param	string|int	            $type				Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
4712
	 *    @param    string		            $selected    		Id of category preselected or 'auto' (autoselect category if there is only one element). Not used if $outputmode = 1.
4713
	 *    @param    string		            $htmlname			HTML field name
4714
	 *    @param    int			            $maxlength      	Maximum length for labels
4715
	 *    @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.
4716
	 *                                                          $markafterid can be an :
4717
	 *                                                          - int (id of category)
4718
	 *                                                          - string (categories ids seprated by comma)
4719
	 *                                                          - array (list of categories ids)
4720
	 *    @param	int			            $outputmode			0=HTML select string, 1=Array
4721
	 *    @param	int			            $include			[=0] Removed or 1=Keep only
4722
	 *    @param	string					$morecss			More CSS
4723
	 *    @return	string
4724
	 *    @see select_categories()
4725
	 */
4726
	public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4727
	{
4728
		// phpcs:enable
4729
		global $conf, $langs;
4730
		$langs->load("categories");
4731
4732
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4733
4734
		// For backward compatibility
4735
		if (is_numeric($type)) {
4736
			dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4737
		}
4738
4739
		if ($type === Categorie::TYPE_BANK_LINE) {
4740
			// TODO Move this into common category feature
4741
			$cate_arbo = array();
4742
			$sql = "SELECT c.label, c.rowid";
4743
			$sql .= " FROM ".$this->db->prefix()."bank_categ as c";
4744
			$sql .= " WHERE entity = ".$conf->entity;
4745
			$sql .= " ORDER BY c.label";
4746
			$result = $this->db->query($sql);
4747
			if ($result) {
4748
				$num = $this->db->num_rows($result);
4749
				$i = 0;
4750
				while ($i < $num) {
4751
					$objp = $this->db->fetch_object($result);
4752
					if ($objp) {
4753
						$cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
4754
					}
4755
					$i++;
4756
				}
4757
				$this->db->free($result);
4758
			} else {
4759
				dol_print_error($this->db);
4760
			}
4761
		} else {
4762
			$cat = new Categorie($this->db);
4763
			$cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4764
		}
4765
4766
		$output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4767
		$outarray = array();
4768
		if (is_array($cate_arbo)) {
4769
			if (!count($cate_arbo)) {
4770
				$output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4771
			} else {
4772
				$output .= '<option value="-1">&nbsp;</option>';
4773
				foreach ($cate_arbo as $key => $value) {
4774
					if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
4775
						$add = 'selected ';
4776
					} else {
4777
						$add = '';
4778
					}
4779
					$output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>';
4780
4781
					$outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4782
				}
4783
			}
4784
		}
4785
		$output .= '</select>';
4786
		$output .= "\n";
4787
4788
		if ($outputmode) {
4789
			return $outarray;
4790
		}
4791
		return $output;
4792
	}
4793
4794
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4795
	/**
4796
	 *     Show a confirmation HTML form or AJAX popup
4797
	 *
4798
	 *     @param	string		$page        	   	Url of page to call if confirmation is OK
4799
	 *     @param	string		$title       	   	Title
4800
	 *     @param	string		$question    	   	Question
4801
	 *     @param 	string		$action      	   	Action
4802
	 *	   @param	array		$formquestion	   	An array with forms complementary inputs
4803
	 * 	   @param	string		$selectedchoice		"" or "no" or "yes"
4804
	 * 	   @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
4805
	 *     @param	int			$height          	Force height of box
4806
	 *     @param	int			$width				Force width of box
4807
	 *     @return 	void
4808
	 *     @deprecated
4809
	 *     @see formconfirm()
4810
	 */
4811
	public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4812
	{
4813
		// phpcs:enable
4814
		dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4815
		print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4816
	}
4817
4818
	/**
4819
	 *     Show a confirmation HTML form or AJAX popup.
4820
	 *     Easiest way to use this is with useajax=1.
4821
	 *     If you use useajax='xxx', you must also add jquery code to trigger opening of box (with correct parameters)
4822
	 *     just after calling this method. For example:
4823
	 *       print '<script type="text/javascript">'."\n";
4824
	 *       print 'jQuery(document).ready(function() {'."\n";
4825
	 *       print 'jQuery(".xxxlink").click(function(e) { jQuery("#aparamid").val(jQuery(this).attr("rel")); jQuery("#dialog-confirm-xxx").dialog("open"); return false; });'."\n";
4826
	 *       print '});'."\n";
4827
	 *       print '</script>'."\n";
4828
	 *
4829
	 *     @param  	string			$page        	   	Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated)
4830
	 *     @param	string			$title       	   	Title
4831
	 *     @param	string			$question    	   	Question
4832
	 *     @param 	string			$action      	   	Action
4833
	 *	   @param  	array|string	$formquestion	   	An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>))
4834
	 *													type can be 'hidden', 'text', 'password', 'checkbox', 'radio', 'date', 'morecss', 'other' or 'onecolumn'...
4835
	 * 	   @param  	string			$selectedchoice  	'' or 'no', or 'yes' or '1' or '0'
4836
	 * 	   @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
4837
	 *     @param  	int|string		$height          	Force height of box (0 = auto)
4838
	 *     @param	int				$width				Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones.
4839
	 *     @param	int				$disableformtag		1=Disable form tag. Can be used if we are already inside a <form> section.
4840
	 *     @return 	string      		    			HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form
4841
	 */
4842
	public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0)
4843
	{
4844
		global $langs, $conf;
4845
4846
		$more = '<!-- formconfirm before calling page='.dol_escape_htmltag($page).' -->';
4847
		$formconfirm = '';
4848
		$inputok = array();
4849
		$inputko = array();
4850
4851
		// Clean parameters
4852
		$newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
4853
		if ($conf->browser->layout == 'phone') {
4854
			$width = '95%';
4855
		}
4856
4857
		// Set height automatically if not defined
4858
		if (empty($height)) {
4859
			$height = 220;
4860
			if (is_array($formquestion) && count($formquestion) > 2) {
4861
				$height += ((count($formquestion) - 2) * 24);
4862
			}
4863
		}
4864
4865
		if (is_array($formquestion) && !empty($formquestion)) {
4866
			// First add hidden fields and value
4867
			foreach ($formquestion as $key => $input) {
4868
				if (is_array($input) && !empty($input)) {
4869
					if ($input['type'] == 'hidden') {
4870
						$more .= '<input type="hidden" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
4871
					}
4872
				}
4873
			}
4874
4875
			// Now add questions
4876
			$moreonecolumn = '';
4877
			$more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
4878
			foreach ($formquestion as $key => $input) {
4879
				if (is_array($input) && !empty($input)) {
4880
					$size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : '');	// deprecated. Use morecss instead.
4881
					$moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4882
					$morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4883
4884
					if ($input['type'] == 'text') {
4885
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="text" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4886
					} elseif ($input['type'] == 'password')	{
4887
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="password" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4888
					} elseif ($input['type'] == 'textarea') {
4889
						/*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
4890
						$more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
4891
						$more .= $input['value'];
4892
						$more .= '</textarea>';
4893
						$more .= '</div></div>'."\n";*/
4894
						$moreonecolumn .= '<div class="margintoponly">';
4895
						$moreonecolumn .= $input['label'].'<br>';
4896
						$moreonecolumn .= '<textarea name="'.dol_escape_htmltag($input['name']).'" id="'.dol_escape_htmltag($input['name']).'" class="'.$morecss.'"'.$moreattr.'>';
4897
						$moreonecolumn .= $input['value'];
4898
						$moreonecolumn .= '</textarea>';
4899
						$moreonecolumn .= '</div>';
4900
					} elseif ($input['type'] == 'select') {
4901
						if (empty($morecss)) {
4902
							$morecss = 'minwidth100';
4903
						}
4904
4905
						$show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
4906
						$key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
4907
						$value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
4908
						$translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
4909
						$maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
4910
						$disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
4911
						$sort = isset($input['select_sort']) ? $input['select_sort'] : '';
4912
4913
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4914
						if (!empty($input['label'])) {
4915
							$more .= $input['label'].'</div><div class="tagtd left">';
4916
						}
4917
						$more .= $this->selectarray($input['name'], $input['values'], $input['default'], $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
4918
						$more .= '</div></div>'."\n";
4919
					} elseif ($input['type'] == 'checkbox') {
4920
						$more .= '<div class="tagtr">';
4921
						$more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
4922
						$more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name']).'" name="'.dol_escape_htmltag($input['name']).'"'.$moreattr;
4923
						if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
4924
							$more .= ' checked';
4925
						}
4926
						if (is_bool($input['value']) && $input['value']) {
4927
							$more .= ' checked';
4928
						}
4929
						if (isset($input['disabled'])) {
4930
							$more .= ' disabled';
4931
						}
4932
						$more .= ' /></div>';
4933
						$more .= '</div>'."\n";
4934
					} elseif ($input['type'] == 'radio') {
4935
						$i = 0;
4936
						foreach ($input['values'] as $selkey => $selval) {
4937
							$more .= '<div class="tagtr">';
4938
							if ($i == 0) {
4939
								$more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
4940
							} else {
4941
								$more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
4942
							}
4943
							$more .= '<div class="tagtd'.($i == 0 ? ' tdtop' : '').'"><input type="radio" class="flat'.$morecss.'" id="'.dol_escape_htmltag($input['name'].$selkey).'" name="'.dol_escape_htmltag($input['name']).'" value="'.$selkey.'"'.$moreattr;
4944
							if ($input['disabled']) {
4945
								$more .= ' disabled';
4946
							}
4947
							if (isset($input['default']) && $input['default'] === $selkey) {
4948
								$more .= ' checked="checked"';
4949
							}
4950
							$more .= ' /> ';
4951
							$more .= '<label for="'.dol_escape_htmltag($input['name'].$selkey).'">'.$selval.'</label>';
4952
							$more .= '</div></div>'."\n";
4953
							$i++;
4954
						}
4955
					} elseif ($input['type'] == 'date') {
4956
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
4957
						$more .= '<div class="tagtd">';
4958
						$addnowlink = (empty($input['datenow']) ? 0 : 1);
4959
						$more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, $addnowlink);
4960
						$more .= '</div></div>'."\n";
4961
						$formquestion[] = array('name'=>$input['name'].'day');
4962
						$formquestion[] = array('name'=>$input['name'].'month');
4963
						$formquestion[] = array('name'=>$input['name'].'year');
4964
						$formquestion[] = array('name'=>$input['name'].'hour');
4965
						$formquestion[] = array('name'=>$input['name'].'min');
4966
					} elseif ($input['type'] == 'other') {
4967
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4968
						if (!empty($input['label'])) {
4969
							$more .= $input['label'].'</div><div class="tagtd">';
4970
						}
4971
						$more .= $input['value'];
4972
						$more .= '</div></div>'."\n";
4973
					} elseif ($input['type'] == 'onecolumn') {
4974
						$moreonecolumn .= '<div class="margintoponly">';
4975
						$moreonecolumn .= $input['value'];
4976
						$moreonecolumn .= '</div>'."\n";
4977
					} elseif ($input['type'] == 'hidden') {
4978
						// Do nothing more, already added by a previous loop
4979
					} elseif ($input['type'] == 'separator') {
4980
						$more .= '<br>';
4981
					} else {
4982
						$more .= 'Error type '.$input['type'].' for the confirm box is not a supported type';
4983
					}
4984
				}
4985
			}
4986
			$more .= '</div>'."\n";
4987
			$more .= $moreonecolumn;
4988
		}
4989
4990
		// JQUERY method dialog is broken with smartphone, we use standard HTML.
4991
		// 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
4992
		// See page product/card.php for example
4993
		if (!empty($conf->dol_use_jmobile)) {
4994
			$useajax = 0;
4995
		}
4996
		if (empty($conf->use_javascript_ajax)) {
4997
			$useajax = 0;
4998
		}
4999
5000
		if ($useajax) {
5001
			$autoOpen = true;
5002
			$dialogconfirm = 'dialog-confirm';
5003
			$button = '';
5004
			if (!is_numeric($useajax)) {
5005
				$button = $useajax;
5006
				$useajax = 1;
5007
				$autoOpen = false;
5008
				$dialogconfirm .= '-'.$button;
5009
			}
5010
			$pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.$action.'&confirm=yes';
5011
			$pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'confirm=no' : '');
5012
5013
			// Add input fields into list of fields to read during submit (inputok and inputko)
5014
			if (is_array($formquestion)) {
5015
				foreach ($formquestion as $key => $input) {
5016
					//print "xx ".$key." rr ".is_array($input)."<br>\n";
5017
					// Add name of fields to propagate with the GET when submitting the form with button OK.
5018
					if (is_array($input) && isset($input['name'])) {
5019
						if (strpos($input['name'], ',') > 0) {
5020
							$inputok = array_merge($inputok, explode(',', $input['name']));
5021
						} else {
5022
							array_push($inputok, $input['name']);
5023
						}
5024
					}
5025
					// Add name of fields to propagate with the GET when submitting the form with button KO.
5026
					if (isset($input['inputko']) && $input['inputko'] == 1) {
5027
						array_push($inputko, $input['name']);
5028
					}
5029
				}
5030
			}
5031
5032
			// Show JQuery confirm box.
5033
			$formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
5034
			if (is_array($formquestion) && !empty($formquestion['text'])) {
5035
				$formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
5036
			}
5037
			if (!empty($more)) {
5038
				$formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
5039
			}
5040
			$formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
5041
			$formconfirm .= '</div>'."\n";
5042
5043
			$formconfirm .= "\n<!-- begin code of popup for formconfirm page=".$page." -->\n";
5044
			$formconfirm .= '<script type="text/javascript">'."\n";
5045
			$formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5046
			$formconfirm .= 'jQuery(document).ready(function() {
5047
            $(function() {
5048
            	$( "#'.$dialogconfirm.'" ).dialog(
5049
            	{
5050
                    autoOpen: '.($autoOpen ? "true" : "false").',';
5051
			if ($newselectedchoice == 'no') {
5052
				$formconfirm .= '
5053
						open: function() {
5054
            				$(this).parent().find("button.ui-button:eq(2)").focus();
5055
						},';
5056
			}
5057
			$formconfirm .= '
5058
                    resizable: false,
5059
                    height: "'.$height.'",
5060
                    width: "'.$width.'",
5061
                    modal: true,
5062
                    closeOnEscape: false,
5063
                    buttons: {
5064
                        "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
5065
                        	var options = "&token='.urlencode(newToken()).'";
5066
                        	var inputok = '.json_encode($inputok).';	/* List of fields into form */
5067
                         	var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
5068
                         	if (inputok.length>0) {
5069
                         		$.each(inputok, function(i, inputname) {
5070
                         			var more = "";
5071
									var inputvalue;
5072
                         			if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5073
										inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5074
									} else {
5075
                         		    	if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5076
                         				inputvalue = $("#" + inputname + more).val();
5077
									}
5078
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
5079
									console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5080
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5081
                         		});
5082
                         	}
5083
                         	var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
5084
            				if (pageyes.length > 0) { location.href = urljump; }
5085
                            $(this).dialog("close");
5086
                        },
5087
                        "'.dol_escape_js($langs->transnoentities("No")).'": function() {
5088
                        	var options = "&token='.urlencode(newToken()).'";
5089
                         	var inputko = '.json_encode($inputko).';	/* List of fields into form */
5090
                         	var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
5091
                         	if (inputko.length>0) {
5092
                         		$.each(inputko, function(i, inputname) {
5093
                         			var more = "";
5094
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5095
                         			var inputvalue = $("#" + inputname + more).val();
5096
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
5097
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5098
                         		});
5099
                         	}
5100
                         	var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
5101
                         	//alert(urljump);
5102
            				if (pageno.length > 0) { location.href = urljump; }
5103
                            $(this).dialog("close");
5104
                        }
5105
                    }
5106
                }
5107
                );
5108
5109
            	var button = "'.$button.'";
5110
            	if (button.length > 0) {
5111
                	$( "#" + button ).click(function() {
5112
                		$("#'.$dialogconfirm.'").dialog("open");
5113
        			});
5114
                }
5115
            });
5116
            });
5117
            </script>';
5118
			$formconfirm .= "<!-- end ajax formconfirm -->\n";
5119
		} else {
5120
			$formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n";
5121
5122
			if (empty($disableformtag)) {
5123
				$formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
5124
			}
5125
5126
			$formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
5127
			$formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
5128
5129
			$formconfirm .= '<table class="valid centpercent">'."\n";
5130
5131
			// Line title
5132
			$formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5133
			$formconfirm .= img_picto('', 'recent').' '.$title;
5134
			$formconfirm .= '</td></tr>'."\n";
5135
5136
			// Line text
5137
			if (is_array($formquestion) && !empty($formquestion['text'])) {
5138
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
5139
			}
5140
5141
			// Line form fields
5142
			if ($more) {
5143
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'."\n";
5144
				$formconfirm .= $more;
5145
				$formconfirm .= '</td></tr>'."\n";
5146
			}
5147
5148
			// Line with question
5149
			$formconfirm .= '<tr class="valid">';
5150
			$formconfirm .= '<td class="valid">'.$question.'</td>';
5151
			$formconfirm .= '<td class="valid center">';
5152
			$formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly');
5153
			$formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="'.$langs->trans("Validate").'">';
5154
			$formconfirm .= '</td>';
5155
			$formconfirm .= '</tr>'."\n";
5156
5157
			$formconfirm .= '</table>'."\n";
5158
5159
			if (empty($disableformtag)) {
5160
				$formconfirm .= "</form>\n";
5161
			}
5162
			$formconfirm .= '<br>';
5163
5164
			if (!empty($conf->use_javascript_ajax)) {
5165
				$formconfirm .= '<!-- code to disable button to avoid double clic -->';
5166
				$formconfirm .= '<script type="text/javascript">'."\n";
5167
				$formconfirm .= '
5168
				$(document).ready(function () {
5169
					$(".confirmvalidatebutton").on("click", function() {
5170
						console.log("We click on button");
5171
						$(this).attr("disabled", "disabled");
5172
						setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5173
						//console.log($(this).closest("form"));
5174
						$(this).closest("form").submit();
5175
					});
5176
				});
5177
				';
5178
				$formconfirm .= '</script>'."\n";
5179
			}
5180
5181
			$formconfirm .= "<!-- end formconfirm -->\n";
5182
		}
5183
5184
		return $formconfirm;
5185
	}
5186
5187
5188
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5189
	/**
5190
	 *    Show a form to select a project
5191
	 *
5192
	 *    @param	int		$page        		Page
5193
	 *    @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)
5194
	 *    @param    int		$selected    		Id pre-selected project
5195
	 *    @param    string	$htmlname    		Name of select field
5196
	 *    @param	int		$discard_closed		Discard closed projects (0=Keep,1=hide completely except $selected,2=Disable)
5197
	 *    @param	int		$maxlength			Max length
5198
	 *    @param	int		$forcefocus			Force focus on field (works with javascript only)
5199
	 *    @param    int     $nooutput           No print is done. String is returned.
5200
	 *    @return	string                      Return html content
5201
	 */
5202
	public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0)
5203
	{
5204
		// phpcs:enable
5205
		global $langs;
5206
5207
		require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
5208
		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
5209
5210
		$out = '';
5211
5212
		$formproject = new FormProjets($this->db);
5213
5214
		$langs->load("project");
5215
		if ($htmlname != "none") {
5216
			$out .= "\n";
5217
			$out .= '<form method="post" action="'.$page.'">';
5218
			$out .= '<input type="hidden" name="action" value="classin">';
5219
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
5220
			$out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
5221
			$out .= '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5222
			$out .= '</form>';
5223
		} else {
5224
			$out .= '<span class="project_head_block">';
5225
			if ($selected) {
5226
				$projet = new Project($this->db);
5227
				$projet->fetch($selected);
5228
				$out .= $projet->getNomUrl(1, '', 1);
5229
			} else {
5230
				$out .= "&nbsp;";
5231
			}
5232
			$out .= '</span>';
5233
		}
5234
5235
		if (empty($nooutput)) {
5236
			print $out;
5237
			return '';
5238
		}
5239
		return $out;
5240
	}
5241
5242
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5243
	/**
5244
	 *	Show a form to select payment conditions
5245
	 *
5246
	 *  @param	int		$page        	Page
5247
	 *  @param  string	$selected    	Id condition pre-selectionne
5248
	 *  @param  string	$htmlname    	Name of select html field
5249
	 *	@param	int		$addempty		Add empty entry
5250
	 *  @param	string	$type			Type ('direct-debit' or 'bank-transfer')
5251
	 *  @return	void
5252
	 */
5253
	public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '')
5254
	{
5255
		// phpcs:enable
5256
		global $langs;
5257
		if ($htmlname != "none") {
5258
			print '<form method="POST" action="'.$page.'">';
5259
			print '<input type="hidden" name="action" value="setconditions">';
5260
			print '<input type="hidden" name="token" value="'.newToken().'">';
5261
			if ($type) {
5262
				print '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5263
			}
5264
			$this->select_conditions_paiements($selected, $htmlname, -1, $addempty, 0, '');
5265
			print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
5266
			print '</form>';
5267
		} else {
5268
			if ($selected) {
5269
				$this->load_cache_conditions_paiements();
5270
				if (isset($this->cache_conditions_paiements[$selected])) {
5271
					print $this->cache_conditions_paiements[$selected]['label'];
5272
				} else {
5273
					$langs->load('errors');
5274
					print $langs->trans('ErrorNotInDictionaryPaymentConditions');
5275
				}
5276
			} else {
5277
				print "&nbsp;";
5278
			}
5279
		}
5280
	}
5281
5282
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5283
	/**
5284
	 *  Show a form to select a delivery delay
5285
	 *
5286
	 *  @param  int		$page        	Page
5287
	 *  @param  string	$selected    	Id condition pre-selectionne
5288
	 *  @param  string	$htmlname    	Name of select html field
5289
	 *	@param	int		$addempty		Ajoute entree vide
5290
	 *  @return	void
5291
	 */
5292
	public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5293
	{
5294
		// phpcs:enable
5295
		global $langs;
5296
		if ($htmlname != "none") {
5297
			print '<form method="post" action="'.$page.'">';
5298
			print '<input type="hidden" name="action" value="setavailability">';
5299
			print '<input type="hidden" name="token" value="'.newToken().'">';
5300
			$this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5301
			print '<input type="submit" name="modify" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5302
			print '<input type="submit" name="cancel" class="button smallpaddingimp" value="'.$langs->trans("Cancel").'">';
5303
			print '</form>';
5304
		} else {
5305
			if ($selected) {
5306
				$this->load_cache_availability();
5307
				print $this->cache_availability[$selected]['label'];
5308
			} else {
5309
				print "&nbsp;";
5310
			}
5311
		}
5312
	}
5313
5314
	/**
5315
	 *  Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
5316
	 *  List found into table c_input_reason loaded by loadCacheInputReason
5317
	 *
5318
	 *  @param  string	$page        	Page
5319
	 *  @param  string	$selected    	Id condition pre-selectionne
5320
	 *  @param  string	$htmlname    	Name of select html field
5321
	 *  @param	int		$addempty		Add empty entry
5322
	 *  @return	void
5323
	 */
5324
	public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5325
	{
5326
		global $langs;
5327
		if ($htmlname != "none") {
5328
			print '<form method="post" action="'.$page.'">';
5329
			print '<input type="hidden" name="action" value="setdemandreason">';
5330
			print '<input type="hidden" name="token" value="'.newToken().'">';
5331
			$this->selectInputReason($selected, $htmlname, -1, $addempty);
5332
			print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5333
			print '</form>';
5334
		} else {
5335
			if ($selected) {
5336
				$this->loadCacheInputReason();
5337
				foreach ($this->cache_demand_reason as $key => $val) {
5338
					if ($val['id'] == $selected) {
5339
						print $val['label'];
5340
						break;
5341
					}
5342
				}
5343
			} else {
5344
				print "&nbsp;";
5345
			}
5346
		}
5347
	}
5348
5349
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5350
	/**
5351
	 *    Show a form + html select a date
5352
	 *
5353
	 *    @param	string		$page        	Page
5354
	 *    @param	string		$selected    	Date preselected
5355
	 *    @param    string		$htmlname    	Html name of date input fields or 'none'
5356
	 *    @param    int			$displayhour 	Display hour selector
5357
	 *    @param    int			$displaymin		Display minutes selector
5358
	 *    @param	int			$nooutput		1=No print output, return string
5359
	 *    @param	string		$type			'direct-debit' or 'bank-transfer'
5360
	 *    @return	string
5361
	 *    @see		selectDate()
5362
	 */
5363
	public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
5364
	{
5365
		// phpcs:enable
5366
		global $langs;
5367
5368
		$ret = '';
5369
5370
		if ($htmlname != "none") {
5371
			$ret .= '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5372
			$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
5373
			$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
5374
			if ($type) {
5375
				$ret .= '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5376
			}
5377
			$ret .= '<table class="nobordernopadding">';
5378
			$ret .= '<tr><td>';
5379
			$ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
5380
			$ret .= '</td>';
5381
			$ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5382
			$ret .= '</tr></table></form>';
5383
		} else {
5384
			if ($displayhour) {
5385
				$ret .= dol_print_date($selected, 'dayhour');
5386
			} else {
5387
				$ret .= dol_print_date($selected, 'day');
5388
			}
5389
		}
5390
5391
		if (empty($nooutput)) {
5392
			print $ret;
5393
		}
5394
		return $ret;
5395
	}
5396
5397
5398
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5399
	/**
5400
	 *  Show a select form to choose a user
5401
	 *
5402
	 *  @param	string	$page        	Page
5403
	 *  @param  string	$selected    	Id of user preselected
5404
	 *  @param  string	$htmlname    	Name of input html field. If 'none', we just output the user link.
5405
	 *  @param  array	$exclude		List of users id to exclude
5406
	 *  @param  array	$include        List of users id to include
5407
	 *  @return	void
5408
	 */
5409
	public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
5410
	{
5411
		// phpcs:enable
5412
		global $langs;
5413
5414
		if ($htmlname != "none") {
5415
			print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5416
			print '<input type="hidden" name="action" value="set'.$htmlname.'">';
5417
			print '<input type="hidden" name="token" value="'.newToken().'">';
5418
			print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5419
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5420
			print '</form>';
5421
		} else {
5422
			if ($selected) {
5423
				require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
5424
				$theuser = new User($this->db);
5425
				$theuser->fetch($selected);
5426
				print $theuser->getNomUrl(1);
5427
			} else {
5428
				print "&nbsp;";
5429
			}
5430
		}
5431
	}
5432
5433
5434
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5435
	/**
5436
	 *    Show form with payment mode
5437
	 *
5438
	 *    @param	string	$page        	Page
5439
	 *    @param    int		$selected    	Id mode pre-selectionne
5440
	 *    @param    string	$htmlname    	Name of select html field
5441
	 *    @param  	string	$filtertype		To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz))
5442
	 *    @param    int     $active         Active or not, -1 = all
5443
	 *    @param   	int     $addempty       1=Add empty entry
5444
	 *    @param	string	$type			Type ('direct-debit' or 'bank-transfer')
5445
	 *    @return	void
5446
	 */
5447
	public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '')
5448
	{
5449
		// phpcs:enable
5450
		global $langs;
5451
		if ($htmlname != "none") {
5452
			print '<form method="POST" action="'.$page.'">';
5453
			print '<input type="hidden" name="action" value="setmode">';
5454
			print '<input type="hidden" name="token" value="'.newToken().'">';
5455
			if ($type) {
5456
				print '<input type="hidden" name="type" value="'.dol_escape_htmltag($type).'">';
5457
			}
5458
			print $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->select_types_paie..., 0, 0, $active, '', 1) targeting Form::select_types_paiements() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
5459
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5460
			print '</form>';
5461
		} else {
5462
			if ($selected) {
5463
				$this->load_cache_types_paiements();
5464
				print $this->cache_types_paiements[$selected]['label'];
5465
			} else {
5466
				print "&nbsp;";
5467
			}
5468
		}
5469
	}
5470
5471
	/**
5472
	 *    Show form with transport mode
5473
	 *
5474
	 *    @param	string	$page        	Page
5475
	 *    @param    int		$selected    	Id mode pre-select
5476
	 *    @param    string	$htmlname    	Name of select html field
5477
	 *    @param    int     $active         Active or not, -1 = all
5478
	 *    @param    int     $addempty       1=Add empty entry
5479
	 *    @return	void
5480
	 */
5481
	public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5482
	{
5483
		global $langs;
5484
		if ($htmlname != "none") {
5485
			print '<form method="POST" action="'.$page.'">';
5486
			print '<input type="hidden" name="action" value="settransportmode">';
5487
			print '<input type="hidden" name="token" value="'.newToken().'">';
5488
			$this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5489
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5490
			print '</form>';
5491
		} else {
5492
			if ($selected) {
5493
				$this->load_cache_transport_mode();
5494
				print $this->cache_transport_mode[$selected]['label'];
5495
			} else {
5496
				print "&nbsp;";
5497
			}
5498
		}
5499
	}
5500
5501
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5502
	/**
5503
	 *    Show form with multicurrency code
5504
	 *
5505
	 *    @param	string	$page        	Page
5506
	 *    @param    string	$selected    	code pre-selectionne
5507
	 *    @param    string	$htmlname    	Name of select html field
5508
	 *    @return	void
5509
	 */
5510
	public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5511
	{
5512
		// phpcs:enable
5513
		global $langs;
5514
		if ($htmlname != "none") {
5515
			print '<form method="POST" action="'.$page.'">';
5516
			print '<input type="hidden" name="action" value="setmulticurrencycode">';
5517
			print '<input type="hidden" name="token" value="'.newToken().'">';
5518
			print $this->selectMultiCurrency($selected, $htmlname, 0);
5519
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5520
			print '</form>';
5521
		} else {
5522
			dol_include_once('/core/lib/company.lib.php');
5523
			print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5524
		}
5525
	}
5526
5527
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5528
	/**
5529
	 *    Show form with multicurrency rate
5530
	 *
5531
	 *    @param	string	$page        	Page
5532
	 *    @param    double	$rate	    	Current rate
5533
	 *    @param    string	$htmlname    	Name of select html field
5534
	 *    @param    string  $currency       Currency code to explain the rate
5535
	 *    @return	void
5536
	 */
5537
	public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5538
	{
5539
		// phpcs:enable
5540
		global $langs, $mysoc, $conf;
5541
5542
		if ($htmlname != "none") {
5543
			print '<form method="POST" action="'.$page.'">';
5544
			print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5545
			print '<input type="hidden" name="token" value="'.newToken().'">';
5546
			print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> ';
5547
			print '<select name="calculation_mode">';
5548
			print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>';
5549
			print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>';
5550
			print '</select> ';
5551
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5552
			print '</form>';
5553
		} else {
5554
			if (!empty($rate)) {
5555
				print price($rate, 1, $langs, 1, 0);
5556
				if ($currency && $rate != 1) {
5557
					print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
5558
				}
5559
			} else {
5560
				print 1;
5561
			}
5562
		}
5563
	}
5564
5565
5566
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5567
	/**
5568
	 *	Show a select box with available absolute discounts
5569
	 *
5570
	 *  @param  string	$page        	Page URL where form is shown
5571
	 *  @param  int		$selected    	Value pre-selected
5572
	 *	@param  string	$htmlname    	Name of SELECT component. If 'none', not changeable. Example 'remise_id'.
5573
	 *	@param	int		$socid			Third party id
5574
	 * 	@param	float	$amount			Total amount available
5575
	 * 	@param	string	$filter			SQL filter on discounts
5576
	 * 	@param	int		$maxvalue		Max value for lines that can be selected
5577
	 *  @param  string	$more           More string to add
5578
	 *  @param  int     $hidelist       1=Hide list
5579
	 *  @param	int		$discount_type	0 => customer discount, 1 => supplier discount
5580
	 *  @return	void
5581
	 */
5582
	public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5583
	{
5584
		// phpcs:enable
5585
		global $conf, $langs;
5586
		if ($htmlname != "none") {
5587
			print '<form method="post" action="'.$page.'">';
5588
			print '<input type="hidden" name="action" value="setabsolutediscount">';
5589
			print '<input type="hidden" name="token" value="'.newToken().'">';
5590
			print '<div class="inline-block">';
5591
			if (!empty($discount_type)) {
5592
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5593
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5594
						$translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5595
					} else {
5596
						$translationKey = 'HasCreditNoteFromSupplier';
5597
					}
5598
				} else {
5599
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5600
						$translationKey = 'HasAbsoluteDiscountFromSupplier';
5601
					} else {
5602
						$translationKey = 'HasCreditNoteFromSupplier';
5603
					}
5604
				}
5605
			} else {
5606
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5607
					if (!$filter || $filter == "fk_facture_source IS NULL") {
5608
						$translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
5609
					} else {
5610
						$translationKey = 'CompanyHasCreditNote';
5611
					}
5612
				} else {
5613
					if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5614
						$translationKey = 'CompanyHasAbsoluteDiscount';
5615
					} else {
5616
						$translationKey = 'CompanyHasCreditNote';
5617
					}
5618
				}
5619
			}
5620
			print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
5621
			if (empty($hidelist)) {
5622
				print ' ';
5623
			}
5624
			print '</div>';
5625
			if (empty($hidelist)) {
5626
				print '<div class="inline-block" style="padding-right: 10px">';
5627
				$newfilter = 'discount_type='.intval($discount_type);
5628
				if (!empty($discount_type)) {
5629
					$newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
5630
				} else {
5631
					$newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
5632
				}
5633
				if ($filter) {
5634
					$newfilter .= ' AND ('.$filter.')';
5635
				}
5636
				$nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
5637
				if ($nbqualifiedlines > 0) {
5638
					print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
5639
					if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5640
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5641
					}
5642
					if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5643
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5644
					}
5645
5646
					print '>';
5647
				}
5648
				print '</div>';
5649
			}
5650
			if ($more) {
5651
				print '<div class="inline-block">';
5652
				print $more;
5653
				print '</div>';
5654
			}
5655
			print '</form>';
5656
		} else {
5657
			if ($selected) {
5658
				print $selected;
5659
			} else {
5660
				print "0";
5661
			}
5662
		}
5663
	}
5664
5665
5666
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5667
	/**
5668
	 *  Show forms to select a contact
5669
	 *
5670
	 *  @param	string		$page        	Page
5671
	 *  @param	Societe		$societe		Filter on third party
5672
	 *  @param    int			$selected    	Id contact pre-selectionne
5673
	 *  @param    string		$htmlname    	Name of HTML select. If 'none', we just show contact link.
5674
	 *  @return	void
5675
	 */
5676
	public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
5677
	{
5678
		// phpcs:enable
5679
		global $langs, $conf;
5680
5681
		if ($htmlname != "none") {
5682
			print '<form method="post" action="'.$page.'">';
5683
			print '<input type="hidden" name="action" value="set_contact">';
5684
			print '<input type="hidden" name="token" value="'.newToken().'">';
5685
			print '<table class="nobordernopadding">';
5686
			print '<tr><td>';
5687
			print $this->selectcontacts($societe->id, $selected, $htmlname);
5688
			$num = $this->num;
5689
			if ($num == 0) {
5690
				$addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
5691
				print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
5692
			}
5693
			print '</td>';
5694
			print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5695
			print '</tr></table></form>';
5696
		} else {
5697
			if ($selected) {
5698
				require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
5699
				$contact = new Contact($this->db);
5700
				$contact->fetch($selected);
5701
				print $contact->getFullName($langs);
5702
			} else {
5703
				print "&nbsp;";
5704
			}
5705
		}
5706
	}
5707
5708
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5709
	/**
5710
	 *  Output html select to select thirdparty
5711
	 *
5712
	 *  @param	string	$page       	Page
5713
	 *  @param  string	$selected   	Id preselected
5714
	 *  @param  string	$htmlname		Name of HTML select
5715
	 *  @param  string	$filter         Optional filters criteras. Do not use a filter coming from input of users.
5716
	 *	@param	int		$showempty		Add an empty field
5717
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
5718
	 * 	@param	int		$forcecombo		Force to use combo box
5719
	 *  @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')))
5720
	 *  @param  int     $nooutput       No print output. Return it only.
5721
	 *  @param	array	$excludeids		Exclude IDs from the select combo
5722
	 *  @return	void|string
5723
	 */
5724
	public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array())
5725
	{
5726
		// phpcs:enable
5727
		global $langs;
5728
5729
		$out = '';
5730
		if ($htmlname != "none") {
5731
			$out .= '<form method="post" action="'.$page.'">';
5732
			$out .= '<input type="hidden" name="action" value="set_thirdparty">';
5733
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
5734
			$out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
5735
			$out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5736
			$out .= '</form>';
5737
		} else {
5738
			if ($selected) {
5739
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
5740
				$soc = new Societe($this->db);
5741
				$soc->fetch($selected);
5742
				$out .= $soc->getNomUrl($langs);
5743
			} else {
5744
				$out .= "&nbsp;";
5745
			}
5746
		}
5747
5748
		if ($nooutput) {
5749
			return $out;
5750
		} else {
5751
			print $out;
5752
		}
5753
	}
5754
5755
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5756
	/**
5757
	 *    Retourne la liste des devises, dans la langue de l'utilisateur
5758
	 *
5759
	 *    @param	string	$selected    preselected currency code
5760
	 *    @param    string	$htmlname    name of HTML select list
5761
	 *    @deprecated
5762
	 *    @return	void
5763
	 */
5764
	public function select_currency($selected = '', $htmlname = 'currency_id')
5765
	{
5766
		// phpcs:enable
5767
		print $this->selectCurrency($selected, $htmlname);
5768
	}
5769
5770
	/**
5771
	 *  Retourne la liste des devises, dans la langue de l'utilisateur
5772
	 *
5773
	 *  @param	string	$selected    preselected currency code
5774
	 *  @param  string	$htmlname    name of HTML select list
5775
	 *  @param  string  $mode        0 = Add currency symbol into label, 1 = Add 3 letter iso code
5776
	 * 	@return	string
5777
	 */
5778
	public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0)
5779
	{
5780
		global $conf, $langs, $user;
5781
5782
		$langs->loadCacheCurrencies('');
5783
5784
		$out = '';
5785
5786
		if ($selected == 'euro' || $selected == 'euros') {
5787
			$selected = 'EUR'; // Pour compatibilite
5788
		}
5789
5790
		$out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
5791
		foreach ($langs->cache_currencies as $code_iso => $currency) {
5792
			$labeltoshow = $currency['label'];
5793
			if ($mode == 1) {
5794
				$labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>';
5795
			} else {
5796
				$labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>';
5797
			}
5798
5799
			if ($selected && $selected == $code_iso) {
5800
				$out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
5801
			} else {
5802
				$out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
5803
			}
5804
			$out .= $labeltoshow;
5805
			$out .= '</option>';
5806
		}
5807
		$out .= '</select>';
5808
		if ($user->admin) {
5809
			$out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5810
		}
5811
5812
		// Make select dynamic
5813
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5814
		$out .= ajax_combobox($htmlname);
5815
5816
		return $out;
5817
	}
5818
5819
	/**
5820
	 *	Return array of currencies in user language
5821
	 *
5822
	 *  @param	string	$selected    preselected currency code
5823
	 *  @param  string	$htmlname    name of HTML select list
5824
	 *  @param  integer	$useempty    1=Add empty line
5825
	 *  @param string $filter Optional filters criteras (example: 'code <> x', ' in (1,3)')
5826
	 *  @param bool $excludeConfCurrency false  = If company current currency not in table, we add it into list. Should always be available.  true = we are in currency_rate update , we don't want to see conf->currency in select
5827
	 * 	@return	string
5828
	 */
5829
	public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false)
5830
	{
5831
		global $conf, $langs;
5832
5833
		$langs->loadCacheCurrencies(''); // Load ->cache_currencies
5834
5835
		$TCurrency = array();
5836
5837
		$sql = "SELECT code FROM ".$this->db->prefix()."multicurrency";
5838
		$sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
5839
		if ($filter) {
5840
			$sql .= " AND ".$filter;
5841
		}
5842
		$resql = $this->db->query($sql);
5843
		if ($resql) {
5844
			while ($obj = $this->db->fetch_object($resql)) {
5845
				$TCurrency[$obj->code] = $obj->code;
5846
			}
5847
		}
5848
5849
		$out = '';
5850
		$out .= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
5851
		if ($useempty) {
5852
			$out .= '<option value="">&nbsp;</option>';
5853
		}
5854
		// If company current currency not in table, we add it into list. Should always be available.
5855
		if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
5856
			$TCurrency[$conf->currency] = $conf->currency;
5857
		}
5858
		if (count($TCurrency) > 0) {
5859
			foreach ($langs->cache_currencies as $code_iso => $currency) {
5860
				if (isset($TCurrency[$code_iso])) {
5861
					if (!empty($selected) && $selected == $code_iso) {
5862
						$out .= '<option value="'.$code_iso.'" selected="selected">';
5863
					} else {
5864
						$out .= '<option value="'.$code_iso.'">';
5865
					}
5866
5867
					$out .= $currency['label'];
5868
					$out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5869
					$out .= '</option>';
5870
				}
5871
			}
5872
		}
5873
5874
		$out .= '</select>';
5875
5876
		// Make select dynamic
5877
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5878
		$out .= ajax_combobox($htmlname);
5879
5880
		return $out;
5881
	}
5882
5883
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5884
	/**
5885
	 *  Load into the cache vat rates of a country
5886
	 *
5887
	 *  @param	string	$country_code		Country code with quotes ("'CA'", or "'CA,IN,...'")
5888
	 *  @return	int							Nb of loaded lines, 0 if already loaded, <0 if KO
5889
	 */
5890
	public function load_cache_vatrates($country_code)
5891
	{
5892
		// phpcs:enable
5893
		global $langs;
5894
5895
		$num = count($this->cache_vatrates);
5896
		if ($num > 0) {
5897
			return $num; // Cache already loaded
5898
		}
5899
5900
		dol_syslog(__METHOD__, LOG_DEBUG);
5901
5902
		$sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
5903
		$sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
5904
		$sql .= " WHERE t.fk_pays = c.rowid";
5905
		$sql .= " AND t.active > 0";
5906
		$sql .= " AND c.code IN (".$this->db->sanitize($country_code, 1).")";
5907
		$sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
5908
5909
		$resql = $this->db->query($sql);
5910
		if ($resql) {
5911
			$num = $this->db->num_rows($resql);
5912
			if ($num) {
5913
				for ($i = 0; $i < $num; $i++) {
5914
					$obj = $this->db->fetch_object($resql);
5915
					$this->cache_vatrates[$i]['rowid']	= $obj->rowid;
5916
					$this->cache_vatrates[$i]['code'] = $obj->code;
5917
					$this->cache_vatrates[$i]['txtva']	= $obj->taux;
5918
					$this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
5919
					$this->cache_vatrates[$i]['localtax1']	    = $obj->localtax1;
5920
					$this->cache_vatrates[$i]['localtax1_type']	= $obj->localtax1_type;
5921
					$this->cache_vatrates[$i]['localtax2']	    = $obj->localtax2;
5922
					$this->cache_vatrates[$i]['localtax2_type']	= $obj->localtax1_type;
5923
5924
					$this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
5925
					$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
5926
					$positiverates = '';
5927
					if ($obj->taux) {
5928
						$positiverates .= ($positiverates ? '/' : '').$obj->taux;
5929
					}
5930
					if ($obj->localtax1) {
5931
						$positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
5932
					}
5933
					if ($obj->localtax2) {
5934
						$positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
5935
					}
5936
					if (empty($positiverates)) {
5937
						$positiverates = '0';
5938
					}
5939
					$this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
5940
				}
5941
5942
				return $num;
5943
			} else {
5944
				$this->error = '<span class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</span>';
5945
				return -1;
5946
			}
5947
		} else {
5948
			$this->error = '<span class="error">'.$this->db->error().'</span>';
5949
			return -2;
5950
		}
5951
	}
5952
5953
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5954
	/**
5955
	 *  Output an HTML select vat rate.
5956
	 *  The name of this function should be selectVat. We keep bad name for compatibility purpose.
5957
	 *
5958
	 *  @param	string	      $htmlname           Name of HTML select field
5959
	 *  @param  float|string  $selectedrate       Force preselected vat rate. Can be '8.5' or '8.5 (NOO)' for example. Use '' for no forcing.
5960
	 *  @param  Societe	      $societe_vendeuse   Thirdparty seller
5961
	 *  @param  Societe	      $societe_acheteuse  Thirdparty buyer
5962
	 *  @param  int		      $idprod             Id product. O if unknown of NA.
5963
	 *  @param  int		      $info_bits          Miscellaneous information on line (1 for NPR)
5964
	 *  @param  int|string    $type               ''=Unknown, 0=Product, 1=Service (Used if idprod not defined)
5965
	 *                  		                  Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle.
5966
	 *                  					      Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle.
5967
	 *                  					      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.
5968
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= particulier alors TVA par défaut=TVA du produit vendu. Fin de règle.
5969
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= entreprise alors TVA par défaut=0. Fin de règle.
5970
	 *                  					      Sinon la TVA proposee par defaut=0. Fin de regle.
5971
	 *  @param	bool	     $options_only		  Return HTML options lines only (for ajax treatment)
5972
	 *  @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
5973
	 *  @return	string
5974
	 */
5975
	public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
5976
	{
5977
		// phpcs:enable
5978
		global $langs, $conf, $mysoc;
5979
5980
		$langs->load('errors');
5981
5982
		$return = '';
5983
5984
		// Define defaultnpr, defaultttx and defaultcode
5985
		$defaultnpr = ($info_bits & 0x01);
5986
		$defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
5987
		$defaulttx = str_replace('*', '', $selectedrate);
5988
		$defaultcode = '';
5989
		$reg = array();
5990
		if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
5991
			$defaultcode = $reg[1];
5992
			$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5993
		}
5994
		//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
5995
5996
		// Check parameters
5997
		if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
5998
			if ($societe_vendeuse->id == $mysoc->id) {
5999
				$return .= '<span class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</span>';
6000
			} else {
6001
				$return .= '<span class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</span>';
6002
			}
6003
			return $return;
6004
		}
6005
6006
		//var_dump($societe_acheteuse);
6007
		//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";
6008
		//exit;
6009
6010
		// Define list of countries to use to search VAT rates to show
6011
		// First we defined code_country to use to find list
6012
		if (is_object($societe_vendeuse)) {
6013
			$code_country = "'".$societe_vendeuse->country_code."'";
6014
		} else {
6015
			$code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
6016
		}
6017
		if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {    // If option to have vat for end customer for services is on
6018
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6019
			if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
6020
				// We also add the buyer
6021
				if (is_numeric($type)) {
6022
					if ($type == 1) { // We know product is a service
6023
						$code_country .= ",'".$societe_acheteuse->country_code."'";
6024
					}
6025
				} elseif (!$idprod) {  // We don't know type of product
6026
					$code_country .= ",'".$societe_acheteuse->country_code."'";
6027
				} else {
6028
					$prodstatic = new Product($this->db);
6029
					$prodstatic->fetch($idprod);
6030
					if ($prodstatic->type == Product::TYPE_SERVICE) {   // We know product is a service
6031
						$code_country .= ",'".$societe_acheteuse->country_code."'";
6032
					}
6033
				}
6034
			}
6035
		}
6036
6037
		// Now we get list
6038
		$num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
6039
6040
		if ($num > 0) {
6041
			// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
6042
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6043
				$tmpthirdparty = new Societe($this->db);
6044
				$defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6045
				$defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
6046
				if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
6047
					$defaultcode = $reg[1];
6048
					$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
6049
				}
6050
				if (empty($defaulttx)) {
6051
					$defaultnpr = 0;
6052
				}
6053
			}
6054
6055
			// Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
6056
			// Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
6057
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
6058
				if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6059
					$defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
6060
				} else {
6061
					$defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
6062
				}
6063
			}
6064
6065
			// Disabled if seller is not subject to VAT
6066
			$disabled = false;
6067
			$title = '';
6068
			if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
6069
				// Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
6070
				// of using supplier invoices (this is a very bad idea !)
6071
				if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
6072
					$title = ' title="'.$langs->trans('VATIsNotUsed').'"';
6073
					$disabled = true;
6074
				}
6075
			}
6076
6077
			if (!$options_only) {
6078
				$return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
6079
			}
6080
6081
			$selectedfound = false;
6082
			foreach ($this->cache_vatrates as $rate) {
6083
				// Keep only 0 if seller is not subject to VAT
6084
				if ($disabled && $rate['txtva'] != 0) {
6085
					continue;
6086
				}
6087
6088
				// Define key to use into select list
6089
				$key = $rate['txtva'];
6090
				$key .= $rate['nprtva'] ? '*' : '';
6091
				if ($mode > 0 && $rate['code']) {
6092
					$key .= ' ('.$rate['code'].')';
6093
				}
6094
				if ($mode < 0) {
6095
					$key = $rate['rowid'];
6096
				}
6097
6098
				$return .= '<option value="'.$key.'"';
6099
				if (!$selectedfound) {
6100
					if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
6101
						if ($defaultcode == $rate['code']) {
6102
							$return .= ' selected';
6103
							$selectedfound = true;
6104
						}
6105
					} elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
6106
						$return .= ' selected';
6107
						$selectedfound = true;
6108
					}
6109
				}
6110
				$return .= '>';
6111
				//if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
6112
				if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
6113
					$return .= $rate['labelpositiverates'];
6114
				} else {
6115
					$return .= vatrate($rate['label']);
6116
				}
6117
				//$return.=($rate['code']?' '.$rate['code']:'');
6118
				$return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the *  (old behaviour only if new vat code is not used)
6119
6120
				$return .= '</option>';
6121
			}
6122
6123
			if (!$options_only) {
6124
				$return .= '</select>';
6125
			}
6126
		} else {
6127
			$return .= $this->error;
6128
		}
6129
6130
		$this->num = $num;
6131
		return $return;
6132
	}
6133
6134
6135
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6136
	/**
6137
	 *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
6138
	 *  Fields are preselected with :
6139
	 *            	- set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
6140
	 *            	- local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
6141
	 *            	- Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
6142
	 *
6143
	 *	@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).
6144
	 *	@param	string		$prefix			Prefix for fields name
6145
	 *	@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
6146
	 *	@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
6147
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
6148
	 *	@param	string		$form_name 		Not used
6149
	 *	@param	int			$d				1=Show days, month, years
6150
	 * 	@param	int			$addnowlink		Add a link "Now"
6151
	 * 	@param	int			$nooutput		Do not output html string but return it
6152
	 * 	@param 	int			$disabled		Disable input fields
6153
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
6154
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another select_date field.
6155
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
6156
	 *  @return	string|void					Nothing or string if nooutput is 1
6157
	 *  @deprecated
6158
	 *  @see    selectDate(), form_date(), select_month(), select_year(), select_dayofweek()
6159
	 */
6160
	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 = '')
6161
	{
6162
		// phpcs:enable
6163
		$retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
6164
		if (!empty($nooutput)) {
6165
			return $retstring;
6166
		}
6167
		print $retstring;
6168
		return;
6169
	}
6170
6171
	/**
6172
	 *  Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
6173
	 *  Fields are preselected with :
6174
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
6175
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
6176
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
6177
	 *
6178
	 *  @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).
6179
	 *  @param  integer     $set_time_end       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).
6180
	 *  @param	string		$prefix				Prefix for fields name
6181
	 *  @param	string		$empty				0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
6182
	 *  @param	string		$forcenewline		Force new line between the 2 dates.
6183
	 * 	@return string                   	    Html for selectDate
6184
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
6185
	 */
6186
	public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
6187
	{
6188
		global $langs;
6189
6190
		$ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6191
		if ($forcenewline) {
6192
			$ret .= '<br>';
6193
		}
6194
		$ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6195
		return $ret;
6196
	}
6197
6198
	/**
6199
	 *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
6200
	 *  Fields are preselected with :
6201
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
6202
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
6203
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
6204
	 *
6205
	 *  @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).
6206
	 *  @param	string		$prefix			Prefix for fields name
6207
	 *  @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
6208
	 *	@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
6209
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
6210
	 *	@param	string		$form_name 		Not used
6211
	 *	@param	int			$d				1=Show days, month, years
6212
	 * 	@param	int			$addnowlink		Add a link "Now", 1 with server time, 2 with local computer time
6213
	 * 	@param 	int			$disabled		Disable input fields
6214
	 *  @param  int			$fullday        When a checkbox with id #fullday is checked, hours are set with 00:00 (if value if 'fulldaystart') or 23:59 (if value is 'fulldayend')
6215
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another selectDate field.
6216
	 *  @param  datetime    $adddateof      Add a link "Date of ..." using the following date. See also $labeladddateof for the label used.
6217
	 *  @param  string      $openinghours   Specify hour start and hour end for the select ex 8,20
6218
	 *  @param  int         $stepminutes    Specify step for minutes between 1 and 30
6219
	 *  @param	string		$labeladddateof Label to use for the $adddateof parameter.
6220
	 *  @param	string 		$placeholder    Placeholder
6221
	 *  @param	mixed		$gm				'auto' (for backward compatibility, avoid this), 'gmt' or 'tzserver' or 'tzuserrel'
6222
	 * 	@return string                      Html for selectDate
6223
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
6224
	 */
6225
	public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '', $placeholder = '', $gm = 'auto')
6226
	{
6227
		global $conf, $langs;
6228
6229
		if ($gm === 'auto') {
6230
			$gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6231
		}
6232
6233
		$retstring = '';
6234
6235
		if ($prefix == '') {
6236
			$prefix = 're';
6237
		}
6238
		if ($h == '') {
6239
			$h = 0;
6240
		}
6241
		if ($m == '') {
6242
			$m = 0;
6243
		}
6244
		$emptydate = 0;
6245
		$emptyhours = 0;
6246
		if ($stepminutes <= 0 || $stepminutes > 30) {
6247
			$stepminutes = 1;
6248
		}
6249
		if ($empty == 1) {
6250
			$emptydate = 1;
6251
			$emptyhours = 1;
6252
		}
6253
		if ($empty == 2) {
6254
			$emptydate = 0;
6255
			$emptyhours = 1;
6256
		}
6257
		$orig_set_time = $set_time;
6258
6259
		if ($set_time === '' && $emptydate == 0) {
6260
			include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6261
			if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6262
				$set_time = dol_now($gm);
6263
			} else {
6264
				$set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6265
			}
6266
		}
6267
6268
		// Analysis of the pre-selection date
6269
		$reg = array();
6270
		if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) {	// deprecated usage
6271
			// Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6272
			$syear	= (!empty($reg[1]) ? $reg[1] : '');
6273
			$smonth = (!empty($reg[2]) ? $reg[2] : '');
6274
			$sday	= (!empty($reg[3]) ? $reg[3] : '');
6275
			$shour	= (!empty($reg[4]) ? $reg[4] : '');
6276
			$smin	= (!empty($reg[5]) ? $reg[5] : '');
6277
		} elseif (strval($set_time) != '' && $set_time != -1) {
6278
			// set_time est un timestamps (0 possible)
6279
			$syear = dol_print_date($set_time, "%Y", $gm);
6280
			$smonth = dol_print_date($set_time, "%m", $gm);
6281
			$sday = dol_print_date($set_time, "%d", $gm);
6282
			if ($orig_set_time != '') {
6283
				$shour = dol_print_date($set_time, "%H", $gm);
6284
				$smin = dol_print_date($set_time, "%M", $gm);
6285
				$ssec = dol_print_date($set_time, "%S", $gm);
6286
			} else {
6287
				$shour = '';
6288
				$smin = '';
6289
				$ssec = '';
6290
			}
6291
		} else {
6292
			// Date est '' ou vaut -1
6293
			$syear = '';
6294
			$smonth = '';
6295
			$sday = '';
6296
			$shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6297
			$smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6298
			$ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6299
		}
6300
		if ($h == 3) {
6301
			$shour = '';
6302
		}
6303
		if ($m == 3) {
6304
			$smin = '';
6305
		}
6306
6307
		$nowgmt = dol_now('gmt');
6308
		//var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6309
6310
		// You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6311
		$usecalendar = 'combo';
6312
		if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6313
			$usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6314
		}
6315
6316
		if ($d) {
6317
			// Show date with popup
6318
			if ($usecalendar != 'combo') {
6319
				$formated_date = '';
6320
				//print "e".$set_time." t ".$conf->format_date_short;
6321
				if (strval($set_time) != '' && $set_time != -1) {
6322
					//$formated_date=dol_print_date($set_time,$conf->format_date_short);
6323
					$formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6324
				}
6325
6326
				// Calendrier popup version eldy
6327
				if ($usecalendar == "eldy") {
6328
					// Input area to enter date manually
6329
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6330
					$retstring .= ($disabled ? ' disabled' : '');
6331
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6332
					$retstring .= '>';
6333
6334
					// Icon calendar
6335
					$retstringbuttom = '';
6336
					if (!$disabled) {
6337
						$retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
6338
						$base = DOL_URL_ROOT.'/core/';
6339
						$retstringbuttom .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
6340
						$retstringbuttom .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
6341
					} else {
6342
						$retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6343
					}
6344
					$retstring = $retstringbuttom.$retstring;
6345
6346
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
6347
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6348
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
6349
				} elseif ($usecalendar == 'jquery') {
6350
					if (!$disabled) {
6351
						// Output javascript for datepicker
6352
						$retstring .= "<script type='text/javascript'>";
6353
						$retstring .= "$(function(){ $('#".$prefix."').datepicker({
6354
							dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
6355
							autoclose: true,
6356
							todayHighlight: true,";
6357
						if (!empty($conf->dol_use_jmobile)) {
6358
							$retstring .= "
6359
								beforeShow: function (input, datePicker) {
6360
									input.disabled = true;
6361
								},
6362
								onClose: function (dateText, datePicker) {
6363
									this.disabled = false;
6364
								},
6365
								";
6366
						}
6367
						// Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6368
						if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6369
							$retstring .= "
6370
								showOn: 'button',	/* both has problem with autocompletion */
6371
								buttonImage: '".DOL_URL_ROOT."/theme/".dol_escape_js($conf->theme)."/img/object_calendarday.png',
6372
								buttonImageOnly: true";
6373
						}
6374
						$retstring .= "
6375
							}) });";
6376
						$retstring .= "</script>";
6377
					}
6378
6379
					// Zone de saisie manuelle de la date
6380
					$retstring .= '<div class="nowrap inline-block divfordateinput">';
6381
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6382
					$retstring .= ($disabled ? ' disabled' : '');
6383
					$retstring .= ($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '');
6384
					$retstring .= ' onChange="dpChangeDay(\''.dol_escape_js($prefix).'\',\''.dol_escape_js($langs->trans("FormatDateShortJavaInput")).'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6385
					$retstring .= '>';
6386
6387
					// Icone calendrier
6388
					if (!$disabled) {
6389
						/* Not required. Managed by option buttonImage of jquery
6390
						$retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6391
						$retstring.="<script type='text/javascript'>";
6392
						$retstring.="jQuery(document).ready(function() {";
6393
						$retstring.='	jQuery("#'.$prefix.'id").click(function() {';
6394
						$retstring.="    	jQuery('#".$prefix."').focus();";
6395
						$retstring.='    });';
6396
						$retstring.='});';
6397
						$retstring.="</script>";*/
6398
					} else {
6399
						$retstringbutton = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6400
						$retsring = $retstringbutton.$retstring;
6401
					}
6402
6403
					$retstring .= '</div>';
6404
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
6405
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6406
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
6407
				} else {
6408
					$retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6409
				}
6410
			} else {
6411
				// Show date with combo selects
6412
				// Day
6413
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
6414
6415
				if ($emptydate || $set_time == -1) {
6416
					$retstring .= '<option value="0" selected>&nbsp;</option>';
6417
				}
6418
6419
				for ($day = 1; $day <= 31; $day++) {
6420
					$retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
6421
				}
6422
6423
				$retstring .= "</select>";
6424
6425
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
6426
				if ($emptydate || $set_time == -1) {
6427
					$retstring .= '<option value="0" selected>&nbsp;</option>';
6428
				}
6429
6430
				// Month
6431
				for ($month = 1; $month <= 12; $month++) {
6432
					$retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
6433
					$retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6434
					$retstring .= "</option>";
6435
				}
6436
				$retstring .= "</select>";
6437
6438
				// Year
6439
				if ($emptydate || $set_time == -1) {
6440
					$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.'">';
6441
				} else {
6442
					$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
6443
6444
					for ($year = $syear - 10; $year < $syear + 10; $year++) {
6445
						$retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
6446
					}
6447
					$retstring .= "</select>\n";
6448
				}
6449
			}
6450
		}
6451
6452
		if ($d && $h) {
6453
			$retstring .= ($h == 2 ? '<br>' : ' ');
6454
			$retstring .= '<span class="nowraponall">';
6455
		}
6456
6457
		if ($h) {
6458
			$hourstart = 0;
6459
			$hourend = 24;
6460
			if ($openinghours != '') {
6461
				$openinghours = explode(',', $openinghours);
6462
				$hourstart = $openinghours[0];
6463
				$hourend = $openinghours[1];
6464
				if ($hourend < $hourstart) {
6465
					$hourend = $hourstart;
6466
				}
6467
			}
6468
			// Show hour
6469
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
6470
			if ($emptyhours) {
6471
				$retstring .= '<option value="-1">&nbsp;</option>';
6472
			}
6473
			for ($hour = $hourstart; $hour < $hourend; $hour++) {
6474
				if (strlen($hour) < 2) {
6475
					$hour = "0".$hour;
6476
				}
6477
				$retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour;
6478
				//$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6479
				$retstring .= '</option>';
6480
			}
6481
			$retstring .= '</select>';
6482
			//if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6483
			if ($m) {
6484
				$retstring .= ":";
6485
			}
6486
		}
6487
6488
		if ($m) {
6489
			// Show minutes
6490
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
6491
			if ($emptyhours) {
6492
				$retstring .= '<option value="-1">&nbsp;</option>';
6493
			}
6494
			for ($min = 0; $min < 60; $min += $stepminutes) {
6495
				if (strlen($min) < 2) {
6496
					$min = "0".$min;
6497
				}
6498
				$retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
6499
			}
6500
			$retstring .= '</select>';
6501
6502
			$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...
6503
		}
6504
6505
		if ($d && $h) {
6506
			$retstring .= '</span>';
6507
		}
6508
6509
		// Add a "Now" link
6510
		if ($conf->use_javascript_ajax && $addnowlink) {
6511
			// Script which will be inserted in the onClick of the "Now" link
6512
			$reset_scripts = "";
6513
			if ($addnowlink == 2) { // local computer time
6514
				// pad add leading 0 on numbers
6515
				$reset_scripts .= "Number.prototype.pad = function(size) {
6516
                        var s = String(this);
6517
                        while (s.length < (size || 2)) {s = '0' + s;}
6518
                        return s;
6519
                    };
6520
                    var d = new Date();";
6521
			}
6522
6523
			// Generate the date part, depending on the use or not of the javascript calendar
6524
			if ($addnowlink == 1) { // server time expressed in user time setup
6525
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6526
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6527
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6528
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6529
			} elseif ($addnowlink == 2) {
6530
				/* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6531
				 * This break application for foreign languages.
6532
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6533
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6534
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6535
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6536
				*/
6537
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6538
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6539
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6540
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6541
			}
6542
			/*if ($usecalendar == "eldy")
6543
			{
6544
				$base=DOL_URL_ROOT.'/core/';
6545
				$reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6546
			}
6547
			else
6548
			{
6549
				$reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6550
				$reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6551
				$reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6552
			}*/
6553
			// Update the hour part
6554
			if ($h) {
6555
				if ($fullday) {
6556
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6557
				}
6558
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
6559
				if ($addnowlink == 1) {
6560
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6561
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6562
				} elseif ($addnowlink == 2) {
6563
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
6564
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6565
				}
6566
6567
				if ($fullday) {
6568
					$reset_scripts .= ' } ';
6569
				}
6570
			}
6571
			// Update the minute part
6572
			if ($m) {
6573
				if ($fullday) {
6574
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6575
				}
6576
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
6577
				if ($addnowlink == 1) {
6578
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6579
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6580
				} elseif ($addnowlink == 2) {
6581
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
6582
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6583
				}
6584
				if ($fullday) {
6585
					$reset_scripts .= ' } ';
6586
				}
6587
			}
6588
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6589
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6590
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
6591
				$retstring .= $langs->trans("Now");
6592
				$retstring .= '</button> ';
6593
			}
6594
		}
6595
6596
		// Add a "Plus one hour" link
6597
		if ($conf->use_javascript_ajax && $addplusone) {
6598
			// Script which will be inserted in the onClick of the "Add plusone" link
6599
			$reset_scripts = "";
6600
6601
			// Generate the date part, depending on the use or not of the javascript calendar
6602
			$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');';
6603
			$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6604
			$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6605
			$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6606
			// Update the hour part
6607
			if ($h) {
6608
				if ($fullday) {
6609
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6610
				}
6611
				$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6612
				if ($fullday) {
6613
					$reset_scripts .= ' } ';
6614
				}
6615
			}
6616
			// Update the minute part
6617
			if ($m) {
6618
				if ($fullday) {
6619
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6620
				}
6621
				$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6622
				if ($fullday) {
6623
					$reset_scripts .= ' } ';
6624
				}
6625
			}
6626
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6627
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6628
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
6629
				$retstring .= $langs->trans("DateStartPlusOne");
6630
				$retstring .= '</button> ';
6631
			}
6632
		}
6633
6634
		// Add a link to set data
6635
		if ($conf->use_javascript_ajax && $adddateof) {
6636
			$tmparray = dol_getdate($adddateof);
6637
			if (empty($labeladddateof)) {
6638
				$labeladddateof = $langs->trans("DateInvoice");
6639
			}
6640
			$retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="console.log(\'Click on now link\'); jQuery(\'#re\').val(\''.dol_print_date($adddateof, 'dayinputnoreduce').'\');jQuery(\'#reday\').val(\''.$tmparray['mday'].'\');jQuery(\'#remonth\').val(\''.$tmparray['mon'].'\');jQuery(\'#reyear\').val(\''.$tmparray['year'].'\');">'.$labeladddateof.'</a>';
6641
		}
6642
6643
		return $retstring;
6644
	}
6645
6646
	/**
6647
	 * selectTypeDuration
6648
	 *
6649
	 * @param   string   	$prefix     	Prefix
6650
	 * @param   string   	$selected   	Selected duration type
6651
	 * @param	array		$excludetypes	Array of duration types to exclude. Example array('y', 'm')
6652
	 * @return  string      	         	HTML select string
6653
	 */
6654
	public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
6655
	{
6656
		global $langs;
6657
6658
		$TDurationTypes = array(
6659
			'y'=>$langs->trans('Years'),
6660
			'm'=>$langs->trans('Month'),
6661
			'w'=>$langs->trans('Weeks'),
6662
			'd'=>$langs->trans('Days'),
6663
			'h'=>$langs->trans('Hours'),
6664
			'i'=>$langs->trans('Minutes')
6665
		);
6666
6667
		// Removed undesired duration types
6668
		foreach ($excludetypes as $value) {
6669
			unset($TDurationTypes[$value]);
6670
		}
6671
6672
		$retstring = '<select class="flat minwidth75 maxwidth100" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
6673
		foreach ($TDurationTypes as $key => $typeduration) {
6674
			$retstring .= '<option value="'.$key.'"';
6675
			if ($key == $selected) {
6676
				$retstring .= " selected";
6677
			}
6678
			$retstring .= ">".$typeduration."</option>";
6679
		}
6680
		$retstring .= "</select>";
6681
6682
		$retstring .= ajax_combobox('select_'.$prefix.'type_duration');
6683
6684
		return $retstring;
6685
	}
6686
6687
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6688
	/**
6689
	 *  Function to show a form to select a duration on a page
6690
	 *
6691
	 *	@param	string		$prefix   		Prefix for input fields
6692
	 *	@param  int			$iSecond  		Default preselected duration (number of seconds or '')
6693
	 * 	@param	int			$disabled       Disable the combo box
6694
	 * 	@param	string		$typehour		If 'select' then input hour and input min is a combo,
6695
	 *						            	If 'text' input hour is in text and input min is a text,
6696
	 *						            	If 'textselect' input hour is in text and input min is a combo
6697
	 *  @param	integer		$minunderhours	If 1, show minutes selection under the hours
6698
	 * 	@param	int			$nooutput		Do not output html string but return it
6699
	 *  @return	string|void
6700
	 */
6701
	public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
6702
	{
6703
		// phpcs:enable
6704
		global $langs;
6705
6706
		$retstring = '<span class="nowraponall">';
6707
6708
		$hourSelected = 0;
6709
		$minSelected = 0;
6710
6711
		// Hours
6712
		if ($iSecond != '') {
6713
			require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6714
6715
			$hourSelected = convertSecondToTime($iSecond, 'allhour');
6716
			$minSelected = convertSecondToTime($iSecond, 'min');
6717
		}
6718
6719
		if ($typehour == 'select') {
6720
			$retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
6721
			for ($hour = 0; $hour < 25; $hour++) {	// For a duration, we allow 24 hours
6722
				$retstring .= '<option value="'.$hour.'"';
6723
				if ($hourSelected == $hour) {
6724
					$retstring .= " selected";
6725
				}
6726
				$retstring .= ">".$hour."</option>";
6727
			}
6728
			$retstring .= "</select>";
6729
		} elseif ($typehour == 'text' || $typehour == 'textselect') {
6730
			$retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
6731
		} else {
6732
			return 'BadValueForParameterTypeHour';
6733
		}
6734
6735
		if ($typehour != 'text') {
6736
			$retstring .= ' '.$langs->trans('HourShort');
6737
		} else {
6738
			$retstring .= '<span class="">:</span>';
6739
		}
6740
6741
		// Minutes
6742
		if ($minunderhours) {
6743
			$retstring .= '<br>';
6744
		} else {
6745
			$retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
6746
		}
6747
6748
		if ($typehour == 'select' || $typehour == 'textselect') {
6749
			$retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
6750
			for ($min = 0; $min <= 55; $min = $min + 5) {
6751
				$retstring .= '<option value="'.$min.'"';
6752
				if ($minSelected == $min) {
6753
					$retstring .= ' selected';
6754
				}
6755
				$retstring .= '>'.$min.'</option>';
6756
			}
6757
			$retstring .= "</select>";
6758
		} elseif ($typehour == 'text') {
6759
			$retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
6760
		}
6761
6762
		if ($typehour != 'text') {
6763
			$retstring .= ' '.$langs->trans('MinuteShort');
6764
		}
6765
6766
		$retstring.="</span>";
6767
6768
		if (!empty($nooutput)) {
6769
			return $retstring;
6770
		}
6771
6772
		print $retstring;
6773
		return;
6774
	}
6775
6776
	/**
6777
	 *  Return list of tickets in Ajax if Ajax activated or go to selectTicketsList
6778
	 *
6779
	 *  @param		int			$selected				Preselected tickets
6780
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page).
6781
	 *  @param  	string		$filtertype     		To add a filter
6782
	 *  @param		int			$limit					Limit on number of returned lines
6783
	 *  @param		int			$status					Ticket status
6784
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
6785
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
6786
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
6787
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
6788
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
6789
	 * 	@param		int			$forcecombo				Force to use combo box
6790
	 *  @param      string      $morecss                Add more css on select
6791
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
6792
	 *  @param		string		$nooutput				No print, return the output into a string
6793
	 *  @return		void|string
6794
	 */
6795
	public function selectTickets($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
6796
	{
6797
		global $langs, $conf;
6798
6799
		$out = '';
6800
6801
		// check parameters
6802
		if (is_null($ajaxoptions)) $ajaxoptions = array();
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
6803
6804
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
6805
			$placeholder = '';
6806
6807
			if ($selected && empty($selected_input_value)) {
6808
				require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
6809
				$tickettmpselect = new Ticket($this->db);
6810
				$tickettmpselect->fetch($selected);
6811
				$selected_input_value = $tickettmpselect->ref;
6812
				unset($tickettmpselect);
6813
			}
6814
6815
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $urloption seems to be never defined.
Loading history...
6816
6817
			if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
6818
			elseif ($hidelabel > 1) {
6819
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
6820
				if ($hidelabel == 2) {
6821
					$out .= img_picto($langs->trans("Search"), 'search');
6822
				}
6823
			}
6824
			$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
6825
			if ($hidelabel == 3) {
6826
				$out .= img_picto($langs->trans("Search"), 'search');
6827
			}
6828
		} else {
6829
			$out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
6830
		}
6831
6832
		if (empty($nooutput)) print $out;
6833
		else return $out;
6834
	}
6835
6836
6837
	/**
6838
	 *	Return list of tickets.
6839
	 *  Called by selectTickets.
6840
	 *
6841
	 *	@param      int		$selected           Preselected ticket
6842
	 *	@param      string	$htmlname           Name of select html
6843
	 *  @param		string	$filtertype         Filter on ticket type
6844
	 *	@param      int		$limit              Limit on number of returned lines
6845
	 * 	@param      string	$filterkey          Filter on ticket ref or subject
6846
	 *	@param		int		$status             Ticket status
6847
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
6848
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
6849
	 * 	@param		int		$forcecombo		    Force to use combo box
6850
	 *  @param      string  $morecss            Add more css on select
6851
	 *  @return     array    				    Array of keys for json
6852
	 */
6853
	public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
6854
	{
6855
		global $langs, $conf;
6856
6857
		$out = '';
6858
		$outarray = array();
6859
6860
		$selectFields = " p.rowid, p.ref, p.message";
6861
6862
		$sql = "SELECT ";
6863
		$sql .= $selectFields;
6864
		$sql .= " FROM ".$this->db->prefix()."ticket as p";
6865
		$sql .= ' WHERE p.entity IN ('.getEntity('ticket').')';
6866
6867
		// Add criteria on ref/label
6868
		if ($filterkey != '') {
6869
			$sql .= ' AND (';
6870
			$prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
6871
			// For natural search
6872
			$scrit = explode(' ', $filterkey);
6873
			$i = 0;
6874
			if (count($scrit) > 1) $sql .= "(";
6875
			foreach ($scrit as $crit) {
6876
				if ($i > 0) $sql .= " AND ";
6877
				$sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.subject LIKE '".$this->db->escape($prefix.$crit)."%'";
6878
				$sql .= ")";
6879
				$i++;
6880
			}
6881
			if (count($scrit) > 1) $sql .= ")";
6882
			$sql .= ')';
6883
		}
6884
6885
		$sql .= $this->db->plimit($limit, 0);
6886
6887
		// Build output string
6888
		dol_syslog(get_class($this)."::selectTicketsList search tickets", LOG_DEBUG);
6889
		$result = $this->db->query($sql);
6890
		if ($result) {
6891
			require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
6892
			require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
6893
6894
			$num = $this->db->num_rows($result);
6895
6896
			$events = null;
6897
6898
			if (!$forcecombo) {
6899
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6900
				$out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
6901
			}
6902
6903
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
6904
6905
			$textifempty = '';
6906
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
6907
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
6908
			if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
6909
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6910
				else $textifempty .= $langs->trans("All");
6911
			} else {
6912
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6913
			}
6914
			if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
6915
6916
			$i = 0;
6917
			while ($num && $i < $num) {
6918
				$opt = '';
6919
				$optJson = array();
6920
				$objp = $this->db->fetch_object($result);
6921
6922
				$this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
6923
				// Add new entry
6924
				// "key" value of json key array is used by jQuery automatically as selected value
6925
				// "label" value of json key array is used by jQuery automatically as text for combo box
6926
				$out .= $opt;
6927
				array_push($outarray, $optJson);
6928
6929
				$i++;
6930
			}
6931
6932
			$out .= '</select>';
6933
6934
			$this->db->free($result);
6935
6936
			if (empty($outputmode)) return $out;
6937
			return $outarray;
6938
		} else {
6939
			dol_print_error($this->db);
6940
		}
6941
	}
6942
6943
	/**
6944
	 * constructTicketListOption.
6945
	 * This define value for &$opt and &$optJson.
6946
	 *
6947
	 * @param 	resource	$objp			    Result set of fetch
6948
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
6949
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
6950
	 * @param 	string		$selected		    Preselected value
6951
	 * @param   string      $filterkey          Filter key to highlight
6952
	 * @return	void
6953
	 */
6954
	protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
6955
	{
6956
		$outkey = '';
6957
		$outval = '';
6958
		$outref = '';
6959
		$outlabel = '';
6960
		$outtype = '';
6961
6962
		$label = $objp->label;
6963
6964
		$outkey = $objp->rowid;
6965
		$outref = $objp->ref;
6966
		$outlabel = $objp->label;
6967
		$outtype = $objp->fk_product_type;
6968
6969
		$opt = '<option value="'.$objp->rowid.'"';
6970
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
6971
		$opt .= '>';
6972
		$opt .= $objp->ref;
6973
		$objRef = $objp->ref;
6974
		if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
6975
		$outval .= $objRef;
6976
6977
		$opt .= "</option>\n";
6978
		$optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtypem);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $outtypem does not exist. Did you maybe mean $outtype?
Loading history...
6979
	}
6980
6981
	/**
6982
	 *  Return list of projects in Ajax if Ajax activated or go to selectTicketsList
6983
	 *
6984
	 *  @param		int			$selected				Preselected tickets
6985
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page).
6986
	 *  @param  	string		$filtertype     		To add a filter
6987
	 *  @param		int			$limit					Limit on number of returned lines
6988
	 *  @param		int			$status					Ticket status
6989
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
6990
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
6991
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
6992
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
6993
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
6994
	 * 	@param		int			$forcecombo				Force to use combo box
6995
	 *  @param      string      $morecss                Add more css on select
6996
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
6997
	 *  @param		string		$nooutput				No print, return the output into a string
6998
	 *  @return		void|string
6999
	 */
7000
	public function selectProjects($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7001
	{
7002
		global $langs, $conf;
7003
7004
		$out = '';
7005
7006
		// check parameters
7007
		if (is_null($ajaxoptions)) $ajaxoptions = array();
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
7008
7009
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7010
			$placeholder = '';
7011
7012
			if ($selected && empty($selected_input_value)) {
7013
				require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7014
				$projecttmpselect = new Project($this->db);
7015
				$projecttmpselect->fetch($selected);
7016
				$selected_input_value = $projecttmpselect->ref;
7017
				unset($projecttmpselect);
7018
			}
7019
7020
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $urloption seems to be never defined.
Loading history...
7021
7022
			if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7023
			elseif ($hidelabel > 1) {
7024
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7025
				if ($hidelabel == 2) {
7026
					$out .= img_picto($langs->trans("Search"), 'search');
7027
				}
7028
			}
7029
			$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7030
			if ($hidelabel == 3) {
7031
				$out .= img_picto($langs->trans("Search"), 'search');
7032
			}
7033
		} else {
7034
			$out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7035
		}
7036
7037
		if (empty($nooutput)) print $out;
7038
		else return $out;
7039
	}
7040
7041
	/**
7042
	 *	Return list of projects.
7043
	 *  Called by selectProjects.
7044
	 *
7045
	 *	@param      int		$selected           Preselected project
7046
	 *	@param      string	$htmlname           Name of select html
7047
	 *  @param		string	$filtertype         Filter on project type
7048
	 *	@param      int		$limit              Limit on number of returned lines
7049
	 * 	@param      string	$filterkey          Filter on project ref or subject
7050
	 *	@param		int		$status             Ticket status
7051
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
7052
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
7053
	 * 	@param		int		$forcecombo		    Force to use combo box
7054
	 *  @param      string  $morecss            Add more css on select
7055
	 *  @return     array    				    Array of keys for json
7056
	 */
7057
	public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7058
	{
7059
		global $langs, $conf;
7060
7061
		$out = '';
7062
		$outarray = array();
7063
7064
		$selectFields = " p.rowid, p.ref";
7065
7066
		$sql = "SELECT ";
7067
		$sql .= $selectFields;
7068
		$sql .= " FROM ".$this->db->prefix()."projet as p";
7069
		$sql .= ' WHERE p.entity IN ('.getEntity('project').')';
7070
7071
		// Add criteria on ref/label
7072
		if ($filterkey != '') {
7073
			$sql .= ' AND (';
7074
			$prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7075
			// For natural search
7076
			$scrit = explode(' ', $filterkey);
7077
			$i = 0;
7078
			if (count($scrit) > 1) $sql .= "(";
7079
			foreach ($scrit as $crit) {
7080
				if ($i > 0) $sql .= " AND ";
7081
				$sql .= "p.ref LIKE '".$this->db->escape($prefix.$crit)."%'";
7082
				$sql .= "";
7083
				$i++;
7084
			}
7085
			if (count($scrit) > 1) $sql .= ")";
7086
			$sql .= ')';
7087
		}
7088
7089
		$sql .= $this->db->plimit($limit, 0);
7090
7091
		// Build output string
7092
		dol_syslog(get_class($this)."::selectProjectsList search projects", LOG_DEBUG);
7093
		$result = $this->db->query($sql);
7094
		if ($result) {
7095
			require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7096
			require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
7097
7098
			$num = $this->db->num_rows($result);
7099
7100
			$events = null;
7101
7102
			if (!$forcecombo) {
7103
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7104
				$out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7105
			}
7106
7107
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7108
7109
			$textifempty = '';
7110
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7111
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7112
			if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7113
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7114
				else $textifempty .= $langs->trans("All");
7115
			} else {
7116
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7117
			}
7118
			if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7119
7120
			$i = 0;
7121
			while ($num && $i < $num) {
7122
				$opt = '';
7123
				$optJson = array();
7124
				$objp = $this->db->fetch_object($result);
7125
7126
				$this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
7127
				// Add new entry
7128
				// "key" value of json key array is used by jQuery automatically as selected value
7129
				// "label" value of json key array is used by jQuery automatically as text for combo box
7130
				$out .= $opt;
7131
				array_push($outarray, $optJson);
7132
7133
				$i++;
7134
			}
7135
7136
			$out .= '</select>';
7137
7138
			$this->db->free($result);
7139
7140
			if (empty($outputmode)) return $out;
7141
			return $outarray;
7142
		} else {
7143
			dol_print_error($this->db);
7144
		}
7145
	}
7146
7147
	/**
7148
	 * constructProjectListOption.
7149
	 * This define value for &$opt and &$optJson.
7150
	 *
7151
	 * @param 	resource	$objp			    Result set of fetch
7152
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
7153
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
7154
	 * @param 	string		$selected		    Preselected value
7155
	 * @param   string      $filterkey          Filter key to highlight
7156
	 * @return	void
7157
	 */
7158
	protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7159
	{
7160
		$outkey = '';
7161
		$outval = '';
7162
		$outref = '';
7163
		$outlabel = '';
7164
		$outtype = '';
7165
7166
		$label = $objp->label;
7167
7168
		$outkey = $objp->rowid;
7169
		$outref = $objp->ref;
7170
		$outlabel = $objp->label;
7171
		$outtype = $objp->fk_product_type;
7172
7173
		$opt = '<option value="'.$objp->rowid.'"';
7174
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
7175
		$opt .= '>';
7176
		$opt .= $objp->ref;
7177
		$objRef = $objp->ref;
7178
		if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7179
		$outval .= $objRef;
7180
7181
		$opt .= "</option>\n";
7182
		$optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7183
	}
7184
7185
7186
	/**
7187
	 *  Return list of members in Ajax if Ajax activated or go to selectTicketsList
7188
	 *
7189
	 *  @param		int			$selected				Preselected tickets
7190
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page).
7191
	 *  @param  	string		$filtertype     		To add a filter
7192
	 *  @param		int			$limit					Limit on number of returned lines
7193
	 *  @param		int			$status					Ticket status
7194
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
7195
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon before and placeholder, 3 search icon after)
7196
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
7197
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
7198
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
7199
	 * 	@param		int			$forcecombo				Force to use combo box
7200
	 *  @param      string      $morecss                Add more css on select
7201
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
7202
	 *  @param		string		$nooutput				No print, return the output into a string
7203
	 *  @return		void|string
7204
	 */
7205
	public function selectMembers($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7206
	{
7207
		global $langs, $conf;
7208
7209
		$out = '';
7210
7211
		// check parameters
7212
		if (is_null($ajaxoptions)) $ajaxoptions = array();
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
7213
7214
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
7215
			$placeholder = '';
7216
7217
			if ($selected && empty($selected_input_value)) {
7218
				require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7219
				$adherenttmpselect = new Member($this->db);
7220
				$adherenttmpselect->fetch($selected);
7221
				$selected_input_value = $adherenttmpselect->ref;
7222
				unset($adherenttmpselect);
7223
			}
7224
7225
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $urloption seems to be never defined.
Loading history...
7226
7227
			if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
7228
			elseif ($hidelabel > 1) {
7229
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
7230
				if ($hidelabel == 2) {
7231
					$out .= img_picto($langs->trans("Search"), 'search');
7232
				}
7233
			}
7234
			$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
7235
			if ($hidelabel == 3) {
7236
				$out .= img_picto($langs->trans("Search"), 'search');
7237
			}
7238
		} else {
7239
			$out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
7240
		}
7241
7242
		if (empty($nooutput)) print $out;
7243
		else return $out;
7244
	}
7245
7246
	/**
7247
	 *	Return list of adherents.
7248
	 *  Called by selectMembers.
7249
	 *
7250
	 *	@param      int		$selected           Preselected adherent
7251
	 *	@param      string	$htmlname           Name of select html
7252
	 *  @param		string	$filtertype         Filter on adherent type
7253
	 *	@param      int		$limit              Limit on number of returned lines
7254
	 * 	@param      string	$filterkey          Filter on adherent ref or subject
7255
	 *	@param		int		$status             Ticket status
7256
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
7257
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
7258
	 * 	@param		int		$forcecombo		    Force to use combo box
7259
	 *  @param      string  $morecss            Add more css on select
7260
	 *  @return     array    				    Array of keys for json
7261
	 */
7262
	public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7263
	{
7264
		global $langs, $conf;
7265
7266
		$out = '';
7267
		$outarray = array();
7268
7269
		$selectFields = " p.rowid, p.ref";
7270
7271
		$sql = "SELECT ";
7272
		$sql .= $selectFields;
7273
		$sql .= " FROM ".$this->db->prefix()."adherent as p";
7274
		$sql .= ' WHERE p.entity IN ('.getEntity('adherent').')';
7275
7276
		// Add criteria on ref/label
7277
		if ($filterkey != '') {
7278
			$sql .= ' AND (';
7279
			$prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7280
			// For natural search
7281
			$scrit = explode(' ', $filterkey);
7282
			$i = 0;
7283
			if (count($scrit) > 1) $sql .= "(";
7284
			foreach ($scrit as $crit) {
7285
				if ($i > 0) $sql .= " AND ";
7286
				$sql .= "p.ref LIKE '".$this->db->escape($prefix.$crit)."%'";
7287
				$sql .= "";
7288
				$i++;
7289
			}
7290
			if (count($scrit) > 1) $sql .= ")";
7291
			$sql .= ')';
7292
		}
7293
7294
		$sql .= $this->db->plimit($limit, 0);
7295
7296
		// Build output string
7297
		dol_syslog(get_class($this)."::selectMembersList search adherents", LOG_DEBUG);
7298
		$result = $this->db->query($sql);
7299
		if ($result) {
7300
			require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
7301
			require_once DOL_DOCUMENT_ROOT.'/core/lib/member.lib.php';
7302
7303
			$num = $this->db->num_rows($result);
7304
7305
			$events = null;
7306
7307
			if (!$forcecombo) {
7308
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7309
				$out .= ajax_combobox($htmlname, $events, $conf->global->PROJECT_USE_SEARCH_TO_SELECT);
7310
			}
7311
7312
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
7313
7314
			$textifempty = '';
7315
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7316
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7317
			if (!empty($conf->global->PROJECT_USE_SEARCH_TO_SELECT)) {
7318
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7319
				else $textifempty .= $langs->trans("All");
7320
			} else {
7321
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
7322
			}
7323
			if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
7324
7325
			$i = 0;
7326
			while ($num && $i < $num) {
7327
				$opt = '';
7328
				$optJson = array();
7329
				$objp = $this->db->fetch_object($result);
7330
7331
				$this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
7332
				// Add new entry
7333
				// "key" value of json key array is used by jQuery automatically as selected value
7334
				// "label" value of json key array is used by jQuery automatically as text for combo box
7335
				$out .= $opt;
7336
				array_push($outarray, $optJson);
7337
7338
				$i++;
7339
			}
7340
7341
			$out .= '</select>';
7342
7343
			$this->db->free($result);
7344
7345
			if (empty($outputmode)) return $out;
7346
			return $outarray;
7347
		} else {
7348
			dol_print_error($this->db);
7349
		}
7350
	}
7351
7352
	/**
7353
	 * constructMemberListOption.
7354
	 * This define value for &$opt and &$optJson.
7355
	 *
7356
	 * @param 	resource	$objp			    Result set of fetch
7357
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
7358
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
7359
	 * @param 	string		$selected		    Preselected value
7360
	 * @param   string      $filterkey          Filter key to highlight
7361
	 * @return	void
7362
	 */
7363
	protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7364
	{
7365
		$outkey = '';
7366
		$outval = '';
7367
		$outref = '';
7368
		$outlabel = '';
7369
		$outtype = '';
7370
7371
		$label = $objp->label;
7372
7373
		$outkey = $objp->rowid;
7374
		$outref = $objp->ref;
7375
		$outlabel = $objp->label;
7376
		$outtype = $objp->fk_product_type;
7377
7378
		$opt = '<option value="'.$objp->rowid.'"';
7379
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
7380
		$opt .= '>';
7381
		$opt .= $objp->ref;
7382
		$objRef = $objp->ref;
7383
		if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
7384
		$outval .= $objRef;
7385
7386
		$opt .= "</option>\n";
7387
		$optJson = array('key'=>$outkey, 'value'=>$outref, 'type'=>$outtype);
7388
	}
7389
7390
	/**
7391
	 * Generic method to select a component from a combo list.
7392
	 * Can use autocomplete with ajax after x key pressed or a full combo, depending on setup.
7393
	 * This is the generic method that will replace all specific existing methods.
7394
	 *
7395
	 * @param 	string			$objectdesc			ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]
7396
	 * @param	string			$htmlname			Name of HTML select component
7397
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
7398
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
7399
	 * @param	string			$searchkey			Search criteria
7400
	 * @param	string			$placeholder		Place holder
7401
	 * @param	string			$morecss			More CSS
7402
	 * @param	string			$moreparams			More params provided to ajax call
7403
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
7404
	 * @param	int				$disabled			1=Html component is disabled
7405
	 * @param	string	        $selected_input_value	Value of preselected input text (for use with ajax)
7406
	 * @return	string								Return HTML string
7407
	 * @see selectForFormsList() select_thirdparty_list()
7408
	 */
7409
	public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
7410
	{
7411
		global $conf, $user;
7412
7413
		$objecttmp = null;
7414
7415
		// Example of value for $objectdec:
7416
		// Bom:bom/class/bom.class.php:0:t.status=1
7417
		// Bom:bom/class/bom.class.php:0:t.status=1:ref
7418
		// Bom:bom/class/bom.class.php:0:(t.status:=:1):ref
7419
		$InfoFieldList = explode(":", $objectdesc, 4);
7420
		$vartmp = $InfoFieldList[3];
7421
		$reg = array();
7422
		if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
7423
			$InfoFieldList[4] = $reg[1];	// take the sort field
7424
		}
7425
		$InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp);	// take the filter field
7426
7427
		$classname = $InfoFieldList[0];
7428
		$classpath = $InfoFieldList[1];
7429
		$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
7430
		$filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
7431
		$sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
7432
7433
		if (!empty($classpath)) {
7434
			dol_include_once($classpath);
7435
7436
			if ($classname && class_exists($classname)) {
7437
				$objecttmp = new $classname($this->db);
7438
				// Make some replacement
7439
				$sharedentities = getEntity(strtolower($classname));
7440
				$objecttmp->filter = str_replace(
7441
					array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
7442
					array($conf->entity, $sharedentities, $user->id),
7443
					$filter
7444
				);
7445
			}
7446
		}
7447
		if (!is_object($objecttmp)) {
7448
			dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
7449
			return 'Error bad setup of type for field '.join(',', $InfoFieldList);
7450
		}
7451
7452
		//var_dump($objecttmp->filter);
7453
		$prefixforautocompletemode = $objecttmp->element;
7454
		if ($prefixforautocompletemode == 'societe') {
7455
			$prefixforautocompletemode = 'company';
7456
		}
7457
		if ($prefixforautocompletemode == 'product') {
7458
			$prefixforautocompletemode = 'produit';
7459
		}
7460
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7461
7462
		dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG);
7463
		$out = '';
7464
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo) {
7465
			// No immediate load of all database
7466
			$placeholder = '';
7467
			if ($preselectedvalue && empty($selected_input_value)) {
7468
				$objecttmp->fetch($preselectedvalue);
7469
				$selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
7470
				//unset($objecttmp);
7471
			}
7472
7473
			$objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
7474
			$urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
7475
7476
			// No immediate load of all database
7477
			$urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&objectdesc='.urlencode($objectdesc).'&filter='.urlencode($objecttmp->filter).($sortfield ? '&sortfield='.urlencode($sortfield) : '');
7478
			// Activate the auto complete using ajax call.
7479
			$out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
7480
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
7481
			$out .= '<input type="text" class="'.$morecss.'"'.($disabled ? ' disabled="disabled"' : '').' name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '') .' />';
7482
		} else {
7483
			// Immediate load of table record. Note: filter is inside $objecttmp->filter
7484
			$out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield);
7485
		}
7486
7487
		return $out;
7488
	}
7489
7490
	/**
7491
	 * Function to forge a SQL criteria
7492
	 *
7493
	 * @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"
7494
	 * @return string                  Forged criteria. Example: "t.field like 'abc%'"
7495
	 */
7496
	protected static function forgeCriteriaCallback($matches)
7497
	{
7498
		global $db;
7499
7500
		//dol_syslog("Convert matches ".$matches[1]);
7501
		if (empty($matches[1])) {
7502
			return '';
7503
		}
7504
		$tmp = explode(':', $matches[1]);
7505
		if (count($tmp) < 3) {
7506
			return '';
7507
		}
7508
7509
		$tmpescaped = $tmp[2];
7510
		$regbis = array();
7511
		if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
7512
			$tmpescaped = "'".$db->escape($regbis[1])."'";
7513
		} else {
7514
			$tmpescaped = $db->escape($tmpescaped);
7515
		}
7516
		return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
7517
	}
7518
7519
	/**
7520
	 * Output html form to select an object.
7521
	 * Note, this function is called by selectForForms or by ajax selectobject.php
7522
	 *
7523
	 * @param 	Object			$objecttmp			Object to knwo the table to scan for combo.
7524
	 * @param	string			$htmlname			Name of HTML select component
7525
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
7526
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
7527
	 * @param	string			$searchkey			Search value
7528
	 * @param	string			$placeholder		Place holder
7529
	 * @param	string			$morecss			More CSS
7530
	 * @param	string			$moreparams			More params provided to ajax call
7531
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
7532
	 * @param	int				$outputmode			0=HTML select string, 1=Array
7533
	 * @param	int				$disabled			1=Html component is disabled
7534
	 * @param	string			$sortfield			Sort field
7535
	 * @return	string|array						Return HTML string
7536
	 * @see selectForForms()
7537
	 */
7538
	public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '')
7539
	{
7540
		global $conf, $langs, $user, $hookmanager;
7541
7542
		//print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled";
7543
7544
		$prefixforautocompletemode = $objecttmp->element;
7545
		if ($prefixforautocompletemode == 'societe') {
7546
			$prefixforautocompletemode = 'company';
7547
		}
7548
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
7549
7550
		if (!empty($objecttmp->fields)) {	// For object that declare it, it is better to use declared fields (like societe, contact, ...)
7551
			$tmpfieldstoshow = '';
7552
			foreach ($objecttmp->fields as $key => $val) {
7553
				if (!dol_eval($val['enabled'], 1, 1, 1, '1')) {
0 ignored issues
show
Unused Code introduced by
The call to dol_eval() has too many arguments starting with '1'. ( Ignorable by Annotation )

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

7553
				if (!/** @scrutinizer ignore-call */ dol_eval($val['enabled'], 1, 1, 1, '1')) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
7554
					continue;
7555
				}
7556
				if (!empty($val['showoncombobox'])) {
7557
					$tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
7558
				}
7559
			}
7560
			if ($tmpfieldstoshow) {
7561
				$fieldstoshow = $tmpfieldstoshow;
7562
			}
7563
		} else {
7564
			// For backward compatibility
7565
			$objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
7566
		}
7567
7568
		if (empty($fieldstoshow)) {
7569
			if (isset($objecttmp->fields['ref'])) {
7570
				$fieldstoshow = 't.ref';
7571
			} else {
7572
				$langs->load("errors");
7573
				$this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
7574
				return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
7575
			}
7576
		}
7577
7578
		$out = '';
7579
		$outarray = array();
7580
7581
		$num = 0;
7582
7583
		// Search data
7584
		$sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".$this->db->prefix().$objecttmp->table_element." as t";
7585
		if (isset($objecttmp->ismultientitymanaged)) {
7586
			if (!is_numeric($objecttmp->ismultientitymanaged)) {
7587
				$tmparray = explode('@', $objecttmp->ismultientitymanaged);
7588
				$sql .= " INNER JOIN ".$this->db->prefix().$tmparray[1]." as parenttable ON parenttable.rowid = t.".$tmparray[0];
7589
			}
7590
			if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7591
				if (empty($user->rights->societe->client->voir) && !$user->socid) {
7592
					$sql .= ", ".$this->db->prefix()."societe_commerciaux as sc";
7593
				}
7594
			}
7595
		}
7596
7597
		// Add where from hooks
7598
		$parameters = array();
7599
		$reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
7600
		if (!empty($hookmanager->resPrint)) {
7601
			$sql .= $hookmanager->resPrint;
7602
		} else {
7603
			$sql .= " WHERE 1=1";
7604
			if (isset($objecttmp->ismultientitymanaged)) {
7605
				if ($objecttmp->ismultientitymanaged == 1) {
7606
					$sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
7607
				}
7608
				if (!is_numeric($objecttmp->ismultientitymanaged)) {
7609
					$sql .= " AND parenttable.entity = t.".$tmparray[0];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmparray does not seem to be defined for all execution paths leading up to this point.
Loading history...
7610
				}
7611
				if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
7612
					if ($objecttmp->element == 'societe') {
7613
						$sql .= " AND t.rowid = ".((int) $user->socid);
7614
					} else {
7615
						$sql .= " AND t.fk_soc = ".((int) $user->socid);
7616
					}
7617
				}
7618
				if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
7619
					if (empty($user->rights->societe->client->voir) && !$user->socid) {
7620
						$sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
7621
					}
7622
				}
7623
			}
7624
			if ($searchkey != '') {
7625
				$sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
7626
			}
7627
			if ($objecttmp->filter) {	 // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
7628
				/*if (! DolibarrApi::_checkFilters($objecttmp->filter))
7629
				{
7630
					throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter);
7631
				}*/
7632
				$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
7633
				$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")";
7634
			}
7635
		}
7636
		$sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
7637
		//$sql.=$this->db->plimit($limit, 0);
7638
		//print $sql;
7639
7640
		// Build output string
7641
		$resql = $this->db->query($sql);
7642
		if ($resql) {
7643
			// Construct $out and $outarray
7644
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
7645
7646
			// 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
7647
			$textifempty = '&nbsp;';
7648
7649
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7650
			if (!empty($conf->global->$confkeyforautocompletemode)) {
7651
				if ($showempty && !is_numeric($showempty)) {
7652
					$textifempty = $langs->trans($showempty);
7653
				} else {
7654
					$textifempty .= $langs->trans("All");
7655
				}
7656
			}
7657
			if ($showempty) {
7658
				$out .= '<option value="-1">'.$textifempty.'</option>'."\n";
7659
			}
7660
7661
			$num = $this->db->num_rows($resql);
7662
			$i = 0;
7663
			if ($num) {
7664
				while ($i < $num) {
7665
					$obj = $this->db->fetch_object($resql);
7666
					$label = '';
7667
					$tmparray = explode(',', $fieldstoshow);
7668
					$oldvalueforshowoncombobox = 0;
7669
					foreach ($tmparray as $key => $val) {
7670
						$val = preg_replace('/t\./', '', $val);
7671
						$label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
7672
						$label .= $obj->$val;
7673
						$oldvalueforshowoncombobox = $objecttmp->fields[$val]['showoncombobox'];
7674
					}
7675
					if (empty($outputmode)) {
7676
						if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
7677
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
7678
						} else {
7679
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
7680
						}
7681
					} else {
7682
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
7683
					}
7684
7685
					$i++;
7686
					if (($i % 10) == 0) {
7687
						$out .= "\n";
7688
					}
7689
				}
7690
			}
7691
7692
			$out .= '</select>'."\n";
7693
7694
			if (!$forcecombo) {
7695
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7696
				$out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
7697
			}
7698
		} else {
7699
			dol_print_error($this->db);
7700
		}
7701
7702
		$this->result = array('nbofelement'=>$num);
7703
7704
		if ($outputmode) {
7705
			return $outarray;
7706
		}
7707
		return $out;
7708
	}
7709
7710
7711
	/**
7712
	 *	Return a HTML select string, built from an array of key+value.
7713
	 *  Note: Do not apply langs->trans function on returned content, content may be entity encoded twice.
7714
	 *
7715
	 *	@param	string			$htmlname			Name of html select area. Must start with "multi" if this is a multiselect
7716
	 *	@param	array			$array				Array like array(key => value) or array(key=>array('label'=>..., 'data-...'=>..., 'disabled'=>..., 'css'=>...))
7717
	 *	@param	string|string[]	$id					Preselected key or preselected keys for multiselect
7718
	 *	@param	int|string		$show_empty			0 no empty value allowed, 1 or string to add an empty value into list (If 1: key is -1 and value is '' or '&nbsp;', If placeholder string: key is -1 and value is the string), <0 to add an empty value with key that is this value.
7719
	 *	@param	int				$key_in_label		1 to show key into label with format "[key] value"
7720
	 *	@param	int				$value_as_key		1 to use value as key
7721
	 *	@param  string			$moreparam			Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
7722
	 *	@param  int				$translate			1=Translate and encode value
7723
	 * 	@param	int				$maxlen				Length maximum for labels
7724
	 * 	@param	int				$disabled			Html select box is disabled
7725
	 *  @param	string			$sort				'ASC' or 'DESC' = Sort on label, '' or 'NONE' or 'POS' = Do not sort, we keep original order
7726
	 *  @param	string			$morecss			Add more class to css styles
7727
	 *  @param	int				$addjscombo			Add js combo
7728
	 *  @param  string          $moreparamonempty	Add more param on the empty option line. Not used if show_empty not set
7729
	 *  @param  int             $disablebademail	1=Check if a not valid email, 2=Check string '---', and if found into value, disable and colorize entry
7730
	 *  @param  int             $nohtmlescape		No html escaping.
7731
	 * 	@return	string								HTML select string.
7732
	 *  @see multiselectarray(), selectArrayAjax(), selectArrayFilter()
7733
	 */
7734
	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 = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
7735
	{
7736
		global $conf, $langs;
7737
7738
		// Do we want a multiselect ?
7739
		//$jsbeautify = 0;
7740
		//if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
7741
		$jsbeautify = 1;
7742
7743
		if ($value_as_key) {
7744
			$array = array_combine($array, $array);
7745
		}
7746
7747
		$out = '';
7748
7749
		if ($addjscombo < 0) {
7750
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7751
				$addjscombo = 1;
7752
			} else {
7753
				$addjscombo = 0;
7754
			}
7755
		}
7756
7757
		$out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
7758
		$out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
7759
		$out .= '>';
7760
7761
		if ($show_empty) {
7762
			$textforempty = ' ';
7763
			if (!empty($conf->use_javascript_ajax)) {
7764
				$textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
7765
			}
7766
			if (!is_numeric($show_empty)) {
7767
				$textforempty = $show_empty;
7768
			}
7769
			$out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
7770
		}
7771
7772
		if (is_array($array)) {
7773
			// Translate
7774
			if ($translate) {
7775
				foreach ($array as $key => $value) {
7776
					if (!is_array($value)) {
7777
						$array[$key] = $langs->trans($value);
7778
					} else {
7779
						$array[$key]['label'] = $langs->trans($value['label']);
7780
					}
7781
				}
7782
			}
7783
7784
			// Sort
7785
			if ($sort == 'ASC') {
7786
				asort($array);
7787
			} elseif ($sort == 'DESC') {
7788
				arsort($array);
7789
			}
7790
7791
			foreach ($array as $key => $tmpvalue) {
7792
				if (is_array($tmpvalue)) {
7793
					$value = $tmpvalue['label'];
7794
					$disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
7795
					$style = empty($tmpvalue['css']) ? '' : ' class="'.$tmpvalue['css'].'"';
7796
				} else {
7797
					$value = $tmpvalue;
7798
					$disabled = '';
7799
					$style = '';
7800
				}
7801
				if (!empty($disablebademail)) {
7802
					if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
7803
						|| ($disablebademail == 2 && preg_match('/---/', $value))) {
7804
						$disabled = ' disabled';
7805
						$style = ' class="warning"';
7806
					}
7807
				}
7808
7809
				if ($key_in_label) {
7810
					if (empty($nohtmlescape)) {
7811
						$selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
7812
					} else {
7813
						$selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
7814
					}
7815
				} else {
7816
					if (empty($nohtmlescape)) {
7817
						$selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
7818
					} else {
7819
						$selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value;
7820
					}
7821
					if ($value == '' || $value == '-') {
7822
						$selectOptionValue = '&nbsp;';
7823
					}
7824
				}
7825
7826
				$out .= '<option value="'.$key.'"';
7827
				$out .= $style.$disabled;
7828
				if (is_array($id)) {
7829
					if (in_array($key, $id) && !$disabled) {
7830
						$out .= ' selected'; // To preselect a value
7831
					}
7832
				} else {
7833
					$id = (string) $id; // if $id = 0, then $id = '0'
7834
					if ($id != '' && $id == $key && !$disabled) {
7835
						$out .= ' selected'; // To preselect a value
7836
					}
7837
				}
7838
				if ($nohtmlescape) {
7839
					$out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
7840
				}
7841
				if (is_array($tmpvalue)) {
7842
					foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
7843
						if (preg_match('/^data-/', $keyforvalue)) {
7844
							$out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
7845
						}
7846
					}
7847
				}
7848
				$out .= '>';
7849
				//var_dump($selectOptionValue);
7850
				$out .= $selectOptionValue;
7851
				$out .= "</option>\n";
7852
			}
7853
		}
7854
7855
		$out .= "</select>";
7856
7857
		// Add code for jquery to use multiselect
7858
		if ($addjscombo && $jsbeautify) {
7859
			// Enhance with select2
7860
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7861
			$out .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', $show_empty < 0 ? (string) $show_empty : '-1');
7862
		}
7863
7864
		return $out;
7865
	}
7866
7867
7868
	/**
7869
	 *	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.
7870
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
7871
	 *
7872
	 *	@param	string	$htmlname       		Name of html select area
7873
	 *	@param	string	$url					Url. Must return a json_encode of array(key=>array('text'=>'A text', 'url'=>'An url'), ...)
7874
	 *	@param	string	$id             		Preselected key
7875
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
7876
	 *	@param  string	$moreparamtourl 		Add more parameters onto the Ajax called URL
7877
	 * 	@param	int		$disabled				Html select box is disabled
7878
	 *  @param	int		$minimumInputLength		Minimum Input Length
7879
	 *  @param	string	$morecss				Add more class to css styles
7880
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
7881
	 *  @param  string  $placeholder            String to use as placeholder
7882
	 *  @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)
7883
	 * 	@return	string   						HTML select string
7884
	 *  @see selectArrayFilter(), ajax_combobox() in ajax.lib.php
7885
	 */
7886
	public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
7887
	{
7888
		global $conf, $langs;
7889
		global $delayedhtmlcontent;	// Will be used later outside of this function
7890
7891
		// TODO Use an internal dolibarr component instead of select2
7892
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
7893
			return '';
7894
		}
7895
7896
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
7897
7898
		$outdelayed = '';
7899
		if (!empty($conf->use_javascript_ajax)) {
7900
			$tmpplugin = 'select2';
7901
			$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
7902
		    	<script>
7903
		    	$(document).ready(function () {
7904
7905
	    	        '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
7906
7907
	                $(".'.$htmlname.'").select2({
7908
				    	ajax: {
7909
					    	dir: "ltr",
7910
					    	url: "'.$url.'",
7911
					    	dataType: \'json\',
7912
					    	delay: 250,
7913
					    	data: function (params) {
7914
					    		return {
7915
							    	q: params.term, 	// search term
7916
					    			page: params.page
7917
					    		};
7918
				    		},
7919
				    		processResults: function (data) {
7920
				    			// parse the results into the format expected by Select2.
7921
				    			// since we are using custom formatting functions we do not need to alter the remote JSON data
7922
				    			//console.log(data);
7923
								saveRemoteData = data;
7924
					    	    /* format json result for select2 */
7925
					    	    result = []
7926
					    	    $.each( data, function( key, value ) {
7927
					    	       result.push({id: key, text: value.text});
7928
	                            });
7929
				    			//return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
7930
				    			//console.log(result);
7931
				    			return {results: result, more: false}
7932
				    		},
7933
				    		cache: true
7934
				    	},
7935
		 				language: select2arrayoflanguage,
7936
						containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
7937
					    placeholder: "'.dol_escape_js($placeholder).'",
7938
				    	escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
7939
				    	minimumInputLength: '.$minimumInputLength.',
7940
				        formatResult: function(result, container, query, escapeMarkup) {
7941
	                        return escapeMarkup(result.text);
7942
	                    },
7943
				    });
7944
7945
	                '.($callurlonselect ? '
7946
	                /* Code to execute a GET when we select a value */
7947
	                $(".'.$htmlname.'").change(function() {
7948
				    	var selected = $(".'.$htmlname.'").val();
7949
	                	console.log("We select in selectArrayAjax the entry "+selected)
7950
				        $(".'.$htmlname.'").val("");  /* reset visible combo value */
7951
	    			    $.each( saveRemoteData, function( key, value ) {
7952
	    				        if (key == selected)
7953
	    			            {
7954
	    			                 console.log("selectArrayAjax - Do a redirect to "+value.url)
7955
	    			                 location.assign(value.url);
7956
	    			            }
7957
	                    });
7958
	    			});' : '').'
7959
7960
	    	   });
7961
		       </script>';
7962
		}
7963
7964
		if ($acceptdelayedhtml) {
7965
			$delayedhtmlcontent .= $outdelayed;
7966
		} else {
7967
			$out .= $outdelayed;
7968
		}
7969
		return $out;
7970
	}
7971
7972
	/**
7973
	 *  Return a HTML select string, built from an array of key+value, but content returned into select is defined into $array parameter.
7974
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
7975
	 *
7976
	 *  @param  string	$htmlname               Name of html select area
7977
	 *	@param	array	$array					Array (key=>array('text'=>'A text', 'url'=>'An url'), ...)
7978
	 *	@param	string	$id             		Preselected key
7979
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
7980
	 *	@param	int		$disableFiltering		If set to 1, results are not filtered with searched string
7981
	 * 	@param	int		$disabled				Html select box is disabled
7982
	 *  @param	int		$minimumInputLength		Minimum Input Length
7983
	 *  @param	string	$morecss				Add more class to css styles
7984
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
7985
	 *  @param  string  $placeholder            String to use as placeholder
7986
	 *  @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)
7987
	 *  @return	string   						HTML select string
7988
	 *  @see selectArrayAjax(), ajax_combobox() in ajax.lib.php
7989
	 */
7990
	public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
7991
	{
7992
		global $conf, $langs;
7993
		global $delayedhtmlcontent;	// Will be used later outside of this function
7994
7995
		// TODO Use an internal dolibarr component instead of select2
7996
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
7997
			return '';
7998
		}
7999
8000
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
8001
8002
		$formattedarrayresult = array();
8003
8004
		foreach ($array as $key => $value) {
8005
			$o = new stdClass();
8006
			$o->id = $key;
8007
			$o->text = $value['text'];
8008
			$o->url = $value['url'];
8009
			$formattedarrayresult[] = $o;
8010
		}
8011
8012
		$outdelayed = '';
8013
		if (!empty($conf->use_javascript_ajax)) {
8014
			$tmpplugin = 'select2';
8015
			$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
8016
				<script>
8017
				$(document).ready(function () {
8018
					var data = '.json_encode($formattedarrayresult).';
8019
8020
					'.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
8021
8022
					$(".'.$htmlname.'").select2({
8023
						data: data,
8024
						language: select2arrayoflanguage,
8025
						containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
8026
						placeholder: "'.dol_escape_js($placeholder).'",
8027
						escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
8028
						minimumInputLength: '.$minimumInputLength.',
8029
						formatResult: function(result, container, query, escapeMarkup) {
8030
							return escapeMarkup(result.text);
8031
						},
8032
						matcher: function (params, data) {
8033
8034
							if(! data.id) return null;';
8035
8036
			if ($callurlonselect) {
8037
				$outdelayed .= '
8038
8039
							var urlBase = data.url;
8040
							var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
8041
							/* console.log("params.term="+params.term); */
8042
							/* console.log("params.term encoded="+encodeURIComponent(params.term)); */
8043
							saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
8044
			}
8045
8046
			if (!$disableFiltering) {
8047
				$outdelayed .= '
8048
8049
							if(data.text.match(new RegExp(params.term))) {
8050
								return data;
8051
							}
8052
8053
							return null;';
8054
			} else {
8055
				$outdelayed .= '
8056
8057
							return data;';
8058
			}
8059
8060
			$outdelayed .= '
8061
						}
8062
					});
8063
8064
					'.($callurlonselect ? '
8065
					/* Code to execute a GET when we select a value */
8066
					$(".'.$htmlname.'").change(function() {
8067
						var selected = $(".'.$htmlname.'").val();
8068
						console.log("We select "+selected)
8069
8070
						$(".'.$htmlname.'").val("");  /* reset visible combo value */
8071
						$.each( saveRemoteData, function( key, value ) {
8072
							if (key == selected)
8073
							{
8074
								console.log("selectArrayFilter - Do a redirect to "+value.url)
8075
								location.assign(value.url);
8076
							}
8077
						});
8078
					});' : '').'
8079
8080
				});
8081
				</script>';
8082
		}
8083
8084
		if ($acceptdelayedhtml) {
8085
			$delayedhtmlcontent .= $outdelayed;
8086
		} else {
8087
			$out .= $outdelayed;
8088
		}
8089
		return $out;
8090
	}
8091
8092
	/**
8093
	 *	Show a multiselect form from an array. WARNING: Use this only for short lists.
8094
	 *
8095
	 *	@param	string		$htmlname		Name of select
8096
	 *	@param	array		$array			Array with key+value
8097
	 *	@param	array		$selected		Array with key+value preselected
8098
	 *	@param	int			$key_in_label   1 to show key like in "[key] value"
8099
	 *	@param	int			$value_as_key   1 to use value as key
8100
	 *	@param  string		$morecss        Add more css style
8101
	 *	@param  int			$translate		Translate and encode value
8102
	 *  @param	int|string	$width			Force width of select box. May be used only when using jquery couch. Example: 250, '95%'
8103
	 *  @param	string		$moreattrib		Add more options on select component. Example: 'disabled'
8104
	 *  @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.
8105
	 *  @param	string		$placeholder	String to use as placeholder
8106
	 *  @param	int			$addjscombo		Add js combo
8107
	 *	@return	string						HTML multiselect string
8108
	 *  @see selectarray(), selectArrayAjax(), selectArrayFilter()
8109
	 */
8110
	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)
8111
	{
8112
		global $conf, $langs;
8113
8114
		$out = '';
8115
8116
		if ($addjscombo < 0) {
8117
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8118
				$addjscombo = 1;
8119
			} else {
8120
				$addjscombo = 0;
8121
			}
8122
		}
8123
8124
		// Try also magic suggest
8125
		$out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
8126
		if (is_array($array) && !empty($array)) {
8127
			if ($value_as_key) {
8128
				$array = array_combine($array, $array);
8129
			}
8130
8131
			if (!empty($array)) {
8132
				foreach ($array as $key => $value) {
8133
					$newval = ($translate ? $langs->trans($value) : $value);
8134
					$newval = ($key_in_label ? $key.' - '.$newval : $newval);
8135
8136
					$out .= '<option value="'.$key.'"';
8137
					if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != '')) {
8138
						$out .= ' selected';
8139
					}
8140
					$out .= ' data-html="'.dol_escape_htmltag($newval).'"';
8141
					$out .= '>';
8142
					$out .= dol_htmlentitiesbr($newval);
8143
					$out .= '</option>'."\n";
8144
				}
8145
			}
8146
		}
8147
		$out .= '</select>'."\n";
8148
8149
		// Add code for jquery to use multiselect
8150
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
8151
			$out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->';
8152
			$out .= "\n".'<script>'."\n";
8153
			if ($addjscombo == 1) {
8154
				$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
8155
				$out .= 'function formatResult(record, container) {'."\n";
8156
				$out .= '	if ($(record.element).attr("data-html") != undefined) return htmlEntityDecodeJs($(record.element).attr("data-html"));		// If property html set, we decode html entities and use this'."\n";
8157
				$out .= '	return record.text;';
8158
				$out .= '};'."\n";
8159
				$out .= 'function formatSelection(record) {'."\n";
8160
				if ($elemtype == 'category') {
8161
					$out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
8162
				} else {
8163
					$out .= 'return record.text;';
8164
				}
8165
				$out .= '};'."\n";
8166
				$out .= '$(document).ready(function () {
8167
							$(\'#'.$htmlname.'\').'.$tmpplugin.'({';
8168
				if ($placeholder) {
8169
					$out .= '
8170
								placeholder: {
8171
								    id: \'-1\',
8172
								    text: \''.dol_escape_js($placeholder).'\'
8173
								  },';
8174
				}
8175
				$out .= '		dir: \'ltr\',
8176
								// Specify format function for dropdown item
8177
								formatResult: formatResult,
8178
							 	templateResult: formatResult,		/* For 4.0 */
8179
								escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
8180
								// Specify format function for selected item
8181
								formatSelection: formatSelection,
8182
							 	templateSelection: formatSelection		/* For 4.0 */
8183
							});
8184
8185
							/* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
8186
								 the size only if component is not hidden by default on load */
8187
							$(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\');
8188
						});'."\n";
8189
			} elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
8190
				// Add other js lib
8191
				// TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
8192
				// ...
8193
				$out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
8194
				$out .= '$(document).ready(function () {
8195
							$(\'#'.$htmlname.'\').multiSelect({
8196
								containerHTML: \'<div class="multi-select-container">\',
8197
								menuHTML: \'<div class="multi-select-menu">\',
8198
								buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
8199
								menuItemHTML: \'<label class="multi-select-menuitem">\',
8200
								activeClass: \'multi-select-container--open\',
8201
								noneText: \''.$placeholder.'\'
8202
							});
8203
						})';
8204
			}
8205
			$out .= '</script>';
8206
		}
8207
8208
		return $out;
8209
	}
8210
8211
8212
	/**
8213
	 *	Show a multiselect dropbox from an array. If a saved selection of fields exists for user (into $user->conf->MAIN_SELECTEDFIELDS_contextofpage), we use this one instead of default.
8214
	 *
8215
	 *	@param	string	$htmlname		Name of HTML field
8216
	 *	@param	array	$array			Array with array of fields we could show. This array may be modified according to setup of user.
8217
	 *  @param  string  $varpage        Id of context for page. Can be set by caller with $varpage=(empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage);
8218
	 *	@return	string					HTML multiselect string
8219
	 *  @see selectarray()
8220
	 */
8221
	public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
8222
	{
8223
		global $conf, $langs, $user, $extrafields;
8224
8225
		if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
8226
			return '';
8227
		}
8228
8229
		$tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved selected fields to show
8230
8231
		if (!empty($user->conf->$tmpvar)) {		// A list of fields was already customized for user
8232
			$tmparray = explode(',', $user->conf->$tmpvar);
8233
			foreach ($array as $key => $val) {
8234
				//var_dump($key);
8235
				//var_dump($tmparray);
8236
				if (in_array($key, $tmparray)) {
8237
					$array[$key]['checked'] = 1;
8238
				} else {
8239
					$array[$key]['checked'] = 0;
8240
				}
8241
			}
8242
		} else {								// There is no list of fields already customized for user
8243
			foreach ($array as $key => $val) {
8244
				if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
8245
					$array[$key]['checked'] = 0;
8246
				}
8247
			}
8248
		}
8249
8250
		$listoffieldsforselection = '';
8251
		$listcheckedstring = '';
8252
8253
		foreach ($array as $key => $val) {
8254
			/* var_dump($val);
8255
			var_dump(array_key_exists('enabled', $val));
8256
			var_dump(!$val['enabled']);*/
8257
			if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
8258
				unset($array[$key]); // We don't want this field
8259
				continue;
8260
			}
8261
			if (!empty($val['type']) && $val['type'] == 'separate') {
8262
				// Field remains in array but we don't add it into $listoffieldsforselection
8263
				//$listoffieldsforselection .= '<li>-----</li>';
8264
				continue;
8265
			}
8266
			if ($val['label']) {
8267
				if (!empty($val['langfile']) && is_object($langs)) {
8268
					$langs->load($val['langfile']);
8269
				}
8270
8271
				// Note: $val['checked'] <> 0 means we must show the field into the combo list
8272
				$listoffieldsforselection .= '<li><input type="checkbox" id="checkbox'.$key.'" value="'.$key.'"'.((empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"').'/><label for="checkbox'.$key.'">'.dol_escape_htmltag($langs->trans($val['label'])).'</label></li>';
8273
				$listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
8274
			}
8275
		}
8276
8277
		$out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
8278
8279
        <dl class="dropdown">
8280
            <dt>
8281
            <a href="#'.$htmlname.'">
8282
              '.img_picto('', 'list').'
8283
            </a>
8284
            <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
8285
            </dt>
8286
            <dd class="dropdowndd">
8287
                <div class="multiselectcheckbox'.$htmlname.'">
8288
                    <ul class="ul'.$htmlname.'">
8289
                    '.$listoffieldsforselection.'
8290
                    </ul>
8291
                </div>
8292
            </dd>
8293
        </dl>
8294
8295
        <script type="text/javascript">
8296
          jQuery(document).ready(function () {
8297
              $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
8298
                  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
8299
8300
                  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\');	// Update field so we know we changed something on selected fields after POST
8301
8302
                  var title = $(this).val() + ",";
8303
                  if ($(this).is(\':checked\')) {
8304
                      $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
8305
                  }
8306
                  else {
8307
                      $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
8308
                  }
8309
                  // Now, we submit page
8310
                  //$(this).parents(\'form:first\').submit();
8311
              });
8312
8313
8314
           });
8315
        </script>
8316
8317
        ';
8318
		return $out;
8319
	}
8320
8321
	/**
8322
	 * 	Render list of categories linked to object with id $id and type $type
8323
	 *
8324
	 * 	@param		int		$id				Id of object
8325
	 * 	@param		string	$type			Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
8326
	 *  @param		int		$rendermode		0=Default, use multiselect. 1=Emulate multiselect (recommended)
8327
	 *  @param		int		$nolink			1=Do not add html links
8328
	 * 	@return		string					String with categories
8329
	 */
8330
	public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
8331
	{
8332
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
8333
8334
		$cat = new Categorie($this->db);
8335
		$categories = $cat->containing($id, $type);
8336
8337
		if ($rendermode == 1) {
8338
			$toprint = array();
8339
			foreach ($categories as $c) {
8340
				$ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
8341
				foreach ($ways as $way) {
8342
					$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>';
8343
				}
8344
			}
8345
			return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
8346
		}
8347
8348
		if ($rendermode == 0) {
8349
			$arrayselected = array();
8350
			$cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
8351
			foreach ($categories as $c) {
8352
				$arrayselected[] = $c->id;
8353
			}
8354
8355
			return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
8356
		}
8357
8358
		return 'ErrorBadValueForParameterRenderMode'; // Should not happened
8359
	}
8360
8361
	/**
8362
	 *  Show linked object block.
8363
	 *
8364
	 *  @param	CommonObject	$object		      Object we want to show links to
8365
	 *  @param  string          $morehtmlright    More html to show on right of title
8366
	 *  @param  array           $compatibleImportElementsList  Array of compatibles elements object for "import from" action
8367
	 *  @return	int							      <0 if KO, >=0 if OK
8368
	 */
8369
	public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false)
8370
	{
8371
		global $conf, $langs, $hookmanager;
8372
		global $bc, $action;
8373
8374
		$object->fetchObjectLinked();
8375
8376
		// Bypass the default method
8377
		$hookmanager->initHooks(array('commonobject'));
8378
		$parameters = array(
8379
			'morehtmlright' => $morehtmlright,
8380
			'compatibleImportElementsList' => &$compatibleImportElementsList,
8381
		);
8382
		$reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8383
8384
		if (empty($reshook)) {
8385
			$nbofdifferenttypes = count($object->linkedObjects);
8386
8387
			print '<!-- showLinkedObjectBlock -->';
8388
			print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
8389
8390
8391
			print '<div class="div-table-responsive-no-min">';
8392
			print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'"  data-elementid="'.$object->id.'"   >';
8393
8394
			print '<tr class="liste_titre">';
8395
			print '<td>'.$langs->trans("Type").'</td>';
8396
			print '<td>'.$langs->trans("Ref").'</td>';
8397
			print '<td class="center"></td>';
8398
			print '<td class="center">'.$langs->trans("Date").'</td>';
8399
			print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8400
			print '<td class="right">'.$langs->trans("Status").'</td>';
8401
			print '<td></td>';
8402
			print '</tr>';
8403
8404
			$nboftypesoutput = 0;
8405
8406
			foreach ($object->linkedObjects as $objecttype => $objects) {
8407
				$tplpath = $element = $subelement = $objecttype;
8408
8409
				// to display inport button on tpl
8410
				$showImportButton = false;
8411
				if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
8412
					$showImportButton = true;
8413
				}
8414
8415
				$regs = array();
8416
				if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
8417
					$element = $regs[1];
8418
					$subelement = $regs[2];
8419
					$tplpath = $element.'/'.$subelement;
8420
				}
8421
				$tplname = 'linkedobjectblock';
8422
8423
				// To work with non standard path
8424
				if ($objecttype == 'facture') {
8425
					$tplpath = 'compta/'.$element;
8426
					if (empty($conf->facture->enabled)) {
8427
						continue; // Do not show if module disabled
8428
					}
8429
				} elseif ($objecttype == 'facturerec') {
8430
					$tplpath = 'compta/facture';
8431
					$tplname = 'linkedobjectblockForRec';
8432
					if (empty($conf->facture->enabled)) {
8433
						continue; // Do not show if module disabled
8434
					}
8435
				} elseif ($objecttype == 'propal') {
8436
					$tplpath = 'comm/'.$element;
8437
					if (empty($conf->propal->enabled)) {
8438
						continue; // Do not show if module disabled
8439
					}
8440
				} elseif ($objecttype == 'supplier_proposal') {
8441
					if (empty($conf->supplier_proposal->enabled)) {
8442
						continue; // Do not show if module disabled
8443
					}
8444
				} elseif ($objecttype == 'shipping' || $objecttype == 'shipment') {
8445
					$tplpath = 'expedition';
8446
					if (empty($conf->expedition->enabled)) {
8447
						continue; // Do not show if module disabled
8448
					}
8449
				} elseif ($objecttype == 'reception') {
8450
					$tplpath = 'reception';
8451
					if (empty($conf->reception->enabled)) {
8452
						continue; // Do not show if module disabled
8453
					}
8454
				} elseif ($objecttype == 'delivery') {
8455
					$tplpath = 'delivery';
8456
					if (empty($conf->expedition->enabled)) {
8457
						continue; // Do not show if module disabled
8458
					}
8459
				} elseif ($objecttype == 'mo') {
8460
					$tplpath = 'mrp/mo';
8461
					if (empty($conf->mrp->enabled)) {
8462
						continue; // Do not show if module disabled
8463
					}
8464
				} elseif ($objecttype == 'ficheinter') {
8465
					$tplpath = 'fichinter';
8466
					if (empty($conf->ficheinter->enabled)) {
8467
						continue; // Do not show if module disabled
8468
					}
8469
				} elseif ($objecttype == 'invoice_supplier') {
8470
					$tplpath = 'fourn/facture';
8471
				} elseif ($objecttype == 'order_supplier') {
8472
					$tplpath = 'fourn/commande';
8473
				} elseif ($objecttype == 'expensereport') {
8474
					$tplpath = 'expensereport';
8475
				} elseif ($objecttype == 'subscription') {
8476
					$tplpath = 'adherents';
8477
				} elseif ($objecttype == 'conferenceorbooth') {
8478
					$tplpath = 'eventorganization';
8479
				} elseif ($objecttype == 'conferenceorboothattendee') {
8480
					$tplpath = 'eventorganization';
8481
				} elseif ($objecttype == 'mo') {
8482
					$tplpath = 'mrp';
8483
					if (empty($conf->mrp->enabled)) {
8484
						continue; // Do not show if module disabled
8485
					}
8486
				}
8487
8488
				global $linkedObjectBlock;
8489
				$linkedObjectBlock = $objects;
8490
8491
				// Output template part (modules that overwrite templates must declare this into descriptor)
8492
				$dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
8493
				foreach ($dirtpls as $reldir) {
8494
					if ($nboftypesoutput == ($nbofdifferenttypes - 1)) {    // No more type to show after
8495
						global $noMoreLinkedObjectBlockAfter;
8496
						$noMoreLinkedObjectBlockAfter = 1;
8497
					}
8498
8499
					$res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
8500
					if ($res) {
8501
						$nboftypesoutput++;
8502
						break;
8503
					}
8504
				}
8505
			}
8506
8507
			if (!$nboftypesoutput) {
8508
				print '<tr><td class="impair" colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
8509
			}
8510
8511
			print '</table>';
8512
8513
			if (!empty($compatibleImportElementsList)) {
8514
				$res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
8515
			}
8516
8517
8518
			print '</div>';
8519
8520
			return $nbofdifferenttypes;
8521
		}
8522
	}
8523
8524
	/**
8525
	 *  Show block with links to link to other objects.
8526
	 *
8527
	 *  @param	CommonObject	$object				Object we want to show links to
8528
	 *  @param	array			$restrictlinksto	Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction.
8529
	 *  @param	array			$excludelinksto		Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion.
8530
	 *  @return	string								<0 if KO, >0 if OK
8531
	 */
8532
	public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
8533
	{
8534
		global $conf, $langs, $hookmanager;
8535
		global $action;
8536
8537
		$linktoelem = '';
8538
		$linktoelemlist = '';
8539
		$listofidcompanytoscan = '';
8540
8541
		if (!is_object($object->thirdparty)) {
8542
			$object->fetch_thirdparty();
8543
		}
8544
8545
		$possiblelinks = array();
8546
		if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
8547
			$listofidcompanytoscan = $object->thirdparty->id;
8548
			if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
8549
				$listofidcompanytoscan .= ','.$object->thirdparty->parent;
8550
			}
8551
			if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
8552
				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
8553
				$tmpproject = new Project($this->db);
8554
				$tmpproject->fetch($object->fk_project);
8555
				if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
8556
					$listofidcompanytoscan .= ','.$tmpproject->socid;
8557
				}
8558
				unset($tmpproject);
8559
			}
8560
8561
			$possiblelinks = array(
8562
				'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 ".$this->db->prefix()."societe as s, ".$this->db->prefix()."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('propal').')'),
8563
				'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 ".$this->db->prefix()."societe as s, ".$this->db->prefix()."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande').')'),
8564
				'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_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('invoice').')'),
8565
				'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_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('invoice').')'),
8566
				'contrat'=>array(
8567
					'enabled'=>$conf->contrat->enabled,
8568
					'perms'=>1,
8569
					'label'=>'LinkToContract',
8570
					'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, SUM(td.total_ht) as total_ht
8571
							FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."contrat as t, ".$this->db->prefix()."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('contract').') GROUP BY s.rowid, s.nom, s.client, t.rowid, t.ref, t.ref_customer, t.ref_supplier'
8572
				),
8573
				'fichinter'=>array('enabled'=>!empty($conf->ficheinter->enabled) ? $conf->ficheinter->enabled : 0, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix()."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('intervention').')'),
8574
				'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 ".$this->db->prefix()."societe as s, ".$this->db->prefix()."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('supplier_proposal').')'),
8575
				'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 ".$this->db->prefix()."societe as s, ".$this->db->prefix()."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande_fournisseur').')'),
8576
				'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 ".$this->db->prefix()."societe as s, ".$this->db->prefix()."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('facture_fourn').')'),
8577
				'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 ".$this->db->prefix()."societe as s, ".$this->db->prefix()."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('ticket').')'),
8578
				'mo'=>array('enabled'=>$conf->mrp->enabled, 'perms'=>1, 'label'=>'LinkToMo', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix()."mrp_mo as t ON t.fk_soc = s.rowid  WHERE  t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('mo').')')
8579
			);
8580
		}
8581
8582
		if (!empty($listofidcompanytoscan)) {  // If empty, we don't have criteria to scan the object we can link to
8583
			// Can complete the possiblelink array
8584
			$hookmanager->initHooks(array('commonobject'));
8585
			$parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
8586
			$reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
8587
		}
8588
8589
		if (empty($reshook)) {
8590
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8591
				$possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
8592
			}
8593
		} 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...
8594
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
8595
				$possiblelinks = $hookmanager->resArray;
8596
			}
8597
		}
8598
8599
		foreach ($possiblelinks as $key => $possiblelink) {
8600
			$num = 0;
8601
8602
			if (empty($possiblelink['enabled'])) {
8603
				continue;
8604
			}
8605
8606
			if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
8607
				print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
8608
8609
				if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8610
					print '<br><form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
8611
					print '<input type="hidden" name="id" value="' . $object->id . '">';
8612
					print '<input type="hidden" name="action" value="addlinkbyref">';
8613
					print '<input type="hidden" name="token" value="'.newToken().'">';
8614
					print '<input type="hidden" name="addlink" value="' . $key . '">';
8615
					print '<table class="noborder">';
8616
					print '<tr>';
8617
					print '<td>' . $langs->trans("Ref") . '</td>';
8618
					print '<td><input type="text" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;<input type="submit" class="button valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;<input type="submit" class="button" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
8619
					print '</tr>';
8620
					print '</table>';
8621
					print '</form>';
8622
				}
8623
8624
				$sql = $possiblelink['sql'];
8625
8626
				$resqllist = $this->db->query($sql);
8627
				if ($resqllist) {
8628
					$num = $this->db->num_rows($resqllist);
8629
					$i = 0;
8630
8631
					print '<br>';
8632
					print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
8633
					print '<input type="hidden" name="action" value="addlink">';
8634
					print '<input type="hidden" name="token" value="'.newToken().'">';
8635
					print '<input type="hidden" name="id" value="'.$object->id.'">';
8636
					print '<input type="hidden" name="addlink" value="'.$key.'">';
8637
					print '<table class="noborder">';
8638
					print '<tr class="liste_titre">';
8639
					print '<td class="nowrap"></td>';
8640
					print '<td class="center">'.$langs->trans("Ref").'</td>';
8641
					print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
8642
					print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8643
					print '<td class="left">'.$langs->trans("Company").'</td>';
8644
					print '</tr>';
8645
					while ($i < $num) {
8646
						$objp = $this->db->fetch_object($resqllist);
8647
8648
						print '<tr class="oddeven">';
8649
						print '<td class="left">';
8650
						print '<input type="radio" name="idtolinkto" id="'.$key.'_'.$objp->rowid.'" value="'.$objp->rowid.'">';
8651
						print '</td>';
8652
						print '<td class="center"><label for="'.$key.'_'.$objp->rowid.'">'.$objp->ref.'</label></td>';
8653
						print '<td>'.(!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')).'</td>';
8654
						print '<td class="right">';
8655
						if ($possiblelink['label'] == 'LinkToContract') {
8656
							$form = new Form($this->db);
8657
							print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' ';
8658
						}
8659
						print '<span class="amount">'.price($objp->total_ht).'</span>';
8660
						print '</td>';
8661
						print '<td>'.$objp->name.'</td>';
8662
						print '</tr>';
8663
						$i++;
8664
					}
8665
					print '</table>';
8666
					print '<div class="center">';
8667
					print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly" value="'.$langs->trans('ToLink').'">';
8668
					if (empty($conf->use_javascript_ajax)) {
8669
						print '<input type="submit" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
8670
					} else {
8671
						print '<input type="submit"; onclick="javascript:jQuery(\'#'.$key.'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
8672
					}
8673
					print '</form>';
8674
					$this->db->free($resqllist);
8675
				} else {
8676
					dol_print_error($this->db);
8677
				}
8678
				print '</div>';
8679
8680
				//$linktoelem.=($linktoelem?' &nbsp; ':'');
8681
				if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8682
					$linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
8683
					// } else $linktoelem.=$langs->trans($possiblelink['label']);
8684
				} else {
8685
					$linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
8686
				}
8687
			}
8688
		}
8689
8690
		if ($linktoelemlist) {
8691
			$linktoelem = '
8692
    		<dl class="dropdown" id="linktoobjectname">
8693
    		';
8694
			if (!empty($conf->use_javascript_ajax)) {
8695
				$linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>'.$langs->trans("LinkTo").'...</a></dt>';
8696
			}
8697
			$linktoelem .= '<dd>
8698
    		<div class="multiselectlinkto">
8699
    		<ul class="ulselectedfields">'.$linktoelemlist.'
8700
    		</ul>
8701
    		</div>
8702
    		</dd>
8703
    		</dl>';
8704
		} else {
8705
			$linktoelem = '';
8706
		}
8707
8708
		if (!empty($conf->use_javascript_ajax)) {
8709
			print '<!-- Add js to show linkto box -->
8710
				<script>
8711
				jQuery(document).ready(function() {
8712
					jQuery(".linkto").click(function() {
8713
						console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
8714
					    jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
8715
					});
8716
				});
8717
				</script>
8718
		    ';
8719
		}
8720
8721
		return $linktoelem;
8722
	}
8723
8724
	/**
8725
	 *	Return an html string with a select combo box to choose yes or no
8726
	 *
8727
	 *	@param	string		$htmlname		Name of html select field
8728
	 *	@param	string		$value			Pre-selected value
8729
	 *	@param	int			$option			0 return yes/no, 1 return 1/0
8730
	 *	@param	bool		$disabled		true or false
8731
	 *  @param	int      	$useempty		1=Add empty line
8732
	 *  @param	int			$addjscombo		1=Add js beautifier on combo box
8733
	 *  @param	string		$morecss		More CSS
8734
	 *	@return	string						See option
8735
	 */
8736
	public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '')
8737
	{
8738
		global $langs;
8739
8740
		$yes = "yes";
8741
		$no = "no";
8742
		if ($option) {
8743
			$yes = "1";
8744
			$no = "0";
8745
		}
8746
8747
		$disabled = ($disabled ? ' disabled' : '');
8748
8749
		$resultyesno = '<select class="flat width75'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
8750
		if ($useempty) {
8751
			$resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
8752
		}
8753
		if (("$value" == 'yes') || ($value == 1)) {
8754
			$resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
8755
			$resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
8756
		} else {
8757
			$selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
8758
			$resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
8759
			$resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
8760
		}
8761
		$resultyesno .= '</select>'."\n";
8762
8763
		if ($addjscombo) {
8764
			$resultyesno .= ajax_combobox($htmlname);
8765
		}
8766
8767
		return $resultyesno;
8768
	}
8769
8770
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8771
	/**
8772
	 *  Return list of export templates
8773
	 *
8774
	 *  @param	string	$selected          Id modele pre-selectionne
8775
	 *  @param  string	$htmlname          Name of HTML select
8776
	 *  @param  string	$type              Type of searched templates
8777
	 *  @param  int		$useempty          Affiche valeur vide dans liste
8778
	 *  @return	void
8779
	 */
8780
	public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
8781
	{
8782
		// phpcs:enable
8783
		$sql = "SELECT rowid, label";
8784
		$sql .= " FROM ".$this->db->prefix()."export_model";
8785
		$sql .= " WHERE type = '".$this->db->escape($type)."'";
8786
		$sql .= " ORDER BY rowid";
8787
		$result = $this->db->query($sql);
8788
		if ($result) {
8789
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
8790
			if ($useempty) {
8791
				print '<option value="-1">&nbsp;</option>';
8792
			}
8793
8794
			$num = $this->db->num_rows($result);
8795
			$i = 0;
8796
			while ($i < $num) {
8797
				$obj = $this->db->fetch_object($result);
8798
				if ($selected == $obj->rowid) {
8799
					print '<option value="'.$obj->rowid.'" selected>';
8800
				} else {
8801
					print '<option value="'.$obj->rowid.'">';
8802
				}
8803
				print $obj->label;
8804
				print '</option>';
8805
				$i++;
8806
			}
8807
			print "</select>";
8808
		} else {
8809
			dol_print_error($this->db);
8810
		}
8811
	}
8812
8813
	/**
8814
	 *    Return a HTML area with the reference of object and a navigation bar for a business object
8815
	 *    Note: To complete search with a particular filter on select, you can set $object->next_prev_filter set to define SQL criterias.
8816
	 *
8817
	 *    @param	object	$object			Object to show.
8818
	 *    @param	string	$paramid   		Name of parameter to use to name the id into the URL next/previous link.
8819
	 *    @param	string	$morehtml  		More html content to output just before the nav bar.
8820
	 *    @param	int		$shownav	  	Show Condition (navigation is shown if value is 1).
8821
	 *    @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.
8822
	 *    @param	string	$fieldref   	Name of field ref of object (object->ref) to show or 'none' to not show ref.
8823
	 *    @param	string	$morehtmlref  	More html to show after ref.
8824
	 *    @param	string	$moreparam  	More param to add in nav link url. Must start with '&...'.
8825
	 *	  @param	int		$nodbprefix		Do not include DB prefix to forge table name.
8826
	 *	  @param	string	$morehtmlleft	More html code to show before ref.
8827
	 *	  @param	string	$morehtmlstatus	More html code to show under navigation arrows (status place).
8828
	 *	  @param	string	$morehtmlright	More html code to show after ref.
8829
	 * 	  @return	string    				Portion HTML with ref + navigation buttons
8830
	 */
8831
	public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
8832
	{
8833
		global $conf, $langs, $hookmanager, $extralanguages;
8834
8835
		$ret = '';
8836
		if (empty($fieldid)) {
8837
			$fieldid = 'rowid';
8838
		}
8839
		if (empty($fieldref)) {
8840
			$fieldref = 'ref';
8841
		}
8842
8843
		// Preparing gender's display if there is one
8844
		$addgendertxt = '';
8845
		if (property_exists($object, 'gender') && !empty($object->gender)) {
8846
			$addgendertxt = ' ';
8847
			switch ($object->gender) {
8848
				case 'man':
8849
					$addgendertxt .= '<i class="fas fa-mars"></i>';
8850
					break;
8851
				case 'woman':
8852
					$addgendertxt .= '<i class="fas fa-venus"></i>';
8853
					break;
8854
				case 'other':
8855
					$addgendertxt .= '<i class="fas fa-genderless"></i>';
8856
					break;
8857
			}
8858
		}
8859
		/*
8860
		$addadmin = '';
8861
		if (property_exists($object, 'admin')) {
8862
			if (!empty($conf->multicompany->enabled) && !empty($object->admin) && empty($object->entity)) {
8863
				$addadmin .= img_picto($langs->trans("SuperAdministratorDesc"), "redstar", 'class="paddingleft"');
8864
			} elseif (!empty($object->admin)) {
8865
				$addadmin .= img_picto($langs->trans("AdministratorDesc"), "star", 'class="paddingleft"');
8866
			}
8867
		}*/
8868
8869
		// Add where from hooks
8870
		if (is_object($hookmanager)) {
8871
			$parameters = array('showrefnav' => true);
8872
			$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
8873
			$object->next_prev_filter .= $hookmanager->resPrint;
8874
		}
8875
		$previous_ref = $next_ref = '';
8876
		if ($shownav) {
8877
			//print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
8878
			$object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
8879
8880
			$navurl = $_SERVER["PHP_SELF"];
8881
			// Special case for project/task page
8882
			if ($paramid == 'project_ref') {
8883
				if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) {     // TODO Remove this when nav with project_ref on task pages are ok
8884
					$navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
8885
					$paramid = 'ref';
8886
				}
8887
			}
8888
8889
			// accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
8890
			// accesskey is for Mac:               CTRL + key for all browsers
8891
			$stringforfirstkey = $langs->trans("KeyboardShortcut");
8892
			if ($conf->browser->name == 'chrome') {
8893
				$stringforfirstkey .= ' ALT +';
8894
			} elseif ($conf->browser->name == 'firefox') {
8895
				$stringforfirstkey .= ' ALT + SHIFT +';
8896
			} else {
8897
				$stringforfirstkey .= ' CTL +';
8898
			}
8899
8900
			$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>';
8901
			$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>';
8902
		}
8903
8904
		//print "xx".$previous_ref."x".$next_ref;
8905
		$ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
8906
8907
		// Right part of banner
8908
		if ($morehtmlright) {
8909
			$ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
8910
		}
8911
8912
		if ($previous_ref || $next_ref || $morehtml) {
8913
			$ret .= '<div class="pagination paginationref"><ul class="right">';
8914
		}
8915
		if ($morehtml) {
8916
			$ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>';
8917
		}
8918
		if ($shownav && ($previous_ref || $next_ref)) {
8919
			$ret .= '<li class="pagination">'.$previous_ref.'</li>';
8920
			$ret .= '<li class="pagination">'.$next_ref.'</li>';
8921
		}
8922
		if ($previous_ref || $next_ref || $morehtml) {
8923
			$ret .= '</ul></div>';
8924
		}
8925
8926
		$parameters = array();
8927
		$reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
8928
		if (empty($reshook)) {
8929
			$morehtmlstatus .= $hookmanager->resPrint;
8930
		} else {
8931
			$morehtmlstatus = $hookmanager->resPrint;
8932
		}
8933
		if ($morehtmlstatus) {
8934
			$ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
8935
		}
8936
8937
		$parameters = array();
8938
		$reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
8939
		if (empty($reshook)) {
8940
			$morehtmlref .= $hookmanager->resPrint;
8941
		} elseif ($reshook > 0) {
8942
			$morehtmlref = $hookmanager->resPrint;
8943
		}
8944
8945
		// Left part of banner
8946
		if ($morehtmlleft) {
8947
			if ($conf->browser->layout == 'phone') {
8948
				$ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
8949
			} else {
8950
				$ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
8951
			}
8952
		}
8953
8954
		//if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
8955
		$ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
8956
8957
		// For thirdparty, contact, user, member, the ref is the id, so we show something else
8958
		if ($object->element == 'societe') {
8959
			$ret .= dol_htmlentities($object->name);
8960
8961
			// List of extra languages
8962
			$arrayoflangcode = array();
8963
			if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
8964
				$arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
8965
			}
8966
8967
			if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
8968
				if (!is_object($extralanguages)) {
8969
					include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
8970
					$extralanguages = new ExtraLanguages($this->db);
8971
				}
8972
				$extralanguages->fetch_name_extralanguages('societe');
8973
8974
				if (!empty($extralanguages->attributes['societe']['name'])) {
8975
					$object->fetchValuesForExtraLanguages();
8976
8977
					$htmltext = '';
8978
					// If there is extra languages
8979
					foreach ($arrayoflangcode as $extralangcode) {
8980
						$htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
8981
						if ($object->array_languages['name'][$extralangcode]) {
8982
							$htmltext .= $object->array_languages['name'][$extralangcode];
8983
						} else {
8984
							$htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
8985
						}
8986
					}
8987
					$ret .= '<!-- Show translations of name -->'."\n";
8988
					$ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
8989
				}
8990
			}
8991
		} elseif ($object->element == 'member') {
8992
			$ret .= $object->ref.'<br>';
8993
			$fullname = $object->getFullName($langs);
8994
			if ($object->morphy == 'mor' && $object->societe) {
8995
				$ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).$addgendertxt.')' : '');
8996
			} else {
8997
				$ret .= dol_htmlentities($fullname).$addgendertxt.((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
8998
			}
8999
		} elseif (in_array($object->element, array('contact', 'user', 'usergroup'))) {
9000
			$ret .= dol_htmlentities($object->getFullName($langs));
9001
		} elseif (in_array($object->element, array('action', 'agenda'))) {
9002
			$ret .= $object->ref.'<br>'.$object->label;
9003
		} elseif (in_array($object->element, array('adherent_type'))) {
9004
			$ret .= $object->label;
9005
		} elseif ($object->element == 'ecm_directories') {
9006
			$ret .= '';
9007
		} elseif ($fieldref != 'none') {
9008
			$ret .= dol_htmlentities($object->$fieldref);
9009
		}
9010
9011
		if ($morehtmlref) {
9012
			// don't add a additional space, when "$morehtmlref" starts with a HTML div tag
9013
			if (substr($morehtmlref, 0, 4) != '<div') {
9014
				$ret .= ' ';
9015
			}
9016
9017
			$ret .= $morehtmlref;
9018
		}
9019
9020
		$ret .= '</div>';
9021
9022
		$ret .= '</div><!-- End banner content -->';
9023
9024
		return $ret;
9025
	}
9026
9027
9028
	/**
9029
	 *  Return HTML code to output a barcode
9030
	 *
9031
	 *  @param	Object	$object			Object containing data to retrieve file name
9032
	 * 	@param	int		$width			Width of photo
9033
	 * 	@param	string	$morecss		More CSS on img of barcode
9034
	 * 	@return string    				HTML code to output barcode
9035
	 */
9036
	public function showbarcode(&$object, $width = 100, $morecss = '')
9037
	{
9038
		global $conf;
9039
9040
		//Check if barcode is filled in the card
9041
		if (empty($object->barcode)) {
9042
			return '';
9043
		}
9044
9045
		// Complete object if not complete
9046
		if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
9047
			$result = $object->fetch_barcode();
9048
			//Check if fetch_barcode() failed
9049
			if ($result < 1) {
9050
				return '<!-- ErrorFetchBarcode -->';
9051
			}
9052
		}
9053
9054
		// Barcode image
9055
		$url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
9056
		$out = '<!-- url barcode = '.$url.' -->';
9057
		$out .= '<img src="'.$url.'"'.($morecss ? ' class="'.$morecss.'"' : '').'>';
9058
		return $out;
9059
	}
9060
9061
	/**
9062
	 *    	Return HTML code to output a photo
9063
	 *
9064
	 *    	@param	string		$modulepart			Key to define module concerned ('societe', 'userphoto', 'memberphoto')
9065
	 *     	@param  object		$object				Object containing data to retrieve file name
9066
	 * 		@param	int			$width				Width of photo
9067
	 * 		@param	int			$height				Height of photo (auto if 0)
9068
	 * 		@param	int			$caneditfield		Add edit fields
9069
	 * 		@param	string		$cssclass			CSS name to use on img for photo
9070
	 * 		@param	string		$imagesize		    'mini', 'small' or '' (original)
9071
	 *      @param  int         $addlinktofullsize  Add link to fullsize image
9072
	 *      @param  int         $cache              1=Accept to use image in cache
9073
	 *      @param	string		$forcecapture		'', 'user' or 'environment'. Force parameter capture on HTML input file element to ask a smartphone to allow to open camera to take photo. Auto if ''.
9074
	 *      @param	int			$noexternsourceoverwrite	No overwrite image with extern source (like 'gravatar' or other module)
9075
	 * 	  	@return string    						HTML code to output photo
9076
	 */
9077
	public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
9078
	{
9079
		global $conf, $langs;
9080
9081
		$entity = (!empty($object->entity) ? $object->entity : $conf->entity);
9082
		$id = (!empty($object->id) ? $object->id : $object->rowid);
9083
9084
		$ret = '';
9085
		$dir = '';
9086
		$file = '';
9087
		$originalfile = '';
9088
		$altfile = '';
9089
		$email = '';
9090
		$capture = '';
9091
		if ($modulepart == 'societe') {
9092
			$dir = $conf->societe->multidir_output[$entity];
9093
			if (!empty($object->logo)) {
9094
				if (dolIsAllowedForPreview($object->logo)) {
9095
					if ((string) $imagesize == 'mini') {
9096
						$file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
9097
					} elseif ((string) $imagesize == 'small') {
9098
						$file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small');
9099
					} else {
9100
						$file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9101
					}
9102
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
9103
				}
9104
			}
9105
			$email = $object->email;
9106
		} elseif ($modulepart == 'contact')	{
9107
			$dir = $conf->societe->multidir_output[$entity].'/contact';
9108
			if (!empty($object->photo)) {
9109
				if (dolIsAllowedForPreview($object->photo)) {
9110
					if ((string) $imagesize == 'mini') {
9111
						$file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9112
					} elseif ((string) $imagesize == 'small') {
9113
						$file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small');
9114
					} else {
9115
						$file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9116
					}
9117
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
9118
				}
9119
			}
9120
			$email = $object->email;
9121
			$capture = 'user';
9122
		} elseif ($modulepart == 'userphoto') {
9123
			$dir = $conf->user->dir_output;
9124
			if (!empty($object->photo)) {
9125
				if (dolIsAllowedForPreview($object->photo)) {
9126
					if ((string) $imagesize == 'mini') {
9127
						$file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9128
					} elseif ((string) $imagesize == 'small') {
9129
						$file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.getImageFileNameForSize($object->photo, '_small');
9130
					} else {
9131
						$file = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9132
					}
9133
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'photos/'.$object->photo;
9134
				}
9135
			}
9136
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9137
				$altfile = $object->id.".jpg"; // For backward compatibility
9138
			}
9139
			$email = $object->email;
9140
			$capture = 'user';
9141
		} elseif ($modulepart == 'memberphoto')	{
9142
			$dir = $conf->adherent->dir_output;
9143
			if (!empty($object->photo)) {
9144
				if (dolIsAllowedForPreview($object->photo)) {
9145
					if ((string) $imagesize == 'mini') {
9146
						$file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
9147
					} elseif ((string) $imagesize == 'small') {
9148
						$file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
9149
					} else {
9150
						$file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9151
					}
9152
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
9153
				}
9154
			}
9155
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9156
				$altfile = $object->id.".jpg"; // For backward compatibility
9157
			}
9158
			$email = $object->email;
9159
			$capture = 'user';
9160
		} else {
9161
			// Generic case to show photos
9162
			$dir = $conf->$modulepart->dir_output;
9163
			if (!empty($object->photo)) {
9164
				if (dolIsAllowedForPreview($object->photo)) {
9165
					if ((string) $imagesize == 'mini') {
9166
						$file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
9167
					} elseif ((string) $imagesize == 'small') {
9168
						$file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
9169
					} else {
9170
						$file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9171
					}
9172
					$originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
9173
				}
9174
			}
9175
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
9176
				$altfile = $object->id.".jpg"; // For backward compatibility
9177
			}
9178
			$email = $object->email;
9179
		}
9180
9181
		if ($forcecapture) {
9182
			$capture = $forcecapture;
9183
		}
9184
9185
		if ($dir) {
9186
			if ($file && file_exists($dir."/".$file)) {
9187
				if ($addlinktofullsize) {
9188
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9189
					if ($urladvanced) {
9190
						$ret .= '<a href="'.$urladvanced.'">';
9191
					} else {
9192
						$ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9193
					}
9194
				}
9195
				$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.'">';
9196
				if ($addlinktofullsize) {
9197
					$ret .= '</a>';
9198
				}
9199
			} elseif ($altfile && file_exists($dir."/".$altfile)) {
9200
				if ($addlinktofullsize) {
9201
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
9202
					if ($urladvanced) {
9203
						$ret .= '<a href="'.$urladvanced.'">';
9204
					} else {
9205
						$ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
9206
					}
9207
				}
9208
				$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.'">';
9209
				if ($addlinktofullsize) {
9210
					$ret .= '</a>';
9211
				}
9212
			} else {
9213
				$nophoto = '/public/theme/common/nophoto.png';
9214
				$defaultimg = 'identicon';		// For gravatar
9215
				if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) {	// For modules that need a special image when photo not found
9216
					if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor')) !== false) {
9217
						$nophoto = 'company';
9218
					} else {
9219
						$nophoto = '/public/theme/common/user_anonymous.png';
9220
						if (!empty($object->gender) && $object->gender == 'man') {
9221
							$nophoto = '/public/theme/common/user_man.png';
9222
						}
9223
						if (!empty($object->gender) && $object->gender == 'woman') {
9224
							$nophoto = '/public/theme/common/user_woman.png';
9225
						}
9226
					}
9227
				}
9228
9229
				if (!empty($conf->gravatar->enabled) && $email && empty($noexternsourceoverwrite)) {
9230
					// see https://gravatar.com/site/implement/images/php/
9231
					$ret .= '<!-- Put link to gravatar -->';
9232
					$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" title="'.$email.' Gravatar avatar" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="https://www.gravatar.com/avatar/'.md5(strtolower(trim($email))).'?s='.$width.'&d='.$defaultimg.'">'; // gravatar need md5 hash
9233
				} else {
9234
					if ($nophoto == 'company') {
9235
						$ret .= '<div class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').'">'.img_picto('', 'company').'</div>';
9236
					} else {
9237
						$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
9238
					}
9239
				}
9240
			}
9241
9242
			if ($caneditfield) {
9243
				if ($object->photo) {
9244
					$ret .= "<br>\n";
9245
				}
9246
				$ret .= '<table class="nobordernopadding centpercent">';
9247
				if ($object->photo) {
9248
					$ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">'.$langs->trans("Delete").'</label><br><br></td></tr>';
9249
				}
9250
				$ret .= '<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'></td></tr>';
9251
				$ret .= '</table>';
9252
			}
9253
		} else {
9254
			dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
9255
		}
9256
9257
		return $ret;
9258
	}
9259
9260
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
9261
	/**
9262
	 *	Return select list of groups
9263
	 *
9264
	 *  @param	string	$selected       Id group preselected
9265
	 *  @param  string	$htmlname       Field name in form
9266
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
9267
	 *  @param  string	$exclude        Array list of groups id to exclude
9268
	 * 	@param	int		$disabled		If select list must be disabled
9269
	 *  @param  string	$include        Array list of groups id to include
9270
	 * 	@param	int		$enableonly		Array list of groups id to be enabled. All other must be disabled
9271
	 * 	@param	string	$force_entity	'0' or Ids of environment to force
9272
	 * 	@param	bool	$multiple		add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
9273
	 *  @param  string	$morecss		More css to add to html component
9274
	 *  @return	string
9275
	 *  @see select_dolusers()
9276
	 */
9277
	public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
9278
	{
9279
		// phpcs:enable
9280
		global $conf, $user, $langs;
9281
9282
		// Permettre l'exclusion de groupes
9283
		if (is_array($exclude)) {
0 ignored issues
show
introduced by
The condition is_array($exclude) is always false.
Loading history...
9284
			$excludeGroups = implode(",", $exclude);
9285
		}
9286
		// Permettre l'inclusion de groupes
9287
		if (is_array($include)) {
0 ignored issues
show
introduced by
The condition is_array($include) is always false.
Loading history...
9288
			$includeGroups = implode(",", $include);
9289
		}
9290
9291
		if (!is_array($selected)) {
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
9292
			$selected = array($selected);
9293
		}
9294
9295
		$out = '';
9296
9297
		// On recherche les groupes
9298
		$sql = "SELECT ug.rowid, ug.nom as name";
9299
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
9300
			$sql .= ", e.label";
9301
		}
9302
		$sql .= " FROM ".$this->db->prefix()."usergroup as ug ";
9303
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
9304
			$sql .= " LEFT JOIN ".$this->db->prefix()."entity as e ON e.rowid=ug.entity";
9305
			if ($force_entity) {
9306
				$sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
9307
			} else {
9308
				$sql .= " WHERE ug.entity IS NOT NULL";
9309
			}
9310
		} else {
9311
			$sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
9312
		}
9313
		if (is_array($exclude) && $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...
9314
			$sql .= " AND ug.rowid NOT IN (".$this->db->sanitize($excludeGroups).")";
9315
		}
9316
		if (is_array($include) && $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...
9317
			$sql .= " AND ug.rowid IN (".$this->db->sanitize($includeGroups).")";
9318
		}
9319
		$sql .= " ORDER BY ug.nom ASC";
9320
9321
		dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
9322
		$resql = $this->db->query($sql);
9323
		if ($resql) {
9324
			// Enhance with select2
9325
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9326
			$out .= ajax_combobox($htmlname);
9327
9328
			$out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
9329
9330
			$num = $this->db->num_rows($resql);
9331
			$i = 0;
9332
			if ($num) {
9333
				if ($show_empty && !$multiple) {
9334
					$out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
9335
				}
9336
9337
				while ($i < $num) {
9338
					$obj = $this->db->fetch_object($resql);
9339
					$disableline = 0;
9340
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
9341
						$disableline = 1;
9342
					}
9343
9344
					$out .= '<option value="'.$obj->rowid.'"';
9345
					if ($disableline) {
9346
						$out .= ' disabled';
9347
					}
9348
					if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid) || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
9349
						$out .= ' selected';
9350
					}
9351
					$out .= '>';
9352
9353
					$out .= $obj->name;
9354
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
9355
						$out .= " (".$obj->label.")";
9356
					}
9357
9358
					$out .= '</option>';
9359
					$i++;
9360
				}
9361
			} else {
9362
				if ($show_empty) {
9363
					$out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
9364
				}
9365
				$out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
9366
			}
9367
			$out .= '</select>';
9368
		} else {
9369
			dol_print_error($this->db);
9370
		}
9371
9372
		return $out;
9373
	}
9374
9375
9376
	/**
9377
	 *	Return HTML to show the search and clear seach button
9378
	 *
9379
	 *  @return	string
9380
	 */
9381
	public function showFilterButtons()
9382
	{
9383
		$out = '<div class="nowraponall">';
9384
		$out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9385
		$out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9386
		$out .= '</div>';
9387
9388
		return $out;
9389
	}
9390
9391
	/**
9392
	 *	Return HTML to show the search and clear search button
9393
	 *
9394
	 *  @param  string  $cssclass                  CSS class
9395
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
9396
	 *  @param  string  $massactionname            Mass action button name that will launch an action on the selected items
9397
	 *  @return	string
9398
	 */
9399
	public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9400
	{
9401
		global $conf, $langs;
9402
9403
		$out = '';
9404
9405
		if (!empty($conf->use_javascript_ajax)) {
9406
			$out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
9407
		}
9408
		$out .= '<script>
9409
            $(document).ready(function() {
9410
                $("#' . $cssclass.'s").click(function() {
9411
                    if($(this).is(\':checked\')){
9412
                        console.log("We check all '.$cssclass.' and trigger the change method");
9413
                		$(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
9414
                    }
9415
                    else
9416
                    {
9417
                        console.log("We uncheck all");
9418
                		$(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
9419
                    }'."\n";
9420
		if ($calljsfunction) {
9421
			$out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
9422
		}
9423
		$out .= '         });
9424
        	        $(".' . $cssclass.'").change(function() {
9425
					$(this).closest("tr").toggleClass("highlight", this.checked);
9426
				});
9427
		 	});
9428
    	</script>';
9429
9430
		return $out;
9431
	}
9432
9433
	/**
9434
	 *	Return HTML to show the search and clear seach button
9435
	 *
9436
	 *  @param	int  	$addcheckuncheckall        Add the check all/uncheck all checkbox (use javascript) and code to manage this
9437
	 *  @param  string  $cssclass                  CSS class
9438
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
9439
	 *  @param  string  $massactionname            Mass action name
9440
	 *  @return	string
9441
	 */
9442
	public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
9443
	{
9444
		$out = $this->showFilterButtons();
9445
		if ($addcheckuncheckall) {
9446
			$out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
9447
		}
9448
		return $out;
9449
	}
9450
9451
	/**
9452
	 * Return HTML to show the select of expense categories
9453
	 *
9454
	 * @param	string	$selected              preselected category
9455
	 * @param	string	$htmlname              name of HTML select list
9456
	 * @param	integer	$useempty              1=Add empty line
9457
	 * @param	array	$excludeid             id to exclude
9458
	 * @param	string	$target                htmlname of target select to bind event
9459
	 * @param	int		$default_selected      default category to select if fk_c_type_fees change = EX_KME
9460
	 * @param	array	$params                param to give
9461
	 * @param	int		$info_admin			   Show the tooltip help picto to setup list
9462
	 * @return	string
9463
	 */
9464
	public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
9465
	{
9466
		global $langs, $user;
9467
9468
		$out = '';
9469
		$sql = "SELECT rowid, label FROM ".$this->db->prefix()."c_exp_tax_cat WHERE active = 1";
9470
		$sql .= " AND entity IN (0,".getEntity('exp_tax_cat').")";
9471
		if (!empty($excludeid)) {
9472
			$sql .= " AND rowid NOT IN (".$this->db->sanitize(implode(',', $excludeid)).")";
9473
		}
9474
		$sql .= " ORDER BY label";
9475
9476
		$resql = $this->db->query($sql);
9477
		if ($resql) {
9478
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
9479
			if ($useempty) {
9480
				$out .= '<option value="0">&nbsp;</option>';
9481
			}
9482
9483
			while ($obj = $this->db->fetch_object($resql)) {
9484
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
9485
			}
9486
			$out .= '</select>';
9487
			$out .= ajax_combobox('select_'.$htmlname);
9488
9489
			if (!empty($htmlname) && $user->admin && $info_admin) {
9490
				$out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
9491
			}
9492
9493
			if (!empty($target)) {
9494
				$sql = "SELECT c.id FROM ".$this->db->prefix()."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
9495
				$resql = $this->db->query($sql);
9496
				if ($resql) {
9497
					if ($this->db->num_rows($resql) > 0) {
9498
						$obj = $this->db->fetch_object($resql);
9499
						$out .= '<script>
9500
							$(function() {
9501
								$("select[name='.$target.']").on("change", function() {
9502
									var current_val = $(this).val();
9503
									if (current_val == '.$obj->id.') {';
9504
						if (!empty($default_selected) || !empty($selected)) {
9505
							$out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
9506
						}
9507
9508
						$out .= '
9509
										$("select[name='.$htmlname.']").change();
9510
									}
9511
								});
9512
9513
								$("select[name='.$htmlname.']").change(function() {
9514
9515
									if ($("select[name='.$target.']").val() == '.$obj->id.') {
9516
										// get price of kilometer to fill the unit price
9517
										$.ajax({
9518
											method: "POST",
9519
											dataType: "json",
9520
											data: { fk_c_exp_tax_cat: $(this).val(), token: \''.currentToken().'\' },
9521
											url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php?'.$params).'",
9522
										}).done(function( data, textStatus, jqXHR ) {
9523
											console.log(data);
9524
											if (typeof data.up != "undefined") {
9525
												$("input[name=value_unit]").val(data.up);
9526
												$("select[name='.$htmlname.']").attr("title", data.title);
9527
											} else {
9528
												$("input[name=value_unit]").val("");
9529
												$("select[name='.$htmlname.']").attr("title", "");
9530
											}
9531
										});
9532
									}
9533
								});
9534
							});
9535
						</script>';
9536
					}
9537
				}
9538
			}
9539
		} else {
9540
			dol_print_error($this->db);
9541
		}
9542
9543
		return $out;
9544
	}
9545
9546
	/**
9547
	 * Return HTML to show the select ranges of expense range
9548
	 *
9549
	 * @param	string	$selected    preselected category
9550
	 * @param	string	$htmlname    name of HTML select list
9551
	 * @param	integer	$useempty    1=Add empty line
9552
	 * @return	string
9553
	 */
9554
	public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
9555
	{
9556
		global $conf, $langs;
9557
9558
		$out = '';
9559
		$sql = "SELECT rowid, range_ik FROM ".$this->db->prefix()."c_exp_tax_range";
9560
		$sql .= " WHERE entity = ".$conf->entity." AND active = 1";
9561
9562
		$resql = $this->db->query($sql);
9563
		if ($resql) {
9564
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9565
			if ($useempty) {
9566
				$out .= '<option value="0"></option>';
9567
			}
9568
9569
			while ($obj = $this->db->fetch_object($resql)) {
9570
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
9571
			}
9572
			$out .= '</select>';
9573
		} else {
9574
			dol_print_error($this->db);
9575
		}
9576
9577
		return $out;
9578
	}
9579
9580
	/**
9581
	 * Return HTML to show a select of expense
9582
	 *
9583
	 * @param	string	$selected    preselected category
9584
	 * @param	string	$htmlname    name of HTML select list
9585
	 * @param	integer	$useempty    1=Add empty choice
9586
	 * @param	integer	$allchoice   1=Add all choice
9587
	 * @param	integer	$useid       0=use 'code' as key, 1=use 'id' as key
9588
	 * @return	string
9589
	 */
9590
	public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
9591
	{
9592
		global $langs;
9593
9594
		$out = '';
9595
		$sql = "SELECT id, code, label FROM ".$this->db->prefix()."c_type_fees";
9596
		$sql .= " WHERE active = 1";
9597
9598
		$resql = $this->db->query($sql);
9599
		if ($resql) {
9600
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
9601
			if ($useempty) {
9602
				$out .= '<option value="0"></option>';
9603
			}
9604
			if ($allchoice) {
9605
				$out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
9606
			}
9607
9608
			$field = 'code';
9609
			if ($useid) {
9610
				$field = 'id';
9611
			}
9612
9613
			while ($obj = $this->db->fetch_object($resql)) {
9614
				$key = $langs->trans($obj->code);
9615
				$out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
9616
			}
9617
			$out .= '</select>';
9618
		} else {
9619
			dol_print_error($this->db);
9620
		}
9621
9622
		return $out;
9623
	}
9624
9625
	/**
9626
	 *  Output a combo list with invoices qualified for a third party
9627
	 *
9628
	 *  @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)
9629
	 *  @param  int		$selected   	Id invoice preselected
9630
	 *  @param  string	$htmlname   	Name of HTML select
9631
	 *	@param	int		$maxlength		Maximum length of label
9632
	 *	@param	int		$option_only	Return only html options lines without the select tag
9633
	 *	@param	string	$show_empty		Add an empty line ('1' or string to show for empty line)
9634
	 *  @param	int		$discard_closed Discard closed projects (0=Keep,1=hide completely,2=Disable)
9635
	 *  @param	int		$forcefocus		Force focus on field (works with javascript only)
9636
	 *  @param	int		$disabled		Disabled
9637
	 *  @param	string	$morecss        More css added to the select component
9638
	 *  @param	string	$projectsListId ''=Automatic filter on project allowed. List of id=Filter on project ids.
9639
	 *  @param	string	$showproject	'all' = Show project info, ''=Hide project info
9640
	 *  @param	User	$usertofilter	User object to use for filtering
9641
	 *	@return int         			Nbr of project if OK, <0 if KO
9642
	 */
9643
	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)
9644
	{
9645
		global $user, $conf, $langs;
9646
9647
		require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
9648
9649
		if (is_null($usertofilter)) {
9650
			$usertofilter = $user;
9651
		}
9652
9653
		$out = '';
9654
9655
		$hideunselectables = false;
9656
		if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
9657
			$hideunselectables = true;
9658
		}
9659
9660
		if (empty($projectsListId)) {
9661
			if (empty($usertofilter->rights->projet->all->lire)) {
9662
				$projectstatic = new Project($this->db);
9663
				$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
9664
			}
9665
		}
9666
9667
		// Search all projects
9668
		$sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
9669
            p.title, p.fk_soc, p.fk_statut, p.public,";
9670
		$sql .= ' s.nom as name';
9671
		$sql .= ' FROM '.$this->db->prefix().'projet as p';
9672
		$sql .= ' LEFT JOIN '.$this->db->prefix().'societe as s ON s.rowid = p.fk_soc,';
9673
		$sql .= ' '.$this->db->prefix().'facture as f';
9674
		$sql .= " WHERE p.entity IN (".getEntity('project').")";
9675
		$sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
9676
		//if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
9677
		//if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
9678
		//if ($socid > 0)  $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
9679
		$sql .= " ORDER BY p.ref, f.ref ASC";
9680
9681
		$resql = $this->db->query($sql);
9682
		if ($resql) {
9683
			// Use select2 selector
9684
			if (!empty($conf->use_javascript_ajax)) {
9685
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9686
				$comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
9687
				$out .= $comboenhancement;
9688
				$morecss = 'minwidth200imp maxwidth500';
9689
			}
9690
9691
			if (empty($option_only)) {
9692
				$out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
9693
			}
9694
			if (!empty($show_empty)) {
9695
				$out .= '<option value="0" class="optiongrey">';
9696
				if (!is_numeric($show_empty)) {
9697
					$out .= $show_empty;
9698
				} else {
9699
					$out .= '&nbsp;';
9700
				}
9701
				$out .= '</option>';
9702
			}
9703
			$num = $this->db->num_rows($resql);
9704
			$i = 0;
9705
			if ($num) {
9706
				while ($i < $num) {
9707
					$obj = $this->db->fetch_object($resql);
9708
					// 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.
9709
					if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
9710
						// Do nothing
9711
					} else {
9712
						if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
9713
							$i++;
9714
							continue;
9715
						}
9716
9717
						$labeltoshow = '';
9718
9719
						if ($showproject == 'all') {
9720
							$labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
9721
							if ($obj->name) {
9722
								$labeltoshow .= ' - '.$obj->name; // Soc name
9723
							}
9724
9725
							$disabled = 0;
9726
							if ($obj->fk_statut == Project::STATUS_DRAFT) {
9727
								$disabled = 1;
9728
								$labeltoshow .= ' - '.$langs->trans("Draft");
9729
							} elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
9730
								if ($discard_closed == 2) {
9731
									$disabled = 1;
9732
								}
9733
								$labeltoshow .= ' - '.$langs->trans("Closed");
9734
							} elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
9735
								$disabled = 1;
9736
								$labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
9737
							}
9738
						}
9739
9740
						if (!empty($selected) && $selected == $obj->rowid) {
9741
							$out .= '<option value="'.$obj->rowid.'" selected';
9742
							//if ($disabled) $out.=' disabled';						// with select2, field can't be preselected if disabled
9743
							$out .= '>'.$labeltoshow.'</option>';
9744
						} else {
9745
							if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
9746
								$resultat = '';
9747
							} else {
9748
								$resultat = '<option value="'.$obj->rowid.'"';
9749
								if ($disabled) {
9750
									$resultat .= ' disabled';
9751
								}
9752
								//if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
9753
								//else $labeltoshow.=' ('.$langs->trans("Private").')';
9754
								$resultat .= '>';
9755
								$resultat .= $labeltoshow;
9756
								$resultat .= '</option>';
9757
							}
9758
							$out .= $resultat;
9759
						}
9760
					}
9761
					$i++;
9762
				}
9763
			}
9764
			if (empty($option_only)) {
9765
				$out .= '</select>';
9766
			}
9767
9768
			print $out;
9769
9770
			$this->db->free($resql);
9771
			return $num;
9772
		} else {
9773
			dol_print_error($this->db);
9774
			return -1;
9775
		}
9776
	}
9777
9778
	/**
9779
	 *  Output a combo list with invoices qualified for a third party
9780
	 *
9781
	 * @param int $selected Id invoice preselected
9782
	 * @param string $htmlname Name of HTML select
9783
	 * @param int $maxlength Maximum length of label
9784
	 * @param int $option_only Return only html options lines without the select tag
9785
	 * @param string $show_empty Add an empty line ('1' or string to show for empty line)
9786
	 * @param int $forcefocus Force focus on field (works with javascript only)
9787
	 * @param int $disabled Disabled
9788
	 * @param string $morecss More css added to the select component
9789
	 * @return int                    Nbr of project if OK, <0 if KO
9790
	 */
9791
	public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
9792
	{
9793
		global $user, $conf, $langs;
9794
9795
		$out = '';
9796
9797
		dol_syslog('FactureRec::fetch', LOG_DEBUG);
9798
9799
		$sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
9800
		//$sql.= ', el.fk_source';
9801
		$sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
9802
		$sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
9803
		$sql .= " ORDER BY f.titre ASC";
9804
9805
		$resql = $this->db->query($sql);
9806
		if ($resql) {
9807
			// Use select2 selector
9808
			if (!empty($conf->use_javascript_ajax)) {
9809
				include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9810
				$comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
9811
				$out .= $comboenhancement;
9812
				$morecss = 'minwidth200imp maxwidth500';
9813
			}
9814
9815
			if (empty($option_only)) {
9816
				$out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
9817
			}
9818
			if (!empty($show_empty)) {
9819
				$out .= '<option value="0" class="optiongrey">';
9820
				if (!is_numeric($show_empty)) {
9821
					$out .= $show_empty;
9822
				} else {
9823
					$out .= '&nbsp;';
9824
				}
9825
				$out .= '</option>';
9826
			}
9827
			$num = $this->db->num_rows($resql);
9828
			if ($num) {
9829
				while ($obj = $this->db->fetch_object($resql)) {
9830
					$labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
9831
9832
					$disabled = 0;
9833
					if (!empty($obj->suspended)) {
9834
						$disabled = 1;
9835
						$labeltoshow .= ' - ' . $langs->trans("Closed");
9836
					}
9837
9838
9839
					if (!empty($selected) && $selected == $obj->rowid) {
9840
						$out .= '<option value="' . $obj->rowid . '" selected';
9841
						//if ($disabled) $out.=' disabled';						// with select2, field can't be preselected if disabled
9842
						$out .= '>' . $labeltoshow . '</option>';
9843
					} else {
9844
						if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $hideunselectables seems to be never defined.
Loading history...
9845
							$resultat = '';
9846
						} else {
9847
							$resultat = '<option value="' . $obj->rowid . '"';
9848
							if ($disabled) {
9849
								$resultat .= ' disabled';
9850
							}
9851
							$resultat .= '>';
9852
							$resultat .= $labeltoshow;
9853
							$resultat .= '</option>';
9854
						}
9855
						$out .= $resultat;
9856
					}
9857
				}
9858
			}
9859
			if (empty($option_only)) {
9860
				$out .= '</select>';
9861
			}
9862
9863
			print $out;
9864
9865
			$this->db->free($resql);
9866
			return $num;
9867
		} else {
9868
			$this->errors[]=$this->db->lasterror;
9869
			return -1;
9870
		}
9871
	}
9872
9873
	/**
9874
	 * Output the component to make advanced search criteries
9875
	 *
9876
	 * @param	array		$arrayofcriterias			          Array of available search criterias. Example: array($object->element => $object->fields, 'otherfamily' => otherarrayoffields, ...)
9877
	 * @param	array		$search_component_params	          Array of selected search criterias
9878
	 * @param   array       $arrayofinputfieldsalreadyoutput      Array of input fields already inform. The component will not generate a hidden input field if it is in this list.
9879
	 * @param	string		$search_component_params_hidden		  String with $search_component_params criterias
9880
	 * @return	string									          HTML component for advanced search
9881
	 */
9882
	public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '')
9883
	{
9884
		global $langs;
9885
9886
		$ret = '';
9887
9888
		$ret .= '<div class="divadvancedsearchfieldcomp inline-block">';
9889
		//$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9890
		$ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
9891
		$ret .= '<span class="fas fa-filter linkobject boxfilter pictofixedwidth" title="'.dol_escape_htmltag($langs->trans("Filters")).'" id="idsubimgproductdistribution"></span>';
9892
		//$ret .= $langs->trans("Filters");
9893
		$ret .= '</a>';
9894
9895
		$ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
9896
9897
		// Show select fields as tags.
9898
		$ret .= '<div name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
9899
9900
		if ($search_component_params_hidden) {
9901
			if (!preg_match('/^\(.*\)$/', $search_component_params_hidden)) {	// If $search_component_params_hidden does not start and end with ()
9902
				$search_component_params_hidden .= '('.$search_component_params_hidden.')';
9903
			}
9904
			$errormessage = '';
9905
			if (!dolCheckFilters($search_component_params_hidden, $errormessage)) {
9906
				print 'ERROR in parsing search string';
9907
			}
9908
			$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
9909
			//var_dump($search_component_params_hidden);
9910
			$htmltags = preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $search_component_params_hidden);
9911
			//var_dump($htmltags);
9912
			$ret .= '<span class="marginleftonlyshort valignmiddle tagsearch"><span class="tagsearchdelete select2-selection__choice__remove">x</span> '.$htmltags.'</span>';
9913
		}
9914
9915
		//$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9916
9917
		//$ret .= search_component_params
9918
		//$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
9919
		//$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
9920
9921
		$show_search_component_params_hidden = 1;
9922
		if ($show_search_component_params_hidden) {
9923
			$ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
9924
		}
9925
		$ret .= "<!-- We store the full search string into this field. For example: (t.ref:like:'SO-%') and ((t.ref:like:'CO-%') or (t.ref:like:'AA%')) -->";
9926
		$ret .= '<input type="hidden" name="search_component_params_hidden" value="'.dol_escape_htmltag($search_component_params_hidden).'">';
9927
		// For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
9928
		foreach ($arrayofcriterias as $criterias) {
9929
			foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
9930
				if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
9931
					continue;
9932
				}
9933
				if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
9934
					continue;
9935
				}
9936
				if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
9937
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
9938
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
9939
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
9940
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
9941
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
9942
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
9943
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
9944
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
9945
				} else {
9946
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
9947
				}
9948
			}
9949
		}
9950
9951
		$ret .= '</div>';
9952
9953
		$ret .= "<!-- Syntax of Generic filter string: t.ref:like:'SO-%', t.date_creation:<:'20160101', t.date_creation:<:'2016-01-01 12:30:00', t.nature:is:NULL, t.field2:isnot:NULL -->\n";
9954
		$ret .= '<input type="text" placeholder="'.$langs->trans("Search").'" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
9955
9956
		$ret .= '</div>';
9957
		$ret .= '</div>';
9958
9959
		return $ret;
9960
	}
9961
9962
	/**
9963
	 * selectModelMail
9964
	 *
9965
	 * @param   string   $prefix     	Prefix
9966
	 * @param   string   $modelType  	Model type
9967
	 * @param	int		 $default	 	1=Show also Default mail template
9968
	 * @param	int		 $addjscombo	Add js combobox
9969
	 * @return  string               	HTML select string
9970
	 */
9971
	public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
9972
	{
9973
		global $langs, $user;
9974
9975
		$retstring = '';
9976
9977
		$TModels = array();
9978
9979
		include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
9980
		$formmail = new FormMail($this->db);
9981
		$result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
9982
9983
		if ($default) {
9984
			$TModels[0] = $langs->trans('DefaultMailModel');
9985
		}
9986
		if ($result > 0) {
9987
			foreach ($formmail->lines_model as $model) {
9988
				$TModels[$model->id] = $model->label;
9989
			}
9990
		}
9991
9992
		$retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
9993
9994
		foreach ($TModels as $id_model => $label_model) {
9995
			$retstring .= '<option value="'.$id_model.'"';
9996
			$retstring .= ">".$label_model."</option>";
9997
		}
9998
9999
		$retstring .= "</select>";
10000
10001
		if ($addjscombo) {
10002
			$retstring .= ajax_combobox('select_'.$prefix.'model_mail');
10003
		}
10004
10005
		return $retstring;
10006
	}
10007
10008
	/**
10009
	 * Output the buttons to submit a creation/edit form
10010
	 *
10011
	 * @param   string  $save_label     Alternative label for save button
10012
	 * @param   string  $cancel_label   Alternative label for cancel button
10013
	 * @param   array   $morebuttons    Add additional buttons between save and cancel
10014
	 * @param   bool    $withoutdiv     Option to remove enclosing centered div
10015
	 * @param	string	$morecss		More CSS
10016
	 * @return 	string					Html code with the buttons
10017
	 */
10018
	public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = 0, $morecss = '')
10019
	{
10020
		global $langs;
10021
10022
		$buttons = array();
10023
10024
		$save = array(
10025
			'name' => 'save',
10026
			'label_key' => $save_label,
10027
		);
10028
10029
		if ($save_label == 'Create' || $save_label == 'Add' ) {
10030
			$save['name'] = 'add';
10031
		} elseif ($save_label == 'Modify') {
10032
			$save['name'] = 'edit';
10033
		}
10034
10035
		$cancel = array(
10036
				'name' => 'cancel',
10037
				'label_key' => 'Cancel',
10038
		);
10039
10040
		!empty($save_label) ? $buttons[] = $save : '';
10041
10042
		if (!empty($morebuttons)) {
10043
			$buttons[] = $morebuttons;
10044
		}
10045
10046
		!empty($cancel_label) ? $buttons[] = $cancel : '';
10047
10048
		$retstring = $withoutdiv ? '': '<div class="center">';
10049
10050
		foreach ($buttons as $button) {
10051
			$addclass = empty($button['addclass']) ? '' : $button['addclass'];
10052
			$retstring .= '<input type="submit" class="button button-'.$button['name'].($morecss ? ' '.$morecss : '').' '.$addclass.'" name="'.$button['name'].'" value="'.dol_escape_htmltag($langs->trans($button['label_key'])).'">';
10053
		}
10054
		$retstring .= $withoutdiv ? '': '</div>';
10055
10056
		return $retstring;
10057
	}
10058
}
10059