Passed
Branch develop (ad461a)
by
unknown
27:24
created

Form::constructProductListOption()   F

Complexity

Conditions 82

Size

Total Lines 261
Code Lines 178

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 82
eloc 178
c 0
b 0
f 0
nop 8
dl 0
loc 261
rs 3.3333

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
/* Copyright (c) 2002-2007  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (C) 2004-2012  Laurent Destailleur     <[email protected]>
4
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
5
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
6
 * Copyright (C) 2004       Eric Seigne             <[email protected]>
7
 * Copyright (C) 2005-2017  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2006       Andre Cianfarani        <[email protected]>
9
 * Copyright (C) 2006       Marc Barilley/Ocebo     <[email protected]>
10
 * Copyright (C) 2007       Franky Van Liedekerke   <[email protected]>
11
 * Copyright (C) 2007       Patrick Raguin          <[email protected]>
12
 * Copyright (C) 2010       Juanjo Menent           <[email protected]>
13
 * Copyright (C) 2010-2019  Philippe Grand          <[email protected]>
14
 * Copyright (C) 2011       Herve Prot              <[email protected]>
15
 * Copyright (C) 2012-2016  Marcos García           <[email protected]>
16
 * Copyright (C) 2012       Cedric Salvador         <[email protected]>
17
 * Copyright (C) 2012-2015  Raphaël Doursenaud      <[email protected]>
18
 * Copyright (C) 2014       Alexandre Spangaro      <[email protected]>
19
 * Copyright (C) 2018       Ferran Marcet           <[email protected]>
20
 * Copyright (C) 2018-2019  Frédéric France         <[email protected]>
21
 * Copyright (C) 2018       Nicolas ZABOURI	        <[email protected]>
22
 * Copyright (C) 2018       Christophe Battarel     <[email protected]>
23
 * Copyright (C) 2018       Josep Lluis Amador      <[email protected]>
24
 *
25
 * This program is free software; you can redistribute it and/or modify
26
 * it under the terms of the GNU General Public License as published by
27
 * the Free Software Foundation; either version 3 of the License, or
28
 * (at your option) any later version.
29
 *
30
 * This program is distributed in the hope that it will be useful,
31
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33
 * GNU General Public License for more details.
34
 *
35
 * You should have received a copy of the GNU General Public License
36
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37
 */
38
39
/**
40
 *	\file       htdocs/core/class/html.form.class.php
41
 *  \ingroup    core
42
 *	\brief      File of class with all html predefined components
43
 */
44
45
46
/**
47
 *	Class to manage generation of HTML components
48
 *	Only common components must be here.
49
 *
50
 *  TODO Merge all function load_cache_* and loadCache* (except load_cache_vatrates) into one generic function loadCacheTable
51
 */
52
class Form
53
{
54
	/**
55
	 * @var DoliDB Database handler.
56
	 */
57
	public $db;
58
59
	/**
60
	 * @var string Error code (or message)
61
	 */
62
	public $error = '';
63
64
	/**
65
	 * @var string[]    Array of error strings
66
	 */
67
	public $errors = array();
68
69
	public $num;
70
71
	// Cache arrays
72
	public $cache_types_paiements = array();
73
	public $cache_conditions_paiements = array();
74
	public $cache_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), '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
		{
116
			if (!empty($perm))
117
			{
118
				$tmp = explode(':', $typeofdata);
119
				$ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">';
120
				if ($fieldrequired) $ret .= '<span class="fieldrequired">';
121
				if ($help) {
122
					$ret .= $this->textwithpicto($langs->trans($text), $help);
123
				} else {
124
					$ret .= $langs->trans($text);
125
				}
126
				if ($fieldrequired) $ret .= '</span>';
127
				$ret .= '</div>'."\n";
128
			} else {
129
				if ($fieldrequired) $ret .= '<span class="fieldrequired">';
130
				if ($help) {
131
					$ret .= $this->textwithpicto($langs->trans($text), $help);
132
				} else {
133
					$ret .= $langs->trans($text);
134
				}
135
				if ($fieldrequired) $ret .= '</span>';
136
			}
137
		} else {
138
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
139
			if ($fieldrequired) $ret .= '<span class="fieldrequired">';
140
			if ($help) {
141
				$ret .= $this->textwithpicto($langs->trans($text), $help);
142
			} else {
143
				$ret .= $langs->trans($text);
144
			}
145
			if ($fieldrequired) $ret .= '</span>';
146
			if (!empty($notabletag)) $ret .= ' ';
147
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</td>';
148
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<td class="right">';
149
			if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&amp;'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>';
150
			if (!empty($notabletag) && $notabletag == 1) $ret .= ' : ';
151
			if (!empty($notabletag) && $notabletag == 3) $ret .= ' ';
152
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</td>';
153
			if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) $ret .= '</tr></table>';
154
		}
155
156
		return $ret;
157
	}
158
159
	/**
160
	 * Output value of a field for an editable field
161
	 *
162
	 * @param	string	$text			Text of label (not used in this function)
163
	 * @param	string	$htmlname		Name of select field
164
	 * @param	string	$value			Value to show/edit
165
	 * @param	object	$object			Object
166
	 * @param	boolean	$perm			Permission to allow button to edit parameter
167
	 * @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,...')
168
	 * @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
169
	 * @param	object	$extObject		External object
170
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
171
	 * @param	string	$moreparam		More param to add on the form action href URL
172
	 * @param   int     $notabletag     Do no output table tags
173
	 * @param	string	$formatfunc		Call a specific function to output field
174
	 * @param	string	$paramid		Key of parameter for id ('id', 'socid')
175
	 * @return  string					HTML edit field
176
	 */
177
	public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id')
178
	{
179
		global $conf, $langs, $db;
180
181
		$ret = '';
182
183
		// Check parameters
184
		if (empty($typeofdata)) return 'ErrorBadParameter';
185
186
		// When option to edit inline is activated
187
		if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|datehourpicker/', $typeofdata)) // TODO add jquery timepicker and support select
188
		{
189
			$ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
190
		} else {
191
			if (GETPOST('action', 'aZ09') == 'edit'.$htmlname)
192
			{
193
				$ret .= "\n";
194
				$ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">';
195
				$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
196
				$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
197
				$ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">';
198
				if (empty($notabletag)) $ret .= '<table class="nobordernopadding centpercent" cellpadding="0" cellspacing="0">';
199
				if (empty($notabletag)) $ret .= '<tr><td>';
200
				if (preg_match('/^(string|safehtmlstring|email)/', $typeofdata))
201
				{
202
					$tmp = explode(':', $typeofdata);
203
					$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>';
204
				} elseif (preg_match('/^(numeric|amount)/', $typeofdata))
205
				{
206
					$tmp = explode(':', $typeofdata);
207
					$valuetoshow = price2num($editvalue ? $editvalue : $value);
208
					$ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ?price($valuetoshow) : '').'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>';
209
				} elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata))	// if wysiwyg is enabled $typeofdata = 'ckeditor'
210
				{
211
					$tmp = explode(':', $typeofdata);
212
					$cols = $tmp[2];
213
					$morealt = '';
214
					if (preg_match('/%/', $cols))
215
					{
216
						$morealt = ' style="width: '.$cols.'"';
217
						$cols = '';
218
					}
219
220
					$valuetoshow = ($editvalue ? $editvalue : $value);
221
					$ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1] ? $tmp[1] : '20').'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'" autofocus>';
222
					// textarea convert automatically entities chars into simple chars.
223
					// 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.
224
					$valuetoshow = str_replace('&', '&amp;', $valuetoshow);
225
					$ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea'));
226
					$ret .= '</textarea>';
227
				} elseif ($typeofdata == 'day' || $typeofdata == 'datepicker')
228
				{
229
					$ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0);
230
				} elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker')
231
				{
232
					$ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0);
233
				} elseif (preg_match('/^select;/', $typeofdata))
234
				{
235
					$arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
236
					$arraylist = array();
237
					foreach ($arraydata as $val)
238
					{
239
						$tmp = explode(':', $val);
240
						$tmpkey = str_replace('|', ':', $tmp[0]);
241
						$arraylist[$tmpkey] = $tmp[1];
242
					}
243
					$ret .= $this->selectarray($htmlname, $arraylist, $value);
244
				} elseif (preg_match('/^ckeditor/', $typeofdata))
245
				{
246
					$tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
247
					require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
248
					$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'));
249
					$ret .= $doleditor->Create(1);
250
				}
251
				if (empty($notabletag)) $ret .= '</td>';
252
253
				if (empty($notabletag)) $ret .= '<td class="left">';
254
				//else $ret.='<div class="clearboth"></div>';
255
				$ret .= '<input type="submit" class="button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">';
256
				if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) $ret .= '<br>'."\n";
257
				$ret .= '<input type="submit" class="button'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">';
258
				if (empty($notabletag)) $ret .= '</td>';
259
260
				if (empty($notabletag)) $ret .= '</tr></table>'."\n";
261
				$ret .= '</form>'."\n";
262
			} else {
263
				if (preg_match('/^(email)/', $typeofdata))              $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
264
				elseif (preg_match('/^(amount|numeric)/', $typeofdata)) $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : '');
265
				elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata))  $ret .= dol_htmlentitiesbr($value);
266
				elseif (preg_match('/^safehtmlstring/', $typeofdata)) $ret .= dol_string_onlythesehtmltags($value);
267
				elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') $ret .= dol_print_date($value, 'day');
268
				elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') $ret .= dol_print_date($value, 'dayhour');
269
				elseif (preg_match('/^select;/', $typeofdata))
270
				{
271
					$arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
272
					$arraylist = array();
273
					foreach ($arraydata as $val)
274
					{
275
						$tmp = explode(':', $val);
276
						$arraylist[$tmp[0]] = $tmp[1];
277
					}
278
					$ret .= $arraylist[$value];
279
				} elseif (preg_match('/^ckeditor/', $typeofdata))
280
				{
281
					$tmpcontent = dol_htmlentitiesbr($value);
282
					if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB))
283
					{
284
						$firstline = preg_replace('/<br>.*/', '', $tmpcontent);
285
						$firstline = preg_replace('/[\n\r].*/', '', $firstline);
286
						$tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
287
					}
288
					// We dont use dol_escape_htmltag to get the html formating active, but this need we must also
289
					// clean data from some dangerous html
290
					$ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent));
291
				} else {
292
					$ret .= dol_escape_htmltag($value);
293
				}
294
295
				if ($formatfunc && method_exists($object, $formatfunc))
296
				{
297
					$ret = $object->$formatfunc($ret);
298
				}
299
			}
300
		}
301
		return $ret;
302
	}
303
304
	/**
305
	 * Output edit in place form
306
	 *
307
	 * @param   string	$fieldname		Name of the field
308
	 * @param	object	$object			Object
309
	 * @param	boolean	$perm			Permission to allow button to edit parameter. Set it to 0 to have a not edited field.
310
	 * @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]'...)
311
	 * @param	string	$check			Same coe than $check parameter of GETPOST()
312
	 * @param	string	$morecss		More CSS
313
	 * @return	string   		      	HTML code for the edit of alternative language
314
	 */
315
	public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
316
	{
317
		global $conf, $langs, $extralanguages;
318
319
		$result = '';
320
321
		// List of extra languages
322
		$arrayoflangcode = array();
323
		if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
324
325
		if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
326
			if (!is_object($extralanguages)) {
327
				include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
328
				$extralanguages = new ExtraLanguages($this->db);
329
			}
330
			$extralanguages->fetch_name_extralanguages('societe');
331
332
			if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
333
				return ''; // No extralang field to show
334
			}
335
336
			$result .= '<!-- Widget for translation -->'."\n";
337
			$result .= '<div class="inline-block paddingleft image-'.$object->element.'-'.$fieldname.'">';
338
			$s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
339
			$result .= $s;
340
			$result .= '</div>';
341
342
			$result .= '<div class="inline-block hidden field-'.$object->element.'-'.$fieldname.'">';
343
344
			$resultforextrlang = '';
345
			foreach ($arrayoflangcode as $langcode)
346
			{
347
				$valuetoshow = GETPOSTISSET('field-'.$object->element."-".$fieldname."-".$langcode) ? GETPOST('field-'.$object->element.'-'.$fieldname."-".$langcode, $check) : '';
348
				if (empty($valuetoshow)) {
349
					$object->fetchValuesForExtraLanguages();
350
					//var_dump($object->array_languages);
351
					$valuetoshow = $object->array_languages[$fieldname][$langcode];
352
				}
353
354
				$s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
355
				$resultforextrlang .= $s;
356
357
				// TODO Use the showInputField() method of ExtraLanguages object
358
				if ($typeofdata == 'textarea') {
359
					$resultforextrlang .= '<textarea name="field-'.$object->element."-".$fieldname."-".$langcode.'" id="'.$fieldname."-".$langcode.'" class="'.$morecss.'" rows="'.ROWS_2.'" wrap="soft">';
360
					$resultforextrlang .= $valuetoshow;
361
					$resultforextrlang .= '</textarea>';
362
				} else {
363
					$resultforextrlang .= '<input type="text" class="inputfieldforlang '.($morecss ? ' '.$morecss : '').'" name="field-'.$object->element.'-'.$fieldname.'-'.$langcode.'" value="'.$valuetoshow.'">';
364
				}
365
			}
366
			$result .= $resultforextrlang;
367
368
			$result .= '</div>';
369
			$result .= '<script>$(".image-'.$object->element.'-'.$fieldname.'").click(function() { console.log("Toggle lang widget"); jQuery(".field-'.$object->element.'-'.$fieldname.'").toggle(); });</script>';
370
		}
371
372
		return $result;
373
	}
374
375
	/**
376
	 * Output edit in place form
377
	 *
378
	 * @param	object	$object			Object
379
	 * @param	string	$value			Value to show/edit
380
	 * @param	string	$htmlname		DIV ID (field name)
381
	 * @param	int		$condition		Condition to edit
382
	 * @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')
383
	 * @param	string	$editvalue		When in edit mode, use this value as $value instead of value
384
	 * @param	object	$extObject		External object
385
	 * @param	mixed	$custommsg		String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
386
	 * @return	string   		      	HTML edit in place
387
	 */
388
	protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
389
	{
390
		global $conf;
391
392
		$out = '';
393
394
		// Check parameters
395
		if (preg_match('/^text/', $inputType)) $value = dol_nl2br($value);
396
		elseif (preg_match('/^numeric/', $inputType)) $value = price($value);
397
		elseif ($inputType == 'day' || $inputType == 'datepicker') $value = dol_print_date($value, 'day');
398
399
		if ($condition)
400
		{
401
			$element = false;
402
			$table_element = false;
403
			$fk_element		= false;
404
			$loadmethod		= false;
405
			$savemethod		= false;
406
			$ext_element	= false;
407
			$button_only	= false;
408
			$inputOption = '';
409
410
			if (is_object($object))
411
			{
412
				$element = $object->element;
413
				$table_element = $object->table_element;
414
				$fk_element = $object->id;
415
			}
416
417
			if (is_object($extObject))
418
			{
419
				$ext_element = $extObject->element;
420
			}
421
422
			if (preg_match('/^(string|email|numeric)/', $inputType))
423
			{
424
				$tmp = explode(':', $inputType);
425
				$inputType = $tmp[0];
426
				if (!empty($tmp[1])) $inputOption = $tmp[1];
427
				if (!empty($tmp[2])) $savemethod = $tmp[2];
428
				$out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n";
429
			} elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType)))
430
			{
431
				$tmp = explode(':', $inputType);
432
				$inputType = $tmp[0];
433
				if (!empty($tmp[1])) $inputOption = $tmp[1];
434
				if (!empty($tmp[2])) $savemethod = $tmp[2];
435
436
				$out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format
437
			} elseif (preg_match('/^(select|autocomplete)/', $inputType))
438
			{
439
				$tmp = explode(':', $inputType);
440
				$inputType = $tmp[0]; $loadmethod = $tmp[1];
441
				if (!empty($tmp[2])) $savemethod = $tmp[2];
442
				if (!empty($tmp[3])) $button_only = true;
443
			} elseif (preg_match('/^textarea/', $inputType))
444
			{
445
				$tmp = explode(':', $inputType);
446
				$inputType = $tmp[0];
447
				$rows = (empty($tmp[1]) ? '8' : $tmp[1]);
448
				$cols = (empty($tmp[2]) ? '80' : $tmp[2]);
449
			} elseif (preg_match('/^ckeditor/', $inputType))
450
			{
451
				$tmp = explode(':', $inputType);
452
				$inputType = $tmp[0]; $toolbar = $tmp[1];
453
				if (!empty($tmp[2])) $width = $tmp[2];
454
				if (!empty($tmp[3])) $heigth = $tmp[3];
455
				if (!empty($tmp[4])) $savemethod = $tmp[4];
456
457
				if (!empty($conf->fckeditor->enabled))
458
				{
459
					$out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n";
460
				} else {
461
					$inputType = 'textarea';
462
				}
463
			}
464
465
			$out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n";
466
			$out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n";
467
			$out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n";
468
			$out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n";
469
			if (!empty($savemethod))	$out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n";
470
			if (!empty($ext_element))	$out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n";
471
			if (!empty($custommsg))
472
			{
473
				if (is_array($custommsg))
474
				{
475
					if (!empty($custommsg['success']))
476
						$out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n";
477
						if (!empty($custommsg['error']))
478
							$out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n";
479
				} else $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n";
480
			}
481
			if ($inputType == 'textarea') {
482
				$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...
483
				$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...
484
			}
485
			$out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n";
486
			$out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n";
487
		} else {
488
			$out = $value;
489
		}
490
491
		return $out;
492
	}
493
494
	/**
495
	 *	Show a text and picto with tooltip on text or picto.
496
	 *  Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip
497
	 *
498
	 *	@param	string		$text				Text to show
499
	 *	@param	string		$htmltext			HTML content of tooltip. Must be HTML/UTF8 encoded.
500
	 *	@param	int			$tooltipon			1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2
501
	 *	@param	int			$direction			-1=image is before, 0=no image, 1=image is after
502
	 *	@param	string		$img				Html code for image (use img_xxx() function to get it)
503
	 *	@param	string		$extracss			Add a CSS style to td tags
504
	 *	@param	int			$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
505
	 *	@param	string		$incbefore			Include code before the text
506
	 *	@param	int			$noencodehtmltext	Do not encode into html entity the htmltext
507
	 *  @param  string      $tooltiptrigger		''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key)
508
	 *  @param	int			$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
509
	 *	@return	string							Code html du tooltip (texte+picto)
510
	 *	@see	textwithpicto() Use thisfunction if you can.
511
	 *  TODO Move this as static as soon as everybody use textwithpicto or @Form::textwithtooltip
512
	 */
513
	public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
514
	{
515
		if ($incbefore) $text = $incbefore.$text;
516
		if (!$htmltext) return $text;
517
518
		$tag = 'td';
519
		if ($notabs == 2) $tag = 'div';
520
		if ($notabs == 3) $tag = 'span';
521
		// Sanitize tooltip
522
		$htmltext = str_replace(array("\r", "\n"), '', $htmltext);
523
524
		$extrastyle = '';
525
		if ($direction < 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-left: 3px !important;'; }
526
		if ($direction > 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-right: 3px !important;'; }
527
528
		$classfortooltip = 'classfortooltip';
529
530
		$s = ''; $textfordialog = '';
531
532
		if ($tooltiptrigger == '')
533
		{
534
			$htmltext = str_replace('"', '&quot;', $htmltext);
535
		} else {
536
			$classfortooltip = 'classfortooltiponclick';
537
			$textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>';
538
		}
539
		if ($tooltipon == 2 || $tooltipon == 3)
540
		{
541
			$paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
542
			if ($tooltiptrigger == '') $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
543
			else $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
544
		} else $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
545
		if ($tooltipon == 1 || $tooltipon == 3)
546
		{
547
			$paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
548
			if ($tooltiptrigger == '') $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
549
			else $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
550
		} else $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
551
		if (empty($notabs)) $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
552
		elseif ($notabs == 2) $s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">';
553
		// Define value if value is before
554
		if ($direction < 0) {
555
			$s .= '<'.$tag.$paramfortooltipimg;
556
			if ($tag == 'td') {
557
				$s .= ' class=valigntop" width="14"';
558
			}
559
			$s .= '>'.$textfordialog.$img.'</'.$tag.'>';
560
		}
561
		// Use another method to help avoid having a space in value in order to use this value with jquery
562
		// Define label
563
		if ((string) $text != '') $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>';
564
		// Define value if value is after
565
		if ($direction > 0) {
566
			$s .= '<'.$tag.$paramfortooltipimg;
567
			if ($tag == 'td') $s .= ' class="valignmiddle" width="14"';
568
			$s .= '>'.$textfordialog.$img.'</'.$tag.'>';
569
		}
570
		if (empty($notabs)) $s .= '</tr></table>';
571
		elseif ($notabs == 2) $s .= '</div>';
572
573
		return $s;
574
	}
575
576
	/**
577
	 *	Show a text with a picto and a tooltip on picto
578
	 *
579
	 *	@param	string	$text				Text to show
580
	 *	@param  string	$htmltext	     	Content of tooltip
581
	 *	@param	int		$direction			1=Icon is after text, -1=Icon is before text, 0=no icon
582
	 * 	@param	string	$type				Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none'
583
	 *  @param  string	$extracss           Add a CSS style to td, div or span tag
584
	 *  @param  int		$noencodehtmltext   Do not encode into html entity the htmltext
585
	 *  @param	int		$notabs				0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
586
	 *  @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')
587
	 *  @param	int		$forcenowrap		Force no wrap between text and picto (works with notabs=2 only)
588
	 * 	@return	string						HTML code of text, picto, tooltip
589
	 */
590
	public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
591
	{
592
		global $conf, $langs;
593
594
		$alt = '';
595
		if ($tooltiptrigger) $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
596
597
		//For backwards compatibility
598
		if ($type == '0') $type = 'info';
599
		elseif ($type == '1') $type = 'help';
600
601
		// If info or help with no javascript, show only text
602
		if (empty($conf->use_javascript_ajax))
603
		{
604
			if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable')	return $text;
605
			else {
606
				$alt = $htmltext;
607
				$htmltext = '';
608
			}
609
		}
610
611
		// If info or help with smartphone, show only text (tooltip hover can't works)
612
		if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger))
613
		{
614
			if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') return $text;
615
		}
616
		// If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
617
		//if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
618
		//{
619
		//if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>';
620
		//}
621
622
		$img = '';
623
		if ($type == 'info') $img = img_help(0, $alt);
624
		elseif ($type == 'help') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
625
		elseif ($type == 'helpclickable') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
626
		elseif ($type == 'superadmin') $img = img_picto($alt, 'redstar');
627
		elseif ($type == 'admin') $img = img_picto($alt, 'star');
628
		elseif ($type == 'warning') $img = img_warning($alt);
629
		elseif ($type != 'none') $img = img_picto($alt, $type); // $type can be an image path
630
631
		return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
632
	}
633
634
	/**
635
	 * Generate select HTML to choose massaction
636
	 *
637
	 * @param	string	$selected		Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default.
638
	 * @param	array		$arrayofaction	array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action.
639
	 * @param   int     $alwaysvisible  1=select button always visible
640
	 * @param       string  $name     Name for massaction
641
	 * @param       string  $cssclass CSS class used to check for select
642
	 * @return	string|void					Select list
643
	 */
644
	public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
645
	{
646
		global $conf, $langs, $hookmanager;
647
648
649
		$disabled = 0;
650
		$ret = '<div class="centpercent center">';
651
		$ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>';
652
653
		// 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.
654
		$parameters = array();
655
		$reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
656
		// check if there is a mass action
657
		if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) return;
658
		if (empty($reshook))
659
		{
660
			$ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>';
661
			foreach ($arrayofaction as $code => $label)
662
			{
663
				$ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>';
664
			}
665
		}
666
		$ret .= $hookmanager->resPrint;
667
668
		$ret .= '</select>';
669
670
				if (empty($conf->dol_optimize_smallscreen)) $ret .= ajax_combobox('.'.$name.'select');
671
672
		// 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
673
		$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.
674
				$ret .= '<input type="submit" disabled name="confirmmassaction" class="button'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">';
675
		$ret .= '</div>';
676
677
		if (!empty($conf->use_javascript_ajax))
678
		{
679
			$ret .= '<!-- JS CODE TO ENABLE mass action select -->
680
    		<script>
681
                        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 */
682
        		{
683
        			atleastoneselected=0;
684
                                jQuery("."+cssclass).each(function( index ) {
685
    	  				/* console.log( index + ": " + $( this ).text() ); */
686
    	  				if ($(this).is(\':checked\')) atleastoneselected++;
687
    	  			});
688
689
					console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
690
691
    	  			if (atleastoneselected || '.$alwaysvisible.')
692
    	  			{
693
                                    jQuery("."+name).show();
694
        			    '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').'
695
        			    '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').'
696
    	  			}
697
    	  			else
698
    	  			{
699
                                    jQuery("."+name).hide();
700
                                    jQuery("."+name+"other").hide();
701
    	            }
702
        		}
703
704
        	jQuery(document).ready(function () {
705
                    initCheckForSelect(0, "' . $name.'", "'.$cssclass.'");
706
                    jQuery(".' . $cssclass.'").click(function() {
707
                        initCheckForSelect(1, "'.$name.'", "'.$cssclass.'");
708
                    });
709
                        jQuery(".' . $name.'select").change(function() {
710
        			var massaction = $( this ).val();
711
        			var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
712
        			if (massaction == "builddoc")
713
                    {
714
                        urlform = urlform + "#show_files";
715
    	            }
716
        			$( this ).closest("form").attr("action", urlform);
717
                    console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform);
718
        	        /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
719
        			if ($(this).val() != \'0\')
720
    	  			{
721
                                        jQuery(".' . $name.'confirmed").prop(\'disabled\', false);
722
										jQuery(".' . $name.'other").hide();	/* To disable if another div was open */
723
                                        jQuery(".' . $name.'"+massaction).show();
724
    	  			}
725
    	  			else
726
    	  			{
727
                                        jQuery(".' . $name.'confirmed").prop(\'disabled\', true);
728
										jQuery(".' . $name.'other").hide();	/* To disable any div open */
729
    	  			}
730
    	        });
731
        	});
732
    		</script>
733
        	';
734
		}
735
736
		return $ret;
737
	}
738
739
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
740
	/**
741
	 *  Return combo list of activated countries, into language of user
742
	 *
743
	 *  @param	string	$selected       		Id or Code or Label of preselected country
744
	 *  @param  string	$htmlname       		Name of html select object
745
	 *  @param  string	$htmloption     		More html options on select object
746
	 *  @param	integer	$maxlength				Max length for labels (0=no limit)
747
	 *  @param	string	$morecss				More css class
748
	 *  @param	string	$usecodeaskey			''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
749
	 *  @param	int		$showempty				Show empty choice
750
	 *  @param	int		$disablefavorites		1=Disable favorites,
751
	 *  @param	int		$addspecialentries		1=Add dedicated entries for group of countries (like 'European Economic Community', ...)
752
	 *  @param	array	$exclude_country_code	Array of country code (iso2) to exclude
753
	 *  @return string           				HTML string with select
754
	 */
755
	public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array())
756
	{
757
		// phpcs:enable
758
		global $conf, $langs, $mysoc;
759
760
		$langs->load("dict");
761
762
		$out = '';
763
		$countryArray = array();
764
		$favorite = array();
765
		$label = array();
766
		$atleastonefavorite = 0;
767
768
		$sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
769
		$sql .= " FROM ".MAIN_DB_PREFIX."c_country";
770
		$sql .= " WHERE active > 0";
771
		//$sql.= " ORDER BY code ASC";
772
773
		dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
774
		$resql = $this->db->query($sql);
775
		if ($resql)
776
		{
777
			$out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>';
778
			$num = $this->db->num_rows($resql);
779
			$i = 0;
780
			if ($num)
781
			{
782
				$foundselected = false;
783
784
				while ($i < $num)
785
				{
786
					$obj = $this->db->fetch_object($resql);
787
788
					$countryArray[$i]['rowid'] = $obj->rowid;
789
					$countryArray[$i]['code_iso'] = $obj->code_iso;
790
					$countryArray[$i]['code_iso3'] 	= $obj->code_iso3;
791
					$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 : ''));
792
					$countryArray[$i]['favorite']   = $obj->favorite;
793
					$favorite[$i] = $obj->favorite;
794
					$label[$i] = dol_string_unaccent($countryArray[$i]['label']);
795
					$i++;
796
				}
797
798
				if (empty($disablefavorites)) array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
799
				else $countryArray = dol_sort_array($countryArray, 'label');
800
801
				if ($showempty)
802
				{
803
					$out .= '<option value="">&nbsp;</option>'."\n";
804
				}
805
806
				if ($addspecialentries)	// Add dedicated entries for groups of countries
807
				{
808
					//if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
809
					$out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
810
					$out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
811
					if ($mysoc->isInEEC()) $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
812
					$out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
813
					$out .= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
814
				}
815
816
				foreach ($countryArray as $row)
817
				{
818
					//if (empty($showempty) && empty($row['rowid'])) continue;
819
					if (empty($row['rowid'])) continue;
820
					if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) continue; // exclude some countries
821
822
					if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) $atleastonefavorite++;
823
					if (empty($row['favorite']) && $atleastonefavorite)
824
					{
825
						$atleastonefavorite = 0;
826
						$out .= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
827
					}
828
					if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label']))
829
					{
830
						$foundselected = true;
831
						$out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" selected>';
832
					} else {
833
						$out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'">';
834
					}
835
					if ($row['label']) $out .= dol_trunc($row['label'], $maxlength, 'middle');
836
					else $out .= '&nbsp;';
837
					if ($row['code_iso']) $out .= ' ('.$row['code_iso'].')';
838
					$out .= '</option>';
839
				}
840
			}
841
			$out .= '</select>';
842
		} else {
843
			dol_print_error($this->db);
844
		}
845
846
		// Make select dynamic
847
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
848
		$out .= ajax_combobox('select'.$htmlname);
849
850
		return $out;
851
	}
852
853
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
854
	/**
855
	 *  Return select list of incoterms
856
	 *
857
	 *  @param	string	$selected       		Id or Code of preselected incoterm
858
	 *  @param	string	$location_incoterms     Value of input location
859
	 *  @param	string	$page       			Defined the form action
860
	 *  @param  string	$htmlname       		Name of html select object
861
	 *  @param  string	$htmloption     		Options html on select object
862
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
863
	 *  @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')))
864
	 *  @return string           				HTML string with select and input
865
	 */
866
	public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array())
867
	{
868
		// phpcs:enable
869
		global $conf, $langs;
870
871
		$langs->load("dict");
872
873
		$out = '';
874
		$incotermArray = array();
875
876
		$sql = "SELECT rowid, code";
877
		$sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms";
878
		$sql .= " WHERE active > 0";
879
		$sql .= " ORDER BY code ASC";
880
881
		dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
882
		$resql = $this->db->query($sql);
883
		if ($resql)
884
		{
885
			if ($conf->use_javascript_ajax && !$forcecombo)
886
			{
887
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
888
				$out .= ajax_combobox($htmlname, $events);
889
			}
890
891
			if (!empty($page))
892
			{
893
				$out .= '<form method="post" action="'.$page.'">';
894
				$out .= '<input type="hidden" name="action" value="set_incoterms">';
895
				$out .= '<input type="hidden" name="token" value="'.newToken().'">';
896
			}
897
898
			$out .= '<select id="'.$htmlname.'" class="flat selectincoterm minwidth100imp noenlargeonsmartphone" name="'.$htmlname.'" '.$htmloption.'>';
899
			$out .= '<option value="0">&nbsp;</option>';
900
			$num = $this->db->num_rows($resql);
901
			$i = 0;
902
			if ($num)
903
			{
904
				$foundselected = false;
905
906
				while ($i < $num)
907
				{
908
					$obj = $this->db->fetch_object($resql);
909
					$incotermArray[$i]['rowid'] = $obj->rowid;
910
					$incotermArray[$i]['code'] = $obj->code;
911
					$i++;
912
				}
913
914
				foreach ($incotermArray as $row)
915
				{
916
					if ($selected && ($selected == $row['rowid'] || $selected == $row['code']))
917
					{
918
						$out .= '<option value="'.$row['rowid'].'" selected>';
919
					} else {
920
						$out .= '<option value="'.$row['rowid'].'">';
921
					}
922
923
					if ($row['code']) $out .= $row['code'];
924
925
					$out .= '</option>';
926
				}
927
			}
928
			$out .= '</select>';
929
930
			$out .= '<input id="location_incoterms" class="maxwidth100onsmartphone" name="location_incoterms" value="'.$location_incoterms.'">';
931
932
			if (!empty($page))
933
			{
934
				$out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'"></form>';
935
			}
936
		} else {
937
			dol_print_error($this->db);
938
		}
939
940
		return $out;
941
	}
942
943
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
944
	/**
945
	 *	Return list of types of lines (product or service)
946
	 * 	Example: 0=product, 1=service, 9=other (for external module)
947
	 *
948
	 *	@param  string	$selected       Preselected type
949
	 *	@param  string	$htmlname       Name of field in html form
950
	 * 	@param	int		$showempty		Add an empty field
951
	 * 	@param	int		$hidetext		Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
952
	 * 	@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')
953
	 *  @return	void
954
	 */
955
	public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
956
	{
957
		// phpcs:enable
958
		global $db, $langs, $user, $conf;
959
960
		// If product & services are enabled or both disabled.
961
		if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
962
			|| (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled)))
963
		{
964
			if (empty($hidetext)) print $langs->trans("Type").': ';
965
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
966
			if ($showempty)
967
			{
968
				print '<option value="-1"';
969
				if ($selected == -1) print ' selected';
970
				print '>&nbsp;</option>';
971
			}
972
973
			print '<option value="0"';
974
			if (0 == $selected) print ' selected';
975
			print '>'.$langs->trans("Product");
976
977
			print '<option value="1"';
978
			if (1 == $selected) print ' selected';
979
			print '>'.$langs->trans("Service");
980
981
			print '</select>';
982
			//if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
983
		}
984
		if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3)
985
		{
986
			print $langs->trans("Service");
987
			print '<input type="hidden" name="'.$htmlname.'" value="1">';
988
		}
989
		if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2)
990
		{
991
			print $langs->trans("Product");
992
			print '<input type="hidden" name="'.$htmlname.'" value="0">';
993
		}
994
		if ($forceall < 0)	// This should happened only for contracts when both predefined product and service are disabled.
995
		{
996
			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
997
		}
998
	}
999
1000
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1001
	/**
1002
	 *	Load into cache cache_types_fees, array of types of fees
1003
	 *
1004
	 *	@return     int             Nb of lines loaded, <0 if KO
1005
	 */
1006
	public function load_cache_types_fees()
1007
	{
1008
		// phpcs:enable
1009
		global $langs;
1010
1011
		$num = count($this->cache_types_fees);
1012
		if ($num > 0) return 0; // Cache already loaded
1013
1014
		dol_syslog(__METHOD__, LOG_DEBUG);
1015
1016
		$langs->load("trips");
1017
1018
		$sql = "SELECT c.code, c.label";
1019
		$sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
1020
		$sql .= " WHERE active > 0";
1021
1022
		$resql = $this->db->query($sql);
1023
		if ($resql)
1024
		{
1025
			$num = $this->db->num_rows($resql);
1026
			$i = 0;
1027
1028
			while ($i < $num)
1029
			{
1030
				$obj = $this->db->fetch_object($resql);
1031
1032
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
1033
				$label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1034
				$this->cache_types_fees[$obj->code] = $label;
1035
				$i++;
1036
			}
1037
1038
			asort($this->cache_types_fees);
1039
1040
			return $num;
1041
		} else {
1042
			dol_print_error($this->db);
1043
			return -1;
1044
		}
1045
	}
1046
1047
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1048
	/**
1049
	 *	Return list of types of notes
1050
	 *
1051
	 *	@param	string		$selected		Preselected type
1052
	 *	@param  string		$htmlname		Name of field in form
1053
	 * 	@param	int			$showempty		Add an empty field
1054
	 * 	@return	void
1055
	 */
