1<?php
2/* Copyright (C) 2008-2012	Laurent Destailleur	<eldy@users.sourceforge.net>
3 * Copyright (C) 2008-2012	Regis Houssin		<regis.houssin@inodbox.com>
4 * Copyright (C) 2014		Juanjo Menent		<jmenent@2byte.es>
5 * Copyright (C) 2017		Rui Strecht			<rui.strecht@aliartalentos.com>
6 * Copyright (C) 2020       Open-Dsi         	<support@open-dsi.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22/**
23 *	\file       htdocs/core/class/html.formcompany.class.php
24 *  \ingroup    core
25 *	\brief      File of class to build HTML component for third parties management
26 */
27
28
29/**
30 *	Class to build HTML component for third parties management
31 *	Only common components are here.
32 */
33
34require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
35
36
37/**
38 * Class of forms component to manage companies
39 */
40class FormCompany extends Form
41{
42
43	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
44	/**
45	 *    	Return list of labels (translated) of third parties type
46	 *
47	 *		@param	int		$mode		0=Return id+label, 1=Return code+label
48	 *      @param  string	$filter     Add a SQL filter to select
49	 *    	@return array      			Array of types
50	 */
51	public function typent_array($mode = 0, $filter = '')
52	{
53		// phpcs:enable
54		global $langs, $mysoc;
55
56		$effs = array();
57
58		$sql = "SELECT id, code, libelle";
59		$sql .= " FROM ".MAIN_DB_PREFIX."c_typent";
60		$sql .= " WHERE active = 1 AND (fk_country IS NULL OR fk_country = ".(empty($mysoc->country_id) ? '0' : $mysoc->country_id).")";
61		if ($filter) $sql .= " ".$filter;
62		$sql .= " ORDER by position, id";
63		dol_syslog(get_class($this).'::typent_array', LOG_DEBUG);
64		$resql = $this->db->query($sql);
65		if ($resql)
66		{
67			$num = $this->db->num_rows($resql);
68			$i = 0;
69
70			while ($i < $num)
71			{
72				$objp = $this->db->fetch_object($resql);
73				if (!$mode) $key = $objp->id;
74				else $key = $objp->code;
75				if ($langs->trans($objp->code) != $objp->code) $effs[$key] = $langs->trans($objp->code);
76				else $effs[$key] = $objp->libelle;
77				if ($effs[$key] == '-') $effs[$key] = '';
78				$i++;
79			}
80			$this->db->free($resql);
81		}
82
83		return $effs;
84	}
85
86	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
87	/**
88	 *	Renvoie la liste des types d'effectifs possibles (pas de traduction car nombre)
89	 *
90	 *	@param	int		$mode		0=renvoi id+libelle, 1=renvoi code+libelle
91	 *	@param  string	$filter     Add a SQL filter to select
92	 *  @return array				Array of types d'effectifs
93	 */
94	public function effectif_array($mode = 0, $filter = '')
95	{
96		// phpcs:enable
97		$effs = array();
98
99		$sql = "SELECT id, code, libelle";
100		$sql .= " FROM ".MAIN_DB_PREFIX."c_effectif";
101		$sql .= " WHERE active = 1";
102		if ($filter) $sql .= " ".$filter;
103		$sql .= " ORDER BY id ASC";
104		dol_syslog(get_class($this).'::effectif_array', LOG_DEBUG);
105		$resql = $this->db->query($sql);
106		if ($resql)
107		{
108			$num = $this->db->num_rows($resql);
109			$i = 0;
110
111			while ($i < $num)
112			{
113				$objp = $this->db->fetch_object($resql);
114				if (!$mode) $key = $objp->id;
115				else $key = $objp->code;
116
117				$effs[$key] = $objp->libelle != '-' ? $objp->libelle : '';
118				$i++;
119			}
120			$this->db->free($resql);
121		}
122		return $effs;
123	}
124
125
126	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
127	/**
128	 *  Affiche formulaire de selection des modes de reglement
129	 *
130	 *  @param	int		$page        	Page
131	 *  @param  int		$selected    	Id or code preselected
132	 *  @param  string	$htmlname   	Nom du formulaire select
133	 *	@param	int		$empty			Add empty value in list
134	 *	@return	void
135	 */
136	public function form_prospect_level($page, $selected = '', $htmlname = 'prospect_level_id', $empty = 0)
137	{
138		// phpcs:enable
139		global $user, $langs;
140
141		print '<form method="post" action="'.$page.'">';
142		print '<input type="hidden" name="action" value="setprospectlevel">';
143		print '<input type="hidden" name="token" value="'.newToken().'">';
144
145		dol_syslog(get_class($this).'::form_prospect_level', LOG_DEBUG);
146		$sql = "SELECT code, label";
147		$sql .= " FROM ".MAIN_DB_PREFIX."c_prospectlevel";
148		$sql .= " WHERE active > 0";
149		$sql .= " ORDER BY sortorder";
150		$resql = $this->db->query($sql);
151		if ($resql)
152		{
153			$options = array();
154
155			if ($empty) {
156				$options[''] = '';
157			}
158
159			while ($obj = $this->db->fetch_object($resql)) {
160				$level = $langs->trans($obj->code);
161
162				if ($level == $obj->code) {
163					$level = $langs->trans($obj->label);
164				}
165
166				$options[$obj->code] = $level;
167			}
168
169			print Form::selectarray($htmlname, $options, $selected);
170		} else dol_print_error($this->db);
171		if (!empty($htmlname) && $user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
172		print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
173		print '</form>';
174	}
175
176	/**
177	 *  Affiche formulaire de selection des niveau de prospection pour les contacts
178	 *
179	 *  @param	int		$page        	Page
180	 *  @param  int		$selected    	Id or code preselected
181	 *  @param  string	$htmlname   	Nom du formulaire select
182	 *	@param	int		$empty			Add empty value in list
183	 *	@return	void
184	 */
185	public function formProspectContactLevel($page, $selected = '', $htmlname = 'prospect_contact_level_id', $empty = 0)
186	{
187		global $user, $langs;
188
189		print '<form method="post" action="'.$page.'">';
190		print '<input type="hidden" name="action" value="setprospectcontactlevel">';
191		print '<input type="hidden" name="token" value="'.newToken().'">';
192
193		dol_syslog(__METHOD__, LOG_DEBUG);
194		$sql = "SELECT code, label";
195		$sql .= " FROM ".MAIN_DB_PREFIX."c_prospectcontactlevel";
196		$sql .= " WHERE active > 0";
197		$sql .= " ORDER BY sortorder";
198		$resql = $this->db->query($sql);
199		if ($resql)
200		{
201			$options = array();
202
203			if ($empty)
204			{
205				$options[''] = '';
206			}
207
208			while ($obj = $this->db->fetch_object($resql))
209			{
210				$level = $langs->trans($obj->code);
211
212				if ($level == $obj->code)
213				{
214					$level = $langs->trans($obj->label);
215				}
216
217				$options[$obj->code] = $level;
218			}
219
220			print Form::selectarray($htmlname, $options, $selected);
221		}
222		else dol_print_error($this->db);
223		if (!empty($htmlname) && $user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
224		print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
225		print '</form>';
226	}
227
228	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
229	/**
230	 *   Returns the drop-down list of departments/provinces/cantons for all countries or for a given country.
231	 *   In the case of an all-country list, the display breaks on the country.
232	 *   The key of the list is the code (there can be several entries for a given code but in this case, the country field differs).
233	 *   Thus the links with the departments are done on a department independently of its name.
234	 *
235	 *   @param     string	$selected        	Code state preselected
236	 *   @param     int		$country_codeid     0=list for all countries, otherwise country code or country rowid to show
237	 *   @param     string	$htmlname			Id of department
238	 *   @return	void
239	 */
240	public function select_departement($selected = '', $country_codeid = 0, $htmlname = 'state_id')
241	{
242		// phpcs:enable
243		print $this->select_state($selected, $country_codeid, $htmlname);
244	}
245
246	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
247	/**
248	 *   Returns the drop-down list of departments/provinces/cantons for all countries or for a given country.
249	 *   In the case of an all-country list, the display breaks on the country.
250	 *   The key of the list is the code (there can be several entries for a given code but in this case, the country field differs).
251	 *   Thus the links with the departments are done on a department independently of its name.
252	 *
253	 *    @param	int		$selected        	Code state preselected (mus be state id)
254	 *    @param    integer	$country_codeid    	Country code or id: 0=list for all countries, otherwise country code or country rowid to show
255	 *    @param    string	$htmlname			Id of department. If '', we want only the string with <option>
256	 * 	  @return	string						String with HTML select
257	 *    @see select_country()
258	 */
259	public function select_state($selected = 0, $country_codeid = 0, $htmlname = 'state_id')
260	{
261		// phpcs:enable
262		global $conf, $langs, $user;
263
264		dol_syslog(get_class($this)."::select_departement selected=".$selected.", country_codeid=".$country_codeid, LOG_DEBUG);
265
266		$langs->load("dict");
267
268		$out = '';
269
270		// Serch departements/cantons/province active d'une region et pays actif
271		$sql = "SELECT d.rowid, d.code_departement as code, d.nom as name, d.active, c.label as country, c.code as country_code, r.nom as region_name FROM";
272		$sql .= " ".MAIN_DB_PREFIX."c_departements as d, ".MAIN_DB_PREFIX."c_regions as r,".MAIN_DB_PREFIX."c_country as c";
273		$sql .= " WHERE d.fk_region=r.code_region and r.fk_pays=c.rowid";
274		$sql .= " AND d.active = 1 AND r.active = 1 AND c.active = 1";
275		if ($country_codeid && is_numeric($country_codeid))   $sql .= " AND c.rowid = '".$this->db->escape($country_codeid)."'";
276		if ($country_codeid && !is_numeric($country_codeid)) $sql .= " AND c.code = '".$this->db->escape($country_codeid)."'";
277		$sql .= " ORDER BY c.code, d.code_departement";
278
279		$result = $this->db->query($sql);
280		if ($result)
281		{
282			if (!empty($htmlname)) $out .= '<select id="'.$htmlname.'" class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'">';
283			if ($country_codeid) $out .= '<option value="0">&nbsp;</option>';
284			$num = $this->db->num_rows($result);
285			$i = 0;
286			dol_syslog(get_class($this)."::select_departement num=".$num, LOG_DEBUG);
287			if ($num)
288			{
289				$country = '';
290				while ($i < $num)
291				{
292					$obj = $this->db->fetch_object($result);
293					if ($obj->code == '0')		// Le code peut etre une chaine
294					{
295						$out .= '<option value="0">&nbsp;</option>';
296					} else {
297						if (!$country || $country != $obj->country)
298						{
299							// Affiche la rupture si on est en mode liste multipays
300							if (!$country_codeid && $obj->country_code)
301							{
302								$out .= '<option value="-1" disabled>----- '.$obj->country." -----</option>\n";
303								$country = $obj->country;
304							}
305						}
306
307						if (!empty($selected) && $selected == $obj->rowid)
308						{
309							$out .= '<option value="'.$obj->rowid.'" selected>';
310						} else {
311							$out .= '<option value="'.$obj->rowid.'">';
312						}
313
314						// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
315						if (!empty($conf->global->MAIN_SHOW_STATE_CODE) &&
316						($conf->global->MAIN_SHOW_STATE_CODE == 1 || $conf->global->MAIN_SHOW_STATE_CODE == 2 || $conf->global->MAIN_SHOW_STATE_CODE === 'all')) {
317							if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1) {
318								$out .= $obj->region_name.' - '.$obj->code.' - '.($langs->trans($obj->code) != $obj->code ? $langs->trans($obj->code) : ($obj->name != '-' ? $obj->name : ''));
319							} else {
320								$out .= $obj->code.' - '.($langs->trans($obj->code) != $obj->code ? $langs->trans($obj->code) : ($obj->name != '-' ? $obj->name : ''));
321							}
322						} else {
323							if (!empty($conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT) && $conf->global->MAIN_SHOW_REGION_IN_STATE_SELECT == 1) {
324								$out .= $obj->region_name.' - '.($langs->trans($obj->code) != $obj->code ? $langs->trans($obj->code) : ($obj->name != '-' ? $obj->name : ''));
325							} else {
326								$out .= ($langs->trans($obj->code) != $obj->code ? $langs->trans($obj->code) : ($obj->name != '-' ? $obj->name : ''));
327							}
328						}
329
330						$out .= '</option>';
331					}
332					$i++;
333				}
334			}
335			if (!empty($htmlname)) $out .= '</select>';
336			if (!empty($htmlname) && $user->admin) $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
337		} else {
338			dol_print_error($this->db);
339		}
340
341		// Make select dynamic
342		if (!empty($htmlname))
343		{
344			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
345			$out .= ajax_combobox($htmlname);
346		}
347
348		return $out;
349	}
350
351
352	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
353	/**
354	 *   Retourne la liste deroulante des regions actives dont le pays est actif
355	 *   La cle de la liste est le code (il peut y avoir plusieurs entree pour
356	 *   un code donnee mais dans ce cas, le champ pays et lang differe).
357	 *   Ainsi les liens avec les regions se font sur une region independemment de son name.
358	 *
359	 *   @param		string		$selected		Preselected value
360	 *   @param		string		$htmlname		Name of HTML select field
361	 *   @return	void
362	 */
363	public function select_region($selected = '', $htmlname = 'region_id')
364	{
365		// phpcs:enable
366		global $conf, $langs;
367		$langs->load("dict");
368
369		$sql = "SELECT r.rowid, r.code_region as code, r.nom as label, r.active, c.code as country_code, c.label as country";
370		$sql .= " FROM ".MAIN_DB_PREFIX."c_regions as r, ".MAIN_DB_PREFIX."c_country as c";
371		$sql .= " WHERE r.fk_pays=c.rowid AND r.active = 1 and c.active = 1";
372		$sql .= " ORDER BY c.code, c.label ASC";
373
374		dol_syslog(get_class($this)."::select_region", LOG_DEBUG);
375		$resql = $this->db->query($sql);
376		if ($resql)
377		{
378			print '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">';
379			$num = $this->db->num_rows($resql);
380			$i = 0;
381			if ($num)
382			{
383				$country = '';
384				while ($i < $num)
385				{
386					$obj = $this->db->fetch_object($resql);
387					if ($obj->code == 0) {
388						print '<option value="0">&nbsp;</option>';
389					} else {
390						if ($country == '' || $country != $obj->country)
391						{
392							// Show break
393							$key = $langs->trans("Country".strtoupper($obj->country_code));
394							$valuetoshow = ($key != "Country".strtoupper($obj->country_code)) ? $obj->country_code." - ".$key : $obj->country;
395							print '<option value="-1" disabled>----- '.$valuetoshow." -----</option>\n";
396							$country = $obj->country;
397						}
398
399						if ($selected > 0 && $selected == $obj->code)
400						{
401							print '<option value="'.$obj->code.'" selected>'.$obj->label.'</option>';
402						} else {
403							print '<option value="'.$obj->code.'">'.$obj->label.'</option>';
404						}
405					}
406					$i++;
407				}
408			}
409			print '</select>';
410			print ajax_combobox($htmlname);
411		} else {
412			dol_print_error($this->db);
413		}
414	}
415
416	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
417	/**
418	 *  Return combo list with people title
419	 *
420	 *  @param  string	$selected   	Civility/Title code preselected
421	 * 	@param	string	$htmlname		Name of HTML select combo field
422	 *  @param  string  $morecss        Add more css on SELECT element
423	 *  @param	int		$addjscombo		Add js combo
424	 *  @return	string					String with HTML select
425	 */
426	public function select_civility($selected = '', $htmlname = 'civility_id', $morecss = 'maxwidth150', $addjscombo = 0)
427	{
428		// phpcs:enable
429		global $conf, $langs, $user;
430		$langs->load("dict");
431
432		$out = '';
433
434		$sql = "SELECT rowid, code, label, active FROM ".MAIN_DB_PREFIX."c_civility";
435		$sql .= " WHERE active = 1";
436
437		dol_syslog("Form::select_civility", LOG_DEBUG);
438		$resql = $this->db->query($sql);
439		if ($resql)
440		{
441			$out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
442			$out .= '<option value="">&nbsp;</option>';
443			$num = $this->db->num_rows($resql);
444			$i = 0;
445			if ($num)
446			{
447				while ($i < $num)
448				{
449					$obj = $this->db->fetch_object($resql);
450					if ($selected == $obj->code)
451					{
452						$out .= '<option value="'.$obj->code.'" selected>';
453					} else {
454						$out .= '<option value="'.$obj->code.'">';
455					}
456					// If translation exists, we use it, otherwise, we use tha had coded label
457					$out .= ($langs->trans("Civility".$obj->code) != "Civility".$obj->code ? $langs->trans("Civility".$obj->code) : ($obj->label != '-' ? $obj->label : ''));
458					$out .= '</option>';
459					$i++;
460				}
461			}
462			$out .= '</select>';
463			if ($user->admin) $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
464
465			if ($addjscombo) {
466				// Enhance with select2
467				include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
468				$out .= ajax_combobox($htmlname);
469			}
470		} else {
471			dol_print_error($this->db);
472		}
473
474		return $out;
475	}
476
477	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
478	/**
479	 *    Retourne la liste deroulante des formes juridiques tous pays confondus ou pour un pays donne.
480	 *    Dans le cas d'une liste tous pays confondu, on affiche une rupture sur le pays.
481	 *
482	 *    @param	string		$selected        	Code forme juridique a pre-selectionne
483	 *    @param    mixed		$country_codeid		0=liste tous pays confondus, sinon code du pays a afficher
484	 *    @param    string		$filter          	Add a SQL filter on list
485	 *    @return	void
486	 *    @deprecated Use print xxx->select_juridicalstatus instead
487	 *    @see select_juridicalstatus()
488	 */
489	public function select_forme_juridique($selected = '', $country_codeid = 0, $filter = '')
490	{
491		// phpcs:enable
492		print $this->select_juridicalstatus($selected, $country_codeid, $filter);
493	}
494
495	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
496	/**
497	 *    Retourne la liste deroulante des formes juridiques tous pays confondus ou pour un pays donne.
498	 *    Dans le cas d'une liste tous pays confondu, on affiche une rupture sur le pays
499	 *
500	 *    @param	string		$selected        	Preselected code of juridical type
501	 *    @param    int			$country_codeid     0=list for all countries, otherwise list only country requested
502	 *    @param    string		$filter          	Add a SQL filter on list
503	 *    @param	string		$htmlname			HTML name of select
504	 *    @param	string		$morecss			More CSS
505	 *    @return	string							String with HTML select
506	 */
507	public function select_juridicalstatus($selected = '', $country_codeid = 0, $filter = '', $htmlname = 'forme_juridique_code', $morecss = '')
508	{
509		// phpcs:enable
510		global $conf, $langs, $user;
511		$langs->load("dict");
512
513		$out = '';
514
515		// On recherche les formes juridiques actives des pays actifs
516		$sql  = "SELECT f.rowid, f.code as code , f.libelle as label, f.active, c.label as country, c.code as country_code";
517		$sql .= " FROM ".MAIN_DB_PREFIX."c_forme_juridique as f, ".MAIN_DB_PREFIX."c_country as c";
518		$sql .= " WHERE f.fk_pays=c.rowid";
519		$sql .= " AND f.active = 1 AND c.active = 1";
520		if ($country_codeid) $sql .= " AND c.code = '".$this->db->escape($country_codeid)."'";
521		if ($filter) $sql .= " ".$filter;
522		$sql .= " ORDER BY c.code";
523
524		dol_syslog(get_class($this)."::select_juridicalstatus", LOG_DEBUG);
525		$resql = $this->db->query($sql);
526		if ($resql)
527		{
528			$out .= '<div id="particulier2" class="visible">';
529			$out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
530			if ($country_codeid) $out .= '<option value="0">&nbsp;</option>'; // When country_codeid is set, we force to add an empty line because it does not appears from select. When not set, we already get the empty line from select.
531
532			$num = $this->db->num_rows($resql);
533			if ($num)
534			{
535				$i = 0;
536				$country = ''; $arraydata = array();
537				while ($i < $num)
538				{
539					$obj = $this->db->fetch_object($resql);
540
541					if ($obj->code)		// We exclude empty line, we will add it later
542					{
543						$labelcountry = (($langs->trans("Country".$obj->country_code) != "Country".$obj->country_code) ? $langs->trans("Country".$obj->country_code) : $obj->country);
544						$labeljs = (($langs->trans("JuridicalStatus".$obj->code) != "JuridicalStatus".$obj->code) ? $langs->trans("JuridicalStatus".$obj->code) : ($obj->label != '-' ? $obj->label : '')); // $obj->label is already in output charset (converted by database driver)
545						$arraydata[$obj->code] = array('code'=>$obj->code, 'label'=>$labeljs, 'label_sort'=>$labelcountry.'_'.$labeljs, 'country_code'=>$obj->country_code, 'country'=>$labelcountry);
546					}
547					$i++;
548				}
549
550				$arraydata = dol_sort_array($arraydata, 'label_sort', 'ASC');
551				if (empty($country_codeid))	// Introduce empty value (if $country_codeid not empty, empty value was already added)
552				{
553					$arraydata[0] = array('code'=>0, 'label'=>'', 'label_sort'=>'_', 'country_code'=>'', 'country'=>'');
554				}
555
556				foreach ($arraydata as $key => $val)
557				{
558					if (!$country || $country != $val['country'])
559					{
560						// Show break when we are in multi country mode
561						if (empty($country_codeid) && $val['country_code'])
562						{
563							$out .= '<option value="0" disabled class="selectoptiondisabledwhite">----- '.$val['country']." -----</option>\n";
564							$country = $val['country'];
565						}
566					}
567
568					if ($selected > 0 && $selected == $val['code'])
569					{
570						$out .= '<option value="'.$val['code'].'" selected>';
571					} else {
572						$out .= '<option value="'.$val['code'].'">';
573					}
574					// If translation exists, we use it, otherwise we use default label in database
575					$out .= $val['label'];
576					$out .= '</option>';
577				}
578			}
579			$out .= '</select>';
580			if ($user->admin) $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
581
582			// Make select dynamic
583			include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
584			$out .= ajax_combobox($htmlname);
585
586			$out .= '</div>';
587		} else {
588			dol_print_error($this->db);
589		}
590
591		return $out;
592	}
593
594
595	/**
596	 *  Output list of third parties.
597	 *
598	 *  @param  object		$object         Object we try to find contacts
599	 *  @param  string		$var_id         Name of id field
600	 *  @param  string		$selected       Pre-selected third party
601	 *  @param  string		$htmlname       Name of HTML form
602	 * 	@param	array		$limitto		Disable answers that are not id in this array list
603	 *  @param	int			$forceid		This is to force another object id than object->id
604	 *  @param	string		$moreparam		String with more param to add into url when noajax search is used.
605	 *  @param	string		$morecss		More CSS on select component
606	 * 	@return int 						The selected third party ID
607	 */
608	public function selectCompaniesForNewContact($object, $var_id, $selected = '', $htmlname = 'newcompany', $limitto = '', $forceid = 0, $moreparam = '', $morecss = '')
609	{
610		global $conf, $langs;
611
612		if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT))
613		{
614			// Use Ajax search
615			$minLength = (is_numeric($conf->global->COMPANY_USE_SEARCH_TO_SELECT) ? $conf->global->COMPANY_USE_SEARCH_TO_SELECT : 2);
616
617			$socid = 0; $name = '';
618			if ($selected > 0)
619			{
620				$tmpthirdparty = new Societe($this->db);
621				$result = $tmpthirdparty->fetch($selected);
622				if ($result > 0)
623				{
624					$socid = $selected;
625					$name = $tmpthirdparty->name;
626				}
627			}
628
629
630			$events = array();
631			// Add an entry 'method' to say 'yes, we must execute url with param action = method';
632			// Add an entry 'url' to say which url to execute
633			// Add an entry htmlname to say which element we must change once url is called
634			// Add entry params => array('cssid' => 'attr') to say to remov or add attribute attr if answer of url return  0 or >0 lines
635			// To refresh contacts list on thirdparty list change
636			$events[] = array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php', 1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
637
638			if (count($events))	// If there is some ajax events to run once selection is done, we add code here to run events
639			{
640				print '<script type="text/javascript">
641				jQuery(document).ready(function() {
642					$("#search_'.$htmlname.'").change(function() {
643						var obj = '.json_encode($events).';
644						$.each(obj, function(key,values) {
645							if (values.method.length) {
646								runJsCodeForEvent'.$htmlname.'(values);
647							}
648						});
649
650						$(this).trigger("blur");
651					});
652
653					// Function used to execute events when search_htmlname change
654					function runJsCodeForEvent'.$htmlname.'(obj) {
655						var id = $("#'.$htmlname.'").val();
656						var method = obj.method;
657						var url = obj.url;
658						var htmlname = obj.htmlname;
659						var showempty = obj.showempty;
660						console.log("Run runJsCodeForEvent-'.$htmlname.' from selectCompaniesForNewContact id="+id+" method="+method+" showempty="+showempty+" url="+url+" htmlname="+htmlname);
661						$.getJSON(url,
662							{
663								action: method,
664								id: id,
665								htmlname: htmlname
666							},
667							function(response) {
668								if (response != null)
669								{
670									console.log("Change select#"+htmlname+" with content "+response.value)
671									$.each(obj.params, function(key,action) {
672										if (key.length) {
673											var num = response.num;
674											if (num > 0) {
675												$("#" + key).removeAttr(action);
676											} else {
677												$("#" + key).attr(action, action);
678											}
679										}
680									});
681									$("select#" + htmlname).html(response.value);
682								}
683							}
684						);
685					};
686				});
687				</script>';
688			}
689
690			print "\n".'<!-- Input text for third party with Ajax.Autocompleter (selectCompaniesForNewContact) -->'."\n";
691			print '<input type="text" size="30" id="search_'.$htmlname.'" name="search_'.$htmlname.'" value="'.$name.'" />';
692			print ajax_autocompleter(($socid ? $socid : -1), $htmlname, DOL_URL_ROOT.'/societe/ajaxcompanies.php', '', $minLength, 0);
693			return $socid;
694		} else {
695			// Search to list thirdparties
696			$sql = "SELECT s.rowid, s.nom as name FROM";
697			$sql .= " ".MAIN_DB_PREFIX."societe as s";
698			$sql .= " WHERE s.entity IN (".getEntity('societe').")";
699			// For ajax search we limit here. For combo list, we limit later
700			if (is_array($limitto) && count($limitto))
701			{
702				$sql .= " AND s.rowid IN (".join(',', $limitto).")";
703			}
704			$sql .= " ORDER BY s.nom ASC";
705
706			$resql = $this->db->query($sql);
707			if ($resql)
708			{
709				print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"';
710				if ($conf->use_javascript_ajax)
711				{
712					$javaScript = "window.location='".$_SERVER['PHP_SELF']."?".$var_id."=".($forceid > 0 ? $forceid : $object->id).$moreparam."&".$htmlname."=' + form.".$htmlname.".options[form.".$htmlname.".selectedIndex].value;";
713					print ' onChange="'.$javaScript.'"';
714				}
715				print '>';
716				$num = $this->db->num_rows($resql);
717				$i = 0;
718				if ($num)
719				{
720					while ($i < $num)
721					{
722						$obj = $this->db->fetch_object($resql);
723						if ($i == 0) $firstCompany = $obj->rowid;
724						$disabled = 0;
725						if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) $disabled = 1;
726						if ($selected > 0 && $selected == $obj->rowid)
727						{
728							print '<option value="'.$obj->rowid.'"';
729							if ($disabled) print ' disabled';
730							print ' selected>'.dol_trunc($obj->name, 24).'</option>';
731							$firstCompany = $obj->rowid;
732						} else {
733							print '<option value="'.$obj->rowid.'"';
734							if ($disabled) print ' disabled';
735							print '>'.dol_trunc($obj->name, 24).'</option>';
736						}
737						$i++;
738					}
739				}
740				print "</select>\n";
741				print ajax_combobox($htmlname);
742				return $firstCompany;
743			} else {
744				dol_print_error($this->db);
745				return 0;
746			}
747		}
748	}
749
750	/**
751	 *  Return a select list with types of contacts
752	 *
753	 *  @param	object		$object         Object to use to find type of contact
754	 *  @param  string		$selected       Default selected value
755	 *  @param  string		$htmlname		HTML select name
756	 *  @param  string		$source			Source ('internal' or 'external')
757	 *  @param  string		$sortorder		Sort criteria ('position', 'code', ...)
758	 *  @param  int			$showempty      1=Add en empty line
759	 *  @param  string      $morecss        Add more css to select component
760	 *  @return	void
761	 */
762	public function selectTypeContact($object, $selected, $htmlname = 'type', $source = 'internal', $sortorder = 'position', $showempty = 0, $morecss = '')
763	{
764		global $user, $langs;
765
766		if (is_object($object) && method_exists($object, 'liste_type_contact'))
767		{
768			$lesTypes = $object->liste_type_contact($source, $sortorder, 0, 1);
769
770			print '<select class="flat valignmiddle'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">';
771			if ($showempty) print '<option value="0"></option>';
772			foreach ($lesTypes as $key=>$value)
773			{
774				print '<option value="'.$key.'"';
775				if ($key == $selected) print ' selected';
776				print '>'.$value.'</option>';
777			}
778			print "</select>";
779			if ($user->admin) print ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
780
781			print ajax_combobox($htmlname);
782
783			print "\n";
784		}
785	}
786
787	/**
788	 * showContactRoles on view and edit mode
789	 *
790	 * @param string $htmlname Html component name and id
791	 * @param Contact $contact Contact Obejct
792	 * @param string $rendermode view, edit
793	 * @param array $selected $key=>$val $val is selected Roles for input mode
794	 * @return string   String with contacts roles
795	 */
796	public function showRoles($htmlname, Contact $contact, $rendermode = 'view', $selected = array())
797	{
798		if ($rendermode === 'view') {
799			$toprint = array();
800			foreach ($contact->roles as $key => $val) {
801				$toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories" style="background: #bbb;">'.$val['label'].'</li>';
802			}
803			return '<div class="select2-container-multi-dolibarr" style="width: 90%;" id="'.$htmlname.'"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>';
804		}
805
806		if ($rendermode === 'edit')
807		{
808			$contactType = $contact->listeTypeContacts('external', '', 1, '', '', 'agenda'); // We exclude agenda as there is no contact on such element
809			if (count($selected) > 0) {
810				$newselected = array();
811				foreach ($selected as $key=>$val) {
812					if (is_array($val) && array_key_exists('id', $val) && in_array($val['id'], array_keys($contactType))) {
813						$newselected[] = $val['id'];
814					} else {
815						break;
816					}
817				}
818				if (count($newselected) > 0) $selected = $newselected;
819			}
820			return $this->multiselectarray($htmlname, $contactType, $selected);
821		}
822
823		return 'ErrorBadValueForParameterRenderMode'; // Should not happened
824	}
825
826	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
827	/**
828	 *    Return a select list with zip codes and their town
829	 *
830	 *    @param	string		$selected				Preselected value
831	 *    @param    string		$htmlname				HTML select name
832	 *    @param    array		$fields					Array with key of fields to refresh after selection
833	 *    @param    int			$fieldsize				Field size
834	 *    @param    int			$disableautocomplete    1 To disable ajax autocomplete features (browser autocomplete may still occurs)
835	 *    @param	string		$moreattrib				Add more attribute on HTML input field
836	 *    @param    string      $morecss                More css
837	 *    @return	string
838	 */
839	public function select_ziptown($selected = '', $htmlname = 'zipcode', $fields = '', $fieldsize = 0, $disableautocomplete = 0, $moreattrib = '', $morecss = '')
840	{
841		// phpcs:enable
842		global $conf;
843
844		$out = '';
845
846		$size = '';
847		if (!empty($fieldsize)) $size = 'size="'.$fieldsize.'"';
848
849		if ($conf->use_javascript_ajax && empty($disableautocomplete))
850		{
851			$out .= ajax_multiautocompleter($htmlname, $fields, DOL_URL_ROOT.'/core/ajax/ziptown.php')."\n";
852			$moreattrib .= ' autocomplete="off"';
853		}
854		$out .= '<input id="'.$htmlname.'" class="maxwidthonsmartphone'.($morecss ? ' '.$morecss : '').'" type="text"'.($moreattrib ? ' '.$moreattrib : '').' name="'.$htmlname.'" '.$size.' value="'.$selected.'">'."\n";
855
856		return $out;
857	}
858
859	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
860	/**
861	 *  Return HTML string to use as input of professional id into a HTML page (siren, siret, etc...)
862	 *
863	 *  @param	int		$idprof         1,2,3,4 (Example: 1=siren,2=siret,3=naf,4=rcs/rm)
864	 *  @param  string	$htmlname       Name of HTML select
865	 *  @param  string	$preselected    Default value to show
866	 *  @param  string	$country_code   FR, IT, ...
867	 *  @param  string  $morecss        More css
868	 *  @return	string					HTML string with prof id
869	 */
870	public function get_input_id_prof($idprof, $htmlname, $preselected, $country_code, $morecss = 'maxwidth100onsmartphone quatrevingtpercent')
871	{
872		// phpcs:enable
873		global $conf, $langs, $hookmanager;
874
875		$formlength = 0;
876		if (empty($conf->global->MAIN_DISABLEPROFIDRULES)) {
877			if ($country_code == 'FR')
878			{
879				if (isset($idprof)) {
880					if ($idprof == 1) $formlength = 9;
881					elseif ($idprof == 2) $formlength = 14;
882					elseif ($idprof == 3) $formlength = 5; // 4 chiffres et 1 lettre depuis janvier
883					elseif ($idprof == 4) $formlength = 32; // No maximum as we need to include a town name in this id
884				}
885			} elseif ($country_code == 'ES')
886			{
887				if ($idprof == 1) $formlength = 9; //CIF/NIF/NIE 9 digits
888				if ($idprof == 2) $formlength = 12; //NASS 12 digits without /
889				if ($idprof == 3) $formlength = 5; //CNAE 5 digits
890				if ($idprof == 4) $formlength = 32; //depend of college
891			}
892		}
893
894		$selected = $preselected;
895		if (!$selected && isset($idprof)) {
896			if ($idprof == 1 && !empty($this->idprof1)) $selected = $this->idprof1;
897			elseif ($idprof == 2 && !empty($this->idprof2)) $selected = $this->idprof2;
898			elseif ($idprof == 3 && !empty($this->idprof3)) $selected = $this->idprof3;
899			elseif ($idprof == 4 && !empty($this->idprof4)) $selected = $this->idprof4;
900		}
901
902		$maxlength = $formlength;
903		if (empty($formlength)) { $formlength = 24; $maxlength = 128; }
904
905		$out = '';
906
907		// Execute hook getInputIdProf to complete or replace $out
908		$parameters = array('formlength'=>$formlength, 'selected'=>$preselected, 'idprof'=>$idprof, 'htmlname'=>$htmlname, 'country_code'=>$country_code);
909		$reshook = $hookmanager->executeHooks('getInputIdProf', $parameters);
910		if (empty($reshook))
911		{
912			$out .= '<input type="text" '.($morecss ? 'class="'.$morecss.'" ' : '').'name="'.$htmlname.'" id="'.$htmlname.'" maxlength="'.$maxlength.'" value="'.$selected.'">';
913		}
914		$out .= $hookmanager->resPrint;
915
916		return $out;
917	}
918
919	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
920	/**
921	 * Return a HTML select with localtax values for thirdparties
922	 *
923	 * @param 	int 		$local			LocalTax
924	 * @param 	int 		$selected		Preselected value
925	 * @param 	string      $htmlname		HTML select name
926	 * @return	void
927	 */
928	public function select_localtax($local, $selected, $htmlname)
929	{
930		// phpcs:enable
931		$tax = get_localtax_by_third($local);
932
933		$num = $this->db->num_rows($tax);
934		$i = 0;
935		if ($num)
936		{
937			$valors = explode(":", $tax);
938
939			if (count($valors) > 1)
940			{
941				//montar select
942				print '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">';
943				while ($i <= (count($valors)) - 1)
944				{
945					if ($selected == $valors[$i])
946					{
947						print '<option value="'.$valors[$i].'" selected>';
948					} else {
949						print '<option value="'.$valors[$i].'">';
950					}
951					print $valors[$i];
952					print '</option>';
953					$i++;
954				}
955				print'</select>';
956			}
957		}
958	}
959
960	/**
961	 * Return a HTML select for thirdparty type
962	 *
963	 * @param int $selected selected value
964	 * @param string $htmlname HTML select name
965	 * @param string $htmlidname HTML select id
966	 * @param string $typeinput HTML output
967	 * @param string $morecss More css
968	 * @return string HTML string
969	 */
970	public function selectProspectCustomerType($selected, $htmlname = 'client', $htmlidname = 'customerprospect', $typeinput = 'form', $morecss = '')
971	{
972
973		global $conf, $langs;
974
975		$out = '<select class="flat '.$morecss.'" name="'.$htmlname.'" id="'.$htmlidname.'">';
976		if ($typeinput == 'form') {
977			if ($selected == '' || $selected == '-1') $out .= '<option value="-1">&nbsp;</option>';
978			if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS)) {
979				$out .= '<option value="2"'.($selected == 2 ? ' selected' : '').'>'.$langs->trans('Prospect').'</option>';
980			}
981			if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) && empty($conf->global->SOCIETE_DISABLE_CUSTOMERS) && empty($conf->global->SOCIETE_DISABLE_PROSPECTSCUSTOMERS)) {
982				$out .= '<option value="3"'.($selected == 3 ? ' selected' : '').'>'.$langs->trans('ProspectCustomer').'</option>';
983			}
984			if (empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) {
985				$out .= '<option value="1"'.($selected == 1 ? ' selected' : '').'>'.$langs->trans('Customer').'</option>';
986			}
987			$out .= '<option value="0"'.((string) $selected == '0' ? ' selected' : '').'>'.$langs->trans('NorProspectNorCustomer').'</option>';
988		} elseif ($typeinput == 'list') {
989			$out .= '<option value="-1"'.(($selected == '' || $selected == '-1') ? ' selected' : '').'>&nbsp;</option>';
990			if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS)) {
991				$out .= '<option value="2,3"'.($selected == '2,3' ? ' selected' : '').'>'.$langs->trans('Prospect').'</option>';
992			}
993			if (empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) {
994				$out .= '<option value="1,3"'.($selected == '1,3' ? ' selected' : '').'>'.$langs->trans('Customer').'</option>';
995			}
996			$out .= '<option value="4"'.($selected == '4' ? ' selected' : '').'>'.$langs->trans('Supplier').'</option>';
997			$out .= '<option value="0"'.($selected == '0' ? ' selected' : '').'>'.$langs->trans('Other').'</option>';
998		} elseif ($typeinput == 'admin') {
999			if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) && empty($conf->global->SOCIETE_DISABLE_CUSTOMERS) && empty($conf->global->SOCIETE_DISABLE_PROSPECTSCUSTOMERS)) {
1000				$out .= '<option value="3"'.($selected == 3 ? ' selected' : '').'>'.$langs->trans('ProspectCustomer').'</option>';
1001			}
1002			if (empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) {
1003				$out .= '<option value="1"'.($selected == 1 ? ' selected' : '').'>'.$langs->trans('Customer').'</option>';
1004			}
1005		}
1006		$out .= '</select>';
1007		$out .= ajax_combobox($htmlidname);
1008
1009		return $out;
1010	}
1011
1012	/**
1013	 *  Output html select to select third-party type
1014	 *
1015	 *  @param	string	$page       	Page
1016	 *  @param  string	$selected   	Id preselected
1017	 *  @param  string	$htmlname		Name of HTML select
1018	 *  @param  string	$filter         optional filters criteras
1019	 *  @param  int     $nooutput       No print output. Return it only.
1020	 *  @return	void|string
1021	 */
1022	public function formThirdpartyType($page, $selected = '', $htmlname = 'socid', $filter = '', $nooutput = 0)
1023	{
1024		// phpcs:enable
1025		global $conf, $langs;
1026
1027		$out = '';
1028		if ($htmlname != "none") {
1029			$out .= '<form method="post" action="'.$page.'">';
1030			$out .= '<input type="hidden" name="action" value="set_thirdpartytype">';
1031			$out .= '<input type="hidden" name="token" value="'.newToken().'">';
1032			$sortparam = (empty($conf->global->SOCIETE_SORT_ON_TYPEENT) ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT); // NONE means we keep sort of original array, so we sort on position. ASC, means next function will sort on label.
1033			$out .= $this->selectarray($htmlname, $this->typent_array(0, $filter), $selected, 0, 0, 0, '', 0, 0, 0, $sortparam, '', 1);
1034			$out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">';
1035			$out .= '</form>';
1036		} else {
1037			if ($selected) {
1038				$arr = $this->typent_array(0);
1039				$typent = $arr[$selected];
1040				$out .= $typent;
1041			} else {
1042				$out .= "&nbsp;";
1043			}
1044		}
1045
1046		if ($nooutput) {
1047			return $out;
1048		} else {
1049			print $out;
1050		}
1051	}
1052}
1053