diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
new file mode 100644
index 00000000000..008006b8fa5
--- /dev/null
+++ b/htdocs/core/class/html.form.class.php
@@ -0,0 +1,8282 @@
+
+ * Copyright (C) 2004-2012 Laurent Destailleur
+ * Copyright (C) 2004 Benoit Mortier
+ * Copyright (C) 2004 Sebastien Di Cintio
+ * Copyright (C) 2004 Eric Seigne
+ * Copyright (C) 2005-2017 Regis Houssin
+ * Copyright (C) 2006 Andre Cianfarani
+ * Copyright (C) 2006 Marc Barilley/Ocebo
+ * Copyright (C) 2007 Franky Van Liedekerke
+ * Copyright (C) 2007 Patrick Raguin
+ * Copyright (C) 2010 Juanjo Menent
+ * Copyright (C) 2010-2019 Philippe Grand
+ * Copyright (C) 2011 Herve Prot
+ * Copyright (C) 2012-2016 Marcos García
+ * Copyright (C) 2012 Cedric Salvador
+ * Copyright (C) 2012-2015 Raphaël Doursenaud
+ * Copyright (C) 2014 Alexandre Spangaro
+ * Copyright (C) 2018 Ferran Marcet
+ * Copyright (C) 2018-2019 Frédéric France
+ * Copyright (C) 2018 Nicolas ZABOURI
+ * Copyright (C) 2018 Christophe Battarel
+ * Copyright (C) 2018 Josep Lluis Amador
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file htdocs/core/class/html.form.class.php
+ * \ingroup core
+ * \brief File of class with all html predefined components
+ */
+
+
+/**
+ * Class to manage generation of HTML components
+ * Only common components must be here.
+ *
+ * TODO Merge all function load_cache_* and loadCache* (except load_cache_vatrates) into one generic function loadCacheTable
+ */
+class Form
+{
+ /**
+ * @var DoliDB Database handler.
+ */
+ public $db;
+
+ /**
+ * @var string Error code (or message)
+ */
+ public $error = '';
+
+ /**
+ * @var string[] Array of error strings
+ */
+ public $errors = array();
+
+ public $num;
+
+ // Cache arrays
+ public $cache_types_paiements = array();
+ public $cache_conditions_paiements = array();
+ public $cache_availability = array();
+ public $cache_demand_reason = array();
+ public $cache_types_fees = array();
+ public $cache_vatrates = array();
+
+
+ /**
+ * Constructor
+ *
+ * @param DoliDB $db Database handler
+ */
+ public function __construct($db)
+ {
+ $this->db = $db;
+ }
+
+ /**
+ * Output key field for an editable field
+ *
+ * @param string $text Text of label or key to translate
+ * @param string $htmlname Name of select field ('edit' prefix will be added)
+ * @param string $preselected Value to show/edit (not used in this function)
+ * @param object $object Object
+ * @param boolean $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field.
+ * @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]'...)
+ * @param string $moreparam More param to add on a href URL.
+ * @param int $fieldrequired 1 if we want to show field as mandatory using the "fieldrequired" CSS.
+ * @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 ' '
+ * @param string $paramid Key of parameter for id ('id', 'socid')
+ * @param string $help Tooltip help
+ * @return string HTML edit field
+ */
+ public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
+ {
+ global $conf, $langs;
+
+ $ret = '';
+
+ // TODO change for compatibility
+ if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata))
+ {
+ if (!empty($perm))
+ {
+ $tmp = explode(':', $typeofdata);
+ $ret .= '
';
+ $result .= '';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Output edit in place form
+ *
+ * @param object $object Object
+ * @param string $value Value to show/edit
+ * @param string $htmlname DIV ID (field name)
+ * @param int $condition Condition to edit
+ * @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')
+ * @param string $editvalue When in edit mode, use this value as $value instead of value
+ * @param object $extObject External object
+ * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage')
+ * @return string HTML edit in place
+ */
+ protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
+ {
+ global $conf;
+
+ $out = '';
+
+ // Check parameters
+ if (preg_match('/^text/', $inputType)) $value = dol_nl2br($value);
+ elseif (preg_match('/^numeric/', $inputType)) $value = price($value);
+ elseif ($inputType == 'day' || $inputType == 'datepicker') $value = dol_print_date($value, 'day');
+
+ if ($condition)
+ {
+ $element = false;
+ $table_element = false;
+ $fk_element = false;
+ $loadmethod = false;
+ $savemethod = false;
+ $ext_element = false;
+ $button_only = false;
+ $inputOption = '';
+
+ if (is_object($object))
+ {
+ $element = $object->element;
+ $table_element = $object->table_element;
+ $fk_element = $object->id;
+ }
+
+ if (is_object($extObject))
+ {
+ $ext_element = $extObject->element;
+ }
+
+ if (preg_match('/^(string|email|numeric)/', $inputType))
+ {
+ $tmp = explode(':', $inputType);
+ $inputType = $tmp[0];
+ if (!empty($tmp[1])) $inputOption = $tmp[1];
+ if (!empty($tmp[2])) $savemethod = $tmp[2];
+ $out .= ''."\n";
+ }
+ elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType)))
+ {
+ $tmp = explode(':', $inputType);
+ $inputType = $tmp[0];
+ if (!empty($tmp[1])) $inputOption = $tmp[1];
+ if (!empty($tmp[2])) $savemethod = $tmp[2];
+
+ $out .= ''."\n"; // Use for timestamp format
+ }
+ elseif (preg_match('/^(select|autocomplete)/', $inputType))
+ {
+ $tmp = explode(':', $inputType);
+ $inputType = $tmp[0]; $loadmethod = $tmp[1];
+ if (!empty($tmp[2])) $savemethod = $tmp[2];
+ if (!empty($tmp[3])) $button_only = true;
+ }
+ elseif (preg_match('/^textarea/', $inputType))
+ {
+ $tmp = explode(':', $inputType);
+ $inputType = $tmp[0];
+ $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
+ $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
+ }
+ elseif (preg_match('/^ckeditor/', $inputType))
+ {
+ $tmp = explode(':', $inputType);
+ $inputType = $tmp[0]; $toolbar = $tmp[1];
+ if (!empty($tmp[2])) $width = $tmp[2];
+ if (!empty($tmp[3])) $heigth = $tmp[3];
+ if (!empty($tmp[4])) $savemethod = $tmp[4];
+
+ if (!empty($conf->fckeditor->enabled))
+ {
+ $out .= ''."\n";
+ }
+ else
+ {
+ $inputType = 'textarea';
+ }
+ }
+
+ $out .= ''."\n";
+ $out .= ''."\n";
+ $out .= ''."\n";
+ $out .= ''."\n";
+ if (!empty($savemethod)) $out .= ''."\n";
+ if (!empty($ext_element)) $out .= ''."\n";
+ if (!empty($custommsg))
+ {
+ if (is_array($custommsg))
+ {
+ if (!empty($custommsg['success']))
+ $out .= ''."\n";
+ if (!empty($custommsg['error']))
+ $out .= ''."\n";
+ }
+ else
+ $out .= ''."\n";
+ }
+ if ($inputType == 'textarea') {
+ $out .= ''."\n";
+ $out .= ''."\n";
+ }
+ $out .= ''.$value.''."\n";
+ $out .= ''.(!empty($editvalue) ? $editvalue : $value).''."\n";
+ }
+ else
+ {
+ $out = $value;
+ }
+
+ return $out;
+ }
+
+ /**
+ * Show a text and picto with tooltip on text or picto.
+ * Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip
+ *
+ * @param string $text Text to show
+ * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded.
+ * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2
+ * @param int $direction -1=image is before, 0=no image, 1=image is after
+ * @param string $img Html code for image (use img_xxx() function to get it)
+ * @param string $extracss Add a CSS style to td tags
+ * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
+ * @param string $incbefore Include code before the text
+ * @param int $noencodehtmltext Do not encode into html entity the htmltext
+ * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key)
+ * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only)
+ * @return string Code html du tooltip (texte+picto)
+ * @see textwithpicto() Use thisfunction if you can.
+ * TODO Move this as static as soon as everybody use textwithpicto or @Form::textwithtooltip
+ */
+ public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
+ {
+ if ($incbefore) $text = $incbefore.$text;
+ if (!$htmltext) return $text;
+
+ $tag = 'td';
+ if ($notabs == 2) $tag = 'div';
+ if ($notabs == 3) $tag = 'span';
+ // Sanitize tooltip
+ $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
+
+ $extrastyle = '';
+ if ($direction < 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-left: 3px !important;'; }
+ if ($direction > 0) { $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); $extrastyle = 'padding: 0px; padding-right: 3px !important;'; }
+
+ $classfortooltip = 'classfortooltip';
+
+ $s = ''; $textfordialog = '';
+
+ if ($tooltiptrigger == '')
+ {
+ $htmltext = str_replace('"', '"', $htmltext);
+ }
+ else
+ {
+ $classfortooltip = 'classfortooltiponclick';
+ $textfordialog .= '
'.$htmltext.'
';
+ }
+ if ($tooltipon == 2 || $tooltipon == 3)
+ {
+ $paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"';
+ if ($tooltiptrigger == '') $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip
+ else $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"';
+ }
+ else $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
+ if ($tooltipon == 1 || $tooltipon == 3)
+ {
+ $paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" ';
+ if ($tooltiptrigger == '') $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip
+ else $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"';
+ }
+ else $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag
+ if (empty($notabs)) $s .= '
';
+ elseif ($notabs == 2) $s .= '
';
+ // Define value if value is before
+ if ($direction < 0) {
+ $s .= '<'.$tag.$paramfortooltipimg;
+ if ($tag == 'td') {
+ $s .= ' class=valigntop" width="14"';
+ }
+ $s .= '>'.$textfordialog.$img.''.$tag.'>';
+ }
+ // Use another method to help avoid having a space in value in order to use this value with jquery
+ // Define label
+ if ((string) $text != '') $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.''.$tag.'>';
+ // Define value if value is after
+ if ($direction > 0) {
+ $s .= '<'.$tag.$paramfortooltipimg;
+ if ($tag == 'td') $s .= ' class="valignmiddle" width="14"';
+ $s .= '>'.$textfordialog.$img.''.$tag.'>';
+ }
+ if (empty($notabs)) $s .= '
';
+ elseif ($notabs == 2) $s .= '';
+
+ return $s;
+ }
+
+ /**
+ * Show a text with a picto and a tooltip on picto
+ *
+ * @param string $text Text to show
+ * @param string $htmltext Content of tooltip
+ * @param int $direction 1=Icon is after text, -1=Icon is before text, 0=no icon
+ * @param string $type Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none'
+ * @param string $extracss Add a CSS style to td, div or span tag
+ * @param int $noencodehtmltext Do not encode into html entity the htmltext
+ * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span
+ * @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')
+ * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only)
+ * @return string HTML code of text, picto, tooltip
+ */
+ public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
+ {
+ global $conf, $langs;
+
+ $alt = '';
+ if ($tooltiptrigger) $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
+
+ //For backwards compatibility
+ if ($type == '0') $type = 'info';
+ elseif ($type == '1') $type = 'help';
+
+ // If info or help with no javascript, show only text
+ if (empty($conf->use_javascript_ajax))
+ {
+ if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') return $text;
+ else
+ {
+ $alt = $htmltext;
+ $htmltext = '';
+ }
+ }
+
+ // If info or help with smartphone, show only text (tooltip hover can't works)
+ if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger))
+ {
+ if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') return $text;
+ }
+ // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
+ //if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger))
+ //{
+ //if ($type == 'info' || $type == 'help') return ''.$text.''';
+ //}
+
+ $img = '';
+ if ($type == 'info') $img = img_help(0, $alt);
+ elseif ($type == 'help') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
+ elseif ($type == 'helpclickable') $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
+ elseif ($type == 'superadmin') $img = img_picto($alt, 'redstar');
+ elseif ($type == 'admin') $img = img_picto($alt, 'star');
+ elseif ($type == 'warning') $img = img_warning($alt);
+ elseif ($type != 'none') $img = img_picto($alt, $type); // $type can be an image path
+
+ return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
+ }
+
+ /**
+ * Generate select HTML to choose massaction
+ *
+ * @param string $selected Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default.
+ * @param array $arrayofaction array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action.
+ * @param int $alwaysvisible 1=select button always visible
+ * @param string $name Name for massaction
+ * @param string $cssclass CSS class used to check for select
+ * @return string|void Select list
+ */
+ public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
+ {
+ global $conf, $langs, $hookmanager;
+
+
+ $disabled = 0;
+ $ret = '
';
+ $ret .= '';
+
+ if (empty($conf->dol_optimize_smallscreen)) $ret .= ajax_combobox('.' . $name . 'select');
+
+ // 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
+ $ret .= ''; // Hidden button BEFORE so it is the one used when we submit with ENTER.
+ $ret .= '';
+ $ret .= '
';
+
+ if (!empty($conf->use_javascript_ajax))
+ {
+ $ret .= '
+
+ ';
+ }
+
+ return $ret;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return combo list of activated countries, into language of user
+ *
+ * @param string $selected Id or Code or Label of preselected country
+ * @param string $htmlname Name of html select object
+ * @param string $htmloption More html options on select object
+ * @param integer $maxlength Max length for labels (0=no limit)
+ * @param string $morecss More css class
+ * @param string $usecodeaskey ''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
+ * @param int $showempty Show empty choice
+ * @param int $disablefavorites 1=Disable favorites,
+ * @param int $addspecialentries 1=Add dedicated entries for group of countries (like 'European Economic Community', ...)
+ * @param array $exclude_country_code Array of country code (iso2) to exclude
+ * @return string HTML string with select
+ */
+ public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array())
+ {
+ // phpcs:enable
+ global $conf, $langs, $mysoc;
+
+ $langs->load("dict");
+
+ $out = '';
+ $countryArray = array();
+ $favorite = array();
+ $label = array();
+ $atleastonefavorite = 0;
+
+ $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite";
+ $sql .= " FROM ".MAIN_DB_PREFIX."c_country";
+ $sql .= " WHERE active > 0";
+ //$sql.= " ORDER BY code ASC";
+
+ dol_syslog(get_class($this)."::select_country", LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ $out .= '';
+ }
+ else
+ {
+ dol_print_error($this->db);
+ }
+
+ // Make select dynamic
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
+ $out .= ajax_combobox('select'.$htmlname);
+
+ return $out;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return select list of incoterms
+ *
+ * @param string $selected Id or Code of preselected incoterm
+ * @param string $location_incoterms Value of input location
+ * @param string $page Defined the form action
+ * @param string $htmlname Name of html select object
+ * @param string $htmloption Options html on select object
+ * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification)
+ * @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')))
+ * @return string HTML string with select and input
+ */
+ public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array())
+ {
+ // phpcs:enable
+ global $conf, $langs;
+
+ $langs->load("dict");
+
+ $out = '';
+ $incotermArray = array();
+
+ $sql = "SELECT rowid, code";
+ $sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms";
+ $sql .= " WHERE active > 0";
+ $sql .= " ORDER BY code ASC";
+
+ dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ if ($conf->use_javascript_ajax && !$forcecombo)
+ {
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
+ $out .= ajax_combobox($htmlname, $events);
+ }
+
+ if (!empty($page))
+ {
+ $out .= '';
+ }
+ }
+ else
+ {
+ dol_print_error($this->db);
+ }
+
+ return $out;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return list of types of lines (product or service)
+ * Example: 0=product, 1=service, 9=other (for external module)
+ *
+ * @param string $selected Preselected type
+ * @param string $htmlname Name of field in html form
+ * @param int $showempty Add an empty field
+ * @param int $hidetext Do not show label 'Type' before combo box (used only if there is at least 2 choices to select)
+ * @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')
+ * @return void
+ */
+ public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0)
+ {
+ // phpcs:enable
+ global $db, $langs, $user, $conf;
+
+ // If product & services are enabled or both disabled.
+ if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled))
+ || (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled)))
+ {
+ if (empty($hidetext)) print $langs->trans("Type").': ';
+ print '';
+ //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
+ }
+ if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3)
+ {
+ print $langs->trans("Service");
+ print '';
+ }
+ if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2)
+ {
+ print $langs->trans("Product");
+ print '';
+ }
+ if ($forceall < 0) // This should happened only for contracts when both predefined product and service are disabled.
+ {
+ print ''; // By default we set on service for contract. If CONTRACT_SUPPORT_PRODUCTS is set, forceall should be 1 not -1
+ }
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Load into cache cache_types_fees, array of types of fees
+ *
+ * @return int Nb of lines loaded, <0 if KO
+ */
+ public function load_cache_types_fees()
+ {
+ // phpcs:enable
+ global $langs;
+
+ $num = count($this->cache_types_fees);
+ if ($num > 0) return 0; // Cache already loaded
+
+ dol_syslog(__METHOD__, LOG_DEBUG);
+
+ $langs->load("trips");
+
+ $sql = "SELECT c.code, c.label";
+ $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c";
+ $sql .= " WHERE active > 0";
+
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ $num = $this->db->num_rows($resql);
+ $i = 0;
+
+ while ($i < $num)
+ {
+ $obj = $this->db->fetch_object($resql);
+
+ // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
+ $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
+ $this->cache_types_fees[$obj->code] = $label;
+ $i++;
+ }
+
+ asort($this->cache_types_fees);
+
+ return $num;
+ }
+ else
+ {
+ dol_print_error($this->db);
+ return -1;
+ }
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return list of types of notes
+ *
+ * @param string $selected Preselected type
+ * @param string $htmlname Name of field in form
+ * @param int $showempty Add an empty field
+ * @return void
+ */
+ public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
+ {
+ // phpcs:enable
+ global $user, $langs;
+
+ dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG);
+
+ $this->load_cache_types_fees();
+
+ print '';
+ if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
+ }
+
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return HTML code to select a company.
+ *
+ * @param int $selected Preselected products
+ * @param string $htmlname Name of HTML select field (must be unique in page)
+ * @param int $filter Filter on thirdparty
+ * @param int $limit Limit on number of returned lines
+ * @param array $ajaxoptions Options for ajax_autocompleter
+ * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification)
+ * @return string Return select box for thirdparty.
+ * @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)
+ */
+ public function select_thirdparty($selected = '', $htmlname = 'socid', $filter = '', $limit = 20, $ajaxoptions = array(), $forcecombo = 0)
+ {
+ // phpcs:enable
+ return $this->select_thirdparty_list($selected, $htmlname, $filter, 1, 0, $forcecombo, array(), '', 0, $limit);
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Output html form to select a third party
+ *
+ * @param string $selected Preselected type
+ * @param string $htmlname Name of field in form
+ * @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)')
+ * @param string $showempty Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty')
+ * @param int $showtype Show third party type in combolist (customer, prospect or supplier)
+ * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification)
+ * @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')))
+ * @param int $limit Maximum number of elements
+ * @param string $morecss Add more css styles to the SELECT component
+ * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
+ * @param string $selected_input_value Value of preselected input text (for use with ajax)
+ * @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after)
+ * @param array $ajaxoptions Options for ajax_autocompleter
+ * @param bool $multiple add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter)
+ * @return string HTML string with select box for thirdparty.
+ */
+ 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)
+ {
+ // phpcs:enable
+ global $conf, $user, $langs;
+
+ $out = '';
+
+ if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo)
+ {
+ // No immediate load of all database
+ $placeholder = '';
+ if ($selected && empty($selected_input_value))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
+ $societetmp = new Societe($this->db);
+ $societetmp->fetch($selected);
+ $selected_input_value = $societetmp->name;
+ unset($societetmp);
+ }
+ // mode 1
+ $urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).($showtype ? '&showtype='.urlencode($showtype) : '');
+ $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions);
+ $out .= '';
+ if (empty($hidelabel)) print $langs->trans("RefOrLabel").' : ';
+ elseif ($hidelabel > 1) {
+ $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"';
+ if ($hidelabel == 2) {
+ $out .= img_picto($langs->trans("Search"), 'search');
+ }
+ }
+ $out .= 'global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />';
+ if ($hidelabel == 3) {
+ $out .= img_picto($langs->trans("Search"), 'search');
+ }
+ }
+ else
+ {
+ // Immediate load of all database
+ $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple);
+ }
+
+ return $out;
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Output html form to select a third party.
+ * 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.
+ *
+ * @param string $selected Preselected type
+ * @param string $htmlname Name of field in form
+ * @param string $filter Optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)')
+ * @param string $showempty Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty')
+ * @param int $showtype Show third party type in combolist (customer, prospect or supplier)
+ * @param int $forcecombo Force to use standard HTML select component without beautification
+ * @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')))
+ * @param string $filterkey Filter on key value
+ * @param int $outputmode 0=HTML select string, 1=Array
+ * @param int $limit Limit number of answers
+ * @param string $morecss Add more css styles to the SELECT component
+ * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
+ * @param bool $multiple add [] in the name of element and add 'multiple' attribut
+ * @return string HTML string with
+ */
+ 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)
+ {
+ // phpcs:enable
+ global $conf, $user, $langs;
+
+ $out = '';
+ $num = 0;
+ $outarray = array();
+
+ if ($selected === '') $selected = array();
+ elseif (!is_array($selected)) $selected = array($selected);
+
+ // Clean $filter that may contains sql conditions so sql code
+ if (function_exists('testSqlAndScriptInject')) {
+ if (testSqlAndScriptInject($filter, 3) > 0) {
+ $filter = '';
+ }
+ }
+
+ // On recherche les societes
+ $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
+
+ if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
+ $sql .= ", s.address, s.zip, s.town";
+ $sql .= ", dictp.code as country_code";
+ }
+
+ $sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
+ if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
+ if ($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST) {
+ $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid=s.fk_pays";
+ }
+ $sql .= " WHERE s.entity IN (".getEntity('societe').")";
+ if (!empty($user->socid)) $sql .= " AND s.rowid = ".$user->socid;
+ if ($filter) $sql .= " AND (".$filter.")";
+ if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
+ if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND s.status <> 0";
+ // Add criteria
+ if ($filterkey && $filterkey != '')
+ {
+ $sql .= " AND (";
+ $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
+ // For natural search
+ $scrit = explode(' ', $filterkey);
+ $i = 0;
+ if (count($scrit) > 1) $sql .= "(";
+ foreach ($scrit as $crit) {
+ if ($i > 0) $sql .= " AND ";
+ $sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')";
+ $i++;
+ }
+ if (count($scrit) > 1) $sql .= ")";
+ if (!empty($conf->barcode->enabled))
+ {
+ $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'";
+ }
+ $sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'";
+ $sql .= ")";
+ }
+ $sql .= $this->db->order("nom", "ASC");
+ $sql .= $this->db->plimit($limit, 0);
+
+ // Build output string
+ dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ if (!$forcecombo)
+ {
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
+ $out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT);
+ }
+
+ // Construct $out and $outarray
+ $out .= ''."\n";
+ }
+ else
+ {
+ dol_print_error($this->db);
+ }
+
+ $this->result = array('nbofthirdparties'=>$num);
+
+ if ($outputmode) return $outarray;
+ return $out;
+ }
+
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return HTML combo list of absolute discounts
+ *
+ * @param string $selected Id remise fixe pre-selectionnee
+ * @param string $htmlname Nom champ formulaire
+ * @param string $filter Criteres optionnels de filtre
+ * @param int $socid Id of thirdparty
+ * @param int $maxvalue Max value for lines that can be selected
+ * @return int Return number of qualifed lines in list
+ */
+ public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
+ {
+ // phpcs:enable
+ global $langs, $conf;
+
+ // On recherche les remises
+ $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
+ $sql .= " re.description, re.fk_facture_source";
+ $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
+ $sql .= " WHERE re.fk_soc = ".(int) $socid;
+ $sql .= " AND re.entity = ".$conf->entity;
+ if ($filter) $sql .= " AND ".$filter;
+ $sql .= " ORDER BY re.description ASC";
+
+ dol_syslog(get_class($this)."::select_remises", LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ print '';
+ return $qualifiedlines;
+ }
+ else
+ {
+ dol_print_error($this->db);
+ return -1;
+ }
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return list of all contacts (for a third party or all)
+ *
+ * @param int $socid Id ot third party or 0 for all
+ * @param string $selected Id contact pre-selectionne
+ * @param string $htmlname Name of HTML field ('none' for a not editable field)
+ * @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
+ * @param string $exclude List of contacts id to exclude
+ * @param string $limitto Disable answers that are not id in this array list
+ * @param integer $showfunction Add function into label
+ * @param string $moreclass Add more class to class style
+ * @param integer $showsoc Add company into label
+ * @param int $forcecombo Force to use combo box
+ * @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')))
+ * @param bool $options_only Return options only (for ajax treatment)
+ * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
+ * @param string $htmlid Html id to use instead of htmlname
+ * @return int <0 if KO, Nb of contact in list if OK
+ * @deprected You can use selectcontacts directly (warning order of param was changed)
+ */
+ 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 = '')
+ {
+ // phpcs:enable
+ print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid);
+ return $this->num;
+ }
+
+ /**
+ * Return HTML code of the SELECT of list of all contacts (for a third party or all).
+ * This also set the number of contacts found into $this->num
+ *
+ * @since 9.0 Add afterSelectContactOptions hook
+ *
+ * @param int $socid Id ot third party or 0 for all or -1 for empty list
+ * @param array|int $selected Array of ID of pre-selected contact id
+ * @param string $htmlname Name of HTML field ('none' for a not editable field)
+ * @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
+ * @param string $exclude List of contacts id to exclude
+ * @param string $limitto Disable answers that are not id in this array list
+ * @param integer $showfunction Add function into label
+ * @param string $moreclass Add more class to class style
+ * @param bool $options_only Return options only (for ajax treatment)
+ * @param integer $showsoc Add company into label
+ * @param int $forcecombo Force to use combo box (so no ajax beautify effect)
+ * @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')))
+ * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container
+ * @param string $htmlid Html id to use instead of htmlname
+ * @param bool $multiple add [] in the name of element and add 'multiple' attribut
+ * @return int <0 if KO, Nb of contact in list if OK
+ */
+ 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)
+ {
+ global $conf, $langs, $hookmanager, $action;
+
+ $langs->load('companies');
+
+ if (empty($htmlid)) $htmlid = $htmlname;
+
+ if ($selected === '') $selected = array();
+ elseif (!is_array($selected)) $selected = array($selected);
+ $out = '';
+
+ if (!is_object($hookmanager))
+ {
+ include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
+ $hookmanager = new HookManager($this->db);
+ }
+
+ // We search third parties
+ $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste";
+ if ($showsoc > 0) $sql .= " , s.nom as company";
+ $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as sp";
+ if ($showsoc > 0) $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=sp.fk_soc";
+ $sql .= " WHERE sp.entity IN (".getEntity('socpeople').")";
+ if ($socid > 0 || $socid == -1) $sql .= " AND sp.fk_soc=".$socid;
+ if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) $sql .= " AND sp.statut <> 0";
+ $sql .= " ORDER BY sp.lastname ASC";
+
+ dol_syslog(get_class($this)."::select_contacts", LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ $num = $this->db->num_rows($resql);
+
+ if ($conf->use_javascript_ajax && !$forcecombo && !$options_only)
+ {
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
+ $out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT);
+ }
+
+ if ($htmlname != 'none' && !$options_only) $out .= '';
+ }
+
+ $this->num = $num;
+ return $out;
+ }
+ else
+ {
+ dol_print_error($this->db);
+ return -1;
+ }
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return the HTML select list of users
+ *
+ * @param string $selected Id user preselected
+ * @param string $htmlname Field name in form
+ * @param int $show_empty 0=liste sans valeur nulle, 1=ajoute valeur inconnue
+ * @param array $exclude Array list of users id to exclude
+ * @param int $disabled If select list must be disabled
+ * @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
+ * @param int $enableonly Array list of users id to be enabled. All other must be disabled
+ * @param string $force_entity '0' or Ids of environment to force
+ * @return void
+ * @deprecated Use select_dolusers instead
+ * @see select_dolusers()
+ */
+ public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0')
+ {
+ // phpcs:enable
+ print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
+ }
+
+ // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
+ /**
+ * Return select list of users
+ *
+ * @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)
+ * @param string $htmlname Field name in form
+ * @param int $show_empty 0=list with no empty value, 1=add also an empty value into list
+ * @param array $exclude Array list of users id to exclude
+ * @param int $disabled If select list must be disabled
+ * @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
+ * @param array $enableonly Array list of users id to be enabled. If defined, it means that others will be disabled
+ * @param string $force_entity '0' or Ids of environment to force
+ * @param int $maxlength Maximum length of string into list (0=no limit)
+ * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status
+ * @param string $morefilter Add more filters into sql request (Example: 'employee = 1')
+ * @param integer $show_every 0=default list, 1=add also a value "Everybody" at beginning of list
+ * @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.
+ * @param string $morecss More css
+ * @param int $noactive Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on).
+ * @param int $outputmode 0=HTML select string, 1=Array
+ * @param bool $multiple add [] in the name of element and add 'multiple' attribut
+ * @return string HTML select string
+ * @see select_dolgroups()
+ */
+ 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)
+ {
+ // phpcs:enable
+ global $conf, $user, $langs, $hookmanager;
+
+ // If no preselected user defined, we take current user
+ if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) $selected = $user->id;
+
+ if ($selected === '') $selected = array();
+ elseif (!is_array($selected)) $selected = array($selected);
+
+ $excludeUsers = null;
+ $includeUsers = null;
+
+ // Permettre l'exclusion d'utilisateurs
+ if (is_array($exclude)) $excludeUsers = implode(",", $exclude);
+ // Permettre l'inclusion d'utilisateurs
+ if (is_array($include)) $includeUsers = implode(",", $include);
+ elseif ($include == 'hierarchy')
+ {
+ // Build list includeUsers to have only hierarchy
+ $includeUsers = implode(",", $user->getAllChildIds(0));
+ }
+ elseif ($include == 'hierarchyme')
+ {
+ // Build list includeUsers to have only hierarchy and current user
+ $includeUsers = implode(",", $user->getAllChildIds(1));
+ }
+
+ $out = '';
+ $outarray = array();
+
+ // Forge request to select users
+ $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut, u.login, u.admin, u.entity";
+ if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
+ {
+ $sql .= ", e.label";
+ }
+ $sql .= " FROM ".MAIN_DB_PREFIX."user as u";
+ if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity)
+ {
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=u.entity";
+ if ($force_entity) $sql .= " WHERE u.entity IN (0,".$force_entity.")";
+ else $sql .= " WHERE u.entity IS NOT NULL";
+ }
+ else
+ {
+ if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
+ {
+ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug";
+ $sql .= " ON ug.fk_user = u.rowid";
+ $sql .= " WHERE ug.entity = ".$conf->entity;
+ }
+ else
+ {
+ $sql .= " WHERE u.entity IN (0,".$conf->entity.")";
+ }
+ }
+ if (!empty($user->socid)) $sql .= " AND u.fk_soc = ".$user->socid;
+ if (is_array($exclude) && $excludeUsers) $sql .= " AND u.rowid NOT IN (".$excludeUsers.")";
+ if ($includeUsers) $sql .= " AND u.rowid IN (".$includeUsers.")";
+ if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) $sql .= " AND u.statut <> 0";
+ if (!empty($morefilter)) $sql .= " ".$morefilter;
+
+ //Add hook to filter on user (for exemple on usergroup define in custom modules)
+ $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
+ if (!empty($reshook)) $sql .= $hookmanager->resPrint;
+
+ if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
+ {
+ $sql .= " ORDER BY u.firstname ASC";
+ }
+ else
+ {
+ $sql .= " ORDER BY u.lastname ASC";
+ }
+
+ dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql)
+ {
+ $num = $this->db->num_rows($resql);
+ $i = 0;
+ if ($num)
+ {
+ // Enhance with select2
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
+ $out .= ajax_combobox($htmlname);
+
+ // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
+ $out .= '