1056
	public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1057
	{
1058
		// phpcs:enable
1059
		global $user, $langs;
1060
1061
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
1062
1063
		$this->load_cache_types_fees();
1064
1065
		print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">';
1066
		if ($showempty)
1067
		{
1068
			print '<option value="-1"';
1069
			if ($selected == -1) print ' selected';
1070
			print '>&nbsp;</option>';
1071
		}
1072
1073
		foreach ($this->cache_types_fees as $key => $value)
1074
		{
1075
			print '<option value="'.$key.'"';
1076
			if ($key == $selected) print ' selected';
1077
			print '>';
1078
			print $value;
1079
			print '</option>';
1080
		}
1081
1082
		print '</select>';
1083
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1084
	}
1085
1086
1087
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1088
	/**
1089
	 *  Output html form to select a third party
1090
	 *
1091
	 *	@param	string	$selected       		Preselected type
1092
	 *	@param  string	$htmlname       		Name of field in form
1093
	 *  @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)')
1094
	 *	@param	string	$showempty				Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty')
1095
	 * 	@param	int		$showtype				Show third party type in combolist (customer, prospect or supplier)
1096
	 * 	@param	int		$forcecombo				Force to load all values and output a standard combobox (with no beautification)
1097
	 *  @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')))
1098
	 *	@param	int		$limit					Maximum number of elements
1099
	 *  @param	string	$morecss				Add more css styles to the SELECT component
1100
	 *	@param  string	$moreparam      		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1101
	 *	@param	string	$selected_input_value	Value of preselected input text (for use with ajax)
1102
	 *  @param	int		$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1103
	 *  @param	array	$ajaxoptions			Options for ajax_autocompleter
1104
	 * 	@param  bool	$multiple				add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
1105
	 * 	@return	string							HTML string with select box for thirdparty.
1106
	 */
1107
	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)
1108
	{
1109
		// phpcs:enable
1110
		global $conf, $user, $langs;
1111
1112
		$out = '';
1113
1114
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo)
1115
		{
1116
			// No immediate load of all database
1117
			$placeholder = '';
1118
			if ($selected && empty($selected_input_value))
1119
			{
1120
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
1121
				$societetmp = new Societe($this->db);
1122
				$societetmp->fetch($selected);
1123
				$selected_input_value = $societetmp->name;
1124
				unset($societetmp);
1125
			}
1126
			// mode 1
1127
			$urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).($showtype ? '&showtype='.urlencode($showtype) : '');
1128
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1129
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
1130
			if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
1131
			elseif ($hidelabel > 1) {
1132
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
1133
				if ($hidelabel == 2) {
1134
					$out .= img_picto($langs->trans("Search"), 'search');
1135
				}
1136
			}
1137
			$out .= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
1138
			if ($hidelabel == 3) {
1139
				$out .= img_picto($langs->trans("Search"), 'search');
1140
			}
1141
		} else {
1142
			// Immediate load of all database
1143
			$out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple);
1144
		}
1145
1146
		return $out;
1147
	}
1148
1149
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1150
	/**
1151
	 *  Output html form to select a third party.
1152
	 *  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.
1153
	 *
1154
	 *	@param	string	$selected       Preselected type
1155
	 *	@param  string	$htmlname       Name of field in form
1156
	 *  @param  string	$filter         Optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)')
1157
	 *	@param	string	$showempty		Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty')
1158
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
1159
	 * 	@param	int		$forcecombo		Force to use standard HTML select component without beautification
1160
	 *  @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')))
1161
	 *  @param	string	$filterkey		Filter on key value
1162
	 *  @param	int		$outputmode		0=HTML select string, 1=Array
1163
	 *  @param	int		$limit			Limit number of answers
1164
	 *  @param	string	$morecss		Add more css styles to the SELECT component
1165
	 *	@param  string	$moreparam      Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1166
	 *	@param  bool	$multiple       add [] in the name of element and add 'multiple' attribut
1167
	 * 	@return	string					HTML string with
1168
	 */
1169
	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)
1170
	{
1171
		// phpcs:enable
1172
		global $conf, $user, $langs;
1173
1174
		$out = '';
1175
		$num = 0;
1176
		$outarray = array();
1177
1178
		if ($selected === '') $selected = array();
1179
		elseif (!is_array($selected)) $selected = array($selected);
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
1180
1181
		// Clean $filter that may contains sql conditions so sql code
1182
		if (function_exists('testSqlAndScriptInject')) {
1183
			if (testSqlAndScriptInject($filter, 3) > 0) {
1184
				$filter = '';
1185
			}
1186
		}
1187
1188
		// On recherche les societes
1189
		$sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1190
1191
		if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1192
			$sql .= ", s.address, s.zip, s.town";
1193
			$sql .= ", dictp.code as country_code";
1194
		}
1195
1196
		$sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
1197
		if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
1198
		if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1199
			$sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid=s.fk_pays";
1200
		}
1201
		$sql .= " WHERE s.entity IN (".getEntity('societe').")";
1202
		if (!empty($user->socid)) $sql .= " AND s.rowid = ".$user->socid;
1203
		if ($filter) $sql .= " AND (".$filter.")";
1204
		if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
1205
		if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND s.status <> 0";
1206
		// Add criteria
1207
		if ($filterkey && $filterkey != '')
1208
		{
1209
			$sql .= " AND (";
1210
			$prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1211
			// For natural search
1212
			$scrit = explode(' ', $filterkey);
1213
			$i = 0;
1214
			if (count($scrit) > 1) $sql .= "(";
1215
			foreach ($scrit as $crit) {
1216
				if ($i > 0) $sql .= " AND ";
1217
				$sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
1218
				$i++;
1219
			}
1220
			if (count($scrit) > 1) $sql .= ")";
1221
			if (!empty($conf->barcode->enabled))
1222
			{
1223
				$sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1224
			}
1225
			$sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
1226
			$sql .= ")";
1227
		}
1228
		$sql .= $this->db->order("nom", "ASC");
1229
		$sql .= $this->db->plimit($limit, 0);
1230
1231
		// Build output string
1232
		dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1233
		$resql = $this->db->query($sql);
1234
		if ($resql)
1235
		{
1236
			if (!$forcecombo)
1237
			{
1238
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1239
				$out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
1240
			}
1241
1242
			// Construct $out and $outarray
1243
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n";
1244
1245
			$textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1246
			if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT))
1247
			{
1248
				// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1249
				//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1250
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
1251
				else $textifempty .= $langs->trans("All");
1252
			}
1253
			if ($showempty) $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
1254
1255
			$num = $this->db->num_rows($resql);
1256
			$i = 0;
1257
			if ($num)
1258
			{
1259
				while ($i < $num)
1260
				{
1261
					$obj = $this->db->fetch_object($resql);
1262
					$label = '';
1263
					if ($conf->global->SOCIETE_ADD_REF_IN_LIST) {
1264
						if (($obj->client) && (!empty($obj->code_client))) {
1265
							$label = $obj->code_client.' - ';
1266
						}
1267
						if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1268
							$label .= $obj->code_fournisseur.' - ';
1269
						}
1270
						$label .= ' '.$obj->name;
1271
					} else {
1272
						$label = $obj->name;
1273
					}
1274
1275
					if (!empty($obj->name_alias)) {
1276
						$label .= ' ('.$obj->name_alias.')';
1277
					}
1278
1279
					if ($showtype)
1280
					{
1281
						if ($obj->client || $obj->fournisseur) $label .= ' (';
1282
						if ($obj->client == 1 || $obj->client == 3) $label .= $langs->trans("Customer");
1283
						if ($obj->client == 2 || $obj->client == 3) $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect");
1284
						if ($obj->fournisseur) $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier");
1285
						if ($obj->client || $obj->fournisseur) $label .= ')';
1286
					}
1287
1288
					if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
1289
						$label .= '-'.$obj->address.'-'.$obj->zip.' '.$obj->town;
1290
						if (!empty($obj->country_code)) {
1291
							$label .= ' '.$langs->trans('Country'.$obj->country_code);
1292
						}
1293
					}
1294
1295
					if (empty($outputmode))
1296
					{
1297
						if (in_array($obj->rowid, $selected))
1298
						{
1299
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
1300
						} else {
1301
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
1302
						}
1303
					} else {
1304
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
1305
					}
1306
1307
					$i++;
1308
					if (($i % 10) == 0) $out .= "\n";
1309
				}
1310
			}
1311
			$out .= '</select>'."\n";
1312
		} else {
1313
			dol_print_error($this->db);
1314
		}
1315
1316
		$this->result = array('nbofthirdparties'=>$num);
1317
1318
		if ($outputmode) return $outarray;
1319
		return $out;
1320
	}
1321
1322
1323
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1324
	/**
1325
	 *  Return HTML combo list of absolute discounts
1326
	 *
1327
	 *  @param	string	$selected       Id remise fixe pre-selectionnee
1328
	 *  @param  string	$htmlname       Nom champ formulaire
1329
	 *  @param  string	$filter         Criteres optionnels de filtre
1330
	 *  @param	int		$socid			Id of thirdparty
1331
	 *  @param	int		$maxvalue		Max value for lines that can be selected
1332
	 *  @return	int						Return number of qualifed lines in list
1333
	 */
1334
	public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
1335
	{
1336
		// phpcs:enable
1337
		global $langs, $conf;
1338
1339
		// On recherche les remises
1340
		$sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
1341
		$sql .= " re.description, re.fk_facture_source";
1342
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
1343
		$sql .= " WHERE re.fk_soc = ".(int) $socid;
1344
		$sql .= " AND re.entity = ".$conf->entity;
1345
		if ($filter) $sql .= " AND ".$filter;
1346
		$sql .= " ORDER BY re.description ASC";
1347
1348
		dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
1349
		$resql = $this->db->query($sql);
1350
		if ($resql)
1351
		{
1352
			print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">';
1353
			$num = $this->db->num_rows($resql);
1354
1355
			$qualifiedlines = $num;
1356
1357
			$i = 0;
1358
			if ($num)
1359
			{
1360
				print '<option value="0">&nbsp;</option>';
1361
				while ($i < $num)
1362
				{
1363
					$obj = $this->db->fetch_object($resql);
1364
					$desc = dol_trunc($obj->description, 40);
1365
					if (preg_match('/\(CREDIT_NOTE\)/', $desc)) $desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc);
1366
					if (preg_match('/\(DEPOSIT\)/', $desc)) $desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc);
1367
					if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) $desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc);
1368
					if (preg_match('/\(EXCESS PAID\)/', $desc)) $desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc);
1369
1370
					$selectstring = '';
1371
					if ($selected > 0 && $selected == $obj->rowid) $selectstring = ' selected';
1372
1373
					$disabled = '';
1374
					if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue)
1375
					{
1376
						$qualifiedlines--;
1377
						$disabled = ' disabled';
1378
					}
1379
1380
					if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source))
1381
					{
1382
						$tmpfac = new Facture($this->db);
1383
						if ($tmpfac->fetch($obj->fk_facture_source) > 0) $desc = $desc.' - '.$tmpfac->ref;
1384
					}
1385
1386
					print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>';
1387
					$i++;
1388
				}
1389
			}
1390
			print '</select>';
1391
			return $qualifiedlines;
1392
		} else {
1393
			dol_print_error($this->db);
1394
			return -1;
1395
		}
1396
	}
1397
1398
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1399
	/**
1400
	 *  Return list of all contacts (for a third party or all)
1401
	 *
1402
	 *  @param	int		$socid      	Id ot third party or 0 for all
1403
	 *  @param  string	$selected   	Id contact pre-selectionne
1404
	 *  @param  string	$htmlname  	    Name of HTML field ('none' for a not editable field)
1405
	 *  @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
1406
	 *  @param  string	$exclude        List of contacts id to exclude
1407
	 *  @param	string	$limitto		Disable answers that are not id in this array list
1408
	 *  @param	integer	$showfunction   Add function into label
1409
	 *  @param	string	$moreclass		Add more class to class style
1410
	 *  @param	integer	$showsoc	    Add company into label
1411
	 *  @param	int		$forcecombo		Force to use combo box
1412
	 *  @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')))
1413
	 *  @param	bool	$options_only	Return options only (for ajax treatment)
1414
	 *  @param	string	$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1415
	 *  @param	string	$htmlid			Html id to use instead of htmlname
1416
	 *  @return	int						<0 if KO, Nb of contact in list if OK
1417
	 *  @deprected						You can use selectcontacts directly (warning order of param was changed)
1418
	 */
1419
	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 = '')
1420
	{
1421
		// phpcs:enable
1422
		print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
1423
		return $this->num;
1424
	}
1425
1426
	/**
1427
	 *	Return HTML code of the SELECT of list of all contacts (for a third party or all).
1428
	 *  This also set the number of contacts found into $this->num
1429
	 *
1430
	 * @since 9.0 Add afterSelectContactOptions hook
1431
	 *
1432
	 *	@param	int			$socid      	Id ot third party or 0 for all or -1 for empty list
1433
	 *	@param  array|int	$selected   	Array of ID of pre-selected contact id
1434
	 *	@param  string		$htmlname  	    Name of HTML field ('none' for a not editable field)
1435
	 *	@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
1436
	 *	@param  string		$exclude        List of contacts id to exclude
1437
	 *	@param	string		$limitto		Disable answers that are not id in this array list
1438
	 *	@param	integer		$showfunction   Add function into label
1439
	 *	@param	string		$moreclass		Add more class to class style
1440
	 *	@param	bool		$options_only	Return options only (for ajax treatment)
1441
	 *	@param	integer		$showsoc	    Add company into label
1442
	 * 	@param	int			$forcecombo		Force to use combo box (so no ajax beautify effect)
1443
	 *  @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')))
1444
	 *  @param	string		$moreparam		Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
1445
	 *  @param	string		$htmlid			Html id to use instead of htmlname
1446
	 *  @param	bool		$multiple		add [] in the name of element and add 'multiple' attribut
1447
	 *	@return	 int						<0 if KO, Nb of contact in list if OK
1448
	 */
1449
	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)
1450
	{
1451
		global $conf, $langs, $hookmanager, $action;
1452
1453
		$langs->load('companies');
1454
1455
		if (empty($htmlid)) $htmlid = $htmlname;
1456
1457
		if ($selected === '') $selected = array();
1458
		elseif (!is_array($selected)) $selected = array($selected);
1459
		$out = '';
1460
1461
		if (!is_object($hookmanager))
1462
		{
1463
			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1464
			$hookmanager = new HookManager($this->db);
1465
		}
1466
1467
		// We search third parties
1468
		$sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste";
1469
		if ($showsoc > 0) $sql .= " , s.nom as company";
1470
		$sql .= " FROM ".MAIN_DB_PREFIX."socpeople as sp";
1471
		if ($showsoc > 0) $sql .= " LEFT OUTER JOIN  ".MAIN_DB_PREFIX."societe as s ON s.rowid=sp.fk_soc";
1472
		$sql .= " WHERE sp.entity IN (".getEntity('socpeople').")";
1473
		if ($socid > 0 || $socid == -1) $sql .= " AND sp.fk_soc=".$socid;
1474
		if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND sp.statut <> 0";
1475
		$sql .= " ORDER BY sp.lastname ASC";
1476
1477
		dol_syslog(get_class($this)."::select_contacts", LOG_DEBUG);
1478
		$resql = $this->db->query($sql);
1479
		if ($resql)
1480
		{
1481
			$num = $this->db->num_rows($resql);
1482
1483
			if ($conf->use_javascript_ajax && !$forcecombo && !$options_only)
1484
			{
1485
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1486
				$out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
1487
			}
1488
1489
			if ($htmlname != 'none' && !$options_only) $out .= '<select class="flat'.($moreclass ? ' '.$moreclass : '').'" id="'.$htmlid.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>';
1490
			if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>&nbsp;</option>';
1491
			if ($showempty == 2) $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>';
1492
1493
			$num = $this->db->num_rows($resql);
1494
			$i = 0;
1495
			if ($num)
1496
			{
1497
				include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1498
				$contactstatic = new Contact($this->db);
1499
1500
				while ($i < $num)
1501
				{
1502
					$obj = $this->db->fetch_object($resql);
1503
1504
					$contactstatic->id = $obj->rowid;
1505
					$contactstatic->lastname = $obj->lastname;
1506
					$contactstatic->firstname = $obj->firstname;
1507
					if ($obj->statut == 1) {
1508
						if ($htmlname != 'none')
1509
						{
1510
							$disabled = 0;
1511
							if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) $disabled = 1;
1512
							if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) $disabled = 1;
1513
							if (!empty($selected) && in_array($obj->rowid, $selected))
1514
							{
1515
								$out .= '<option value="'.$obj->rowid.'"';
1516
								if ($disabled) $out .= ' disabled';
1517
								$out .= ' selected>';
1518
								$out .= $contactstatic->getFullName($langs);
1519
								if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1520
								if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1521
								$out .= '</option>';
1522
							} else {
1523
								$out .= '<option value="'.$obj->rowid.'"';
1524
								if ($disabled) $out .= ' disabled';
1525
								$out .= '>';
1526
								$out .= $contactstatic->getFullName($langs);
1527
								if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1528
								if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1529
								$out .= '</option>';
1530
							}
1531
						} else {
1532
							if (in_array($obj->rowid, $selected))
1533
							{
1534
								$out .= $contactstatic->getFullName($langs);
1535
								if ($showfunction && $obj->poste) $out .= ' ('.$obj->poste.')';
1536
								if (($showsoc > 0) && $obj->company) $out .= ' - ('.$obj->company.')';
1537
							}
1538
						}
1539
					}
1540
					$i++;
1541
				}
1542
			} else {
1543
				$out .= '<option value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled>';
1544
				$out .= ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1545
				$out .= '</option>';
1546
			}
1547
1548
			$parameters = array(
1549
				'socid'=>$socid,
1550
				'htmlname'=>$htmlname,
1551
				'resql'=>$resql,
1552
				'out'=>&$out,
1553
				'showfunction'=>$showfunction,
1554
				'showsoc'=>$showsoc,
1555
			);
1556
1557
			$reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1558
1559
			if ($htmlname != 'none' && !$options_only)
1560
			{
1561
				$out .= '</select>';
1562
			}
1563
1564
			$this->num = $num;
1565
			return $out;
1566
		} else {
1567
			dol_print_error($this->db);
1568
			return -1;
1569
		}
1570
	}
1571
1572
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1573
	/**
1574
	 *	Return the HTML select list of users
1575
	 *
1576
	 *  @param	string			$selected       Id user preselected
1577
	 *  @param  string			$htmlname       Field name in form
1578
	 *  @param  int				$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
1579
	 *  @param  array			$exclude        Array list of users id to exclude
1580
	 * 	@param	int				$disabled		If select list must be disabled
1581
	 *  @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
1582
	 * 	@param	int				$enableonly		Array list of users id to be enabled. All other must be disabled
1583
	 *  @param	string			$force_entity	'0' or Ids of environment to force
1584
	 * 	@return	void
1585
	 *  @deprecated		Use select_dolusers instead
1586
	 *  @see select_dolusers()
1587
	 */
1588
	public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
1589
	{
1590
		// phpcs:enable
1591
		print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
1592
	}
1593
1594
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1595
	/**
1596
	 *	Return select list of users
1597
	 *
1598
	 *  @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)
1599
	 *  @param  string			$htmlname       Field name in form
1600
	 *  @param  int				$show_empty     0=list with no empty value, 1=add also an empty value into list
1601
	 *  @param  array			$exclude        Array list of users id to exclude
1602
	 * 	@param	int				$disabled		If select list must be disabled
1603
	 *  @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
1604
	 * 	@param	array			$enableonly		Array list of users id to be enabled. If defined, it means that others will be disabled
1605
	 *  @param	string			$force_entity	'0' or Ids of environment to force
1606
	 *  @param	int				$maxlength		Maximum length of string into list (0=no limit)
1607
	 *  @param	int				$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1608
	 *  @param	string			$morefilter		Add more filters into sql request (Example: 'employee = 1')
1609
	 *  @param	integer			$show_every		0=default list, 1=add also a value "Everybody" at beginning of list
1610
	 *  @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.
1611
	 *  @param	string			$morecss		More css
1612
	 *  @param  int     		$noactive       Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
1613
	 *  @param  int				$outputmode     0=HTML select string, 1=Array
1614
	 *  @param  bool			$multiple       add [] in the name of element and add 'multiple' attribut
1615
	 * 	@return	string							HTML select string
1616
	 *  @see select_dolgroups()
1617
	 */
1618
	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)
1619
	{
1620
		// phpcs:enable
1621
		global $conf, $user, $langs, $hookmanager;
1622
1623
		// If no preselected user defined, we take current user
1624
		if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) $selected = $user->id;
1625
1626
		if ($selected === '') $selected = array();
1627
		elseif (!is_array($selected)) $selected = array($selected);
1628
1629
		$excludeUsers = null;
1630
		$includeUsers = null;
1631
1632
		// Permettre l'exclusion d'utilisateurs
1633
		if (is_array($exclude))	$excludeUsers = implode(",", $exclude);
1634
		// Permettre l'inclusion d'utilisateurs
1635
		if (is_array($include))	$includeUsers = implode(",", $include);
1636
		elseif ($include == 'hierarchy')
1637
		{
1638
			// Build list includeUsers to have only hierarchy
1639
			$includeUsers = implode(",", $user->getAllChildIds(0));
1640
		} elseif ($include == 'hierarchyme')
1641
		{
1642
			// Build list includeUsers to have only hierarchy and current user
1643
			$includeUsers = implode(",", $user->getAllChildIds(1));
1644
		}
1645
1646
		$out = '';
1647
		$outarray = array();
1648
1649
		// Forge request to select users
1650
		$sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut, u.login, u.admin, u.entity";
1651
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
1652
		{
1653
			$sql .= ", e.label";
1654
		}
1655
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
1656
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
1657
		{
1658
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=u.entity";
1659
			if ($force_entity) $sql .= " WHERE u.entity IN (0,".$force_entity.")";
1660
			else $sql .= " WHERE u.entity IS NOT NULL";
1661
		} else {
1662
			if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
1663
			{
1664
				$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
1665
				$sql .= " ON ug.fk_user = u.rowid";
1666
				$sql .= " WHERE ug.entity = ".$conf->entity;
1667
			} else {
1668
				$sql .= " WHERE u.entity IN (0,".$conf->entity.")";
1669
			}
1670
		}
1671
		if (!empty($user->socid)) $sql .= " AND u.fk_soc = ".$user->socid;
1672
		if (is_array($exclude) && $excludeUsers) $sql .= " AND u.rowid NOT IN (".$excludeUsers.")";
1673
		if ($includeUsers) $sql .= " AND u.rowid IN (".$includeUsers.")";
1674
		if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) $sql .= " AND u.statut <> 0";
1675
		if (!empty($morefilter)) $sql .= " ".$morefilter;
1676
1677
		//Add hook to filter on user (for exemple on usergroup define in custom modules)
1678
		$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...
1679
		if (!empty($reshook)) $sql .= $hookmanager->resPrint;
1680
1681
		if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))	// MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
1682
		{
1683
			$sql .= " ORDER BY u.firstname ASC";
1684
		} else {
1685
			$sql .= " ORDER BY u.lastname ASC";
1686
		}
1687
1688
		dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
1689
		$resql = $this->db->query($sql);
1690
		if ($resql)
1691
		{
1692
			$num = $this->db->num_rows($resql);
1693
			$i = 0;
1694
			if ($num)
1695
			{
1696
				// Enhance with select2
1697
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
1698
				$out .= ajax_combobox($htmlname);
1699
1700
				// do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
1701
				$out .= '<select class="flat'.($morecss ? ' minwidth100imp '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
1702
				if ($show_empty && !$multiple) $out .= '<option value="-1"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>&nbsp;</option>'."\n";
1703
				if ($show_every) $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n";
1704
1705
				$userstatic = new User($this->db);
1706
1707
				while ($i < $num)
1708
				{
1709
					$obj = $this->db->fetch_object($resql);
1710
1711
					$userstatic->id = $obj->rowid;
1712
					$userstatic->lastname = $obj->lastname;
1713
					$userstatic->firstname = $obj->firstname;
1714
1715
					$disableline = '';
1716
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) $disableline = ($enableonlytext ? $enableonlytext : '1');
1717
1718
					$labeltoshow = '';
1719
1720
					// $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
1721
					$fullNameMode = 0;
1722
					if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION))
1723
					{
1724
						$fullNameMode = 1; //Firstname+lastname
1725
					}
1726
					$labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
1727
1728
					// Complete name with more info
1729
					$moreinfo = '';
1730
					if (!empty($conf->global->MAIN_SHOW_LOGIN))
1731
					{
1732
						$moreinfo .= ($moreinfo ? ' - ' : ' (').$obj->login;
1733
					}
1734
					if ($showstatus >= 0)
1735
					{
1736
						if ($obj->statut == 1 && $showstatus == 1)
1737
						{
1738
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled');
1739
						}
1740
						if ($obj->statut == 0 && $showstatus == 1)
1741
						{
1742
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled');
1743
						}
1744
					}
1745
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity)
1746
					{
1747
						if (!$obj->entity)
1748
						{
1749
							$moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities");
1750
						} else {
1751
							$moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
1752
						}
1753
					}
1754
					$moreinfo .= ($moreinfo ? ')' : '');
1755
					if ($disableline && $disableline != '1')
1756
					{
1757
						$moreinfo .= ' - '.$disableline; // This is text from $enableonlytext parameter
1758
					}
1759
					$labeltoshow .= $moreinfo;
1760
1761
					$out .= '<option value="'.$obj->rowid.'"';
1762
					if ($disableline) $out .= ' disabled';
1763
					if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) {
1764
						$out .= ' selected';
1765
					}
1766
					if ($showstatus >= 0 && $obj->statut == 0) {
1767
						$out .= ' data-html="'.dol_escape_htmltag('<strike class="opacitymediumxxx">'.$labeltoshow.'</strike>').'"';
1768
					}
1769
					$out .= '>';
1770
					$out .= $labeltoshow;
1771
					$out .= '</option>';
1772
1773
					$outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo;
1774
1775
					$i++;
1776
				}
1777
			} else {
1778
				$out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>';
1779
				$out .= '<option value="">'.$langs->trans("None").'</option>';
1780
			}
1781
			$out .= '</select>';
1782
		} else {
1783
			dol_print_error($this->db);
1784
		}
1785
1786
		if ($outputmode) return $outarray;
1787
		return $out;
1788
	}
1789
1790
1791
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1792
	/**
1793
	 *	Return select list of users. Selected users are stored into session.
1794
	 *  List of users are provided into $_SESSION['assignedtouser'].
1795
	 *
1796
	 *  @param  string	$action         Value for $action
1797
	 *  @param  string	$htmlname       Field name in form
1798
	 *  @param  int		$show_empty     0=list without the empty value, 1=add empty value
1799
	 *  @param  array	$exclude        Array list of users id to exclude
1800
	 * 	@param	int		$disabled		If select list must be disabled
1801
	 *  @param  array	$include        Array list of users id to include or 'hierarchy' to have only supervised users
1802
	 * 	@param	array	$enableonly		Array list of users id to be enabled. All other must be disabled
1803
	 *  @param	int		$force_entity	'0' or Ids of environment to force
1804
	 *  @param	int		$maxlength		Maximum length of string into list (0=no limit)
1805
	 *  @param	int		$showstatus		0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
1806
	 *  @param	string	$morefilter		Add more filters into sql request
1807
	 *  @param	int		$showproperties		Show properties of each attendees
1808
	 *  @param	array	$listofuserid		Array with properties of each user
1809
	 *  @param	array	$listofcontactid	Array with properties of each contact
1810
	 *  @param	array	$listofotherid		Array with properties of each other contact
1811
	 * 	@return	string					HTML select string
1812
	 *  @see select_dolgroups()
1813
	 */
1814
	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())
1815
	{
1816
		// phpcs:enable
1817
		global $conf, $user, $langs;
1818
1819
		$userstatic = new User($this->db);
1820
		$out = '';
1821
1822
1823
		$assignedtouser = array();
1824
		if (!empty($_SESSION['assignedtouser']))
1825
		{
1826
			$assignedtouser = json_decode($_SESSION['assignedtouser'], true);
1827
		}
1828
		$nbassignetouser = count($assignedtouser);
1829
1830
		//if ($nbassignetouser && $action != 'view') $out .= '<br>';
1831
		if ($nbassignetouser) $out .= '<ul class="attendees">';
1832
		$i = 0; $ownerid = 0;
1833
		foreach ($assignedtouser as $key => $value)
1834
		{
1835
			if ($value['id'] == $ownerid) continue;
1836
1837
			$out .= '<li>';
1838
			$userstatic->fetch($value['id']);
1839
			$out .= $userstatic->getNomUrl(-1);
1840
			if ($i == 0) { $ownerid = $value['id']; $out .= ' ('.$langs->trans("Owner").')'; }
1841
			if ($nbassignetouser > 1 && $action != 'view')
1842
			{
1843
				$out .= ' <input type="image" style="border: 0px;" src="'.img_picto($langs->trans("Remove"), 'delete', '', 0, 1).'" value="'.$userstatic->id.'" class="removedassigned" id="removedassigned_'.$userstatic->id.'" name="removedassigned_'.$userstatic->id.'">';
1844
			}
1845
			// Show my availability
1846
			if ($showproperties)
1847
			{
1848
				if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid)))
1849
				{
1850
					$out .= '<div class="myavailability inline-block">';
1851
					$out .= '&nbsp;-&nbsp;<span class="opacitymedium">'.$langs->trans("Availability").':</span>  <input id="transparency" class="marginleftonly marginrightonly" '.($action == 'view' ? 'disabled' : '').' type="checkbox" name="transparency"'.($listofuserid[$ownerid]['transparency'] ? ' checked' : '').'>'.$langs->trans("Busy");
1852
					$out .= '</div>';
1853
				}
1854
			}
1855
			//$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
1856
			//$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
1857
1858
			$out .= '</li>';
1859
			$i++;
1860
		}
1861
		if ($nbassignetouser) $out .= '</ul>';
1862
1863
		// Method with no ajax
1864
		if ($action != 'view')
1865
		{
1866
			$out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
1867
			$out .= '<script type="text/javascript" language="javascript">jQuery(document).ready(function () {    jQuery(".removedassigned").click(function() {        jQuery(".removedassignedhidden").val(jQuery(this).val());    });})</script>';
1868
			$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
1869
			$out .= ' <input type="submit" class="button valignmiddle" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">';
1870
			$out .= '<br>';
1871
		}
1872
1873
		return $out;
1874
	}
1875
1876
1877
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1878
	/**
1879
	 *  Return list of products for customer in Ajax if Ajax activated or go to select_produits_list
1880
	 *
1881
	 *  @param		int			$selected				Preselected products
1882
	 *  @param		string		$htmlname				Name of HTML select field (must be unique in page)
1883
	 *  @param		int			$filtertype				Filter on product type (''=nofilter, 0=product, 1=service)
1884
	 *  @param		int			$limit					Limit on number of returned lines
1885
	 *  @param		int			$price_level			Level of price to show
1886
	 *  @param		int			$status					Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell
1887
	 *  @param		int			$finished				2=all, 1=finished, 0=raw material
1888
	 *  @param		string		$selected_input_value	Value of preselected input text (for use with ajax)
1889
	 *  @param		int			$hidelabel				Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
1890
	 *  @param		array		$ajaxoptions			Options for ajax_autocompleter
1891
	 *  @param      int			$socid					Thirdparty Id (to get also price dedicated to this customer)
1892
	 *  @param		string		$showempty				'' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
1893
	 * 	@param		int			$forcecombo				Force to use combo box
1894
	 *  @param      string      $morecss                Add more css on select
1895
	 *  @param      int         $hidepriceinlabel       1=Hide prices in label
1896
	 *  @param      string      $warehouseStatus        Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used
1897
	 *										            'warehouseopen' = count products from open warehouses,
1898
	 *										            'warehouseclosed' = count products from closed warehouses,
1899
	 *										            'warehouseinternal' = count products from warehouses for internal correct/transfer only
1900
	 *  @param 		array 		$selected_combinations 	Selected combinations. Format: array([attrid] => attrval, [...])
1901
	 *  @param		string		$nooutput				No print, return the output into a string
1902
	 *  @return		void|string
1903
	 */
1904
	public function select_produits($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = array(), $nooutput = 0)
1905
	{
1906
		// phpcs:enable
1907
		global $langs, $conf;
1908
1909
		$out = '';
1910
1911
		// check parameters
1912
		$price_level = (!empty($price_level) ? $price_level : 0);
1913
		if (is_null($ajaxoptions)) $ajaxoptions = array();
0 ignored issues
show
introduced by
The condition is_null($ajaxoptions) is always false.
Loading history...
1914
1915
		if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
1916
			if (!empty($conf->product->enabled) && empty($conf->service->enabled)) {
1917
				$filtertype = '0';
1918
			} elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) {
1919
				$filtertype = '1';
1920
			}
1921
		}
1922
1923
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
1924
		{
1925
			$placeholder = '';
1926
1927
			if ($selected && empty($selected_input_value))
1928
			{
1929
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
1930
				$producttmpselect = new Product($this->db);
1931
				$producttmpselect->fetch($selected);
1932
				$selected_input_value = $producttmpselect->ref;
1933
				unset($producttmpselect);
1934
			}
1935
			// handle case where product or service module is disabled + no filter specified
1936
			if ($filtertype == '')
1937
			{
1938
				if (empty($conf->product->enabled)) { // when product module is disabled, show services only
1939
					$filtertype = 1;
1940
				} elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
1941
					$filtertype = 0;
1942
				}
1943
			}
1944
			// mode=1 means customers products
1945
			$urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus;
1946
			//Price by customer
1947
			if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
1948
				$urloption .= '&socid='.$socid;
1949
			}
1950
			$out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
1951
1952
			if (!empty($conf->variants->enabled)) {
1953
				$out .= '
1954
				<script>
1955
1956
					selected = '.json_encode($selected_combinations).';
1957
					combvalues = {};
1958
1959
					jQuery(document).ready(function () {
1960
1961
						jQuery("input[name=\'prod_entry_mode\']").change(function () {
1962
							if (jQuery(this).val() == \'free\') {
1963
								jQuery(\'div#attributes_box\').empty();
1964
							}
1965
						});
1966
1967
						jQuery("input#'.$htmlname.'").change(function () {
1968
1969
							if (!jQuery(this).val()) {
1970
								jQuery(\'div#attributes_box\').empty();
1971
								return;
1972
							}
1973
1974
							jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", {
1975
								id: jQuery(this).val()
1976
							}, function (data) {
1977
								jQuery(\'div#attributes_box\').empty();
1978
1979
								jQuery.each(data, function (key, val) {
1980
1981
									combvalues[val.id] = val.values;
1982
1983
									var span = jQuery(document.createElement(\'div\')).css({
1984
										\'display\': \'table-row\'
1985
									});
1986
1987
									span.append(
1988
										jQuery(document.createElement(\'div\')).text(val.label).css({
1989
											\'font-weight\': \'bold\',
1990
											\'display\': \'table-cell\',
1991
											\'text-align\': \'right\'
1992
										})
1993
									);
1994
1995
									var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
1996
										\'margin-left\': \'15px\',
1997
										\'white-space\': \'pre\'
1998
									}).append(
1999
										jQuery(document.createElement(\'option\')).val(\'\')
2000
									);
2001
2002
									jQuery.each(combvalues[val.id], function (key, val) {
2003
										var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2004
2005
										if (selected[val.fk_product_attribute] == val.id) {
2006
											tag.attr(\'selected\', \'selected\');
2007
										}
2008
2009
										html.append(tag);
2010
									});
2011
2012
									span.append(html);
2013
									jQuery(\'div#attributes_box\').append(span);
2014
								});
2015
							})
2016
						});
2017
2018
						'.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').'
2019
					});
2020
				</script>
2021
                ';
2022
			}
2023
2024
			if (empty($hidelabel)) $out .= $langs->trans("RefOrLabel").' : ';
2025
			elseif ($hidelabel > 1) {
2026
				$placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
2027
				if ($hidelabel == 2) {
2028
					$out .= img_picto($langs->trans("Search"), 'search');
2029
				}
2030
			}
2031
			$out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
2032
			if ($hidelabel == 3) {
2033
				$out .= img_picto($langs->trans("Search"), 'search');
2034
			}
2035
		} else {
2036
			$out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus);
2037
		}
2038
2039
		if (empty($nooutput)) print $out;
2040
		else return $out;
2041
	}
