Passed
Branch develop (5ec324)
by
unknown
37:40
created

Form::select_company()   F

Complexity

Conditions 15
Paths 513

Size

Total Lines 46
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 28
nc 513
nop 15
dl 0
loc 46
rs 2.4263
c 1
b 0
f 0

How to fix   Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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

915
					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

915
					array_multisort($favorite, SORT_DESC, $label, /** @scrutinizer ignore-type */ SORT_ASC, $countryArray);
Loading history...
916
				} else {
917
					$countryArray = dol_sort_array($countryArray, 'label');
918
				}
919
920
				if ($showempty) {
921
					$out .= '<option value="">&nbsp;</option>'."\n";
922
				}
923
924
				if ($addspecialentries) {	// Add dedicated entries for groups of countries
925
					//if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
926
					$out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
927
					$out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
928
					if ($mysoc->isInEEC()) {
929
						$out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
930
					}
931
					$out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
932
					$out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
933
				}
934
935
				foreach ($countryArray as $row) {
936
					//if (empty($showempty) && empty($row['rowid'])) continue;
937
					if (empty($row['rowid'])) {
938
						continue;
939
					}
940
					if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
941
						continue; // exclude some countries
942
					}
943
944
					if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
945
						$atleastonefavorite++;
946
					}
947
					if (empty($row['favorite']) && $atleastonefavorite) {
948
						$atleastonefavorite = 0;
949
						$out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
950
					}
951
952
					$labeltoshow = '';
953
					if ($row['label']) {
954
						$labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
955
					} else {
956
						$labeltoshow .= '&nbsp;';
957
					}
958
					if ($row['code_iso']) {
959
						$labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>';
960
						if (empty($hideflags)) {
961
							$tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"');
962
							$labeltoshow = $tmpflag.' '.$labeltoshow;
963
						}
964
					}
965
966
					if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
967
						$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']).'">';
968
					} else {
969
						$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']).'">';
970
					}
971
					$out .= $labeltoshow;
972
					$out .= '</option>';
973
				}
974
			}
975
			$out .= '</select>';
976
		} else {
977
			dol_print_error($this->db);
978
		}
979
980
		// Make select dynamic
981
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
982
		$out .= ajax_combobox('select'.$htmlname, array(), 0, 0, 'resolve');
983
984
		return $out;
985
	}
986
987
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
988
	/**
989
	 *  Return select list of incoterms
990
	 *
991
	 *  @param	string	$selected       		Id or Code of preselected incoterm
992
	 *  @param	string	$location_incoterms     Value of input location
993
	 *  @param	string	$page       			Defined the form action
994
	 *  @param  string	$htmlname       		Name of html select object
995
	 *  @param  string	$htmloption     		Options html on select object
996
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
997
	 *  @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')))
998
	 *  @return string           				HTML string with select and input
999
	 */
1000
	public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array())
1001
	{
1002
		// phpcs:enable
1003
		global $conf, $langs;
1004
1005
		$langs->load("dict");
1006
1007
		$out = '';
1008
		$incotermArray = array();
1009
1010
		$sql = "SELECT rowid, code";
1011
		$sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms";
1012
		$sql .= " WHERE active > 0";
1013
		$sql .= " ORDER BY code ASC";
1014
1015
		dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
1016
		$resql = $this->db->query($sql);
1017
		if ($resql) {
1018
			if ($conf->use_javascript_ajax && !$forcecombo) {
1019
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1020
				$out .= ajax_combobox($htmlname, $events);
1021
			}
1022
1023
			if (!empty($page)) {
1024
				$out .= '<form method="post" action="'.$page.'">';
1025
				$out .= '<input type="hidden" name="action" value="set_incoterms">';
1026
				$out .= '<input type="hidden" name="token" value="'.newToken().'">';
1027
			}
1028
1029
			$out .= '<select id="'.$htmlname.'" class="flat selectincoterm width75" name="'.$htmlname.'" '.$htmloption.'>';
1030
			$out .= '<option value="0">&nbsp;</option>';
1031
			$num = $this->db->num_rows($resql);
1032
			$i = 0;
1033
			if ($num) {
1034
				$foundselected = false;
1035
1036
				while ($i < $num) {
1037
					$obj = $this->db->fetch_object($resql);
1038
					$incotermArray[$i]['rowid'] = $obj->rowid;
1039
					$incotermArray[$i]['code'] = $obj->code;
1040
					$i++;
1041
				}
1042
1043
				foreach ($incotermArray as $row) {
1044
					if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1045
						$out .= '<option value="'.$row['rowid'].'" selected>';
1046
					} else {
1047
						$out .= '<option value="'.$row['rowid'].'">';
1048
					}
1049
1050
					if ($row['code']) {
1051
						$out .= $row['code'];
1052
					}
1053
1054
					$out .= '</option>';
1055
				}
1056
			}
1057
			$out .= '</select>';
1058
1059
			$out .= '<input id="location_incoterms" class="maxwidth100onsmartphone nomargintop nomarginbottom" name="location_incoterms" value="'.$location_incoterms.'">';
1060
1061
			if (!empty($page)) {
1062
				$out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="'.$langs->trans("Modify").'"></form>';
1063
			}
1064
		} else {
1065
			dol_print_error($this->db);
1066
		}
1067
1068
		return $out;
1069
	}
1070
1071
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1072
	/**
1073
	 *	Return list of types of lines (product or service)
1074
	 * 	Example: 0=product, 1=service, 9=other (for external module)
1075
	 *
1076
	 *	@param  string	$selected       Preselected type
1077
	 *	@param  string	$htmlname       Name of field in html form
1078
	 * 	@param	int		$showempty		Add an empty field
1079
	 * 	@param	int		$hidetext		Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
1080
	 * 	@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')
1081
	 *  @return	void
1082
	 */
1083
	public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
1084
	{
1085
		// phpcs:enable
1086
		global $db, $langs, $user, $conf;
1087
1088
		// If product & services are enabled or both disabled.
1089
		if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
1090
			|| (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled))) {
1091
			if (empty($hidetext)) {
1092
				print $langs->trans("Type").': ';
1093
			}
1094
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
1095
			if ($showempty) {
1096
				print '<option value="-1"';
1097
				if ($selected == -1) {
1098
					print ' selected';
1099
				}
1100
				print '>&nbsp;</option>';
1101
			}
1102
1103
			print '<option value="0"';
1104
			if (0 == $selected) {
1105
				print ' selected';
1106
			}
1107
			print '>'.$langs->trans("Product");
1108
1109
			print '<option value="1"';
1110
			if (1 == $selected) {
1111
				print ' selected';
1112
			}
1113
			print '>'.$langs->trans("Service");
1114
1115
			print '</select>';
1116
			print ajax_combobox('select_'.$htmlname);
1117
			//if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1118
		}
1119
		if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3) {
1120
			print $langs->trans("Service");
1121
			print '<input type="hidden" name="'.$htmlname.'" value="1">';
1122
		}
1123
		if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2) {
1124
			print $langs->trans("Product");
1125
			print '<input type="hidden" name="'.$htmlname.'" value="0">';
1126
		}
1127
		if ($forceall < 0) {	// This should happened only for contracts when both predefined product and service are disabled.
1128
			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
1129
		}
1130
	}
1131
1132
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1133
	/**
1134
	 *	Load into cache cache_types_fees, array of types of fees
1135
	 *
1136
	 *	@return     int             Nb of lines loaded, <0 if KO
1137
	 */
1138
	public function load_cache_types_fees()
1139
	{
1140
		// phpcs:enable
1141
		global $langs;
1142
1143
		$num = count($this->cache_types_fees);
1144
		if ($num > 0) {
1145
			return 0; // Cache already loaded
1146
		}
1147
1148
		dol_syslog(__METHOD__, LOG_DEBUG);
1149
1150
		$langs->load("trips");
1151
1152
		$sql = "SELECT c.code, c.label";
1153
		$sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
1154
		$sql .= " WHERE active > 0";
1155
1156
		$resql = $this->db->query($sql);
1157
		if ($resql) {
1158
			$num = $this->db->num_rows($resql);
1159
			$i = 0;
1160
1161
			while ($i < $num) {
1162
				$obj = $this->db->fetch_object($resql);
1163
1164
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1165
				$label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1166
				$this->cache_types_fees[$obj->code] = $label;
1167
				$i++;
1168
			}
1169
1170
			asort($this->cache_types_fees);
1171
1172
			return $num;
1173
		} else {
1174
			dol_print_error($this->db);
1175
			return -1;
1176
		}
1177
	}
1178
1179
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1180
	/**
1181
	 *	Return list of types of notes
1182
	 *
1183
	 *	@param	string		$selected		Preselected type
1184
	 *	@param  string		$htmlname		Name of field in form
1185
	 * 	@param	int			$showempty		Add an empty field
1186
	 * 	@return	void
1187
	 */
1188
	public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1189
	{
1190
		// phpcs:enable
1191
		global $user, $langs;
1192
1193
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1194
1195
		$this->load_cache_types_fees();
1196
1197
		print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1198
		if ($showempty) {
1199
			print '<option value="-1"';
1200
			if ($selected == -1) {
1201
				print ' selected';
1202
			}
1203
			print '>&nbsp;</option>';
1204
		}
1205
1206
		foreach ($this->cache_types_fees as $key => $value) {
1207
			print '<option value="'.$key.'"';
1208
			if ($key == $selected) {
1209
				print ' selected';
1210
			}
1211
			print '>';
1212
			print $value;
1213
			print '</option>';
1214
		}
1215
1216
		print '</select>';
1217
		if ($user->admin) {
1218
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1219
		}
1220
	}
1221
1222
1223
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1224
	/**
1225
	 *  Output html form to select a third party
1226
	 *
1227
	 *	@param	string	$selected       		Preselected type
1228
	 *	@param  string	$htmlname       		Name of field in form
1229
	 *  @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)')
1230
	 *	@param	string	$showempty				Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty')
1231
	 * 	@param	int		$showtype				Show third party type in combolist (customer, prospect or supplier)
1232
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1233
	 *  @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')))
1234
	 *	@param	int		$limit					Maximum number of elements
1235
	 *  @param	string	$morecss				Add more css styles to the SELECT component
1236
	 *	@param  string	$moreparam      		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1237
	 *	@param	string	$selected_input_value	Value of preselected input text (for use with ajax)
1238
	 *  @param	int		$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1239
	 *  @param	array	$ajaxoptions			Options for ajax_autocompleter
1240
	 * 	@param  bool	$multiple				add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
1241
	 *  @param	array	$excludeids				Exclude IDs from the select combo
1242
	 * 	@return	string							HTML string with select box for thirdparty.
1243
	 */
1244
	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())
1245
	{
1246
		// phpcs:enable
1247
		global $conf, $user, $langs;
1248
1249
		$out = '';
1250
1251
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) {
1252
			if (is_null($ajaxoptions)) {
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
1253
				$ajaxoptions = array();
1254
			}
1255
1256
			require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1257
1258
			// No immediate load of all database
1259
			$placeholder = '';
1260
			if ($selected && empty($selected_input_value)) {
1261
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1262
				$societetmp = new Societe($this->db);
1263
				$societetmp->fetch($selected);
1264
				$selected_input_value = $societetmp->name;
1265
				unset($societetmp);
1266
			}
1267
			// mode 1
1268
			$urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).(empty($excludeids) ? '' : '&excludeids='.join(',', $excludeids)).($showtype ? '&showtype='.urlencode($showtype) : '');
1269
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1270
1271
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
1272
			if (empty($hidelabel)) {
1273
				print $langs->trans("RefOrLabel").' : ';
1274
			} elseif ($hidelabel > 1) {
1275
				$placeholder = $langs->trans("RefOrLabel");
1276
				if ($hidelabel == 2) {
1277
					$out .= img_picto($langs->trans("Search"), 'search');
1278
				}
1279
			}
1280
			$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' : '').' />';
1281
			if ($hidelabel == 3) {
1282
				$out .= img_picto($langs->trans("Search"), 'search');
1283
			}
1284
		} else {
1285
			// Immediate load of all database
1286
			$out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids);
1287
		}
1288
1289
		return $out;
1290
	}
1291
1292
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1293
	/**
1294
	 *  Output html form to select a third party.
1295
	 *  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.
1296
	 *
1297
	 *	@param	string	$selected       Preselected type
1298
	 *	@param  string	$htmlname       Name of field in form
1299
	 *  @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.
1300
	 *	@param	string	$showempty		Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty')
1301
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
1302
	 * 	@param	int		$forcecombo		Force to use standard HTML select component without beautification
1303
	 *  @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')))
1304
	 *  @param	string	$filterkey		Filter on key value
1305
	 *  @param	int		$outputmode		0=HTML select string, 1=Array
1306
	 *  @param	int		$limit			Limit number of answers
1307
	 *  @param	string	$morecss		Add more css styles to the SELECT component
1308
	 *	@param  string	$moreparam      Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1309
	 *	@param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1310
	 *  @param	array	$excludeids		Exclude IDs from the select combo
1311
	 * 	@return	string					HTML string with
1312
	 */
1313
	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())
1314
	{
1315
		// phpcs:enable
1316
		global $conf, $user, $langs;
1317
1318
		$out = '';
1319
		$num = 0;
1320
		$outarray = array();
1321
1322
		if ($selected === '') {
1323
			$selected = array();
1324
		} elseif (!is_array($selected)) {
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
1325
			$selected = array($selected);
1326
		}
1327
1328
		// Clean $filter that may contains sql conditions so sql code
1329
		if (function_exists('testSqlAndScriptInject')) {
1330
			if (testSqlAndScriptInject($filter, 3) > 0) {
1331
				$filter = '';
1332
			}
1333
		}
1334
1335
		// We search companies
1336
		$sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1337
		if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1338
			$sql .= ", s.address, s.zip, s.town";
1339
			$sql .= ", dictp.code as country_code";
1340
		}
1341
		$sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
1342
		if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1343
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid = s.fk_pays";
1344
		}
1345
		if (!$user->rights->societe->client->voir && !$user->socid) {
1346
			$sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1347
		}
1348
		$sql .= " WHERE s.entity IN (".getEntity('societe').")";
1349
		if (!empty($user->socid)) {
1350
			$sql .= " AND s.rowid = ".$user->socid;
1351
		}
1352
		if ($filter) {
1353
			$sql .= " AND (".$filter.")";
1354
		}
1355
		if (!$user->rights->societe->client->voir && !$user->socid) {
1356
			$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
1357
		}
1358
		if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) {
1359
			$sql .= " AND s.status <> 0";
1360
		}
1361
		if (!empty($excludeids)) {
1362
			$sql .= " AND rowid NOT IN (".$this->db->sanitize(join(',', $excludeids)).")";
1363
		}
1364
		// Add criteria
1365
		if ($filterkey && $filterkey != '') {
1366
			$sql .= " AND (";
1367
			$prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1368
			// For natural search
1369
			$scrit = explode(' ', $filterkey);
1370
			$i = 0;
1371
			if (count($scrit) > 1) {
1372
				$sql .= "(";
1373
			}
1374
			foreach ($scrit as $crit) {
1375
				if ($i > 0) {
1376
					$sql .= " AND ";
1377
				}
1378
				$sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1379
				$i++;
1380
			}
1381
			if (count($scrit) > 1) {
1382
				$sql .= ")";
1383
			}
1384
			if (!empty($conf->barcode->enabled)) {
1385
				$sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1386
			}
1387
			$sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1388
			$sql .= " OR s.name_alias LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.tva_intra LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1389
			$sql .= ")";
1390
		}
1391
		$sql .= $this->db->order("nom", "ASC");
1392
		$sql .= $this->db->plimit($limit, 0);
1393
1394
		// Build output string
1395
		dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1396
		$resql = $this->db->query($sql);
1397
		if ($resql) {
1398
			if (!$forcecombo) {
1399
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1400
				$out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
1401
			}
1402
1403
			// Construct $out and $outarray
1404
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1405
1406
			$textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1407
			if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) {
1408
				// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1409
				//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1410
				if ($showempty && !is_numeric($showempty)) {
1411
					$textifempty = $langs->trans($showempty);
1412
				} else {
1413
					$textifempty .= $langs->trans("All");
1414
				}
1415
			}
1416
			if ($showempty) {
1417
				$out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.$textifempty.'</span>').'">'.$textifempty.'</option>'."\n";
1418
			}
1419
1420
			$num = $this->db->num_rows($resql);
1421
			$i = 0;
1422
			if ($num) {
1423
				while ($i < $num) {
1424
					$obj = $this->db->fetch_object($resql);
1425
					$label = '';
1426
					if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1427
						if (($obj->client) && (!empty($obj->code_client))) {
1428
							$label = $obj->code_client.' - ';
1429
						}
1430
						if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1431
							$label .= $obj->code_fournisseur.' - ';
1432
						}
1433
						$label .= ' '.$obj->name;
1434
					} else {
1435
						$label = $obj->name;
1436
					}
1437
1438
					if (!empty($obj->name_alias)) {
1439
						$label .= ' ('.$obj->name_alias.')';
1440
					}
1441
1442
					if ($showtype) {
1443
						if ($obj->client || $obj->fournisseur) {
1444
							$label .= ' (';
1445
						}
1446
						if ($obj->client == 1 || $obj->client == 3) {
1447
							$label .= $langs->trans("Customer");
1448
						}
1449
						if ($obj->client == 2 || $obj->client == 3) {
1450
							$label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1451
						}
1452
						if ($obj->fournisseur) {
1453
							$label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1454
						}
1455
						if ($obj->client || $obj->fournisseur) {
1456
							$label .= ')';
1457
						}
1458
					}
1459
1460
					if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) {
1461
						$label .= ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : '');
1462
						if (!empty($obj->country_code)) {
1463
							$label .= ', '.$langs->trans('Country'.$obj->country_code);
1464
						}
1465
					}
1466
1467
					if (empty($outputmode)) {
1468
						if (in_array($obj->rowid, $selected)) {
1469
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1470
						} else {
1471
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1472
						}
1473
					} else {
1474
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1475
					}
1476
1477
					$i++;
1478
					if (($i % 10) == 0) {
1479
						$out .= "\n";
1480
					}
1481
				}
1482
			}
1483
			$out .= '</select>'."\n";
1484
		} else {
1485
			dol_print_error($this->db);
1486
		}
1487
1488
		$this->result = array('nbofthirdparties'=>$num);
1489
1490
		if ($outputmode) {
1491
			return $outarray;
1492
		}
1493
		return $out;
1494
	}
1495
1496
1497
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1498
	/**
1499
	 *  Return HTML combo list of absolute discounts
1500
	 *
1501
	 *  @param	string	$selected       Id remise fixe pre-selectionnee
1502
	 *  @param  string	$htmlname       Nom champ formulaire
1503
	 *  @param  string	$filter         Criteres optionnels de filtre
1504
	 *  @param	int		$socid			Id of thirdparty
1505
	 *  @param	int		$maxvalue		Max value for lines that can be selected
1506
	 *  @return	int						Return number of qualifed lines in list
1507
	 */
1508
	public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1509
	{
1510
		// phpcs:enable
1511
		global $langs, $conf;
1512
1513
		// On recherche les remises
1514
		$sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1515
		$sql .= " re.description, re.fk_facture_source";
1516
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
1517
		$sql .= " WHERE re.fk_soc = ".(int) $socid;
1518
		$sql .= " AND re.entity = ".$conf->entity;
1519
		if ($filter) {
1520
			$sql .= " AND ".$filter;
1521
		}
1522
		$sql .= " ORDER BY re.description ASC";
1523
1524
		dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1525
		$resql = $this->db->query($sql);
1526
		if ($resql) {
1527
			print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1528
			$num = $this->db->num_rows($resql);
1529
1530
			$qualifiedlines = $num;
1531
1532
			$i = 0;
1533
			if ($num) {
1534
				print '<option value="0">&nbsp;</option>';
1535
				while ($i < $num) {
1536
					$obj = $this->db->fetch_object($resql);
1537
					$desc = dol_trunc($obj->description, 40);
1538
					if (preg_match('/\(CREDIT_NOTE\)/', $desc)) {
1539
						$desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1540
					}
1541
					if (preg_match('/\(DEPOSIT\)/', $desc)) {
1542
						$desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1543
					}
1544
					if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) {
1545
						$desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1546
					}
1547
					if (preg_match('/\(EXCESS PAID\)/', $desc)) {
1548
						$desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1549
					}
1550
1551
					$selectstring = '';
1552
					if ($selected > 0 && $selected == $obj->rowid) {
1553
						$selectstring = ' selected';
1554
					}
1555
1556
					$disabled = '';
1557
					if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
1558
						$qualifiedlines--;
1559
						$disabled = ' disabled';
1560
					}
1561
1562
					if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) {
1563
						$tmpfac = new Facture($this->db);
1564
						if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
1565
							$desc = $desc.' - '.$tmpfac->ref;
1566
						}
1567
					}
1568
1569
					print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1570
					$i++;
1571
				}
1572
			}
1573
			print '</select>';
1574
			return $qualifiedlines;
1575
		} else {
1576
			dol_print_error($this->db);
1577
			return -1;
1578
		}
1579
	}
1580
1581
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1582
	/**
1583
	 *  Return list of all contacts (for a third party or all)
1584
	 *
1585
	 *  @param	int		$socid      	Id ot third party or 0 for all
1586
	 *  @param  string	$selected   	Id contact pre-selectionne
1587
	 *  @param  string	$htmlname  	    Name of HTML field ('none' for a not editable field)
1588
	 *  @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
1589
	 *  @param  string	$exclude        List of contacts id to exclude
1590
	 *  @param	string	$limitto		Disable answers that are not id in this array list
1591
	 *  @param	integer	$showfunction   Add function into label
1592
	 *  @param	string	$moreclass		Add more class to class style
1593
	 *  @param	integer	$showsoc	    Add company into label
1594
	 *  @param	int		$forcecombo		Force to use combo box
1595
	 *  @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')))
1596
	 *  @param	bool	$options_only	Return options only (for ajax treatment)
1597
	 *  @param	string	$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1598
	 *  @param	string	$htmlid			Html id to use instead of htmlname
1599
	 *  @return	int						<0 if KO, Nb of contact in list if OK
1600
	 *  @deprecated						You can use selectcontacts directly (warning order of param was changed)
1601
	 */
1602
	public function select_contacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $showsoc = 0, $forcecombo = 0, $events = array(), $options_only = false, $moreparam = '', $htmlid = '')
1603
	{
1604
		// phpcs:enable
1605
		print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1606
		return $this->num;
1607
	}
1608
1609
	/**
1610
	 *	Return HTML code of the SELECT of list of all contacts (for a third party or all).
1611
	 *  This also set the number of contacts found into $this->num
1612
	 *
1613
	 * @since 9.0 Add afterSelectContactOptions hook
1614
	 *
1615
	 *	@param	int			$socid      	Id ot third party or 0 for all or -1 for empty list
1616
	 *	@param  array|int	$selected   	Array of ID of pre-selected contact id
1617
	 *	@param  string		$htmlname  	    Name of HTML field ('none' for a not editable field)
1618
	 *	@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
1619
	 *	@param  string		$exclude        List of contacts id to exclude
1620
	 *	@param	string		$limitto		Disable answers that are not id in this array list
1621
	 *	@param	integer		$showfunction   Add function into label
1622
	 *	@param	string		$moreclass		Add more class to class style
1623
	 *	@param	bool		$options_only	Return options only (for ajax treatment)
1624
	 *	@param	integer		$showsoc	    Add company into label
1625
	 * 	@param	int			$forcecombo		Force to use combo box (so no ajax beautify effect)
1626
	 *  @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')))
1627
	 *  @param	string		$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1628
	 *  @param	string		$htmlid			Html id to use instead of htmlname
1629
	 *  @param	bool		$multiple		add [] in the name of element and add 'multiple' attribut
1630
	 *  @param	integer		$disableifempty Set tag 'disabled' on select if there is no choice
1631
	 *	@return	 int|string					<0 if KO, HTML with select string if OK.
1632
	 */
1633
	public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0)
1634
	{
1635
		global $conf, $langs, $hookmanager, $action;
1636
1637
		$langs->load('companies');
1638
1639
		if (empty($htmlid)) {
1640
			$htmlid = $htmlname;
1641
		}
1642
		$num = 0;
1643
1644
		if ($selected === '') {
1645
			$selected = array();
1646
		} elseif (!is_array($selected)) {
1647
			$selected = array($selected);
1648
		}
1649
		$out = '';
1650
1651
		if (!is_object($hookmanager)) {
1652
			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1653
			$hookmanager = new HookManager($this->db);
1654
		}
1655
1656
		// We search third parties
1657
		$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";
1658
		if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1659
			$sql .= ", s.nom as company, s.town AS company_town";
1660
		}
1661
		$sql .= " FROM ".MAIN_DB_PREFIX."socpeople as sp";
1662
		if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1663
			$sql .= " LEFT OUTER JOIN  ".MAIN_DB_PREFIX."societe as s ON s.rowid=sp.fk_soc";
1664
		}
1665
		$sql .= " WHERE sp.entity IN (".getEntity('socpeople').")";
1666
		if ($socid > 0 || $socid == -1) {
1667
			$sql .= " AND sp.fk_soc=".$socid;
1668
		}
1669
		if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) {
1670
			$sql .= " AND sp.statut <> 0";
1671
		}
1672
		$sql .= " ORDER BY sp.lastname ASC";
1673
1674
		dol_syslog(get_class($this)."::selectcontacts", LOG_DEBUG);
1675
		$resql = $this->db->query($sql);
1676
		if ($resql) {
1677
			$num = $this->db->num_rows($resql);
1678
1679
			if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1680
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1681
				$out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
1682
			}
1683
1684
			if ($htmlname != 'none' && !$options_only) {
1685
				$out .= '<select class="flat'.($moreclass ? ' '.$moreclass : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1686
			}
1687
1688
			if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1689
				$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1690
			}
1691
			if ($showempty == 2) {
1692
				$out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1693
			}
1694
1695
			$i = 0;
1696
			if ($num) {
1697
				include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1698
				$contactstatic = new Contact($this->db);
1699
1700
				while ($i < $num) {
1701
					$obj = $this->db->fetch_object($resql);
1702
1703
					// Set email (or phones) and town extended infos
1704
					$extendedInfos = '';
1705
					if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) {
1706
						$extendedInfos = array();
1707
						$email = trim($obj->email);
1708
						if (!empty($email)) {
1709
							$extendedInfos[] = $email;
1710
						} else {
1711
							$phone = trim($obj->phone);
1712
							$phone_perso = trim($obj->phone_perso);
1713
							$phone_mobile = trim($obj->phone_mobile);
1714
							if (!empty($phone)) {
1715
								$extendedInfos[] = $phone;
1716
							}
1717
							if (!empty($phone_perso)) {
1718
								$extendedInfos[] = $phone_perso;
1719
							}
1720
							if (!empty($phone_mobile)) {
1721
								$extendedInfos[] = $phone_mobile;
1722
							}
1723
						}
1724
						$contact_town = trim($obj->contact_town);
1725
						$company_town = trim($obj->company_town);
1726
						if (!empty($contact_town)) {
1727
							$extendedInfos[] = $contact_town;
1728
						} elseif (!empty($company_town)) {
1729
							$extendedInfos[] = $company_town;
1730
						}
1731
						$extendedInfos = implode(' - ', $extendedInfos);
1732
						if (!empty($extendedInfos)) {
1733
							$extendedInfos = ' - '.$extendedInfos;
1734
						}
1735
					}
1736
1737
					$contactstatic->id = $obj->rowid;
1738
					$contactstatic->lastname = $obj->lastname;
1739
					$contactstatic->firstname = $obj->firstname;
1740
					if ($obj->statut == 1) {
1741
						if ($htmlname != 'none') {
1742
							$disabled = 0;
1743
							if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1744
								$disabled = 1;
1745
							}
1746
							if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1747
								$disabled = 1;
1748
							}
1749
							if (!empty($selected) && in_array($obj->rowid, $selected)) {
1750
								$out .= '<option value="'.$obj->rowid.'"';
1751
								if ($disabled) {
1752
									$out .= ' disabled';
1753
								}
1754
								$out .= ' selected>';
1755
								$out .= $contactstatic->getFullName($langs).$extendedInfos;
1756
								if ($showfunction && $obj->poste) {
1757
									$out .= ' ('.$obj->poste.')';
1758
								}
1759
								if (($showsoc > 0) && $obj->company) {
1760
									$out .= ' - ('.$obj->company.')';
1761
								}
1762
								$out .= '</option>';
1763
							} else {
1764
								$out .= '<option value="'.$obj->rowid.'"';
1765
								if ($disabled) {
1766
									$out .= ' disabled';
1767
								}
1768
								$out .= '>';
1769
								$out .= $contactstatic->getFullName($langs).$extendedInfos;
1770
								if ($showfunction && $obj->poste) {
1771
									$out .= ' ('.$obj->poste.')';
1772
								}
1773
								if (($showsoc > 0) && $obj->company) {
1774
									$out .= ' - ('.$obj->company.')';
1775
								}
1776
								$out .= '</option>';
1777
							}
1778
						} else {
1779
							if (in_array($obj->rowid, $selected)) {
1780
								$out .= $contactstatic->getFullName($langs).$extendedInfos;
1781
								if ($showfunction && $obj->poste) {
1782
									$out .= ' ('.$obj->poste.')';
1783
								}
1784
								if (($showsoc > 0) && $obj->company) {
1785
									$out .= ' - ('.$obj->company.')';
1786
								}
1787
							}
1788
						}
1789
					}
1790
					$i++;
1791
				}
1792
			} else {
1793
				$labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1794
				$out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">';
1795
				$out .= $labeltoshow;
1796
				$out .= '</option>';
1797
			}
1798
1799
			$parameters = array(
1800
				'socid'=>$socid,
1801
				'htmlname'=>$htmlname,
1802
				'resql'=>$resql,
1803
				'out'=>&$out,
1804
				'showfunction'=>$showfunction,
1805
				'showsoc'=>$showsoc,
1806
			);
1807
1808
			$reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1809
1810
			if ($htmlname != 'none' && !$options_only) {
1811
				$out .= '</select>';
1812
			}
1813
1814
			$this->num = $num;
1815
			return $out;
1816
		} else {
1817
			dol_print_error($this->db);
1818
			return -1;
1819
		}
1820
	}
1821
1822
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1823
	/**
1824
	 *	Return the HTML select list of users
1825
	 *
1826
	 *  @param	string			$selected       Id user preselected
1827
	 *  @param  string			$htmlname       Field name in form
1828
	 *  @param  int				$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
1829
	 *  @param  array			$exclude        Array list of users id to exclude
1830
	 * 	@param	int				$disabled		If select list must be disabled
1831
	 *  @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
1832
	 * 	@param	int				$enableonly		Array list of users id to be enabled. All other must be disabled
1833
	 *  @param	string			$force_entity	'0' or Ids of environment to force
1834
	 * 	@return	void
1835
	 *  @deprecated		Use select_dolusers instead
1836
	 *  @see select_dolusers()
1837
	 */
1838
	public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1839
	{
1840
		// phpcs:enable
1841
		print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1842
	}
1843
1844
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1845
	/**
1846
	 *	Return select list of users
1847
	 *
1848
	 *  @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)
1849
	 *  @param  string			$htmlname       Field name in form
1850
	 *  @param  int|string		$show_empty     0=list with no empty value, 1=add also an empty value into list
1851
	 *  @param  array			$exclude        Array list of users id to exclude
1852
	 * 	@param	int				$disabled		If select list must be disabled
1853
	 *  @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
1854
	 * 	@param	array			$enableonly		Array list of users id to be enabled. If defined, it means that others will be disabled
1855
	 *  @param	string			$force_entity	'0' or Ids of environment to force
1856
	 *  @param	int				$maxlength		Maximum length of string into list (0=no limit)
1857
	 *  @param	int				$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1858
	 *  @param	string			$morefilter		Add more filters into sql request (Example: 'employee = 1'). This value must not come from user input.
1859
	 *  @param	integer			$show_every		0=default list, 1=add also a value "Everybody" at beginning of list
1860
	 *  @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.
1861
	 *  @param	string			$morecss		More css
1862
	 *  @param  int     		$noactive       Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
1863
	 *  @param  int				$outputmode     0=HTML select string, 1=Array
1864
	 *  @param  bool			$multiple       add [] in the name of element and add 'multiple' attribut
1865
	 * 	@return	string							HTML select string
1866
	 *  @see select_dolgroups()
1867
	 */
1868
	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)
1869
	{
1870
		// phpcs:enable
1871
		global $conf, $user, $langs, $hookmanager;
1872
1873
		// If no preselected user defined, we take current user
1874
		if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) {
1875
			$selected = $user->id;
1876
		}
1877
1878
		if ($selected === '') {
1879
			$selected = array();
1880
		} elseif (!is_array($selected)) {
1881
			$selected = array($selected);
1882
		}
1883
1884
		$excludeUsers = null;
1885
		$includeUsers = null;
1886
1887
		// Permettre l'exclusion d'utilisateurs
1888
		if (is_array($exclude)) {
1889
			$excludeUsers = implode(",", $exclude);
1890
		}
1891
		// Permettre l'inclusion d'utilisateurs
1892
		if (is_array($include)) {
1893
			$includeUsers = implode(",", $include);
1894
		} elseif ($include == 'hierarchy') {
1895
			// Build list includeUsers to have only hierarchy
1896
			$includeUsers = implode(",", $user->getAllChildIds(0));
1897
		} elseif ($include == 'hierarchyme') {
1898
			// Build list includeUsers to have only hierarchy and current user
1899
			$includeUsers = implode(",", $user->getAllChildIds(1));
1900
		}
1901
1902
		$out = '';
1903
		$outarray = array();
1904
1905
		// Forge request to select users
1906
		$sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo";
1907
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
1908
			$sql .= ", e.label";
1909
		}
1910
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
1911
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
1912
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid = u.entity";
1913
			if ($force_entity) {
1914
				$sql .= " WHERE u.entity IN (0, ".$this->db->sanitize($force_entity).")";
1915
			} else {
1916
				$sql .= " WHERE u.entity IS NOT NULL";
1917
			}
1918
		} else {
1919
			if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1920
				$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
1921
				$sql .= " ON ug.fk_user = u.rowid";
1922
				$sql .= " WHERE ug.entity = ".$conf->entity;
1923
			} else {
1924
				$sql .= " WHERE u.entity IN (0, ".$conf->entity.")";
1925
			}
1926
		}
1927
		if (!empty($user->socid)) {
1928
			$sql .= " AND u.fk_soc = ".((int) $user->socid);
1929
		}
1930
		if (is_array($exclude) && $excludeUsers) {
1931
			$sql .= " AND u.rowid NOT IN (".$this->db->sanitize($excludeUsers).")";
1932
		}
1933
		if ($includeUsers) {
1934
			$sql .= " AND u.rowid IN (".$this->db->sanitize($includeUsers).")";
1935
		}
1936
		if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) {
1937
			$sql .= " AND u.statut <> 0";
1938
		}
1939
		if (!empty($morefilter)) {
1940
			$sql .= " ".$morefilter;
1941
		}
