Passed
Branch develop (73c118)
by
unknown
25:42
created

Form::showrefnav()   D

Complexity

Conditions 54

Size

Total Lines 170
Code Lines 93

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 54
eloc 93
nop 12
dl 0
loc 170
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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

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

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

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

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