2042
2043
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2044
	/**
2045
	 *	Return list of products for a customer.
2046
	 *  Called by select_produits.
2047
	 *
2048
	 *	@param      int		$selected           Preselected product
2049
	 *	@param      string	$htmlname           Name of select html
2050
	 *  @param		string	$filtertype         Filter on product type (''=nofilter, 0=product, 1=service)
2051
	 *	@param      int		$limit              Limit on number of returned lines
2052
	 *	@param      int		$price_level        Level of price to show
2053
	 * 	@param      string	$filterkey          Filter on product
2054
	 *	@param		int		$status             -1=Return all products, 0=Products not on sell, 1=Products on sell
2055
	 *  @param      int		$finished           Filter on finished field: 2=No filter
2056
	 *  @param      int		$outputmode         0=HTML select string, 1=Array
2057
	 *  @param      int		$socid     		    Thirdparty Id (to get also price dedicated to this customer)
2058
	 *  @param		string	$showempty		    '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text.
2059
	 * 	@param		int		$forcecombo		    Force to use combo box
2060
	 *  @param      string  $morecss            Add more css on select
2061
	 *  @param      int     $hidepriceinlabel   1=Hide prices in label
2062
	 *  @param      string  $warehouseStatus    Warehouse status filter to group/count stock. Following comma separated filter options can be used.
2063
	 *										    'warehouseopen' = count products from open warehouses,
2064
	 *										    'warehouseclosed' = count products from closed warehouses,
2065
	 *										    'warehouseinternal' = count products from warehouses for internal correct/transfer only
2066
	 *  @return     array    				    Array of keys for json
2067
	 */
2068
	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 = '')
2069
	{
2070
		// phpcs:enable
2071
		global $langs, $conf, $user, $db;
2072
2073
		$out = '';
2074
		$outarray = array();
2075
2076
		// Units
2077
		if ($conf->global->PRODUCT_USE_UNITS) {
2078
			$langs->load('other');
2079
		}
2080
2081
		$warehouseStatusArray = array();
2082
		if (!empty($warehouseStatus))
2083
		{
2084
			require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
2085
			if (preg_match('/warehouseclosed/', $warehouseStatus))
2086
			{
2087
				$warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2088
			}
2089
			if (preg_match('/warehouseopen/', $warehouseStatus))
2090
			{
2091
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2092
			}
2093
			if (preg_match('/warehouseinternal/', $warehouseStatus))
2094
			{
2095
				$warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2096
			}
2097
		}
2098
2099
		$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";
2100
		if (count($warehouseStatusArray))
2101
		{
2102
			$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
2103
		} else {
2104
			$selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock";
2105
		}
2106
2107
		$sql = "SELECT ";
2108
		$sql .= $selectFields.$selectFieldsGrouped;
2109
2110
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2111
		{
2112
			//Product category
2113
			$sql .= ", (SELECT ".MAIN_DB_PREFIX."categorie_product.fk_categorie
2114
						FROM ".MAIN_DB_PREFIX."categorie_product
2115
						WHERE ".MAIN_DB_PREFIX."categorie_product.fk_product=p.rowid
2116
						LIMIT 1
2117
				) AS categorie_product_id ";
2118
		}
2119
2120
		//Price by customer
2121
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid))
2122
		{
2123
			$sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2124
			$sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx';
2125
			$selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx";
2126
		}
2127
		// Units
2128
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2129
			$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";
2130
			$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';
2131
		}
2132
2133
		// Multilang : we add translation
2134
		if (!empty($conf->global->MAIN_MULTILANGS))
2135
		{
2136
			$sql .= ", pl.label as label_translated";
2137
			$selectFields .= ", label_translated";
2138
		}
2139
		// Price by quantity
2140
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
2141
		{
2142
			$sql .= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid";
2143
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql .= " AND price_level=".$price_level;
2144
			$sql .= " ORDER BY date_price";
2145
			$sql .= " DESC LIMIT 1) as price_rowid";
2146
			$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
2147
			if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) $sql .= " AND price_level=".$price_level;
2148
			$sql .= " ORDER BY date_price";
2149
			$sql .= " DESC LIMIT 1) as price_by_qty";
2150
			$selectFields .= ", price_rowid, price_by_qty";
2151
		}
2152
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2153
		if (count($warehouseStatusArray))
2154
		{
2155
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
2156
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")";
2157
			$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.
2158
		}
2159
2160
		// include search in supplier ref
2161
		if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
2162
		{
2163
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
2164
		}
2165
2166
		//Price by customer
2167
		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
2168
			$sql .= " LEFT JOIN  ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".$socid." AND pcp.fk_product=p.rowid";
2169
		}
2170
		// Units
2171
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2172
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2173
		}
2174
		// Multilang : we add translation
2175
		if (!empty($conf->global->MAIN_MULTILANGS))
2176
		{
2177
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang='".$this->db->escape($langs->getDefaultLang())."'";
2178
		}
2179
2180
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2181
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
2182
		}
2183
2184
		$sql .= ' WHERE p.entity IN ('.getEntity('product').')';
2185
2186
		if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
2187
			$sql .= " AND pac.rowid IS NULL";
2188
		}
2189
2190
		if ($finished == 0)
2191
		{
2192
			$sql .= " AND p.finished = ".$finished;
2193
		} elseif ($finished == 1)
2194
		{
2195
			$sql .= " AND p.finished = ".$finished;
2196
			if ($status >= 0)  $sql .= " AND p.tosell = ".$status;
2197
		} elseif ($status >= 0)
2198
		{
2199
			$sql .= " AND p.tosell = ".$status;
2200
		}
2201
		// Filter by product type
2202
		if (strval($filtertype) != '') $sql .= " AND p.fk_product_type = ".$filtertype;
2203
		elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only
2204
			$sql .= " AND p.fk_product_type = 1";
2205
		} elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only
2206
			$sql .= " AND p.fk_product_type = 0";
2207
		}
2208
		// Add criteria on ref/label
2209
		if ($filterkey != '')
2210
		{
2211
			$sql .= ' AND (';
2212
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2213
			// For natural search
2214
			$scrit = explode(' ', $filterkey);
2215
			$i = 0;
2216
			if (count($scrit) > 1) $sql .= "(";
2217
			foreach ($scrit as $crit)
2218
			{
2219
				if ($i > 0) $sql .= " AND ";
2220
				$sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2221
				if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'";
2222
				if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION))
2223
				{
2224
					$sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2225
					if (!empty($conf->global->MAIN_MULTILANGS)) $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'";
2226
				}
2227
				if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'";
2228
				$sql .= ")";
2229
				$i++;
2230
			}
2231
			if (count($scrit) > 1) $sql .= ")";
2232
			if (!empty($conf->barcode->enabled)) $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2233
			$sql .= ')';
2234
		}
2235
		if (count($warehouseStatusArray))
2236
		{
2237
			$sql .= ' GROUP BY'.$selectFields;
2238
		}
2239
2240
		//Sort by category
2241
		if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY))
2242
		{
2243
			$sql .= " ORDER BY categorie_product_id ";
2244
			//ASC OR DESC order
2245
			($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC";
2246
		} else {
2247
			$sql .= $this->db->order("p.ref");
2248
		}
2249
2250
		$sql .= $this->db->plimit($limit, 0);
2251
2252
		// Build output string
2253
		dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG);
2254
		$result = $this->db->query($sql);
2255
		if ($result)
2256
		{
2257
			require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2258
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2259
			require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2260
2261
			$num = $this->db->num_rows($result);
2262
2263
			$events = null;
2264
2265
			if (!$forcecombo)
2266
			{
2267
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2268
				$out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT);
2269
			}
2270
2271
			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
2272
2273
			$textifempty = '';
2274
			// Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
2275
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
2276
			if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2277
			{
2278
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
2279
				else $textifempty .= $langs->trans("All");
2280
			} else {
2281
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
2282
			}
2283
			if ($showempty) $out .= '<option value="0" selected>'.$textifempty.'</option>';
2284
2285
			$i = 0;
2286
			while ($num && $i < $num)
2287
			{
2288
				$opt = '';
2289
				$optJson = array();
2290
				$objp = $this->db->fetch_object($result);
2291
2292
				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)
2293
				{ // Price by quantity will return many prices for the same product
2294
					$sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
2295
					$sql .= " FROM ".MAIN_DB_PREFIX."product_price_by_qty";
2296
					$sql .= " WHERE fk_product_price=".$objp->price_rowid;
2297
					$sql .= " ORDER BY quantity ASC";
2298
2299
					dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG);
2300
					$result2 = $this->db->query($sql);
2301
					if ($result2)
2302
					{
2303
						$nb_prices = $this->db->num_rows($result2);
2304
						$j = 0;
2305
						while ($nb_prices && $j < $nb_prices) {
2306
							$objp2 = $this->db->fetch_object($result2);
2307
2308
							$objp->price_by_qty_rowid = $objp2->rowid;
2309
							$objp->price_by_qty_price_base_type = $objp2->price_base_type;
2310
							$objp->price_by_qty_quantity = $objp2->quantity;
2311
							$objp->price_by_qty_unitprice = $objp2->unitprice;
2312
							$objp->price_by_qty_remise_percent = $objp2->remise_percent;
2313
							// For backward compatibility
2314
							$objp->quantity = $objp2->quantity;
2315
							$objp->price = $objp2->price;
2316
							$objp->unitprice = $objp2->unitprice;
2317
							$objp->remise_percent = $objp2->remise_percent;
2318
							$objp->remise = $objp2->remise;
2319
2320
							$this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
2321
2322
							$j++;
2323
2324
							// Add new entry
2325
							// "key" value of json key array is used by jQuery automatically as selected value
2326
							// "label" value of json key array is used by jQuery automatically as text for combo box
2327
							$out .= $opt;
2328
							array_push($outarray, $optJson);
2329
						}
2330
					}
2331
				} else {
2332
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) {
2333
						$price_product = new Product($this->db);
2334
						$price_product->fetch($objp->rowid, '', '', 1);
2335
						$priceparser = new PriceParser($this->db);
2336
						$price_result = $priceparser->parseProduct($price_product);
2337
						if ($price_result >= 0) {
2338
							$objp->price = $price_result;
2339
							$objp->unitprice = $price_result;
2340
							//Calculate the VAT
2341
							$objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100));
2342
							$objp->price_ttc = price2num($objp->price_ttc, 'MU');
2343
						}
2344
					}
2345
2346
					$this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
2347
					// Add new entry
2348
					// "key" value of json key array is used by jQuery automatically as selected value
2349
					// "label" value of json key array is used by jQuery automatically as text for combo box
2350
					$out .= $opt;
2351
					array_push($outarray, $optJson);
2352
				}
2353
2354
				$i++;
2355
			}
2356
2357
			$out .= '</select>';
2358
2359
			$this->db->free($result);
2360
2361
			if (empty($outputmode)) return $out;
2362
			return $outarray;
2363
		} else {
2364
			dol_print_error($db);
2365
		}
2366
	}
2367
2368
	/**
2369
	 * constructProductListOption.
2370
	 * This define value for &$opt and &$optJson.
2371
	 *
2372
	 * @param 	resource	$objp			    Resultset of fetch
2373
	 * @param 	string		$opt			    Option (var used for returned value in string option format)
2374
	 * @param 	string		$optJson		    Option (var used for returned value in json format)
2375
	 * @param 	int			$price_level	    Price level
2376
	 * @param 	string		$selected		    Preselected value
2377
	 * @param   int         $hidepriceinlabel   Hide price in label
2378
	 * @param   string      $filterkey          Filter key to highlight
2379
	 * @param	int			$novirtualstock 	Do not load virtual stock, even if slow option STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO is on.
2380
	 * @return	void
2381
	 */
2382
	protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
2383
	{
2384
		global $langs, $conf, $user, $db;
2385
2386
		$outkey = '';
2387
		$outval = '';
2388
		$outref = '';
2389
		$outlabel = '';
2390
		$outdesc = '';
2391
		$outbarcode = '';
2392
		$outorigin = '';
2393
		$outtype = '';
2394
		$outprice_ht = '';
2395
		$outprice_ttc = '';
2396
		$outpricebasetype = '';
2397
		$outtva_tx = '';
2398
		$outqty = 1;
2399
		$outdiscount = 0;
2400
2401
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2402
2403
		$label = $objp->label;
2404
		if (!empty($objp->label_translated)) $label = $objp->label_translated;
2405
		if (!empty($filterkey) && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2406
2407
		$outkey = $objp->rowid;
2408
		$outref = $objp->ref;
2409
		$outlabel = $objp->label;
2410
		$outdesc = $objp->description;
2411
		$outbarcode = $objp->barcode;
2412
		$outorigin = $objp->fk_country;
2413
		$outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
2414
2415
		$outtype = $objp->fk_product_type;
2416
		$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2417
		$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2418
2419
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO))  require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
2420
2421
		// Units
2422
		$outvalUnits = '';
2423
		if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2424
			if (!empty($objp->unit_short)) {
2425
				$outvalUnits .= ' - '.$objp->unit_short;
2426
			}
2427
		}
2428
		if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) {
2429
			if (!empty($objp->weight) && $objp->weight_units !== null) {
2430
				$unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2431
				$outvalUnits .= ' - '.$unitToShow;
2432
			}
2433
			if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2434
				$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2435
				$outvalUnits .= ' - '.$unitToShow;
2436
			}
2437
			if (!empty($objp->surface) && $objp->surface_units !== null) {
2438
				$unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2439
				$outvalUnits .= ' - '.$unitToShow;
2440
			}
2441
			if (!empty($objp->volume) && $objp->volume_units !== null) {
2442
				$unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2443
				$outvalUnits .= ' - '.$unitToShow;
2444
			}
2445
		}
2446
		if ($outdurationvalue && $outdurationunit) {
2447
			$da = array(
2448
				'h' => $langs->trans('Hour'),
2449
				'd' => $langs->trans('Day'),
2450
				'w' => $langs->trans('Week'),
2451
				'm' => $langs->trans('Month'),
2452
				'y' => $langs->trans('Year')
2453
			);
2454
			if (isset($da[$outdurationunit])) {
2455
				$outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2456
			}
2457
		}
2458
2459
		$opt = '<option value="'.$objp->rowid.'"';
2460
		$opt .= ($objp->rowid == $selected) ? ' selected' : '';
2461
		if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0)
2462
		{
2463
			$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.'"';
2464
		}
2465
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2466
		{
2467
			if (!empty($user->rights->stock->lire)) {
2468
				if ($objp->stock > 0) $opt .= ' class="product_line_stock_ok"';
2469
		   		elseif ($objp->stock <= 0) $opt .= ' class="product_line_stock_too_low"';
2470
			}
2471
		}
2472
		$opt .= '>';
2473
		$opt .= $objp->ref;
2474
		if ($outbarcode) $opt .= ' ('.$outbarcode.')';
2475
		$opt .= ' - '.dol_trunc($label, $maxlengtharticle);
2476
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) $opt .= ' ('.getCountry($outorigin, 1).')';
2477
2478
		$objRef = $objp->ref;
2479
		if (!empty($filterkey) && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2480
		$outval .= $objRef;
2481
		if ($outbarcode) $outval .= ' ('.$outbarcode.')';
2482
		$outval .= ' - '.dol_trunc($label, $maxlengtharticle);
2483
		if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) $outval .= ' ('.getCountry($outorigin, 1).')';
2484
2485
		// Units
2486
		$opt .= $outvalUnits;
2487
		$outval .= $outvalUnits;
2488
2489
		$found = 0;
2490
2491
		// Multiprice
2492
		// If we need a particular price level (from 1 to 6)
2493
		if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)))
2494
		{
2495
			$sql = "SELECT price, price_ttc, price_base_type, tva_tx";
2496
			$sql .= " FROM ".MAIN_DB_PREFIX."product_price";
2497
			$sql .= " WHERE fk_product = ".((int) $objp->rowid);
2498
			$sql .= " AND entity IN (".getEntity('productprice').")";
2499
			$sql .= " AND price_level = ".((int) $price_level);
2500
			$sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
2501
			$sql .= " LIMIT 1";
2502
2503
			dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG);
2504
			$result2 = $this->db->query($sql);
2505
			if ($result2)
2506
			{
2507
				$objp2 = $this->db->fetch_object($result2);
2508
				if ($objp2)
2509
				{
2510
					$found = 1;
2511
					if ($objp2->price_base_type == 'HT')
2512
					{
2513
						$opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2514
						$outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2515
					} else {
2516
						$opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2517
						$outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2518
					}
2519
					$outprice_ht = price($objp2->price);
2520
					$outprice_ttc = price($objp2->price_ttc);
2521
					$outpricebasetype = $objp2->price_base_type;
2522
					$outtva_tx = $objp2->tva_tx;
2523
				}
2524
			} else {
2525
				dol_print_error($this->db);
2526
			}
2527
		}
2528
2529
		// Price by quantity
2530
		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)))
2531
		{
2532
			$found = 1;
2533
			$outqty = $objp->quantity;
2534
			$outdiscount = $objp->remise_percent;
2535
			if ($objp->quantity == 1)
2536
			{
2537
				$opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/";
2538
				$outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/";
2539
				$opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2540
				$outval .= $langs->transnoentities("Unit");
2541
			} else {
2542
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2543
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity;
2544
				$opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2545
				$outval .= $langs->transnoentities("Units");
2546
			}
2547
2548
			$outprice_ht = price($objp->unitprice);
2549
			$outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
2550
			$outpricebasetype = $objp->price_base_type;
2551
			$outtva_tx = $objp->tva_tx;
2552
		}
2553
		if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1)
2554
		{
2555
			$opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2556
			$outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding
2557
		}
2558
		if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1)
2559
		{
2560
			$opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2561
			$outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2562
		}
2563
2564
		// Price by customer
2565
		if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES))
2566
		{
2567
			if (!empty($objp->idprodcustprice))
2568
			{
2569
				$found = 1;
2570
2571
				if ($objp->custprice_base_type == 'HT')
2572
				{
2573
					$opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2574
					$outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2575
				} else {
2576
					$opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2577
					$outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2578
				}
2579
2580
				$outprice_ht = price($objp->custprice);
2581
				$outprice_ttc = price($objp->custprice_ttc);
2582
				$outpricebasetype = $objp->custprice_base_type;
2583
				$outtva_tx = $objp->custtva_tx;
2584
			}
2585
		}
2586
2587
		// If level no defined or multiprice not found, we used the default price
2588
		if (empty($hidepriceinlabel) && !$found)
2589
		{
2590
			if ($objp->price_base_type == 'HT')
2591
			{
2592
				$opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT");
2593
				$outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT");
2594
			} else {
2595
				$opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC");
2596
				$outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC");
2597
			}
2598
			$outprice_ht = price($objp->price);
2599
			$outprice_ttc = price($objp->price_ttc);
2600
			$outpricebasetype = $objp->price_base_type;
2601
			$outtva_tx = $objp->tva_tx;
2602
		}
2603
2604
		if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)))
2605
		{
2606
			if (!empty($user->rights->stock->lire)) {
2607
				$opt .= ' - '.$langs->trans("Stock").':'.$objp->stock;
2608
2609
				if ($objp->stock > 0) {
2610
					$outval .= ' - <span class="product_line_stock_ok">';
2611
				} elseif ($objp->stock <= 0) {
2612
					$outval .= ' - <span class="product_line_stock_too_low">';
2613
				}
2614
				$outval .= $langs->transnoentities("Stock").':'.$objp->stock;
2615
				$outval .= '</span>';
2616
				if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO))  // Warning, this option may slow down combo list generation
2617
				{
2618
					$langs->load("stocks");
2619
2620
					$tmpproduct = new Product($this->db);
2621
					$tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
2622
					$tmpproduct->load_virtual_stock();
2623
					$virtualstock = $tmpproduct->stock_theorique;
2624
2625
					$opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock;
2626
2627
					$outval .= ' - '.$langs->transnoentities("VirtualStock").':';
2628
					if ($virtualstock > 0) {
2629
						$outval .= '<span class="product_line_stock_ok">';
2630
					} elseif ($virtualstock <= 0) {
2631
						$outval .= '<span class="product_line_stock_too_low">';
2632
					}
2633
					$outval .= $virtualstock;
2634
					$outval .= '</span>';
2635
2636
					unset($tmpproduct);
2637
				}
2638
			}
2639
		}
2640
2641
		$opt .= "</option>\n";
2642
		$optJson = array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'label2'=>$outlabel, 'desc'=>$outdesc, 'type'=>$outtype, 'price_ht'=>price2num($outprice_ht), 'price_ttc'=>price2num($outprice_ttc), 'pricebasetype'=>$outpricebasetype, 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 'discount'=>$outdiscount, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit, 'pbq'=>$outpbq);
2643
	}
2644
2645
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2646
	/**
2647
	 *	Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list)
2648
	 *
2649
	 *	@param	int		$socid			Id third party
2650
	 *	@param  string	$selected       Preselected product
2651
	 *	@param  string	$htmlname       Name of HTML Select
2652
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
2653
	 *	@param  string	$filtre			For a SQL filter
2654
	 *	@param	array	$ajaxoptions	Options for ajax_autocompleter
2655
	 *  @param	int		$hidelabel		Hide label (0=no, 1=yes)
2656
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
2657
	 *  @param	string	$morecss		More CSS
2658
	 *	@return	void
2659
	 */
2660
	public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '')
2661
	{
2662
		// phpcs:enable
2663
		global $langs, $conf;
2664
		global $price_level, $status, $finished;
2665
2666
		$selected_input_value = '';
2667
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT))
2668
		{
2669
			if ($selected > 0)
2670
			{
2671
				require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
2672
				$producttmpselect = new Product($this->db);
2673
				$producttmpselect->fetch($selected);
2674
				$selected_input_value = $producttmpselect->ref;
2675
				unset($producttmpselect);
2676
			}
2677
2678
			// mode=2 means suppliers products
2679
			$urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice;
2680
			print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
2681
			print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" size="20" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'">';
2682
		} else {
2683
			print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', -1, 0, 0, $alsoproductwithnosupplierprice, $morecss);
2684
		}
2685
	}
2686
2687
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2688
	/**
2689
	 *	Return list of suppliers products
2690
	 *
2691
	 *	@param	int		$socid   		Id societe fournisseur (0 pour aucun filtre)
2692
	 *	@param  int		$selected       Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD')
2693
	 *	@param  string	$htmlname       Nom de la zone select
2694
	 *  @param	string	$filtertype     Filter on product type (''=nofilter, 0=product, 1=service)
2695
	 *	@param  string	$filtre         Pour filtre sql
2696
	 *	@param  string	$filterkey      Filtre des produits
2697
	 *  @param  int		$statut         -1=Return all products, 0=Products not on sell, 1=Products on sell (not used here, a filter on tobuy is already hard coded in request)
2698
	 *  @param  int		$outputmode     0=HTML select string, 1=Array
2699
	 *  @param  int     $limit          Limit of line number
2700
	 *  @param  int     $alsoproductwithnosupplierprice    1=Add also product without supplier prices
2701
	 *  @param	string	$morecss		Add more CSS
2702
	 *  @return array           		Array of keys for json
2703
	 */
2704
	public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '')
2705
	{
2706
		// phpcs:enable
2707
		global $langs, $conf, $db;
2708
2709
		$out = '';
2710
		$outarray = array();
2711
2712
		$maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
2713
2714
		$langs->load('stocks');
2715
		// Units
2716
		if ($conf->global->PRODUCT_USE_UNITS) {
2717
			$langs->load('other');
2718
		}
2719
2720
		$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type,";
2721
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,";
2722
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,";
2723
		$sql .= " pfp.supplier_reputation";
2724
		// Units
2725
		if ($conf->global->PRODUCT_USE_UNITS) {
2726
			$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";
2727
		}
2728
		if (!empty($conf->barcode->enabled)) $sql .= ", pfp.barcode";
2729
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
2730
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )";
2731
		if ($socid) $sql .= " AND pfp.fk_soc = ".$socid;
2732
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
2733
		// Units
2734
		if ($conf->global->PRODUCT_USE_UNITS) {
2735
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit";
2736
		}
2737
		$sql .= " WHERE p.entity IN (".getEntity('product').")";
2738
		$sql .= " AND p.tobuy = 1";
2739
		if (strval($filtertype) != '') $sql .= " AND p.fk_product_type=".$this->db->escape($filtertype);
2740
		if (!empty($filtre)) $sql .= " ".$filtre;
2741
		// Add criteria on ref/label
2742
		if ($filterkey != '')
2743
		{
2744
			$sql .= ' AND (';
2745
			$prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
2746
			// For natural search
2747
			$scrit = explode(' ', $filterkey);
2748
			$i = 0;
2749
			if (count($scrit) > 1) $sql .= "(";
2750
			foreach ($scrit as $crit)
2751
			{
2752
				if ($i > 0) $sql .= " AND ";
2753
				$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)."%')";
2754
				$i++;
2755
			}
2756
			if (count($scrit) > 1) $sql .= ")";
2757
			if (!empty($conf->barcode->enabled)) {
2758
				$sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2759
				$sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
2760
			}
2761
			$sql .= ')';
2762
		}
2763
		$sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
2764
		$sql .= $this->db->plimit($limit, 0);
2765
2766
		// Build output string
2767
2768
		dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG);
2769
		$result = $this->db->query($sql);
2770
		if ($result)
2771
		{
2772
			require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
2773
			require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
2774
2775
			$num = $this->db->num_rows($result);
2776
2777
			//$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">';	// remove select to have id same with combo and ajax
2778
			$out .= '<select class="flat maxwidthonsmartphone'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">';
2779
			if (!$selected) $out .= '<option value="0" selected>&nbsp;</option>';
2780
			else $out .= '<option value="0">&nbsp;</option>';
2781
2782
			$i = 0;
2783
			while ($i < $num)
2784
			{
2785
				$objp = $this->db->fetch_object($result);
2786
2787
				$outkey = $objp->idprodfournprice; // id in table of price
2788
				if (!$outkey && $alsoproductwithnosupplierprice) $outkey = 'idprod_'.$objp->rowid; // id of product
2789
2790
				$outref = $objp->ref;
2791
				$outval = '';
2792
				$outbarcode = $objp->barcode;
2793
				$outqty = 1;
2794
				$outdiscount = 0;
2795
				$outtype = $objp->fk_product_type;
2796
				$outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
2797
				$outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : '';
2798
2799
				// Units
2800
				$outvalUnits = '';
2801
				if ($conf->global->PRODUCT_USE_UNITS) {
2802
					if (!empty($objp->unit_short)) {
2803
						$outvalUnits .= ' - '.$objp->unit_short;
2804
					}
2805
					if (!empty($objp->weight) && $objp->weight_units !== null) {
2806
						$unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
2807
						$outvalUnits .= ' - '.$unitToShow;
2808
					}
2809
					if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
2810
						$unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units);
2811
						$outvalUnits .= ' - '.$unitToShow;
2812
					}
2813
					if (!empty($objp->surface) && $objp->surface_units !== null) {
2814
						$unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
2815
						$outvalUnits .= ' - '.$unitToShow;
2816
					}
2817
					if (!empty($objp->volume) && $objp->volume_units !== null) {
2818
						$unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
2819
						$outvalUnits .= ' - '.$unitToShow;
2820
					}
2821
					if ($outdurationvalue && $outdurationunit) {
2822
						$da = array(
2823
							'h' => $langs->trans('Hour'),
2824
							'd' => $langs->trans('Day'),
2825
							'w' => $langs->trans('Week'),
2826
							'm' => $langs->trans('Month'),
2827
							'y' => $langs->trans('Year')
2828
						);
2829
						if (isset($da[$outdurationunit])) {
2830
							$outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : ''));
2831
						}
2832
					}
2833
				}
2834
2835
				$objRef = $objp->ref;
2836
				if ($filterkey && $filterkey != '') $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1);
2837
				$objRefFourn = $objp->ref_fourn;
2838
				if ($filterkey && $filterkey != '') $objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1);
2839
				$label = $objp->label;
2840
				if ($filterkey && $filterkey != '') $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1);
2841
2842
				$optlabel = $objp->ref;
2843
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
2844
					$optlabel .= ' <span class=\'opacitymedium\'>('.$objp->ref_fourn.')</span>';
2845
				}
2846
				if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
2847
					$optlabel .= ' ('.$outbarcode.')';
2848
				}
2849
				$optlabel .= ' - '.dol_trunc($label, $maxlengtharticle);
2850
2851
				$outvallabel = $objRef;
2852
				if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
2853
					$outvallabel .= ' ('.$objRefFourn.')';
2854
				}
2855
				if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) {
2856
					$outvallabel .= ' ('.$outbarcode.')';
2857
				}
2858
				$outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle);
2859
2860
				// Units
2861
				$optlabel .= $outvalUnits;
2862
				$outvallabel .= $outvalUnits;
2863
2864
				if (!empty($objp->idprodfournprice))
2865
				{
2866
					$outqty = $objp->quantity;
2867
					$outdiscount = $objp->remise_percent;
2868
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
2869
						$prod_supplier = new ProductFournisseur($this->db);
2870
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
2871
						$prod_supplier->id = $objp->fk_product;
2872
						$prod_supplier->fourn_qty = $objp->quantity;
2873
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
2874
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
2875
						$priceparser = new PriceParser($this->db);
2876
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
2877
						if ($price_result >= 0) {
2878
							$objp->fprice = $price_result;
2879
							if ($objp->quantity >= 1)
2880
							{
2881
								$objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
2882
							}
2883
						}
2884
					}
2885
					if ($objp->quantity == 1)
2886
					{
2887
						$optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
2888
						$outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/";
2889
						$optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
2890
						$outvallabel .= $langs->transnoentities("Unit");
2891
					} else {
2892
						$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;
2893
						$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;
2894
						$optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
2895
						$outvallabel .= ' '.$langs->transnoentities("Units");
2896
					}
2897
2898
					if ($objp->quantity > 1)
2899
					{
2900
						$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
2901
						$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
2902
					}
2903
					if ($objp->remise_percent >= 1)
2904
					{
2905
						$optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %';
2906
						$outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %';
2907
					}
2908
					if ($objp->duration)
2909
					{
2910
						$optlabel .= " - ".$objp->duration;
2911
						$outvallabel .= " - ".$objp->duration;
2912
					}
2913
					if (!$socid)
2914
					{
2915
						$optlabel .= " - ".dol_trunc($objp->name, 8);
2916
						$outvallabel .= " - ".dol_trunc($objp->name, 8);
2917
					}
2918
					if ($objp->supplier_reputation)
2919
					{
2920
						//TODO dictionary
2921
						$reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier'));
2922
2923
						$optlabel .= " - ".$reputations[$objp->supplier_reputation];
2924
						$outvallabel .= " - ".$reputations[$objp->supplier_reputation];
2925
					}
2926
				} else {
2927
					if (empty($alsoproductwithnosupplierprice))     // No supplier price defined for couple product/supplier
2928
					{
2929
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
2930
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
2931
					} else // No supplier price defined for product, even on other suppliers
2932
					{
2933
						$optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>';
2934
						$outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier");
2935
					}
2936
				}
2937
2938
				$opt = '<option value="'.$outkey.'"';
2939
				if ($selected && $selected == $objp->idprodfournprice) $opt .= ' selected';
2940
				if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) $opt .= ' disabled';
2941
				if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0)
2942
				{
2943
					$opt .= ' pbq="'.$objp->idprodfournprice.'" data-pbq="'.$objp->idprodfournprice.'" data-pbqqty="'.$objp->quantity.'" data-pbqup="'.$objp->unitprice.'" data-pbqpercent="'.$objp->remise_percent.'"';
2944
				}
2945
				$opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"';
2946
				$opt .= '>';
2947
2948
				$opt .= $optlabel;
2949
				$outval .= $outvallabel;
2950
2951
				$opt .= "</option>\n";
2952
2953
2954
				// Add new entry
2955
				// "key" value of json key array is used by jQuery automatically as selected value
2956
				// "label" value of json key array is used by jQuery automatically as text for combo box
2957
				$out .= $opt;
2958
				array_push($outarray, array('key'=>$outkey, 'value'=>$outref, 'label'=>$outval, 'qty'=>$outqty, 'up'=>$objp->unitprice, 'discount'=>$outdiscount, 'type'=>$outtype, 'duration_value'=>$outdurationvalue, 'duration_unit'=>$outdurationunit, 'disabled'=>(empty($objp->idprodfournprice) ?true:false)));
2959
				// Exemple of var_dump $outarray
2960
				// array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
2961
				//           ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
2962
				//      	 ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
2963
				//}
2964
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2965
				//$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
2966
				//var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
2967
2968
				$i++;
2969
			}
2970
			$out .= '</select>';
2971
2972
			$this->db->free($result);
2973
2974
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2975
			$out .= ajax_combobox($htmlname);
2976
2977
			if (empty($outputmode)) return $out;
2978
			return $outarray;
2979
		} else {
2980
			dol_print_error($this->db);
2981
		}
2982
	}
2983
2984
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2985
	/**
2986
	 *	Return list of suppliers prices for a product
2987
	 *
2988
	 *  @param	    int		$productid       	Id of product
2989
	 *  @param      string	$htmlname        	Name of HTML field
2990
	 *  @param      int		$selected_supplier  Pre-selected supplier if more than 1 result
2991
	 *  @return	    string
2992
	 */
2993
	public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '')
2994
	{
2995
		// phpcs:enable
2996
		global $langs, $conf;
2997
2998
		$langs->load('stocks');
2999
3000
		$sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
3001
		$sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
3002
		$sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
3003
		$sql .= " FROM ".MAIN_DB_PREFIX."product as p";
3004
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3005
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid";
3006
		$sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")";
3007
		$sql .= " AND p.tobuy = 1";
3008
		$sql .= " AND s.fournisseur = 1";
3009
		$sql .= " AND p.rowid = ".$productid;
3010
		$sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
3011
3012
		dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG);
3013
		$result = $this->db->query($sql);
3014
3015
		if ($result)
3016
		{
3017
			$num = $this->db->num_rows($result);
3018
3019
			$form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3020
3021
			if (!$num)
3022
			{
3023
				$form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>';
3024
			} else {
3025
				require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php';
3026
				$form .= '<option value="0">&nbsp;</option>';
3027
3028
				$i = 0;
3029
				while ($i < $num)
3030
				{
3031
					$objp = $this->db->fetch_object($result);
3032
3033
					$opt = '<option value="'.$objp->idprodfournprice.'"';
3034
					//if there is only one supplier, preselect it
3035
					if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) {
3036
						$opt .= ' selected';
3037
					}
3038
					$opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - ';
3039
3040
					if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) {
3041
						$prod_supplier = new ProductFournisseur($this->db);
3042
						$prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3043
						$prod_supplier->id = $productid;
3044
						$prod_supplier->fourn_qty = $objp->quantity;
3045
						$prod_supplier->fourn_tva_tx = $objp->tva_tx;
3046
						$prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3047
						$priceparser = new PriceParser($this->db);
3048
						$price_result = $priceparser->parseProductSupplier($prod_supplier);
3049
						if ($price_result >= 0) {
3050
							$objp->fprice = $price_result;
3051
							if ($objp->quantity >= 1)
3052
							{
3053
								$objp->unitprice = $objp->fprice / $objp->quantity;
3054
							}
3055
						}
3056
					}
3057
					if ($objp->quantity == 1)
3058
					{
3059
						$opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/";
3060
					}
3061
3062
					$opt .= $objp->quantity.' ';
3063
3064
					if ($objp->quantity == 1)
3065
					{
3066
						$opt .= $langs->trans("Unit");
3067
					} else {
3068
						$opt .= $langs->trans("Units");
3069
					}
3070
					if ($objp->quantity > 1)
3071
					{
3072
						$opt .= " - ";
3073
						$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");
3074
					}
3075
					if ($objp->duration) $opt .= " - ".$objp->duration;
3076
					$opt .= "</option>\n";
3077
3078
					$form .= $opt;
3079
					$i++;
3080
				}
3081
			}
3082
3083
			$form .= '</select>';
3084
			$this->db->free($result);
3085
			return $form;
3086
		} else {
3087
			dol_print_error($this->db);
3088
		}
3089
	}
3090
3091
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3092
	/**
3093
	 *    Return list of delivery address
3094
	 *
3095
	 *    @param    string	$selected          	Id contact pre-selectionn
3096
	 *    @param    int		$socid				Id of company
3097
	 *    @param    string	$htmlname          	Name of HTML field
3098
	 *    @param    int		$showempty         	Add an empty field
3099
	 *    @return	integer|null
3100
	 */