1942
1943
		//Add hook to filter on user (for exemple on usergroup define in custom modules)
1944
		$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...
1945
		if (!empty($reshook)) {
1946
			$sql .= $hookmanager->resPrint;
1947
		}
1948
1949
		if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {	// MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1950
			$sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
1951
		} else {
1952
			$sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
1953
		}
1954
1955
		dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1956
1957
		$resql = $this->db->query($sql);
1958
		if ($resql) {
1959
			$num = $this->db->num_rows($resql);
1960
			$i = 0;
1961
			if ($num) {
1962
				// do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1963
				$out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
1964
				if ($show_empty && !$multiple) {
1965
					$textforempty = ' ';
1966
					if (!empty($conf->use_javascript_ajax)) {
1967
						$textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
1968
					}
1969
					if (!is_numeric($show_empty)) {
1970
						$textforempty = $show_empty;
1971
					}
1972
					$out .= '<option class="optiongrey" value="'.($show_empty < 0 ? $show_empty : -1).'"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
1973
				}
1974
				if ($show_every) {
1975
					$out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
1976
				}
1977
1978
				$userstatic = new User($this->db);
1979
1980
				while ($i < $num) {
1981
					$obj = $this->db->fetch_object($resql);
1982
1983
					$userstatic->id = $obj->rowid;
1984
					$userstatic->lastname = $obj->lastname;
1985
					$userstatic->firstname = $obj->firstname;
1986
					$userstatic->photo = $obj->photo;
1987
					$userstatic->statut = $obj->status;
1988
					$userstatic->entity = $obj->entity;
1989
					$userstatic->admin = $obj->admin;
1990
1991
					$disableline = '';
1992
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
1993
						$disableline = ($enableonlytext ? $enableonlytext : '1');
1994
					}
1995
1996
					$labeltoshow = '';
1997
1998
					// $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
1999
					$fullNameMode = 0;
2000
					if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) {
2001
						$fullNameMode = 1; //Firstname+lastname
2002
					}
2003
					$labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2004
					if (empty($obj->firstname) && empty($obj->lastname)) {
2005
						$labeltoshow .= $obj->login;
2006
					}
2007
2008
					// Complete name with more info
2009
					$moreinfo = '';
2010
					if (!empty($conf->global->MAIN_SHOW_LOGIN)) {
2011
						$moreinfo .= ($moreinfo ? ' - ' : ' (').$obj->login;
2012
					}
2013
					if ($showstatus >= 0) {
2014
						if ($obj->status == 1 && $showstatus == 1) {
2015
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
2016
						}
2017
						if ($obj->status == 0 && $showstatus == 1) {
2018
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
2019
						}
2020
					}
2021
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) {
2022
						if (!$obj->entity) {
2023
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
2024
						} else {
2025
							if ($obj->entity != $conf->entity) {
2026
								$moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2027
							}
2028
						}
2029
					}
2030
					$moreinfo .= ($moreinfo ? ')' : '');
2031
					if ($disableline && $disableline != '1') {
2032
						$moreinfo .= ' - '.$disableline; // This is text from $enableonlytext parameter
2033
					}
2034
					$labeltoshow .= $moreinfo;
2035
2036
					$out .= '<option value="'.$obj->rowid.'"';
2037
					if ($disableline) {
2038
						$out .= ' disabled';
2039
					}
2040
					if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
2041
						$out .= ' selected';
2042
					}
2043
					$out .= ' data-html="';
2044
					$outhtml = '';
2045
					// if (!empty($obj->photo)) {
2046
					$outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' ';
2047
					// }
2048
					if ($showstatus >= 0 && $obj->status == 0) {
2049
						$outhtml .= '<strike class="opacitymediumxxx">';
2050
					}
2051
					$outhtml .= $labeltoshow;
2052
					if ($showstatus >= 0 && $obj->status == 0) {
2053
						$outhtml .= '</strike>';
2054
					}
2055
					$out .= dol_escape_htmltag($outhtml);
2056
					$out .= '">';
2057
					$out .= $labeltoshow;
2058
					$out .= '</option>';
2059
2060
					$outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
2061
2062
					$i++;
2063
				}
2064
			} else {
2065
				$out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
2066
				$out .= '<option value="">'.$langs->trans("None").'</option>';
2067
			}
2068
			$out .= '</select>';
2069
2070
			if ($num) {
2071
				// Enhance with select2
2072
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2073
				$out .= ajax_combobox($htmlname);
2074
			}
2075
		} else {
2076
			dol_print_error($this->db);
2077
		}
2078
2079
		if ($outputmode) {
2080
			return $outarray;
2081
		}
2082
		return $out;
2083
	}
2084
2085
2086
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2087
	/**
2088
	 *	Return select list of users. Selected users are stored into session.
2089
	 *  List of users are provided into $_SESSION['assignedtouser'].
2090
	 *
2091
	 *  @param  string	$action         Value for $action
2092
	 *  @param  string	$htmlname       Field name in form
2093
	 *  @param  int		$show_empty     0=list without the empty value, 1=add empty value
2094
	 *  @param  array	$exclude        Array list of users id to exclude
2095
	 * 	@param	int		$disabled		If select list must be disabled
2096
	 *  @param  array	$include        Array list of users id to include or 'hierarchy' to have only supervised users
2097
	 * 	@param	array	$enableonly		Array list of users id to be enabled. All other must be disabled
2098
	 *  @param	int		$force_entity	'0' or Ids of environment to force
2099
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
2100
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
2101
	 *  @param	string	$morefilter		Add more filters into sql request
2102
	 *  @param	int		$showproperties		Show properties of each attendees
2103
	 *  @param	array	$listofuserid		Array with properties of each user
2104
	 *  @param	array	$listofcontactid	Array with properties of each contact
2105
	 *  @param	array	$listofotherid		Array with properties of each other contact
2106
	 * 	@return	string					HTML select string
2107
	 *  @see select_dolgroups()
2108
	 */
2109
	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())
2110
	{
2111
		// phpcs:enable
2112
		global $conf, $user, $langs;
2113
2114
		$userstatic = new User($this->db);
2115
		$out = '';
2116
2117
2118
		$assignedtouser = array();
2119
		if (!empty($_SESSION['assignedtouser'])) {
2120
			$assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2121
		}
2122
		$nbassignetouser = count($assignedtouser);
2123
2124
		//if ($nbassignetouser && $action != 'view') $out .= '<br>';
2125
		if ($nbassignetouser) {
2126
			$out .= '<ul class="attendees">';
2127
		}
2128
		$i = 0;
2129
		$ownerid = 0;
2130
		foreach ($assignedtouser as $key => $value) {
2131
			if ($value['id'] == $ownerid) {
2132
				continue;
2133
			}
2134
2135
			$out .= '<li>';
2136
			$userstatic->fetch($value['id']);
2137
			$out .= $userstatic->getNomUrl(-1);
2138
			if ($i == 0) {
2139
				$ownerid = $value['id'];
2140
				$out .= ' ('.$langs->trans("Owner").')';
2141
			}
2142
			if ($nbassignetouser > 1 && $action != 'view') {
2143
				$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.'">';
2144
			}
2145
			// Show my availability
2146
			if ($showproperties) {
2147
				if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2148
					$out .= '<div class="myavailability inline-block">';
2149
					$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>';
2150
					$out .= '</div>';
2151
				}
2152
			}
2153
			//$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2154
			//$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2155
2156
			$out .= '</li>';
2157
			$i++;
2158
		}
2159
		if ($nbassignetouser) {
2160
			$out .= '</ul>';
2161
		}
2162
2163
		// Method with no ajax
2164
		if ($action != 'view') {
2165
			$out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2166
			$out .= '<script type="text/javascript" language="javascript">jQuery(document).ready(function () {';
2167
			$out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2168
			$out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2169
			$out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }';
2170
			$out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }';
2171
			$out .= '});';
2172
			$out .= '})</script>';
2173
			$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2174
			$out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
2175
			$out .= '<br>';
2176
		}
2177
2178
		return $out;
2179
	}
2180
2181
2182
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2183
	/**
2184
	 *  Return list of products for customer in Ajax if Ajax activated or go to select_produits_list
2185
	 *
2186
	 *  @param		int			$selected				Preselected products
2187
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page).
2188
	 *  @param		int|string	$filtertype				Filter on product type (''=nofilter, 0=product, 1=service)
2189
	 *  @param		int			$limit					Limit on number of returned lines
2190
	 *  @param		int			$price_level			Level of price to show
2191
	 *  @param		int			$status					Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell
2192
	 *  @param		int			$finished				2=all, 1=finished, 0=raw material
2193
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
2194
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
2195
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
2196
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
2197
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2198
	 * 	@param		int			$forcecombo				Force to use combo box
2199
	 *  @param      string      $morecss                Add more css on select
2200
	 *  @param      int         $hidepriceinlabel       1=Hide prices in label
2201
	 *  @param      string      $warehouseStatus        Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used
2202
	 *										            'warehouseopen' = count products from open warehouses,
2203
	 *										            'warehouseclosed' = count products from closed warehouses,
2204
	 *										            'warehouseinternal' = count products from warehouses for internal correct/transfer only
2205
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
2206
	 *  @param		string		$nooutput				No print, return the output into a string
2207
	 *  @return		void|string
2208
	 */
2209
	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)
2210
	{
2211
		// phpcs:enable
2212
		global $langs, $conf;
2213
2214
		$out = '';
2215
2216
		// check parameters
2217
		$price_level = (!empty($price_level) ? $price_level : 0);
2218
		if (is_null($ajaxoptions)) {
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
2219
			$ajaxoptions = array();
2220
		}
2221
2222
		if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
2223
			if (!empty($conf->product->enabled) && empty($conf->service->enabled)) {
2224
				$filtertype = '0';
2225
			} elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) {
2226
				$filtertype = '1';
2227
			}
2228
		}
2229
2230
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2231
			$placeholder = '';
2232
2233
			if ($selected && empty($selected_input_value)) {
2234
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2235
				$producttmpselect = new Product($this->db);
2236
				$producttmpselect->fetch($selected);
2237
				$selected_input_value = $producttmpselect->ref;
2238
				unset($producttmpselect);
2239
			}
2240
			// handle case where product or service module is disabled + no filter specified
2241
			if ($filtertype == '') {
2242
				if (empty($conf->product->enabled)) { // when product module is disabled, show services only
2243
					$filtertype = 1;
2244
				} elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2245
					$filtertype = 0;
2246
				}
2247
			}
2248
			// mode=1 means customers products
2249
			$urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
2250
			//Price by customer
2251
			if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2252
				$urloption .= '&socid='.$socid;
2253
			}
2254
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2255
2256
			if (!empty($conf->variants->enabled) && is_array($selected_combinations)) {
2257
				// Code to automatically insert with javascript the select of attributes under the select of product
2258
				// when a parent of variant has been selected.
2259
				$out .= '
2260
				<!-- script to auto show attributes select tags if a variant was selected -->
2261
				<script>
2262
					// auto show attributes fields
2263
					selected = '.json_encode($selected_combinations).';
2264
					combvalues = {};
2265
2266
					jQuery(document).ready(function () {
2267
2268
						jQuery("input[name=\'prod_entry_mode\']").change(function () {
2269
							if (jQuery(this).val() == \'free\') {
2270
								jQuery(\'div#attributes_box\').empty();
2271
							}
2272
						});
2273
2274
						jQuery("input#'.$htmlname.'").change(function () {
2275
2276
							if (!jQuery(this).val()) {
2277
								jQuery(\'div#attributes_box\').empty();
2278
								return;
2279
							}
2280
2281
							console.log("A change has started. We get variants fields to inject html select");
2282
2283
							jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
2284
								id: jQuery(this).val()
2285
							}, function (data) {
2286
								jQuery(\'div#attributes_box\').empty();
2287
2288
								jQuery.each(data, function (key, val) {
2289
2290
									combvalues[val.id] = val.values;
2291
2292
									var span = jQuery(document.createElement(\'div\')).css({
2293
										\'display\': \'table-row\'
2294
									});
2295
2296
									span.append(
2297
										jQuery(document.createElement(\'div\')).text(val.label).css({
2298
											\'font-weight\': \'bold\',
2299
											\'display\': \'table-cell\'
2300
										})
2301
									);
2302
2303
									var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2304
										\'margin-left\': \'15px\',
2305
										\'white-space\': \'pre\'
2306
									}).append(
2307
										jQuery(document.createElement(\'option\')).val(\'\')
2308
									);
2309
2310
									jQuery.each(combvalues[val.id], function (key, val) {
2311
										var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2312
2313
										if (selected[val.fk_product_attribute] == val.id) {
2314
											tag.attr(\'selected\', \'selected\');
2315
										}
2316
2317
										html.append(tag);
2318
									});
2319
2320
									span.append(html);
2321
									jQuery(\'div#attributes_box\').append(span);
2322
								});
2323
							})
2324
						});
2325
2326
						'.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2327
					});
2328
				</script>
2329
                ';
2330
			}
2331
2332
			if (empty($hidelabel)) {
2333
				$out .= $langs->trans("RefOrLabel").' : ';
2334
			} elseif ($hidelabel > 1) {
2335
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2336
				if ($hidelabel == 2) {
2337
					$out .= img_picto($langs->trans("Search"), 'search');
2338
				}
2339
			}
2340
			$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
2341
			if ($hidelabel == 3) {
2342
				$out .= img_picto($langs->trans("Search"), 'search');
2343
			}
2344
		} else {
2345
			$out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
2346
		}
2347
2348
		if (empty($nooutput)) {
2349
			print $out;
2350
		} else {
2351
			return $out;
2352
		}
2353
	}
2354
2355
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2356
	/**
2357
	 *	Return list of products for a customer.
2358
	 *  Called by select_produits.
2359
	 *
2360
	 *	@param      int		$selected           Preselected product
2361
	 *	@param      string	$htmlname           Name of select html
2362
	 *  @param		string	$filtertype         Filter on product type (''=nofilter, 0=product, 1=service)
2363
	 *	@param      int		$limit              Limit on number of returned lines
2364
	 *	@param      int		$price_level        Level of price to show
2365
	 * 	@param      string	$filterkey          Filter on product
2366
	 *	@param		int		$status             -1=Return all products, 0=Products not on sell, 1=Products on sell
2367
	 *  @param      int		$finished           Filter on finished field: 2=No filter
2368
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
2369
	 *  @param      int		$socid     		    Thirdparty Id (to get also price dedicated to this customer)
2370
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2371
	 * 	@param		int		$forcecombo		    Force to use combo box
2372
	 *  @param      string  $morecss            Add more css on select
2373
	 *  @param      int     $hidepriceinlabel   1=Hide prices in label
2374
	 *  @param      string  $warehouseStatus    Warehouse status filter to group/count stock. Following comma separated filter options can be used.
2375
	 *										    'warehouseopen' = count products from open warehouses,
2376
	 *										    'warehouseclosed' = count products from closed warehouses,
2377
	 *										    'warehouseinternal' = count products from warehouses for internal correct/transfer only
2378
	 *  @return     array    				    Array of keys for json
2379
	 */
2380
	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 = '')
2381
	{
2382
		// phpcs:enable
2383
		global $langs, $conf, $user, $db;
2384
2385
		$out = '';
2386
		$outarray = array();
2387
2388
		// Units
2389
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2390
			$langs->load('other');
2391
		}
2392
2393
		$warehouseStatusArray = array();
2394
		if (!empty($warehouseStatus)) {
2395
			require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2396
			if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2397
				$warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2398
			}
2399
			if (preg_match('/warehouseopen/', $warehouseStatus)) {
2400
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2401
			}
2402
			if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2403
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2404
			}
2405
		}
2406
2407
		$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.duration, p.fk_price_expression";
2408
		if (count($warehouseStatusArray)) {
2409
			$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
2410
		} else {
2411
			$selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2412
		}
2413
2414
		$sql = "SELECT ";
2415
		$sql .= $selectFields.$selectFieldsGrouped;
2416
2417
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2418
			//Product category
2419
			$sql .= ", (SELECT ".MAIN_DB_PREFIX."categorie_product.fk_categorie
2420
						FROM ".MAIN_DB_PREFIX."categorie_product
2421
						WHERE ".MAIN_DB_PREFIX."categorie_product.fk_product=p.rowid
2422
						LIMIT 1
2423
				) AS categorie_product_id ";
2424
		}
2425
2426
		//Price by customer
2427
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2428
			$sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2429
			$sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.ref_customer as custref';
2430
			$selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custref";
2431
		}
2432
		// Units
2433
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2434
			$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";
2435
			$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';
2436
		}
2437
2438
		// Multilang : we add translation
2439
		if (!empty($conf->global->MAIN_MULTILANGS)) {
2440
			$sql .= ", pl.label as label_translated";
2441
			$sql .= ", pl.description as description_translated";
2442
			$selectFields .= ", label_translated";
2443
			$selectFields .= ", description_translated";
2444
		}
2445
		// Price by quantity
2446
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2447
			$sql .= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
2448
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2449
				$sql .= " AND price_level=".$price_level;
2450
			}
2451
			$sql .= " ORDER BY date_price";
2452
			$sql .= " DESC LIMIT 1) as price_rowid";
2453
			$sql .= ", (SELECT pp.price_by_qty FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid"; // price_by_qty is 1 if some prices by qty exists in subtable
2454
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
2455
				$sql .= " AND price_level=".$price_level;
2456
			}
2457
			$sql .= " ORDER BY date_price";
2458
			$sql .= " DESC LIMIT 1) as price_by_qty";
2459
			$selectFields .= ", price_rowid, price_by_qty";
2460
		}
2461
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2462
		if (count($warehouseStatusArray)) {
2463
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
2464
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2465
			$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.
2466
		}
2467
2468
		// include search in supplier ref
2469
		if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2470
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2471
		}
2472
2473
		//Price by customer
2474
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2475
			$sql .= " LEFT JOIN  ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".$socid." AND pcp.fk_product=p.rowid";
2476
		}
2477
		// Units
2478
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2479
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2480
		}
2481
		// Multilang : we add translation
2482
		if (!empty($conf->global->MAIN_MULTILANGS)) {
2483
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid ";
2484
			if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) {
2485
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
2486
				$soc = new Societe($db);
2487
				$result = $soc->fetch($socid);
2488
				if ($result > 0 && !empty($soc->default_lang)) {
2489
					$sql .= " AND pl.lang='" . $this->db->escape($soc->default_lang) . "'";
2490
				} else {
2491
					$sql .= " AND pl.lang='".$this->db->escape($langs->getDefaultLang())."'";
2492
				}
2493
			} else {
2494
				$sql .= " AND pl.lang='".$this->db->escape($langs->getDefaultLang())."'";
2495
			}
2496
		}
2497
2498
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2499
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2500
		}
2501
2502
		$sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2503
2504
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2505
			$sql .= " AND pac.rowid IS NULL";
2506
		}
2507
2508
		if ($finished == 0) {
2509
			$sql .= " AND p.finished = ".((int) $finished);
2510
		} elseif ($finished == 1) {
2511
			$sql .= " AND p.finished = ".((int) $finished);
2512
			if ($status >= 0) {
2513
				$sql .= " AND p.tosell = ".((int) $status);
2514
			}
2515
		} elseif ($status >= 0) {
2516
			$sql .= " AND p.tosell = ".((int) $status);
2517
		}
2518
		// Filter by product type
2519
		if (strval($filtertype) != '') {
2520
			$sql .= " AND p.fk_product_type = ".((int) $filtertype);
2521
		} elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only
2522
			$sql .= " AND p.fk_product_type = 1";
2523
		} elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2524
			$sql .= " AND p.fk_product_type = 0";
2525
		}
2526
		// Add criteria on ref/label
2527
		if ($filterkey != '') {
2528
			$sql .= ' AND (';
2529
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2530
			// For natural search
2531
			$scrit = explode(' ', $filterkey);
2532
			$i = 0;
2533
			if (count($scrit) > 1) {
2534
				$sql .= "(";
2535
			}
2536
			foreach ($scrit as $crit) {
2537
				if ($i > 0) {
2538
					$sql .= " AND ";
2539
				}
2540
				$sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2541
				if (!empty($conf->global->MAIN_MULTILANGS)) {
2542
					$sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2543
				}
2544
				if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && ! empty($socid)) {
2545
					$sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'";
2546
				}
2547
				if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) {
2548
					$sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2549
					if (!empty($conf->global->MAIN_MULTILANGS)) {
2550
						$sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2551
					}
2552
				}
2553
				if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) {
2554
					$sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2555
				}
2556
				$sql .= ")";
2557
				$i++;
2558
			}
2559
			if (count($scrit) > 1) {
2560
				$sql .= ")";
2561
			}
2562
			if (!empty($conf->barcode->enabled)) {
2563
				$sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2564
			}
2565
			$sql .= ')';
2566
		}
2567
		if (count($warehouseStatusArray)) {
2568
			$sql .= ' GROUP BY'.$selectFields;
2569
		}
2570
2571
		//Sort by category
2572
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) {
2573
			$sql .= " ORDER BY categorie_product_id ";
2574
			//ASC OR DESC order
2575
			($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2576
		} else {
2577
			$sql .= $this->db->order("p.ref");
2578
		}
2579
2580
		$sql .= $this->db->plimit($limit, 0);
2581
2582
		// Build output string
2583
		dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2584
		$result = $this->db->query($sql);
2585
		if ($result) {
2586
			require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2587
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2588
			require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2589
2590
			$num = $this->db->num_rows($result);
2591
2592
			$events = null;
2593
2594
			if (!$forcecombo) {
2595
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2596
				$out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT);
2597
			}
2598
2599
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2600
2601
			$textifempty = '';
2602
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2603
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2604
			if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
2605
				if ($showempty && !is_numeric($showempty)) {
2606
					$textifempty = $langs->trans($showempty);
2607
				} else {
2608
					$textifempty .= $langs->trans("All");
2609
				}
2610
			} else {
2611
				if ($showempty && !is_numeric($showempty)) {
2612
					$textifempty = $langs->trans($showempty);
2613
				}
2614
			}
2615
			if ($showempty) {
2616
				$out .= '<option value="-1" selected>'.($textifempty ? $textifempty : '&nbsp;').'</option>';
2617
			}
2618
2619
			$i = 0;
2620
			while ($num && $i < $num) {
2621
				$opt = '';
2622
				$optJson = array();
2623
				$objp = $this->db->fetch_object($result);
2624
2625
				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
2626
					$sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2627
					$sql .= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
2628
					$sql .= " WHERE fk_product_price=".$objp->price_rowid;
2629
					$sql .= " ORDER BY quantity ASC";
2630
2631
					dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2632
					$result2 = $this->db->query($sql);
2633
					if ($result2) {
2634
						$nb_prices = $this->db->num_rows($result2);
2635
						$j = 0;
2636
						while ($nb_prices && $j < $nb_prices) {
2637
							$objp2 = $this->db->fetch_object($result2);
2638
2639
							$objp->price_by_qty_rowid = $objp2->rowid;
2640
							$objp->price_by_qty_price_base_type = $objp2->price_base_type;
2641
							$objp->price_by_qty_quantity = $objp2->quantity;
2642
							$objp->price_by_qty_unitprice = $objp2->unitprice;
2643
							$objp->price_by_qty_remise_percent = $objp2->remise_percent;
2644
							// For backward compatibility
2645
							$objp->quantity = $objp2->quantity;
2646
							$objp->price = $objp2->price;
2647
							$objp->unitprice = $objp2->unitprice;
2648
							$objp->remise_percent = $objp2->remise_percent;
2649
							$objp->remise = $objp2->remise;
2650
2651
							$this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2652
2653
							$j++;
2654
2655
							// Add new entry
2656
							// "key" value of json key array is used by jQuery automatically as selected value
2657
							// "label" value of json key array is used by jQuery automatically as text for combo box
2658
							$out .= $opt;
2659
							array_push($outarray, $optJson);
2660
						}
2661
					}
2662
				} else {
2663
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2664
						$price_product = new Product($this->db);
2665
						$price_product->fetch($objp->rowid, '', '', 1);
2666
						$priceparser = new PriceParser($this->db);
2667
						$price_result = $priceparser->parseProduct($price_product);
2668
						if ($price_result >= 0) {
2669
							$objp->price = $price_result;
2670
							$objp->unitprice = $price_result;
2671
							//Calculate the VAT
2672
							$objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2673
							$objp->price_ttc = price2num($objp->price_ttc, 'MU');
2674
						}
2675
					}
2676
2677
					$this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2678
					// Add new entry
2679
					// "key" value of json key array is used by jQuery automatically as selected value
2680
					// "label" value of json key array is used by jQuery automatically as text for combo box
2681
					$out .= $opt;
2682
					array_push($outarray, $optJson);
2683
				}
2684
2685
				$i++;
2686
			}
2687
2688
			$out .= '</select>';
2689
2690
			$this->db->free($result);
2691
2692
			if (empty($outputmode)) {
2693
				return $out;
2694
			}
2695
			return $outarray;
2696
		} else {
2697
			dol_print_error($db);
2698
		}
2699
	}
2700
2701
	/**
2702
	 * constructProductListOption.
2703
	 * This define value for &$opt and &$optJson.
2704
	 *
2705
	 * @param 	resource	$objp			    Resultset of fetch
2706
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
2707
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
2708
	 * @param 	int			$price_level	    Price level
2709
	 * @param 	string		$selected		    Preselected value
2710
	 * @param   int         $hidepriceinlabel   Hide price in label
2711
	 * @param   string      $filterkey          Filter key to highlight
2712
	 * @param	int			$novirtualstock 	Do not load virtual stock, even if slow option STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO is on.
2713
	 * @return	void
2714
	 */
2715
	protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2716
	{
2717
		global $langs, $conf, $user, $db;
2718
2719
		$outkey = '';
2720
		$outval = '';
2721
		$outref = '';
2722
		$outlabel = '';
2723
		$outlabel_translated = '';
2724
		$outdesc = '';
2725
		$outdesc_translated = '';
2726
		$outbarcode = '';
2727
		$outorigin = '';
2728
		$outtype = '';
2729
		$outprice_ht = '';
2730
		$outprice_ttc = '';
2731
		$outpricebasetype = '';
2732
		$outtva_tx = '';
2733
		$outqty = 1;
2734
		$outdiscount = 0;
2735
2736
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2737
2738
		$label = $objp->label;
2739
		if (!empty($objp->label_translated)) {
2740
			$label = $objp->label_translated;
2741
		}
2742
		if (!empty($filterkey) && $filterkey != '') {
2743
			$label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2744
		}
2745
2746
		$outkey = $objp->rowid;
2747
		$outref = $objp->ref;
2748
		$outrefcust = empty($objp->custref) ? '' : $objp->custref;
2749
		$outlabel = $objp->label;
2750
		$outdesc = $objp->description;
2751
		if (!empty($conf->global->MAIN_MULTILANGS)) {
2752
			$outlabel_translated = $objp->label_translated;
2753
			$outdesc_translated = $objp->description_translated;
2754
		}
2755
		$outbarcode = $objp->barcode;
2756
		$outorigin = $objp->fk_country;
2757
		$outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
2758
2759
		$outtype = $objp->fk_product_type;
2760
		$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2761
		$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2762
2763
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2764
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
2765
		}
2766
2767
		// Units
2768
		$outvalUnits = '';
2769
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2770
			if (!empty($objp->unit_short)) {
2771
				$outvalUnits .= ' - '.$objp->unit_short;
2772
			}
2773
		}
2774
		if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2775
			if (!empty($objp->weight) && $objp->weight_units !== null) {
2776
				$unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2777
				$outvalUnits .= ' - '.$unitToShow;
2778
			}
2779
			if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2780
				$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2781
				$outvalUnits .= ' - '.$unitToShow;
2782
			}
2783
			if (!empty($objp->surface) && $objp->surface_units !== null) {
2784
				$unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2785
				$outvalUnits .= ' - '.$unitToShow;
2786
			}
2787
			if (!empty($objp->volume) && $objp->volume_units !== null) {
2788
				$unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2789
				$outvalUnits .= ' - '.$unitToShow;
2790
			}
2791
		}
2792
		if ($outdurationvalue && $outdurationunit) {
2793
			$da = array(
2794
				'h' => $langs->trans('Hour'),
2795
				'd' => $langs->trans('Day'),
2796
				'w' => $langs->trans('Week'),
2797
				'm' => $langs->trans('Month'),
2798
				'y' => $langs->trans('Year')
2799
			);
2800
			if (isset($da[$outdurationunit])) {
2801
				$outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2802
			}
2803
		}
2804
2805
		$opt = '<option value="'.$objp->rowid.'"';
2806
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
2807
		if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
2808
			$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.'"';
2809
		}
2810
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
2811
			if (!empty($user->rights->stock->lire)) {
2812
				if ($objp->stock > 0) {
2813
					$opt .= ' class="product_line_stock_ok"';
2814
				} elseif ($objp->stock <= 0) {
2815
					$opt .= ' class="product_line_stock_too_low"';
2816
				}
2817
			}
2818
		}
2819
		if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2820
			$opt .= ' data-labeltrans="'.$outlabel_translated.'"';
2821
			$opt .= ' data-desctrans="'.dol_escape_htmltag($outdesc_translated).'"';
2822
		}
2823
		$opt .= '>';
2824
		$opt .= $objp->ref;
2825
		if (! empty($objp->custref)) {
2826
			$opt.= ' (' . $objp->custref . ')';
2827
		}
2828
		if ($outbarcode) {
2829
			$opt .= ' ('.$outbarcode.')';
2830
		}
2831
		$opt .= ' - '.dol_trunc($label, $maxlengtharticle);
2832
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2833
			$opt .= ' ('.getCountry($outorigin, 1).')';
2834
		}
2835
2836
		$objRef = $objp->ref;
2837
		if (! empty($objp->custref)) {
2838
			$objRef .= ' (' . $objp->custref . ')';
2839
		}
2840
		if (!empty($filterkey) && $filterkey != '') {
2841
			$objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2842
		}
2843
		$outval .= $objRef;
2844
		if ($outbarcode) {
2845
			$outval .= ' ('.$outbarcode.')';
2846
		}
2847
		$outval .= ' - '.dol_trunc($label, $maxlengtharticle);
2848
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) {
2849
			$outval .= ' ('.getCountry($outorigin, 1).')';
2850
		}
2851
2852
		// Units
2853
		$opt .= $outvalUnits;
2854
		$outval .= $outvalUnits;
2855
2856
		$found = 0;
2857
2858
		// Multiprice
2859
		// If we need a particular price level (from 1 to 6)
2860
		if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) {
2861
			$sql = "SELECT price, price_ttc, price_base_type, tva_tx";
2862
			$sql .= " FROM ".MAIN_DB_PREFIX."product_price";
2863
			$sql .= " WHERE fk_product = ".((int) $objp->rowid);
2864
			$sql .= " AND entity IN (".getEntity('productprice').")";
2865
			$sql .= " AND price_level = ".((int) $price_level);
2866
			$sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2867
			$sql .= " LIMIT 1";
2868
2869
			dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
2870
			$result2 = $this->db->query($sql);
2871
			if ($result2) {
2872
				$objp2 = $this->db->fetch_object($result2);
2873
				if ($objp2) {
2874
					$found = 1;
2875
					if ($objp2->price_base_type == 'HT') {
2876
						$opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2877
						$outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2878
					} else {
2879
						$opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2880
						$outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2881
					}
2882
					$outprice_ht = price($objp2->price);
2883
					$outprice_ttc = price($objp2->price_ttc);
2884
					$outpricebasetype = $objp2->price_base_type;
2885
					$outtva_tx = $objp2->tva_tx;
2886
				}
2887
			} else {
2888
				dol_print_error($this->db);
2889
			}
2890
		}
2891
2892
		// Price by quantity
2893
		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))) {
2894
			$found = 1;
2895
			$outqty = $objp->quantity;
2896
			$outdiscount = $objp->remise_percent;
2897
			if ($objp->quantity == 1) {
2898
				$opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
2899
				$outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
2900
				$opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2901
				$outval .= $langs->transnoentities("Unit");
2902
			} else {
2903
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2904
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2905
				$opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2906
				$outval .= $langs->transnoentities("Units");
2907
			}
2908
2909
			$outprice_ht = price($objp->unitprice);
2910
			$outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
2911
			$outpricebasetype = $objp->price_base_type;
2912
			$outtva_tx = $objp->tva_tx;
2913
		}
2914
		if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
2915
			$opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2916
			$outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2917
		}
2918
		if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
2919
			$opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2920
			$outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2921
		}
2922
2923
		// Price by customer
2924
		if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
2925
			if (!empty($objp->idprodcustprice)) {
2926
				$found = 1;
2927
2928
				if ($objp->custprice_base_type == 'HT') {
2929
					$opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2930
					$outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2931
				} else {
2932
					$opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2933
					$outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2934
				}
2935
2936
				$outprice_ht = price($objp->custprice);
2937
				$outprice_ttc = price($objp->custprice_ttc);
2938
				$outpricebasetype = $objp->custprice_base_type;
2939
				$outtva_tx = $objp->custtva_tx;
2940
			}
2941
		}
2942
2943
		// If level no defined or multiprice not found, we used the default price
2944
		if (empty($hidepriceinlabel) && !$found) {
2945
			if ($objp->price_base_type == 'HT') {
2946
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2947
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2948
			} else {
2949
				$opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2950
				$outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2951
			}
2952
			$outprice_ht = price($objp->price);
2953
			$outprice_ttc = price($objp->price_ttc);
2954
			$outpricebasetype = $objp->price_base_type;
2955
			$outtva_tx = $objp->tva_tx;
2956
		}
2957
2958
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
2959
			if (!empty($user->rights->stock->lire)) {
2960
				$opt .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
2961
2962
				if ($objp->stock > 0) {
2963
					$outval .= ' - <span class="product_line_stock_ok">';
2964
				} elseif ($objp->stock <= 0) {
2965
					$outval .= ' - <span class="product_line_stock_too_low">';
2966
				}
2967
				$outval .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS'));
2968
				$outval .= '</span>';
2969
				if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) {  // Warning, this option may slow down combo list generation
2970
					$langs->load("stocks");
2971
2972
					$tmpproduct = new Product($this->db);
2973
					$tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
2974
					$tmpproduct->load_virtual_stock();
2975
					$virtualstock = $tmpproduct->stock_theorique;
2976
2977
					$opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
2978
2979
					$outval .= ' - '.$langs->transnoentities("VirtualStock").':';
2980
					if ($virtualstock > 0) {
2981
						$outval .= '<span class="product_line_stock_ok">';
2982
					} elseif ($virtualstock <= 0) {
2983
						$outval .= '<span class="product_line_stock_too_low">';
2984
					}
2985
					$outval .= $virtualstock;
2986
					$outval .= '</span>';
2987
2988
					unset($tmpproduct);
2989
				}
2990
			}
2991
		}
2992
2993
		$opt .= "</option>\n";