3101
	public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0)
3102
	{
3103
		// phpcs:enable
3104
		// looking for users
3105
		$sql = "SELECT a.rowid, a.label";
3106
		$sql .= " FROM ".MAIN_DB_PREFIX."societe_address as a";
3107
		$sql .= " WHERE a.fk_soc = ".$socid;
3108
		$sql .= " ORDER BY a.label ASC";
3109
3110
		dol_syslog(get_class($this)."::select_address", LOG_DEBUG);
3111
		$resql = $this->db->query($sql);
3112
		if ($resql)
3113
		{
3114
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3115
			if ($showempty) print '<option value="0">&nbsp;</option>';
3116
			$num = $this->db->num_rows($resql);
3117
			$i = 0;
3118
			if ($num)
3119
			{
3120
				while ($i < $num)
3121
				{
3122
					$obj = $this->db->fetch_object($resql);
3123
3124
					if ($selected && $selected == $obj->rowid)
3125
					{
3126
						print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>';
3127
					} else {
3128
						print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>';
3129
					}
3130
					$i++;
3131
				}
3132
			}
3133
			print '</select>';
3134
			return $num;
3135
		} else {
3136
			dol_print_error($this->db);
3137
		}
3138
	}
3139
3140
3141
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3142
	/**
3143
	 *      Load into cache list of payment terms
3144
	 *
3145
	 *      @return     int             Nb of lines loaded, <0 if KO
3146
	 */
3147
	public function load_cache_conditions_paiements()
3148
	{
3149
		// phpcs:enable
3150
		global $langs;
3151
3152
		$num = count($this->cache_conditions_paiements);
3153
		if ($num > 0) return 0; // Cache already loaded
3154
3155
		dol_syslog(__METHOD__, LOG_DEBUG);
3156
3157
		$sql = "SELECT rowid, code, libelle as label";
3158
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_payment_term';
3159
		$sql .= " WHERE entity IN (".getEntity('c_payment_term').")";
3160
		$sql .= " AND active > 0";
3161
		$sql .= " ORDER BY sortorder";
3162
3163
		$resql = $this->db->query($sql);
3164
		if ($resql)
3165
		{
3166
			$num = $this->db->num_rows($resql);
3167
			$i = 0;
3168
			while ($i < $num)
3169
			{
3170
				$obj = $this->db->fetch_object($resql);
3171
3172
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3173
				$label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3174
				$this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
3175
				$this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
3176
				$i++;
3177
			}
3178
3179
			//$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1);		// We use the field sortorder of table
3180
3181
			return $num;
3182
		} else {
3183
			dol_print_error($this->db);
3184
			return -1;
3185
		}
3186
	}
3187
3188
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3189
	/**
3190
	 *      Charge dans cache la liste des délais de livraison possibles
3191
	 *
3192
	 *      @return     int             Nb of lines loaded, <0 if KO
3193
	 */
3194
	public function load_cache_availability()
3195
	{
3196
		// phpcs:enable
3197
		global $langs;
3198
3199
		$num = count($this->cache_availability);
3200
		if ($num > 0) return 0; // Cache already loaded
3201
3202
		dol_syslog(__METHOD__, LOG_DEBUG);
3203
3204
		$langs->load('propal');
3205
3206
		$sql = "SELECT rowid, code, label";
3207
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_availability';
3208
		$sql .= " WHERE active > 0";
3209
3210
		$resql = $this->db->query($sql);
3211
		if ($resql)
3212
		{
3213
			$num = $this->db->num_rows($resql);
3214
			$i = 0;
3215
			while ($i < $num)
3216
			{
3217
				$obj = $this->db->fetch_object($resql);
3218
3219
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3220
				$label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3221
				$this->cache_availability[$obj->rowid]['code'] = $obj->code;
3222
				$this->cache_availability[$obj->rowid]['label'] = $label;
3223
				$i++;
3224
			}
3225
3226
			$this->cache_availability = dol_sort_array($this->cache_availability, 'label', 'asc', 0, 0, 1);
3227
3228
			return $num;
3229
		} else {
3230
			dol_print_error($this->db);
3231
			return -1;
3232
		}
3233
	}
3234
3235
	/**
3236
	 *      Retourne la liste des types de delais de livraison possibles
3237
	 *
3238
	 *      @param	int		$selected        Id du type de delais pre-selectionne
3239
	 *      @param  string	$htmlname        Nom de la zone select
3240
	 *      @param  string	$filtertype      To add a filter
3241
	 *		@param	int		$addempty		Add empty entry
3242
	 *		@return	void
3243
	 */
3244
	public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0)
3245
	{
3246
		global $langs, $user;
3247
3248
		$this->load_cache_availability();
3249
3250
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3251
3252
		print '<select id="'.$htmlname.'" class="flat" name="'.$htmlname.'">';
3253
		if ($addempty) print '<option value="0">&nbsp;</option>';
3254
		foreach ($this->cache_availability as $id => $arrayavailability)
3255
		{
3256
			if ($selected == $id)
3257
			{
3258
				print '<option value="'.$id.'" selected>';
3259
			} else {
3260
				print '<option value="'.$id.'">';
3261
			}
3262
			print $arrayavailability['label'];
3263
			print '</option>';
3264
		}
3265
		print '</select>';
3266
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3267
	}
3268
3269
	/**
3270
	 *      Load into cache cache_demand_reason, array of input reasons
3271
	 *
3272
	 *      @return     int             Nb of lines loaded, <0 if KO
3273
	 */
3274
	public function loadCacheInputReason()
3275
	{
3276
		global $langs;
3277
3278
		$num = count($this->cache_demand_reason);
3279
		if ($num > 0) return 0; // Cache already loaded
3280
3281
		$sql = "SELECT rowid, code, label";
3282
		$sql .= " FROM ".MAIN_DB_PREFIX.'c_input_reason';
3283
		$sql .= " WHERE active > 0";
3284
3285
		$resql = $this->db->query($sql);
3286
		if ($resql)
3287
		{
3288
			$num = $this->db->num_rows($resql);
3289
			$i = 0;
3290
			$tmparray = array();
3291
			while ($i < $num)
3292
			{
3293
				$obj = $this->db->fetch_object($resql);
3294
3295
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3296
				$label = ($obj->label != '-' ? $obj->label : '');
3297
				if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
3298
				if ($langs->trans($obj->code) != $obj->code) $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
3299
3300
				$tmparray[$obj->rowid]['id']   = $obj->rowid;
3301
				$tmparray[$obj->rowid]['code'] = $obj->code;
3302
				$tmparray[$obj->rowid]['label'] = $label;
3303
				$i++;
3304
			}
3305
3306
			$this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
3307
3308
			unset($tmparray);
3309
			return $num;
3310
		} else {
3311
			dol_print_error($this->db);
3312
			return -1;
3313
		}
3314
	}
3315
3316
	/**
3317
	 *	Return list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
3318
	 *  List found into table c_input_reason loaded by loadCacheInputReason
3319
	 *
3320
	 *  @param	int		$selected        Id or code of type origin to select by default
3321
	 *  @param  string	$htmlname        Nom de la zone select
3322
	 *  @param  string	$exclude         To exclude a code value (Example: SRC_PROP)
3323
	 *	@param	int		$addempty		 Add an empty entry
3324
	 *	@return	void
3325
	 */
3326
	public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0)
3327
	{
3328
		global $langs, $user;
3329
3330
		$this->loadCacheInputReason();
3331
3332
		print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3333
		if ($addempty) print '<option value="0"'.(empty($selected) ? ' selected' : '').'>&nbsp;</option>';
3334
		foreach ($this->cache_demand_reason as $id => $arraydemandreason)
3335
		{
3336
			if ($arraydemandreason['code'] == $exclude) continue;
3337
3338
			if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code']))
3339
			{
3340
				print '<option value="'.$arraydemandreason['id'].'" selected>';
3341
			} else {
3342
				print '<option value="'.$arraydemandreason['id'].'">';
3343
			}
3344
			$label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
3345
			print $langs->trans($label);
3346
			print '</option>';
3347
		}
3348
		print '</select>';
3349
		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3350
	}
3351
3352
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3353
	/**
3354
	 *      Charge dans cache la liste des types de paiements possibles
3355
	 *
3356
	 *      @return     int                 Nb of lines loaded, <0 if KO
3357
	 */
3358
	public function load_cache_types_paiements()
3359
	{
3360
		// phpcs:enable
3361
		global $langs;
3362
3363
		$num = count($this->cache_types_paiements);
3364
		if ($num > 0) return $num; // Cache already loaded
3365
3366
		dol_syslog(__METHOD__, LOG_DEBUG);
3367
3368
		$this->cache_types_paiements = array();
3369
3370
		$sql = "SELECT id, code, libelle as label, type, active";
3371
		$sql .= " FROM ".MAIN_DB_PREFIX."c_paiement";
3372
		$sql .= " WHERE entity IN (".getEntity('c_paiement').")";
3373
		//if ($active >= 0) $sql.= " AND active = ".$active;
3374
3375
		$resql = $this->db->query($sql);
3376
		if ($resql)
3377
		{
3378
			$num = $this->db->num_rows($resql);
3379
			$i = 0;
3380
			while ($i < $num)
3381
			{
3382
				$obj = $this->db->fetch_object($resql);
3383
3384
				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
3385
				$label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
3386
				$this->cache_types_paiements[$obj->id]['id'] = $obj->id;
3387
				$this->cache_types_paiements[$obj->id]['code'] = $obj->code;
3388
				$this->cache_types_paiements[$obj->id]['label'] = $label;
3389
				$this->cache_types_paiements[$obj->id]['type'] = $obj->type;
3390
				$this->cache_types_paiements[$obj->id]['active'] = $obj->active;
3391
				$i++;
3392
			}
3393
3394
			$this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
3395
3396
			return $num;
3397
		} else {
3398
			dol_print_error($this->db);
3399
			return -1;
3400
		}
3401
	}
3402
3403
3404
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3405
	/**
3406
	 *      Return list of payment modes.
3407
	 *      Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want.
3408
	 *      See instead to force the default value by the caller.
3409
	 *
3410
	 *      @param	int		$selected		Id of payment term to preselect by default
3411
	 *      @param	string	$htmlname		Nom de la zone select
3412
	 *      @param	int		$filtertype		Not used
3413
	 *		@param	int		$addempty		Add an empty entry
3414
	 * 		@param	int		$noinfoadmin		0=Add admin info, 1=Disable admin info
3415
	 * 		@param	string	$morecss			Add more CSS on select tag
3416
	 *		@return	void
3417
	 */
3418
	public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '')
3419
	{
3420
		// phpcs:enable
3421
		global $langs, $user, $conf;
3422
3423
		dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
3424
3425
		$this->load_cache_conditions_paiements();
3426
3427
		// Set default value if not already set by caller
3428
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID;
3429
3430
		print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3431
		if ($addempty) print '<option value="0">&nbsp;</option>';
3432
		foreach ($this->cache_conditions_paiements as $id => $arrayconditions)
3433
		{
3434
			if ($selected == $id)
3435
			{
3436
				print '<option value="'.$id.'" selected>';
3437
			} else {
3438
				print '<option value="'.$id.'">';
3439
			}
3440
			print $arrayconditions['label'];
3441
			print '</option>';
3442
		}
3443
		print '</select>';
3444
		if ($user->admin && empty($noinfoadmin)) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3445
		print ajax_combobox($htmlname);
3446
	}
3447
3448
3449
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3450
	/**
3451
	 *      Return list of payment methods
3452
	 *      Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value but scope is all application, probably not what you want.
3453
	 *
3454
	 *      @param	string	$selected       Id or code or preselected payment mode
3455
	 *      @param  string	$htmlname       Name of select field
3456
	 *      @param  string	$filtertype     To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz))
3457
	 *      @param  int		$format         0=id+label, 1=code+code, 2=code+label, 3=id+code
3458
	 *      @param  int		$empty			1=can be empty, 0 otherwise
3459
	 * 		@param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
3460
	 *      @param  int		$maxlength      Max length of label
3461
	 *      @param  int     $active         Active or not, -1 = all
3462
	 *      @param  string  $morecss        Add more CSS on select tag
3463
	 * 		@return	void
3464
	 */
3465
	public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
3466
	{
3467
		// phpcs:enable
3468
		global $langs, $user, $conf;
3469
3470
		dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG);
3471
3472
		$filterarray = array();
3473
		if ($filtertype == 'CRDT')  	$filterarray = array(0, 2, 3);
3474
		elseif ($filtertype == 'DBIT') 	$filterarray = array(1, 2, 3);
3475
		elseif ($filtertype != '' && $filtertype != '-1') $filterarray = explode(',', $filtertype);
3476
3477
		$this->load_cache_types_paiements();
3478
3479
		// Set default value if not already set by caller
3480
		if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID;
3481
3482
		print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">';
3483
		if ($empty) print '<option value="">&nbsp;</option>';
3484
		foreach ($this->cache_types_paiements as $id => $arraytypes)
3485
		{
3486
			// If not good status
3487
			if ($active >= 0 && $arraytypes['active'] != $active) continue;
3488
3489
			// On passe si on a demande de filtrer sur des modes de paiments particuliers
3490
			if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) continue;
3491
3492
			// We discard empty line if showempty is on because an empty line has already been output.
3493
			if ($empty && empty($arraytypes['code'])) continue;
3494
3495
			if ($format == 0) print '<option value="'.$id.'"';
3496
			elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3497
			elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3498
			elseif ($format == 3) print '<option value="'.$id.'"';
3499
			// Print attribute selected or not
3500
			if ($format == 1 || $format == 2) {
3501
				if ($selected == $arraytypes['code']) print ' selected';
3502
			} else {
3503
				if ($selected == $id) print ' selected';
3504
			}
3505
			print '>';
3506
			if ($format == 0) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3507
			elseif ($format == 1) $value = $arraytypes['code'];
3508
			elseif ($format == 2) $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
3509
			elseif ($format == 3) $value = $arraytypes['code'];
3510
			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...
3511
			print '</option>';
3512
		}
3513
		print '</select>';
3514
		if ($user->admin && !$noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3515
		print ajax_combobox('select'.$htmlname);
3516
	}
3517
3518
3519
	/**
3520
	 *  Selection HT or TTC
3521
	 *
3522
	 *  @param	string	$selected       Id pre-selectionne
3523
	 *  @param  string	$htmlname       Nom de la zone select
3524
	 * 	@return	string					Code of HTML select to chose tax or not
3525
	 */
3526
	public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type')
3527
	{
3528
		global $langs;
3529
3530
		$return = '';
3531
3532
		$return .= '<select class="flat maxwidth75" id="select_'.$htmlname.'" name="'.$htmlname.'">';
3533
		$options = array(
3534
			'HT'=>$langs->trans("HT"),
3535
			'TTC'=>$langs->trans("TTC")
3536
		);
3537
		foreach ($options as $id => $value)
3538
		{
3539
			if ($selected == $id)
3540
			{
3541
				$return .= '<option value="'.$id.'" selected>'.$value;
3542
			} else {
3543
				$return .= '<option value="'.$id.'">'.$value;
3544
			}
3545
			$return .= '</option>';
3546
		}
3547
		$return .= '</select>';
3548
3549
		return $return;
3550
	}
3551
3552
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3553
    /**
3554
     *      Load in cache list of transport mode
3555
     *
3556
     *      @return     int                 Nb of lines loaded, <0 if KO
3557
     */
3558
    public function load_cache_transport_mode()
3559
    {
3560
        // phpcs:enable
3561
        global $langs;
3562
3563
        $num=count($this->cache_transport_mode);
3564
        if ($num > 0) return $num;    // Cache already loaded
3565
3566
        dol_syslog(__METHOD__, LOG_DEBUG);
3567
3568
        $this->cache_transport_mode = array();
3569
3570
        $sql = "SELECT rowid, code, label, active";
3571
        $sql.= " FROM ".MAIN_DB_PREFIX."c_transport_mode";
3572
        $sql.= " WHERE entity IN (".getEntity('c_transport_mode').")";
3573
        //if ($active >= 0) $sql.= " AND active = ".$active;
3574
3575
        $resql = $this->db->query($sql);
3576
        if ($resql)
3577
        {
3578
            $num = $this->db->num_rows($resql);
3579
            $i = 0;
3580
            while ($i < $num)
3581
            {
3582
                $obj = $this->db->fetch_object($resql);
3583
3584
                // If traduction exist, we use it else we take the default label
3585
                $label=($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code)!=("PaymentTypeShort".$obj->code)?$langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code):($obj->label!='-'?$obj->label:''));
3586
                $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
3587
                $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
3588
                $this->cache_transport_mode[$obj->rowid]['label']= $label;
3589
                $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
3590
                $i++;
3591
            }
3592
3593
            $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
3594
3595
            return $num;
3596
        }
3597
        else {
3598
            dol_print_error($this->db);
3599
            return -1;
3600
        }
3601
    }
3602
3603
    /**
3604
     *      Return list of transport mode for intracomm report
3605
     *
3606
     *      @param	string	$selected       Id of the transport mode pre-selected
3607
     *      @param  string	$htmlname       Name of the select field
3608
     *      @param  int		$format         0=id+label, 1=code+code, 2=code+label, 3=id+code
3609
     *      @param  int		$empty			1=can be empty, 0 else
3610
     *      @param	int		$noadmininfo	0=Add admin info, 1=Disable admin info
3611
     *      @param  int		$maxlength      Max length of label
3612
     *      @param  int     $active         Active or not, -1 = all
3613
     *      @param  string  $morecss        Add more CSS on select tag
3614
     * 		@return	void
3615
     */
3616
    public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
3617
    {
3618
        global $langs,$user;
3619
3620
        dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG);
3621
3622
        $this->load_cache_transport_mode();
3623
3624
        print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss?' '.$morecss:'').'" name="'.$htmlname.'">';
3625
        if ($empty) print '<option value="">&nbsp;</option>';
3626
        foreach ($this->cache_transport_mode as $id => $arraytypes)
3627
        {
3628
            // If not good status
3629
            if ($active >= 0 && $arraytypes['active'] != $active) continue;
3630
3631
            // We discard empty line if showempty is on because an empty line has already been output.
3632
            if ($empty && empty($arraytypes['code'])) continue;
3633
3634
            if ($format == 0) print '<option value="'.$id.'"';
3635
            elseif ($format == 1) print '<option value="'.$arraytypes['code'].'"';
3636
            elseif ($format == 2) print '<option value="'.$arraytypes['code'].'"';
3637
            elseif ($format == 3) print '<option value="'.$id.'"';
3638
            // If text is selected, we compare with code, else with id
3639
            if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) print ' selected';
3640
            elseif ($selected == $id) print ' selected';
3641
            print '>';
3642
            if ($format == 0) $value=($maxlength?dol_trunc($arraytypes['label'], $maxlength):$arraytypes['label']);
3643
            elseif ($format == 1) $value=$arraytypes['code'];
3644
            elseif ($format == 2) $value=($maxlength?dol_trunc($arraytypes['label'], $maxlength):$arraytypes['label']);
3645
            elseif ($format == 3) $value=$arraytypes['code'];
3646
            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...
3647
            print '</option>';
3648
        }
3649
        print '</select>';
3650
        if ($user->admin && ! $noadmininfo) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3651
    }
3652
3653
	/**
3654
	 *  Return a HTML select list of shipping mode
3655
	 *
3656
	 *  @param	string	$selected          Id shipping mode pre-selected
3657
	 *  @param  string	$htmlname          Name of select zone
3658
	 *  @param  string	$filtre            To filter list
3659
	 *  @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.
3660
	 *  @param  string	$moreattrib        To add more attribute on select
3661
	 * 	@return	void
3662
	 */
3663
	public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '')
3664
	{
3665
		global $langs, $conf, $user;
3666
3667
		$langs->load("admin");
3668
		$langs->load("deliveries");
3669
3670
		$sql = "SELECT rowid, code, libelle as label";
3671
		$sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode";
3672
		$sql .= " WHERE active > 0";
3673
		if ($filtre) $sql .= " AND ".$filtre;
3674
		$sql .= " ORDER BY libelle ASC";
3675
3676
		dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG);
3677
		$result = $this->db->query($sql);
3678
		if ($result) {
3679
			$num = $this->db->num_rows($result);
3680
			$i = 0;
3681
			if ($num) {
3682
				print '<select id="select'.$htmlname.'" class="flat selectshippingmethod" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3683
				if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
3684
					print '<option value="-1">&nbsp;</option>';
3685
				}
3686
				while ($i < $num) {
3687
					$obj = $this->db->fetch_object($result);
3688
					if ($selected == $obj->rowid) {
3689
						print '<option value="'.$obj->rowid.'" selected>';
3690
					} else {
3691
						print '<option value="'.$obj->rowid.'">';
3692
					}
3693
					print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label;
3694
					print '</option>';
3695
					$i++;
3696
				}
3697
				print "</select>";
3698
				if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3699
			} else {
3700
				print $langs->trans("NoShippingMethodDefined");
3701
			}
3702
		} else {
3703
			dol_print_error($this->db);
3704
		}
3705
	}
3706
3707
	/**
3708
	 *    Display form to select shipping mode
3709
	 *
3710
	 *    @param	string	$page        Page
3711
	 *    @param    int		$selected    Id of shipping mode
3712
	 *    @param    string	$htmlname    Name of select html field
3713
	 *    @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.
3714
	 *    @return	void
3715
	 */
3716
	public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
3717
	{
3718
		global $langs, $db;
3719
3720
		$langs->load("deliveries");
3721
3722
		if ($htmlname != "none") {
3723
			print '<form method="POST" action="'.$page.'">';
3724
			print '<input type="hidden" name="action" value="setshippingmethod">';
3725
			print '<input type="hidden" name="token" value="'.newToken().'">';
3726
			$this->selectShippingMethod($selected, $htmlname, '', $addempty);
3727
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3728
			print '</form>';
3729
		} else {
3730
			if ($selected) {
3731
				$code = $langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code');
3732
				print $langs->trans("SendingMethod".strtoupper($code));
3733
			} else {
3734
				print "&nbsp;";
3735
			}
3736
		}
3737
	}
3738
3739
	/**
3740
	 * Creates HTML last in cycle situation invoices selector
3741
	 *
3742
	 * @param     string  $selected   		Preselected ID
3743
	 * @param     int     $socid      		Company ID
3744
	 *
3745
	 * @return    string                     HTML select
3746
	 */
3747
	public function selectSituationInvoices($selected = '', $socid = 0)
3748
	{
3749
		global $langs;
3750
3751
		$langs->load('bills');
3752
3753
		$opt = '<option value ="" selected></option>';
3754
		$sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc';
3755
		$sql .= ' FROM '.MAIN_DB_PREFIX.'facture';
3756
		$sql .= ' WHERE entity IN ('.getEntity('invoice').')';
3757
		$sql .= ' AND situation_counter >= 1';
3758
		$sql .= ' AND fk_soc = '.(int) $socid;
3759
		$sql .= ' AND type <> 2';
3760
		$sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
3761
		$resql = $this->db->query($sql);
3762
3763
		if ($resql && $this->db->num_rows($resql) > 0) {
3764
			// Last seen cycle
3765
			$ref = 0;
3766
			while ($obj = $this->db->fetch_object($resql)) {
3767
				//Same cycle ?
3768
				if ($obj->situation_cycle_ref != $ref) {
3769
					// Just seen this cycle
3770
					$ref = $obj->situation_cycle_ref;
3771
					//not final ?
3772
					if ($obj->situation_final != 1) {
3773
						//Not prov?
3774
						if (substr($obj->ref, 1, 4) != 'PROV') {
3775
							if ($selected == $obj->rowid) {
3776
								$opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>';
3777
							} else {
3778
								$opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>';
3779
							}
3780
						}
3781
					}
3782
				}
3783
			}
3784
		} else {
3785
				dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR);
3786
		}
3787
		if ($opt == '<option value ="" selected></option>')
3788
		{
3789
			$opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>';
3790
		}
3791
		return $opt;
3792
	}
3793
3794
	/**
3795
	 *      Creates HTML units selector (code => label)
3796
	 *
3797
	 *      @param	string	$selected       Preselected Unit ID
3798
	 *      @param  string	$htmlname       Select name
3799
	 *      @param	int		$showempty		Add a nempty line
3800
	 * 		@return	string                  HTML select
3801
	 */
3802
	public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0)
3803
	{
3804
		global $langs;
3805
3806
		$langs->load('products');
3807
3808
		$return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
3809
3810
		$sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units';
3811
		$sql .= ' WHERE active > 0';
3812
3813
		$resql = $this->db->query($sql);
3814
		if ($resql && $this->db->num_rows($resql) > 0)
3815
		{
3816
			if ($showempty) $return .= '<option value="none"></option>';
3817
3818
			while ($res = $this->db->fetch_object($resql))
3819
			{
3820
				$unitLabel = $res->label;
3821
				if (!empty($langs->tab_translate['unit'.$res->code]))	// check if Translation is available before
3822
				{
3823
					$unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label;
3824
				}
3825
3826
				if ($selected == $res->rowid)
3827
				{
3828
					$return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
3829
				} else {
3830
					$return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
3831
				}
3832
			}
3833
			$return .= '</select>';
3834
		}
3835
		return $return;
3836
	}
3837
3838
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3839
	/**
3840
	 *  Return a HTML select list of bank accounts
3841
	 *
3842
	 *  @param	string	$selected           Id account pre-selected
3843
	 *  @param  string	$htmlname           Name of select zone
3844
	 *  @param  int		$status             Status of searched accounts (0=open, 1=closed, 2=both)
3845
	 *  @param  string	$filtre             To filter list
3846
	 *  @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.
3847
	 *  @param  string	$moreattrib         To add more attribute on select
3848
	 *  @param	int		$showcurrency		Show currency in label
3849
	 *  @param	string	$morecss			More CSS
3850
	 * 	@return	int							<0 if error, Num of bank account found if OK (0, 1, 2, ...)
3851
	 */
3852
	public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '')
3853
	{
3854
		// phpcs:enable
3855
		global $langs, $conf;
3856
3857
		$langs->load("admin");
3858
		$num = 0;
3859
3860
		$sql = "SELECT rowid, label, bank, clos as status, currency_code";
3861
		$sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
3862
		$sql .= " WHERE entity IN (".getEntity('bank_account').")";
3863
		if ($status != 2) $sql .= " AND clos = ".(int) $status;
3864
		if ($filtre) $sql .= " AND ".$filtre;
3865
		$sql .= " ORDER BY label";
3866
3867
		dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG);
3868
		$result = $this->db->query($sql);
3869
		if ($result)
3870
		{
3871
			$num = $this->db->num_rows($result);
3872
			$i = 0;
3873
			if ($num)
3874
			{
3875
				print '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3876
				if ($useempty == 1 || ($useempty == 2 && $num > 1))
3877
				{
3878
					print '<option value="-1">&nbsp;</option>';
3879
				}
3880
3881
				while ($i < $num)
3882
				{
3883
					$obj = $this->db->fetch_object($result);
3884
					if ($selected == $obj->rowid)
3885
					{
3886
						print '<option value="'.$obj->rowid.'" selected>';
3887
					} else {
3888
						print '<option value="'.$obj->rowid.'">';
3889
					}
3890
					print trim($obj->label);
3891
					if ($showcurrency) print ' ('.$obj->currency_code.')';
3892
					if ($status == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
3893
					print '</option>';
3894
					$i++;
3895
				}
3896
				print "</select>";
3897
			} else {
3898
				if ($status == 0) print '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
3899
				else print '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>';
3900
			}
3901
		} else {
3902
			dol_print_error($this->db);
3903
		}
3904
3905
		return $num;
3906
	}
3907
3908
	/**
3909
	 *  Return a HTML select list of establishment
3910
	 *
3911
	 *  @param	string	$selected           Id establishment pre-selected
3912
	 *  @param  string	$htmlname           Name of select zone
3913
	 *  @param  int		$status             Status of searched establishment (0=open, 1=closed, 2=both)
3914
	 *  @param  string	$filtre             To filter list
3915
	 *  @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.
3916
	 *  @param  string	$moreattrib         To add more attribute on select
3917
	 * 	@return	int							<0 if error, Num of establishment found if OK (0, 1, 2, ...)
3918
	 */
3919
	public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
3920
	{
3921
		// phpcs:enable
3922
		global $langs, $conf;
3923
3924
		$langs->load("admin");
3925
		$num = 0;
3926
3927
		$sql = "SELECT rowid, name, fk_country, status, entity";
3928
		$sql .= " FROM ".MAIN_DB_PREFIX."establishment";
3929
		$sql .= " WHERE 1=1";
3930
		if ($status != 2) $sql .= " AND status = ".(int) $status;
3931
		if ($filtre) $sql .= " AND ".$filtre;
3932
		$sql .= " ORDER BY name";
3933
3934
		dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG);
3935
		$result = $this->db->query($sql);
3936
		if ($result)
3937
		{
3938
			$num = $this->db->num_rows($result);
3939
			$i = 0;
3940
			if ($num)
3941
			{
3942
				print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>';
3943
				if ($useempty == 1 || ($useempty == 2 && $num > 1))
3944
				{
3945
					print '<option value="-1">&nbsp;</option>';
3946
				}
3947
3948
				while ($i < $num)
3949
				{
3950
					$obj = $this->db->fetch_object($result);
3951
					if ($selected == $obj->rowid)
3952
					{
3953
						print '<option value="'.$obj->rowid.'" selected>';
3954
					} else {
3955
						print '<option value="'.$obj->rowid.'">';
3956
					}
3957
					print trim($obj->name);
3958
					if ($status == 2 && $obj->status == 1) print ' ('.$langs->trans("Closed").')';
3959
					print '</option>';
3960
					$i++;
3961
				}
3962
				print "</select>";
3963
			} else {
3964
				if ($status == 0) print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>';
3965
				else print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>';
3966
			}
3967
		} else {
3968
			dol_print_error($this->db);
3969
		}
3970
	}
3971
3972
	/**
3973
	 *    Display form to select bank account
3974
	 *
3975
	 *    @param	string	$page        Page
3976
	 *    @param    int		$selected    Id of bank account
3977
	 *    @param    string	$htmlname    Name of select html field
3978
	 *    @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.
3979
	 *    @return	void
3980
	 */
3981
	public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
3982
	{
3983
		global $langs;
3984
		if ($htmlname != "none") {
3985
			print '<form method="POST" action="'.$page.'">';
3986
			print '<input type="hidden" name="action" value="setbankaccount">';
3987
			print '<input type="hidden" name="token" value="'.newToken().'">';
3988
			$nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
3989
			if ($nbaccountfound > 0) print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
3990
			print '</form>';
3991
		} else {
3992
			$langs->load('banks');
3993
3994
			if ($selected) {
3995
				require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
3996
				$bankstatic = new Account($this->db);
3997
				$result = $bankstatic->fetch($selected);
3998
				if ($result) print $bankstatic->getNomUrl(1);
3999
			} else {
4000
				print "&nbsp;";
4001
			}
4002
		}
4003
	}
4004
4005
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4006
	/**
4007
	 *    Return list of categories having choosed type
4008
	 *
4009
	 *    @param	string|int	            $type				Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated.
4010
	 *    @param    string		            $selected    		Id of category preselected or 'auto' (autoselect category if there is only one element). Not used if $outputmode = 1.
4011
	 *    @param    string		            $htmlname			HTML field name
4012
	 *    @param    int			            $maxlength      	Maximum length for labels
4013
	 *    @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.
4014
	 *                                                          $markafterid can be an :
4015
	 *                                                          - int (id of category)
4016
	 *                                                          - string (categories ids seprated by comma)
4017
	 *                                                          - array (list of categories ids)
4018
	 *    @param	int			            $outputmode			0=HTML select string, 1=Array
4019
	 *    @param	int			            $include			[=0] Removed or 1=Keep only
4020
	 *    @param	string					$morecss			More CSS
4021
	 *    @return	string
4022
	 *    @see select_categories()
4023
	 */
4024
	public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '')
4025
	{
4026
		// phpcs:enable
4027
		global $conf, $langs;
4028
		$langs->load("categories");
4029
4030
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4031
4032
		// For backward compatibility
4033
		if (is_numeric($type))
4034
		{
4035
			dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
4036
		}
4037
4038
		if ($type === Categorie::TYPE_BANK_LINE)
4039
		{
4040
			// TODO Move this into common category feature
4041
			$cate_arbo = array();
4042
			$sql = "SELECT c.label, c.rowid";
4043
			$sql .= " FROM ".MAIN_DB_PREFIX."bank_categ as c";
4044
			$sql .= " WHERE entity = ".$conf->entity;
4045
			$sql .= " ORDER BY c.label";
4046
			$result = $this->db->query($sql);
4047
			if ($result)
4048
			{
4049
				$num = $this->db->num_rows($result);
4050
				$i = 0;
4051
				while ($i < $num)
4052
				{
4053
					$objp = $this->db->fetch_object($result);
4054
					if ($objp) $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label);
4055
					$i++;
4056
				}
4057
				$this->db->free($result);
4058
			} else dol_print_error($this->db);
4059
		} else {
4060
			$cat = new Categorie($this->db);
4061
			$cate_arbo = $cat->get_full_arbo($type, $markafterid, $include);
4062
		}
4063
4064
		$output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
4065
		$outarray = array();
4066
		if (is_array($cate_arbo))
4067
		{
4068
			if (!count($cate_arbo)) $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>';
4069
			else {
4070
				$output .= '<option value="-1">&nbsp;</option>';
4071
				foreach ($cate_arbo as $key => $value)
4072
				{
4073
					if ($cate_arbo[$key]['id'] == $selected || ($selected == 'auto' && count($cate_arbo) == 1))
4074
					{
4075
						$add = 'selected ';
4076
					} else {
4077
						$add = '';
4078
					}
4079
					$output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>';
4080
4081
					$outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
4082
				}
4083
			}
4084
		}
4085
		$output .= '</select>';
4086
		$output .= "\n";
4087
4088
		if ($outputmode) return $outarray;
4089
		return $output;
4090
	}
4091
4092
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4093
	/**
4094
	 *     Show a confirmation HTML form or AJAX popup
4095
	 *
4096
	 *     @param	string		$page        	   	Url of page to call if confirmation is OK
4097
	 *     @param	string		$title       	   	Title
4098
	 *     @param	string		$question    	   	Question
4099
	 *     @param 	string		$action      	   	Action
4100
	 *	   @param	array		$formquestion	   	An array with forms complementary inputs
4101
	 * 	   @param	string		$selectedchoice		"" or "no" or "yes"
4102
	 * 	   @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
4103
	 *     @param	int			$height          	Force height of box
4104
	 *     @param	int			$width				Force width of box
4105
	 *     @return 	void
4106
	 *     @deprecated
4107
	 *     @see formconfirm()
4108
	 */
4109
	public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
4110
	{
4111
		// phpcs:enable
4112
		dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
4113
		print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
4114
	}
4115
4116
	/**
4117
	 *     Show a confirmation HTML form or AJAX popup.
4118
	 *     Easiest way to use this is with useajax=1.
4119
	 *     If you use useajax='xxx', you must also add jquery code to trigger opening of box (with correct parameters)
4120
	 *     just after calling this method. For example:
4121
	 *       print '<script type="text/javascript">'."\n";
4122
	 *       print 'jQuery(document).ready(function() {'."\n";
4123
	 *       print 'jQuery(".xxxlink").click(function(e) { jQuery("#aparamid").val(jQuery(this).attr("rel")); jQuery("#dialog-confirm-xxx").dialog("open"); return false; });'."\n";
4124
	 *       print '});'."\n";
4125
	 *       print '</script>'."\n";
4126
	 *
4127
	 *     @param  	string			$page        	   	Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated)
4128
	 *     @param	string			$title       	   	Title
4129
	 *     @param	string			$question    	   	Question
4130
	 *     @param 	string			$action      	   	Action
4131
	 *	   @param  	array|string	$formquestion	   	An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , ))
4132
	 *													type can be 'hidden', 'text', 'password', 'checkbox', 'radio', 'date', 'morecss', ...
4133
	 * 	   @param  	string			$selectedchoice  	'' or 'no', or 'yes' or '1' or '0'
4134
	 * 	   @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
4135
	 *     @param  	int|string		$height          	Force height of box (0 = auto)
4136
	 *     @param	int				$width				Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones.
4137
	 *     @param	int				$disableformtag		1=Disable form tag. Can be used if we are already inside a <form> section.
4138
	 *     @return 	string      		    			HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form
4139
	 */
4140
	public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0)
4141
	{
4142
		global $langs, $conf;
4143
4144
		$more = '<!-- formconfirm for page='.dol_escape_htmltag($page).' -->';
4145
		$formconfirm = '';
4146
		$inputok = array();
4147
		$inputko = array();
4148
4149
		// Clean parameters
4150
		$newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
4151
		if ($conf->browser->layout == 'phone') $width = '95%';
4152
4153
		// Set height automatically if not defined
4154
		if (empty($height)) {
4155
			$height = 220;
4156
			if (is_array($formquestion) && count($formquestion) > 2) {
4157
				$height += ((count($formquestion) - 2) * 24);
4158
			}
4159
		}
4160
4161
		if (is_array($formquestion) && !empty($formquestion))
4162
		{
4163
			// First add hidden fields and value
4164
			foreach ($formquestion as $key => $input)
4165
			{
4166
				if (is_array($input) && !empty($input))
4167
				{
4168
					if ($input['type'] == 'hidden')
4169
					{
4170
						$more .= '<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n";
4171
					}
4172
				}
4173
			}
4174
4175
			// Now add questions
4176
			$moreonecolumn = '';
4177
			$more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n";
4178
			foreach ($formquestion as $key => $input)
4179
			{
4180
				if (is_array($input) && !empty($input))
4181
				{
4182
					$size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : '');
4183
					$moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : '');
4184
					$morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : '');
4185
4186
					if ($input['type'] == 'text')
4187
					{
4188
						$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";
4189
					} elseif ($input['type'] == 'password')
4190
					{
4191
						$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";
4192
					} elseif ($input['type'] == 'select')
4193
					{
4194
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4195
						if (!empty($input['label'])) $more .= $input['label'].'</div><div class="tagtd left">';
4196
						$more .= $this->selectarray($input['name'], $input['values'], $input['default'], 1, 0, 0, $moreattr, 0, 0, 0, '', $morecss);
4197
						$more .= '</div></div>'."\n";
4198
					} elseif ($input['type'] == 'checkbox')
4199
					{
4200
						$more .= '<div class="tagtr">';
4201
						$more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">';
4202
						$more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr;
4203
						if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') $more .= ' checked';
4204
						if (is_bool($input['value']) && $input['value']) $more .= ' checked';
4205
						if (isset($input['disabled'])) $more .= ' disabled';
4206
						$more .= ' /></div>';
4207
						$more .= '</div>'."\n";
4208
					} elseif ($input['type'] == 'radio')
4209
					{
4210
						$i = 0;
4211
						foreach ($input['values'] as $selkey => $selval)
4212
						{
4213
							$more .= '<div class="tagtr">';
4214
							if ($i == 0) $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>';
4215
							else $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'">&nbsp;</div>';
4216
							$more .= '<div class="tagtd"><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr;
4217
							if ($input['disabled']) $more .= ' disabled';
4218
							$more .= ' /> ';
4219
							$more .= $selval;
4220
							$more .= '</div></div>'."\n";
4221
							$i++;
4222
						}
4223
					} elseif ($input['type'] == 'date')
4224
					{
4225
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>';
4226
						$more .= '<div class="tagtd">';
4227
						$more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, 0);
4228
						$more .= '</div></div>'."\n";
4229
						$formquestion[] = array('name'=>$input['name'].'day');
4230
						$formquestion[] = array('name'=>$input['name'].'month');
4231
						$formquestion[] = array('name'=>$input['name'].'year');
4232
						$formquestion[] = array('name'=>$input['name'].'hour');
4233
						$formquestion[] = array('name'=>$input['name'].'min');
4234
					} elseif ($input['type'] == 'other')
4235
					{
4236
						$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
4237
						if (!empty($input['label'])) $more .= $input['label'].'</div><div class="tagtd">';
4238
						$more .= $input['value'];
4239
						$more .= '</div></div>'."\n";
4240
					} elseif ($input['type'] == 'onecolumn')
4241
					{
4242
						$moreonecolumn .= '<div class="margintoponly">';
4243
						$moreonecolumn .= $input['value'];
4244
						$moreonecolumn .= '</div>'."\n";
4245
					}
4246
				}
4247
			}
4248
			$more .= '</div>'."\n";
4249
			$more .= $moreonecolumn;
4250
		}
4251
4252
		// JQUI method dialog is broken with jmobile, we use standard HTML.
4253
		// 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
4254
		// See page product/card.php for example
4255
		if (!empty($conf->dol_use_jmobile)) $useajax = 0;
4256
		if (empty($conf->use_javascript_ajax)) $useajax = 0;
4257
4258
		if ($useajax)
4259
		{
4260
			$autoOpen = true;
4261
			$dialogconfirm = 'dialog-confirm';
4262
			$button = '';
4263
			if (!is_numeric($useajax))
4264
			{
4265
				$button = $useajax;
4266
				$useajax = 1;
4267
				$autoOpen = false;
4268
				$dialogconfirm .= '-'.$button;
4269
			}
4270
			$pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.$action.'&confirm=yes';
4271
			$pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'confirm=no' : '');
4272
			// Add input fields into list of fields to read during submit (inputok and inputko)
4273
			if (is_array($formquestion))
4274
			{
4275
				foreach ($formquestion as $key => $input)
4276
				{
4277
					//print "xx ".$key." rr ".is_array($input)."<br>\n";
4278
					if (is_array($input) && isset($input['name'])) array_push($inputok, $input['name']);
4279
					if (isset($input['inputko']) && $input['inputko'] == 1) array_push($inputko, $input['name']);
4280
				}
4281
			}
4282
			// Show JQuery confirm box.
4283
			$formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">';
4284
			if (is_array($formquestion) && !empty($formquestion['text'])) {
4285
				$formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n";
4286
			}
4287
			if (!empty($more)) {
4288
				$formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n";
4289
			}
4290
			$formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : '');
4291
			$formconfirm .= '</div>'."\n";
4292
4293
			$formconfirm .= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
4294
			$formconfirm .= '<script type="text/javascript">'."\n";
4295
			$formconfirm .= 'jQuery(document).ready(function() {
4296
            $(function() {
4297
            	$( "#'.$dialogconfirm.'" ).dialog(
4298
            	{
4299
                    autoOpen: '.($autoOpen ? "true" : "false").',';
4300
			if ($newselectedchoice == 'no')
4301
			{
4302
				$formconfirm .= '
4303
						open: function() {
4304
            				$(this).parent().find("button.ui-button:eq(2)").focus();
4305
						},';
4306
			}
4307
			$formconfirm .= '
4308
                    resizable: false,
4309
                    height: "'.$height.'",
4310
                    width: "'.$width.'",
4311
                    modal: true,
4312
                    closeOnEscape: false,
4313
                    buttons: {
4314
                        "'.dol_escape_js($langs->transnoentities("Yes")).'": function() {
4315
                        	var options = "&token='.urlencode(newToken()).'";
4316
                        	var inputok = '.json_encode($inputok).';	/* List of fields into form */
4317
                         	var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'";
4318
                         	if (inputok.length>0) {
4319
                         		$.each(inputok, function(i, inputname) {
4320
                         			var more = "";
4321
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4322
                         		    if ($("#" + inputname).attr("type") == "radio") { more = ":checked"; }
4323
                         			var inputvalue = $("#" + inputname + more).val();
4324
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4325
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4326
                         		});
4327
                         	}
4328
                         	var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options;
4329
            				if (pageyes.length > 0) { location.href = urljump; }
4330
                            $(this).dialog("close");
4331
                        },
4332
                        "'.dol_escape_js($langs->transnoentities("No")).'": function() {
4333
                        	var options = "&token='.urlencode(newToken()).'";
4334
                         	var inputko = '.json_encode($inputko).';	/* List of fields into form */
4335
                         	var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'";
4336
                         	if (inputko.length>0) {
4337
                         		$.each(inputko, function(i, inputname) {
4338
                         			var more = "";
4339
                         			if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
4340
                         			var inputvalue = $("#" + inputname + more).val();
4341
                         			if (typeof inputvalue == "undefined") { inputvalue=""; }
4342
                         			options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
4343
                         		});
4344
                         	}
4345
                         	var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options;
4346
                         	//alert(urljump);
4347
            				if (pageno.length > 0) { location.href = urljump; }
4348
                            $(this).dialog("close");
4349
                        }
4350
                    }
4351
                }
4352
                );
4353
4354
            	var button = "'.$button.'";
4355
            	if (button.length > 0) {
4356
                	$( "#" + button ).click(function() {
4357
                		$("#'.$dialogconfirm.'").dialog("open");
4358
        			});
4359
                }
4360
            });
4361
            });
4362
            </script>';
4363
			$formconfirm .= "<!-- end ajax formconfirm -->\n";
4364
		} else {
4365
			$formconfirm .= "\n<!-- begin formconfirm page=".$page." -->\n";
4366
4367
			if (empty($disableformtag)) $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
4368
4369
			$formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n";
4370
			$formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n";
4371
4372
			$formconfirm .= '<table class="valid centpercent">'."\n";
4373
4374
			// Line title
4375
			$formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="3">'.img_picto('', 'recent').' '.$title.'</td></tr>'."\n";
4376
4377
			// Line text
4378
			if (is_array($formquestion) && !empty($formquestion['text'])) {
4379
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="3">'.$formquestion['text'].'</td></tr>'."\n";
4380
			}
4381
4382
			// Line form fields
4383
			if ($more)
4384
			{
4385
				$formconfirm .= '<tr class="valid"><td class="valid" colspan="3">'."\n";
4386
				$formconfirm .= $more;
4387
				$formconfirm .= '</td></tr>'."\n";
4388
			}
4389
4390
			// Line with question
4391
			$formconfirm .= '<tr class="valid">';
4392
			$formconfirm .= '<td class="valid">'.$question.'</td>';
4393
			$formconfirm .= '<td class="valid">';
4394
			$formconfirm .= $this->selectyesno("confirm", $newselectedchoice);
4395
			$formconfirm .= '</td>';
4396
			$formconfirm .= '<td class="valid center"><input class="button valignmiddle" type="submit" value="'.$langs->trans("Validate").'"></td>';
4397
			$formconfirm .= '</tr>'."\n";
4398
4399
			$formconfirm .= '</table>'."\n";
4400
4401
			if (empty($disableformtag)) $formconfirm .= "</form>\n";
4402
			$formconfirm .= '<br>';
4403
4404
			$formconfirm .= "<!-- end formconfirm -->\n";
4405
		}
4406
4407
		return $formconfirm;
4408
	}
4409
4410
4411
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4412
	/**
4413
	 *    Show a form to select a project
4414
	 *
4415
	 *    @param	int		$page        		Page
4416
	 *    @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)
4417
	 *    @param    int		$selected    		Id pre-selected project
4418
	 *    @param    string	$htmlname    		Name of select field
4419
	 *    @param	int		$discard_closed		Discard closed projects (0=Keep,1=hide completely except $selected,2=Disable)
4420
	 *    @param	int		$maxlength			Max length
4421
	 *    @param	int		$forcefocus			Force focus on field (works with javascript only)
4422
	 *    @param    int     $nooutput           No print is done. String is returned.
4423
	 *    @return	string                      Return html content
4424
	 */
4425
	public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0)
4426
	{
4427
		// phpcs:enable
4428
		global $langs;
4429
4430
		require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
4431
		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
4432
4433
		$out = '';
4434
4435
		$formproject = new FormProjets($this->db);
4436
4437
		$langs->load("project");
4438
		if ($htmlname != "none")
4439
		{
4440
			$out .= "\n";
4441
			$out .= '<form method="post" action="'.$page.'">';
4442
			$out .= '<input type="hidden" name="action" value="classin">';
4443
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
4444
			$out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1);
4445
			$out .= '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4446
			$out .= '</form>';
4447
		} else {
4448
			if ($selected)
4449
			{
4450
				$projet = new Project($this->db);
4451
				$projet->fetch($selected);
4452
				//print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>';
4453
				$out .= $projet->getNomUrl(0, '', 1);
4454
			} else {
4455
				$out .= "&nbsp;";
4456
			}
4457
		}
4458
4459
		if (empty($nooutput))
4460
		{
4461
			print $out;
4462
			return '';
4463
		}
4464
		return $out;
4465
	}
4466
4467
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4468
	/**
4469
	 *	Show a form to select payment conditions
4470
	 *
4471
	 *  @param	int		$page        	Page
4472
	 *  @param  string	$selected    	Id condition pre-selectionne
4473
	 *  @param  string	$htmlname    	Name of select html field
4474
	 *	@param	int		$addempty		Add empty entry
4475
	 *  @return	void
4476
	 */
4477
	public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0)
4478
	{
4479
		// phpcs:enable
4480
		global $langs;
4481
		if ($htmlname != "none")
4482
		{
4483
			print '<form method="post" action="'.$page.'">';
4484
			print '<input type="hidden" name="action" value="setconditions">';
4485
			print '<input type="hidden" name="token" value="'.newToken().'">';
4486
			$this->select_conditions_paiements($selected, $htmlname, -1, $addempty);
4487
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4488
			print '</form>';
4489
		} else {
4490
			if ($selected)
4491
			{
4492
				$this->load_cache_conditions_paiements();
4493
				print $this->cache_conditions_paiements[$selected]['label'];
4494
			} else {
4495
				print "&nbsp;";
4496
			}
4497
		}
4498
	}
4499
4500
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4501
	/**
4502
	 *  Show a form to select a delivery delay
4503
	 *
4504
	 *  @param  int		$page        	Page
4505
	 *  @param  string	$selected    	Id condition pre-selectionne
4506
	 *  @param  string	$htmlname    	Name of select html field
4507
	 *	@param	int		$addempty		Ajoute entree vide
4508
	 *  @return	void
4509
	 */
4510
	public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
4511
	{
4512
		// phpcs:enable
4513
		global $langs;
4514
		if ($htmlname != "none")
4515
		{
4516
			print '<form method="post" action="'.$page.'">';
4517
			print '<input type="hidden" name="action" value="setavailability">';
4518
			print '<input type="hidden" name="token" value="'.newToken().'">';
4519
			$this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
4520
			print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4521
			print '</form>';
4522
		} else {
4523
			if ($selected)
4524
			{
4525
				$this->load_cache_availability();
4526
				print $this->cache_availability[$selected]['label'];
4527
			} else {
4528
				print "&nbsp;";
4529
			}
4530
		}
4531
	}
4532
4533
	/**
4534
	 *  Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...)
4535
	 *  List found into table c_input_reason loaded by loadCacheInputReason
4536
	 *
4537
	 *  @param  string	$page        	Page
4538
	 *  @param  string	$selected    	Id condition pre-selectionne
4539
	 *  @param  string	$htmlname    	Name of select html field
4540
	 *  @param	int		$addempty		Add empty entry
4541
	 *  @return	void
4542
	 */
4543
	public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
4544
	{
4545
		global $langs;
4546
		if ($htmlname != "none")
4547
		{
4548
			print '<form method="post" action="'.$page.'">';
4549
			print '<input type="hidden" name="action" value="setdemandreason">';
4550
			print '<input type="hidden" name="token" value="'.newToken().'">';
4551
			$this->selectInputReason($selected, $htmlname, -1, $addempty);
4552
			print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
4553
			print '</form>';
4554
		} else {
4555
			if ($selected)
4556
			{
4557
				$this->loadCacheInputReason();
4558
				foreach ($this->cache_demand_reason as $key => $val)
4559
				{
4560
					if ($val['id'] == $selected)
4561
					{
4562
						print $val['label'];
4563
						break;
4564
					}
4565
				}
4566
			} else {
4567
				print "&nbsp;";
4568
			}
4569
		}
4570
	}
4571
4572
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4573
	/**
4574
	 *    Show a form + html select a date
4575
	 *
4576
	 *    @param	string		$page        	Page
4577
	 *    @param	string		$selected    	Date preselected
4578
	 *    @param    string		$htmlname    	Html name of date input fields or 'none'
4579
	 *    @param    int			$displayhour 	Display hour selector
4580
	 *    @param    int			$displaymin		Display minutes selector
4581
	 *    @param	int			$nooutput		1=No print output, return string
4582
	 *    @return	string
4583
	 *    @see		selectDate()
4584
	 */
4585
	public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0)
4586
	{
4587
		// phpcs:enable
4588
		global $langs;
4589
4590
		$ret = '';
4591
4592
		if ($htmlname != "none")
4593
		{
4594
			$ret .= '<form method="post" action="'.$page.'" name="form'.$htmlname.'">';
4595
			$ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">';
4596
			$ret .= '<input type="hidden" name="token" value="'.newToken().'">';
4597
			$ret .= '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4598
			$ret .= '<tr><td>';
4599
			$ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0);
4600
			$ret .= '</td>';
4601
			$ret .= '<td class="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4602
			$ret .= '</tr></table></form>';
4603
		} else {
4604
			if ($displayhour) $ret .= dol_print_date($selected, 'dayhour');
4605
			else $ret .= dol_print_date($selected, 'day');
4606
		}
4607
4608
		if (empty($nooutput)) print $ret;
4609
		return $ret;
4610
	}
4611
4612
4613
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4614
	/**
4615
	 *  Show a select form to choose a user
4616
	 *
4617
	 *  @param	string	$page        	Page
4618
	 *  @param  string	$selected    	Id of user preselected
4619
	 *  @param  string	$htmlname    	Name of input html field. If 'none', we just output the user link.
4620
	 *  @param  array	$exclude		List of users id to exclude
4621
	 *  @param  array	$include        List of users id to include
4622
	 *  @return	void
4623
	 */
4624
	public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '')
4625
	{
4626
		// phpcs:enable
4627
		global $langs;
4628
4629
		if ($htmlname != "none")
4630
		{
4631
			print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">';
4632
			print '<input type="hidden" name="action" value="set'.$htmlname.'">';
4633
			print '<input type="hidden" name="token" value="'.newToken().'">';
4634
			print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
4635
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4636
			print '</form>';
4637
		} else {
4638
			if ($selected)
4639
			{
4640
				require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
4641
				$theuser = new User($this->db);
4642
				$theuser->fetch($selected);
4643
				print $theuser->getNomUrl(1);
4644
			} else {
4645
				print "&nbsp;";
4646
			}
4647
		}
4648
	}
4649
4650
4651
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4652
	/**
4653
	 *    Show form with payment mode
4654
	 *
4655
	 *    @param	string	$page        	Page
4656
	 *    @param    int		$selected    	Id mode pre-selectionne
4657
	 *    @param    string	$htmlname    	Name of select html field
4658
	 *    @param  	string	$filtertype		To filter on field type in llx_c_paiement (array('code'=>xx,'label'=>zz))
4659
	 *    @param    int     $active         Active or not, -1 = all
4660
	 *    @param   int     $addempty       1=Add empty entry
4661
	 *    @return	void
4662
	 */
4663
	public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0)
4664
	{
4665
		// phpcs:enable
4666
		global $langs;
4667
		if ($htmlname != "none")
4668
		{
4669
			print '<form method="POST" action="'.$page.'">';
4670
			print '<input type="hidden" name="action" value="setmode">';
4671
			print '<input type="hidden" name="token" value="'.newToken().'">';
4672
			$this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active);
4673
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4674
			print '</form>';
4675
		} else {
4676
			if ($selected)
4677
			{
4678
				$this->load_cache_types_paiements();
4679
				print $this->cache_types_paiements[$selected]['label'];
4680
			} else {
4681
				print "&nbsp;";
4682
			}
4683
		}
4684
	}
4685
4686
    /**
4687
     *    Show form with transport mode
4688
     *
4689
     *    @param	string	$page        	Page
4690
     *    @param    int		$selected    	Id mode pre-select
4691
     *    @param    string	$htmlname    	Name of select html field
4692
     *    @param    int     $active         Active or not, -1 = all
4693
     *    @param    int     $addempty       1=Add empty entry
4694
     *    @return	void
4695
     */
4696
    public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
4697
    {
4698
        global $langs;
4699
        if ($htmlname != "none")
4700
        {
4701
            print '<form method="POST" action="'.$page.'">';
4702
            print '<input type="hidden" name="action" value="setmode">';
4703
            print '<input type="hidden" name="token" value="'.newToken().'">';
4704
            $this->selectTransportMode($selected, $htmlname, 2, $addempty, 0, 0, $active);
4705
            print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4706
            print '</form>';
4707
        }
4708
        else {
4709
            if ($selected)
4710
            {
4711
                $this->load_cache_transport_mode();
4712
                print $this->cache_transport_mode[$selected]['label'];
4713
            } else {
4714
                print "&nbsp;";
4715
            }
4716
        }
4717
    }
4718
4719
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4720
	/**
4721
	 *    Show form with multicurrency code
4722
	 *
4723
	 *    @param	string	$page        	Page
4724
	 *    @param    string	$selected    	code pre-selectionne
4725
	 *    @param    string	$htmlname    	Name of select html field
4726
	 *    @return	void
4727
	 */
4728
	public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
4729
	{
4730
		// phpcs:enable
4731
		global $langs;
4732
		if ($htmlname != "none")
4733
		{
4734
			print '<form method="POST" action="'.$page.'">';
4735
			print '<input type="hidden" name="action" value="setmulticurrencycode">';
4736
			print '<input type="hidden" name="token" value="'.newToken().'">';
4737
			print $this->selectMultiCurrency($selected, $htmlname, 0);
4738
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4739
			print '</form>';
4740
		} else {
4741
			dol_include_once('/core/lib/company.lib.php');
4742
			print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
4743
		}
4744
	}
4745
4746
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4747
	/**
4748
	 *    Show form with multicurrency rate
4749
	 *
4750
	 *    @param	string	$page        	Page
4751
	 *    @param    double	$rate	    	Current rate
4752
	 *    @param    string	$htmlname    	Name of select html field
4753
	 *    @param    string  $currency       Currency code to explain the rate
4754
	 *    @return	void
4755
	 */
4756
	public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '')
4757
	{
4758
		// phpcs:enable
4759
		global $langs, $mysoc, $conf;
4760
4761
		if ($htmlname != "none")
4762
		{
4763
			print '<form method="POST" action="'.$page.'">';
4764
			print '<input type="hidden" name="action" value="setmulticurrencyrate">';
4765
			print '<input type="hidden" name="token" value="'.newToken().'">';
4766
			print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CR')) : 1).'" /> ';
4767
			print '<select name="calculation_mode">';
4768
			print '<option value="1">'.$currency.' > '.$conf->currency.'</option>';
4769
			print '<option value="2">'.$conf->currency.' > '.$currency.'</option>';
4770
			print '</select> ';
4771
			print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4772
			print '</form>';
4773
		} else {
4774
			if (!empty($rate))
4775
			{
4776
				print price($rate, 1, $langs, 1, 0);
4777
				if ($currency && $rate != 1) print ' &nbsp; ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')';
4778
			} else {
4779
				print 1;
4780
			}
4781
		}
4782
	}
4783
4784
4785
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4786
	/**
4787
	 *	Show a select box with available absolute discounts
4788
	 *
4789
	 *  @param  string	$page        	Page URL where form is shown
4790
	 *  @param  int		$selected    	Value pre-selected
4791
	 *	@param  string	$htmlname    	Name of SELECT component. If 'none', not changeable. Example 'remise_id'.
4792
	 *	@param	int		$socid			Third party id
4793
	 * 	@param	float	$amount			Total amount available
4794
	 * 	@param	string	$filter			SQL filter on discounts
4795
	 * 	@param	int		$maxvalue		Max value for lines that can be selected
4796
	 *  @param  string	$more           More string to add
4797
	 *  @param  int     $hidelist       1=Hide list
4798
	 *  @param	int		$discount_type	0 => customer discount, 1 => supplier discount
4799
	 *  @return	void
4800
	 */
4801
	public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
4802
	{
4803
		// phpcs:enable
4804
		global $conf, $langs;
4805
		if ($htmlname != "none")
4806
		{
4807
			print '<form method="post" action="'.$page.'">';
4808
			print '<input type="hidden" name="action" value="setabsolutediscount">';
4809
			print '<input type="hidden" name="token" value="'.newToken().'">';
4810
			print '<div class="inline-block">';
4811
			if (!empty($discount_type)) {
4812
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4813
				{
4814
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice
4815
					else $translationKey = 'HasCreditNoteFromSupplier';
4816
				} else {
4817
					if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") $translationKey = 'HasAbsoluteDiscountFromSupplier';
4818
					else $translationKey = 'HasCreditNoteFromSupplier';
4819
				}
4820
			} else {
4821
				if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS))
4822
				{
4823
					if (!$filter || $filter == "fk_facture_source IS NULL") $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice
4824
					else $translationKey = 'CompanyHasCreditNote';
4825
				} else {
4826
					if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") $translationKey = 'CompanyHasAbsoluteDiscount';
4827
					else $translationKey = 'CompanyHasCreditNote';
4828
				}
4829
			}
4830
			print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
4831
			if (empty($hidelist)) print ': ';
4832
			print '</div>';
4833
			if (empty($hidelist))
4834
			{
4835
				print '<div class="inline-block" style="padding-right: 10px">';
4836
				$newfilter = 'discount_type='.intval($discount_type);
4837
				if (!empty($discount_type)) {
4838
					$newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
4839
				} else {
4840
					$newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
4841
				}
4842
				if ($filter) $newfilter .= ' AND ('.$filter.')';
4843
				$nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue);
4844
				if ($nbqualifiedlines > 0)
4845
				{
4846
					print ' &nbsp; <input type="submit" class="button" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"';
4847
					if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')")
4848
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4849
					if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')")
4850
						print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"';
4851
4852
					print '>';
4853
				}
4854
				print '</div>';
4855
			}
4856
			if ($more)
4857
			{
4858
				print '<div class="inline-block">';
4859
				print $more;
4860
				print '</div>';
4861
			}
4862
			print '</form>';
4863
		} else {
4864
			if ($selected)
4865
			{
4866
				print $selected;
4867
			} else {
4868
				print "0";
4869
			}
4870
		}
4871
	}
4872
4873
4874
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4875
	/**
4876
	 *  Show forms to select a contact
4877
	 *
4878
	 *  @param	string		$page        	Page
4879
	 *  @param	Societe		$societe		Filter on third party
4880
	 *  @param    int			$selected    	Id contact pre-selectionne
4881
	 *  @param    string		$htmlname    	Name of HTML select. If 'none', we just show contact link.
4882
	 *  @return	void
4883
	 */
4884
	public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
4885
	{
4886
		// phpcs:enable
4887
		global $langs, $conf;
4888
4889
		if ($htmlname != "none")
4890
		{
4891
			print '<form method="post" action="'.$page.'">';
4892
			print '<input type="hidden" name="action" value="set_contact">';
4893
			print '<input type="hidden" name="token" value="'.newToken().'">';
4894
			print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">';
4895
			print '<tr><td>';
4896
			$num = $this->select_contacts($societe->id, $selected, $htmlname);
4897
			if ($num == 0)
4898
			{
4899
				$addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
4900
				print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&amp;action=create&amp;backtoreferer=1">'.$addcontact.'</a>';
4901
			}
4902
			print '</td>';
4903
			print '<td class="left"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
4904
			print '</tr></table></form>';
4905
		} else {
4906
			if ($selected)
4907
			{
4908
				require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
4909
				$contact = new Contact($this->db);
4910
				$contact->fetch($selected);
4911
				print $contact->getFullName($langs);
4912
			} else {
4913
				print "&nbsp;";
4914
			}
4915
		}
4916
	}
4917
4918
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4919
	/**
4920
	 *  Output html select to select thirdparty
4921
	 *
4922
	 *  @param	string	$page       	Page
4923
	 *  @param  string	$selected   	Id preselected
4924
	 *  @param  string	$htmlname		Name of HTML select
4925
	 *  @param  string	$filter         optional filters criteras
4926
	 *	@param	int		$showempty		Add an empty field
4927
	 * 	@param	int		$showtype		Show third party type in combolist (customer, prospect or supplier)
4928
	 * 	@param	int		$forcecombo		Force to use combo box
4929
	 *  @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')))
4930
	 *  @param  int     $nooutput       No print output. Return it only.
4931
	 *  @return	void|string
4932
	 */
4933
	public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0)
4934
	{
4935
		// phpcs:enable
4936
		global $langs;
4937
4938
		$out = '';
4939
		if ($htmlname != "none")
4940
		{
4941
			$out .= '<form method="post" action="'.$page.'">';
4942
			$out .= '<input type="hidden" name="action" value="set_thirdparty">';
4943
			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
4944
			$out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events);
4945
			$out .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
4946
			$out .= '</form>';
4947
		} else {
4948
			if ($selected)
4949
			{
4950
				require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
4951
				$soc = new Societe($this->db);
4952
				$soc->fetch($selected);
4953
				$out .= $soc->getNomUrl($langs);
4954
			} else {
4955
				$out .= "&nbsp;";
4956
			}
4957
		}
4958
4959
		if ($nooutput) return $out;
4960
		else print $out;
4961
	}
4962
4963
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4964
	/**
4965
	 *    Retourne la liste des devises, dans la langue de l'utilisateur
4966
	 *
4967
	 *    @param	string	$selected    preselected currency code
4968
	 *    @param    string	$htmlname    name of HTML select list
4969
	 *    @deprecated
4970
	 *    @return	void
4971
	 */
4972
	public function select_currency($selected = '', $htmlname = 'currency_id')
4973
	{
4974
		// phpcs:enable
4975
		print $this->selectCurrency($selected, $htmlname);
4976
	}
4977
4978
	/**
4979
	 *  Retourne la liste des devises, dans la langue de l'utilisateur
4980
	 *
4981
	 *  @param	string	$selected    preselected currency code
4982
	 *  @param  string	$htmlname    name of HTML select list
4983
	 *  @param  string  $mode        0 = Add currency symbol into label, 1 = Add 3 letter iso code
4984
	 * 	@return	string
4985
	 */
4986
	public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0)
4987
	{
4988
		global $conf, $langs, $user;
4989
4990
		$langs->loadCacheCurrencies('');
4991
4992
		$out = '';
4993
4994
		if ($selected == 'euro' || $selected == 'euros') $selected = 'EUR'; // Pour compatibilite
4995
4996
		$out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">';
4997
		foreach ($langs->cache_currencies as $code_iso => $currency)
4998
		{
4999
			if ($selected && $selected == $code_iso)
5000
			{
5001
				$out .= '<option value="'.$code_iso.'" selected>';
5002
			} else {
5003
				$out .= '<option value="'.$code_iso.'">';
5004
			}
5005
			$out .= $currency['label'];
5006
			if ($mode == 1)
5007
			{
5008
				$out .= ' ('.$code_iso.')';
5009
			} else {
5010
				$out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5011
			}
5012
			$out .= '</option>';
5013
		}
5014
		$out .= '</select>';
5015
		if ($user->admin) $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5016
5017
		// Make select dynamic
5018
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5019
		$out .= ajax_combobox($htmlname);
5020
5021
		return $out;
5022
	}
5023
5024
	/**
5025
	 *	Return array of currencies in user language
5026
	 *
5027
	 *  @param	string	$selected    preselected currency code
5028
	 *  @param  string	$htmlname    name of HTML select list
5029
	 *  @param  integer	$useempty    1=Add empty line
5030
	 * 	@return	string
5031
	 */
5032
	public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0)
5033
	{
5034
		global $db, $conf, $langs, $user;
5035
5036
		$langs->loadCacheCurrencies(''); // Load ->cache_currencies
5037
5038
		$TCurrency = array();
5039
5040
		$sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency';
5041
		$sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')";
5042
		$resql = $this->db->query($sql);
5043
		if ($resql)
5044
		{
5045
			while ($obj = $this->db->fetch_object($resql)) $TCurrency[$obj->code] = $obj->code;
5046
		}
5047
5048
		$out = '';
5049
		$out .= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
5050
		if ($useempty) $out .= '<option value="">&nbsp;</option>';
5051
		// If company current currency not in table, we add it into list. Should always be available.
5052
		if (!in_array($conf->currency, $TCurrency))
5053
		{
5054
			$TCurrency[$conf->currency] = $conf->currency;
5055
		}
5056
		if (count($TCurrency) > 0)
5057
		{
5058
			foreach ($langs->cache_currencies as $code_iso => $currency)
5059
			{
5060
				if (isset($TCurrency[$code_iso]))
5061
				{
5062
					if (!empty($selected) && $selected == $code_iso) $out .= '<option value="'.$code_iso.'" selected="selected">';
5063
					else $out .= '<option value="'.$code_iso.'">';
5064
5065
					$out .= $currency['label'];
5066
					$out .= ' ('.$langs->getCurrencySymbol($code_iso).')';
5067
					$out .= '</option>';
5068
				}
5069
			}
5070
		}
5071
5072
		$out .= '</select>';
5073
		// Make select dynamic
5074
		include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
5075
		$out .= ajax_combobox($htmlname);
5076
5077
		return $out;
5078
	}
5079
5080
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5081
	/**
5082
	 *  Load into the cache vat rates of a country
5083
	 *
5084
	 *  @param	string	$country_code		Country code with quotes ("'CA'", or "'CA,IN,...'")
5085
	 *  @return	int							Nb of loaded lines, 0 if already loaded, <0 if KO
5086
	 */
5087
	public function load_cache_vatrates($country_code)
5088
	{
5089
		// phpcs:enable
5090
		global $langs;
5091
5092
		$num = count($this->cache_vatrates);
5093
		if ($num > 0) return $num; // Cache already loaded
5094
5095
		dol_syslog(__METHOD__, LOG_DEBUG);
5096
5097
		$sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
5098
		$sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
5099
		$sql .= " WHERE t.fk_pays = c.rowid";
5100
		$sql .= " AND t.active > 0";
5101
		$sql .= " AND c.code IN (".$country_code.")";
5102
		$sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
5103
5104
		$resql = $this->db->query($sql);
5105
		if ($resql)
5106
		{
5107
			$num = $this->db->num_rows($resql);
5108
			if ($num)
5109
			{
5110
				for ($i = 0; $i < $num; $i++)
5111
				{
5112
					$obj = $this->db->fetch_object($resql);
5113
					$this->cache_vatrates[$i]['rowid']	= $obj->rowid;
5114
					$this->cache_vatrates[$i]['code'] = $obj->code;
5115
					$this->cache_vatrates[$i]['txtva']	= $obj->taux;
5116
					$this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly;
5117
					$this->cache_vatrates[$i]['localtax1']	    = $obj->localtax1;
5118
					$this->cache_vatrates[$i]['localtax1_type']	= $obj->localtax1_type;
5119
					$this->cache_vatrates[$i]['localtax2']	    = $obj->localtax2;
5120
					$this->cache_vatrates[$i]['localtax2_type']	= $obj->localtax1_type;
5121
5122
					$this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or *
5123
					$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
5124
					$positiverates = '';
5125
					if ($obj->taux) $positiverates .= ($positiverates ? '/' : '').$obj->taux;
5126
					if ($obj->localtax1) $positiverates .= ($positiverates ? '/' : '').$obj->localtax1;
5127
					if ($obj->localtax2) $positiverates .= ($positiverates ? '/' : '').$obj->localtax2;
5128
					if (empty($positiverates)) $positiverates = '0';
5129
					$this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label
5130
				}
5131
5132
				return $num;
5133
			} else {
5134
				$this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</font>';
5135
				return -1;
5136
			}
5137
		} else {
5138
			$this->error = '<font class="error">'.$this->db->error().'</font>';
5139
			return -2;
5140
		}
5141
	}