2994
		$optJson = array(
2995
			'key'=>$outkey,
2996
			'value'=>$outref,
2997
			'label'=>$outval,
2998
			'label2'=>$outlabel,
2999
			'desc'=>$outdesc,
3000
			'type'=>$outtype,
3001
			'price_ht'=>price2num($outprice_ht),
3002
			'price_ttc'=>price2num($outprice_ttc),
3003
			'pricebasetype'=>$outpricebasetype,
3004
			'tva_tx'=>$outtva_tx, 'qty'=>$outqty,
3005
			'discount'=>$outdiscount,
3006
			'duration_value'=>$outdurationvalue,
3007
			'duration_unit'=>$outdurationunit,
3008
			'pbq'=>$outpbq,
3009
			'labeltrans'=>$outlabel_translated,
3010
			'desctrans'=>$outdesc_translated,
3011
			'ref_customer'=>$outrefcust
3012
		);
3013
	}
3014
3015
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3016
	/**
3017
	 *	Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list)
3018
	 *
3019
	 *	@param	int		$socid			Id third party
3020
	 *	@param  string	$selected       Preselected product
3021
	 *	@param  string	$htmlname       Name of HTML Select
3022
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
3023
	 *	@param  string	$filtre			For a SQL filter
3024
	 *	@param	array	$ajaxoptions	Options for ajax_autocompleter
3025
	 *  @param	int		$hidelabel		Hide label (0=no, 1=yes)
3026
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
3027
	 *  @param	string	$morecss		More CSS
3028
	 *  @param	string	$placeholder	Placeholder
3029
	 *	@return	void
3030
	 */
3031
	public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3032
	{
3033
		// phpcs:enable
3034
		global $langs, $conf;
3035
		global $price_level, $status, $finished;
3036
3037
		if (!isset($status)) {
3038
			$status = 1;
3039
		}
3040
3041
		$selected_input_value = '';
3042
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) {
3043
			if ($selected > 0) {
3044
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
3045
				$producttmpselect = new Product($this->db);
3046
				$producttmpselect->fetch($selected);
3047
				$selected_input_value = $producttmpselect->ref;
3048
				unset($producttmpselect);
3049
			}
3050
3051
			// mode=2 means suppliers products
3052
			$urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
3053
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
3054
			print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" class="minwidth300" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.$placeholder.'"' : '').'>';
3055
		} else {
3056
			print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3057
		}
3058
	}
3059
3060
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3061
	/**
3062
	 *	Return list of suppliers products
3063
	 *
3064
	 *	@param	int		$socid   			Id of supplier thirdparty (0 = no filter)
3065
	 *	@param  int		$selected       	Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD')
3066
	 *	@param  string	$htmlname       	Name of HTML select
3067
	 *  @param	string	$filtertype     	Filter on product type (''=nofilter, 0=product, 1=service)
3068
	 *	@param  string	$filtre         	Generic filter. Data must not come from user input.
3069
	 *	@param  string	$filterkey      	Filter of produdts
3070
	 *  @param  int		$statut         	-1=Return all products, 0=Products not on buy, 1=Products on buy
3071
	 *  @param  int		$outputmode     	0=HTML select string, 1=Array
3072
	 *  @param  int     $limit          	Limit of line number
3073
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
3074
	 *  @param	string	$morecss			Add more CSS
3075
	 *  @param	int		$showstockinlist	Show stock information (slower).
3076
	 *  @param	string	$placeholder		Placeholder
3077
	 *  @return array           			Array of keys for json
3078
	 */
3079
	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 = '')
3080
	{
3081
		// phpcs:enable
3082
		global $langs, $conf, $db, $user;
3083
3084
		$out = '';
3085
		$outarray = array();
3086
3087
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3088
3089
		$langs->load('stocks');
3090
		// Units
3091
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3092
			$langs->load('other');
3093
		}
3094
3095
		$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock,";
3096
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
3097
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,";
3098
		$sql .= " pfp.supplier_reputation";
3099
		// if we use supplier description of the products
3100
		if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3101
			$sql .= " ,pfp.desc_fourn as description";
3102
		} else {
3103
			$sql .= " ,p.description";
3104
		}
3105
		// Units
3106
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3107
			$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";
3108
		}
3109
		if (!empty($conf->barcode->enabled)) {
3110
			$sql .= ", pfp.barcode";
3111
		}
3112
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
3113
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )";
3114
		if ($socid > 0) {
3115
			$sql .= " AND pfp.fk_soc = ".((int) $socid);
3116
		}
3117
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
3118
		// Units
3119
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3120
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
3121
		}
3122
		$sql .= " WHERE p.entity IN (".getEntity('product').")";
3123
		if ($statut != -1) {
3124
			$sql .= " AND p.tobuy = ".((int) $statut);
3125
		}
3126
		if (strval($filtertype) != '') {
3127
			$sql .= " AND p.fk_product_type = ".((int) $filtertype);
3128
		}
3129
		if (!empty($filtre)) {
3130
			$sql .= " ".$filtre;
3131
		}
3132
		// Add criteria on ref/label
3133
		if ($filterkey != '') {
3134
			$sql .= ' AND (';
3135
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3136
			// For natural search
3137
			$scrit = explode(' ', $filterkey);
3138
			$i = 0;
3139
			if (count($scrit) > 1) {
3140
				$sql .= "(";
3141
			}
3142
			foreach ($scrit as $crit) {
3143
				if ($i > 0) {
3144
					$sql .= " AND ";
3145
				}
3146
				$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)."%'";
3147
				if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) {
3148
					$sql .= " OR pfp.desc_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
3149
				}
3150
				$sql .= ")";
3151
				$i++;
3152
			}
3153
			if (count($scrit) > 1) {
3154
				$sql .= ")";
3155
			}
3156
			if (!empty($conf->barcode->enabled)) {
3157
				$sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3158
				$sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
3159
			}
3160
			$sql .= ')';
3161
		}
3162
		$sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3163
		$sql .= $this->db->plimit($limit, 0);
3164
3165
		// Build output string
3166
3167
		dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
3168
		$result = $this->db->query($sql);
3169
		if ($result) {
3170
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3171
			require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
3172
3173
			$num = $this->db->num_rows($result);
3174
3175
			//$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">';	// remove select to have id same with combo and ajax
3176
			$out .= '<select class="flat '.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
3177
			if (!$selected) {
3178
				$out .= '<option value="-1" selected>'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3179
			} else {
3180
				$out .= '<option value="-1">'.($placeholder ? $placeholder : '&nbsp;').'</option>';
3181
			}
3182
3183
			$i = 0;
3184
			while ($i < $num) {
3185
				$objp = $this->db->fetch_object($result);
3186
3187
				$outkey = $objp->idprodfournprice; // id in table of price
3188
				if (!$outkey && $alsoproductwithnosupplierprice) {
3189
					$outkey = 'idprod_'.$objp->rowid; // id of product
3190
				}
3191
3192
				$outref = $objp->ref;
3193
				$outval = '';
3194
				$outbarcode = $objp->barcode;
3195
				$outqty = 1;
3196
				$outdiscount = 0;
3197
				$outtype = $objp->fk_product_type;
3198
				$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3199
				$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
3200
3201
				// Units
3202
				$outvalUnits = '';
3203
				if (!empty($conf->global->PRODUCT_USE_UNITS)) {
3204
					if (!empty($objp->unit_short)) {
3205
						$outvalUnits .= ' - '.$objp->unit_short;
3206
					}
3207
					if (!empty($objp->weight) && $objp->weight_units !== null) {
3208
						$unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3209
						$outvalUnits .= ' - '.$unitToShow;
3210
					}
3211
					if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3212
						$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
3213
						$outvalUnits .= ' - '.$unitToShow;
3214
					}
3215
					if (!empty($objp->surface) && $objp->surface_units !== null) {
3216
						$unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3217
						$outvalUnits .= ' - '.$unitToShow;
3218
					}
3219
					if (!empty($objp->volume) && $objp->volume_units !== null) {
3220
						$unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3221
						$outvalUnits .= ' - '.$unitToShow;
3222
					}
3223
					if ($outdurationvalue && $outdurationunit) {
3224
						$da = array(
3225
							'h' => $langs->trans('Hour'),
3226
							'd' => $langs->trans('Day'),
3227
							'w' => $langs->trans('Week'),
3228
							'm' => $langs->trans('Month'),
3229
							'y' => $langs->trans('Year')
3230
						);
3231
						if (isset($da[$outdurationunit])) {
3232
							$outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
3233
						}
3234
					}
3235
				}
3236
3237
				$objRef = $objp->ref;
3238
				if ($filterkey && $filterkey != '') {
3239
					$objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
3240
				}
3241
				$objRefFourn = $objp->ref_fourn;
3242
				if ($filterkey && $filterkey != '') {
3243
					$objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1);
3244
				}
3245
				$label = $objp->label;
3246
				if ($filterkey && $filterkey != '') {
3247
					$label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
3248
				}
3249
3250
				$optlabel = $objp->ref;
3251
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3252
					$optlabel .= ' <span class=\'opacitymedium\'>('.$objp->ref_fourn.')</span>';
3253
				}
3254
				if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
3255
					$optlabel .= ' ('.$outbarcode.')';
3256
				}
3257
				$optlabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3258
3259
				$outvallabel = $objRef;
3260
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3261
					$outvallabel .= ' ('.$objRefFourn.')';
3262
				}
3263
				if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
3264
					$outvallabel .= ' ('.$outbarcode.')';
3265
				}
3266
				$outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle);
3267
3268
				// Units
3269
				$optlabel .= $outvalUnits;
3270
				$outvallabel .= $outvalUnits;
3271
3272
				if (!empty($objp->idprodfournprice)) {
3273
					$outqty = $objp->quantity;
3274
					$outdiscount = $objp->remise_percent;
3275
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3276
						$prod_supplier = new ProductFournisseur($this->db);
3277
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3278
						$prod_supplier->id = $objp->fk_product;
3279
						$prod_supplier->fourn_qty = $objp->quantity;
3280
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
3281
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3282
						$priceparser = new PriceParser($this->db);
3283
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
3284
						if ($price_result >= 0) {
3285
							$objp->fprice = $price_result;
3286
							if ($objp->quantity >= 1) {
3287
								$objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3288
							}
3289
						}
3290
					}
3291
					if ($objp->quantity == 1) {
3292
						$optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3293
						$outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
3294
						$optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3295
						$outvallabel .= $langs->transnoentities("Unit");
3296
					} else {
3297
						$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;
3298
						$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;
3299
						$optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3300
						$outvallabel .= ' '.$langs->transnoentities("Units");
3301
					}
3302
3303
					if ($objp->quantity > 1) {
3304
						$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
3305
						$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
3306
					}
3307
					if ($objp->remise_percent >= 1) {
3308
						$optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
3309
						$outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
3310
					}
3311
					if ($objp->duration) {
3312
						$optlabel .= " - ".$objp->duration;
3313
						$outvallabel .= " - ".$objp->duration;
3314
					}
3315
					if (!$socid) {
3316
						$optlabel .= " - ".dol_trunc($objp->name, 8);
3317
						$outvallabel .= " - ".dol_trunc($objp->name, 8);
3318
					}
3319
					if ($objp->supplier_reputation) {
3320
						//TODO dictionary
3321
						$reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
3322
3323
						$optlabel .= " - ".$reputations[$objp->supplier_reputation];
3324
						$outvallabel .= " - ".$reputations[$objp->supplier_reputation];
3325
					}
3326
				} else {
3327
					if (empty($alsoproductwithnosupplierprice)) {     // No supplier price defined for couple product/supplier
3328
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3329
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3330
					} else // No supplier price defined for product, even on other suppliers
3331
					{
3332
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
3333
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
3334
					}
3335
				}
3336
3337
				if (!empty($conf->stock->enabled) && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) {
3338
					$novirtualstock = ($showstockinlist == 2);
3339
3340
					if (!empty($user->rights->stock->lire)) {
3341
						$outvallabel .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS'));
3342
3343
						if ($objp->stock > 0) {
3344
							$optlabel .= ' - <span class="product_line_stock_ok">';
3345
						} elseif ($objp->stock <= 0) {
3346
							$optlabel .= ' - <span class="product_line_stock_too_low">';
3347
						}
3348
						$optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS'));
3349
						$optlabel .= '</span>';
3350
						if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) {  // Warning, this option may slow down combo list generation
3351
							$langs->load("stocks");
3352
3353
							$tmpproduct = new Product($this->db);
3354
							$tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3355
							$tmpproduct->load_virtual_stock();
3356
							$virtualstock = $tmpproduct->stock_theorique;
3357
3358
							$outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
3359
3360
							$optlabel .= ' - '.$langs->transnoentities("VirtualStock").':';
3361
							if ($virtualstock > 0) {
3362
								$optlabel .= '<span class="product_line_stock_ok">';
3363
							} elseif ($virtualstock <= 0) {
3364
								$optlabel .= '<span class="product_line_stock_too_low">';
3365
							}
3366
							$optlabel .= $virtualstock;
3367
							$optlabel .= '</span>';
3368
3369
							unset($tmpproduct);
3370
						}
3371
					}
3372
				}
3373
3374
				$opt = '<option value="'.$outkey.'"';
3375
				if ($selected && $selected == $objp->idprodfournprice) {
3376
					$opt .= ' selected';
3377
				}
3378
				if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3379
					$opt .= ' disabled';
3380
				}
3381
				if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3382
					$opt .= ' data-qty="'.$objp->quantity.'" data-up="'.$objp->unitprice.'" data-discount="'.$outdiscount.'"';
3383
				}
3384
				$opt .= ' data-description="'.dol_escape_htmltag($objp->description).'"';
3385
				$opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"';
3386
				$opt .= '>';
3387
3388
				$opt .= $optlabel;
3389
				$outval .= $outvallabel;
3390
3391
				$opt .= "</option>\n";
3392
3393
3394
				// Add new entry
3395
				// "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
3396
				// "label" value of json key array is used by jQuery automatically as text for combo box
3397
				$out .= $opt;
3398
				array_push(
3399
					$outarray,
3400
					array('key'=>$outkey,
3401
						'value'=>$outref,
3402
						'label'=>$outval,
3403
						'qty'=>$outqty,
3404
						'price_ht'=>price2num($objp->unitprice, 'MT'),
3405
						'discount'=>$outdiscount,
3406
						'type'=>$outtype,
3407
						'duration_value'=>$outdurationvalue,
3408
						'duration_unit'=>$outdurationunit,
3409
						'disabled'=>(empty($objp->idprodfournprice) ? true : false),
3410
						'description'=>$objp->description
3411
					)
3412
				);
3413
				// Exemple of var_dump $outarray
3414
				// array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
3415
				//           ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
3416
				//      	 ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
3417
				//}
3418
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3419
				//$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
3420
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
3421
3422
				$i++;
3423
			}
3424
			$out .= '</select>';
3425
3426
			$this->db->free($result);
3427
3428
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
3429
			$out .= ajax_combobox($htmlname);
3430
3431
			if (empty($outputmode)) {
3432
				return $out;
3433
			}
3434
			return $outarray;
3435
		} else {
3436
			dol_print_error($this->db);
3437
		}
3438
	}
3439
3440
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3441
	/**
3442
	 *	Return list of suppliers prices for a product
3443
	 *
3444
	 *  @param	    int		$productid       	Id of product
3445
	 *  @param      string	$htmlname        	Name of HTML field
3446
	 *  @param      int		$selected_supplier  Pre-selected supplier if more than 1 result
3447
	 *  @return	    string
3448
	 */
3449
	public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
3450
	{
3451
		// phpcs:enable
3452
		global $langs, $conf;
3453
3454
		$langs->load('stocks');
3455
3456
		$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3457
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3458
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3459
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
3460
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3461
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
3462
		$sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3463
		$sql .= " AND p.tobuy = 1";
3464
		$sql .= " AND s.fournisseur = 1";
3465
		$sql .= " AND p.rowid = ".$productid;
3466
		$sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3467
3468
		dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3469
		$result = $this->db->query($sql);
3470
3471
		if ($result) {
3472
			$num = $this->db->num_rows($result);
3473
3474
			$form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3475
3476
			if (!$num) {
3477
				$form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3478
			} else {
3479
				require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3480
				$form .= '<option value="0">&nbsp;</option>';
3481
3482
				$i = 0;
3483
				while ($i < $num) {
3484
					$objp = $this->db->fetch_object($result);
3485
3486
					$opt = '<option value="'.$objp->idprodfournprice.'"';
3487
					//if there is only one supplier, preselect it
3488
					if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
3489
						$opt .= ' selected';
3490
					}
3491
					$opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3492
3493
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3494
						$prod_supplier = new ProductFournisseur($this->db);
3495
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3496
						$prod_supplier->id = $productid;
3497
						$prod_supplier->fourn_qty = $objp->quantity;
3498
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
3499
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3500
						$priceparser = new PriceParser($this->db);
3501
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
3502
						if ($price_result >= 0) {
3503
							$objp->fprice = $price_result;
3504
							if ($objp->quantity >= 1) {
3505
								$objp->unitprice = $objp->fprice / $objp->quantity;
3506
							}
3507
						}
3508
					}
3509
					if ($objp->quantity == 1) {
3510
						$opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3511
					}
3512
3513
					$opt .= $objp->quantity.' ';
3514
3515
					if ($objp->quantity == 1) {
3516
						$opt .= $langs->trans("Unit");
3517
					} else {
3518
						$opt .= $langs->trans("Units");
3519
					}
3520
					if ($objp->quantity > 1) {
3521
						$opt .= " - ";
3522
						$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");
3523
					}
3524
					if ($objp->duration) {
3525
						$opt .= " - ".$objp->duration;
3526
					}
3527
					$opt .= "</option>\n";
3528
3529
					$form .= $opt;
3530
					$i++;
3531
				}
3532
			}
3533
3534
			$form .= '</select>';
3535
			$this->db->free($result);
3536
			return $form;
3537
		} else {
3538
			dol_print_error($this->db);
3539
		}
3540
	}
3541
3542
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3543
	/**
3544
	 *    Return list of delivery address
3545
	 *
3546
	 *    @param    string	$selected          	Id contact pre-selectionn
3547
	 *    @param    int		$socid				Id of company
3548
	 *    @param    string	$htmlname          	Name of HTML field
3549
	 *    @param    int		$showempty         	Add an empty field
3550
	 *    @return	integer|null
3551
	 */
3552
	public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3553
	{
3554
		// phpcs:enable
3555
		// looking for users
3556
		$sql = "SELECT a.rowid, a.label";
3557
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_address as a";
3558
		$sql .= " WHERE a.fk_soc = ".((int) $socid);
3559
		$sql .= " ORDER BY a.label ASC";
3560
3561
		dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3562
		$resql = $this->db->query($sql);
3563
		if ($resql) {
3564
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3565
			if ($showempty) {
3566
				print '<option value="0">&nbsp;</option>';
3567
			}
3568
			$num = $this->db->num_rows($resql);
3569
			$i = 0;
3570
			if ($num) {
3571
				while ($i < $num) {
3572
					$obj = $this->db->fetch_object($resql);
3573
3574
					if ($selected && $selected == $obj->rowid) {
3575
						print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3576
					} else {
3577
						print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3578
					}
3579
					$i++;
3580
				}
3581
			}
3582
			print '</select>';
3583
			return $num;
3584
		} else {
3585
			dol_print_error($this->db);
3586
		}
3587
	}
3588
3589
3590
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3591
	/**
3592
	 *      Load into cache list of payment terms
3593
	 *
3594
	 *      @return     int             Nb of lines loaded, <0 if KO
3595
	 */
3596
	public function load_cache_conditions_paiements()
3597
	{
3598
		// phpcs:enable
3599
		global $langs;
3600
3601
		$num = count($this->cache_conditions_paiements);
3602
		if ($num > 0) {
3603
			return 0; // Cache already loaded
3604
		}
3605
3606
		dol_syslog(__METHOD__, LOG_DEBUG);
3607
3608
		$sql = "SELECT rowid, code, libelle as label";
3609
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_payment_term';
3610
		$sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3611
		$sql .= " AND active > 0";
3612
		$sql .= " ORDER BY sortorder";
3613
3614
		$resql = $this->db->query($sql);
3615
		if ($resql) {
3616
			$num = $this->db->num_rows($resql);
3617
			$i = 0;
3618
			while ($i < $num) {
3619
				$obj = $this->db->fetch_object($resql);
3620
3621
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3622
				$label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3623
				$this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3624
				$this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3625
				$i++;
3626
			}
3627
3628
			//$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1);		// We use the field sortorder of table
3629
3630
			return $num;
3631
		} else {
3632
			dol_print_error($this->db);
3633
			return -1;
3634
		}
3635
	}
3636
3637
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3638
	/**
3639
	 *      Charge dans cache la liste des délais de livraison possibles
3640
	 *
3641
	 *      @return     int             Nb of lines loaded, <0 if KO
3642
	 */
3643
	public function load_cache_availability()
3644
	{
3645
		// phpcs:enable
3646
		global $langs;
3647
3648
		$num = count($this->cache_availability);
3649
		if ($num > 0) {
3650
			return 0; // Cache already loaded
3651
		}
3652
3653
		dol_syslog(__METHOD__, LOG_DEBUG);
3654
3655
		$langs->load('propal');
3656
3657
		$sql = "SELECT rowid, code, label, position";
3658
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_availability';
3659
		$sql .= " WHERE active > 0";
3660
3661
		$resql = $this->db->query($sql);
3662
		if ($resql) {
3663
			$num = $this->db->num_rows($resql);
3664
			$i = 0;
3665
			while ($i < $num) {
3666
				$obj = $this->db->fetch_object($resql);
3667
3668
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3669
				$label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3670
				$this->cache_availability[$obj->rowid]['code'] = $obj->code;
3671
				$this->cache_availability[$obj->rowid]['label'] = $label;
3672
				$this->cache_availability[$obj->rowid]['position'] = $obj->position;
3673
				$i++;
3674
			}
3675
3676
			$this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
3677
3678
			return $num;
3679
		} else {
3680
			dol_print_error($this->db);
3681
			return -1;
3682
		}
3683
	}
3684
3685
	/**
3686
	 *      Retourne la liste des types de delais de livraison possibles
3687
	 *
3688
	 *      @param	int		$selected       Id du type de delais pre-selectionne
3689
	 *      @param  string	$htmlname       Nom de la zone select
3690
	 *      @param  string	$filtertype     To add a filter
3691
	 *		@param	int		$addempty		Add empty entry
3692
	 * 		@param	string	$morecss		More CSS
3693
	 *		@return	void
3694
	 */
3695
	public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
3696
	{
3697
		global $langs, $user;
3698
3699
		$this->load_cache_availability();
3700
3701
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3702
3703
		print '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3704
		if ($addempty) {
3705
			print '<option value="0">&nbsp;</option>';
3706
		}
3707
		foreach ($this->cache_availability as $id => $arrayavailability) {
3708
			if ($selected == $id) {
3709
				print '<option value="'.$id.'" selected>';
3710
			} else {
3711
				print '<option value="'.$id.'">';
3712
			}
3713
			print dol_escape_htmltag($arrayavailability['label']);
3714
			print '</option>';
3715
		}
3716
		print '</select>';
3717
		if ($user->admin) {
3718
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3719
		}
3720
		print ajax_combobox($htmlname);
3721
	}
3722
3723
	/**
3724
	 *      Load into cache cache_demand_reason, array of input reasons
3725
	 *
3726
	 *      @return     int             Nb of lines loaded, <0 if KO
3727
	 */
3728
	public function loadCacheInputReason()
3729
	{
3730
		global $langs;
3731
3732
		$num = count($this->cache_demand_reason);
3733
		if ($num > 0) {
3734
			return 0; // Cache already loaded
3735
		}
3736
3737
		$sql = "SELECT rowid, code, label";
3738
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_input_reason';
3739
		$sql .= " WHERE active > 0";
3740
3741
		$resql = $this->db->query($sql);
3742
		if ($resql) {
3743
			$num = $this->db->num_rows($resql);
3744
			$i = 0;
3745
			$tmparray = array();
3746
			while ($i < $num) {
3747
				$obj = $this->db->fetch_object($resql);
3748
3749
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3750
				$label = ($obj->label != '-' ? $obj->label : '');
3751
				if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) {
3752
					$label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3753
				}
3754
				if ($langs->trans($obj->code) != $obj->code) {
3755
					$label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3756
				}
3757
3758
				$tmparray[$obj->rowid]['id']   = $obj->rowid;
3759
				$tmparray[$obj->rowid]['code'] = $obj->code;
3760
				$tmparray[$obj->rowid]['label'] = $label;
3761
				$i++;
3762
			}
3763
3764
			$this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3765
3766
			unset($tmparray);
3767
			return $num;
3768
		} else {
3769
			dol_print_error($this->db);
3770
			return -1;
3771
		}
3772
	}
3773
3774
	/**
3775
	 *	Return list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
3776
	 *  List found into table c_input_reason loaded by loadCacheInputReason
3777
	 *
3778
	 *  @param	int		$selected        Id or code of type origin to select by default
3779
	 *  @param  string	$htmlname        Nom de la zone select
3780
	 *  @param  string	$exclude         To exclude a code value (Example: SRC_PROP)
3781
	 *	@param	int		$addempty		 Add an empty entry
3782
	 *  @param  string	$morecss		 Add more css to the HTML select component
3783
	 *  @param	int		$notooltip		 Do not show the tooltip for admin
3784
	 *	@return	void
3785
	 */
3786
	public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
3787
	{
3788
		global $langs, $user;
3789
3790
		$this->loadCacheInputReason();
3791
3792
		print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3793
		if ($addempty) {
3794
			print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
3795
		}
3796
		foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
3797
			if ($arraydemandreason['code'] == $exclude) {
3798
				continue;
3799
			}
3800
3801
			if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
3802
				print '<option value="'.$arraydemandreason['id'].'" selected>';
3803
			} else {
3804
				print '<option value="'.$arraydemandreason['id'].'">';
3805
			}
3806
			$label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3807
			print $langs->trans($label);
3808
			print '</option>';
3809
		}
3810
		print '</select>';
3811
		if ($user->admin && empty($notooltip)) {
3812
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3813
		}
3814
		print ajax_combobox('select_'.$htmlname);
3815
	}
3816
3817
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3818
	/**
3819
	 *      Charge dans cache la liste des types de paiements possibles
3820
	 *
3821
	 *      @return     int                 Nb of lines loaded, <0 if KO
3822
	 */
3823
	public function load_cache_types_paiements()
3824
	{
3825
		// phpcs:enable
3826
		global $langs;
3827
3828
		$num = count($this->cache_types_paiements);
3829
		if ($num > 0) {
3830
			return $num; // Cache already loaded
3831
		}
3832
3833
		dol_syslog(__METHOD__, LOG_DEBUG);
3834
3835
		$this->cache_types_paiements = array();
3836
3837
		$sql = "SELECT id, code, libelle as label, type, active";
3838
		$sql .= " FROM ".MAIN_DB_PREFIX."c_paiement";
3839
		$sql .= " WHERE entity IN (".getEntity('c_paiement').")";
3840
3841
		$resql = $this->db->query($sql);
3842
		if ($resql) {
3843
			$num = $this->db->num_rows($resql);
3844
			$i = 0;
3845
			while ($i < $num) {
3846
				$obj = $this->db->fetch_object($resql);
3847
3848
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3849
				$label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3850
				$this->cache_types_paiements[$obj->id]['id'] = $obj->id;
3851
				$this->cache_types_paiements[$obj->id]['code'] = $obj->code;
3852
				$this->cache_types_paiements[$obj->id]['label'] = $label;
3853
				$this->cache_types_paiements[$obj->id]['type'] = $obj->type;
3854
				$this->cache_types_paiements[$obj->id]['active'] = $obj->active;
3855
				$i++;
3856
			}
3857
3858
			$this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3859
3860
			return $num;
3861
		} else {
3862
			dol_print_error($this->db);
3863
			return -1;
3864
		}
3865
	}
3866
3867
3868
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3869
	/**
3870
	 *      Return list of payment modes.
3871
	 *      Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
3872
	 *      See instead to force the default value by the caller.
3873
	 *
3874
	 *      @param	int		$selected		Id of payment term to preselect by default
3875
	 *      @param	string	$htmlname		Nom de la zone select
3876
	 *      @param	int		$filtertype		Not used
3877
	 *		@param	int		$addempty		Add an empty entry
3878
	 * 		@param	int		$noinfoadmin		0=Add admin info, 1=Disable admin info
3879
	 * 		@param	string	$morecss			Add more CSS on select tag
3880
	 *		@return	void
3881
	 */
3882
	public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
3883
	{
3884
		// phpcs:enable
3885
		global $langs, $user, $conf;
3886
3887
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3888
3889
		$this->load_cache_conditions_paiements();
3890
3891
		// Set default value if not already set by caller
3892
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) {
3893
			$selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
3894
		}
3895
3896
		print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3897
		if ($addempty) {
3898
			print '<option value="0">&nbsp;</option>';
3899
		}
3900
		foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
3901
			if ($selected == $id) {
3902
				print '<option value="'.$id.'" selected>';
3903
			} else {
3904
				print '<option value="'.$id.'">';
3905
			}
3906
			print $arrayconditions['label'];
3907
			print '</option>';
3908
		}
3909
		print '</select>';
3910
		if ($user->admin && empty($noinfoadmin)) {
3911
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3912
		}
3913
		print ajax_combobox($htmlname);
3914
	}
3915
3916
3917
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3918
	/**
3919
	 *      Return list of payment methods
3920
	 *      Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value but scope is all application, probably not what you want.
3921
	 *
3922
	 *      @param	string	$selected       Id or code or preselected payment mode
3923
	 *      @param  string	$htmlname       Name of select field
3924
	 *      @param  string	$filtertype     To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz))
3925
	 *      @param  int		$format         0=id+label, 1=code+code, 2=code+label, 3=id+code
3926
	 *      @param  int		$empty			1=can be empty, 0 otherwise
3927
	 * 		@param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
3928
	 *      @param  int		$maxlength      Max length of label
3929
	 *      @param  int     $active         Active or not, -1 = all
3930
	 *      @param  string  $morecss        Add more CSS on select tag
3931
	 * 		@return	void
3932
	 */
3933
	public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
3934
	{
3935
		// phpcs:enable
3936
		global $langs, $user, $conf;
3937
3938
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
3939
3940
		$filterarray = array();
3941
		if ($filtertype == 'CRDT') {
3942
			$filterarray = array(0, 2, 3);
3943
		} elseif ($filtertype == 'DBIT') {
3944
			$filterarray = array(1, 2, 3);
3945
		} elseif ($filtertype != '' && $filtertype != '-1') {
3946
			$filterarray = explode(',', $filtertype);
3947
		}
3948
3949
		$this->load_cache_types_paiements();
3950
3951
		// Set default value if not already set by caller
3952
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) {
3953
			$selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
3954
		}
3955
3956
		print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3957
		if ($empty) {
3958
			print '<option value="">&nbsp;</option>';
3959
		}
3960
		foreach ($this->cache_types_paiements as $id => $arraytypes) {
3961
			// If not good status
3962
			if ($active >= 0 && $arraytypes['active'] != $active) {
3963
				continue;
3964
			}
3965
3966
			// On passe si on a demande de filtrer sur des modes de paiments particuliers
3967
			if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
3968
				continue;
3969
			}
3970
3971
			// We discard empty line if showempty is on because an empty line has already been output.
3972
			if ($empty && empty($arraytypes['code'])) {
3973
				continue;
3974
			}
3975
3976
			if ($format == 0) {
3977
				print '<option value="'.$id.'"';
3978
			} elseif ($format == 1) {
3979
				print '<option value="'.$arraytypes['code'].'"';
3980
			} elseif ($format == 2) {
3981
				print '<option value="'.$arraytypes['code'].'"';
3982
			} elseif ($format == 3) {
3983
				print '<option value="'.$id.'"';
3984
			}
3985
			// Print attribute selected or not
3986
			if ($format == 1 || $format == 2) {
3987
				if ($selected == $arraytypes['code']) {
3988
					print ' selected';
3989
				}
3990
			} else {
3991
				if ($selected == $id) {
3992
					print ' selected';
3993
				}
3994
			}
3995
			print '>';
3996
			if ($format == 0) {
3997
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3998
			} elseif ($format == 1) {
3999
				$value = $arraytypes['code'];
4000
			} elseif ($format == 2) {
4001
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4002
			} elseif ($format == 3) {
4003
				$value = $arraytypes['code'];
4004
			}
4005
			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...
4006
			print '</option>';
4007
		}
4008
		print '</select>';
4009
		if ($user->admin && !$noadmininfo) {
4010
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4011
		}
4012
		print ajax_combobox('select'.$htmlname);
4013
	}
4014
4015
4016
	/**
4017
	 *  Selection HT or TTC
4018
	 *
4019
	 *  @param	string	$selected       Id pre-selectionne
4020
	 *  @param  string	$htmlname       Nom de la zone select
4021
	 *  @param	string	$addjscombo		Add js combo
4022
	 * 	@return	string					Code of HTML select to chose tax or not
4023
	 */
4024
	public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4025
	{
4026
		global $langs;
4027
4028
		$return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">';
4029
		$options = array(
4030
			'HT'=>$langs->trans("HT"),
4031
			'TTC'=>$langs->trans("TTC")
4032
		);
4033
		foreach ($options as $id => $value) {
4034
			if ($selected == $id) {
4035
				$return .= '<option value="'.$id.'" selected>'.$value;
4036
			} else {
4037
				$return .= '<option value="'.$id.'">'.$value;
4038
			}
4039
			$return .= '</option>';
4040
		}
4041
		$return .= '</select>';
4042
		if ($addjscombo) {
4043
			$return .= ajax_combobox('select_'.$htmlname);
4044
		}
4045
4046
		return $return;
4047
	}
4048
4049
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4050
	/**
4051
	 *      Load in cache list of transport mode
4052
	 *
4053
	 *      @return     int                 Nb of lines loaded, <0 if KO
4054
	 */
4055
	public function load_cache_transport_mode()
4056
	{
4057
		// phpcs:enable
4058
		global $langs;
4059
4060
		$num = count($this->cache_transport_mode);
4061
		if ($num > 0) {
4062
			return $num; // Cache already loaded
4063
		}
4064
4065
		dol_syslog(__METHOD__, LOG_DEBUG);
4066
4067
		$this->cache_transport_mode = array();
4068
4069
		$sql = "SELECT rowid, code, label, active";
4070
		$sql .= " FROM ".MAIN_DB_PREFIX."c_transport_mode";
4071
		$sql .= " WHERE entity IN (".getEntity('c_transport_mode').")";
4072
4073
		$resql = $this->db->query($sql);
4074
		if ($resql) {
4075
			$num = $this->db->num_rows($resql);
4076
			$i = 0;
4077
			while ($i < $num) {
4078
				$obj = $this->db->fetch_object($resql);
4079
4080
				// If traduction exist, we use it else we take the default label
4081
				$label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
4082
				$this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4083
				$this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4084
				$this->cache_transport_mode[$obj->rowid]['label'] = $label;
4085
				$this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4086
				$i++;
4087
			}
4088
4089
			$this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4090
4091
			return $num;
4092
		} else {
4093
			dol_print_error($this->db);
4094
			return -1;
4095
		}
4096
	}
4097
4098
	/**
4099
	 *      Return list of transport mode for intracomm report
4100
	 *
4101
	 *      @param	string	$selected       Id of the transport mode pre-selected
4102
	 *      @param  string	$htmlname       Name of the select field
4103
	 *      @param  int		$format         0=id+label, 1=code+code, 2=code+label, 3=id+code
4104
	 *      @param  int		$empty			1=can be empty, 0 else
4105
	 *      @param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
4106
	 *      @param  int		$maxlength      Max length of label
4107
	 *      @param  int     $active         Active or not, -1 = all
4108
	 *      @param  string  $morecss        Add more CSS on select tag
4109
	 * 		@return	void
4110
	 */
4111
	public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4112
	{
4113
		global $langs, $user;
4114
4115
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
4116
4117
		$this->load_cache_transport_mode();
4118
4119
		print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
4120
		if ($empty) {
4121
			print '<option value="">&nbsp;</option>';
4122
		}
4123
		foreach ($this->cache_transport_mode as $id => $arraytypes) {
4124
			// If not good status
4125
			if ($active >= 0 && $arraytypes['active'] != $active) {
4126
				continue;
4127
			}
4128
4129
			// We discard empty line if showempty is on because an empty line has already been output.
4130
			if ($empty && empty($arraytypes['code'])) {
4131
				continue;
4132
			}
4133
4134
			if ($format == 0) {
4135
				print '<option value="'.$id.'"';
4136
			} elseif ($format == 1) {
4137
				print '<option value="'.$arraytypes['code'].'"';
4138
			} elseif ($format == 2) {
4139
				print '<option value="'.$arraytypes['code'].'"';
4140
			} elseif ($format == 3) {
4141
				print '<option value="'.$id.'"';
4142
			}
4143
			// If text is selected, we compare with code, else with id
4144
			if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4145
				print ' selected';
4146
			} elseif ($selected == $id) {
4147
				print ' selected';
4148
			}
4149
			print '>';
4150
			if ($format == 0) {
4151
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4152
			} elseif ($format == 1) {
4153
				$value = $arraytypes['code'];
4154
			} elseif ($format == 2) {
4155
				$value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4156
			} elseif ($format == 3) {
4157
				$value = $arraytypes['code'];
4158
			}
4159
			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...
4160
			print '</option>';
4161
		}
4162
		print '</select>';
4163
		if ($user->admin && !$noadmininfo) {
4164
			print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4165
		}
4166
	}
4167
4168
	/**
4169
	 *  Return a HTML select list of shipping mode
4170
	 *
4171
	 *  @param	string	$selected           Id shipping mode pre-selected
4172
	 *  @param  string	$htmlname           Name of select zone
4173
	 *  @param  string	$filtre             To filter list. This parameter must not come from input of users
4174
	 *  @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.
4175
	 *  @param  string	$moreattrib         To add more attribute on select
4176
	 *	@param	int		$noinfoadmin		0=Add admin info, 1=Disable admin info
4177
	 *  @param	string	$morecss			More CSS
4178
	 * 	@return	void
4179
	 */
4180
	public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4181
	{
4182
		global $langs, $conf, $user;
4183
4184
		$langs->load("admin");
4185
		$langs->load("deliveries");
4186
4187
		$sql = "SELECT rowid, code, libelle as label";
4188
		$sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode";
4189
		$sql .= " WHERE active > 0";
4190
		if ($filtre) {
4191
			$sql .= " AND ".$filtre;
4192
		}
4193
		$sql .= " ORDER BY libelle ASC";
4194
4195
		dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
4196
		$result = $this->db->query($sql);
4197
		if ($result) {
4198
			$num = $this->db->num_rows($result);
4199
			$i = 0;
4200
			if ($num) {
4201
				print '<select id="select'.$htmlname.'" class="flat selectshippingmethod'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4202
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4203
					print '<option value="-1">&nbsp;</option>';
4204
				}
4205
				while ($i < $num) {
4206
					$obj = $this->db->fetch_object($result);
4207
					if ($selected == $obj->rowid) {
4208
						print '<option value="'.$obj->rowid.'" selected>';
4209
					} else {
4210
						print '<option value="'.$obj->rowid.'">';
4211
					}
4212
					print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
4213
					print '</option>';
4214
					$i++;
4215
				}
4216
				print "</select>";
4217
				if ($user->admin  && empty($noinfoadmin)) {
4218
					print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4219
				}
4220
4221
				print ajax_combobox('select'.$htmlname);
4222
			} else {
4223
				print $langs->trans("NoShippingMethodDefined");
4224
			}
4225
		} else {
4226
			dol_print_error($this->db);
4227
		}
4228
	}
4229
4230
	/**
4231
	 *    Display form to select shipping mode
4232
	 *
4233
	 *    @param	string	$page        Page
4234
	 *    @param    int		$selected    Id of shipping mode
4235
	 *    @param    string	$htmlname    Name of select html field
4236
	 *    @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.
4237
	 *    @return	void
4238
	 */
4239
	public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4240
	{
4241
		global $langs, $db;
4242
4243
		$langs->load("deliveries");
4244
4245
		if ($htmlname != "none") {
4246
			print '<form method="POST" action="'.$page.'">';
4247
			print '<input type="hidden" name="action" value="setshippingmethod">';
4248
			print '<input type="hidden" name="token" value="'.newToken().'">';
4249
			$this->selectShippingMethod($selected, $htmlname, '', $addempty);
4250
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4251
			print '</form>';
4252
		} else {
4253
			if ($selected) {
4254
				$code = $langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code');
4255
				print $langs->trans("SendingMethod".strtoupper($code));
4256
			} else {
4257
				print "&nbsp;";
4258
			}
4259
		}
4260
	}
4261
4262
	/**
4263
	 * Creates HTML last in cycle situation invoices selector
4264
	 *
4265
	 * @param     string  $selected   		Preselected ID
4266
	 * @param     int     $socid      		Company ID
4267
	 *
4268
	 * @return    string                     HTML select
4269
	 */
4270
	public function selectSituationInvoices($selected = '', $socid = 0)
4271
	{
4272
		global $langs;
4273
4274
		$langs->load('bills');
4275
4276
		$opt = '<option value ="" selected></option>';
4277
		$sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc';
4278
		$sql .= ' FROM '.MAIN_DB_PREFIX.'facture';
4279
		$sql .= ' WHERE entity IN ('.getEntity('invoice').')';
4280
		$sql .= ' AND situation_counter >= 1';
4281
		$sql .= ' AND fk_soc = '.(int) $socid;
4282
		$sql .= ' AND type <> 2';
4283
		$sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4284
		$resql = $this->db->query($sql);
4285
4286
		if ($resql && $this->db->num_rows($resql) > 0) {
4287
			// Last seen cycle
4288
			$ref = 0;
4289
			while ($obj = $this->db->fetch_object($resql)) {
4290
				//Same cycle ?
4291
				if ($obj->situation_cycle_ref != $ref) {
4292
					// Just seen this cycle
4293
					$ref = $obj->situation_cycle_ref;
4294
					//not final ?
4295
					if ($obj->situation_final != 1) {
4296
						//Not prov?
4297
						if (substr($obj->ref, 1, 4) != 'PROV') {
4298
							if ($selected == $obj->rowid) {
4299
								$opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
4300
							} else {
4301
								$opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
4302
							}
4303
						}
4304
					}
4305
				}
4306
			}
4307
		} else {
4308
				dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
4309
		}
4310
		if ($opt == '<option value ="" selected></option>') {
4311
			$opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
4312
		}
4313
		return $opt;
4314
	}
4315
4316
	/**
4317
	 *      Creates HTML units selector (code => label)
4318
	 *
4319
	 *      @param	string	$selected       Preselected Unit ID
4320
	 *      @param  string	$htmlname       Select name
4321
	 *      @param	int		$showempty		Add a nempty line
4322
	 *      @param  string  $unit_type      Restrict to one given unit type
4323
	 * 		@return	string                  HTML select
4324
	 */
4325
	public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
4326
	{
4327
		global $langs;
4328
4329
		$langs->load('products');
4330
4331
		$return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
4332
4333
		$sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units';
4334
		$sql .= ' WHERE active > 0';
4335
		if (!empty($unit_type)) {
4336
			$sql .= " AND unit_type = '".$this->db->escape($unit_type)."'";
4337
		}
4338
4339
		$resql = $this->db->query($sql);
4340
		if ($resql && $this->db->num_rows($resql) > 0) {
4341
			if ($showempty) {
4342
				$return .= '<option value="none"></option>';
4343
			}
4344
4345
			while ($res = $this->db->fetch_object($resql)) {
4346
				$unitLabel = $res->label;
4347
				if (!empty($langs->tab_translate['unit'.$res->code])) {	// check if Translation is available before
4348
					$unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
4349
				}
4350
4351
				if ($selected == $res->rowid) {
4352
					$return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
4353
				} else {
4354
					$return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
4355
				}
4356
			}
4357
			$return .= '</select>';
4358
		}
4359
		return $return;
4360
	}
4361
4362
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4363
	/**
4364
	 *  Return a HTML select list of bank accounts
4365
	 *
4366
	 *  @param	string	$selected           Id account pre-selected
4367
	 *  @param  string	$htmlname           Name of select zone
4368
	 *  @param  int		$status             Status of searched accounts (0=open, 1=closed, 2=both)
4369
	 *  @param  string	$filtre             To filter list. This parameter must not come from input of users
4370
	 *  @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.
4371
	 *  @param  string	$moreattrib         To add more attribute on select
4372
	 *  @param	int		$showcurrency		Show currency in label
4373
	 *  @param	string	$morecss			More CSS
4374
	 *  @param	int		$nooutput			1=Return string, do not send to output
4375
	 * 	@return	int							<0 if error, Num of bank account found if OK (0, 1, 2, ...)
4376
	 */
4377
	public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
4378
	{
4379
		// phpcs:enable
4380
		global $langs, $conf;
4381
4382
		$out = '';
4383
4384
		$langs->load("admin");
4385
		$num = 0;
4386
4387
		$sql = "SELECT rowid, label, bank, clos as status, currency_code";
4388
		$sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
4389
		$sql .= " WHERE entity IN (".getEntity('bank_account').")";
4390
		if ($status != 2) {
4391
			$sql .= " AND clos = ".(int) $status;
4392
		}
4393
		if ($filtre) {
4394
			$sql .= " AND ".$filtre;
4395
		}
4396
		$sql .= " ORDER BY label";
4397
4398
		dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
4399
		$result = $this->db->query($sql);
4400
		if ($result) {
4401
			$num = $this->db->num_rows($result);
4402
			$i = 0;
4403
			if ($num) {
4404
				$out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4405
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4406
					$out .= '<option value="-1">&nbsp;</option>';
4407
				}
4408
4409
				while ($i < $num) {
4410
					$obj = $this->db->fetch_object($result);
4411
					if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
4412
						$out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'" selected>';
4413
					} else {
4414
						$out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'">';
4415
					}
4416
					$out .= trim($obj->label);
4417
					if ($showcurrency) {
4418
						$out .= ' ('.$obj->currency_code.')';
4419
					}
4420
					if ($status == 2 && $obj->status == 1) {
4421
						$out .= ' ('.$langs->trans("Closed").')';
4422
					}
4423
					$out .= '</option>';
4424
					$i++;
4425
				}
4426
				$out .= "</select>";
4427
				$out .= ajax_combobox('select'.$htmlname);
4428
			} else {
4429
				if ($status == 0) {
4430
					$out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
4431
				} else {
4432
					$out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
4433
				}
4434
			}
4435
		} else {
4436
			dol_print_error($this->db);
4437
		}
4438
4439
		// Output or return
4440
		if (empty($nooutput)) {
4441
			print $out;
4442
		} else {
4443
			return $out;
4444
		}
4445
4446
		return $num;
4447
	}
4448
4449
	/**
4450
	 *  Return a HTML select list of establishment
4451
	 *
4452
	 *  @param	string	$selected           Id establishment pre-selected
4453
	 *  @param  string	$htmlname           Name of select zone
4454
	 *  @param  int		$status             Status of searched establishment (0=open, 1=closed, 2=both)
4455
	 *  @param  string	$filtre             To filter list. This parameter must not come from input of users
4456
	 *  @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.
4457
	 *  @param  string	$moreattrib         To add more attribute on select
4458
	 * 	@return	int							<0 if error, Num of establishment found if OK (0, 1, 2, ...)
4459
	 */
4460
	public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
4461
	{
4462
		global $langs, $conf;
4463
4464
		$langs->load("admin");
4465
		$num = 0;
4466
4467
		$sql = "SELECT rowid, name, fk_country, status, entity";
4468
		$sql .= " FROM ".MAIN_DB_PREFIX."establishment";
4469
		$sql .= " WHERE 1=1";
4470
		if ($status != 2) {
4471
			$sql .= " AND status = ".(int) $status;
4472
		}
4473
		if ($filtre) {
4474
			$sql .= " AND ".$filtre;
4475
		}
4476
		$sql .= " ORDER BY name";
4477
4478
		dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
4479
		$result = $this->db->query($sql);
4480
		if ($result) {
4481
			$num = $this->db->num_rows($result);
4482
			$i = 0;
4483
			if ($num) {
4484
				print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
4485
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4486
					print '<option value="-1">&nbsp;</option>';
4487
				}
4488
4489
				while ($i < $num) {
4490
					$obj = $this->db->fetch_object($result);
4491
					if ($selected == $obj->rowid) {
4492
						print '<option value="'.$obj->rowid.'" selected>';
4493
					} else {
4494
						print '<option value="'.$obj->rowid.'">';
4495
					}
4496
					print trim($obj->name);
4497
					if ($status == 2 && $obj->status == 1) {
4498
						print ' ('.$langs->trans("Closed").')';
4499
					}
4500
					print '</option>';
4501
					$i++;
4502
				}
4503
				print "</select>";
4504
			} else {
4505
				if ($status == 0) {
4506
					print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
4507
				} else {
4508
					print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
4509
				}
4510
			}
4511
		} else {
4512
			dol_print_error($this->db);
4513
		}
4514
	}
4515
4516
	/**
4517
	 *    Display form to select bank account
4518
	 *
4519
	 *    @param	string	$page        Page
4520
	 *    @param    int		$selected    Id of bank account
4521
	 *    @param    string	$htmlname    Name of select html field
4522
	 *    @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.
4523
	 *    @return	void
4524
	 */
4525
	public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
4526
	{
4527
		global $langs;
4528
		if ($htmlname != "none") {
4529
			print '<form method="POST" action="'.$page.'">';
4530
			print '<input type="hidden" name="action" value="setbankaccount">';
4531
			print '<input type="hidden" name="token" value="'.newToken().'">';
4532
			print img_picto('', 'bank_account', 'class="pictofixedwidth"');
4533
			$nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
4534
			if ($nbaccountfound > 0) {
4535
				print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4536
			}
4537
			print '</form>';
4538
		} else {
4539
			$langs->load('banks');
4540
4541
			if ($selected) {
4542
				require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
4543
				$bankstatic = new Account($this->db);
4544
				$result = $bankstatic->fetch($selected);
4545
				if ($result) {
4546
					print $bankstatic->getNomUrl(1);
4547
				}
4548
			} else {
4549
				print "&nbsp;";
4550
			}
4551
		}
4552
	}
4553
4554
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4555
	/**
4556
	 *    Return list of categories having choosed type
4557
	 *
4558
	 *    @param	string|int	            $type				Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
4559
	 *    @param    string		            $selected    		Id of category preselected or 'auto' (autoselect category if there is only one element). Not used if $outputmode = 1.
4560
	 *    @param    string		            $htmlname			HTML field name
4561
	 *    @param    int			            $maxlength      	Maximum length for labels
4562
	 *    @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.
4563
	 *                                                          $markafterid can be an :
4564
	 *                                                          - int (id of category)
4565
	 *                                                          - string (categories ids seprated by comma)
4566
	 *                                                          - array (list of categories ids)
4567
	 *    @param	int			            $outputmode			0=HTML select string, 1=Array
4568
	 *    @param	int			            $include			[=0] Removed or 1=Keep only
4569
	 *    @param	string					$morecss			More CSS
4570
	 *    @return	string
4571
	 *    @see select_categories()
4572
	 */
4573
	public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4574
	{
4575
		// phpcs:enable
4576
		global $conf, $langs;
4577
		$langs->load("categories");
4578
4579
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4580
4581
		// For backward compatibility
4582
		if (is_numeric($type)) {
4583
			dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4584
		}
4585
4586
		if ($type === Categorie::TYPE_BANK_LINE) {
4587
			// TODO Move this into common category feature
4588
			$cate_arbo = array();
4589
			$sql = "SELECT c.label, c.rowid";
4590
			$sql .= " FROM ".MAIN_DB_PREFIX."bank_categ as c";
4591
			$sql .= " WHERE entity = ".$conf->entity;
4592
			$sql .= " ORDER BY c.label";
4593
			$result = $this->db->query($sql);
4594
			if ($result) {
4595
				$num = $this->db->num_rows($result);
4596
				$i = 0;
4597
				while ($i < $num) {
4598
					$objp = $this->db->fetch_object($result);
4599
					if ($objp) {
4600
						$cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
4601
					}
4602
					$i++;
4603
				}
4604
				$this->db->free($result);
4605
			} else {
4606
				dol_print_error($this->db);
4607
			}
4608
		} else {
4609
			$cat = new Categorie($this->db);
4610
			$cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4611
		}
4612
4613
		$output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4614
		$outarray = array();
4615
		if (is_array($cate_arbo)) {
4616
			if (!count($cate_arbo)) {
4617
				$output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4618
			} else {
4619
				$output .= '<option value="-1">&nbsp;</option>';
4620
				foreach ($cate_arbo as $key => $value) {
4621
					if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
4622
						$add = 'selected ';
4623
					} else {
4624
						$add = '';
4625
					}
4626
					$output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>';
4627
4628
					$outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4629
				}
4630
			}
4631
		}
4632
		$output .= '</select>';
4633
		$output .= "\n";
4634
4635
		if ($outputmode) {
4636
			return $outarray;
4637
		}
4638
		return $output;
4639
	}
4640
4641
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4642
	/**
4643
	 *     Show a confirmation HTML form or AJAX popup
4644
	 *
4645
	 *     @param	string		$page        	   	Url of page to call if confirmation is OK
4646
	 *     @param	string		$title       	   	Title
4647
	 *     @param	string		$question    	   	Question
4648
	 *     @param 	string		$action      	   	Action
4649
	 *	   @param	array		$formquestion	   	An array with forms complementary inputs
4650
	 * 	   @param	string		$selectedchoice		"" or "no" or "yes"
4651
	 * 	   @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
4652
	 *     @param	int			$height          	Force height of box
4653
	 *     @param	int			$width				Force width of box
4654
	 *     @return 	void
4655
	 *     @deprecated
4656
	 *     @see formconfirm()
4657
	 */
4658
	public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4659
	{
4660
		// phpcs:enable
4661
		dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4662
		print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4663
	}
4664
4665
	/**
4666
	 *     Show a confirmation HTML form or AJAX popup.
4667
	 *     Easiest way to use this is with useajax=1.
4668
	 *     If you use useajax='xxx', you must also add jquery code to trigger opening of box (with correct parameters)
4669
	 *     just after calling this method. For example:
4670
	 *       print '<script type="text/javascript">'."\n";
4671
	 *       print 'jQuery(document).ready(function() {'."\n";
4672
	 *       print 'jQuery(".xxxlink").click(function(e) { jQuery("#aparamid").val(jQuery(this).attr("rel")); jQuery("#dialog-confirm-xxx").dialog("open"); return false; });'."\n";
4673
	 *       print '});'."\n";
4674
	 *       print '</script>'."\n";
4675
	 *
4676
	 *     @param  	string			$page        	   	Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated)
4677
	 *     @param	string			$title       	   	Title
4678
	 *     @param	string			$question    	   	Question
4679
	 *     @param 	string			$action      	   	Action
4680
	 *	   @param  	array|string	$formquestion	   	An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>))
4681
	 *													type can be 'hidden', 'text', 'password', 'checkbox', 'radio', 'date', 'morecss', 'other' or 'onecolumn'...
4682
	 * 	   @param  	string			$selectedchoice  	'' or 'no', or 'yes' or '1' or '0'
4683
	 * 	   @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
4684
	 *     @param  	int|string		$height          	Force height of box (0 = auto)
4685
	 *     @param	int				$width				Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones.
4686
	 *     @param	int				$disableformtag		1=Disable form tag. Can be used if we are already inside a <form> section.
4687
	 *     @return 	string      		    			HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form
4688
	 */
4689
	public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0)
4690
	{
4691
		global $langs, $conf;
4692
4693
		$more = '<!-- formconfirm before calling page='.dol_escape_htmltag($page).' -->';
4694
		$formconfirm = '';
4695
		$inputok = array();
4696
		$inputko = array();
4697
4698
		// Clean parameters
4699
		$newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
4700
		if ($conf->browser->layout == 'phone') {
4701
			$width = '95%';
4702
		}
4703
4704
		// Set height automatically if not defined
4705
		if (empty($height)) {
4706
			$height = 220;
4707
			if (is_array($formquestion) && count($formquestion) > 2) {
4708
				$height += ((count($formquestion) - 2) * 24);
4709
			}
4710
		}
4711
4712
		if (is_array($formquestion) && !empty($formquestion)) {
4713
			// First add hidden fields and value
4714
			foreach ($formquestion as $key => $input) {
4715
				if (is_array($input) && !empty($input)) {
4716
					if ($input['type'] == 'hidden') {
4717
						$more .= '<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
4718
					}
4719
				}
4720
			}
4721
4722
			// Now add questions
4723
			$moreonecolumn = '';
4724
			$more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
4725
			foreach ($formquestion as $key => $input) {
4726
				if (is_array($input) && !empty($input)) {
4727
					$size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : '');
4728
					$moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4729
					$morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4730
4731
					if ($input['type'] == 'text') {
4732
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="text" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4733
					} elseif ($input['type'] == 'password')	{
4734
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="password" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n";
4735
					} elseif ($input['type'] == 'select') {
4736
						if (empty($morecss)) {
4737
							$morecss = 'minwidth100';
4738
						}
4739
4740
						$show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
4741
						$key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
4742
						$value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
4743
						$translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
4744
						$maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
4745
						$disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
4746
						$sort = isset($input['select_sort']) ? $input['select_sort'] : '';
4747
4748
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4749
						if (!empty($input['label'])) {
4750
							$more .= $input['label'].'</div><div class="tagtd left">';
4751
						}
4752
						$more .= $this->selectarray($input['name'], $input['values'], $input['default'], $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
4753
						$more .= '</div></div>'."\n";
4754
					} elseif ($input['type'] == 'checkbox') {
4755
						$more .= '<div class="tagtr">';
4756
						$more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
4757
						$more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr;
4758
						if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') {
4759
							$more .= ' checked';
4760
						}
4761
						if (is_bool($input['value']) && $input['value']) {
4762
							$more .= ' checked';
4763
						}
4764
						if (isset($input['disabled'])) {
4765
							$more .= ' disabled';
4766
						}
4767
						$more .= ' /></div>';
4768
						$more .= '</div>'."\n";
4769
					} elseif ($input['type'] == 'radio') {
4770
						$i = 0;
4771
						foreach ($input['values'] as $selkey => $selval) {
4772
							$more .= '<div class="tagtr">';
4773
							if ($i == 0) {
4774
								$more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
4775
							} else {
4776
								$more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
4777
							}
4778
							$more .= '<div class="tagtd'.($i == 0 ? ' tdtop' : '').'"><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].$selkey.'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr;
4779
							if ($input['disabled']) {
4780
								$more .= ' disabled';
4781
							}
4782
							if (isset($input['default']) && $input['default'] === $selkey) {
4783
								$more .= ' checked="checked"';
4784
							}
4785
							$more .= ' /> ';
4786
							$more .= '<label for="'.$input['name'].$selkey.'">'.$selval.'</label>';
4787
							$more .= '</div></div>'."\n";
4788
							$i++;
4789
						}
4790
					} elseif ($input['type'] == 'date') {
4791
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
4792
						$more .= '<div class="tagtd">';
4793
						$more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, 0);
4794
						$more .= '</div></div>'."\n";
4795
						$formquestion[] = array('name'=>$input['name'].'day');
4796
						$formquestion[] = array('name'=>$input['name'].'month');
4797
						$formquestion[] = array('name'=>$input['name'].'year');
4798
						$formquestion[] = array('name'=>$input['name'].'hour');
4799
						$formquestion[] = array('name'=>$input['name'].'min');
4800
					} elseif ($input['type'] == 'other') {
4801
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4802
						if (!empty($input['label'])) {
4803
							$more .= $input['label'].'</div><div class="tagtd">';
4804
						}
4805
						$more .= $input['value'];
4806
						$more .= '</div></div>'."\n";
4807
					} elseif ($input['type'] == 'onecolumn') {
4808
						$moreonecolumn .= '<div class="margintoponly">';
4809
						$moreonecolumn .= $input['value'];
4810
						$moreonecolumn .= '</div>'."\n";
4811
					} elseif ($input['type'] == 'hidden') {
4812
						// Do nothing more, already added by a previous loop
4813
					} else {
4814
						$more .= 'Error type '.$input['type'].' for the confirm box is not a supported type';
4815
					}
4816
				}
4817
			}
4818
			$more .= '</div>'."\n";
4819
			$more .= $moreonecolumn;
4820
		}
4821
4822
		// JQUI method dialog is broken with jmobile, we use standard HTML.
4823
		// 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
4824
		// See page product/card.php for example
4825
		if (!empty($conf->dol_use_jmobile)) {
4826
			$useajax = 0;
4827
		}
4828
		if (empty($conf->use_javascript_ajax)) {
4829
			$useajax = 0;
4830
		}
4831
4832
		if ($useajax) {
4833
			$autoOpen = true;
4834
			$dialogconfirm = 'dialog-confirm';
4835
			$button = '';
4836
			if (!is_numeric($useajax)) {
4837
				$button = $useajax;
4838
				$useajax = 1;
4839
				$autoOpen = false;
4840
				$dialogconfirm .= '-'.$button;
4841
			}
4842
			$pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.$action.'&confirm=yes';
4843
			$pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'confirm=no' : '');
4844
4845
			// Add input fields into list of fields to read during submit (inputok and inputko)
4846
			if (is_array($formquestion)) {
4847
				foreach ($formquestion as $key => $input) {
4848
					//print "xx ".$key." rr ".is_array($input)."<br>\n";
4849
					// Add name of fields to propagate with the GET when submitting the form with button OK.
4850
					if (is_array($input) && isset($input['name'])) {
4851
						if (strpos($input['name'], ',') > 0) {
4852
							$inputok = array_merge($inputok, explode(',', $input['name']));
4853
						} else {
4854
							array_push($inputok, $input['name']);
4855
						}
4856
					}
4857
					// Add name of fields to propagate with the GET when submitting the form with button KO.
4858
					if (isset($input['inputko']) && $input['inputko'] == 1) {
4859
						array_push($inputko, $input['name']);
4860
					}
4861
				}
4862
			}
4863
4864
			// Show JQuery confirm box.
4865
			$formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
4866
			if (is_array($formquestion) && !empty($formquestion['text'])) {
4867
				$formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
4868
			}
4869
			if (!empty($more)) {
4870
				$formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
4871
			}
4872
			$formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
4873
			$formconfirm .= '</div>'."\n";
4874
4875
			$formconfirm .= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
4876
			$formconfirm .= '<script type="text/javascript">'."\n";
4877
			$formconfirm .= 'jQuery(document).ready(function() {
4878
            $(function() {
4879
            	$( "#'.$dialogconfirm.'" ).dialog(
4880
            	{
4881
                    autoOpen: '.($autoOpen ? "true" : "false").',';
4882
			if ($newselectedchoice == 'no') {
4883
				$formconfirm .= '
4884
						open: function() {
4885
            				$(this).parent().find("button.ui-button:eq(2)").focus();
4886
						},';
4887
			}
4888
			$formconfirm .= '
4889
                    resizable: false,
4890
                    height: "'.$height.'",
4891
                    width: "'.$width.'",
4892
                    modal: true,
4893
                    closeOnEscape: false,
4894
                    buttons: {
4895
                        "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
4896
                        	var options = "&token='.urlencode(newToken()).'";
4897
                        	var inputok = '.json_encode($inputok).';	/* List of fields into form */
4898
                         	var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
4899
                         	if (inputok.length>0) {
4900
                         		$.each(inputok, function(i, inputname) {
4901
                         			var more = "";
4902
									var inputvalue;
4903
                         			if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
4904
										inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
4905
									} else {
4906
                         		    	if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4907
                         				inputvalue = $("#" + inputname + more).val();
4908
									}
4909
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4910
									console.log("check inputname="+inputname+" inputvalue="+inputvalue);
4911
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4912
                         		});
4913
                         	}
4914
                         	var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
4915
            				if (pageyes.length > 0) { location.href = urljump; }
4916
                            $(this).dialog("close");
4917
                        },
4918
                        "'.dol_escape_js($langs->transnoentities("No")).'": function() {
4919
                        	var options = "&token='.urlencode(newToken()).'";
4920
                         	var inputko = '.json_encode($inputko).';	/* List of fields into form */
4921
                         	var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
4922
                         	if (inputko.length>0) {
4923
                         		$.each(inputko, function(i, inputname) {
4924
                         			var more = "";
4925
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4926
                         			var inputvalue = $("#" + inputname + more).val();
4927
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4928
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4929
                         		});
4930
                         	}
4931
                         	var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
4932
                         	//alert(urljump);
4933
            				if (pageno.length > 0) { location.href = urljump; }
4934
                            $(this).dialog("close");
4935
                        }
4936
                    }
4937
                }
4938
                );
4939
4940
            	var button = "'.$button.'";
4941
            	if (button.length > 0) {
4942
                	$( "#" + button ).click(function() {
4943
                		$("#'.$dialogconfirm.'").dialog("open");
4944
        			});
4945
                }
4946
            });
4947
            });
4948
            </script>';
4949
			$formconfirm .= "<!-- end ajax formconfirm -->\n";
4950
		} else {
4951
			$formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n";
4952
4953
			if (empty($disableformtag)) {
4954
				$formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
4955
			}
4956
4957
			$formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
4958
			$formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
4959
4960
			$formconfirm .= '<table class="valid centpercent">'."\n";
4961
4962
			// Line title
4963
			$formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
4964
			$formconfirm .= img_picto('', 'recent').' '.$title;
4965
			$formconfirm .= '</td></tr>'."\n";
4966
4967
			// Line text
4968
			if (is_array($formquestion) && !empty($formquestion['text'])) {
4969
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'.$formquestion['text'].'</td></tr>'."\n";
4970
			}
4971
4972
			// Line form fields
4973
			if ($more) {
4974
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'."\n";
4975
				$formconfirm .= $more;
4976
				$formconfirm .= '</td></tr>'."\n";
4977
			}
4978
4979
			// Line with question
4980
			$formconfirm .= '<tr class="valid">';
4981
			$formconfirm .= '<td class="valid">'.$question.'</td>';
4982
			$formconfirm .= '<td class="valid center">';
4983
			$formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly');
4984
			$formconfirm .= '<input class="button valignmiddle confirmvalidatebutton" type="submit" value="'.$langs->trans("Validate").'">';
4985
			$formconfirm .= '</td>';
4986
			$formconfirm .= '</tr>'."\n";
4987
4988
			$formconfirm .= '</table>'."\n";
4989
4990
			if (empty($disableformtag)) {
4991
				$formconfirm .= "</form>\n";
4992
			}
4993
			$formconfirm .= '<br>';
4994
4995
			if (empty($conf->use_javascript_ajax)) {
4996
				$formconfirm .= '<!-- code to disable button to avoid double clic -->';
4997
				$formconfirm .= '<script type="text/javascript">'."\n";
4998
				$formconfirm .= '
4999
				$(document).ready(function () {
5000
					$(".confirmvalidatebutton").on("click", function() {
5001
						console.log("We click on button");
5002
						$(this).attr("disabled", "disabled");
5003
						setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5004
						//console.log($(this).closest("form"));
5005
						$(this).closest("form").submit();
5006
					});
5007
				});
5008
				';
5009
				$formconfirm .= '</script>'."\n";
5010
			}
5011
5012
			$formconfirm .= "<!-- end formconfirm -->\n";
5013
		}
5014
5015
		return $formconfirm;
5016
	}
5017
5018
5019
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5020
	/**
5021
	 *    Show a form to select a project
5022
	 *
5023
	 *    @param	int		$page        		Page
5024
	 *    @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)
5025
	 *    @param    int		$selected    		Id pre-selected project
5026
	 *    @param    string	$htmlname    		Name of select field
5027
	 *    @param	int		$discard_closed		Discard closed projects (0=Keep,1=hide completely except $selected,2=Disable)
5028
	 *    @param	int		$maxlength			Max length
5029
	 *    @param	int		$forcefocus			Force focus on field (works with javascript only)
5030
	 *    @param    int     $nooutput           No print is done. String is returned.
5031
	 *    @return	string                      Return html content
5032
	 */
5033
	public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0)
5034
	{
5035
		// phpcs:enable
5036
		global $langs;
5037
5038
		require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
5039
		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
5040
5041
		$out = '';
5042
5043
		$formproject = new FormProjets($this->db);
5044
5045
		$langs->load("project");
5046
		if ($htmlname != "none") {
5047
			$out .= "\n";
5048
			$out .= '<form method="post" action="'.$page.'">';
5049
			$out .= '<input type="hidden" name="action" value="classin">';
5050
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
5051
			$out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
5052
			$out .= '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5053
			$out .= '</form>';
5054
		} else {
5055
			if ($selected) {
5056
				$projet = new Project($this->db);
5057
				$projet->fetch($selected);
5058
				//print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
5059
				$out .= $projet->getNomUrl(0, '', 1);
5060
			} else {
5061
				$out .= "&nbsp;";
5062
			}
5063
		}
5064
5065
		if (empty($nooutput)) {
5066
			print $out;
5067
			return '';
5068
		}
5069
		return $out;
5070
	}
5071
5072
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5073
	/**
5074
	 *	Show a form to select payment conditions
5075
	 *
5076
	 *  @param	int		$page        	Page
5077
	 *  @param  string	$selected    	Id condition pre-selectionne
5078
	 *  @param  string	$htmlname    	Name of select html field
5079
	 *	@param	int		$addempty		Add empty entry
5080
	 *  @return	void
5081
	 */
5082
	public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0)
5083
	{
5084
		// phpcs:enable
5085
		global $langs;
5086
		if ($htmlname != "none") {
5087
			print '<form method="post" action="'.$page.'">';
5088
			print '<input type="hidden" name="action" value="setconditions">';
5089
			print '<input type="hidden" name="token" value="'.newToken().'">';
5090
			$this->select_conditions_paiements($selected, $htmlname, -1, $addempty);
5091
			print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
5092
			print '</form>';
5093
		} else {
5094
			if ($selected) {
5095
				$this->load_cache_conditions_paiements();
5096
				if (isset($this->cache_conditions_paiements[$selected])) {
5097
					print $this->cache_conditions_paiements[$selected]['label'];
5098
				} else {
5099
					$langs->load('errors');
5100
					print $langs->trans('ErrorNotInDictionaryPaymentConditions');
5101
				}
5102
			} else {
5103
				print "&nbsp;";
5104
			}
5105
		}
5106
	}