5142
5143
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5144
	/**
5145
	 *  Output an HTML select vat rate.
5146
	 *  The name of this function should be selectVat. We keep bad name for compatibility purpose.
5147
	 *
5148
	 *  @param	string	      $htmlname           Name of HTML select field
5149
	 *  @param  float|string  $selectedrate       Force preselected vat rate. Can be '8.5' or '8.5 (NOO)' for example. Use '' for no forcing.
5150
	 *  @param  Societe	      $societe_vendeuse   Thirdparty seller
5151
	 *  @param  Societe	      $societe_acheteuse  Thirdparty buyer
5152
	 *  @param  int		      $idprod             Id product. O if unknown of NA.
5153
	 *  @param  int		      $info_bits          Miscellaneous information on line (1 for NPR)
5154
	 *  @param  int|string    $type               ''=Unknown, 0=Product, 1=Service (Used if idprod not defined)
5155
	 *                  		                  Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle.
5156
	 *                  					      Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle.
5157
	 *                  					      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.
5158
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= particulier alors TVA par défaut=TVA du produit vendu. Fin de règle.
5159
	 *                                            Si vendeur et acheteur dans Communauté européenne et acheteur= entreprise alors TVA par défaut=0. Fin de règle.
5160
	 *                  					      Sinon la TVA proposee par defaut=0. Fin de regle.
5161
	 *  @param	bool	     $options_only		  Return HTML options lines only (for ajax treatment)
5162
	 *  @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
5163
	 *  @return	string
5164
	 */
5165
	public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0)
5166
	{
5167
		// phpcs:enable
5168
		global $langs, $conf, $mysoc;
5169
5170
		$langs->load('errors');
5171
5172
		$return = '';
5173
5174
		// Define defaultnpr, defaultttx and defaultcode
5175
		$defaultnpr = ($info_bits & 0x01);
5176
		$defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
5177
		$defaulttx = str_replace('*', '', $selectedrate);
5178
		$defaultcode = '';
5179
		if (preg_match('/\((.*)\)/', $defaulttx, $reg))
5180
		{
5181
			$defaultcode = $reg[1];
5182
			$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5183
		}
5184
		//var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
5185
5186
		// Check parameters
5187
		if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code)
5188
		{
5189
			if ($societe_vendeuse->id == $mysoc->id)
5190
			{
5191
				$return .= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</font>';
5192
			} else {
5193
				$return .= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</font>';
5194
			}
5195
			return $return;
5196
		}
5197
5198
		//var_dump($societe_acheteuse);
5199
		//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";
5200
		//exit;
5201
5202
		// Define list of countries to use to search VAT rates to show
5203
		// First we defined code_country to use to find list
5204
		if (is_object($societe_vendeuse))
5205
		{
5206
			$code_country = "'".$societe_vendeuse->country_code."'";
5207
		} else {
5208
			$code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente
5209
		}
5210
		if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC))    // If option to have vat for end customer for services is on
5211
		{
5212
			require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
5213
			if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany())))
5214
			{
5215
				// We also add the buyer
5216
				if (is_numeric($type))
5217
				{
5218
					if ($type == 1) // We know product is a service
5219
					{
5220
						$code_country .= ",'".$societe_acheteuse->country_code."'";
5221
					}
5222
				} elseif (!$idprod)  // We don't know type of product
5223
				{
5224
					$code_country .= ",'".$societe_acheteuse->country_code."'";
5225
				} else {
5226
					$prodstatic = new Product($this->db);
5227
					$prodstatic->fetch($idprod);
5228
					if ($prodstatic->type == Product::TYPE_SERVICE)   // We know product is a service
5229
					{
5230
						$code_country .= ",'".$societe_acheteuse->country_code."'";
5231
					}
5232
				}
5233
			}
5234
		}
5235
5236
		// Now we get list
5237
		$num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
5238
5239
		if ($num > 0)
5240
		{
5241
			// Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '')
5242
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
5243
			{
5244
				$tmpthirdparty = new Societe($this->db);
5245
				$defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5246
				$defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
5247
				if (preg_match('/\((.*)\)/', $defaulttx, $reg)) {
5248
					$defaultcode = $reg[1];
5249
					$defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx);
5250
				}
5251
				if (empty($defaulttx)) $defaultnpr = 0;
5252
			}
5253
5254
			// Si taux par defaut n'a pu etre determine, on prend dernier de la liste.
5255
			// Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant
5256
			if ($defaulttx < 0 || dol_strlen($defaulttx) == 0)
5257
			{
5258
				if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) $defaulttx = $this->cache_vatrates[$num - 1]['txtva'];
5259
				else $defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS);
5260
			}
5261
5262
			// Disabled if seller is not subject to VAT
5263
			$disabled = false; $title = '';
5264
			if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0")
5265
			{
5266
				// Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
5267
				// of using supplier invoices (this is a very bad idea !)
5268
				if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT))
5269
				{
5270
					$title = ' title="'.$langs->trans('VATIsNotUsed').'"';
5271
					$disabled = true;
5272
				}
5273
			}
5274
5275
			if (!$options_only) $return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>';
5276
5277
			$selectedfound = false;
5278
			foreach ($this->cache_vatrates as $rate)
5279
			{
5280
				// Keep only 0 if seller is not subject to VAT
5281
				if ($disabled && $rate['txtva'] != 0) continue;
5282
5283
				// Define key to use into select list
5284
				$key = $rate['txtva'];
5285
				$key .= $rate['nprtva'] ? '*' : '';
5286
				if ($mode > 0 && $rate['code']) $key .= ' ('.$rate['code'].')';
5287
				if ($mode < 0) $key = $rate['rowid'];
5288
5289
				$return .= '<option value="'.$key.'"';
5290
				if (!$selectedfound)
5291
				{
5292
					if ($defaultcode) // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
5293
					{
5294
						if ($defaultcode == $rate['code'])
5295
						{
5296
							$return .= ' selected';
5297
							$selectedfound = true;
5298
						}
5299
					} elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr)
5300
			   		{
5301
			   			$return .= ' selected';
5302
			   			$selectedfound = true;
5303
					}
5304
				}
5305
				$return .= '>';
5306
				//if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES))
5307
				if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES))
5308
				{
5309
					$return .= $rate['labelpositiverates'];
5310
				} else {
5311
					$return .= vatrate($rate['label']);
5312
				}
5313
				//$return.=($rate['code']?' '.$rate['code']:'');
5314
				$return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the *  (old behaviour only if new vat code is not used)
5315
5316
				$return .= '</option>';
5317
			}
5318
5319
			if (!$options_only) $return .= '</select>';
5320
		} else {
5321
			$return .= $this->error;
5322
		}
5323
5324
		$this->num = $num;
5325
		return $return;
5326
	}
5327
5328
5329
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5330
	/**
5331
	 *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5332
	 *  Fields are preselected with :
5333
	 *            	- set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5334
	 *            	- local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5335
	 *            	- Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5336
	 *
5337
	 *	@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).
5338
	 *	@param	string		$prefix			Prefix for fields name
5339
	 *	@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
5340
	 *	@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
5341
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5342
	 *	@param	string		$form_name 		Not used
5343
	 *	@param	int			$d				1=Show days, month, years
5344
	 * 	@param	int			$addnowlink		Add a link "Now"
5345
	 * 	@param	int			$nooutput		Do not output html string but return it
5346
	 * 	@param 	int			$disabled		Disable input fields
5347
	 *  @param  int			$fullday        When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59
5348
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another select_date field.
5349
	 *  @param  datetime    $adddateof      Add a link "Date of invoice" using the following date.
5350
	 *  @return	string|void					Nothing or string if nooutput is 1
5351
	 *  @deprecated
5352
	 *  @see    selectDate(), form_date(), select_month(), select_year(), select_dayofweek()
5353
	 */
5354
	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 = '')
5355
	{
5356
		// phpcs:enable
5357
		$retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
5358
		if (!empty($nooutput)) {
5359
			return $retstring;
5360
		}
5361
		print $retstring;
5362
		return;
5363
	}
5364
5365
	/**
5366
	 *  Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5367
	 *  Fields are preselected with :
5368
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5369
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5370
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5371
	 *
5372
	 *  @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).
5373
	 *  @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).
5374
	 *  @param	string		$prefix			Prefix for fields name
5375
	 *  @param	string		$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5376
	 * 	@return string                      Html for selectDate
5377
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
5378
	 */
5379
	public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0)
5380
	{
5381
		$ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty);
5382
		$ret .= '<br/>';
5383
		$ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty);
5384
		return $ret;
5385
	}
5386
5387
	/**
5388
	 *  Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes.
5389
	 *  Fields are preselected with :
5390
	 *              - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM')
5391
	 *              - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location)
5392
	 *              - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1)
5393
	 *
5394
	 *  @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).
5395
	 *  @param	string		$prefix			Prefix for fields name
5396
	 *  @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
5397
	 *	@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
5398
	 *	@param	int			$empty			0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only
5399
	 *	@param	string		$form_name 		Not used
5400
	 *	@param	int			$d				1=Show days, month, years
5401
	 * 	@param	int			$addnowlink		Add a link "Now", 1 with server time, 2 with local computer time
5402
	 * 	@param 	int			$disabled		Disable input fields
5403
	 *  @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')
5404
	 *  @param	string		$addplusone		Add a link "+1 hour". Value must be name of another selectDate field.
5405
	 *  @param  datetime    $adddateof      Add a link "Date of ..." using the following date. See also $labeladddateof for the label used.
5406
	 *  @param  string      $openinghours   Specify hour start and hour end for the select ex 8,20
5407
	 *  @param  int         $stepminutes    Specify step for minutes between 1 and 30
5408
	 *  @param	string		$labeladddateof Label to use for the $adddateof parameter.
5409
	 *  @param	string 		$placeholder    Placeholder
5410
	 * 	@return string                      Html for selectDate
5411
	 *  @see    form_date(), select_month(), select_year(), select_dayofweek()
5412
	 */
5413
	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 = '')
5414
	{
5415
		global $conf, $langs;
5416
5417
		$retstring = '';
5418
5419
		if ($prefix == '') $prefix = 're';
5420
		if ($h == '') $h = 0;
5421
		if ($m == '') $m = 0;
5422
		$emptydate = 0;
5423
		$emptyhours = 0;
5424
		if ($stepminutes <= 0 || $stepminutes > 30) $stepminutes = 1;
5425
		if ($empty == 1) { $emptydate = 1; $emptyhours = 1; }
5426
		if ($empty == 2) { $emptydate = 0; $emptyhours = 1; }
5427
		$orig_set_time = $set_time;
5428
5429
		if ($set_time === '' && $emptydate == 0)
5430
		{
5431
			include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5432
			$set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
5433
		}
5434
5435
		// Analysis of the pre-selection date
5436
		$reg = array();
5437
		if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg))	// deprecated usage
5438
		{
5439
			// Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
5440
			$syear	= (!empty($reg[1]) ? $reg[1] : '');
5441
			$smonth = (!empty($reg[2]) ? $reg[2] : '');
5442
			$sday	= (!empty($reg[3]) ? $reg[3] : '');
5443
			$shour	= (!empty($reg[4]) ? $reg[4] : '');
5444
			$smin	= (!empty($reg[5]) ? $reg[5] : '');
5445
		} elseif (strval($set_time) != '' && $set_time != -1)
5446
		{
5447
			// set_time est un timestamps (0 possible)
5448
			$syear = dol_print_date($set_time, "%Y");
5449
			$smonth = dol_print_date($set_time, "%m");
5450
			$sday = dol_print_date($set_time, "%d");
5451
			if ($orig_set_time != '')
5452
			{
5453
				$shour = dol_print_date($set_time, "%H");
5454
				$smin = dol_print_date($set_time, "%M");
5455
				$ssec = dol_print_date($set_time, "%S");
5456
			} else {
5457
				$shour = '';
5458
				$smin = '';
5459
				$ssec = '';
5460
			}
5461
		} else {
5462
			// Date est '' ou vaut -1
5463
			$syear = '';
5464
			$smonth = '';
5465
			$sday = '';
5466
			$shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR;
5467
			$smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN;
5468
			$ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC;
5469
		}
5470
		if ($h == 3) $shour = '';
5471
		if ($m == 3) $smin = '';
5472
5473
		// You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
5474
		$usecalendar = 'combo';
5475
		if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) {
5476
			$usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR);
5477
		}
5478
5479
		if ($d)
5480
		{
5481
			// Show date with popup
5482
			if ($usecalendar != 'combo')
5483
			{
5484
				$formated_date = '';
5485
				//print "e".$set_time." t ".$conf->format_date_short;
5486
				if (strval($set_time) != '' && $set_time != -1)
5487
				{
5488
					//$formated_date=dol_print_date($set_time,$conf->format_date_short);
5489
					$formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput")); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5490
				}
5491
5492
				// Calendrier popup version eldy
5493
				if ($usecalendar == "eldy")
5494
				{
5495
					// Zone de saisie manuelle de la date
5496
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
5497
					$retstring .= ($disabled ? ' disabled' : '');
5498
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5499
					$retstring .= '>';
5500
5501
					// Icone calendrier
5502
					if (!$disabled)
5503
					{
5504
						$retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"';
5505
						$base = DOL_URL_ROOT.'/core/';
5506
						$retstring .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"';
5507
						$retstring .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>';
5508
					} else $retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
5509
5510
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
5511
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5512
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
5513
				} elseif ($usecalendar == 'jquery')
5514
				{
5515
					if (!$disabled)
5516
					{
5517
						// Output javascript for datepicker
5518
						$retstring .= "<script type='text/javascript'>";
5519
						$retstring .= "$(function(){ $('#".$prefix."').datepicker({
5520
							dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."',
5521
							autoclose: true,
5522
							todayHighlight: true,";
5523
						if (!empty($conf->dol_use_jmobile))
5524
						{
5525
							$retstring .= "
5526
								beforeShow: function (input, datePicker) {
5527
									input.disabled = true;
5528
								},
5529
								onClose: function (dateText, datePicker) {
5530
									this.disabled = false;
5531
								},
5532
								";
5533
						}
5534
						// Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
5535
						if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS))
5536
						{
5537
							$retstring .= "
5538
								showOn: 'button',
5539
								buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png',
5540
								buttonImageOnly: true";
5541
						}
5542
						$retstring .= "
5543
							}) });";
5544
						$retstring .= "</script>";
5545
					}
5546
5547
					// Zone de saisie manuelle de la date
5548
					$retstring .= '<div class="nowrap inline-block">';
5549
					$retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"';
5550
					$retstring .= ($disabled ? ' disabled' : '');
5551
					$retstring .= ($placeholder ? ' placeholder="'.$placeholder.'"' : '');
5552
					$retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
5553
					$retstring .= '>';
5554
5555
					// Icone calendrier
5556
					if (!$disabled)
5557
					{
5558
						/* Not required. Managed by option buttonImage of jquery
5559
                		$retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"');
5560
                		$retstring.="<script type='text/javascript'>";
5561
                		$retstring.="jQuery(document).ready(function() {";
5562
                		$retstring.='	jQuery("#'.$prefix.'id").click(function() {';
5563
                		$retstring.="    	jQuery('#".$prefix."').focus();";
5564
                		$retstring.='    });';
5565
                		$retstring.='});';
5566
                		$retstring.="</script>";*/
5567
					} else {
5568
						$retstring .= '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>';
5569
					}
5570
5571
					$retstring .= '</div>';
5572
					$retstring .= '<input type="hidden" id="'.$prefix.'day"   name="'.$prefix.'day"   value="'.$sday.'">'."\n";
5573
					$retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n";
5574
					$retstring .= '<input type="hidden" id="'.$prefix.'year"  name="'.$prefix.'year"  value="'.$syear.'">'."\n";
5575
				} else {
5576
					$retstring .= "Bad value of MAIN_POPUP_CALENDAR";
5577
				}
5578
			}
5579
			// Show date with combo selects
5580
			else {
5581
				//$retstring.='<div class="inline-block">';
5582
				// Day
5583
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">';
5584
5585
				if ($emptydate || $set_time == -1)
5586
				{
5587
					$retstring .= '<option value="0" selected>&nbsp;</option>';
5588
				}
5589
5590
				for ($day = 1; $day <= 31; $day++)
5591
				{
5592
					$retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>';
5593
				}
5594
5595
				$retstring .= "</select>";
5596
5597
				$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">';
5598
				if ($emptydate || $set_time == -1)
5599
				{
5600
					$retstring .= '<option value="0" selected>&nbsp;</option>';
5601
				}
5602
5603
				// Month
5604
				for ($month = 1; $month <= 12; $month++)
5605
				{
5606
					$retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>';
5607
					$retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
5608
					$retstring .= "</option>";
5609
				}
5610
				$retstring .= "</select>";
5611
5612
				// Year
5613
				if ($emptydate || $set_time == -1)
5614
				{
5615
					$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.'">';
5616
				} else {
5617
					$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
5618
5619
					for ($year = $syear - 10; $year < $syear + 10; $year++)
5620
					{
5621
						$retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>';
5622
					}
5623
					$retstring .= "</select>\n";
5624
				}
5625
				//$retstring.='</div>';
5626
			}
5627
		}
5628
5629
		if ($d && $h) $retstring .= ($h == 2 ? '<br>' : ' ');
5630
5631
		if ($h)
5632
		{
5633
			$hourstart = 0;
5634
			$hourend = 24;
5635
			if ($openinghours != '') {
5636
				$openinghours = explode(',', $openinghours);
5637
				$hourstart = $openinghours[0];
5638
				$hourend = $openinghours[1];
5639
				if ($hourend < $hourstart) $hourend = $hourstart;
5640
			}
5641
			// Show hour
5642
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">';
5643
			if ($emptyhours) $retstring .= '<option value="-1">&nbsp;</option>';
5644
			for ($hour = $hourstart; $hour < $hourend; $hour++)
5645
			{
5646
				if (strlen($hour) < 2) $hour = "0".$hour;
5647
				$retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour.(empty($conf->dol_optimize_smallscreen) ? '' : 'H').'</option>';
5648
			}
5649
			$retstring .= '</select>';
5650
			if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":";
5651
		}
5652
5653
		if ($m)
5654
		{
5655
			// Show minutes
5656
			$retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">';
5657
			if ($emptyhours) $retstring .= '<option value="-1">&nbsp;</option>';
5658
			for ($min = 0; $min < 60; $min += $stepminutes)
5659
			{
5660
				if (strlen($min) < 2) $min = "0".$min;
5661
				$retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>';
5662
			}
5663
			$retstring .= '</select>';
5664
5665
			$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...
5666
		}
5667
5668
		// Add a "Now" link
5669
		if ($conf->use_javascript_ajax && $addnowlink)
5670
		{
5671
			// Script which will be inserted in the onClick of the "Now" link
5672
			$reset_scripts = "";
5673
			if ($addnowlink == 2) // local computer time
5674
			{
5675
				// pad add leading 0 on numbers
5676
				$reset_scripts .= "Number.prototype.pad = function(size) {
5677
                        var s = String(this);
5678
                        while (s.length < (size || 2)) {s = '0' + s;}
5679
                        return s;
5680
                    };
5681
                    var d = new Date();";
5682
			}
5683
5684
			// Generate the date part, depending on the use or not of the javascript calendar
5685
			if ($addnowlink == 1) // server time expressed in user time setup
5686
			{
5687
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(), 'day', 'tzuser').'\');';
5688
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(), '%d', 'tzuser').'\');';
5689
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(), '%m', 'tzuser').'\');';
5690
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(), '%Y', 'tzuser').'\');';
5691
			} elseif ($addnowlink == 2)
5692
			{
5693
				/* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
5694
            	 * This break application for foreign languages.
5695
                $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
5696
                $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
5697
                $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
5698
                $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
5699
                */
5700
				$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(), 'day', 'tzuser').'\');';
5701
				$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(), '%d', 'tzuser').'\');';
5702
				$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(), '%m', 'tzuser').'\');';
5703
				$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(), '%Y', 'tzuser').'\');';
5704
			}
5705
			/*if ($usecalendar == "eldy")
5706
            {
5707
                $base=DOL_URL_ROOT.'/core/';
5708
                $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
5709
            }
5710
            else
5711
            {
5712
                $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
5713
                $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
5714
                $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
5715
            }*/
5716
			// Update the hour part
5717
			if ($h)
5718
			{
5719
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5720
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
5721
				if ($addnowlink == 1)
5722
				{
5723
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(), '%H', 'tzuser').'\');';
5724
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
5725
				} elseif ($addnowlink == 2)
5726
				{
5727
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());';
5728
					$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();';
5729
				}
5730
5731
				if ($fullday) $reset_scripts .= ' } ';
5732
			}
5733
			// Update the minute part
5734
			if ($m)
5735
			{
5736
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5737
				//$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
5738
				if ($addnowlink == 1)
5739
				{
5740
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(), '%M', 'tzuser').'\');';
5741
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
5742
				} elseif ($addnowlink == 2)
5743
				{
5744
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());';
5745
					$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();';
5746
				}
5747
				if ($fullday) $reset_scripts .= ' } ';
5748
			}
5749
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5750
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5751
			{
5752
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">';
5753
				$retstring .= $langs->trans("Now");
5754
				$retstring .= '</button> ';
5755
			}
5756
		}
5757
5758
		// Add a "Plus one hour" link
5759
		if ($conf->use_javascript_ajax && $addplusone)
5760
		{
5761
			// Script which will be inserted in the onClick of the "Add plusone" link
5762
			$reset_scripts = "";
5763
5764
			// Generate the date part, depending on the use or not of the javascript calendar
5765
			$reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date(dol_now(), 'day').'\');';
5766
			$reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date(dol_now(), '%d').'\');';
5767
			$reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date(dol_now(), '%m').'\');';
5768
			$reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date(dol_now(), '%Y').'\');';
5769
			// Update the hour part
5770
			if ($h)
5771
			{
5772
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5773
				$reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date(dol_now(), '%H').'\');';
5774
				if ($fullday) $reset_scripts .= ' } ';
5775
			}
5776
			// Update the minute part
5777
			if ($m)
5778
			{
5779
				if ($fullday) $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
5780
				$reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date(dol_now(), '%M').'\');';
5781
				if ($fullday) $reset_scripts .= ' } ';
5782
			}
5783
			// If reset_scripts is not empty, print the link with the reset_scripts in the onClick
5784
			if ($reset_scripts && empty($conf->dol_optimize_smallscreen))
5785
			{
5786
				$retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">';
5787
				$retstring .= $langs->trans("DateStartPlusOne");
5788
				$retstring .= '</button> ';
5789
			}
5790
		}
5791
5792
		// Add a "Plus one hour" link
5793
		if ($conf->use_javascript_ajax && $adddateof)
5794
		{
5795
			$tmparray = dol_getdate($adddateof);
5796
			if (empty($labeladddateof)) $labeladddateof = $langs->trans("DateInvoice");
5797
			$retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="jQuery(\'#re\').val(\''.dol_print_date($adddateof, 'day').'\');jQuery(\'#reday\').val(\''.$tmparray['mday'].'\');jQuery(\'#remonth\').val(\''.$tmparray['mon'].'\');jQuery(\'#reyear\').val(\''.$tmparray['year'].'\');">'.$labeladddateof.'</a>';
5798
		}
5799
5800
		return $retstring;
5801
	}
5802
5803
	/**
5804
	 * selectTypeDuration
5805
	 *
5806
	 * @param   string   $prefix     Prefix
5807
	 * @param   string   $selected   Selected type
5808
	 * @return  string               HTML select string
5809
	 */
5810
	public function selectTypeDuration($prefix, $selected = 'i')
5811
	{
5812
		global $langs;
5813
5814
		$TDurationTypes = array('y'=>$langs->trans('Years'), 'm'=>$langs->trans('Month'), 'w'=>$langs->trans('Weeks'), 'd'=>$langs->trans('Days'), 'h'=>$langs->trans('Hours'), 'i'=>$langs->trans('Minutes'));
5815
5816
		$retstring = '<select class="flat" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">';
5817
		foreach ($TDurationTypes as $key=>$typeduration) {
5818
			$retstring .= '<option value="'.$key.'"';
5819
			if ($key == $selected) {
5820
				$retstring .= " selected";
5821
			}
5822
			$retstring .= ">".$typeduration."</option>";
5823
		}
5824
		$retstring .= "</select>";
5825
5826
		return $retstring;
5827
	}
5828
5829
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5830
	/**
5831
	 *  Function to show a form to select a duration on a page
5832
	 *
5833
	 *	@param	string		$prefix   		Prefix for input fields
5834
	 *	@param  int			$iSecond  		Default preselected duration (number of seconds or '')
5835
	 * 	@param	int			$disabled       Disable the combo box
5836
	 * 	@param	string		$typehour		If 'select' then input hour and input min is a combo,
5837
	 *						            	If 'text' input hour is in text and input min is a text,
5838
	 *						            	If 'textselect' input hour is in text and input min is a combo
5839
	 *  @param	integer		$minunderhours	If 1, show minutes selection under the hours
5840
	 * 	@param	int			$nooutput		Do not output html string but return it
5841
	 *  @return	string|void
5842
	 */
5843
	public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
5844
	{
5845
		// phpcs:enable
5846
		global $langs;
5847
5848
		$retstring = '';
5849
5850
		$hourSelected = 0; $minSelected = 0;
5851
5852
		// Hours
5853
		if ($iSecond != '')
5854
		{
5855
			require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
5856
5857
			$hourSelected = convertSecondToTime($iSecond, 'allhour');
5858
			$minSelected = convertSecondToTime($iSecond, 'min');
5859
		}
5860
5861
		if ($typehour == 'select') {
5862
			$retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>';
5863
			for ($hour = 0; $hour < 25; $hour++)	// For a duration, we allow 24 hours
5864
			{
5865
				$retstring .= '<option value="'.$hour.'"';
5866
				if ($hourSelected == $hour)
5867
				{
5868
					$retstring .= " selected";
5869
				}
5870
				$retstring .= ">".$hour."</option>";
5871
			}
5872
			$retstring .= "</select>";
5873
		} elseif ($typehour == 'text' || $typehour == 'textselect') {
5874
			$retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">';
5875
		} else {
5876
			return 'BadValueForParameterTypeHour';
5877
		}
5878
5879
		if ($typehour != 'text') $retstring .= ' '.$langs->trans('HourShort');
5880
		else $retstring .= '<span class="hideonsmartphone">:</span>';
5881
5882
		// Minutes
5883
		if ($minunderhours) $retstring .= '<br>';
5884
		else $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
5885
5886
		if ($typehour == 'select' || $typehour == 'textselect')
5887
		{
5888
			$retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>';
5889
			for ($min = 0; $min <= 55; $min = $min + 5)
5890
			{
5891
				$retstring .= '<option value="'.$min.'"';
5892
				if ($minSelected == $min) $retstring .= ' selected';
5893
				$retstring .= '>'.$min.'</option>';
5894
			}
5895
			$retstring .= "</select>";
5896
		} elseif ($typehour == 'text')
5897
		{
5898
			$retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">';
5899
		}
5900
5901
		if ($typehour != 'text') $retstring .= ' '.$langs->trans('MinuteShort');
5902
5903
		//$retstring.="&nbsp;";
5904
5905
		if (!empty($nooutput)) return $retstring;
5906
5907
		print $retstring;
5908
		return;
5909
	}
5910
5911
5912
	/**
5913
	 * Generic method to select a component from a combo list.
5914
	 * Can use autocomplete with ajax after x key pressed or a full combo, depending on setup.
5915
	 * This is the generic method that will replace all specific existing methods.
5916
	 *
5917
	 * @param 	string			$objectdesc			ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]
5918
	 * @param	string			$htmlname			Name of HTML select component
5919
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
5920
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
5921
	 * @param	string			$searchkey			Search criteria
5922
	 * @param	string			$placeholder		Place holder
5923
	 * @param	string			$morecss			More CSS
5924
	 * @param	string			$moreparams			More params provided to ajax call
5925
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
5926
	 * @param	int				$disabled			1=Html component is disabled
5927
	 * @param	string	        $selected_input_value	Value of preselected input text (for use with ajax)
5928
	 * @return	string								Return HTML string
5929
	 * @see selectForFormsList() select_thirdparty_list()
5930
	 */
5931
	public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '')
5932
	{
5933
		global $conf, $user;
5934
5935
		$objecttmp = null;
5936
5937
		$InfoFieldList = explode(":", $objectdesc);
5938
		$classname = $InfoFieldList[0];
5939
		$classpath = $InfoFieldList[1];
5940
		$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
5941
		$filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
5942
5943
		if (!empty($classpath))
5944
		{
5945
			dol_include_once($classpath);
5946
5947
			if ($classname && class_exists($classname))
5948
			{
5949
				$objecttmp = new $classname($this->db);
5950
				// Make some replacement
5951
				$sharedentities = getEntity(strtolower($classname));
5952
				$objecttmp->filter = str_replace(
5953
					array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
5954
					array($conf->entity, $sharedentities, $user->id),
5955
					$filter);
5956
			}
5957
		}
5958
		if (!is_object($objecttmp))
5959
		{
5960
			dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING);
5961
			return 'Error bad setup of type for field '.join(',', $InfoFieldList);
5962
		}
5963
5964
		//var_dump($objecttmp->filter);
5965
		$prefixforautocompletemode = $objecttmp->element;
5966
		if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode = 'company';
5967
		if ($prefixforautocompletemode == 'product') $prefixforautocompletemode = 'produit';
5968
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
5969
5970
		dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG);
5971
		$out = '';
5972
		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo)
5973
		{
5974
			// No immediate load of all database
5975
			$placeholder = '';
5976
			if ($preselectedvalue && empty($selected_input_value))
5977
			{
5978
				$objecttmp->fetch($preselectedvalue);
5979
				$selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
5980
				//unset($objecttmp);
5981
			}
5982
5983
			$objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter;
5984
			$urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php';
5985
5986
			// No immediate load of all database
5987
			$urloption = 'htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.'&filter='.urlencode($objecttmp->filter);
5988
			// Activate the auto complete using ajax call.
5989
			$out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array());
5990
			$out .= '<style type="text/css">.ui-autocomplete { z-index: 250; }</style>';
5991
			if ($placeholder) $placeholder = ' placeholder="'.$placeholder.'"';
5992
			$out .= '<input type="text" class="'.$morecss.'"'.($disabled ? ' disabled="disabled"' : '').' name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' />';
5993
		} else {
5994
			// Immediate load of table record. Note: filter is inside $objecttmp->filter
5995
			$out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled);
5996
		}
5997
5998
		return $out;
5999
	}
6000
6001
	/**
6002
	 * Function to forge a SQL criteria
6003
	 *
6004
	 * @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"
6005
	 * @return string                  Forged criteria. Example: "t.field like 'abc%'"
6006
	 */
6007
	protected static function forgeCriteriaCallback($matches)
6008
	{
6009
		global $db;
6010
6011
		//dol_syslog("Convert matches ".$matches[1]);
6012
		if (empty($matches[1])) return '';
6013
		$tmp = explode(':', $matches[1]);
6014
		if (count($tmp) < 3) return '';
6015
6016
		$tmpescaped = $tmp[2];
6017
		$regbis = array();
6018
		if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis))
6019
		{
6020
			$tmpescaped = "'".$db->escape($regbis[1])."'";
6021
		} else {
6022
			$tmpescaped = $db->escape($tmpescaped);
6023
		}
6024
		return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped;
6025
	}
6026
6027
	/**
6028
	 * Output html form to select an object.
6029
	 * Note, this function is called by selectForForms or by ajax selectobject.php
6030
	 *
6031
	 * @param 	Object			$objecttmp			Object to knwo the table to scan for combo.
6032
	 * @param	string			$htmlname			Name of HTML select component
6033
	 * @param	int				$preselectedvalue	Preselected value (ID of element)
6034
	 * @param	string			$showempty			''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...)
6035
	 * @param	string			$searchkey			Search value
6036
	 * @param	string			$placeholder		Place holder
6037
	 * @param	string			$morecss			More CSS
6038
	 * @param	string			$moreparams			More params provided to ajax call
6039
	 * @param	int				$forcecombo			Force to load all values and output a standard combobox (with no beautification)
6040
	 * @param	int				$outputmode			0=HTML select string, 1=Array
6041
	 * @param	int				$disabled			1=Html component is disabled
6042
	 * @return	string|array						Return HTML string
6043
	 * @see selectForForms()
6044
	 */
6045
	public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0)
6046
	{
6047
		global $conf, $langs, $user;
6048
6049
		//print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled";
6050
6051
		$prefixforautocompletemode = $objecttmp->element;
6052
		if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode = 'company';
6053
		$confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
6054
6055
		if (!empty($objecttmp->fields))	// For object that declare it, it is better to use declared fields (like societe, contact, ...)
6056
		{
6057
			$tmpfieldstoshow = '';
6058
			foreach ($objecttmp->fields as $key => $val)
6059
			{
6060
				if ($val['showoncombobox']) $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key;
6061
			}
6062
			if ($tmpfieldstoshow) $fieldstoshow = $tmpfieldstoshow;
6063
		} else {
6064
			// For backward compatibility
6065
			$objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1);
6066
		}
6067
6068
		if (empty($fieldstoshow))
6069
		{
6070
			if (isset($objecttmp->fields['ref'])) {
6071
				$fieldstoshow = 't.ref';
6072
			} else {
6073
				$langs->load("errors");
6074
				$this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
6075
				return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
6076
			}
6077
		}
6078
6079
		$out = '';
6080
		$outarray = array();
6081
6082
		$num = 0;
6083
6084
		// Search data
6085
		$sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX.$objecttmp->table_element." as t";
6086
		if (isset($objecttmp->ismultientitymanaged) && !is_numeric($objecttmp->ismultientitymanaged)) {
6087
			$tmparray = explode('@', $objecttmp->ismultientitymanaged);
6088
			$sql .= ' INNER JOIN '.MAIN_DB_PREFIX.$tmparray[1].' as parenttable ON parenttable.rowid = t.'.$tmparray[0];
6089
		}
6090
		if ($objecttmp->ismultientitymanaged == 'fk_soc@societe')
6091
			if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
6092
		$sql .= " WHERE 1=1";
6093
		if (isset($objecttmp->ismultientitymanaged) && $objecttmp->ismultientitymanaged == 1) $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")";
6094
		if (isset($objecttmp->ismultientitymanaged) && !is_numeric($objecttmp->ismultientitymanaged)) {
6095
			$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...
6096
		}
6097
		if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
6098
			if ($objecttmp->element == 'societe') $sql .= " AND t.rowid = ".$user->socid;
6099
			else $sql .= " AND t.fk_soc = ".$user->socid;
6100
		}
6101
		if ($searchkey != '') $sql .= natural_search(explode(',', $fieldstoshow), $searchkey);
6102
		if ($objecttmp->ismultientitymanaged == 'fk_soc@societe') {
6103
			if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
6104
		}
6105
		if ($objecttmp->filter) {	 // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
6106
			/*if (! DolibarrApi::_checkFilters($objecttmp->filter))
6107
			{
6108
				throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter);
6109
			}*/
6110
			$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
6111
			$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")";
6112
		}
6113
		$sql .= $this->db->order($fieldstoshow, "ASC");
6114
		//$sql.=$this->db->plimit($limit, 0);
6115
		//print $sql;
6116
6117
		// Build output string
6118
		$resql = $this->db->query($sql);
6119
		if ($resql)
6120
		{
6121
			if (!$forcecombo)
6122
			{
6123
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6124
				$out .= ajax_combobox($htmlname, null, $conf->global->$confkeyforautocompletemode);
6125
			}
6126
6127
			// Construct $out and $outarray
6128
			$out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n";
6129
6130
			// 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
6131
			$textifempty = '&nbsp;';
6132
6133
			//if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
6134
			if (!empty($conf->global->$confkeyforautocompletemode))
6135
			{
6136
				if ($showempty && !is_numeric($showempty)) $textifempty = $langs->trans($showempty);
6137
				else $textifempty .= $langs->trans("All");
6138
			}
6139
			if ($showempty) $out .= '<option value="-1">'.$textifempty.'</option>'."\n";
6140
6141
			$num = $this->db->num_rows($resql);
6142
			$i = 0;
6143
			if ($num)
6144
			{
6145
				while ($i < $num)
6146
				{
6147
					$obj = $this->db->fetch_object($resql);
6148
					$label = '';
6149
					$tmparray = explode(',', $fieldstoshow);
6150
					foreach ($tmparray as $key => $val)
6151
					{
6152
						$val = preg_replace('/t\./', '', $val);
6153
						$label .= (($label && $obj->$val) ? ' - ' : '').$obj->$val;
6154
					}
6155
					if (empty($outputmode))
6156
					{
6157
						if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid)
6158
						{
6159
							$out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>';
6160
						} else {
6161
							$out .= '<option value="'.$obj->rowid.'">'.$label.'</option>';
6162
						}
6163
					} else {
6164
						array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label));
6165
					}
6166
6167
					$i++;
6168
					if (($i % 10) == 0) $out .= "\n";
6169
				}
6170
			}
6171
6172
			$out .= '</select>'."\n";
6173
		} else {
6174
			dol_print_error($this->db);
6175
		}
6176
6177
		$this->result = array('nbofelement'=>$num);
6178
6179
		if ($outputmode) return $outarray;
6180
		return $out;
6181
	}
6182
6183
6184
	/**
6185
	 *	Return a HTML select string, built from an array of key+value.
6186
	 *  Note: Do not apply langs->trans function on returned content, content may be entity encoded twice.
6187
	 *
6188
	 *	@param	string			$htmlname			Name of html select area. Must start with "multi" if this is a multiselect
6189
	 *	@param	array			$array				Array like array(key => value) or array(key=>array('label'=>..., 'data-...'=>...))
6190
	 *	@param	string|string[]	$id					Preselected key or preselected keys for multiselect
6191
	 *	@param	int|string		$show_empty			0 no empty value allowed, 1 or string to add an empty value into list (key is -1 and value is '' or '&nbsp;' if 1, key is -1 and value is text if string), <0 to add an empty value with key that is this value.
6192
	 *	@param	int				$key_in_label		1 to show key into label with format "[key] value"
6193
	 *	@param	int				$value_as_key		1 to use value as key
6194
	 *	@param  string			$moreparam			Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
6195
	 *	@param  int				$translate			1=Translate and encode value
6196
	 * 	@param	int				$maxlen				Length maximum for labels
6197
	 * 	@param	int				$disabled			Html select box is disabled
6198
	 *  @param	string			$sort				'ASC' or 'DESC' = Sort on label, '' or 'NONE' or 'POS' = Do not sort, we keep original order
6199
	 *  @param	string			$morecss			Add more class to css styles
6200
	 *  @param	int				$addjscombo			Add js combo
6201
	 *  @param  string          $moreparamonempty	Add more param on the empty option line. Not used if show_empty not set
6202
	 *  @param  int             $disablebademail	1=Check if a not valid email, 2=Check string '---', and if found into value, disable and colorize entry
6203
	 *  @param  int             $nohtmlescape		No html escaping.
6204
	 * 	@return	string								HTML select string.
6205
	 *  @see multiselectarray(), selectArrayAjax(), selectArrayFilter()
6206
	 */
6207
	public static function selectarray($htmlname, $array, $id = '', $show_empty = 0, $key_in_label = 0, $value_as_key = 0, $moreparam = '', $translate = 0, $maxlen = 0, $disabled = 0, $sort = '', $morecss = '', $addjscombo = 0, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
6208
	{
6209
		global $conf, $langs;
6210
6211
		// Do we want a multiselect ?
6212
		//$jsbeautify = 0;
6213
		//if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
6214
		$jsbeautify = 1;
6215
6216
		if ($value_as_key) $array = array_combine($array, $array);
6217
6218
		$out = '';
6219
6220
		// Add code for jquery to use multiselect
6221
		if ($addjscombo && $jsbeautify)
6222
		{
6223
			$minLengthToAutocomplete = 0;
6224
			$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ? (constant('REQUIRE_JQUERY_MULTISELECT') ?constant('REQUIRE_JQUERY_MULTISELECT') : 'select2') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
6225
6226
			// Enhance with select2
6227
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
6228
			$out .= ajax_combobox($htmlname);
6229
		}
6230
6231
		$out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"';
6232
		$out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : '');
6233
		$out .= '>';
6234
6235
		if ($show_empty)
6236
		{
6237
			$textforempty = ' ';
6238
			if (!empty($conf->use_javascript_ajax)) $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
6239
			if (!is_numeric($show_empty)) $textforempty = $show_empty;
6240
			$out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n";
6241
		}
6242
6243
		if (is_array($array))
6244
		{
6245
			// Translate
6246
			if ($translate)
6247
			{
6248
				foreach ($array as $key => $value)
6249
				{
6250
					if (!is_array($value)) $array[$key] = $langs->trans($value);
6251
					else $array[$key]['label'] = $langs->trans($value['label']);
6252
				}
6253
			}
6254
6255
			// Sort
6256
			if ($sort == 'ASC') asort($array);
6257
			elseif ($sort == 'DESC') arsort($array);
6258
6259
			foreach ($array as $key => $tmpvalue)
6260
			{
6261
				if (is_array($tmpvalue)) $value = $tmpvalue['label'];
6262
				else $value = $tmpvalue;
6263
6264
				$disabled = ''; $style = '';
6265
				if (!empty($disablebademail))
6266
				{
6267
					if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
6268
						|| ($disablebademail == 2 && preg_match('/---/', $value)))
6269
					{
6270
						$disabled = ' disabled';
6271
						$style = ' class="warning"';
6272
					}
6273
				}
6274
6275
				if ($key_in_label)
6276
				{
6277
					if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value));
6278
					else $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value);
6279
				} else {
6280
					if (empty($nohtmlescape)) $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value);
6281
					else $selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value;
6282
					if ($value == '' || $value == '-') $selectOptionValue = '&nbsp;';
6283
				}
6284
6285
				$out .= '<option value="'.$key.'"';
6286
				$out .= $style.$disabled;
6287
				if (is_array($id)) {
6288
					if (in_array($key, $id) && !$disabled) $out .= ' selected'; // To preselect a value
6289
				} else {
6290
					$id = (string) $id; // if $id = 0, then $id = '0'
6291
					if ($id != '' && $id == $key && !$disabled) $out .= ' selected'; // To preselect a value
6292
				}
6293
				if ($nohtmlescape) $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"';
6294
				if (is_array($tmpvalue))
6295
				{
6296
					foreach ($tmpvalue as $keyforvalue => $valueforvalue)
6297
					{
6298
						if (preg_match('/^data-/', $keyforvalue)) $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"';
6299
					}
6300
				}
6301
				$out .= '>';
6302
				//var_dump($selectOptionValue);
6303
				$out .= $selectOptionValue;
6304
				$out .= "</option>\n";
6305
			}
6306
		}
6307
6308
		$out .= "</select>";
6309
		return $out;
6310
	}
6311
6312
6313
	/**
6314
	 *	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.
6315
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
6316
	 *
6317
	 *	@param	string	$htmlname       		Name of html select area
6318
	 *	@param	string	$url					Url. Must return a json_encode of array(key=>array('text'=>'A text', 'url'=>'An url'), ...)
6319
	 *	@param	string	$id             		Preselected key
6320
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
6321
	 *	@param  string	$moreparamtourl 		Add more parameters onto the Ajax called URL
6322
	 * 	@param	int		$disabled				Html select box is disabled
6323
	 *  @param	int		$minimumInputLength		Minimum Input Length
6324
	 *  @param	string	$morecss				Add more class to css styles
6325
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
6326
	 *  @param  string  $placeholder            String to use as placeholder
6327
	 *  @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)
6328
	 * 	@return	string   						HTML select string
6329
	 *  @see selectArrayFilter(), ajax_combobox() in ajax.lib.php
6330
	 */
6331
	public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
6332
	{
6333
		global $conf, $langs;
6334
		global $delayedhtmlcontent;
6335
6336
		// TODO Use an internal dolibarr component instead of select2
6337
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) return '';
6338
6339
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>';
6340
6341
		$tmpplugin = 'select2';
6342
		$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6343
	    	<script>
6344
	    	$(document).ready(function () {
6345
6346
    	        '.($callurlonselect ? 'var saveRemoteData = [];' : '').'
6347
6348
                $(".'.$htmlname.'").select2({
6349
			    	ajax: {
6350
				    	dir: "ltr",
6351
				    	url: "'.$url.'",
6352
				    	dataType: \'json\',
6353
				    	delay: 250,
6354
				    	data: function (params) {
6355
				    		return {
6356
						    	q: params.term, 	// search term
6357
				    			page: params.page
6358
				    		};
6359
			    		},
6360
			    		processResults: function (data) {
6361
			    			// parse the results into the format expected by Select2.
6362
			    			// since we are using custom formatting functions we do not need to alter the remote JSON data
6363
			    			//console.log(data);
6364
							saveRemoteData = data;
6365
				    	    /* format json result for select2 */
6366
				    	    result = []
6367
				    	    $.each( data, function( key, value ) {
6368
				    	       result.push({id: key, text: value.text});
6369
                            });
6370
			    			//return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
6371
			    			//console.log(result);
6372
			    			return {results: result, more: false}
6373
			    		},
6374
			    		cache: true
6375
			    	},
6376
	 				language: select2arrayoflanguage,
6377
					containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
6378
				    placeholder: "'.dol_escape_js($placeholder).'",
6379
			    	escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
6380
			    	minimumInputLength: '.$minimumInputLength.',
6381
			        formatResult: function(result, container, query, escapeMarkup) {
6382
                        return escapeMarkup(result.text);
6383
                    },
6384
			    });
6385
6386
                '.($callurlonselect ? '
6387
                /* Code to execute a GET when we select a value */
6388
                $(".'.$htmlname.'").change(function() {
6389
			    	var selected = $(".'.$htmlname.'").val();
6390
                	console.log("We select in selectArrayAjax the entry "+selected)
6391
			        $(".'.$htmlname.'").val("");  /* reset visible combo value */
6392
    			    $.each( saveRemoteData, function( key, value ) {
6393
    				        if (key == selected)
6394
    			            {
6395
    			                 console.log("selectArrayAjax - Do a redirect to "+value.url)
6396
    			                 location.assign(value.url);
6397
    			            }
6398
                    });
6399
    			});' : '').'
6400
6401
    	   });
6402
	       </script>';
6403
6404
		if ($acceptdelayedhtml)
6405
		{
6406
			$delayedhtmlcontent .= $outdelayed;
6407
		} else {
6408
			$out .= $outdelayed;
6409
		}
6410
		return $out;
6411
	}
6412
6413
	/**
6414
	 *  Return a HTML select string, built from an array of key+value, but content returned into select is defined into $array parameter.
6415
	 *  Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice.
6416
	 *
6417
	 *  @param  string	$htmlname               Name of html select area
6418
	 *	@param	string	$array					Array (key=>array('text'=>'A text', 'url'=>'An url'), ...)
6419
	 *	@param	string	$id             		Preselected key
6420
	 *	@param  string	$moreparam      		Add more parameters onto the select tag
6421
	 *	@param	int		$disableFiltering		If set to 1, results are not filtered with searched string
6422
	 * 	@param	int		$disabled				Html select box is disabled
6423
	 *  @param	int		$minimumInputLength		Minimum Input Length
6424
	 *  @param	string	$morecss				Add more class to css styles
6425
	 *  @param  int     $callurlonselect        If set to 1, some code is added so an url return by the ajax is called when value is selected.
6426
	 *  @param  string  $placeholder            String to use as placeholder
6427
	 *  @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)
6428
	 *  @return	string   						HTML select string
6429
	 *  @see selectArrayAjax(), ajax_combobox() in ajax.lib.php
6430
	 */
6431
	public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
6432
	{
6433
		global $conf, $langs;
6434
		global $delayedhtmlcontent;
6435
6436
		// TODO Use an internal dolibarr component instead of select2
6437
		if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) return '';
6438
6439
		$out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>';
6440
6441
		$formattedarrayresult = array();
6442
6443
		foreach ($array as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $array of type string is not traversable.
Loading history...
6444
			$o = new stdClass();
6445
			$o->id = $key;
6446
			$o->text = $value['text'];
6447
			$o->url = $value['url'];
6448
			$formattedarrayresult[] = $o;
6449
		}
6450
6451
		$tmpplugin = 'select2';
6452
		$outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' -->
6453
			<script>
6454
			$(document).ready(function () {
6455
				var data = '.json_encode($formattedarrayresult).';
6456
6457
				'.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').'
6458
6459
				$(".'.$htmlname.'").select2({
6460
					data: data,
6461
					language: select2arrayoflanguage,
6462
					containerCssClass: \':all:\',					/* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */
6463
					placeholder: "'.dol_escape_js($placeholder).'",
6464
					escapeMarkup: function (markup) { return markup; }, 	// let our custom formatter work
6465
					minimumInputLength: '.$minimumInputLength.',
6466
					formatResult: function(result, container, query, escapeMarkup) {
6467
						return escapeMarkup(result.text);
6468
					},
6469
					matcher: function (params, data) {
6470
6471
						if(! data.id) return null;';
6472
6473
		if ($callurlonselect) {
6474
			$outdelayed .= '
6475
6476
						var urlBase = data.url;
6477
						var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
6478
						/* console.log("params.term="+params.term); */
6479
						/* console.log("params.term encoded="+encodeURIComponent(params.term)); */
6480
						saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term);';
6481
		}
6482
6483
		if (!$disableFiltering) {
6484
			$outdelayed .= '
6485
6486
						if(data.text.match(new RegExp(params.term))) {
6487
							return data;
6488
						}
6489
6490
						return null;';
6491
		} else {
6492
			$outdelayed .= '
6493
6494
						return data;';
6495
		}
6496
6497
		$outdelayed .= '
6498
					}
6499
				});
6500
6501
				'.($callurlonselect ? '
6502
				/* Code to execute a GET when we select a value */
6503
				$(".'.$htmlname.'").change(function() {
6504
					var selected = $(".'.$htmlname.'").val();
6505
					console.log("We select "+selected)
6506
6507
					$(".'.$htmlname.'").val("");  /* reset visible combo value */
6508
					$.each( saveRemoteData, function( key, value ) {
6509
						if (key == selected)
6510
						{
6511
							console.log("selectArrayAjax - Do a redirect to "+value.url)
6512
							location.assign(value.url);
6513
						}
6514
					});
6515
				});' : '').'
6516
6517
			});
6518
			</script>';
6519
6520
		if ($acceptdelayedhtml)
6521
		{
6522
			$delayedhtmlcontent .= $outdelayed;
6523
		} else {
6524
			$out .= $outdelayed;
6525
		}
6526
		return $out;
6527
	}
6528
6529
	/**
6530
	 *	Show a multiselect form from an array.
6531
	 *
6532
	 *	@param	string	$htmlname		Name of select
6533
	 *	@param	array	$array			Array with key+value
6534
	 *	@param	array	$selected		Array with key+value preselected
6535
	 *	@param	int		$key_in_label   1 to show key like in "[key] value"
6536
	 *	@param	int		$value_as_key   1 to use value as key
6537
	 *	@param  string	$morecss        Add more css style
6538
	 *	@param  int		$translate		Translate and encode value
6539
	 *  @param	int		$width			Force width of select box. May be used only when using jquery couch. Example: 250, 95%
6540
	 *  @param	string	$moreattrib		Add more options on select component. Example: 'disabled'
6541
	 *  @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.
6542
	 *  @param	string	$placeholder	String to use as placeholder
6543
	 *  @param	int		$addjscombo		Add js combo
6544
	 *	@return	string					HTML multiselect string
6545
	 *  @see selectarray(), selectArrayAjax(), selectArrayFilter()
6546
	 */
6547
	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)
6548
	{
6549
		global $conf, $langs;
6550
6551
		$out = '';
6552
6553
		if ($addjscombo < 0) {
6554
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $addjscombo = 1;
6555
			else $addjscombo = 0;
6556
		}
6557
6558
		// Add code for jquery to use multiselect
6559
		if (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))
6560
		{
6561
			$out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.' -->
6562
						<script>'."\n";
6563
			if ($addjscombo == 1)
6564
			{
6565
				$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
6566
				$out .= 'function formatResult(record) {'."\n";
6567
				if ($elemtype == 'category')
6568
				{
6569
					$out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
6570
				} else {
6571
					$out .= 'return record.text;';
6572
				}
6573
				$out .= '};'."\n";
6574
				$out .= 'function formatSelection(record) {'."\n";
6575
				if ($elemtype == 'category')
6576
				{
6577
					$out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
6578
				} else {
6579
					$out .= 'return record.text;';
6580
				}
6581
				$out .= '};'."\n";
6582
				$out .= '$(document).ready(function () {
6583
							$(\'#'.$htmlname.'\').'.$tmpplugin.'({
6584
								dir: \'ltr\',
6585
								// Specify format function for dropdown item
6586
								formatResult: formatResult,
6587
							 	templateResult: formatResult,		/* For 4.0 */
6588
								// Specify format function for selected item
6589
								formatSelection: formatSelection,
6590
							 	templateSelection: formatSelection		/* For 4.0 */
6591
							});
6592
						});'."\n";
6593
			} elseif ($addjscombo == 2 && ! defined('DISABLE_MULTISELECT'))
6594
			{
6595
				// Add other js lib
6596
				// TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
6597
				// ...
6598
				$out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
6599
				$out .= '$(document).ready(function () {
6600
							$(\'#'.$htmlname.'\').multiSelect({
6601
								containerHTML: \'<div class="multi-select-container">\',
6602
								menuHTML: \'<div class="multi-select-menu">\',
6603
								buttonHTML: \'<span class="multi-select-button '.$morecss.'">\',
6604
								menuItemHTML: \'<label class="multi-select-menuitem">\',
6605
								activeClass: \'multi-select-container--open\',
6606
								noneText: \''.$placeholder.'\'
6607
							});
6608
						})';
6609
			}
6610
			$out .= '</script>';
6611
		}
6612
6613
		// Try also magic suggest
6614
		$out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n";
6615
		if (is_array($array) && !empty($array))
6616
		{
6617
			if ($value_as_key) $array = array_combine($array, $array);
6618
6619
			if (!empty($array))
6620
			{
6621
				foreach ($array as $key => $value)
6622
				{
6623
					$newval = ($translate ? $langs->trans($value) : $value);
6624
					$newval = ($key_in_label ? $key.' - '.$newval : $newval);
6625
6626
					$out .= '<option value="'.$key.'"';
6627
					if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != ''))
6628
					{
6629
						$out .= ' selected';
6630
					}
6631
					$out .= ' data-html="'.$newval.'"';
6632
					$out .= '>';
6633
					$out .= dol_htmlentitiesbr($newval);
6634
					$out .= '</option>'."\n";
6635
				}
6636
			}
6637
		}
6638
		$out .= '</select>'."\n";
6639
6640
		return $out;
6641
	}
6642
6643
6644
	/**
6645
	 *	Show a multiselect dropbox from an array.
6646
	 *
6647
	 *	@param	string	$htmlname		Name of HTML field
6648
	 *	@param	array	$array			Array with array of fields we could show. This array may be modified according to setup of user.
6649
	 *  @param  string  $varpage        Id of context for page. Can be set by caller with $varpage=(empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage);
6650
	 *	@return	string					HTML multiselect string
6651
	 *  @see selectarray()
6652
	 */
6653
	public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage)
6654
	{
6655
		global $conf, $langs, $user, $extrafields;
6656
6657
		if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) return '';
6658
6659
		$tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved seleteced properties
6660
		if (!empty($user->conf->$tmpvar))
6661
		{
6662
			$tmparray = explode(',', $user->conf->$tmpvar);
6663
			foreach ($array as $key => $val)
6664
			{
6665
				//var_dump($key);
6666
				//var_dump($tmparray);
6667
				if (in_array($key, $tmparray)) $array[$key]['checked'] = 1;
6668
				else $array[$key]['checked'] = 0;
6669
			}
6670
		}
6671
6672
		$lis = '';
6673
		$listcheckedstring = '';
6674
6675
		foreach ($array as $key => $val)
6676
		{
6677
			/* var_dump($val);
6678
            var_dump(array_key_exists('enabled', $val));
6679
            var_dump(!$val['enabled']);*/
6680
			if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled'])
6681
			{
6682
				unset($array[$key]); // We don't want this field
6683
				continue;
6684
			}
6685
			if ($val['label'])
6686
			{
6687
				if (!empty($val['langfile']) && is_object($langs)) {
6688
					$langs->load($val['langfile']);
6689
				}
6690
6691
				$lis .= '<li><input type="checkbox" id="checkbox'.$key.'" value="'.$key.'"'.(empty($val['checked']) ? '' : ' checked="checked"').'/><label for="checkbox'.$key.'">'.dol_escape_htmltag($langs->trans($val['label'])).'</label></li>';
6692
				$listcheckedstring .= (empty($val['checked']) ? '' : $key.',');
6693
			}
6694
		}
6695
6696
		$out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' -->
6697
6698
        <dl class="dropdown">
6699
            <dt>
6700
            <a href="#'.$htmlname.'">
6701
              '.img_picto('', 'list').'
6702
            </a>
6703
            <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'">
6704
            </dt>
6705
            <dd class="dropdowndd">
6706
                <div class="multiselectcheckbox'.$htmlname.'">
6707
                    <ul class="ul'.$htmlname.'">
6708
                    '.$lis.'
6709
                    </ul>
6710
                </div>
6711
            </dd>
6712
        </dl>
6713
6714
        <script type="text/javascript">
6715
          jQuery(document).ready(function () {
6716
              $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () {
6717
                  console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
6718
6719
                  $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\');	// Update field so we know we changed something on selected fields after POST
6720
6721
                  var title = $(this).val() + ",";
6722
                  if ($(this).is(\':checked\')) {
6723
                      $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val());
6724
                  }
6725
                  else {
6726
                      $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') )
6727
                  }
6728
                  // Now, we submit page
6729
                  //$(this).parents(\'form:first\').submit();
6730
              });
6731
6732
6733
           });
6734
        </script>
6735
6736
        ';
6737
		return $out;
6738
	}
6739
6740
	/**
6741
	 * 	Render list of categories linked to object with id $id and type $type
6742
	 *
6743
	 * 	@param		int		$id				Id of object
6744
	 * 	@param		string	$type			Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
6745
	 *  @param		int		$rendermode		0=Default, use multiselect. 1=Emulate multiselect (recommended)
6746
	 *  @param		int		$nolink			1=Do not add html links
6747
	 * 	@return		string					String with categories
6748
	 */
6749
	public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
6750
	{
6751
		global $db;
6752
6753
		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
6754
6755
		$cat = new Categorie($db);
6756
		$categories = $cat->containing($id, $type);
6757
6758
		if ($rendermode == 1)
6759
		{
6760
			$toprint = array();
6761
			foreach ($categories as $c)
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
6762
			{
6763
				$ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text
6764
				foreach ($ways as $way)
6765
				{
6766
					$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #aaa"').'>'.$way.'</li>';
6767
				}
6768
			}
6769
			return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
6770
		}
6771
6772
		if ($rendermode == 0)
6773
		{
6774
			$arrayselected = array();
6775
			$cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1);
6776
			foreach ($categories as $c) {
0 ignored issues
show
Bug introduced by
The expression $categories of type integer is not traversable.
Loading history...
6777
				$arrayselected[] = $c->id;
6778
			}
6779
6780
			return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category');
6781
		}
6782
6783
		return 'ErrorBadValueForParameterRenderMode'; // Should not happened
6784
	}
6785
6786
	/**
6787
	 *  Show linked object block.
6788
	 *
6789
	 *  @param	CommonObject	$object		      Object we want to show links to
6790
	 *  @param  string          $morehtmlright    More html to show on right of title
6791
	 *  @param  array           $compatibleImportElementsList  Array of compatibles elements object for "import from" action
6792
	 *  @return	int							      <0 if KO, >=0 if OK
6793
	 */
6794
	public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false)
6795
	{
6796
		global $conf, $langs, $hookmanager;
6797
		global $bc, $action;
6798
6799
		$object->fetchObjectLinked();
6800
6801
		// Bypass the default method
6802
		$hookmanager->initHooks(array('commonobject'));
6803
		$parameters = array(
6804
			'morehtmlright' => $morehtmlright,
6805
			'compatibleImportElementsList' => &$compatibleImportElementsList,
6806
		);
6807
		$reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
6808
6809
		if (empty($reshook))
6810
		{
6811
			$nbofdifferenttypes = count($object->linkedObjects);
6812
6813
			print '<!-- showLinkedObjectBlock -->';
6814
			print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock');
6815
6816
6817
			print '<div class="div-table-responsive-no-min">';
6818
			print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'"  data-elementid="'.$object->id.'"   >';
6819
6820
			print '<tr class="liste_titre">';
6821
			print '<td>'.$langs->trans("Type").'</td>';
6822
			print '<td>'.$langs->trans("Ref").'</td>';
6823
			print '<td class="center"></td>';
6824
			print '<td class="center">'.$langs->trans("Date").'</td>';
6825
			print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
6826
			print '<td class="right">'.$langs->trans("Status").'</td>';
6827
			print '<td></td>';
6828
			print '</tr>';
6829
6830
			$nboftypesoutput = 0;
6831
6832
			foreach ($object->linkedObjects as $objecttype => $objects)
6833
			{
6834
				$tplpath = $element = $subelement = $objecttype;
6835
6836
				// to display inport button on tpl
6837
				$showImportButton = false;
6838
				if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
6839
					$showImportButton = true;
6840
				}
6841
6842
				$regs = array();
6843
				if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs))
6844
				{
6845
					$element = $regs[1];
6846
					$subelement = $regs[2];
6847
					$tplpath = $element.'/'.$subelement;
6848
				}
6849
				$tplname = 'linkedobjectblock';
6850
6851
				// To work with non standard path
6852
				if ($objecttype == 'facture') {
6853
					$tplpath = 'compta/'.$element;
6854
					if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
6855
				} elseif ($objecttype == 'facturerec') {
6856
					$tplpath = 'compta/facture';
6857
					$tplname = 'linkedobjectblockForRec';
6858
					if (empty($conf->facture->enabled)) continue; // Do not show if module disabled
6859
				} elseif ($objecttype == 'propal') {
6860
					$tplpath = 'comm/'.$element;
6861
					if (empty($conf->propal->enabled)) continue; // Do not show if module disabled
6862
				} elseif ($objecttype == 'supplier_proposal') {
6863
					if (empty($conf->supplier_proposal->enabled)) continue; // Do not show if module disabled
6864
				} elseif ($objecttype == 'shipping' || $objecttype == 'shipment') {
6865
					$tplpath = 'expedition';
6866
					if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
6867
				} elseif ($objecttype == 'reception') {
6868
					$tplpath = 'reception';
6869
					if (empty($conf->reception->enabled)) continue; // Do not show if module disabled
6870
				} elseif ($objecttype == 'delivery') {
6871
					$tplpath = 'livraison';
6872
					if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled
6873
				} elseif ($objecttype == 'invoice_supplier') {
6874
					$tplpath = 'fourn/facture';
6875
				} elseif ($objecttype == 'order_supplier') {
6876
					$tplpath = 'fourn/commande';
6877
				} elseif ($objecttype == 'expensereport') {
6878
					$tplpath = 'expensereport';
6879
				} elseif ($objecttype == 'subscription') {
6880
					$tplpath = 'adherents';
6881
				}
6882
6883
				global $linkedObjectBlock;
6884
				$linkedObjectBlock = $objects;
6885
6886
6887
				// Output template part (modules that overwrite templates must declare this into descriptor)
6888
				$dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl'));
6889
				foreach ($dirtpls as $reldir)
6890
				{
6891
					if ($nboftypesoutput == ($nbofdifferenttypes - 1))    // No more type to show after
6892
					{
6893
						global $noMoreLinkedObjectBlockAfter;
6894
						$noMoreLinkedObjectBlockAfter = 1;
6895
					}
6896
6897
					$res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php');
6898
					if ($res)
6899
					{
6900
						$nboftypesoutput++;
6901
						break;
6902
					}
6903
				}
6904
			}
6905
6906
			if (!$nboftypesoutput)
6907
			{
6908
				print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>';
6909
			}
6910
6911
			print '</table>';
6912
6913
			if (!empty($compatibleImportElementsList))
6914
			{
6915
				$res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php');
6916
			}
6917
6918
6919
			print '</div>';
6920
6921
			return $nbofdifferenttypes;
6922
		}
6923
	}
6924
6925
	/**
6926
	 *  Show block with links to link to other objects.
6927
	 *
6928
	 *  @param	CommonObject	$object				Object we want to show links to
6929
	 *  @param	array			$restrictlinksto	Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction.
6930
	 *  @param	array			$excludelinksto		Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion.
6931
	 *  @return	string								<0 if KO, >0 if OK
6932
	 */
6933
	public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array())
6934
	{
6935
		global $conf, $langs, $hookmanager;
6936
		global $bc, $action;
6937
6938
		$linktoelem = '';
6939
		$linktoelemlist = '';
6940
		$listofidcompanytoscan = '';
6941
6942
		if (!is_object($object->thirdparty)) $object->fetch_thirdparty();
6943
6944
		$possiblelinks = array();
6945
		if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0)
6946
		{
6947
			$listofidcompanytoscan = $object->thirdparty->id;
6948
			if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) $listofidcompanytoscan .= ','.$object->thirdparty->parent;
6949
			if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO))
6950
			{
6951
				include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
6952
				$tmpproject = new Project($this->db);
6953
				$tmpproject->fetch($object->fk_project);
6954
				if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) $listofidcompanytoscan .= ','.$tmpproject->socid;
6955
				unset($tmpproject);
6956
			}
6957
6958
			$possiblelinks = array(
6959
				'propal'=>array('enabled'=>$conf->propal->enabled, 'perms'=>1, 'label'=>'LinkToProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('propal').')'),
6960
				'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande').')'),
6961
				'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'),
6962
				'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'),
6963
				'contrat'=>array('enabled'=>$conf->contrat->enabled, 'perms'=>1, 'label'=>'LinkToContract',
6964
								'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, '' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'),
6965
				'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('intervention').')'),
6966
				'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled, 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('supplier_proposal').')'),
6967
				'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled, 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande_fournisseur').')'),
6968
				'invoice_supplier'=>array('enabled'=>$conf->supplier_invoice->enabled, 'perms'=>1, 'label'=>'LinkToSupplierInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('facture_fourn').')'),
6969
				'ticket'=>array('enabled'=>$conf->ticket->enabled, 'perms'=>1, 'label'=>'LinkToTicket', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('ticket').')')
6970
			);
6971
		}
6972
6973
		// Can complete the possiblelink array
6974
		$hookmanager->initHooks(array('commonobject'));
6975
		$parameters = array('listofidcompanytoscan' => $listofidcompanytoscan);
6976
6977
		if (!empty($listofidcompanytoscan))  // If empty, we don't have criteria to scan the object we can link to
6978
		{
6979
			$reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
6980
		}
6981
6982
		if (empty($reshook))
6983
		{
6984
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6985
			{
6986
				$possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
6987
			}
6988
		} 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...
6989
		{
6990
			if (is_array($hookmanager->resArray) && count($hookmanager->resArray))
6991
			{
6992
				$possiblelinks = $hookmanager->resArray;
6993
			}
6994
		}
6995
6996
		foreach ($possiblelinks as $key => $possiblelink)
6997
		{
6998
			$num = 0;
6999
7000
			if (empty($possiblelink['enabled'])) continue;
7001
7002
			if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto)))
7003
			{
7004
				print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>';
7005
				$sql = $possiblelink['sql'];
7006
7007
				$resqllist = $this->db->query($sql);
7008
				if ($resqllist)
7009
				{
7010
					$num = $this->db->num_rows($resqllist);
7011
					$i = 0;
7012
7013
					print '<br>';
7014
					print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">';
7015
					print '<input type="hidden" name="action" value="addlink">';
7016
					print '<input type="hidden" name="token" value="'.newToken().'">';
7017
					print '<input type="hidden" name="id" value="'.$object->id.'">';
7018
					print '<input type="hidden" name="addlink" value="'.$key.'">';
7019
					print '<table class="noborder">';
7020
					print '<tr class="liste_titre">';
7021
					print '<td class="nowrap"></td>';
7022
					print '<td class="center">'.$langs->trans("Ref").'</td>';
7023
					print '<td class="left">'.$langs->trans("RefCustomer").'</td>';
7024
					print '<td class="right">'.$langs->trans("AmountHTShort").'</td>';
7025
					print '<td class="left">'.$langs->trans("Company").'</td>';
7026
					print '</tr>';
7027
					while ($i < $num)
7028
					{
7029
						$objp = $this->db->fetch_object($resqllist);
7030
7031
						print '<tr class="oddeven">';
7032
						print '<td class="left">';
7033
						print '<input type="radio" name="idtolinkto" value='.$objp->rowid.'>';
7034
						print '</td>';
7035
						print '<td class="center">'.$objp->ref.'</td>';
7036
						print '<td>'.$objp->ref_client.'</td>';
7037
						print '<td class="right">'.price($objp->total_ht).'</td>';
7038
						print '<td>'.$objp->name.'</td>';
7039
						print '</tr>';
7040
						$i++;
7041
					}
7042
					print '</table>';
7043
					print '<div class="center"><input type="submit" class="button valignmiddle" value="'.$langs->trans('ToLink').'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" class="button" name="cancel" value="'.$langs->trans('Cancel').'"></div>';
7044
7045
					print '</form>';
7046
					$this->db->free($resqllist);
7047
				} else {
7048
					dol_print_error($this->db);
7049
				}
7050
				print '</div>';
7051
				if ($num > 0)
7052
				{
7053
				}
7054
7055
				//$linktoelem.=($linktoelem?' &nbsp; ':'');
7056
				if ($num > 0) $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>';
7057
				//else $linktoelem.=$langs->trans($possiblelink['label']);
7058
				else $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>';
7059
			}
7060
		}
7061
7062
		if ($linktoelemlist)
7063
		{
7064
			$linktoelem = '
7065
    		<dl class="dropdown" id="linktoobjectname">
7066
    		';
7067
			if (!empty($conf->use_javascript_ajax)) $linktoelem .= '<dt><a href="#linktoobjectname">'.$langs->trans("LinkTo").'...</a></dt>';
7068
			$linktoelem .= '<dd>
7069
    		<div class="multiselectlinkto">
7070
    		<ul class="ulselectedfields">'.$linktoelemlist.'
7071
    		</ul>
7072
    		</div>
7073
    		</dd>
7074
    		</dl>';
7075
		} else {
7076
			$linktoelem = '';
7077
		}
7078
7079
		if (!empty($conf->use_javascript_ajax))
7080
		{
7081
			print '<!-- Add js to show linkto box -->
7082
				<script>
7083
				jQuery(document).ready(function() {
7084
					jQuery(".linkto").click(function() {
7085
						console.log("We choose to show/hide link for rel="+jQuery(this).attr(\'rel\'));
7086
					    jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
7087
					});
7088
				});
7089
				</script>
7090
		    ';
7091
		}
7092
7093
		return $linktoelem;
7094
	}
7095
7096
	/**
7097
	 *	Return an html string with a select combo box to choose yes or no
7098
	 *
7099
	 *	@param	string		$htmlname		Name of html select field
7100
	 *	@param	string		$value			Pre-selected value
7101
	 *	@param	int			$option			0 return yes/no, 1 return 1/0
7102
	 *	@param	bool		$disabled		true or false
7103
	 *  @param	int      	$useempty		1=Add empty line
7104
	 *	@return	string						See option
7105
	 */
7106
	public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0)
7107
	{
7108
		global $langs;
7109
7110
		$yes = "yes"; $no = "no";
7111
		if ($option)
7112
		{
7113
			$yes = "1";
7114
			$no = "0";
7115
		}
7116
7117
		$disabled = ($disabled ? ' disabled' : '');
7118
7119
		$resultyesno = '<select class="flat width75" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n";
7120
		if ($useempty) $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'>&nbsp;</option>'."\n";
7121
		if (("$value" == 'yes') || ($value == 1))
7122
		{
7123
			$resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n";
7124
			$resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n";
7125
		} else {
7126
	   		$selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
7127
			$resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n";
7128
			$resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n";
7129
		}
7130
		$resultyesno .= '</select>'."\n";
7131
		return $resultyesno;
7132
	}
7133
7134
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7135
	/**
7136
	 *  Return list of export templates
7137
	 *
7138
	 *  @param	string	$selected          Id modele pre-selectionne
7139
	 *  @param  string	$htmlname          Name of HTML select
7140
	 *  @param  string	$type              Type of searched templates
7141
	 *  @param  int		$useempty          Affiche valeur vide dans liste
7142
	 *  @return	void
7143
	 */
7144
	public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