5107
5108
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5109
	/**
5110
	 *  Show a form to select a delivery delay
5111
	 *
5112
	 *  @param  int		$page        	Page
5113
	 *  @param  string	$selected    	Id condition pre-selectionne
5114
	 *  @param  string	$htmlname    	Name of select html field
5115
	 *	@param	int		$addempty		Ajoute entree vide
5116
	 *  @return	void
5117
	 */
5118
	public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5119
	{
5120
		// phpcs:enable
5121
		global $langs;
5122
		if ($htmlname != "none") {
5123
			print '<form method="post" action="'.$page.'">';
5124
			print '<input type="hidden" name="action" value="setavailability">';
5125
			print '<input type="hidden" name="token" value="'.newToken().'">';
5126
			$this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5127
			print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5128
			print '</form>';
5129
		} else {
5130
			if ($selected) {
5131
				$this->load_cache_availability();
5132
				print $this->cache_availability[$selected]['label'];
5133
			} else {
5134
				print "&nbsp;";
5135
			}
5136
		}
5137
	}
5138
5139
	/**
5140
	 *  Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
5141
	 *  List found into table c_input_reason loaded by loadCacheInputReason
5142
	 *
5143
	 *  @param  string	$page        	Page
5144
	 *  @param  string	$selected    	Id condition pre-selectionne
5145
	 *  @param  string	$htmlname    	Name of select html field
5146
	 *  @param	int		$addempty		Add empty entry
5147
	 *  @return	void
5148
	 */
5149
	public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5150
	{
5151
		global $langs;
5152
		if ($htmlname != "none") {
5153
			print '<form method="post" action="'.$page.'">';
5154
			print '<input type="hidden" name="action" value="setdemandreason">';
5155
			print '<input type="hidden" name="token" value="'.newToken().'">';
5156
			$this->selectInputReason($selected, $htmlname, -1, $addempty);
5157
			print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
5158
			print '</form>';
5159
		} else {
5160
			if ($selected) {
5161
				$this->loadCacheInputReason();
5162
				foreach ($this->cache_demand_reason as $key => $val) {
5163
					if ($val['id'] == $selected) {
5164
						print $val['label'];
5165
						break;
5166
					}
5167
				}
5168
			} else {
5169
				print "&nbsp;";
5170
			}
5171
		}
5172
	}
5173
5174
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5175
	/**
5176
	 *    Show a form + html select a date
5177
	 *
5178
	 *    @param	string		$page        	Page
5179
	 *    @param	string		$selected    	Date preselected
5180
	 *    @param    string		$htmlname    	Html name of date input fields or 'none'
5181
	 *    @param    int			$displayhour 	Display hour selector
5182
	 *    @param    int			$displaymin		Display minutes selector
5183
	 *    @param	int			$nooutput		1=No print output, return string
5184
	 *    @return	string
5185
	 *    @see		selectDate()
5186
	 */
5187
	public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0)
5188
	{
5189
		// phpcs:enable
5190
		global $langs;
5191
5192
		$ret = '';
5193
5194
		if ($htmlname != "none") {
5195
			$ret .= '<form method="post" action="'.$page.'" name="form'.$htmlname.'">';
5196
			$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
5197
			$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
5198
			$ret .= '<table class="nobordernopadding">';
5199
			$ret .= '<tr><td>';
5200
			$ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
5201
			$ret .= '</td>';
5202
			$ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5203
			$ret .= '</tr></table></form>';
5204
		} else {
5205
			if ($displayhour) {
5206
				$ret .= dol_print_date($selected, 'dayhour');
5207
			} else {
5208
				$ret .= dol_print_date($selected, 'day');
5209
			}
5210
		}
5211
5212
		if (empty($nooutput)) {
5213
			print $ret;
5214
		}
5215
		return $ret;
5216
	}
5217
5218
5219
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5220
	/**
5221
	 *  Show a select form to choose a user
5222
	 *
5223
	 *  @param	string	$page        	Page
5224
	 *  @param  string	$selected    	Id of user preselected
5225
	 *  @param  string	$htmlname    	Name of input html field. If 'none', we just output the user link.
5226
	 *  @param  array	$exclude		List of users id to exclude
5227
	 *  @param  array	$include        List of users id to include
5228
	 *  @return	void
5229
	 */
5230
	public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
5231
	{
5232
		// phpcs:enable
5233
		global $langs;
5234
5235
		if ($htmlname != "none") {
5236
			print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
5237
			print '<input type="hidden" name="action" value="set'.$htmlname.'">';
5238
			print '<input type="hidden" name="token" value="'.newToken().'">';
5239
			print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
5240
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5241
			print '</form>';
5242
		} else {
5243
			if ($selected) {
5244
				require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
5245
				$theuser = new User($this->db);
5246
				$theuser->fetch($selected);
5247
				print $theuser->getNomUrl(1);
5248
			} else {
5249
				print "&nbsp;";
5250
			}
5251
		}
5252
	}
5253
5254
5255
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5256
	/**
5257
	 *    Show form with payment mode
5258
	 *
5259
	 *    @param	string	$page        	Page
5260
	 *    @param    int		$selected    	Id mode pre-selectionne
5261
	 *    @param    string	$htmlname    	Name of select html field
5262
	 *    @param  	string	$filtertype		To filter on field type in llx_c_paiement (array('code'=>xx,'label'=>zz))
5263
	 *    @param    int     $active         Active or not, -1 = all
5264
	 *    @param   int     $addempty       1=Add empty entry
5265
	 *    @return	void
5266
	 */
5267
	public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0)
5268
	{
5269
		// phpcs:enable
5270
		global $langs;
5271
		if ($htmlname != "none") {
5272
			print '<form method="POST" action="'.$page.'">';
5273
			print '<input type="hidden" name="action" value="setmode">';
5274
			print '<input type="hidden" name="token" value="'.newToken().'">';
5275
			$this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active);
5276
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5277
			print '</form>';
5278
		} else {
5279
			if ($selected) {
5280
				$this->load_cache_types_paiements();
5281
				print $this->cache_types_paiements[$selected]['label'];
5282
			} else {
5283
				print "&nbsp;";
5284
			}
5285
		}
5286
	}
5287
5288
	/**
5289
	 *    Show form with transport mode
5290
	 *
5291
	 *    @param	string	$page        	Page
5292
	 *    @param    int		$selected    	Id mode pre-select
5293
	 *    @param    string	$htmlname    	Name of select html field
5294
	 *    @param    int     $active         Active or not, -1 = all
5295
	 *    @param    int     $addempty       1=Add empty entry
5296
	 *    @return	void
5297
	 */
5298
	public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
5299
	{
5300
		global $langs;
5301
		if ($htmlname != "none") {
5302
			print '<form method="POST" action="'.$page.'">';
5303
			print '<input type="hidden" name="action" value="settransportmode">';
5304
			print '<input type="hidden" name="token" value="'.newToken().'">';
5305
			$this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
5306
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5307
			print '</form>';
5308
		} else {
5309
			if ($selected) {
5310
				$this->load_cache_transport_mode();
5311
				print $this->cache_transport_mode[$selected]['label'];
5312
			} else {
5313
				print "&nbsp;";
5314
			}
5315
		}
5316
	}
5317
5318
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5319
	/**
5320
	 *    Show form with multicurrency code
5321
	 *
5322
	 *    @param	string	$page        	Page
5323
	 *    @param    string	$selected    	code pre-selectionne
5324
	 *    @param    string	$htmlname    	Name of select html field
5325
	 *    @return	void
5326
	 */
5327
	public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
5328
	{
5329
		// phpcs:enable
5330
		global $langs;
5331
		if ($htmlname != "none") {
5332
			print '<form method="POST" action="'.$page.'">';
5333
			print '<input type="hidden" name="action" value="setmulticurrencycode">';
5334
			print '<input type="hidden" name="token" value="'.newToken().'">';
5335
			print $this->selectMultiCurrency($selected, $htmlname, 0);
5336
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5337
			print '</form>';
5338
		} else {
5339
			dol_include_once('/core/lib/company.lib.php');
5340
			print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
5341
		}
5342
	}
5343
5344
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5345
	/**
5346
	 *    Show form with multicurrency rate
5347
	 *
5348
	 *    @param	string	$page        	Page
5349
	 *    @param    double	$rate	    	Current rate
5350
	 *    @param    string	$htmlname    	Name of select html field
5351
	 *    @param    string  $currency       Currency code to explain the rate
5352
	 *    @return	void
5353
	 */
5354
	public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
5355
	{
5356
		// phpcs:enable
5357
		global $langs, $mysoc, $conf;
5358
5359
		if ($htmlname != "none") {
5360
			print '<form method="POST" action="'.$page.'">';
5361
			print '<input type="hidden" name="action" value="setmulticurrencyrate">';
5362
			print '<input type="hidden" name="token" value="'.newToken().'">';
5363
			print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> ';
5364
			print '<select name="calculation_mode">';
5365
			print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>';
5366
			print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>';
5367
			print '</select> ';
5368
			print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5369
			print '</form>';
5370
		} else {
5371
			if (!empty($rate)) {
5372
				print price($rate, 1, $langs, 1, 0);
5373
				if ($currency && $rate != 1) {
5374
					print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
5375
				}
5376
			} else {
5377
				print 1;
5378
			}
5379
		}
5380
	}
5381
5382
5383
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5384
	/**
5385
	 *	Show a select box with available absolute discounts
5386
	 *
5387
	 *  @param  string	$page        	Page URL where form is shown
5388
	 *  @param  int		$selected    	Value pre-selected
5389
	 *	@param  string	$htmlname    	Name of SELECT component. If 'none', not changeable. Example 'remise_id'.
5390
	 *	@param	int		$socid			Third party id
5391
	 * 	@param	float	$amount			Total amount available
5392
	 * 	@param	string	$filter			SQL filter on discounts
5393
	 * 	@param	int		$maxvalue		Max value for lines that can be selected
5394
	 *  @param  string	$more           More string to add
5395
	 *  @param  int     $hidelist       1=Hide list
5396
	 *  @param	int		$discount_type	0 => customer discount, 1 => supplier discount
5397
	 *  @return	void
5398
	 */
5399
	public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
5400
	{
5401
		// phpcs:enable
5402
		global $conf, $langs;
5403
		if ($htmlname != "none") {
5404
			print '<form method="post" action="'.$page.'">';
5405
			print '<input type="hidden" name="action" value="setabsolutediscount">';
5406
			print '<input type="hidden" name="token" value="'.newToken().'">';
5407
			print '<div class="inline-block">';
5408
			if (!empty($discount_type)) {
5409
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5410
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
5411
						$translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
5412
					} else {
5413
						$translationKey = 'HasCreditNoteFromSupplier';
5414
					}
5415
				} else {
5416
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5417
						$translationKey = 'HasAbsoluteDiscountFromSupplier';
5418
					} else {
5419
						$translationKey = 'HasCreditNoteFromSupplier';
5420
					}
5421
				}
5422
			} else {
5423
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
5424
					if (!$filter || $filter == "fk_facture_source IS NULL") {
5425
						$translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
5426
					} else {
5427
						$translationKey = 'CompanyHasCreditNote';
5428
					}
5429
				} else {
5430
					if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5431
						$translationKey = 'CompanyHasAbsoluteDiscount';
5432
					} else {
5433
						$translationKey = 'CompanyHasCreditNote';
5434
					}
5435
				}
5436
			}
5437
			print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
5438
			if (empty($hidelist)) {
5439
				print ' ';
5440
			}
5441
			print '</div>';
5442
			if (empty($hidelist)) {
5443
				print '<div class="inline-block" style="padding-right: 10px">';
5444
				$newfilter = 'discount_type='.intval($discount_type);
5445
				if (!empty($discount_type)) {
5446
					$newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
5447
				} else {
5448
					$newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
5449
				}
5450
				if ($filter) {
5451
					$newfilter .= ' AND ('.$filter.')';
5452
				}
5453
				$nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
5454
				if ($nbqualifiedlines > 0) {
5455
					print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
5456
					if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
5457
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5458
					}
5459
					if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
5460
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
5461
					}
5462
5463
					print '>';
5464
				}
5465
				print '</div>';
5466
			}
5467
			if ($more) {
5468
				print '<div class="inline-block">';
5469
				print $more;
5470
				print '</div>';
5471
			}
5472
			print '</form>';
5473
		} else {
5474
			if ($selected) {
5475
				print $selected;
5476
			} else {
5477
				print "0";
5478
			}
5479
		}
5480
	}
5481
5482
5483
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5484
	/**
5485
	 *  Show forms to select a contact
5486
	 *
5487
	 *  @param	string		$page        	Page
5488
	 *  @param	Societe		$societe		Filter on third party
5489
	 *  @param    int			$selected    	Id contact pre-selectionne
5490
	 *  @param    string		$htmlname    	Name of HTML select. If 'none', we just show contact link.
5491
	 *  @return	void
5492
	 */
5493
	public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
5494
	{
5495
		// phpcs:enable
5496
		global $langs, $conf;
5497
5498
		if ($htmlname != "none") {
5499
			print '<form method="post" action="'.$page.'">';
5500
			print '<input type="hidden" name="action" value="set_contact">';
5501
			print '<input type="hidden" name="token" value="'.newToken().'">';
5502
			print '<table class="nobordernopadding">';
5503
			print '<tr><td>';
5504
			print $this->selectcontacts($societe->id, $selected, $htmlname);
5505
			$num = $this->num;
5506
			if ($num == 0) {
5507
				$addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
5508
				print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
5509
			}
5510
			print '</td>';
5511
			print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>';
5512
			print '</tr></table></form>';
5513
		} else {
5514
			if ($selected) {
5515
				require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
5516
				$contact = new Contact($this->db);
5517
				$contact->fetch($selected);
5518
				print $contact->getFullName($langs);
5519
			} else {
5520
				print "&nbsp;";
5521
			}
5522
		}
5523
	}
5524
5525
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5526
	/**
5527
	 *  Output html select to select thirdparty
5528
	 *
5529
	 *  @param	string	$page       	Page
5530
	 *  @param  string	$selected   	Id preselected
5531
	 *  @param  string	$htmlname		Name of HTML select
5532
	 *  @param  string	$filter         Optional filters criteras. Do not use a filter coming from input of users.
5533
	 *	@param	int		$showempty		Add an empty field
5534
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
5535
	 * 	@param	int		$forcecombo		Force to use combo box
5536
	 *  @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')))
5537
	 *  @param  int     $nooutput       No print output. Return it only.
5538
	 *  @param	array	$excludeids		Exclude IDs from the select combo
5539
	 *  @return	void|string
5540
	 */
5541
	public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array())
5542
	{
5543
		// phpcs:enable
5544
		global $langs;
5545
5546
		$out = '';
5547
		if ($htmlname != "none") {
5548
			$out .= '<form method="post" action="'.$page.'">';
5549
			$out .= '<input type="hidden" name="action" value="set_thirdparty">';
5550
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
5551
			$out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
5552
			$out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
5553
			$out .= '</form>';
5554
		} else {
5555
			if ($selected) {
5556
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
5557
				$soc = new Societe($this->db);
5558
				$soc->fetch($selected);
5559
				$out .= $soc->getNomUrl($langs);
5560
			} else {
5561
				$out .= "&nbsp;";
5562
			}
5563
		}
5564
5565
		if ($nooutput) {
5566
			return $out;
5567
		} else {
5568
			print $out;
5569
		}
5570
	}
5571
5572
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5573
	/**
5574
	 *    Retourne la liste des devises, dans la langue de l'utilisateur
5575
	 *
5576
	 *    @param	string	$selected    preselected currency code
5577
	 *    @param    string	$htmlname    name of HTML select list
5578
	 *    @deprecated
5579
	 *    @return	void
5580
	 */
5581
	public function select_currency($selected = '', $htmlname = 'currency_id')
5582
	{
5583
		// phpcs:enable
5584
		print $this->selectCurrency($selected, $htmlname);
5585
	}
5586
5587
	/**
5588
	 *  Retourne la liste des devises, dans la langue de l'utilisateur
5589
	 *
5590
	 *  @param	string	$selected    preselected currency code
5591
	 *  @param  string	$htmlname    name of HTML select list
5592
	 *  @param  string  $mode        0 = Add currency symbol into label, 1 = Add 3 letter iso code
5593
	 * 	@return	string
5594
	 */
5595
	public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0)
5596
	{
5597
		global $conf, $langs, $user;
5598
5599
		$langs->loadCacheCurrencies('');
5600
5601
		$out = '';
5602
5603
		if ($selected == 'euro' || $selected == 'euros') {
5604
			$selected = 'EUR'; // Pour compatibilite
5605
		}
5606
5607
		$out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
5608
		foreach ($langs->cache_currencies as $code_iso => $currency) {
5609
			$labeltoshow = $currency['label'];
5610
			if ($mode == 1) {
5611
				$labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>';
5612
			} else {
5613
				$labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>';
5614
			}
5615
5616
			if ($selected && $selected == $code_iso) {
5617
				$out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">';
5618
			} else {
5619
				$out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">';
5620
			}
5621
			$out .= $labeltoshow;
5622
			$out .= '</option>';
5623
		}
5624
		$out .= '</select>';
5625
		if ($user->admin) {
5626
			$out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5627
		}
5628
5629
		// Make select dynamic
5630
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5631
		$out .= ajax_combobox($htmlname);
5632
5633
		return $out;
5634
	}
5635
5636
	/**
5637
	 *	Return array of currencies in user language
5638
	 *
5639
	 *  @param	string	$selected    preselected currency code
5640
	 *  @param  string	$htmlname    name of HTML select list
5641
	 *  @param  integer	$useempty    1=Add empty line
5642
	 *  @param string $filter Optional filters criteras (example: 'code <> x', ' in (1,3)')
5643
	 *  @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
5644
	 * 	@return	string
5645
	 */
5646
	public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false)
5647
	{
5648
		global $db, $conf, $langs, $user;
5649
5650
		$langs->loadCacheCurrencies(''); // Load ->cache_currencies
5651
5652
		$TCurrency = array();
5653
5654
		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
5655
		$sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
5656
		if ($filter) {
5657
			$sql .= " AND ".$filter;
5658
		}
5659
		$resql = $this->db->query($sql);
5660
		if ($resql) {
5661
			while ($obj = $this->db->fetch_object($resql)) {
5662
				$TCurrency[$obj->code] = $obj->code;
5663
			}
5664
		}
5665
5666
		$out = '';
5667
		$out .= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
5668
		if ($useempty) {
5669
			$out .= '<option value="">&nbsp;</option>';
5670
		}
5671
		// If company current currency not in table, we add it into list. Should always be available.
5672
		if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
5673
			$TCurrency[$conf->currency] = $conf->currency;
5674
		}
5675
		if (count($TCurrency) > 0) {
5676
			foreach ($langs->cache_currencies as $code_iso => $currency) {
5677
				if (isset($TCurrency[$code_iso])) {
5678
					if (!empty($selected) && $selected == $code_iso) {
5679
						$out .= '<option value="'.$code_iso.'" selected="selected">';
5680
					} else {
5681
						$out .= '<option value="'.$code_iso.'">';
5682
					}
5683
5684
					$out .= $currency['label'];
5685
					$out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5686
					$out .= '</option>';
5687
				}
5688
			}
5689
		}
5690
5691
		$out .= '</select>';
5692
		// Make select dynamic
5693
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5694
		$out .= ajax_combobox($htmlname);
5695
5696
		return $out;
5697
	}
5698
5699
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5700
	/**
5701
	 *  Load into the cache vat rates of a country
5702
	 *
5703
	 *  @param	string	$country_code		Country code with quotes ("'CA'", or "'CA,IN,...'")
5704
	 *  @return	int							Nb of loaded lines, 0 if already loaded, <0 if KO
5705
	 */
5706
	public function load_cache_vatrates($country_code)
5707
	{
5708
		// phpcs:enable
5709
		global $langs;
5710
5711
		$num = count($this->cache_vatrates);
5712
		if ($num > 0) {
5713
			return $num; // Cache already loaded
5714
		}
5715
5716
		dol_syslog(__METHOD__, LOG_DEBUG);
5717
5718
		$sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
5719
		$sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
5720
		$sql .= " WHERE t.fk_pays = c.rowid";
5721
		$sql .= " AND t.active > 0";
5722
		$sql .= " AND c.code IN (".$this->db->sanitize($country_code, 1).")";
5723
		$sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
5724
5725
		$resql = $this->db->query($sql);
5726
		if ($resql) {
5727
			$num = $this->db->num_rows($resql);
5728
			if ($num) {
5729
				for ($i = 0; $i < $num; $i++) {
5730
					$obj = $this->db->fetch_object($resql);
5731
					$this->cache_vatrates[$i]['rowid']	= $obj->rowid;
5732
					$this->cache_vatrates[$i]['code'] = $obj->code;
5733
					$this->cache_vatrates[$i]['txtva']	= $obj->taux;
5734
					$this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
5735
					$this->cache_vatrates[$i]['localtax1']	    = $obj->localtax1;
5736
					$this->cache_vatrates[$i]['localtax1_type']	= $obj->localtax1_type;
5737
					$this->cache_vatrates[$i]['localtax2']	    = $obj->localtax2;
5738
					$this->cache_vatrates[$i]['localtax2_type']	= $obj->localtax1_type;
5739
5740
					$this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
5741
					$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
5742
					$positiverates = '';
5743
					if ($obj->taux) {
5744
						$positiverates .= ($positiverates ? '/' : '').$obj->taux;
5745
					}
5746
					if ($obj->localtax1) {
5747
						$positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
5748
					}
5749
					if ($obj->localtax2) {
5750
						$positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
5751
					}
5752
					if (empty($positiverates)) {
5753
						$positiverates = '0';
5754
					}
5755
					$this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
5756
				}
5757
5758
				return $num;
5759
			} else {
5760
				$this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</font>';
5761
				return -1;
5762
			}
5763
		} else {
5764
			$this->error = '<font class="error">'.$this->db->error().'</font>';
5765
			return -2;
5766
		}
5767
	}
5768
5769
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5770
	/**
5771
	 *  Output an HTML select vat rate.
5772
	 *  The name of this function should be selectVat. We keep bad name for compatibility purpose.
5773
	 *
5774
	 *  @param	string	      $htmlname           Name of HTML select field
5775
	 *  @param  float|string  $selectedrate       Force preselected vat rate. Can be '8.5' or '8.5 (NOO)' for example. Use '' for no forcing.
5776
	 *  @param  Societe	      $societe_vendeuse   Thirdparty seller
5777
	 *  @param  Societe	      $societe_acheteuse  Thirdparty buyer
5778
	 *  @param  int		      $idprod             Id product. O if unknown of NA.
5779
	 *  @param  int		      $info_bits          Miscellaneous information on line (1 for NPR)
5780
	 *  @param  int|string    $type               ''=Unknown, 0=Product, 1=Service (Used if idprod not defined)
5781
	 *                  		                  Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle.
5782
	 *                  					      Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle.
5783
	 *                  					      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.
5784
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= particulier alors TVA par défaut=TVA du produit vendu. Fin de règle.
5785
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= entreprise alors TVA par défaut=0. Fin de règle.
5786
	 *                  					      Sinon la TVA proposee par defaut=0. Fin de regle.
5787
	 *  @param	bool	     $options_only		  Return HTML options lines only (for ajax treatment)
5788
	 *  @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
5789
	 *  @return	string
5790
	 */
5791
	public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
5792
	{
5793
		// phpcs:enable
5794
		global $langs, $conf, $mysoc;
5795
5796
		$langs->load('errors');
5797
5798
		$return = '';
5799
5800
		// Define defaultnpr, defaultttx and defaultcode
5801
		$defaultnpr = ($info_bits & 0x01);
5802
		$defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
5803
		$defaulttx = str_replace('*', '', $selectedrate);
5804
		$defaultcode = '';
5805
		$reg = array();
5806
		if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
5807
			$defaultcode = $reg[1];
5808
			$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5809
		}
5810
		//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
5811
5812
		// Check parameters
5813
		if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
5814
			if ($societe_vendeuse->id == $mysoc->id) {
5815
				$return .= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</font>';
5816
			} else {
5817
				$return .= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</font>';
5818
			}
5819
			return $return;
5820
		}
5821
5822
		//var_dump($societe_acheteuse);
5823
		//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";
5824
		//exit;
5825
5826
		// Define list of countries to use to search VAT rates to show
5827
		// First we defined code_country to use to find list
5828
		if (is_object($societe_vendeuse)) {
5829
			$code_country = "'".$societe_vendeuse->country_code."'";
5830
		} else {
5831
			$code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
5832
		}
5833
		if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {    // If option to have vat for end customer for services is on
5834
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
5835
			if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) {
5836
				// We also add the buyer
5837
				if (is_numeric($type)) {
5838
					if ($type == 1) { // We know product is a service
5839
						$code_country .= ",'".$societe_acheteuse->country_code."'";
5840
					}
5841
				} elseif (!$idprod) {  // We don't know type of product
5842
					$code_country .= ",'".$societe_acheteuse->country_code."'";
5843
				} else {
5844
					$prodstatic = new Product($this->db);
5845
					$prodstatic->fetch($idprod);
5846
					if ($prodstatic->type == Product::TYPE_SERVICE) {   // We know product is a service
5847
						$code_country .= ",'".$societe_acheteuse->country_code."'";
5848
					}
5849
				}
5850
			}
5851
		}
5852
5853
		// Now we get list
5854
		$num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
5855
5856
		if ($num > 0) {
5857
			// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
5858
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
5859
				$tmpthirdparty = new Societe($this->db);
5860
				$defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5861
				$defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5862
				if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
5863
					$defaultcode = $reg[1];
5864
					$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5865
				}
5866
				if (empty($defaulttx)) {
5867
					$defaultnpr = 0;
5868
				}
5869
			}
5870
5871
			// Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
5872
			// Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
5873
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
5874
				if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
5875
					$defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
5876
				} else {
5877
					$defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
5878
				}
5879
			}
5880
5881
			// Disabled if seller is not subject to VAT
5882
			$disabled = false;
5883
			$title = '';
5884
			if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
5885
				// Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
5886
				// of using supplier invoices (this is a very bad idea !)
5887
				if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) {
5888
					$title = ' title="'.$langs->trans('VATIsNotUsed').'"';
5889
					$disabled = true;
5890
				}
5891
			}
5892
5893
			if (!$options_only) {
5894
				$return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
5895
			}
5896
5897
			$selectedfound = false;
5898
			foreach ($this->cache_vatrates as $rate) {
5899
				// Keep only 0 if seller is not subject to VAT
5900
				if ($disabled && $rate['txtva'] != 0) {
5901
					continue;
5902
				}
5903
5904
				// Define key to use into select list
5905
				$key = $rate['txtva'];
5906
				$key .= $rate['nprtva'] ? '*' : '';
5907
				if ($mode > 0 && $rate['code']) {
5908
					$key .= ' ('.$rate['code'].')';
5909
				}
5910
				if ($mode < 0) {
5911
					$key = $rate['rowid'];
5912
				}
5913
5914
				$return .= '<option value="'.$key.'"';
5915
				if (!$selectedfound) {
5916
					if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
5917
						if ($defaultcode == $rate['code']) {
5918
							$return .= ' selected';
5919
							$selectedfound = true;
5920
						}
5921
					} elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
5922
						$return .= ' selected';
5923
						$selectedfound = true;
5924
					}
5925
				}
5926
				$return .= '>';
5927
				//if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
5928
				if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) {
5929
					$return .= $rate['labelpositiverates'];
5930
				} else {
5931
					$return .= vatrate($rate['label']);
5932
				}
5933
				//$return.=($rate['code']?' '.$rate['code']:'');
5934
				$return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the *  (old behaviour only if new vat code is not used)
5935
5936
				$return .= '</option>';
5937
			}
5938
5939
			if (!$options_only) {
5940
				$return .= '</select>';
5941
			}
5942
		} else {
5943
			$return .= $this->error;
5944
		}
5945
5946
		$this->num = $num;
5947
		return $return;
5948
	}
5949
5950
5951
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5952
	/**
5953
	 *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5954
	 *  Fields are preselected with :
5955
	 *            	- set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5956
	 *            	- local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5957
	 *            	- Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5958
	 *
5959
	 *	@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).
5960
	 *	@param	string		$prefix			Prefix for fields name
5961
	 *	@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
5962
	 *	@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
5963
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5964
	 *	@param	string		$form_name 		Not used
5965
	 *	@param	int			$d				1=Show days, month, years
5966
	 * 	@param	int			$addnowlink		Add a link "Now"
5967
	 * 	@param	int			$nooutput		Do not output html string but return it
5968
	 * 	@param 	int			$disabled		Disable input fields
5969
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
5970
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another select_date field.
5971
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
5972
	 *  @return	string|void					Nothing or string if nooutput is 1
5973
	 *  @deprecated
5974
	 *  @see    selectDate(), form_date(), select_month(), select_year(), select_dayofweek()
5975
	 */
5976
	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 = '')
5977
	{
5978
		// phpcs:enable
5979
		$retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
5980
		if (!empty($nooutput)) {
5981
			return $retstring;
5982
		}
5983
		print $retstring;
5984
		return;
5985
	}
5986
5987
	/**
5988
	 *  Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5989
	 *  Fields are preselected with :
5990
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5991
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5992
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5993
	 *
5994
	 *  @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).
5995
	 *  @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).
5996
	 *  @param	string		$prefix			Prefix for fields name
5997
	 *  @param	string		$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5998
	 * 	@return string                      Html for selectDate
5999
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
6000
	 */
6001
	public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0)
6002
	{
6003
		global $langs;
6004
6005
		$ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
6006
		$ret .= '<br>';
6007
		$ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
6008
		return $ret;
6009
	}
6010
6011
	/**
6012
	 *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
6013
	 *  Fields are preselected with :
6014
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
6015
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
6016
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
6017
	 *
6018
	 *  @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).
6019
	 *  @param	string		$prefix			Prefix for fields name
6020
	 *  @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
6021
	 *	@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
6022
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
6023
	 *	@param	string		$form_name 		Not used
6024
	 *	@param	int			$d				1=Show days, month, years
6025
	 * 	@param	int			$addnowlink		Add a link "Now", 1 with server time, 2 with local computer time
6026
	 * 	@param 	int			$disabled		Disable input fields
6027
	 *  @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')
6028
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another selectDate field.
6029
	 *  @param  datetime    $adddateof      Add a link "Date of ..." using the following date. See also $labeladddateof for the label used.
6030
	 *  @param  string      $openinghours   Specify hour start and hour end for the select ex 8,20
6031
	 *  @param  int         $stepminutes    Specify step for minutes between 1 and 30
6032
	 *  @param	string		$labeladddateof Label to use for the $adddateof parameter.
6033
	 *  @param	string 		$placeholder    Placeholder
6034
	 *  @param	mixed		$gm				'auto' (for backward compatibility, avoid this), 'gmt' or 'tzserver' or 'tzuserrel'
6035
	 * 	@return string                      Html for selectDate
6036
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
6037
	 */
6038
	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')
6039
	{
6040
		global $conf, $langs;
6041
6042
		if ($gm === 'auto') {
6043
			$gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
6044
		}
6045
6046
		$retstring = '';
6047
6048
		if ($prefix == '') {
6049
			$prefix = 're';
6050
		}
6051
		if ($h == '') {
6052
			$h = 0;
6053
		}
6054
		if ($m == '') {
6055
			$m = 0;
6056
		}
6057
		$emptydate = 0;
6058
		$emptyhours = 0;
6059
		if ($stepminutes <= 0 || $stepminutes > 30) {
6060
			$stepminutes = 1;
6061
		}
6062
		if ($empty == 1) {
6063
			$emptydate = 1;
6064
			$emptyhours = 1;
6065
		}
6066
		if ($empty == 2) {
6067
			$emptydate = 0;
6068
			$emptyhours = 1;
6069
		}
6070
		$orig_set_time = $set_time;
6071
6072
		if ($set_time === '' && $emptydate == 0) {
6073
			include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6074
			if ($gm == 'tzuser' || $gm == 'tzuserrel') {
6075
				$set_time = dol_now($gm);
6076
			} else {
6077
				$set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
6078
			}
6079
		}
6080
6081
		// Analysis of the pre-selection date
6082
		$reg = array();
6083
		if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) {	// deprecated usage
6084
			// Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
6085
			$syear	= (!empty($reg[1]) ? $reg[1] : '');
6086
			$smonth = (!empty($reg[2]) ? $reg[2] : '');
6087
			$sday	= (!empty($reg[3]) ? $reg[3] : '');
6088
			$shour	= (!empty($reg[4]) ? $reg[4] : '');
6089
			$smin	= (!empty($reg[5]) ? $reg[5] : '');
6090
		} elseif (strval($set_time) != '' && $set_time != -1) {
6091
			// set_time est un timestamps (0 possible)
6092
			$syear = dol_print_date($set_time, "%Y", $gm);
6093
			$smonth = dol_print_date($set_time, "%m", $gm);
6094
			$sday = dol_print_date($set_time, "%d", $gm);
6095
			if ($orig_set_time != '') {
6096
				$shour = dol_print_date($set_time, "%H", $gm);
6097
				$smin = dol_print_date($set_time, "%M", $gm);
6098
				$ssec = dol_print_date($set_time, "%S", $gm);
6099
			} else {
6100
				$shour = '';
6101
				$smin = '';
6102
				$ssec = '';
6103
			}
6104
		} else {
6105
			// Date est '' ou vaut -1
6106
			$syear = '';
6107
			$smonth = '';
6108
			$sday = '';
6109
			$shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
6110
			$smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
6111
			$ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
6112
		}
6113
		if ($h == 3) {
6114
			$shour = '';
6115
		}
6116
		if ($m == 3) {
6117
			$smin = '';
6118
		}
6119
6120
		$nowgmt = dol_now('gmt');
6121
		//var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
6122
6123
		// You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
6124
		$usecalendar = 'combo';
6125
		if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
6126
			$usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
6127
		}
6128
6129
		if ($d) {
6130
			// Show date with popup
6131
			if ($usecalendar != 'combo') {
6132
				$formated_date = '';
6133
				//print "e".$set_time." t ".$conf->format_date_short;
6134
				if (strval($set_time) != '' && $set_time != -1) {
6135
					//$formated_date=dol_print_date($set_time,$conf->format_date_short);
6136
					$formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6137
				}
6138
6139
				// Calendrier popup version eldy
6140
				if ($usecalendar == "eldy") {
6141
					// Input area to enter date manually
6142
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6143
					$retstring .= ($disabled ? ' disabled' : '');
6144
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6145
					$retstring .= '>';
6146
6147
					// Icon calendar
6148
					$retstringbuttom = '';
6149
					if (!$disabled) {
6150
						$retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
6151
						$base = DOL_URL_ROOT.'/core/';
6152
						$retstringbuttom .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
6153
						$retstringbuttom .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
6154
					} else {
6155
						$retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6156
					}
6157
					$retstring = $retstringbuttom.$retstring;
6158
6159
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
6160
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6161
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
6162
				} elseif ($usecalendar == 'jquery') {
6163
					if (!$disabled) {
6164
						// Output javascript for datepicker
6165
						$retstring .= "<script type='text/javascript'>";
6166
						$retstring .= "$(function(){ $('#".$prefix."').datepicker({
6167
							dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
6168
							autoclose: true,
6169
							todayHighlight: true,";
6170
						if (!empty($conf->dol_use_jmobile)) {
6171
							$retstring .= "
6172
								beforeShow: function (input, datePicker) {
6173
									input.disabled = true;
6174
								},
6175
								onClose: function (dateText, datePicker) {
6176
									this.disabled = false;
6177
								},
6178
								";
6179
						}
6180
						// Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
6181
						if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) {
6182
							$retstring .= "
6183
								showOn: 'button',	/* both has problem with autocompletion */
6184
								buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png',
6185
								buttonImageOnly: true";
6186
						}
6187
						$retstring .= "
6188
							}) });";
6189
						$retstring .= "</script>";
6190
					}
6191
6192
					// Zone de saisie manuelle de la date
6193
					$retstring .= '<div class="nowrap inline-block divfordateinput">';
6194
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
6195
					$retstring .= ($disabled ? ' disabled' : '');
6196
					$retstring .= ($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '');
6197
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
6198
					$retstring .= '>';
6199
6200
					// Icone calendrier
6201
					if (!$disabled) {
6202
						/* Not required. Managed by option buttonImage of jquery
6203
						$retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
6204
						$retstring.="<script type='text/javascript'>";
6205
						$retstring.="jQuery(document).ready(function() {";
6206
						$retstring.='	jQuery("#'.$prefix.'id").click(function() {';
6207
						$retstring.="    	jQuery('#".$prefix."').focus();";
6208
						$retstring.='    });';
6209
						$retstring.='});';
6210
						$retstring.="</script>";*/
6211
					} else {
6212
						$retstringbutton = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
6213
						$retsring = $retstringbutton.$retstring;
6214
					}
6215
6216
					$retstring .= '</div>';
6217
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
6218
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
6219
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
6220
				} else {
6221
					$retstring .= "Bad value of MAIN_POPUP_CALENDAR";
6222
				}
6223
			} else {
6224
				// Show date with combo selects
6225
				// Day
6226
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
6227
6228
				if ($emptydate || $set_time == -1) {
6229
					$retstring .= '<option value="0" selected>&nbsp;</option>';
6230
				}
6231
6232
				for ($day = 1; $day <= 31; $day++) {
6233
					$retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
6234
				}
6235
6236
				$retstring .= "</select>";
6237
6238
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
6239
				if ($emptydate || $set_time == -1) {
6240
					$retstring .= '<option value="0" selected>&nbsp;</option>';
6241
				}
6242
6243
				// Month
6244
				for ($month = 1; $month <= 12; $month++) {
6245
					$retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
6246
					$retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
6247
					$retstring .= "</option>";
6248
				}
6249
				$retstring .= "</select>";
6250
6251
				// Year
6252
				if ($emptydate || $set_time == -1) {
6253
					$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.'">';
6254
				} else {
6255
					$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
6256
6257
					for ($year = $syear - 10; $year < $syear + 10; $year++) {
6258
						$retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
6259
					}
6260
					$retstring .= "</select>\n";
6261
				}
6262
			}
6263
		}
6264
6265
		if ($d && $h) {
6266
			$retstring .= ($h == 2 ? '<br>' : ' ');
6267
			$retstring .= '<span class="nowraponall">';
6268
		}
6269
6270
		if ($h) {
6271
			$hourstart = 0;
6272
			$hourend = 24;
6273
			if ($openinghours != '') {
6274
				$openinghours = explode(',', $openinghours);
6275
				$hourstart = $openinghours[0];
6276
				$hourend = $openinghours[1];
6277
				if ($hourend < $hourstart) {
6278
					$hourend = $hourstart;
6279
				}
6280
			}
6281
			// Show hour
6282
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
6283
			if ($emptyhours) {
6284
				$retstring .= '<option value="-1">&nbsp;</option>';
6285
			}
6286
			for ($hour = $hourstart; $hour < $hourend; $hour++) {
6287
				if (strlen($hour) < 2) {
6288
					$hour = "0".$hour;
6289
				}
6290
				$retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour;
6291
				//$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H');
6292
				$retstring .= '</option>';
6293
			}
6294
			$retstring .= '</select>';
6295
			//if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
6296
			if ($m) {
6297
				$retstring .= ":";
6298
			}
6299
		}
6300
6301
		if ($m) {
6302
			// Show minutes
6303
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
6304
			if ($emptyhours) {
6305
				$retstring .= '<option value="-1">&nbsp;</option>';
6306
			}
6307
			for ($min = 0; $min < 60; $min += $stepminutes) {
6308
				if (strlen($min) < 2) {
6309
					$min = "0".$min;
6310
				}
6311
				$retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
6312
			}
6313
			$retstring .= '</select>';
6314
6315
			$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...
6316
		}
6317
6318
		if ($d && $h) {
6319
			$retstring .= '</span>';
6320
		}
6321
6322
		// Add a "Now" link
6323
		if ($conf->use_javascript_ajax && $addnowlink) {
6324
			// Script which will be inserted in the onClick of the "Now" link
6325
			$reset_scripts = "";
6326
			if ($addnowlink == 2) { // local computer time
6327
				// pad add leading 0 on numbers
6328
				$reset_scripts .= "Number.prototype.pad = function(size) {
6329
                        var s = String(this);
6330
                        while (s.length < (size || 2)) {s = '0' + s;}
6331
                        return s;
6332
                    };
6333
                    var d = new Date();";
6334
			}
6335
6336
			// Generate the date part, depending on the use or not of the javascript calendar
6337
			if ($addnowlink == 1) { // server time expressed in user time setup
6338
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6339
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6340
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6341
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6342
			} elseif ($addnowlink == 2) {
6343
				/* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
6344
				 * This break application for foreign languages.
6345
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
6346
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
6347
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
6348
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
6349
				*/
6350
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');';
6351
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6352
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6353
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6354
			}
6355
			/*if ($usecalendar == "eldy")
6356
			{
6357
				$base=DOL_URL_ROOT.'/core/';
6358
				$reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
6359
			}
6360
			else
6361
			{
6362
				$reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
6363
				$reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
6364
				$reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
6365
			}*/
6366
			// Update the hour part
6367
			if ($h) {
6368
				if ($fullday) {
6369
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6370
				}
6371
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
6372
				if ($addnowlink == 1) {
6373
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6374
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6375
				} elseif ($addnowlink == 2) {
6376
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
6377
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
6378
				}
6379
6380
				if ($fullday) {
6381
					$reset_scripts .= ' } ';
6382
				}
6383
			}
6384
			// Update the minute part
6385
			if ($m) {
6386
				if ($fullday) {
6387
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6388
				}
6389
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
6390
				if ($addnowlink == 1) {
6391
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6392
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6393
				} elseif ($addnowlink == 2) {
6394
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
6395
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
6396
				}
6397
				if ($fullday) {
6398
					$reset_scripts .= ' } ';
6399
				}
6400
			}
6401
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6402
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6403
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
6404
				$retstring .= $langs->trans("Now");
6405
				$retstring .= '</button> ';
6406
			}
6407
		}
6408
6409
		// Add a "Plus one hour" link
6410
		if ($conf->use_javascript_ajax && $addplusone) {
6411
			// Script which will be inserted in the onClick of the "Add plusone" link
6412
			$reset_scripts = "";
6413
6414
			// Generate the date part, depending on the use or not of the javascript calendar
6415
			$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');';
6416
			$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');';
6417
			$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');';
6418
			$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');';
6419
			// Update the hour part
6420
			if ($h) {
6421
				if ($fullday) {
6422
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6423
				}
6424
				$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');';
6425
				if ($fullday) {
6426
					$reset_scripts .= ' } ';
6427
				}
6428
			}
6429
			// Update the minute part
6430
			if ($m) {
6431
				if ($fullday) {
6432
					$reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
6433
				}
6434
				$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');';
6435
				if ($fullday) {
6436
					$reset_scripts .= ' } ';
6437
				}
6438
			}
6439
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
6440
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
6441
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
6442
				$retstring .= $langs->trans("DateStartPlusOne");
6443
				$retstring .= '</button> ';
6444
			}
6445
		}
6446
6447
		// Add a link to set data
6448
		if ($conf->use_javascript_ajax && $adddateof) {
6449
			$tmparray = dol_getdate($adddateof);
6450
			if (empty($labeladddateof)) {
6451
				$labeladddateof = $langs->trans("DateInvoice");
6452
			}
6453
			$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>';
6454
		}
6455
6456
		return $retstring;
6457
	}
6458
6459
	/**
6460
	 * selectTypeDuration
6461
	 *
6462
	 * @param   string   	$prefix     	Prefix
6463
	 * @param   string   	$selected   	Selected duration type
6464
	 * @param	array		$excludetypes	Array of duration types to exclude. Example array('y', 'm')
6465
	 * @return  string      	         	HTML select string
6466
	 */
6467
	public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
6468
	{
6469
		global $langs;
6470
6471
		$TDurationTypes = array(
6472
			'y'=>$langs->trans('Years'),
6473
			'm'=>$langs->trans('Month'),
6474
			'w'=>$langs->trans('Weeks'),
6475
			'd'=>$langs->trans('Days'),
6476
			'h'=>$langs->trans('Hours'),
6477
			'i'=>$langs->trans('Minutes')
6478
		);
6479
6480
		// Removed undesired duration types
6481
		foreach ($excludetypes as $value) {
6482
			unset($TDurationTypes[$value]);
6483
		}
6484
6485
		$retstring = '<select class="flat" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
6486
		foreach ($TDurationTypes as $key => $typeduration) {
6487
			$retstring .= '<option value="'.$key.'"';
6488
			if ($key == $selected) {
6489
				$retstring .= " selected";
6490
			}
6491
			$retstring .= ">".$typeduration."</option>";
6492
		}
6493
		$retstring .= "</select>";
6494
6495
		$retstring .= ajax_combobox('select_'.$prefix.'type_duration');
6496
6497
		return $retstring;
6498
	}
6499
6500
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6501
	/**
6502
	 *  Function to show a form to select a duration on a page
6503
	 *
6504
	 *	@param	string		$prefix   		Prefix for input fields
6505
	 *	@param  int			$iSecond  		Default preselected duration (number of seconds or '')
6506
	 * 	@param	int			$disabled       Disable the combo box
6507
	 * 	@param	string		$typehour		If 'select' then input hour and input min is a combo,
6508
	 *						            	If 'text' input hour is in text and input min is a text,
6509
	 *						            	If 'textselect' input hour is in text and input min is a combo
6510
	 *  @param	integer		$minunderhours	If 1, show minutes selection under the hours
6511
	 * 	@param	int			$nooutput		Do not output html string but return it
6512
	 *  @return	string|void
6513
	 */
6514
	public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
6515
	{
6516
		// phpcs:enable
6517
		global $langs;
6518
6519
		$retstring = '';
6520
6521
		$hourSelected = 0;
6522
		$minSelected = 0;
6523
6524
		// Hours
6525
		if ($iSecond != '') {
6526
			require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
6527
6528
			$hourSelected = convertSecondToTime($iSecond, 'allhour');
6529
			$minSelected = convertSecondToTime($iSecond, 'min');
6530
		}
6531
6532
		if ($typehour == 'select') {
6533
			$retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
6534
			for ($hour = 0; $hour < 25; $hour++) {	// For a duration, we allow 24 hours
6535
				$retstring .= '<option value="'.$hour.'"';
6536
				if ($hourSelected == $hour) {
6537
					$retstring .= " selected";
6538
				}
6539
				$retstring .= ">".$hour."</option>";
6540
			}
6541
			$retstring .= "</select>";
6542
		} elseif ($typehour == 'text' || $typehour == 'textselect') {
6543
			$retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
6544
		} else {
6545
			return 'BadValueForParameterTypeHour';
6546
		}
6547
6548
		if ($typehour != 'text') {
6549
			$retstring .= ' '.$langs->trans('HourShort');
6550
		} else {
6551
			$retstring .= '<span class="hideonsmartphone">:</span>';
6552
		}
6553
6554
		// Minutes
6555
		if ($minunderhours) {
6556
			$retstring .= '<br>';
6557
		} else {
6558
			$retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
6559
		}
6560
6561
		if ($typehour == 'select' || $typehour == 'textselect') {
6562
			$retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
6563
			for ($min = 0; $min <= 55; $min = $min + 5) {
6564
				$retstring .= '<option value="'.$min.'"';
6565
				if ($minSelected == $min) {
6566
					$retstring .= ' selected';
6567
				}
6568
				$retstring .= '>'.$min.'</option>';
6569
			}
6570
			$retstring .= "</select>";
6571
		} elseif ($typehour == 'text') {
6572
			$retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
6573
		}
6574
6575
		if ($typehour != 'text') {
6576
			$retstring .= ' '.$langs->trans('MinuteShort');
6577
		}
6578
6579
		//$retstring.="&nbsp;";
6580
6581
		if (!empty($nooutput)) {
6582
			return $retstring;
6583
		}
6584
6585
		print $retstring;
6586
		return;
6587
	}
6588
6589
	/**
6590
	 *  Return list of tickets in Ajax if Ajax activated or go to selectTicketsList
6591
	 *
6592
	 *  @param		int			$selected				Preselected tickets
6593
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page).
6594
	 *  @param  	string		$filtertype     		To add a filter
6595
	 *  @param		int			$limit					Limit on number of returned lines
6596
	 *  @param		int			$status					Ticket status
6597
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
6598
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
6599
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
6600
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
6601
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
6602
	 * 	@param		int			$forcecombo				Force to use combo box
6603
	 *  @param      string      $morecss                Add more css on select
6604
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
6605
	 *  @param		string		$nooutput				No print, return the output into a string
6606
	 *  @return		void|string
6607
	 */
6608
	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)
6609
	{
6610
		global $langs, $conf;
6611
6612
		$out = '';
6613
6614
		// check parameters
6615
		if (is_null($ajaxoptions)) $ajaxoptions = array();
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
6616
6617
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
6618
			$placeholder = '';
6619
6620
			if ($selected && empty($selected_input_value)) {
6621
				require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
6622
				$tickettmpselect = new Ticket($this->db);
6623
				$tickettmpselect->fetch($selected);
6624
				$selected_input_value = $tickettmpselect->ref;
6625
				unset($tickettmpselect);
6626
			}
6627
6628
			$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...
6629
6630
			if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
6631
			elseif ($hidelabel > 1) {
6632
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
6633
				if ($hidelabel == 2) {
6634
					$out .= img_picto($langs->trans("Search"), 'search');
6635
				}
6636
			}
6637
			$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
6638
			if ($hidelabel == 3) {
6639
				$out .= img_picto($langs->trans("Search"), 'search');
6640
			}
6641
		} else {
6642
			$out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, $status, 0, $socid, $showempty, $forcecombo, $morecss);
6643
		}
6644
6645
		if (empty($nooutput)) print $out;
6646
		else return $out;
6647
	}
6648
6649
6650
	/**
6651
	 *	Return list of tickets.
6652
	 *  Called by selectTickets.
6653
	 *
6654
	 *	@param      int		$selected           Preselected ticket
6655
	 *	@param      string	$htmlname           Name of select html
6656
	 *  @param		string	$filtertype         Filter on ticket type
6657
	 *	@param      int		$limit              Limit on number of returned lines
6658
	 * 	@param      string	$filterkey          Filter on product
6659
	 *	@param		int		$status             Ticket status
6660
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
6661
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
6662
	 * 	@param		int		$forcecombo		    Force to use combo box
6663
	 *  @param      string  $morecss            Add more css on select
6664
	 *  @return     array    				    Array of keys for json
6665
	 */
6666
	public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
6667
	{
6668
		global $langs, $conf, $user, $db;
6669
6670
		$out = '';
6671
		$outarray = array();
6672
6673
		$selectFields = " p.rowid, p.ref, p.message";
6674
6675
		$sql = "SELECT ";
6676
		$sql .= $selectFields;
6677
		$sql .= " FROM ".MAIN_DB_PREFIX."ticket as p";
6678
		$sql .= ' WHERE p.entity IN ('.getEntity('ticket').')';
6679
6680
		// Add criteria on ref/label
6681
		if ($filterkey != '') {
6682
			$sql .= ' AND (';
6683
			$prefix = empty($conf->global->TICKET_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
6684
			// For natural search
6685
			$scrit = explode(' ', $filterkey);
6686
			$i = 0;
6687
			if (count($scrit) > 1) $sql .= "(";
6688
			foreach ($scrit as $crit) {
6689
				if ($i > 0) $sql .= " AND ";
6690
				$sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
6691
				$sql .= ")";
6692
				$i++;
6693
			}
6694
			if (count($scrit) > 1) $sql .= ")";
6695
			$sql .= ')';
6696
		}
6697
6698
		$sql .= $this->db->plimit($limit, 0);
6699
6700
		// Build output string
6701
		dol_syslog(get_class($this)."::selectTicketsList search tickets", LOG_DEBUG);
6702
		$result = $this->db->query($sql);
6703
		if ($result) {
6704
			require_once DOL_DOCUMENT_ROOT.'/ticket/class/ticket.class.php';
6705
			require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php';
6706
6707
			$num = $this->db->num_rows($result);
6708
6709
			$events = null;
6710
6711
			if (!$forcecombo) {
6712
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6713
				$out .= ajax_combobox($htmlname, $events, $conf->global->TICKET_USE_SEARCH_TO_SELECT);
6714
			}
6715
6716
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
6717
6718
			$textifempty = '';
6719
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
6720
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
6721
			if (!empty($conf->global->TICKET_USE_SEARCH_TO_SELECT)) {
6722
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6723
				else $textifempty .= $langs->trans("All");
6724
			} else {
6725
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6726
			}
6727
			if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
6728
6729
			$i = 0;
6730
			while ($num && $i < $num) {
6731
				$opt = '';
6732
				$optJson = array();
6733
				$objp = $this->db->fetch_object($result);
6734
6735
				$this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
6736
				// Add new entry
6737
				// "key" value of json key array is used by jQuery automatically as selected value
6738
				// "label" value of json key array is used by jQuery automatically as text for combo box
6739
				$out .= $opt;
6740
				array_push($outarray, $optJson);
6741
6742
				$i++;
6743
			}
6744
6745
			$out .= '</select>';
6746
6747
			$this->db->free($result);
6748
6749
			if (empty($outputmode)) return $out;
6750
			return $outarray;
6751
		} else {
6752
			dol_print_error($db);
6753
		}
6754
	}
6755
6756
	/**
6757
	 * constructTicketListOption.
6758
	 * This define value for &$opt and &$optJson.
6759
	 *
6760
	 * @param 	resource	$objp			    Result set of fetch
6761
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
6762
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
6763
	 * @param 	string		$selected		    Preselected value
6764
	 * @param   string      $filterkey          Filter key to highlight
6765
	 * @return	void
6766
	 */
6767
	protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
6768
	{
6769
		global $langs, $conf, $user, $db;
6770
6771
		$outkey = '';
6772
		$outval = '';
6773
		$outref = '';
6774
		$outlabel = '';
6775
		$outtype = '';
6776
6777
		$label = $objp->label;
6778
6779
		$outkey = $objp->rowid;
6780
		$outref = $objp->ref;
6781
		$outlabel = $objp->label;
6782
		$outtype = $objp->fk_product_type;
6783
6784
		$opt = '<option value="'.$objp->rowid.'"';
6785
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
6786
		$opt .= '>';
6787
		$opt .= $objp->ref;
6788
		$objRef = $objp->ref;
6789
		if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
6790
		$outval .= $objRef;
6791
6792
		$opt .= "</option>\n";
6793
		$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...
6794
	}
6795
6796
6797
	/**
6798
	 * Generic method to select a component from a combo list.
6799
	 * Can use autocomplete with ajax after x key pressed or a full combo, depending on setup.
6800
	 * This is the generic method that will replace all specific existing methods.
6801
	 *
6802
	 * @param 	string			$objectdesc			ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]
6803
	 * @param	string			$htmlname			Name of HTML select component
6804
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
6805
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
6806
	 * @param	string			$searchkey			Search criteria
6807
	 * @param	string			$placeholder		Place holder
6808
	 * @param	string			$morecss			More CSS
6809
	 * @param	string			$moreparams			More params provided to ajax call
6810
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
6811
	 * @param	int				$disabled			1=Html component is disabled
6812
	 * @param	string	        $selected_input_value	Value of preselected input text (for use with ajax)
6813
	 * @return	string								Return HTML string
6814
	 * @see selectForFormsList() select_thirdparty_list()
6815
	 */
6816
	public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
6817
	{
6818
		global $conf, $user;
6819
6820
		$objecttmp = null;
6821
6822
		$InfoFieldList = explode(":", $objectdesc);
6823
		$classname = $InfoFieldList[0];
6824
		$classpath = $InfoFieldList[1];
6825
		$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
6826
		$filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
6827
6828
		if (!empty($classpath)) {
6829
			dol_include_once($classpath);
6830
6831
			if ($classname && class_exists($classname)) {
6832
				$objecttmp = new $classname($this->db);
6833
				// Make some replacement
6834
				$sharedentities = getEntity(strtolower($classname));
6835
				$objecttmp->filter = str_replace(
6836
					array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
6837
					array($conf->entity, $sharedentities, $user->id),
6838
					$filter
6839
				);
6840
			}
6841
		}
6842
		if (!is_object($objecttmp)) {
6843
			dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
6844
			return 'Error bad setup of type for field '.join(',', $InfoFieldList);
6845
		}
6846
6847
		//var_dump($objecttmp->filter);
6848
		$prefixforautocompletemode = $objecttmp->element;
6849
		if ($prefixforautocompletemode == 'societe') {
6850
			$prefixforautocompletemode = 'company';
6851
		}
6852
		if ($prefixforautocompletemode == 'product') {
6853
			$prefixforautocompletemode = 'produit';
6854
		}
6855
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
6856
6857
		dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG);
6858
		$out = '';
6859
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo) {
6860
			// No immediate load of all database
6861
			$placeholder = '';
6862
			if ($preselectedvalue && empty($selected_input_value)) {
6863
				$objecttmp->fetch($preselectedvalue);
6864
				$selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
6865
				//unset($objecttmp);
6866
			}
6867
6868
			$objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
6869
			$urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
6870
6871
			// No immediate load of all database
6872
			$urloption = 'htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.'&filter='.urlencode($objecttmp->filter);
6873
			// Activate the auto complete using ajax call.
6874
			$out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
6875
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>';
6876
			$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).'"' : '') .' />';
6877
		} else {
6878
			// Immediate load of table record. Note: filter is inside $objecttmp->filter
6879
			$out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled);
6880
		}
6881
6882
		return $out;
6883
	}
6884
6885
	/**
6886
	 * Function to forge a SQL criteria
6887
	 *
6888
	 * @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"
6889
	 * @return string                  Forged criteria. Example: "t.field like 'abc%'"
6890
	 */
6891
	protected static function forgeCriteriaCallback($matches)
6892
	{
6893
		global $db;
6894
6895
		//dol_syslog("Convert matches ".$matches[1]);
6896
		if (empty($matches[1])) {
6897
			return '';
6898
		}
6899
		$tmp = explode(':', $matches[1]);
6900
		if (count($tmp) < 3) {
6901
			return '';
6902
		}
6903
6904
		$tmpescaped = $tmp[2];
6905
		$regbis = array();
6906
		if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
6907
			$tmpescaped = "'".$db->escape($regbis[1])."'";
6908
		} else {
6909
			$tmpescaped = $db->escape($tmpescaped);
6910
		}
6911
		return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
6912
	}
6913
6914
	/**
6915
	 * Output html form to select an object.
6916
	 * Note, this function is called by selectForForms or by ajax selectobject.php
6917
	 *
6918
	 * @param 	Object			$objecttmp			Object to knwo the table to scan for combo.
6919
	 * @param	string			$htmlname			Name of HTML select component
6920
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
6921
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
6922
	 * @param	string			$searchkey			Search value
6923
	 * @param	string			$placeholder		Place holder
6924
	 * @param	string			$morecss			More CSS
6925
	 * @param	string			$moreparams			More params provided to ajax call
6926
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
6927
	 * @param	int				$outputmode			0=HTML select string, 1=Array
6928
	 * @param	int				$disabled			1=Html component is disabled
6929
	 * @return	string|array						Return HTML string
6930
	 * @see selectForForms()
6931
	 */
6932
	public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0)
6933
	{
6934
		global $conf, $langs, $user, $hookmanager;
6935
6936
		//print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled";
6937
6938
		$prefixforautocompletemode = $objecttmp->element;
6939
		if ($prefixforautocompletemode == 'societe') {
6940
			$prefixforautocompletemode = 'company';
6941
		}
6942
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
6943
6944
		if (!empty($objecttmp->fields)) {	// For object that declare it, it is better to use declared fields (like societe, contact, ...)
6945
			$tmpfieldstoshow = '';
6946
			foreach ($objecttmp->fields as $key => $val) {
6947
				if (!dol_eval($val['enabled'], 1, 1)) {
6948
					continue;
6949
				}
6950
				if (!empty($val['showoncombobox'])) {
6951
					$tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
6952
				}
6953
			}
6954
			if ($tmpfieldstoshow) {
6955
				$fieldstoshow = $tmpfieldstoshow;
6956
			}
6957
		} else {
6958
			// For backward compatibility
6959
			$objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
6960
		}
6961
6962
		if (empty($fieldstoshow)) {
6963
			if (isset($objecttmp->fields['ref'])) {
6964
				$fieldstoshow = 't.ref';
6965
			} else {
6966
				$langs->load("errors");
6967
				$this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
6968
				return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
6969
			}
6970
		}
6971
6972
		$out = '';
6973
		$outarray = array();
6974
6975
		$num = 0;
6976
6977
		// Search data
6978
		$sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX.$objecttmp->table_element." as t";
6979
		if (isset($objecttmp->ismultientitymanaged)) {
6980
			if (!is_numeric($objecttmp->ismultientitymanaged)) {
6981
				$tmparray = explode('@', $objecttmp->ismultientitymanaged);
6982
				$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.$tmparray[1].' as parenttable ON parenttable.rowid = t.'.$tmparray[0];
6983
			}
6984
			if ($objecttmp->ismultientitymanaged == 'fk_soc@societe') {
6985
				if (!$user->rights->societe->client->voir && !$user->socid) {
6986
					$sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
6987
				}
6988
			}
6989
		}
6990
6991
		// Add where from hooks
6992
		$parameters = array();
6993
		$reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
6994
		if (!empty($hookmanager->resPrint)) {
6995
			$sql .= $hookmanager->resPrint;
6996
		} else {
6997
			$sql .= " WHERE 1=1";
6998
			if (isset($objecttmp->ismultientitymanaged)) {
6999
				if ($objecttmp->ismultientitymanaged == 1) {
7000
					$sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
7001
				}
7002
				if (!is_numeric($objecttmp->ismultientitymanaged)) {
7003
					$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...
7004
				}
7005
				if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
7006
					if ($objecttmp->element == 'societe') {
7007
						$sql .= " AND t.rowid = ".$user->socid;
7008
					} else {
7009
						$sql .= " AND t.fk_soc = ".$user->socid;
7010
					}
7011
				}
7012
				if ($objecttmp->ismultientitymanaged == 'fk_soc@societe') {
7013
					if (!$user->rights->societe->client->voir && !$user->socid) {
7014
						$sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
7015
					}
7016
				}
7017
			}
7018
			if ($searchkey != '') {
7019
				$sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
7020
			}
7021
			if ($objecttmp->filter) {	 // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
7022
				/*if (! DolibarrApi::_checkFilters($objecttmp->filter))
7023
				{
7024
					throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter);
7025
				}*/
7026
				$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
7027
				$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")";
7028
			}
7029
		}
7030
		$sql .= $this->db->order($fieldstoshow, "ASC");
7031
		//$sql.=$this->db->plimit($limit, 0);
7032
		//print $sql;
7033
7034
		// Build output string
7035
		$resql = $this->db->query($sql);
7036
		if ($resql) {
7037
			// Construct $out and $outarray
7038
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
7039
7040
			// 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
7041
			$textifempty = '&nbsp;';
7042
7043
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7044
			if (!empty($conf->global->$confkeyforautocompletemode)) {
7045
				if ($showempty && !is_numeric($showempty)) {
7046
					$textifempty = $langs->trans($showempty);
7047
				} else {
7048
					$textifempty .= $langs->trans("All");
7049
				}
7050
			}
7051
			if ($showempty) {
7052
				$out .= '<option value="-1">'.$textifempty.'</option>'."\n";
7053
			}
7054
7055
			$num = $this->db->num_rows($resql);
7056
			$i = 0;
7057
			if ($num) {
7058
				while ($i < $num) {
7059
					$obj = $this->db->fetch_object($resql);
7060
					$label = '';
7061
					$tmparray = explode(',', $fieldstoshow);
7062
					$oldvalueforshowoncombobox = 0;
7063
					foreach ($tmparray as $key => $val) {
7064
						$val = preg_replace('/t\./', '', $val);
7065
						$label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
7066
						$label .= $obj->$val;
7067
						$oldvalueforshowoncombobox = $objecttmp->fields[$val]['showoncombobox'];
7068
					}
7069
					if (empty($outputmode)) {
7070
						if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
7071
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
7072
						} else {
7073
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
7074
						}
7075
					} else {
7076
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
7077
					}
7078
7079
					$i++;
7080
					if (($i % 10) == 0) {
7081
						$out .= "\n";
7082
					}
7083
				}
7084
			}
7085
7086
			$out .= '</select>'."\n";
7087
7088
			if (!$forcecombo) {
7089
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7090
				$out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0));
7091
			}
7092
		} else {
7093
			dol_print_error($this->db);
7094
		}
7095
7096
		$this->result = array('nbofelement'=>$num);
7097
7098
		if ($outputmode) {
7099
			return $outarray;
7100
		}
7101
		return $out;
7102
	}
7103
7104
7105
	/**
7106
	 *	Return a HTML select string, built from an array of key+value.
7107
	 *  Note: Do not apply langs->trans function on returned content, content may be entity encoded twice.
7108
	 *
7109
	 *	@param	string			$htmlname			Name of html select area. Must start with "multi" if this is a multiselect
7110
	 *	@param	array			$array				Array like array(key => value) or array(key=>array('label'=>..., 'data-...'=>..., 'disabled'=>..., 'css'=>...))
7111
	 *	@param	string|string[]	$id					Preselected key or preselected keys for multiselect
7112
	 *	@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.
7113
	 *	@param	int				$key_in_label		1 to show key into label with format "[key] value"
7114
	 *	@param	int				$value_as_key		1 to use value as key
7115
	 *	@param  string			$moreparam			Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
7116
	 *	@param  int				$translate			1=Translate and encode value
7117
	 * 	@param	int				$maxlen				Length maximum for labels
7118
	 * 	@param	int				$disabled			Html select box is disabled
7119
	 *  @param	string			$sort				'ASC' or 'DESC' = Sort on label, '' or 'NONE' or 'POS' = Do not sort, we keep original order
7120
	 *  @param	string			$morecss			Add more class to css styles
7121
	 *  @param	int				$addjscombo			Add js combo
7122
	 *  @param  string          $moreparamonempty	Add more param on the empty option line. Not used if show_empty not set
7123
	 *  @param  int             $disablebademail	1=Check if a not valid email, 2=Check string '---', and if found into value, disable and colorize entry
7124
	 *  @param  int             $nohtmlescape		No html escaping.
7125
	 * 	@return	string								HTML select string.
7126
	 *  @see multiselectarray(), selectArrayAjax(), selectArrayFilter()
7127
	 */
7128
	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)
7129
	{
7130
		global $conf, $langs;
7131
7132
		// Do we want a multiselect ?
7133
		//$jsbeautify = 0;
7134
		//if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
7135
		$jsbeautify = 1;
7136
7137
		if ($value_as_key) {
7138
			$array = array_combine($array, $array);
7139
		}
7140
7141
		$out = '';
7142
7143
		if ($addjscombo < 0) {
7144
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7145
				$addjscombo = 1;
7146
			} else {
7147
				$addjscombo = 0;
7148
			}
7149
		}
7150
7151
		// Add code for jquery to use multiselect
7152
		if ($addjscombo && $jsbeautify) {
7153
			// Enhance with select2
7154
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7155
			$out .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', $show_empty < 0 ? (string) $show_empty : '-1');
7156
		}
7157
7158
		$out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
7159
		$out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
7160
		$out .= '>';
7161
7162
		if ($show_empty) {
7163
			$textforempty = ' ';
7164
			if (!empty($conf->use_javascript_ajax)) {
7165
				$textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
7166
			}
7167
			if (!is_numeric($show_empty)) {
7168
				$textforempty = $show_empty;
7169
			}
7170
			$out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
7171
		}
7172
7173
		if (is_array($array)) {
7174
			// Translate
7175
			if ($translate) {
7176
				foreach ($array as $key => $value) {
7177
					if (!is_array($value)) {
7178
						$array[$key] = $langs->trans($value);
7179
					} else {
7180
						$array[$key]['label'] = $langs->trans($value['label']);
7181
					}
7182
				}
7183
			}
7184
7185
			// Sort
7186
			if ($sort == 'ASC') {
7187
				asort($array);
7188
			} elseif ($sort == 'DESC') {
7189
				arsort($array);
7190
			}
7191
7192
			foreach ($array as $key => $tmpvalue) {
7193
				if (is_array($tmpvalue)) {
7194
					$value = $tmpvalue['label'];
7195
					$disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
7196
					$style = empty($tmpvalue['css']) ? ' class="'.$tmpvalue['css'].'"' : '';
7197
				} else {
7198
					$value = $tmpvalue;
7199
					$disabled = '';
7200
					$style = '';
7201
				}
7202
				if (!empty($disablebademail)) {
7203
					if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
7204
						|| ($disablebademail == 2 && preg_match('/---/', $value))) {
7205
						$disabled = ' disabled';
7206
						$style = ' class="warning"';
7207
					}
7208
				}
7209
7210
				if ($key_in_label) {
7211
					if (empty($nohtmlescape)) {
7212
						$selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
7213
					} else {
7214
						$selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
7215
					}
7216
				} else {
7217
					if (empty($nohtmlescape)) {
7218
						$selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
7219
					} else {
7220
						$selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value;
7221
					}
7222
					if ($value == '' || $value == '-') {
7223
						$selectOptionValue = '&nbsp;';
7224
					}
7225
				}
7226
7227
				$out .= '<option value="'.$key.'"';
7228
				$out .= $style.$disabled;
7229
				if (is_array($id)) {
7230
					if (in_array($key, $id) && !$disabled) {
7231
						$out .= ' selected'; // To preselect a value
7232
					}
7233
				} else {
7234
					$id = (string) $id; // if $id = 0, then $id = '0'
7235
					if ($id != '' && $id == $key && !$disabled) {
7236
						$out .= ' selected'; // To preselect a value
7237
					}
7238
				}
7239
				if ($nohtmlescape) {
7240
					$out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
7241
				}
7242
				if (is_array($tmpvalue)) {
7243
					foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
7244
						if (preg_match('/^data-/', $keyforvalue)) {
7245
							$out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
7246
						}
7247
					}
7248
				}