7145
	{
7146
		// phpcs:enable
7147
		$sql = "SELECT rowid, label";
7148
		$sql .= " FROM ".MAIN_DB_PREFIX."export_model";
7149
		$sql .= " WHERE type = '".$this->db->escape($type)."'";
7150
		$sql .= " ORDER BY rowid";
7151
		$result = $this->db->query($sql);
7152
		if ($result)
7153
		{
7154
			print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">';
7155
			if ($useempty)
7156
			{
7157
				print '<option value="-1">&nbsp;</option>';
7158
			}
7159
7160
			$num = $this->db->num_rows($result);
7161
			$i = 0;
7162
			while ($i < $num)
7163
			{
7164
				$obj = $this->db->fetch_object($result);
7165
				if ($selected == $obj->rowid)
7166
				{
7167
					print '<option value="'.$obj->rowid.'" selected>';
7168
				} else {
7169
					print '<option value="'.$obj->rowid.'">';
7170
				}
7171
				print $obj->label;
7172
				print '</option>';
7173
				$i++;
7174
			}
7175
			print "</select>";
7176
		} else {
7177
			dol_print_error($this->db);
7178
		}
7179
	}
7180
7181
	/**
7182
	 *    Return a HTML area with the reference of object and a navigation bar for a business object
7183
	 *    Note: To complete search with a particular filter on select, you can set $object->next_prev_filter set to define SQL criterias.
7184
	 *
7185
	 *    @param	object	$object			Object to show.
7186
	 *    @param	string	$paramid   		Name of parameter to use to name the id into the URL next/previous link.
7187
	 *    @param	string	$morehtml  		More html content to output just before the nav bar.
7188
	 *    @param	int		$shownav	  	Show Condition (navigation is shown if value is 1).
7189
	 *    @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.
7190
	 *    @param	string	$fieldref   	Name of field ref of object (object->ref) to show or 'none' to not show ref.
7191
	 *    @param	string	$morehtmlref  	More html to show after ref.
7192
	 *    @param	string	$moreparam  	More param to add in nav link url. Must start with '&...'.
7193
	 *	  @param	int		$nodbprefix		Do not include DB prefix to forge table name.
7194
	 *	  @param	string	$morehtmlleft	More html code to show before ref.
7195
	 *	  @param	string	$morehtmlstatus	More html code to show under navigation arrows (status place).
7196
	 *	  @param	string	$morehtmlright	More html code to show after ref.
7197
	 * 	  @return	string    				Portion HTML with ref + navigation buttons
7198
	 */
7199
	public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
7200
	{
7201
		global $langs, $conf, $hookmanager, $extralanguages;
7202
7203
		$ret = '';
7204
		if (empty($fieldid))  $fieldid = 'rowid';
7205
		if (empty($fieldref)) $fieldref = 'ref';
7206
7207
		// Add where from hooks
7208
		if (is_object($hookmanager))
7209
		{
7210
			$parameters = array();
7211
			$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
7212
			$object->next_prev_filter .= $hookmanager->resPrint;
7213
		}
7214
		$previous_ref = $next_ref = '';
7215
		if ($shownav)
7216
		{
7217
			//print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
7218
			$object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
7219
7220
			$navurl = $_SERVER["PHP_SELF"];
7221
			// Special case for project/task page
7222
			if ($paramid == 'project_ref')
7223
			{
7224
				if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl))     // TODO Remove this when nav with project_ref on task pages are ok
7225
				{
7226
					$navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
7227
					$paramid = 'ref';
7228
				}
7229
			}
7230
7231
			// accesskey is for Windows or Linux:  ALT + key for chrome, ALT + SHIFT + KEY for firefox
7232
			// accesskey is for Mac:               CTRL + key for all browsers
7233
			$stringforfirstkey = $langs->trans("KeyboardShortcut");
7234
			if ($conf->browser->name == 'chrome')
7235
			{
7236
				$stringforfirstkey .= ' ALT +';
7237
			} elseif ($conf->browser->name == 'firefox')
7238
			{
7239
				$stringforfirstkey .= ' ALT + SHIFT +';
7240
			} else {
7241
				$stringforfirstkey .= ' CTL +';
7242
			}
7243
7244
			$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>';
7245
			$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>';
7246
		}
7247
7248
		//print "xx".$previous_ref."x".$next_ref;
7249
		$ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
7250
7251
		// Right part of banner
7252
		if ($morehtmlright) $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>';
7253
7254
		if ($previous_ref || $next_ref || $morehtml)
7255
		{
7256
			$ret .= '<div class="pagination paginationref"><ul class="right">';
7257
		}
7258
		if ($morehtml)
7259
		{
7260
			$ret .= '<li class="noborder litext">'.$morehtml.'</li>';
7261
		}
7262
		if ($shownav && ($previous_ref || $next_ref))
7263
		{
7264
			$ret .= '<li class="pagination">'.$previous_ref.'</li>';
7265
			$ret .= '<li class="pagination">'.$next_ref.'</li>';
7266
		}
7267
		if ($previous_ref || $next_ref || $morehtml)
7268
		{
7269
			$ret .= '</ul></div>';
7270
		}
7271
7272
		$parameters = array();
7273
		$reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
7274
		if (empty($reshook)) $morehtmlstatus .= $hookmanager->resPrint;
7275
		else $morehtmlstatus = $hookmanager->resPrint;
7276
		if ($morehtmlstatus) $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>';
7277
7278
		$parameters = array();
7279
		$reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
7280
		if (empty($reshook)) $morehtmlref .= $hookmanager->resPrint;
7281
		elseif ($reshook > 0) $morehtmlref = $hookmanager->resPrint;
7282
7283
		// Left part of banner
7284
		if ($morehtmlleft)
7285
		{
7286
			if ($conf->browser->layout == 'phone') $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle
7287
			else $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>';
7288
		}
7289
7290
		//if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
7291
		$ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
7292
7293
		// For thirdparty, contact, user, member, the ref is the id, so we show something else
7294
		if ($object->element == 'societe')
7295
		{
7296
			$ret .= dol_htmlentities($object->name);
7297
7298
			// List of extra languages
7299
			$arrayoflangcode = array();
7300
			if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE;
7301
7302
			if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
7303
				if (!is_object($extralanguages)) {
7304
					include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php';
7305
					$extralanguages = new ExtraLanguages($this->db);
7306
				}
7307
				$extralanguages->fetch_name_extralanguages('societe');
7308
7309
				if (!empty($extralanguages->attributes['societe']['name']))
7310
				{
7311
					$object->fetchValuesForExtraLanguages();
7312
7313
					$htmltext = '';
7314
					// If there is extra languages
7315
					foreach ($arrayoflangcode as $extralangcode) {
7316
						$htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
7317
						if ($object->array_languages['name'][$extralangcode]) {
7318
							$htmltext .= $object->array_languages['name'][$extralangcode];
7319
						} else {
7320
							$htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>';
7321
						}
7322
					}
7323
					$ret .= '<!-- Show translations of name -->'."\n";
7324
					$ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
7325
				}
7326
			}
7327
		} elseif ($object->element == 'member')
7328
		{
7329
			$ret .= $object->ref.'<br>';
7330
			$fullname = $object->getFullName($langs);
7331
			if ($object->morphy == 'mor' && $object->societe) {
7332
				$ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).')' : '');
7333
			} else {
7334
				$ret .= dol_htmlentities($fullname).((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : '');
7335
			}
7336
		} elseif (in_array($object->element, array('contact', 'user', 'usergroup')))
7337
		{
7338
			$ret .= dol_htmlentities($object->getFullName($langs));
7339
		} elseif (in_array($object->element, array('action', 'agenda')))
7340
		{
7341
			$ret .= $object->ref.'<br>'.$object->label;
7342
		} elseif (in_array($object->element, array('adherent_type')))
7343
		{
7344
			$ret .= $object->label;
7345
		} elseif ($object->element == 'ecm_directories')
7346
		{
7347
			$ret .= '';
7348
		} elseif ($fieldref != 'none')
7349
		{
7350
			$ret .= dol_htmlentities($object->$fieldref);
7351
		}
7352
7353
		if ($morehtmlref)
7354
		{
7355
			// don't add a additional space, when "$morehtmlref" starts with a HTML div tag
7356
			if (substr($morehtmlref, 0, 4) != '<div')
7357
			{
7358
				$ret .= ' ';
7359
			}
7360
7361
			$ret .= $morehtmlref;
7362
		}
7363
7364
		$ret .= '</div>';
7365
7366
		$ret .= '</div><!-- End banner content -->';
7367
7368
		return $ret;
7369
	}
7370
7371
7372
	/**
7373
	 *    	Return HTML code to output a barcode
7374
	 *
7375
	 *     	@param	Object	$object		Object containing data to retrieve file name
7376
	 * 		@param	int		$width			Width of photo
7377
	 * 	  	@return string    				HTML code to output barcode
7378
	 */
7379
	public function showbarcode(&$object, $width = 100)
7380
	{
7381
		global $conf;
7382
7383
		//Check if barcode is filled in the card
7384
		if (empty($object->barcode)) return '';
7385
7386
		// Complete object if not complete
7387
		if (empty($object->barcode_type_code) || empty($object->barcode_type_coder))
7388
		{
7389
			$result = $object->fetch_barcode();
7390
			//Check if fetch_barcode() failed
7391
			if ($result < 1) return '<!-- ErrorFetchBarcode -->';
7392
		}
7393
7394
		// Barcode image
7395
		$url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code);
7396
		$out = '<!-- url barcode = '.$url.' -->';
7397
		$out .= '<img src="'.$url.'">';
7398
		return $out;
7399
	}
7400
7401
	/**
7402
	 *    	Return HTML code to output a photo
7403
	 *
7404
	 *    	@param	string		$modulepart			Key to define module concerned ('societe', 'userphoto', 'memberphoto')
7405
	 *     	@param  object		$object				Object containing data to retrieve file name
7406
	 * 		@param	int			$width				Width of photo
7407
	 * 		@param	int			$height				Height of photo (auto if 0)
7408
	 * 		@param	int			$caneditfield		Add edit fields
7409
	 * 		@param	string		$cssclass			CSS name to use on img for photo
7410
	 * 		@param	string		$imagesize		    'mini', 'small' or '' (original)
7411
	 *      @param  int         $addlinktofullsize  Add link to fullsize image
7412
	 *      @param  int         $cache              1=Accept to use image in cache
7413
	 *      @param	string		$forcecapture		Force parameter capture on HTML input file element to ask a smartphone to allow to open camera to take photo. Auto if empty.
7414
	 * 	  	@return string    						HTML code to output photo
7415
	 */
7416
	public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '')
7417
	{
7418
		global $conf, $langs;
7419
7420
		$entity = (!empty($object->entity) ? $object->entity : $conf->entity);
7421
		$id = (!empty($object->id) ? $object->id : $object->rowid);
7422
7423
		$ret = ''; $dir = ''; $file = ''; $originalfile = ''; $altfile = ''; $email = ''; $capture = '';
7424
		if ($modulepart == 'societe')
7425
		{
7426
			$dir = $conf->societe->multidir_output[$entity];
7427
			if (!empty($object->logo))
7428
			{
7429
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
7430
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.getImageFileNameForSize($object->logo, '_small');
7431
				else $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.$object->logo;
7432
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'/logos/'.$object->logo;
7433
			}
7434
			$email = $object->email;
7435
		} elseif ($modulepart == 'contact')
7436
		{
7437
			$dir = $conf->societe->multidir_output[$entity].'/contact';
7438
			if (!empty($object->photo))
7439
			{
7440
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.getImageFileNameForSize($object->photo, '_mini');
7441
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.getImageFileNameForSize($object->photo, '_small');
7442
				else $file = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.$object->photo;
7443
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'/photos/'.$object->photo;
7444
			}
7445
			$email = $object->email;
7446
			$capture = 'user';
7447
		} elseif ($modulepart == 'userphoto')
7448
		{
7449
			$dir = $conf->user->dir_output;
7450
			if (!empty($object->photo))
7451
			{
7452
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_mini');
7453
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_small');
7454
				else $file = get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
7455
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
7456
			}
7457
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7458
			$email = $object->email;
7459
			$capture = 'user';
7460
		} elseif ($modulepart == 'memberphoto')
7461
		{
7462
			$dir = $conf->adherent->dir_output;
7463
			if (!empty($object->photo))
7464
			{
7465
				if ((string) $imagesize == 'mini') $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini');
7466
				elseif ((string) $imagesize == 'small') $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small');
7467
				else $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
7468
				$originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo;
7469
			}
7470
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7471
			$email = $object->email;
7472
			$capture = 'user';
7473
		} else {
7474
			// Generic case to show photos
7475
			$dir = $conf->$modulepart->dir_output;
7476
			if (!empty($object->photo))
7477
			{
7478
				if ((string) $imagesize == 'mini') $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini');
7479
				elseif ((string) $imagesize == 'small') $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small');
7480
				else $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
7481
				$originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo;
7482
			}
7483
			if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile = $object->id.".jpg"; // For backward compatibility
7484
			$email = $object->email;
7485
		}
7486
7487
		if ($forcecapture) $capture = $forcecapture;
7488
7489
		if ($dir)
7490
		{
7491
			if ($file && file_exists($dir."/".$file))
7492
			{
7493
				if ($addlinktofullsize)
7494
				{
7495
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
7496
					if ($urladvanced) $ret .= '<a href="'.$urladvanced.'">';
7497
					else $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
7498
				}
7499
				$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.'">';
7500
				if ($addlinktofullsize) $ret .= '</a>';
7501
			} elseif ($altfile && file_exists($dir."/".$altfile))
7502
			{
7503
				if ($addlinktofullsize)
7504
				{
7505
					$urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity);
7506
					if ($urladvanced) $ret .= '<a href="'.$urladvanced.'">';
7507
					else $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">';
7508
				}
7509
				$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.'">';
7510
				if ($addlinktofullsize) $ret .= '</a>';
7511
			} else {
7512
				$nophoto = '/public/theme/common/nophoto.png';
7513
				if (in_array($modulepart, array('userphoto', 'contact', 'memberphoto')))	// For module that are "physical" users
7514
				{
7515
					if ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor') !== false) {
7516
						$nophoto = '/public/theme/common/company.png';
7517
					} else {
7518
						$nophoto = '/public/theme/common/user_anonymous.png';
7519
						if ($object->gender == 'man') $nophoto = '/public/theme/common/user_man.png';
7520
						if ($object->gender == 'woman') $nophoto = '/public/theme/common/user_woman.png';
7521
					}
7522
				}
7523
7524
				if (!empty($conf->gravatar->enabled) && $email)
7525
				{
7526
					/**
7527
					 * @see https://gravatar.com/site/implement/images/php/
7528
					 */
7529
					global $dolibarr_main_url_root;
7530
					$ret .= '<!-- Put link to gravatar -->';
7531
					//$defaultimg=urlencode(dol_buildpath($nophoto,3));
7532
					$defaultimg = 'mm';
7533
					$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
7534
				} else {
7535
					$ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">';
7536
				}
7537
			}
7538
7539
			if ($caneditfield)
7540
			{
7541
				if ($object->photo) $ret .= "<br>\n";
7542
				$ret .= '<table class="nobordernopadding centpercent">';
7543
				if ($object->photo) $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> '.$langs->trans("Delete").'<br><br></td></tr>';
7544
				$ret .= '<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'></td></tr>';
7545
				$ret .= '</table>';
7546
			}
7547
		} else dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart);
7548
7549
		return $ret;
7550
	}
7551
7552
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7553
	/**
7554
	 *	Return select list of groups
7555
	 *
7556
	 *  @param	string	$selected       Id group preselected
7557
	 *  @param  string	$htmlname       Field name in form
7558
	 *  @param  int		$show_empty     0=liste sans valeur nulle, 1=ajoute valeur inconnue
7559
	 *  @param  string	$exclude        Array list of groups id to exclude
7560
	 * 	@param	int		$disabled		If select list must be disabled
7561
	 *  @param  string	$include        Array list of groups id to include
7562
	 * 	@param	int		$enableonly		Array list of groups id to be enabled. All other must be disabled
7563
	 * 	@param	string	$force_entity	'0' or Ids of environment to force
7564
	 * 	@param	bool	$multiple		add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
7565
	 *  @param  string	$morecss		More css to add to html component
7566
	 *  @return	string
7567
	 *  @see select_dolusers()
7568
	 */
7569
	public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '')
7570
	{
7571
		// phpcs:enable
7572
		global $conf, $user, $langs;
7573
7574
		// Permettre l'exclusion de groupes
7575
		if (is_array($exclude))	$excludeGroups = implode("','", $exclude);
0 ignored issues
show
introduced by
The condition is_array($exclude) is always false.
Loading history...
7576
		// Permettre l'inclusion de groupes
7577
		if (is_array($include))	$includeGroups = implode("','", $include);
0 ignored issues
show
introduced by
The condition is_array($include) is always false.
Loading history...
7578
7579
		if (!is_array($selected)) $selected = array($selected);
0 ignored issues
show
introduced by
The condition is_array($selected) is always false.
Loading history...
7580
7581
		$out = '';
7582
7583
		// On recherche les groupes
7584
		$sql = "SELECT ug.rowid, ug.nom as name";
7585
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
7586
		{
7587
			$sql .= ", e.label";
7588
		}
7589
		$sql .= " FROM ".MAIN_DB_PREFIX."usergroup as ug ";
7590
		if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
7591
		{
7592
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=ug.entity";
7593
			if ($force_entity) $sql .= " WHERE ug.entity IN (0, ".$force_entity.")";
7594
			else $sql .= " WHERE ug.entity IS NOT NULL";
7595
		} else {
7596
			$sql .= " WHERE ug.entity IN (0, ".$conf->entity.")";
7597
		}
7598
		if (is_array($exclude) && $excludeGroups) $sql .= " AND ug.rowid NOT IN ('".$excludeGroups."')";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $excludeGroups does not seem to be defined for all execution paths leading up to this point.
Loading history...
introduced by
The condition is_array($exclude) is always false.
Loading history...
7599
		if (is_array($include) && $includeGroups) $sql .= " AND ug.rowid IN ('".$includeGroups."')";
0 ignored issues
show
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...
introduced by
The condition is_array($include) is always false.
Loading history...
7600
		$sql .= " ORDER BY ug.nom ASC";
7601
7602
		dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG);
7603
		$resql = $this->db->query($sql);
7604
		if ($resql)
7605
		{
7606
			// Enhance with select2
7607
			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7608
		   	$out .= ajax_combobox($htmlname);
7609
7610
			$out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>';
7611
7612
			$num = $this->db->num_rows($resql);
7613
			$i = 0;
7614
			if ($num)
7615
			{
7616
				if ($show_empty && !$multiple) $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'>&nbsp;</option>'."\n";
7617
7618
				while ($i < $num)
7619
				{
7620
					$obj = $this->db->fetch_object($resql);
7621
					$disableline = 0;
7622
					if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) $disableline = 1;
7623
7624
					$out .= '<option value="'.$obj->rowid.'"';
7625
					if ($disableline) $out .= ' disabled';
7626
					if ((is_object($selected[0]) && $selected[0]->id == $obj->rowid) || (!is_object($selected[0]) && in_array($obj->rowid, $selected)))
7627
					{
7628
						$out .= ' selected';
7629
					}
7630
					$out .= '>';
7631
7632
					$out .= $obj->name;
7633
					if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1)
7634
					{
7635
						$out .= " (".$obj->label.")";
7636
					}
7637
7638
					$out .= '</option>';
7639
					$i++;
7640
				}
7641
			} else {
7642
				if ($show_empty) $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n";
7643
				$out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>';
7644
			}
7645
			$out .= '</select>';
7646
		} else {
7647
			dol_print_error($this->db);
7648
		}
7649
7650
		return $out;
7651
	}
7652
7653
7654
	/**
7655
	 *	Return HTML to show the search and clear seach button
7656
	 *
7657
	 *  @return	string
7658
	 */
7659
	public function showFilterButtons()
7660
	{
7661
		$out = '<div class="nowrap">';
7662
		$out .= '<button type="submit" class="liste_titre button_search" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
7663
		$out .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
7664
		$out .= '</div>';
7665
7666
		return $out;
7667
	}
7668
7669
	/**
7670
	 *	Return HTML to show the search and clear search button
7671
	 *
7672
	 *  @param  string  $cssclass                  CSS class
7673
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
7674
	 *  @param  string  $massactionname            Mass action button name that will launch an action on the selected items
7675
	 *  @return	string
7676
	 */
7677
	public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
7678
	{
7679
		global $conf, $langs;
7680
7681
		$out = '';
7682
7683
		if (!empty($conf->use_javascript_ajax)) $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>';
7684
		$out .= '<script>
7685
            $(document).ready(function() {
7686
                $("#' . $cssclass.'s").click(function() {
7687
                    if($(this).is(\':checked\')){
7688
                        console.log("We check all '.$cssclass.'");
7689
                		$(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\');
7690
                    }
7691
                    else
7692
                    {
7693
                        console.log("We uncheck all");
7694
                		$(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\');
7695
                    }'."\n";
7696
				if ($calljsfunction) $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
7697
		$out .= '         });
7698
        	        $(".' . $cssclass.'").change(function() {
7699
					$(this).closest("tr").toggleClass("highlight", this.checked);
7700
				});
7701
		 	});
7702
    	</script>';
7703
7704
		return $out;
7705
	}
7706
7707
	/**
7708
	 *	Return HTML to show the search and clear seach button
7709
	 *
7710
	 *  @param	int  	$addcheckuncheckall        Add the check all/uncheck all checkbox (use javascript) and code to manage this
7711
	 *  @param  string  $cssclass                  CSS class
7712
	 *  @param  int     $calljsfunction            0=default. 1=call function initCheckForSelect() after changing status of checkboxes
7713
	 *  @param  string  $massactionname            Mass action name
7714
	 *  @return	string
7715
	 */
7716
	public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
7717
	{
7718
		$out = $this->showFilterButtons();
7719
		if ($addcheckuncheckall)
7720
		{
7721
			$out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
7722
		}
7723
		return $out;
7724
	}
7725
7726
	/**
7727
	 * Return HTML to show the select of expense categories
7728
	 *
7729
	 * @param	string	$selected              preselected category
7730
	 * @param	string	$htmlname              name of HTML select list
7731
	 * @param	integer	$useempty              1=Add empty line
7732
	 * @param	array	$excludeid             id to exclude
7733
	 * @param	string	$target                htmlname of target select to bind event
7734
	 * @param	int		$default_selected      default category to select if fk_c_type_fees change = EX_KME
7735
	 * @param	array	$params                param to give
7736
	 * @param	int		$info_admin			   Show the tooltip help picto to setup list
7737
	 * @return	string
7738
	 */
7739
	public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
7740
	{
7741
		global $db, $langs, $user;
7742
7743
		$out = '';
7744
		$sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1';
7745
		$sql .= ' AND entity IN (0,'.getEntity('exp_tax_cat').')';
7746
		if (!empty($excludeid)) $sql .= ' AND rowid NOT IN ('.implode(',', $excludeid).')';
7747
		$sql .= ' ORDER BY label';
7748
7749
		$resql = $db->query($sql);
7750
		if ($resql)
7751
		{
7752
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">';
7753
			if ($useempty) $out .= '<option value="0">&nbsp;</option>';
7754
7755
			while ($obj = $db->fetch_object($resql))
7756
			{
7757
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>';
7758
			}
7759
			$out .= '</select>';
7760
			$out .= ajax_combobox('select_'.$htmlname);
7761
7762
			if (!empty($htmlname) && $user->admin && $info_admin) $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
7763
7764
			if (!empty($target))
7765
			{
7766
				$sql = "SELECT c.id FROM ".MAIN_DB_PREFIX."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
7767
				$resql = $db->query($sql);
7768
				if ($resql)
7769
				{
7770
					if ($db->num_rows($resql) > 0)
7771
					{
7772
						$obj = $db->fetch_object($resql);
7773
						$out .= '<script>
7774
							$(function() {
7775
								$("select[name='.$target.']").on("change", function() {
7776
									var current_val = $(this).val();
7777
									if (current_val == '.$obj->id.') {';
7778
						if (!empty($default_selected) || !empty($selected)) $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");';
7779
7780
						$out .= '
7781
										$("select[name='.$htmlname.']").change();
7782
									}
7783
								});
7784
7785
								$("select[name='.$htmlname.']").change(function() {
7786
7787
									if ($("select[name='.$target.']").val() == '.$obj->id.') {
7788
										// get price of kilometer to fill the unit price
7789
										var data = '.json_encode($params).';
7790
										data.fk_c_exp_tax_cat = $(this).val();
7791
7792
										$.ajax({
7793
											method: "POST",
7794
											dataType: "json",
7795
											data: data,
7796
											url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php').'",
7797
										}).done(function( data, textStatus, jqXHR ) {
7798
											console.log(data);
7799
											if (typeof data.up != "undefined") {
7800
												$("input[name=value_unit]").val(data.up);
7801
												$("select[name='.$htmlname.']").attr("title", data.title);
7802
											} else {
7803
												$("input[name=value_unit]").val("");
7804
												$("select[name='.$htmlname.']").attr("title", "");
7805
											}
7806
										});
7807
									}
7808
								});
7809
							});
7810
						</script>';
7811
					}
7812
				}
7813
			}
7814
		} else {
7815
			dol_print_error($db);
7816
		}
7817
7818
		return $out;
7819
	}
7820
7821
	/**
7822
	 * Return HTML to show the select ranges of expense range
7823
	 *
7824
	 * @param	string	$selected    preselected category
7825
	 * @param	string	$htmlname    name of HTML select list
7826
	 * @param	integer	$useempty    1=Add empty line
7827
	 * @return	string
7828
	 */
7829
	public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
7830
	{
7831
		global $db, $conf, $langs;
7832
7833
		$out = '';
7834
		$sql = 'SELECT rowid, range_ik FROM '.MAIN_DB_PREFIX.'c_exp_tax_range';
7835
		$sql .= ' WHERE entity = '.$conf->entity.' AND active = 1';
7836
7837
		$resql = $db->query($sql);
7838
		if ($resql)
7839
		{
7840
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7841
			if ($useempty) $out .= '<option value="0"></option>';
7842
7843
			while ($obj = $db->fetch_object($resql))
7844
			{
7845
				$out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>';
7846
			}
7847
			$out .= '</select>';
7848
		} else {
7849
			dol_print_error($db);
7850
		}
7851
7852
		return $out;
7853
	}
7854
7855
	/**
7856
	 * Return HTML to show a select of expense
7857
	 *
7858
	 * @param	string	$selected    preselected category
7859
	 * @param	string	$htmlname    name of HTML select list
7860
	 * @param	integer	$useempty    1=Add empty choice
7861
	 * @param	integer	$allchoice   1=Add all choice
7862
	 * @param	integer	$useid       0=use 'code' as key, 1=use 'id' as key
7863
	 * @return	string
7864
	 */
7865
	public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
7866
	{
7867
		global $db, $langs;
7868
7869
		$out = '';
7870
		$sql = 'SELECT id, code, label FROM '.MAIN_DB_PREFIX.'c_type_fees';
7871
		$sql .= ' WHERE active = 1';
7872
7873
		$resql = $db->query($sql);
7874
		if ($resql)
7875
		{
7876
			$out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">';
7877
			if ($useempty) $out .= '<option value="0"></option>';
7878
			if ($allchoice) $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>';
7879
7880
			$field = 'code';
7881
			if ($useid) $field = 'id';
7882
7883
			while ($obj = $db->fetch_object($resql))
7884
			{
7885
				$key = $langs->trans($obj->code);
7886
				$out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>';
7887
			}
7888
			$out .= '</select>';
7889
		} else {
7890
			dol_print_error($db);
7891
		}
7892
7893
		return $out;
7894
	}
7895
7896
	/**
7897
	 *  Output a combo list with invoices qualified for a third party
7898
	 *
7899
	 *  @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)
7900
	 *  @param  int		$selected   	Id invoice preselected
7901
	 *  @param  string	$htmlname   	Name of HTML select
7902
	 *	@param	int		$maxlength		Maximum length of label
7903
	 *	@param	int		$option_only	Return only html options lines without the select tag
7904
	 *	@param	string	$show_empty		Add an empty line ('1' or string to show for empty line)
7905
	 *  @param	int		$discard_closed Discard closed projects (0=Keep,1=hide completely,2=Disable)
7906
	 *  @param	int		$forcefocus		Force focus on field (works with javascript only)
7907
	 *  @param	int		$disabled		Disabled
7908
	 *  @param	string	$morecss        More css added to the select component
7909
	 *  @param	string	$projectsListId ''=Automatic filter on project allowed. List of id=Filter on project ids.
7910
	 *  @param	string	$showproject	'all' = Show project info, ''=Hide project info
7911
	 *  @param	User	$usertofilter	User object to use for filtering
7912
	 *	@return int         			Nbr of project if OK, <0 if KO
7913
	 */
7914
	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)
7915
	{
7916
		global $user, $conf, $langs;
7917
7918
		require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
7919
7920
		if (is_null($usertofilter))
7921
		{
7922
			$usertofilter = $user;
7923
		}
7924
7925
		$out = '';
7926
7927
		$hideunselectables = false;
7928
		if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) $hideunselectables = true;
7929
7930
		if (empty($projectsListId))
7931
		{
7932
			if (empty($usertofilter->rights->projet->all->lire))
7933
			{
7934
				$projectstatic = new Project($this->db);
7935
				$projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
7936
			}
7937
		}
7938
7939
		// Search all projects
7940
		$sql = 'SELECT f.rowid, f.ref as fref, "nolabel" as flabel, p.rowid as pid, f.ref,
7941
            p.title, p.fk_soc, p.fk_statut, p.public,';
7942
		$sql .= ' s.nom as name';
7943
		$sql .= ' FROM '.MAIN_DB_PREFIX.'projet as p';
7944
		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = p.fk_soc,';
7945
		$sql .= ' '.MAIN_DB_PREFIX.'facture as f';
7946
		$sql .= " WHERE p.entity IN (".getEntity('project').")";
7947
		$sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
7948
		//if ($projectsListId) $sql.= " AND p.rowid IN (".$projectsListId.")";
7949
		//if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
7950
		//if ($socid > 0)  $sql.= " AND (p.fk_soc=".$socid." OR p.fk_soc IS NULL)";
7951
		$sql .= " GROUP BY f.ref ORDER BY p.ref, f.ref ASC";
7952
7953
		$resql = $this->db->query($sql);
7954
		if ($resql)
7955
		{
7956
			// Use select2 selector
7957
			if (!empty($conf->use_javascript_ajax))
7958
			{
7959
				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
7960
			   	$comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus);
7961
				$out .= $comboenhancement;
7962
				$morecss = 'minwidth200imp maxwidth500';
7963
			}
7964
7965
			if (empty($option_only)) {
7966
				$out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">';
7967
			}
7968
			if (!empty($show_empty)) {
7969
				$out .= '<option value="0" class="optiongrey">';
7970
				if (!is_numeric($show_empty)) $out .= $show_empty;
7971
				else $out .= '&nbsp;';
7972
				$out .= '</option>';
7973
			}
7974
			$num = $this->db->num_rows($resql);
7975
			$i = 0;
7976
			if ($num)
7977
			{
7978
				while ($i < $num)
7979
				{
7980
					$obj = $this->db->fetch_object($resql);
7981
					// 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.
7982
					if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire))
7983
					{
7984
						// Do nothing
7985
					} else {
7986
						if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED)
7987
						{
7988
							$i++;
7989
							continue;
7990
						}
7991
7992
						$labeltoshow = '';
7993
7994
						if ($showproject == 'all')
7995
						{
7996
							$labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
7997
							if ($obj->name) $labeltoshow .= ' - '.$obj->name; // Soc name
7998
7999
							$disabled = 0;
8000
							if ($obj->fk_statut == Project::STATUS_DRAFT)
8001
							{
8002
								$disabled = 1;
8003
								$labeltoshow .= ' - '.$langs->trans("Draft");
8004
							} elseif ($obj->fk_statut == Project::STATUS_CLOSED)
8005
							{
8006
								if ($discard_closed == 2) $disabled = 1;
8007
								$labeltoshow .= ' - '.$langs->trans("Closed");
8008
							} elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid))
8009
							{
8010
								$disabled = 1;
8011
								$labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany");
8012
							}
8013
						}
8014
8015
						if (!empty($selected) && $selected == $obj->rowid)
8016
						{
8017
							$out .= '<option value="'.$obj->rowid.'" selected';
8018
							//if ($disabled) $out.=' disabled';						// with select2, field can't be preselected if disabled
8019
							$out .= '>'.$labeltoshow.'</option>';
8020
						} else {
8021
							if ($hideunselectables && $disabled && ($selected != $obj->rowid))
8022
							{
8023
								$resultat = '';
8024
							} else {
8025
								$resultat = '<option value="'.$obj->rowid.'"';
8026
								if ($disabled) $resultat .= ' disabled';
8027
								//if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
8028
								//else $labeltoshow.=' ('.$langs->trans("Private").')';
8029
								$resultat .= '>';
8030
								$resultat .= $labeltoshow;
8031
								$resultat .= '</option>';
8032
							}
8033
							$out .= $resultat;
8034
						}
8035
					}
8036
					$i++;
8037
				}
8038
			}
8039
			if (empty($option_only)) {
8040
				$out .= '</select>';
8041
			}
8042
8043
			print $out;
8044
8045
			$this->db->free($resql);
8046
			return $num;
8047
		} else {
8048
			dol_print_error($this->db);
8049
			return -1;
8050
		}
8051
	}
8052
8053
	/**
8054
	 * Output the component to make advanced search criteries
8055
	 *
8056
	 * @param	array		$arrayofcriterias			          Array of available search criterias. Example: array($object->element => $object->fields, 'otherfamily' => otherarrayoffields, ...)
8057
	 * @param	array		$search_component_params	          Array of selected search criterias
8058
	 * @param   array       $arrayofinputfieldsalreadyoutput      Array of input fields already inform. The component will not generate a hidden input field if it is in this list.
8059
	 * @return	string									          HTML component for advanced search
8060
	 */
8061
	public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array())
8062
	{
8063
		global $langs;
8064
8065
		$ret = '';
8066
8067
		$ret .= '<div class="nowrap centpercent">';
8068
		//$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>';
8069
		$ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor paddingright">';
8070
		$ret .= '<span class="fas fa-filter linkobject boxfilter" title="Filter" id="idsubimgproductdistribution"></span>';
8071
		$ret .= $langs->trans("Filters");
8072
		$ret .= '</a>';
8073
		//$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
8074
		$ret .= '<div name="search_component_params" class="search_component_params inline-block minwidth500 maxwidth300onsmartphone valignmiddle">';
8075
		$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
8076
8077
		$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
8078
		$ret .= '</div>';
8079
		$ret .= '<input type="hidden" name="search_component_params_hidden" class="search_component_params_hidden" value="'.GETPOST("search_component_params_hidden").'">';
8080
		// For compatibility with forms that show themself the search criteria in addition of this component, we output the fields
8081
		foreach ($arrayofcriterias as $criterias) {
8082
			foreach ($criterias as $criteriafamilykey => $criteriafamilyval) {
8083
				if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) continue;
8084
				if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) continue;
8085
				if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
8086
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">';
8087
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">';
8088
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">';
8089
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">';
8090
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">';
8091
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">';
8092
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">';
8093
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">';
8094
				} else {
8095
					$ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">';
8096
				}
8097
			}
8098
		}
8099
		$ret .= '</div>';
8100
8101
8102
		return $ret;
8103
	}
8104
8105
	/**
8106
	 * selectModelMail
8107
	 *
8108
	 * @param   string   $prefix     Prefix
8109
	 * @param   string   $modelType  Model type
8110
	 * @param	int		 $default	 1=Show also Default mail template
8111
	 * @return  string               HTML select string
8112
	 */
8113
	public function selectModelMail($prefix, $modelType = '', $default = 0)
8114
	{
8115
		global $langs, $db, $user;
8116
8117
		$retstring = '';
8118
8119
		$TModels = array();
8120
8121
		include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
8122
		$formmail = new FormMail($db);
8123
		$result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
8124
8125
		if ($default) $TModels[0] = $langs->trans('DefaultMailModel');
8126
		if ($result > 0) {
8127
			foreach ($formmail->lines_model as $model) {
8128
				$TModels[$model->id] = $model->label;
8129
			}
8130
		}
8131
8132
		$retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">';
8133
8134
		foreach ($TModels as $id_model=>$label_model) {
8135
			$retstring .= '<option value="'.$id_model.'"';
8136
			$retstring .= ">".$label_model."</option>";
8137
		}
8138
8139
		$retstring .= "</select>";
8140
8141
		return $retstring;
8142
	}
8143
}
8144