7249
				$out .= '>';
7250
				//var_dump($selectOptionValue);
7251
				$out .= $selectOptionValue;
7252
				$out .= "</option>\n";
7253
			}
7254
		}
7255
7256
		$out .= "</select>";
7257
		return $out;
7258
	}
7259
7260
7261
	/**
7262
	 *	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.
7263
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
7264
	 *
7265
	 *	@param	string	$htmlname       		Name of html select area
7266
	 *	@param	string	$url					Url. Must return a json_encode of array(key=>array('text'=>'A text', 'url'=>'An url'), ...)
7267
	 *	@param	string	$id             		Preselected key
7268
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
7269
	 *	@param  string	$moreparamtourl 		Add more parameters onto the Ajax called URL
7270
	 * 	@param	int		$disabled				Html select box is disabled
7271
	 *  @param	int		$minimumInputLength		Minimum Input Length
7272
	 *  @param	string	$morecss				Add more class to css styles
7273
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
7274
	 *  @param  string  $placeholder            String to use as placeholder
7275
	 *  @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)
7276
	 * 	@return	string   						HTML select string
7277
	 *  @see selectArrayFilter(), ajax_combobox() in ajax.lib.php
7278
	 */
7279
	public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
7280
	{
7281
		global $conf, $langs;
7282
		global $delayedhtmlcontent;	// Will be used later outside of this function
7283
7284
		// TODO Use an internal dolibarr component instead of select2
7285
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
7286
			return '';
7287
		}
7288
7289
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
7290
7291
		$outdelayed = '';
7292
		if (!empty($conf->use_javascript_ajax)) {
7293
			$tmpplugin = 'select2';
7294
			$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
7295
		    	<script>
7296
		    	$(document).ready(function () {
7297
7298
	    	        '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
7299
7300
	                $(".'.$htmlname.'").select2({
7301
				    	ajax: {
7302
					    	dir: "ltr",
7303
					    	url: "'.$url.'",
7304
					    	dataType: \'json\',
7305
					    	delay: 250,
7306
					    	data: function (params) {
7307
					    		return {
7308
							    	q: params.term, 	// search term
7309
					    			page: params.page
7310
					    		};
7311
				    		},
7312
				    		processResults: function (data) {
7313
				    			// parse the results into the format expected by Select2.
7314
				    			// since we are using custom formatting functions we do not need to alter the remote JSON data
7315
				    			//console.log(data);
7316
								saveRemoteData = data;
7317
					    	    /* format json result for select2 */
7318
					    	    result = []
7319
					    	    $.each( data, function( key, value ) {
7320
					    	       result.push({id: key, text: value.text});
7321
	                            });
7322
				    			//return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
7323
				    			//console.log(result);
7324
				    			return {results: result, more: false}
7325
				    		},
7326
				    		cache: true
7327
				    	},
7328
		 				language: select2arrayoflanguage,
7329
						containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
7330
					    placeholder: "'.dol_escape_js($placeholder).'",
7331
				    	escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
7332
				    	minimumInputLength: '.$minimumInputLength.',
7333
				        formatResult: function(result, container, query, escapeMarkup) {
7334
	                        return escapeMarkup(result.text);
7335
	                    },
7336
				    });
7337
7338
	                '.($callurlonselect ? '
7339
	                /* Code to execute a GET when we select a value */
7340
	                $(".'.$htmlname.'").change(function() {
7341
				    	var selected = $(".'.$htmlname.'").val();
7342
	                	console.log("We select in selectArrayAjax the entry "+selected)
7343
				        $(".'.$htmlname.'").val("");  /* reset visible combo value */
7344
	    			    $.each( saveRemoteData, function( key, value ) {
7345
	    				        if (key == selected)
7346
	    			            {
7347
	    			                 console.log("selectArrayAjax - Do a redirect to "+value.url)
7348
	    			                 location.assign(value.url);
7349
	    			            }
7350
	                    });
7351
	    			});' : '').'
7352
7353
	    	   });
7354
		       </script>';
7355
		}
7356
7357
		if ($acceptdelayedhtml) {
7358
			$delayedhtmlcontent .= $outdelayed;
7359
		} else {
7360
			$out .= $outdelayed;
7361
		}
7362
		return $out;
7363
	}
7364
7365
	/**
7366
	 *  Return a HTML select string, built from an array of key+value, but content returned into select is defined into $array parameter.
7367
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
7368
	 *
7369
	 *  @param  string	$htmlname               Name of html select area
7370
	 *	@param	array	$array					Array (key=>array('text'=>'A text', 'url'=>'An url'), ...)
7371
	 *	@param	string	$id             		Preselected key
7372
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
7373
	 *	@param	int		$disableFiltering		If set to 1, results are not filtered with searched string
7374
	 * 	@param	int		$disabled				Html select box is disabled
7375
	 *  @param	int		$minimumInputLength		Minimum Input Length
7376
	 *  @param	string	$morecss				Add more class to css styles
7377
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
7378
	 *  @param  string  $placeholder            String to use as placeholder
7379
	 *  @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)
7380
	 *  @return	string   						HTML select string
7381
	 *  @see selectArrayAjax(), ajax_combobox() in ajax.lib.php
7382
	 */
7383
	public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
7384
	{
7385
		global $conf, $langs;
7386
		global $delayedhtmlcontent;	// Will be used later outside of this function
7387
7388
		// TODO Use an internal dolibarr component instead of select2
7389
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) {
7390
			return '';
7391
		}
7392
7393
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
7394
7395
		$formattedarrayresult = array();
7396
7397
		foreach ($array as $key => $value) {
7398
			$o = new stdClass();
7399
			$o->id = $key;
7400
			$o->text = $value['text'];
7401
			$o->url = $value['url'];
7402
			$formattedarrayresult[] = $o;
7403
		}
7404
7405
		$outdelayed = '';
7406
		if (!empty($conf->use_javascript_ajax)) {
7407
			$tmpplugin = 'select2';
7408
			$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
7409
				<script>
7410
				$(document).ready(function () {
7411
					var data = '.json_encode($formattedarrayresult).';
7412
7413
					'.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
7414
7415
					$(".'.$htmlname.'").select2({
7416
						data: data,
7417
						language: select2arrayoflanguage,
7418
						containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
7419
						placeholder: "'.dol_escape_js($placeholder).'",
7420
						escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
7421
						minimumInputLength: '.$minimumInputLength.',
7422
						formatResult: function(result, container, query, escapeMarkup) {
7423
							return escapeMarkup(result.text);
7424
						},
7425
						matcher: function (params, data) {
7426
7427
							if(! data.id) return null;';
7428
7429
			if ($callurlonselect) {
7430
				$outdelayed .= '
7431
7432
							var urlBase = data.url;
7433
							var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
7434
							/* console.log("params.term="+params.term); */
7435
							/* console.log("params.term encoded="+encodeURIComponent(params.term)); */
7436
							saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
7437
			}
7438
7439
			if (!$disableFiltering) {
7440
				$outdelayed .= '
7441
7442
							if(data.text.match(new RegExp(params.term))) {
7443
								return data;
7444
							}
7445
7446
							return null;';
7447
			} else {
7448
				$outdelayed .= '
7449
7450
							return data;';
7451
			}
7452
7453
			$outdelayed .= '
7454
						}
7455
					});
7456
7457
					'.($callurlonselect ? '
7458
					/* Code to execute a GET when we select a value */
7459
					$(".'.$htmlname.'").change(function() {
7460
						var selected = $(".'.$htmlname.'").val();
7461
						console.log("We select "+selected)
7462
7463
						$(".'.$htmlname.'").val("");  /* reset visible combo value */
7464
						$.each( saveRemoteData, function( key, value ) {
7465
							if (key == selected)
7466
							{
7467
								console.log("selectArrayFilter - Do a redirect to "+value.url)
7468
								location.assign(value.url);
7469
							}
7470
						});
7471
					});' : '').'
7472
7473
				});
7474
				</script>';
7475
		}
7476
7477
		if ($acceptdelayedhtml) {
7478
			$delayedhtmlcontent .= $outdelayed;
7479
		} else {
7480
			$out .= $outdelayed;
7481
		}
7482
		return $out;
7483
	}
7484
7485
	/**
7486
	 *	Show a multiselect form from an array. WARNING: Use this only for short lists.
7487
	 *
7488
	 *	@param	string	$htmlname		Name of select
7489
	 *	@param	array	$array			Array with key+value
7490
	 *	@param	array	$selected		Array with key+value preselected
7491
	 *	@param	int		$key_in_label   1 to show key like in "[key] value"
7492
	 *	@param	int		$value_as_key   1 to use value as key
7493
	 *	@param  string	$morecss        Add more css style
7494
	 *	@param  int		$translate		Translate and encode value
7495
	 *  @param	int		$width			Force width of select box. May be used only when using jquery couch. Example: 250, 95%
7496
	 *  @param	string	$moreattrib		Add more options on select component. Example: 'disabled'
7497
	 *  @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.
7498
	 *  @param	string	$placeholder	String to use as placeholder
7499
	 *  @param	int		$addjscombo		Add js combo
7500
	 *	@return	string					HTML multiselect string
7501
	 *  @see selectarray(), selectArrayAjax(), selectArrayFilter()
7502
	 */
7503
	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)
7504
	{
7505
		global $conf, $langs;
7506
7507
		$out = '';
7508
7509
		if ($addjscombo < 0) {
7510
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7511
				$addjscombo = 1;
7512
			} else {
7513
				$addjscombo = 0;
7514
			}
7515
		}
7516
7517
		// Add code for jquery to use multiselect
7518
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) {
7519
			$out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->';
7520
			$out .= "\n".'<script>'."\n";
7521
			if ($addjscombo == 1) {
7522
				$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
7523
				$out .= 'function formatResult(record) {'."\n";
7524
				if ($elemtype == 'category') {
7525
					$out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
7526
				} else {
7527
					$out .= 'return record.text;';
7528
				}
7529
				$out .= '};'."\n";
7530
				$out .= 'function formatSelection(record) {'."\n";
7531
				if ($elemtype == 'category') {
7532
					$out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
7533
				} else {
7534
					$out .= 'return record.text;';
7535
				}
7536
				$out .= '};'."\n";
7537
				$out .= '$(document).ready(function () {
7538
							$(\'#'.$htmlname.'\').'.$tmpplugin.'({
7539
								dir: \'ltr\',
7540
								// Specify format function for dropdown item
7541
								formatResult: formatResult,
7542
							 	templateResult: formatResult,		/* For 4.0 */
7543
								// Specify format function for selected item
7544
								formatSelection: formatSelection,
7545
							 	templateSelection: formatSelection		/* For 4.0 */
7546
							});
7547
7548
							/* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
7549
								 the size only if component is not hidden by default on load */
7550
							$(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\');
7551
						});'."\n";
7552
			} elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
7553
				// Add other js lib
7554
				// TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
7555
				// ...
7556
				$out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
7557
				$out .= '$(document).ready(function () {
7558
							$(\'#'.$htmlname.'\').multiSelect({
7559
								containerHTML: \'<div class="multi-select-container">\',
7560
								menuHTML: \'<div class="multi-select-menu">\',
7561
								buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
7562
								menuItemHTML: \'<label class="multi-select-menuitem">\',
7563
								activeClass: \'multi-select-container--open\',
7564
								noneText: \''.$placeholder.'\'
7565
							});
7566
						})';
7567
			}
7568
			$out .= '</script>';
7569
		}
7570
7571
		// Try also magic suggest
7572
		$out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
7573
		if (is_array($array) && !empty($array)) {
7574
			if ($value_as_key) {
7575
				$array = array_combine($array, $array);
7576
			}
7577
7578
			if (!empty($array)) {
7579
				foreach ($array as $key => $value) {
7580
					$newval = ($translate ? $langs->trans($value) : $value);
7581
					$newval = ($key_in_label ? $key.' - '.$newval : $newval);
7582
7583
					$out .= '<option value="'.$key.'"';
7584
					if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != '')) {
7585
						$out .= ' selected';
7586
					}
7587
					$out .= ' data-html="'.dol_escape_htmltag($newval).'"';
7588
					$out .= '>';
7589
					$out .= dol_htmlentitiesbr($newval);
7590
					$out .= '</option>'."\n";
7591
				}
7592
			}
7593
		}
7594
		$out .= '</select>'."\n";
7595
7596
		return $out;
7597
	}
7598
7599
7600
	/**
7601
	 *	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.
7602
	 *
7603
	 *	@param	string	$htmlname		Name of HTML field
7604
	 *	@param	array	$array			Array with array of fields we could show. This array may be modified according to setup of user.
7605
	 *  @param  string  $varpage        Id of context for page. Can be set by caller with $varpage=(empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage);
7606
	 *	@return	string					HTML multiselect string
7607
	 *  @see selectarray()
7608
	 */
7609
	public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
7610
	{
7611
		global $conf, $langs, $user, $extrafields;
7612
7613
		if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
7614
			return '';
7615
		}
7616
7617
		$tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved selected fields to show
7618
7619
		if (!empty($user->conf->$tmpvar)) {		// A list of fields was already customized for user
7620
			$tmparray = explode(',', $user->conf->$tmpvar);
7621
			foreach ($array as $key => $val) {
7622
				//var_dump($key);
7623
				//var_dump($tmparray);
7624
				if (in_array($key, $tmparray)) {
7625
					$array[$key]['checked'] = 1;
7626
				} else {
7627
					$array[$key]['checked'] = 0;
7628
				}
7629
			}
7630
		} else {								// There is no list of fields already customized for user
7631
			foreach ($array as $key => $val) {
7632
				if ($array[$key]['checked'] < 0) {
7633
					$array[$key]['checked'] = 0;
7634
				}
7635
			}
7636
		}
7637
7638
		$listoffieldsforselection = '';
7639
		$listcheckedstring = '';
7640
7641
		foreach ($array as $key => $val) {
7642
			/* var_dump($val);
7643
			var_dump(array_key_exists('enabled', $val));
7644
			var_dump(!$val['enabled']);*/
7645
			if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
7646
				unset($array[$key]); // We don't want this field
7647
				continue;
7648
			}
7649
			if (!empty($val['type']) && $val['type'] == 'separate') {
7650
				// Field remains in array but we don't add it into $listoffieldsforselection
7651
				//$listoffieldsforselection .= '<li>-----</li>';
7652
				continue;
7653
			}
7654
			if ($val['label']) {
7655
				if (!empty($val['langfile']) && is_object($langs)) {
7656
					$langs->load($val['langfile']);
7657
				}
7658
7659
				// Note: $val['checked'] <> 0 means we must show the field into the combo list
7660
				$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>';
7661
				$listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
7662
			}
7663
		}
7664
7665
		$out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
7666
7667
        <dl class="dropdown">
7668
            <dt>
7669
            <a href="#'.$htmlname.'">
7670
              '.img_picto('', 'list').'
7671
            </a>
7672
            <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
7673
            </dt>
7674
            <dd class="dropdowndd">
7675
                <div class="multiselectcheckbox'.$htmlname.'">
7676
                    <ul class="ul'.$htmlname.'">
7677
                    '.$listoffieldsforselection.'
7678
                    </ul>
7679
                </div>
7680
            </dd>
7681
        </dl>
7682
7683
        <script type="text/javascript">
7684
          jQuery(document).ready(function () {
7685
              $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
7686
                  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
7687
7688
                  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\');	// Update field so we know we changed something on selected fields after POST
7689
7690
                  var title = $(this).val() + ",";
7691
                  if ($(this).is(\':checked\')) {
7692
                      $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
7693
                  }
7694
                  else {
7695
                      $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
7696
                  }
7697
                  // Now, we submit page
7698
                  //$(this).parents(\'form:first\').submit();
7699
              });
7700
7701
7702
           });
7703
        </script>
7704
7705
        ';
7706
		return $out;
7707
	}
7708
7709
	/**
7710
	 * 	Render list of categories linked to object with id $id and type $type
7711
	 *
7712
	 * 	@param		int		$id				Id of object
7713
	 * 	@param		string	$type			Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
7714
	 *  @param		int		$rendermode		0=Default, use multiselect. 1=Emulate multiselect (recommended)
7715
	 *  @param		int		$nolink			1=Do not add html links
7716
	 * 	@return		string					String with categories
7717
	 */
7718
	public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
7719
	{
7720
		global $db;
7721
7722
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
7723
7724
		$cat = new Categorie($db);
7725
		$categories = $cat->containing($id, $type);
7726
7727
		if ($rendermode == 1) {
7728
			$toprint = array();
7729
			foreach ($categories as $c) {
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
7730
				$ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
7731
				foreach ($ways as $way) {
7732
					$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>';
7733
				}
7734
			}
7735
			return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
7736
		}
7737
7738
		if ($rendermode == 0) {
7739
			$arrayselected = array();
7740
			$cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
7741
			foreach ($categories as $c) {
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
7742
				$arrayselected[] = $c->id;
7743
			}
7744
7745
			return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
7746
		}
7747
7748
		return 'ErrorBadValueForParameterRenderMode'; // Should not happened
7749
	}
7750
7751
	/**
7752
	 *  Show linked object block.
7753
	 *
7754
	 *  @param	CommonObject	$object		      Object we want to show links to
7755
	 *  @param  string          $morehtmlright    More html to show on right of title
7756
	 *  @param  array           $compatibleImportElementsList  Array of compatibles elements object for "import from" action
7757
	 *  @return	int							      <0 if KO, >=0 if OK
7758
	 */
7759
	public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false)
7760
	{
7761
		global $conf, $langs, $hookmanager;
7762
		global $bc, $action;
7763
7764
		$object->fetchObjectLinked();
7765
7766
		// Bypass the default method
7767
		$hookmanager->initHooks(array('commonobject'));
7768
		$parameters = array(
7769
			'morehtmlright' => $morehtmlright,
7770
			'compatibleImportElementsList' => &$compatibleImportElementsList,
7771
		);
7772
		$reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
7773
7774
		if (empty($reshook)) {
7775
			$nbofdifferenttypes = count($object->linkedObjects);
7776
7777
			print '<!-- showLinkedObjectBlock -->';
7778
			print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
7779
7780
7781
			print '<div class="div-table-responsive-no-min">';
7782
			print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'"  data-elementid="'.$object->id.'"   >';
7783
7784
			print '<tr class="liste_titre">';
7785
			print '<td>'.$langs->trans("Type").'</td>';
7786
			print '<td>'.$langs->trans("Ref").'</td>';
7787
			print '<td class="center"></td>';
7788
			print '<td class="center">'.$langs->trans("Date").'</td>';
7789
			print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
7790
			print '<td class="right">'.$langs->trans("Status").'</td>';
7791
			print '<td></td>';
7792
			print '</tr>';
7793
7794
			$nboftypesoutput = 0;
7795
7796
			foreach ($object->linkedObjects as $objecttype => $objects) {
7797
				$tplpath = $element = $subelement = $objecttype;
7798
7799
				// to display inport button on tpl
7800
				$showImportButton = false;
7801
				if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
7802
					$showImportButton = true;
7803
				}
7804
7805
				$regs = array();
7806
				if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
7807
					$element = $regs[1];
7808
					$subelement = $regs[2];
7809
					$tplpath = $element.'/'.$subelement;
7810
				}
7811
				$tplname = 'linkedobjectblock';
7812
7813
				// To work with non standard path
7814
				if ($objecttype == 'facture') {
7815
					$tplpath = 'compta/'.$element;
7816
					if (empty($conf->facture->enabled)) {
7817
						continue; // Do not show if module disabled
7818
					}
7819
				} elseif ($objecttype == 'facturerec') {
7820
					$tplpath = 'compta/facture';
7821
					$tplname = 'linkedobjectblockForRec';
7822
					if (empty($conf->facture->enabled)) {
7823
						continue; // Do not show if module disabled
7824
					}
7825
				} elseif ($objecttype == 'propal') {
7826
					$tplpath = 'comm/'.$element;
7827
					if (empty($conf->propal->enabled)) {
7828
						continue; // Do not show if module disabled
7829
					}
7830
				} elseif ($objecttype == 'supplier_proposal') {
7831
					if (empty($conf->supplier_proposal->enabled)) {
7832
						continue; // Do not show if module disabled
7833
					}
7834
				} elseif ($objecttype == 'shipping' || $objecttype == 'shipment') {
7835
					$tplpath = 'expedition';
7836
					if (empty($conf->expedition->enabled)) {
7837
						continue; // Do not show if module disabled
7838
					}
7839
				} elseif ($objecttype == 'reception') {
7840
					$tplpath = 'reception';
7841
					if (empty($conf->reception->enabled)) {
7842
						continue; // Do not show if module disabled
7843
					}
7844
				} elseif ($objecttype == 'delivery') {
7845
					$tplpath = 'delivery';
7846
					if (empty($conf->expedition->enabled)) {
7847
						continue; // Do not show if module disabled
7848
					}
7849
				} elseif ($objecttype == 'invoice_supplier') {
7850
					$tplpath = 'fourn/facture';
7851
				} elseif ($objecttype == 'order_supplier') {
7852
					$tplpath = 'fourn/commande';
7853
				} elseif ($objecttype == 'expensereport') {
7854
					$tplpath = 'expensereport';
7855
				} elseif ($objecttype == 'subscription') {
7856
					$tplpath = 'adherents';
7857
				} elseif ($objecttype == 'conferenceorbooth') {
7858
					$tplpath = 'eventorganization';
7859
				} elseif ($objecttype == 'conferenceorboothattendee') {
7860
					$tplpath = 'eventorganization';
7861
				}
7862
7863
				global $linkedObjectBlock;
7864
				$linkedObjectBlock = $objects;
7865
7866
7867
				// Output template part (modules that overwrite templates must declare this into descriptor)
7868
				$dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
7869
				foreach ($dirtpls as $reldir) {
7870
					if ($nboftypesoutput == ($nbofdifferenttypes - 1)) {    // No more type to show after
7871
						global $noMoreLinkedObjectBlockAfter;
7872
						$noMoreLinkedObjectBlockAfter = 1;
7873
					}
7874
7875
					$res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
7876
					if ($res) {
7877
						$nboftypesoutput++;
7878
						break;
7879
					}
7880
				}
7881
			}
7882
7883
			if (!$nboftypesoutput) {
7884
				print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>';
7885
			}
7886
7887
			print '</table>';
7888
7889
			if (!empty($compatibleImportElementsList)) {
7890
				$res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
7891
			}
7892
7893
7894
			print '</div>';
7895
7896
			return $nbofdifferenttypes;
7897
		}
7898
	}
7899
7900
	/**
7901
	 *  Show block with links to link to other objects.
7902
	 *
7903
	 *  @param	CommonObject	$object				Object we want to show links to
7904
	 *  @param	array			$restrictlinksto	Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction.
7905
	 *  @param	array			$excludelinksto		Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion.
7906
	 *  @return	string								<0 if KO, >0 if OK
7907
	 */
7908
	public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
7909
	{
7910
		global $conf, $langs, $hookmanager;
7911
		global $bc, $action;
7912
7913
		$linktoelem = '';
7914
		$linktoelemlist = '';
7915
		$listofidcompanytoscan = '';
7916
7917
		if (!is_object($object->thirdparty)) {
7918
			$object->fetch_thirdparty();
7919
		}
7920
7921
		$possiblelinks = array();
7922
		if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
7923
			$listofidcompanytoscan = $object->thirdparty->id;
7924
			if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) {
7925
				$listofidcompanytoscan .= ','.$object->thirdparty->parent;
7926
			}
7927
			if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) {
7928
				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7929
				$tmpproject = new Project($this->db);
7930
				$tmpproject->fetch($object->fk_project);
7931
				if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
7932
					$listofidcompanytoscan .= ','.$tmpproject->socid;
7933
				}
7934
				unset($tmpproject);
7935
			}
7936
7937
			$possiblelinks = array(
7938
				'propal'=>array('enabled'=>$conf->propal->enabled, 'perms'=>1, 'label'=>'LinkToProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('propal').')'),
7939
				'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande').')'),
7940
				'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 ".MAIN_DB_PREFIX."societe as s, ".MAIN_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').')'),
7941
				'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 ".MAIN_DB_PREFIX."societe as s, ".MAIN_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').')'),
7942
				'contrat'=>array(
7943
					'enabled'=>$conf->contrat->enabled,
7944
					'perms'=>1,
7945
					'label'=>'LinkToContract',
7946
					'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 FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t, ".MAIN_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'
7947
				),
7948
				'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('intervention').')'),
7949
				'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled, 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('supplier_proposal').')'),
7950
				'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled, 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande_fournisseur').')'),
7951
				'invoice_supplier'=>array('enabled'=>$conf->supplier_invoice->enabled, 'perms'=>1, 'label'=>'LinkToSupplierInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('facture_fourn').')'),
7952
				'ticket'=>array('enabled'=>$conf->ticket->enabled, 'perms'=>1, 'label'=>'LinkToTicket', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('ticket').')')
7953
			);
7954
		}
7955
7956
		// Can complete the possiblelink array
7957
		$hookmanager->initHooks(array('commonobject'));
7958
		$parameters = array('listofidcompanytoscan' => $listofidcompanytoscan);
7959
7960
		if (!empty($listofidcompanytoscan)) {  // If empty, we don't have criteria to scan the object we can link to
7961
			$reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
7962
		}
7963
7964
		if (empty($reshook)) {
7965
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
7966
				$possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
7967
			}
7968
		} 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...
7969
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
7970
				$possiblelinks = $hookmanager->resArray;
7971
			}
7972
		}
7973
7974
		foreach ($possiblelinks as $key => $possiblelink) {
7975
			$num = 0;
7976
7977
			if (empty($possiblelink['enabled'])) {
7978
				continue;
7979
			}
7980
7981
			if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
7982
				print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
7983
7984
				if (!empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
7985
					print '<br><form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
7986
					print '<input type="hidden" name="id" value="' . $object->id . '">';
7987
					print '<input type="hidden" name="action" value="addlinkbyref">';
7988
					print '<input type="hidden" name="addlink" value="' . $key . '">';
7989
					print '<table class="noborder">';
7990
					print '<tr>';
7991
					print '<td>' . $langs->trans("Ref") . '</td>';
7992
					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>';
7993
					print '</tr>';
7994
					print '</table>';
7995
					print '</form>';
7996
				}
7997
7998
				$sql = $possiblelink['sql'];
7999
8000
				$resqllist = $this->db->query($sql);
8001
				if ($resqllist) {
8002
					$num = $this->db->num_rows($resqllist);
8003
					$i = 0;
8004
8005
					print '<br>';
8006
					print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
8007
					print '<input type="hidden" name="action" value="addlink">';
8008
					print '<input type="hidden" name="token" value="'.newToken().'">';
8009
					print '<input type="hidden" name="id" value="'.$object->id.'">';
8010
					print '<input type="hidden" name="addlink" value="'.$key.'">';
8011
					print '<table class="noborder">';
8012
					print '<tr class="liste_titre">';
8013
					print '<td class="nowrap"></td>';
8014
					print '<td class="center">'.$langs->trans("Ref").'</td>';
8015
					print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
8016
					print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
8017
					print '<td class="left">'.$langs->trans("Company").'</td>';
8018
					print '</tr>';
8019
					while ($i < $num) {
8020
						$objp = $this->db->fetch_object($resqllist);
8021
8022
						print '<tr class="oddeven">';
8023
						print '<td class="left">';
8024
						print '<input type="radio" name="idtolinkto" id="'.$key.'_'.$objp->rowid.'" value="'.$objp->rowid.'">';
8025
						print '</td>';
8026
						print '<td class="center"><label for="'.$key.'_'.$objp->rowid.'">'.$objp->ref.'</label></td>';
8027
						print '<td>'.(!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')).'</td>';
8028
						print '<td class="right">';
8029
						if ($possiblelink['label'] == 'LinkToContract') {
8030
							$form = new Form($this->db);
8031
							print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' ';
8032
						}
8033
						print '<span class="amount">'.price($objp->total_ht).'</span>';
8034
						print '</td>';
8035
						print '<td>'.$objp->name.'</td>';
8036
						print '</tr>';
8037
						$i++;
8038
					}
8039
					print '</table>';
8040
					print '<div class="center">';
8041
					print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly" value="'.$langs->trans('ToLink').'">';
8042
					if (empty($conf->use_javascript_ajax)) {
8043
						print '<input type="submit" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>';
8044
					} else {
8045
						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>';
8046
					}
8047
					print '</form>';
8048
					$this->db->free($resqllist);
8049
				} else {
8050
					dol_print_error($this->db);
8051
				}
8052
				print '</div>';
8053
8054
				//$linktoelem.=($linktoelem?' &nbsp; ':'');
8055
				if ($num > 0 || !empty($conf->global->MAIN_LINK_BY_REF_IN_LINKTO)) {
8056
					$linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
8057
					// } else $linktoelem.=$langs->trans($possiblelink['label']);
8058
				} else {
8059
					$linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
8060
				}
8061
			}
8062
		}
8063
8064
		if ($linktoelemlist) {
8065
			$linktoelem = '
8066
    		<dl class="dropdown" id="linktoobjectname">
8067
    		';
8068
			if (!empty($conf->use_javascript_ajax)) {
8069
				$linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>'.$langs->trans("LinkTo").'...</a></dt>';
8070
			}
8071
			$linktoelem .= '<dd>
8072
    		<div class="multiselectlinkto">
8073
    		<ul class="ulselectedfields">'.$linktoelemlist.'
8074
    		</ul>
8075
    		</div>
8076
    		</dd>
8077
    		</dl>';
8078
		} else {
8079
			$linktoelem = '';
8080
		}
8081
8082
		if (!empty($conf->use_javascript_ajax)) {
8083
			print '<!-- Add js to show linkto box -->
8084
				<script>
8085
				jQuery(document).ready(function() {
8086
					jQuery(".linkto").click(function() {
8087
						console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
8088
					    jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
8089
					});
8090
				});
8091
				</script>
8092
		    ';
8093
		}
8094
8095
		return $linktoelem;
8096
	}
8097
8098
	/**
8099
	 *	Return an html string with a select combo box to choose yes or no
8100
	 *
8101
	 *	@param	string		$htmlname		Name of html select field
8102
	 *	@param	string		$value			Pre-selected value
8103
	 *	@param	int			$option			0 return yes/no, 1 return 1/0
8104
	 *	@param	bool		$disabled		true or false
8105
	 *  @param	int      	$useempty		1=Add empty line
8106
	 *  @param	int			$addjscombo		1=Add js beautifier on combo box
8107
	 *  @param	string		$morecss		More CSS
8108
	 *	@return	string						See option
8109
	 */
8110
	public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '')
8111
	{
8112
		global $langs;
8113
8114
		$yes = "yes";
8115
		$no = "no";
8116
		if ($option) {
8117
			$yes = "1";
8118
			$no = "0";
8119
		}
8120
8121
		$disabled = ($disabled ? ' disabled' : '');
8122
8123
		$resultyesno = '<select class="flat width75'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
8124
		if ($useempty) {
8125
			$resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
8126
		}
8127
		if (("$value" == 'yes') || ($value == 1)) {
8128
			$resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
8129
			$resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
8130
		} else {
8131
			$selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
8132
			$resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
8133
			$resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
8134
		}
8135
		$resultyesno .= '</select>'."\n";
8136
8137
		if ($addjscombo) {
8138
			$resultyesno .= ajax_combobox($htmlname);
8139
		}
8140
8141
		return $resultyesno;
8142
	}
8143
8144
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8145
	/**
8146
	 *  Return list of export templates
8147
	 *
8148
	 *  @param	string	$selected          Id modele pre-selectionne
8149
	 *  @param  string	$htmlname          Name of HTML select
8150
	 *  @param  string	$type              Type of searched templates
8151
	 *  @param  int		$useempty          Affiche valeur vide dans liste
8152
	 *  @return	void
8153
	 */
8154
	public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
8155
	{
8156
		// phpcs:enable
8157
		$sql = "SELECT rowid, label";
8158
		$sql .= " FROM ".MAIN_DB_PREFIX."export_model";
8159
		$sql .= " WHERE type = '".$this->db->escape($type)."'";
8160
		$sql .= " ORDER BY rowid";
8161
		$result = $this->db->query($sql);
8162
		if ($result) {
8163
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
8164
			if ($useempty) {
8165
				print '<option value="-1">&nbsp;</option>';
8166
			}
8167
8168
			$num = $this->db->num_rows($result);
8169
			$i = 0;
8170
			while ($i < $num) {
8171
				$obj = $this->db->fetch_object($result);
8172
				if ($selected == $obj->rowid) {
8173
					print '<option value="'.$obj->rowid.'" selected>';
8174
				} else {
8175
					print '<option value="'.$obj->rowid.'">';
8176
				}
8177
				print $obj->label;
8178
				print '</option>';
8179
				$i++;
8180
			}
8181
			print "</select>";
8182
		} else {
8183
			dol_print_error($this->db);
8184
		}
8185
	}
8186
8187
	/**
8188
	 *    Return a HTML area with the reference of object and a navigation bar for a business object
8189
	 *    Note: To complete search with a particular filter on select, you can set $object->next_prev_filter set to define SQL criterias.
8190
	 *
8191
	 *    @param	object	$object			Object to show.
8192
	 *    @param	string	$paramid   		Name of parameter to use to name the id into the URL next/previous link.
8193
	 *    @param	string	$morehtml  		More html content to output just before the nav bar.
8194
	 *    @param	int		$shownav	  	Show Condition (navigation is shown if value is 1).
8195
	 *    @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.
8196
	 *    @param	string	$fieldref   	Name of field ref of object (object->ref) to show or 'none' to not show ref.
8197
	 *    @param	string	$morehtmlref  	More html to show after ref.
8198
	 *    @param	string	$moreparam  	More param to add in nav link url. Must start with '&...'.
8199
	 *	  @param	int		$nodbprefix		Do not include DB prefix to forge table name.
8200
	 *	  @param	string	$morehtmlleft	More html code to show before ref.
8201
	 *	  @param	string	$morehtmlstatus	More html code to show under navigation arrows (status place).
8202
	 *	  @param	string	$morehtmlright	More html code to show after ref.
8203
	 * 	  @return	string    				Portion HTML with ref + navigation buttons
8204
	 */
8205
	public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
8206
	{
8207
		global $langs, $conf, $hookmanager, $extralanguages;
8208
8209
		$ret = '';
8210
		if (empty($fieldid)) {
8211
			$fieldid = 'rowid';
8212
		}
8213
		if (empty($fieldref)) {
8214
			$fieldref = 'ref';
8215
		}
8216
8217
		// Preparing gender's display if there is one
8218
		$addgendertxt = '';
8219
		if (!empty($object->gender)) {
8220
			$addgendertxt = ' ';
8221
			switch ($object->gender) {
8222
				case 'man':
8223
					$addgendertxt .= '<i class="fas fa-mars"></i>';
8224
					break;
8225
				case 'woman':
8226
					$addgendertxt .= '<i class="fas fa-venus"></i>';
8227
					break;
8228
				case 'other':
8229
					$addgendertxt .= '<i class="fas fa-genderless"></i>';
8230
					break;
8231
			}
8232
		}
8233
8234
		// Add where from hooks
8235
		if (is_object($hookmanager)) {
8236
			$parameters = array();
8237
			$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
8238
			$object->next_prev_filter .= $hookmanager->resPrint;
8239
		}
8240
		$previous_ref = $next_ref = '';
8241
		if ($shownav) {
8242
			//print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
8243
			$object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
8244
8245
			$navurl = $_SERVER["PHP_SELF"];
8246
			// Special case for project/task page
8247
			if ($paramid == 'project_ref') {
8248
				if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) {     // TODO Remove this when nav with project_ref on task pages are ok
8249
					$navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
8250
					$paramid = 'ref';
8251
				}
8252
			}
8253
8254
			// accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
8255
			// accesskey is for Mac:               CTRL + key for all browsers
8256
			$stringforfirstkey = $langs->trans("KeyboardShortcut");
8257
			if ($conf->browser->name == 'chrome') {
8258
				$stringforfirstkey .= ' ALT +';
8259
			} elseif ($conf->browser->name == 'firefox') {
8260
				$stringforfirstkey .= ' ALT + SHIFT +';
8261
			} else {
8262
				$stringforfirstkey .= ' CTL +';
8263
			}
8264
8265
			$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>';
8266
			$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>';
8267
		}
8268
8269
		//print "xx".$previous_ref."x".$next_ref;
8270
		$ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
8271
8272
		// Right part of banner
8273
		if ($morehtmlright) {
8274
			$ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
8275
		}
8276
8277
		if ($previous_ref || $next_ref || $morehtml) {
8278
			$ret .= '<div class="pagination paginationref"><ul class="right">';
8279
		}
8280
		if ($morehtml) {
8281
			$ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>';
8282
		}
8283
		if ($shownav && ($previous_ref || $next_ref)) {
8284
			$ret .= '<li class="pagination">'.$previous_ref.'</li>';
8285
			$ret .= '<li class="pagination">'.$next_ref.'</li>';
8286
		}
8287
		if ($previous_ref || $next_ref || $morehtml) {
8288
			$ret .= '</ul></div>';
8289
		}
8290
8291
		$parameters = array();
8292
		$reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
8293
		if (empty($reshook)) {
8294
			$morehtmlstatus .= $hookmanager->resPrint;
8295
		} else {
8296
			$morehtmlstatus = $hookmanager->resPrint;
8297
		}
8298
		if ($morehtmlstatus) {
8299
			$ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
8300
		}
8301
8302
		$parameters = array();
8303
		$reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
8304
		if (empty($reshook)) {
8305
			$morehtmlref .= $hookmanager->resPrint;
8306
		} elseif ($reshook > 0) {
8307
			$morehtmlref = $hookmanager->resPrint;
8308
		}
8309
8310
		// Left part of banner
8311
		if ($morehtmlleft) {
8312
			if ($conf->browser->layout == 'phone') {
8313
				$ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
8314
			} else {
8315
				$ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
8316
			}
8317
		}
8318
8319
		//if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
8320
		$ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
8321
8322
		// For thirdparty, contact, user, member, the ref is the id, so we show something else
8323
		if ($object->element == 'societe') {
8324
			$ret .= dol_htmlentities($object->name);
8325
8326
			// List of extra languages
8327
			$arrayoflangcode = array();
8328
			if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) {
8329
				$arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
8330
			}
8331
8332
			if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
8333
				if (!is_object($extralanguages)) {
8334
					include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
8335
					$extralanguages = new ExtraLanguages($this->db);
8336
				}
8337
				$extralanguages->fetch_name_extralanguages('societe');
8338
8339
				if (!empty($extralanguages->attributes['societe']['name'])) {
8340
					$object->fetchValuesForExtraLanguages();
8341
8342
					$htmltext = '';
8343
					// If there is extra languages
8344
					foreach ($arrayoflangcode as $extralangcode) {
8345
						$htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
8346
						if ($object->array_languages['name'][$extralangcode]) {
8347
							$htmltext .= $object->array_languages['name'][$extralangcode];
8348
						} else {
8349
							$htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
8350
						}
8351
					}
8352
					$ret .= '<!-- Show translations of name -->'."\n";
8353
					$ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
8354
				}
8355
			}
8356
		} elseif ($object->element == 'member') {
8357
			$ret .= $object->ref.'<br>';
8358
			$fullname = $object->getFullName($langs);
8359
			if ($object->morphy == 'mor' && $object->societe) {
8360
				$ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).$addgendertxt.')' : '');
8361
			} else {
8362
				$ret .= dol_htmlentities($fullname).$addgendertxt.((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
8363
			}
8364
		} elseif (in_array($object->element, array('contact', 'user', 'usergroup'))) {
8365
			$ret .= dol_htmlentities($object->getFullName($langs)).$addgendertxt;
8366
		} elseif (in_array($object->element, array('action', 'agenda'))) {
8367
			$ret .= $object->ref.'<br>'.$object->label;
8368
		} elseif (in_array($object->element, array('adherent_type'))) {
8369
			$ret .= $object->label;
8370
		} elseif ($object->element == 'ecm_directories') {
8371
			$ret .= '';
8372
		} elseif ($fieldref != 'none') {
8373
			$ret .= dol_htmlentities($object->$fieldref);
8374
		}
8375
8376
		if ($morehtmlref) {
8377
			// don't add a additional space, when "$morehtmlref" starts with a HTML div tag
8378
			if (substr($morehtmlref, 0, 4) != '<div') {
8379
				$ret .= ' ';
8380
			}
8381
8382
			$ret .= $morehtmlref;
8383
		}
8384
8385
		$ret .= '</div>';
8386
8387
		$ret .= '</div><!-- End banner content -->';
8388
8389
		return $ret;
8390
	}
8391
8392
8393
	/**
8394
	 *  Return HTML code to output a barcode
8395
	 *
8396
	 *  @param	Object	$object			Object containing data to retrieve file name
8397
	 * 	@param	int		$width			Width of photo
8398
	 * 	@param	string	$morecss		More CSS on img of barcode
8399
	 * 	@return string    				HTML code to output barcode
8400
	 */
8401
	public function showbarcode(&$object, $width = 100, $morecss = '')
8402
	{
8403
		global $conf;
8404
8405
		//Check if barcode is filled in the card
8406
		if (empty($object->barcode)) {
8407
			return '';
8408
		}
8409
8410
		// Complete object if not complete
8411
		if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
8412
			$result = $object->fetch_barcode();
8413
			//Check if fetch_barcode() failed
8414
			if ($result < 1) {
8415
				return '<!-- ErrorFetchBarcode -->';
8416
			}
8417
		}
8418
8419
		// Barcode image
8420
		$url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
8421
		$out = '<!-- url barcode = '.$url.' -->';
8422
		$out .= '<img src="'.$url.'"'.($morecss ? ' class="'.$morecss.'"' : '').'>';
8423
		return $out;
8424
	}
8425
8426
	/**
8427
	 *    	Return HTML code to output a photo
8428
	 *
8429
	 *    	@param	string		$modulepart			Key to define module concerned ('societe', 'userphoto', 'memberphoto')
8430
	 *     	@param  object		$object				Object containing data to retrieve file name
8431
	 * 		@param	int			$width				Width of photo
8432
	 * 		@param	int			$height				Height of photo (auto if 0)
8433
	 * 		@param	int			$caneditfield		Add edit fields
8434
	 * 		@param	string		$cssclass			CSS name to use on img for photo
8435
	 * 		@param	string		$imagesize		    'mini', 'small' or '' (original)
8436
	 *      @param  int         $addlinktofullsize  Add link to fullsize image
8437
	 *      @param  int         $cache              1=Accept to use image in cache
8438
	 *      @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 ''.
8439
	 *      @param	int			$noexternsourceoverwrite	No overwrite image with extern source (like 'gravatar' or other module)
8440
	 * 	  	@return string    						HTML code to output photo
8441
	 */
8442
	public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
8443
	{
8444
		global $conf, $langs;
8445
8446
		$entity = (!empty($object->entity) ? $object->entity : $conf->entity);
8447
		$id = (!empty($object->id) ? $object->id : $object->rowid);
8448
8449
		$ret = '';
8450
		$dir = '';
8451
		$file = '';
8452
		$originalfile = '';
8453
		$altfile = '';
8454
		$email = '';
8455
		$capture = '';
8456
		if ($modulepart == 'societe') {
8457
			$dir = $conf->societe->multidir_output[$entity];
8458
			if (!empty($object->logo)) {
8459
				if (dolIsAllowedForPreview($object->logo)) {
8460
					if ((string) $imagesize == 'mini') {
8461
						$file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
8462
					} elseif ((string) $imagesize == 'small') {
8463
						$file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small');
8464
					} else {
8465
						$file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
8466
					}
8467
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo;
8468
				}
8469
			}
8470
			$email = $object->email;
8471
		} elseif ($modulepart == 'contact')	{
8472
			$dir = $conf->societe->multidir_output[$entity].'/contact';
8473
			if (!empty($object->photo)) {
8474
				if (dolIsAllowedForPreview($object->photo)) {
8475
					if ((string) $imagesize == 'mini') {
8476
						$file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini');
8477
					} elseif ((string) $imagesize == 'small') {
8478
						$file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small');
8479
					} else {
8480
						$file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
8481
					}
8482
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo;
8483
				}
8484
			}
8485
			$email = $object->email;
8486
			$capture = 'user';
8487
		} elseif ($modulepart == 'userphoto') {
8488
			$dir = $conf->user->dir_output;
8489
			if (!empty($object->photo)) {
8490
				if (dolIsAllowedForPreview($object->photo)) {
8491
					if ((string) $imagesize == 'mini') {
8492
						$file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_mini');
8493
					} elseif ((string) $imagesize == 'small') {
8494
						$file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_small');
8495
					} else {
8496
						$file = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo;
8497
					}
8498
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo;
8499
				}
8500
			}
8501
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
8502
				$altfile = $object->id.".jpg"; // For backward compatibility
8503
			}
8504
			$email = $object->email;
8505
			$capture = 'user';
8506
		} elseif ($modulepart == 'memberphoto')	{
8507
			$dir = $conf->adherent->dir_output;
8508
			if (!empty($object->photo)) {
8509
				if (dolIsAllowedForPreview($object->photo)) {
8510
					if ((string) $imagesize == 'mini') {
8511
						$file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
8512
					} elseif ((string) $imagesize == 'small') {
8513
						$file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
8514
					} else {
8515
						$file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
8516
					}
8517
					$originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
8518
				}
8519
			}
8520
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
8521
				$altfile = $object->id.".jpg"; // For backward compatibility
8522
			}
8523
			$email = $object->email;
8524
			$capture = 'user';
8525
		} else {
8526
			// Generic case to show photos
8527
			$dir = $conf->$modulepart->dir_output;
8528
			if (!empty($object->photo)) {
8529
				if (dolIsAllowedForPreview($object->photo)) {
8530
					if ((string) $imagesize == 'mini') {
8531
						$file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
8532
					} elseif ((string) $imagesize == 'small') {
8533
						$file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
8534
					} else {
8535
						$file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
8536
					}
8537
					$originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
8538
				}
8539
			}
8540
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) {
8541
				$altfile = $object->id.".jpg"; // For backward compatibility
8542
			}
8543
			$email = $object->email;
8544
		}
8545
8546
		if ($forcecapture) {
8547
			$capture = $forcecapture;
8548
		}
8549
8550
		if ($dir) {
8551
			if ($file && file_exists($dir."/".$file)) {
8552
				if ($addlinktofullsize) {
8553
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
8554
					if ($urladvanced) {
8555
						$ret .= '<a href="'.$urladvanced.'">';
8556
					} else {
8557
						$ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
8558
					}
8559
				}
8560
				$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.'">';
8561
				if ($addlinktofullsize) {
8562
					$ret .= '</a>';
8563
				}
8564
			} elseif ($altfile && file_exists($dir."/".$altfile)) {
8565
				if ($addlinktofullsize) {
8566
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
8567
					if ($urladvanced) {
8568
						$ret .= '<a href="'.$urladvanced.'">';
8569
					} else {
8570
						$ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
8571
					}
8572
				}
8573
				$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.'">';
8574
				if ($addlinktofullsize) {
8575
					$ret .= '</a>';
8576
				}
8577
			} else {
8578
				$nophoto = '/public/theme/common/nophoto.png';
8579
				$defaultimg = 'identicon';		// For gravatar
8580
				if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) {	// For modules that need a special image when photo not found
8581
					if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor')) !== false) {
8582
						$nophoto = 'company';
8583
					} else {
8584
						$nophoto = '/public/theme/common/user_anonymous.png';
8585
						if (!empty($object->gender) && $object->gender == 'man') {
8586
							$nophoto = '/public/theme/common/user_man.png';
8587
						}
8588
						if (!empty($object->gender) && $object->gender == 'woman') {
8589
							$nophoto = '/public/theme/common/user_woman.png';
8590
						}
8591
					}
8592
				}
8593
8594
				if (!empty($conf->gravatar->enabled) && $email && empty($noexternsourceoverwrite)) {
8595
					// see https://gravatar.com/site/implement/images/php/
8596
					$ret .= '<!-- Put link to gravatar -->';
8597
					$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="Gravatar avatar" title="'.$email.' Gravatar avatar" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="https://www.gravatar.com/avatar/'.md5(strtolower(trim($email))).'?s='.$width.'&d='.$defaultimg.'">'; // gravatar need md5 hash
8598
				} else {
8599
					if ($nophoto == 'company') {
8600
						$ret .= '<div class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').'">'.img_picto('', 'company').'</div>';
8601
					} else {
8602
						$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
8603
					}
8604
				}
8605
			}
8606
8607
			if ($caneditfield) {
8608
				if ($object->photo) {
8609
					$ret .= "<br>\n";
8610
				}
8611
				$ret .= '<table class="nobordernopadding centpercent">';
8612
				if ($object->photo) {
8613
					$ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> '.$langs->trans("Delete").'<br><br></td></tr>';
8614
				}
8615
				$ret .= '<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'></td></tr>';
8616
				$ret .= '</table>';
8617
			}
8618
		} else {
8619
			dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
8620
		}
8621
8622
		return $ret;
8623
	}
8624
8625
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
8626
	/**
8627
	 *	Return select list of groups
8628
	 *
8629
	 *  @param	string	$selected       Id group preselected
8630
	 *  @param  string	$htmlname       Field name in form
8631
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
8632
	 *  @param  string	$exclude        Array list of groups id to exclude
8633
	 * 	@param	int		$disabled		If select list must be disabled
8634
	 *  @param  string	$include        Array list of groups id to include
8635
	 * 	@param	int		$enableonly		Array list of groups id to be enabled. All other must be disabled
8636
	 * 	@param	string	$force_entity	'0' or Ids of environment to force
8637
	 * 	@param	bool	$multiple		add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
8638
	 *  @param  string	$morecss		More css to add to html component
8639
	 *  @return	string
8640
	 *  @see select_dolusers()
8641
	 */
8642
	public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
8643
	{
8644
		// phpcs:enable
8645
		global $conf, $user, $langs;
8646
8647
		// Permettre l'exclusion de groupes
8648
		if (is_array($exclude)) {
0 ignored issues
show
introduced by
The condition is_array($exclude) is always false.
Loading history...
8649
			$excludeGroups = implode(",", $exclude);
8650
		}
8651
		// Permettre l'inclusion de groupes
8652
		if (is_array($include)) {
0 ignored issues
show
introduced by
The condition is_array($include) is always false.
Loading history...
8653
			$includeGroups = implode(",", $include);
8654
		}
8655
8656
		if (!is_array($selected)) {
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
8657
			$selected = array($selected);
8658
		}
8659
8660
		$out = '';
8661
8662
		// On recherche les groupes
8663
		$sql = "SELECT ug.rowid, ug.nom as name";
8664
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
8665
			$sql .= ", e.label";
8666
		}
8667
		$sql .= " FROM ".MAIN_DB_PREFIX."usergroup as ug ";
8668
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
8669
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=ug.entity";
8670
			if ($force_entity) {
8671
				$sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
8672
			} else {
8673
				$sql .= " WHERE ug.entity IS NOT NULL";
8674
			}
8675
		} else {
8676
			$sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
8677
		}
8678
		if (is_array($exclude) && $excludeGroups) {
0 ignored issues
show
introduced by
The condition is_array($exclude) is always false.
Loading history...
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...
8679
			$sql .= " AND ug.rowid NOT IN (".$this->db->sanitize($excludeGroups).")";
8680
		}
8681
		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...
8682
			$sql .= " AND ug.rowid IN (".$this->db->sanitize($includeGroups).")";
8683
		}
8684
		$sql .= " ORDER BY ug.nom ASC";
8685
8686
		dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
8687
		$resql = $this->db->query($sql);
8688
		if ($resql) {
8689
			// Enhance with select2
8690
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
8691
			$out .= ajax_combobox($htmlname);
8692
8693
			$out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
8694
8695
			$num = $this->db->num_rows($resql);
8696
			$i = 0;
8697
			if ($num) {
8698
				if ($show_empty && !$multiple) {
8699
					$out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
8700
				}
8701
8702
				while ($i < $num) {
8703
					$obj = $this->db->fetch_object($resql);
8704
					$disableline = 0;
8705
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
8706
						$disableline = 1;
8707
					}
8708
8709
					$out .= '<option value="'.$obj->rowid.'"';
8710
					if ($disableline) {
8711
						$out .= ' disabled';
8712
					}
8713
					if ((is_object($selected[0]) && $selected[0]->id == $obj->rowid) || (!is_object($selected[0]) && in_array($obj->rowid, $selected))) {
8714
						$out .= ' selected';
8715
					}
8716
					$out .= '>';
8717
8718
					$out .= $obj->name;
8719
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) {
8720
						$out .= " (".$obj->label.")";
8721
					}
8722
8723
					$out .= '</option>';
8724
					$i++;
8725
				}
8726
			} else {
8727
				if ($show_empty) {
8728
					$out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
8729
				}
8730
				$out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
8731
			}
8732
			$out .= '</select>';
8733
		} else {
8734
			dol_print_error($this->db);
8735
		}
8736
8737
		return $out;
8738
	}
8739
8740
8741
	/**
8742
	 *	Return HTML to show the search and clear seach button
8743
	 *
8744
	 *  @return	string
8745
	 */
8746
	public function showFilterButtons()
8747
	{
8748
		$out = '<div class="nowraponall">';
8749
		$out .= '<button type="submit" class="liste_titre button_search" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
8750
		$out .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
8751
		$out .= '</div>';
8752
8753
		return $out;
8754
	}
8755
8756
	/**
8757
	 *	Return HTML to show the search and clear search button
8758
	 *
8759
	 *  @param  string  $cssclass                  CSS class
8760
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
8761
	 *  @param  string  $massactionname            Mass action button name that will launch an action on the selected items
8762
	 *  @return	string
8763
	 */
8764
	public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
8765
	{
8766
		global $conf, $langs;
8767
8768
		$out = '';
8769
8770
		if (!empty($conf->use_javascript_ajax)) {
8771
			$out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
8772
		}
8773
		$out .= '<script>
8774
            $(document).ready(function() {
8775
                $("#' . $cssclass.'s").click(function() {
8776
                    if($(this).is(\':checked\')){
8777
                        console.log("We check all '.$cssclass.' and trigger the change method");
8778
                		$(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
8779
                    }
8780
                    else
8781
                    {
8782
                        console.log("We uncheck all");
8783
                		$(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
8784
                    }'."\n";
8785
		if ($calljsfunction) {
8786
			$out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
8787
		}
8788
		$out .= '         });
8789
        	        $(".' . $cssclass.'").change(function() {
8790
					$(this).closest("tr").toggleClass("highlight", this.checked);
8791
				});
8792
		 	});
8793
    	</script>';
8794
8795
		return $out;
8796
	}
8797
8798
	/**
8799
	 *	Return HTML to show the search and clear seach button
8800
	 *
8801
	 *  @param	int  	$addcheckuncheckall        Add the check all/uncheck all checkbox (use javascript) and code to manage this
8802
	 *  @param  string  $cssclass                  CSS class
8803
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
8804
	 *  @param  string  $massactionname            Mass action name
8805
	 *  @return	string
8806
	 */
8807
	public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
8808
	{
8809
		$out = $this->showFilterButtons();
8810
		if ($addcheckuncheckall) {
8811
			$out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
8812
		}
8813
		return $out;
8814
	}
8815
8816
	/**
8817
	 * Return HTML to show the select of expense categories
8818
	 *
8819
	 * @param	string	$selected              preselected category
8820
	 * @param	string	$htmlname              name of HTML select list
8821
	 * @param	integer	$useempty              1=Add empty line
8822
	 * @param	array	$excludeid             id to exclude
8823
	 * @param	string	$target                htmlname of target select to bind event
8824
	 * @param	int		$default_selected      default category to select if fk_c_type_fees change = EX_KME
8825
	 * @param	array	$params                param to give
8826
	 * @param	int		$info_admin			   Show the tooltip help picto to setup list
8827
	 * @return	string
8828
	 */
8829
	public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
8830
	{
8831
		global $db, $langs, $user;
8832
8833
		$out = '';
8834
		$sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1';
8835
		$sql .= ' AND entity IN (0,'.getEntity('exp_tax_cat').')';
8836
		if (!empty($excludeid)) {
8837
			$sql .= ' AND rowid NOT IN ('.$this->db->sanitize(implode(',', $excludeid)).')';
8838
		}
8839
		$sql .= ' ORDER BY label';
8840
8841
		$resql = $db->query($sql);
8842
		if ($resql) {
8843
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
8844
			if ($useempty) {
8845
				$out .= '<option value="0">&nbsp;</option>';
8846
			}
8847
8848
			while ($obj = $db->fetch_object($resql)) {
8849
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
8850
			}
8851
			$out .= '</select>';
8852
			$out .= ajax_combobox('select_'.$htmlname);
8853
8854
			if (!empty($htmlname) && $user->admin && $info_admin) {
8855
				$out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
8856
			}
8857
8858
			if (!empty($target)) {
8859
				$sql = "SELECT c.id FROM ".MAIN_DB_PREFIX."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
8860
				$resql = $db->query($sql);
8861
				if ($resql) {
8862
					if ($db->num_rows($resql) > 0) {
8863
						$obj = $db->fetch_object($resql);
8864
						$out .= '<script>
8865
							$(function() {
8866
								$("select[name='.$target.']").on("change", function() {
8867
									var current_val = $(this).val();
8868
									if (current_val == '.$obj->id.') {';
8869
						if (!empty($default_selected) || !empty($selected)) {
8870
							$out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
8871
						}
8872
8873
						$out .= '
8874
										$("select[name='.$htmlname.']").change();
8875
									}
8876
								});
8877
8878
								$("select[name='.$htmlname.']").change(function() {
8879
8880
									if ($("select[name='.$target.']").val() == '.$obj->id.') {
8881
										// get price of kilometer to fill the unit price
8882
										$.ajax({
8883
											method: "POST",
8884
											dataType: "json",
8885
											data: { fk_c_exp_tax_cat: $(this).val(), token: \''.currentToken().'\' },
8886
											url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php?'.$params).'",
8887
										}).done(function( data, textStatus, jqXHR ) {
8888
											console.log(data);
8889
											if (typeof data.up != "undefined") {
8890
												$("input[name=value_unit]").val(data.up);
8891
												$("select[name='.$htmlname.']").attr("title", data.title);
8892
											} else {
8893
												$("input[name=value_unit]").val("");
8894
												$("select[name='.$htmlname.']").attr("title", "");
8895
											}
8896
										});
8897
									}
8898
								});
8899
							});
8900
						</script>';
8901
					}
8902
				}
8903
			}
8904
		} else {
8905
			dol_print_error($db);
8906
		}
8907
8908
		return $out;
8909
	}
8910
8911
	/**
8912
	 * Return HTML to show the select ranges of expense range
8913
	 *
8914
	 * @param	string	$selected    preselected category
8915
	 * @param	string	$htmlname    name of HTML select list
8916
	 * @param	integer	$useempty    1=Add empty line
8917
	 * @return	string
8918
	 */
8919
	public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
8920
	{
8921
		global $db, $conf, $langs;
8922
8923
		$out = '';
8924
		$sql = 'SELECT rowid, range_ik FROM '.MAIN_DB_PREFIX.'c_exp_tax_range';
8925
		$sql .= ' WHERE entity = '.$conf->entity.' AND active = 1';
8926
8927
		$resql = $db->query($sql);
8928
		if ($resql) {
8929
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
8930
			if ($useempty) {
8931
				$out .= '<option value="0"></option>';
8932
			}
8933
8934
			while ($obj = $db->fetch_object($resql)) {
8935
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
8936
			}
8937
			$out .= '</select>';
8938
		} else {
8939
			dol_print_error($db);
8940
		}
8941
8942
		return $out;
8943
	}
8944
8945
	/**
8946
	 * Return HTML to show a select of expense
8947
	 *
8948
	 * @param	string	$selected    preselected category
8949
	 * @param	string	$htmlname    name of HTML select list
8950
	 * @param	integer	$useempty    1=Add empty choice
8951
	 * @param	integer	$allchoice   1=Add all choice
8952
	 * @param	integer	$useid       0=use 'code' as key, 1=use 'id' as key
8953
	 * @return	string
8954
	 */
8955
	public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
8956
	{
8957
		global $db, $langs;
8958
8959
		$out = '';
8960
		$sql = 'SELECT id, code, label FROM '.MAIN_DB_PREFIX.'c_type_fees';
8961
		$sql .= ' WHERE active = 1';
8962
8963
		$resql = $db->query($sql);
8964
		if ($resql) {
8965
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
8966
			if ($useempty) {
8967
				$out .= '<option value="0"></option>';
8968
			}
8969
			if ($allchoice) {
8970
				$out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
8971
			}
8972
8973
			$field = 'code';
8974
			if ($useid) {
8975
				$field = 'id';
8976
			}
8977
8978
			while ($obj = $db->fetch_object($resql)) {
8979
				$key = $langs->trans($obj->code);
8980
				$out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
8981
			}
8982
			$out .= '</select>';
8983
		} else {
8984
			dol_print_error($db);
8985
		}
8986
8987
		return $out;
8988
	}
8989
8990
	/**
8991
	 *  Output a combo list with invoices qualified for a third party
8992
	 *
8993
	 *  @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)
8994
	 *  @param  int		$selected   	Id invoice preselected
8995
	 *  @param  string	$htmlname   	Name of HTML select
8996
	 *	@param	int		$maxlength		Maximum length of label
8997
	 *	@param	int		$option_only	Return only html options lines without the select tag
8998
	 *	@param	string	$show_empty		Add an empty line ('1' or string to show for empty line)
8999
	 *  @param	int		$discard_closed Discard closed projects (0=Keep,1=hide completely,2=Disable)
9000
	 *  @param	int		$forcefocus		Force focus on field (works with javascript only)
9001
	 *  @param	int		$disabled		Disabled
9002
	 *  @param	string	$morecss        More css added to the select component
9003
	 *  @param	string	$projectsListId ''=Automatic filter on project allowed. List of id=Filter on project ids.
9004
	 *  @param	string	$showproject	'all' = Show project info, ''=Hide project info
9005
	 *  @param	User	$usertofilter	User object to use for filtering
9006
	 *	@return int         			Nbr of project if OK, <0 if KO
9007
	 */
9008
	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)
9009
	{
9010
		global $user, $conf, $langs;
9011
9012
		require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
9013
9014
		if (is_null($usertofilter)) {
9015
			$usertofilter = $user;
9016
		}
9017
9018
		$out = '';
9019
9020
		$hideunselectables = false;
9021
		if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) {
9022
			$hideunselectables = true;
9023
		}
9024
9025
		if (empty($projectsListId)) {
9026
			if (empty($usertofilter->rights->projet->all->lire)) {
9027
				$projectstatic = new Project($this->db);
9028
				$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
9029
			}
9030
		}
9031
9032
		// Search all projects
9033
		$sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
9034
            p.title, p.fk_soc, p.fk_statut, p.public,";
9035
		$sql .= ' s.nom as name';
9036
		$sql .= ' FROM '.MAIN_DB_PREFIX.'projet as p';
9037
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = p.fk_soc,';
9038
		$sql .= ' '.MAIN_DB_PREFIX.'facture as f';
9039
		$sql .= " WHERE p.entity IN (".getEntity('project').")";
9040
		$sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
9041
		//if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
9042
		//if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
9043
		//if ($socid > 0)  $sql.= " AND (p.fk_soc=".$socid." OR p.fk_soc IS NULL)";
9044
		$sql .= " ORDER BY p.ref, f.ref ASC";
9045
9046
		$resql = $this->db->query($sql);
9047
		if ($resql) {
9048
			// Use select2 selector
9049
			if (!empty($conf->use_javascript_ajax)) {
9050
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
9051
				$comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
9052
				$out .= $comboenhancement;
9053
				$morecss = 'minwidth200imp maxwidth500';
9054
			}
9055
9056
			if (empty($option_only)) {
9057
				$out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
9058
			}
9059
			if (!empty($show_empty)) {
9060
				$out .= '<option value="0" class="optiongrey">';
9061
				if (!is_numeric($show_empty)) {
9062
					$out .= $show_empty;
9063
				} else {
9064
					$out .= '&nbsp;';
9065
				}
9066
				$out .= '</option>';
9067
			}
9068
			$num = $this->db->num_rows($resql);
9069
			$i = 0;
9070
			if ($num) {
9071
				while ($i < $num) {
9072
					$obj = $this->db->fetch_object($resql);
9073
					// 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.
9074
					if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) {
9075
						// Do nothing
9076
					} else {
9077
						if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
9078
							$i++;
9079
							continue;
9080
						}
9081
9082
						$labeltoshow = '';
9083
9084
						if ($showproject == 'all') {
9085
							$labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
9086
							if ($obj->name) {
9087
								$labeltoshow .= ' - '.$obj->name; // Soc name
9088
							}
9089
9090
							$disabled = 0;
9091
							if ($obj->fk_statut == Project::STATUS_DRAFT) {
9092
								$disabled = 1;
9093
								$labeltoshow .= ' - '.$langs->trans("Draft");
9094
							} elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
9095
								if ($discard_closed == 2) {
9096
									$disabled = 1;
9097
								}
9098
								$labeltoshow .= ' - '.$langs->trans("Closed");
9099
							} elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
9100
								$disabled = 1;
9101
								$labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
9102
							}
9103
						}
9104
9105
						if (!empty($selected) && $selected == $obj->rowid) {
9106
							$out .= '<option value="'.$obj->rowid.'" selected';
9107
							//if ($disabled) $out.=' disabled';						// with select2, field can't be preselected if disabled
9108
							$out .= '>'.$labeltoshow.'</option>';
9109
						} else {
9110
							if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
9111
								$resultat = '';
9112
							} else {
9113
								$resultat = '<option value="'.$obj->rowid.'"';
9114
								if ($disabled) {
9115
									$resultat .= ' disabled';
9116
								}
9117
								//if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
9118
								//else $labeltoshow.=' ('.$langs->trans("Private").')';
9119
								$resultat .= '>';
9120
								$resultat .= $labeltoshow;
9121
								$resultat .= '</option>';
9122
							}
9123
							$out .= $resultat;
9124
						}
9125
					}
9126
					$i++;
9127
				}
9128
			}
9129
			if (empty($option_only)) {
9130
				$out .= '</select>';
9131
			}
9132
9133
			print $out;
9134
9135
			$this->db->free($resql);
9136
			return $num;
9137
		} else {
9138
			dol_print_error($this->db);
9139
			return -1;
9140
		}
9141
	}
9142
9143
	/**
9144
	 * Output the component to make advanced search criteries
9145
	 *
9146
	 * @param	array		$arrayofcriterias			          Array of available search criterias. Example: array($object->element => $object->fields, 'otherfamily' => otherarrayoffields, ...)
9147
	 * @param	array		$search_component_params	          Array of selected search criterias
9148
	 * @param   array       $arrayofinputfieldsalreadyoutput      Array of input fields already inform. The component will not generate a hidden input field if it is in this list.
9149
	 * @return	string									          HTML component for advanced search
9150
	 */
9151
	public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array())
9152
	{
9153
		global $langs;
9154
9155
		$ret = '';
9156
9157
		$ret .= '<div class="nowrap centpercent">';
9158
		//$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
9159
		$ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor paddingright">';
9160
		$ret .= '<span class="fas fa-filter linkobject boxfilter" title="Filter" id="idsubimgproductdistribution"></span>';
9161
		$ret .= $langs->trans("Filters");
9162
		$ret .= '</a>';
9163
		//$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
9164
		$ret .= '<div name="search_component_params" class="search_component_params inline-block minwidth500 maxwidth300onsmartphone valignmiddle">';
9165
		$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
9166
9167
		$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
9168
		$ret .= '</div>';
9169
		$ret .= '<input type="hidden" name="search_component_params_hidden" class="search_component_params_hidden" value="'.GETPOST("search_component_params_hidden").'">';
9170
		// For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
9171
		foreach ($arrayofcriterias as $criterias) {
9172
			foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
9173
				if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
9174
					continue;
9175
				}
9176
				if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
9177
					continue;
9178
				}
9179
				if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
9180
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
9181
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
9182
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
9183
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
9184
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
9185
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
9186
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
9187
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
9188
				} else {
9189
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
9190
				}
9191
			}
9192
		}
9193
		$ret .= '</div>';
9194
9195
9196
		return $ret;
9197
	}
9198
9199
	/**
9200
	 * selectModelMail
9201
	 *
9202
	 * @param   string   $prefix     	Prefix
9203
	 * @param   string   $modelType  	Model type
9204
	 * @param	int		 $default	 	1=Show also Default mail template
9205
	 * @param	int		 $addjscombo	Add js combobox
9206
	 * @return  string               	HTML select string
9207
	 */
9208
	public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0)
9209
	{
9210
		global $langs, $db, $user;
9211
9212
		$retstring = '';
9213
9214
		$TModels = array();
9215
9216
		include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
9217
		$formmail = new FormMail($db);
9218
		$result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
9219
9220
		if ($default) {
9221
			$TModels[0] = $langs->trans('DefaultMailModel');
9222
		}
9223
		if ($result > 0) {
9224
			foreach ($formmail->lines_model as $model) {
9225
				$TModels[$model->id] = $model->label;
9226
			}
9227
		}
9228
9229
		$retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
9230
9231
		foreach ($TModels as $id_model => $label_model) {
9232
			$retstring .= '<option value="'.$id_model.'"';
9233
			$retstring .= ">".$label_model."</option>";
9234
		}
9235
9236
		$retstring .= "</select>";
9237
9238
		if ($addjscombo) {
9239
			$retstring .= ajax_combobox('select_'.$prefix.'model_mail');
9240
		}
9241
9242
		return $retstring;
9243
	}
9244
}
9245