1<?php 2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org> 3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net> 4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be> 5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org> 6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> 7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com> 8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr> 9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com> 10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be> 11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com> 12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es> 13 * Copyright (C) 2010-2019 Philippe Grand <philippe.grand@atoo-net.com> 14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com> 15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com> 16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr> 17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> 18 * Copyright (C) 2014-2020 Alexandre Spangaro <aspangaro@open-dsi.fr> 19 * Copyright (C) 2018-2021 Ferran Marcet <fmarcet@2byte.es> 20 * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr> 21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com> 22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr> 23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat> 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 */ 52class Form 53{ 54 /** 55 * @var DoliDB Database handler. 56 */ 57 public $db; 58 59 /** 60 * @var string Error code (or message) 61 */ 62 public $error = ''; 63 64 /** 65 * @var string[] Array of error strings 66 */ 67 public $errors = array(); 68 69 public $num; 70 71 // Cache arrays 72 public $cache_types_paiements = array(); 73 public $cache_conditions_paiements = array(); 74 public $cache_transport_mode = array(); 75 public $cache_availability = array(); 76 public $cache_demand_reason = array(); 77 public $cache_types_fees = array(); 78 public $cache_vatrates = array(); 79 80 81 /** 82 * Constructor 83 * 84 * @param DoliDB $db Database handler 85 */ 86 public function __construct($db) 87 { 88 $this->db = $db; 89 } 90 91 /** 92 * Output key field for an editable field 93 * 94 * @param string $text Text of label or key to translate 95 * @param string $htmlname Name of select field ('edit' prefix will be added) 96 * @param string $preselected Value to show/edit (not used in this function) 97 * @param object $object Object 98 * @param boolean $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field. 99 * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'datepicker' ('day' do not work, don't know why), 'checkbox:ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...) 100 * @param string $moreparam More param to add on a href URL. 101 * @param int $fieldrequired 1 if we want to show field as mandatory using the "fieldrequired" CSS. 102 * @param int $notabletag 1=Do not output table tags but output a ':', 2=Do not output table tags and no ':', 3=Do not output table tags but output a ' ' 103 * @param string $paramid Key of parameter for id ('id', 'socid') 104 * @param string $help Tooltip help 105 * @return string HTML edit field 106 */ 107 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '') 108 { 109 global $conf, $langs; 110 111 $ret = ''; 112 113 // TODO change for compatibility 114 if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;/', $typeofdata)) { 115 if (!empty($perm)) { 116 $tmp = explode(':', $typeofdata); 117 $ret .= '<div class="editkey_'.$tmp[0].(!empty($tmp[1]) ? ' '.$tmp[1] : '').'" id="'.$htmlname.'">'; 118 if ($fieldrequired) { 119 $ret .= '<span class="fieldrequired">'; 120 } 121 if ($help) { 122 $ret .= $this->textwithpicto($langs->trans($text), $help); 123 } else { 124 $ret .= $langs->trans($text); 125 } 126 if ($fieldrequired) { 127 $ret .= '</span>'; 128 } 129 $ret .= '</div>'."\n"; 130 } else { 131 if ($fieldrequired) { 132 $ret .= '<span class="fieldrequired">'; 133 } 134 if ($help) { 135 $ret .= $this->textwithpicto($langs->trans($text), $help); 136 } else { 137 $ret .= $langs->trans($text); 138 } 139 if ($fieldrequired) { 140 $ret .= '</span>'; 141 } 142 } 143 } else { 144 if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { 145 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">'; 146 } 147 if ($fieldrequired) { 148 $ret .= '<span class="fieldrequired">'; 149 } 150 if ($help) { 151 $ret .= $this->textwithpicto($langs->trans($text), $help); 152 } else { 153 $ret .= $langs->trans($text); 154 } 155 if ($fieldrequired) { 156 $ret .= '</span>'; 157 } 158 if (!empty($notabletag)) { 159 $ret .= ' '; 160 } 161 if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { 162 $ret .= '</td>'; 163 } 164 if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { 165 $ret .= '<td class="right">'; 166 } 167 if ($htmlname && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { 168 $ret .= '<a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=edit'.$htmlname.'&'.$paramid.'='.$object->id.$moreparam.'">'.img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)).'</a>'; 169 } 170 if (!empty($notabletag) && $notabletag == 1) { 171 $ret .= ' : '; 172 } 173 if (!empty($notabletag) && $notabletag == 3) { 174 $ret .= ' '; 175 } 176 if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { 177 $ret .= '</td>'; 178 } 179 if (empty($notabletag) && GETPOST('action', 'aZ09') != 'edit'.$htmlname && $perm) { 180 $ret .= '</tr></table>'; 181 } 182 } 183 184 return $ret; 185 } 186 187 /** 188 * Output value of a field for an editable field 189 * 190 * @param string $text Text of label (not used in this function) 191 * @param string $htmlname Name of select field 192 * @param string $value Value to show/edit 193 * @param object $object Object 194 * @param boolean $perm Permission to allow button to edit parameter 195 * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols%', 'datepicker' ('day' do not work, don't know why), 'dayhour' or 'datepickerhour', 'ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols', 'select;xkey:xval,ykey:yval,...') 196 * @param string $editvalue When in edit mode, use this value as $value instead of value (for example, you can provide here a formated price instead of value). Use '' to use same than $value 197 * @param object $extObject External object 198 * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') 199 * @param string $moreparam More param to add on the form action href URL 200 * @param int $notabletag Do no output table tags 201 * @param string $formatfunc Call a specific function to output field 202 * @param string $paramid Key of parameter for id ('id', 'socid') 203 * @return string HTML edit field 204 */ 205 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 0, $formatfunc = '', $paramid = 'id') 206 { 207 global $conf, $langs, $db; 208 209 $ret = ''; 210 211 // Check parameters 212 if (empty($typeofdata)) { 213 return 'ErrorBadParameter'; 214 } 215 216 // When option to edit inline is activated 217 if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !preg_match('/^select;|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select 218 $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg); 219 } else { 220 $editmode = (GETPOST('action', 'aZ09') == 'edit'.$htmlname); 221 if ($editmode) { 222 $ret .= "\n"; 223 $ret .= '<form method="post" action="'.$_SERVER["PHP_SELF"].($moreparam ? '?'.$moreparam : '').'">'; 224 $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">'; 225 $ret .= '<input type="hidden" name="token" value="'.newToken().'">'; 226 $ret .= '<input type="hidden" name="'.$paramid.'" value="'.$object->id.'">'; 227 if (empty($notabletag)) { 228 $ret .= '<table class="nobordernopadding centpercent">'; 229 } 230 if (empty($notabletag)) { 231 $ret .= '<tr><td>'; 232 } 233 if (preg_match('/^(string|safehtmlstring|email)/', $typeofdata)) { 234 $tmp = explode(':', $typeofdata); 235 $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($editvalue ? $editvalue : $value).'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>'; 236 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) { 237 $tmp = explode(':', $typeofdata); 238 $valuetoshow = price2num($editvalue ? $editvalue : $value); 239 $ret .= '<input type="text" id="'.$htmlname.'" name="'.$htmlname.'" value="'.($valuetoshow != '' ?price($valuetoshow) : '').'"'.($tmp[1] ? ' size="'.$tmp[1].'"' : '').' autofocus>'; 240 } elseif (preg_match('/^(checkbox)/', $typeofdata)) { 241 $tmp = explode(':', $typeofdata); 242 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($tmp[1] ? $tmp[1] : '') . '/>'; 243 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor' 244 $tmp = explode(':', $typeofdata); 245 $cols = $tmp[2]; 246 $morealt = ''; 247 if (preg_match('/%/', $cols)) { 248 $morealt = ' style="width: '.$cols.'"'; 249 $cols = ''; 250 } 251 252 $valuetoshow = ($editvalue ? $editvalue : $value); 253 $ret .= '<textarea id="'.$htmlname.'" name="'.$htmlname.'" wrap="soft" rows="'.($tmp[1] ? $tmp[1] : '20').'"'.($cols ? ' cols="'.$cols.'"' : 'class="quatrevingtpercent"').$morealt.'" autofocus>'; 254 // textarea convert automatically entities chars into simple chars. 255 // So we convert & into & so a string like 'a < <b>b</b><br>é<br><script>alert('X');<script>' stay a correct html and is not converted by textarea component when wysiwig is off. 256 $valuetoshow = str_replace('&', '&', $valuetoshow); 257 $ret .= dol_string_neverthesehtmltags($valuetoshow, array('textarea')); 258 $ret .= '</textarea>'; 259 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') { 260 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form'.$htmlname, 1, 0); 261 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') { 262 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form'.$htmlname, 1, 0); 263 } elseif (preg_match('/^select;/', $typeofdata)) { 264 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata)); 265 $arraylist = array(); 266 foreach ($arraydata as $val) { 267 $tmp = explode(':', $val); 268 $tmpkey = str_replace('|', ':', $tmp[0]); 269 $arraylist[$tmpkey] = $tmp[1]; 270 } 271 $ret .= $this->selectarray($htmlname, $arraylist, $value); 272 } elseif (preg_match('/^ckeditor/', $typeofdata)) { 273 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser 274 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; 275 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), ($tmp[2] ? $tmp[2] : ''), ($tmp[3] ? $tmp[3] : '100'), ($tmp[1] ? $tmp[1] : 'dolibarr_notes'), 'In', ($tmp[5] ? $tmp[5] : 0), (isset($tmp[8]) ? ($tmp[8] ?true:false) : true), true, ($tmp[6] ? $tmp[6] : '20'), ($tmp[7] ? $tmp[7] : '100')); 276 $ret .= $doleditor->Create(1); 277 } 278 if (empty($notabletag)) { 279 $ret .= '</td>'; 280 } 281 282 if (empty($notabletag)) { 283 $ret .= '<td class="left">'; 284 } 285 //else $ret.='<div class="clearboth"></div>'; 286 $ret .= '<input type="submit" class="smallpaddingimp button'.(empty($notabletag) ? '' : ' ').'" name="modify" value="'.$langs->trans("Modify").'">'; 287 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) { 288 $ret .= '<br>'."\n"; 289 } 290 $ret .= '<input type="submit" class="smallpaddingimp button button-cancel'.(empty($notabletag) ? '' : ' ').'" name="cancel" value="'.$langs->trans("Cancel").'">'; 291 if (empty($notabletag)) { 292 $ret .= '</td>'; 293 } 294 295 if (empty($notabletag)) { 296 $ret .= '</tr></table>'."\n"; 297 } 298 $ret .= '</form>'."\n"; 299 } else { 300 if (preg_match('/^(email)/', $typeofdata)) { 301 $ret .= dol_print_email($value, 0, 0, 0, 0, 1); 302 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) { 303 $ret .= ($value != '' ? price($value, '', $langs, 0, -1, -1, $conf->currency) : ''); 304 } elseif (preg_match('/^(checkbox)/', $typeofdata)) { 305 $tmp = explode(':', $typeofdata); 306 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($tmp[1] ? $tmp[1] : '') . '/>'; 307 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { 308 $ret .= dol_htmlentitiesbr($value); 309 } elseif (preg_match('/^safehtmlstring/', $typeofdata)) { 310 $ret .= dol_string_onlythesehtmltags($value); 311 } elseif (preg_match('/^restricthtml/', $typeofdata)) { 312 $ret .= dol_string_onlythesehtmltags($value); 313 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') { 314 $ret .= '<span class="valuedate">'.dol_print_date($value, 'day').'</span>'; 315 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') { 316 $ret .= '<span class="valuedate">'.dol_print_date($value, 'dayhour').'</span>'; 317 } elseif (preg_match('/^select;/', $typeofdata)) { 318 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata)); 319 $arraylist = array(); 320 foreach ($arraydata as $val) { 321 $tmp = explode(':', $val); 322 $arraylist[$tmp[0]] = $tmp[1]; 323 } 324 $ret .= $arraylist[$value]; 325 if ($htmlname == 'fk_product_type') { 326 if ($value == 0) { 327 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"').$ret; 328 } else { 329 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"').$ret; 330 } 331 } 332 } elseif (preg_match('/^ckeditor/', $typeofdata)) { 333 $tmpcontent = dol_htmlentitiesbr($value); 334 if (!empty($conf->global->MAIN_DISABLE_NOTES_TAB)) { 335 $firstline = preg_replace('/<br>.*/', '', $tmpcontent); 336 $firstline = preg_replace('/[\n\r].*/', '', $firstline); 337 $tmpcontent = $firstline.((strlen($firstline) != strlen($tmpcontent)) ? '...' : ''); 338 } 339 // We dont use dol_escape_htmltag to get the html formating active, but this need we must also 340 // clean data from some dangerous html 341 $ret .= dol_string_onlythesehtmltags(dol_htmlentitiesbr($tmpcontent)); 342 } else { 343 $ret .= dol_escape_htmltag($value); 344 } 345 346 if ($formatfunc && method_exists($object, $formatfunc)) { 347 $ret = $object->$formatfunc($ret); 348 } 349 } 350 } 351 return $ret; 352 } 353 354 /** 355 * Output edit in place form 356 * 357 * @param string $fieldname Name of the field 358 * @param object $object Object 359 * @param boolean $perm Permission to allow button to edit parameter. Set it to 0 to have a not edited field. 360 * @param string $typeofdata Type of data ('string' by default, 'email', 'amount:99', 'numeric:99', 'text' or 'textarea:rows:cols', 'datepicker' ('day' do not work, don't know why), 'ckeditor:dolibarr_zzz:width:height:savemethod:1:rows:cols', 'select;xxx[:class]'...) 361 * @param string $check Same coe than $check parameter of GETPOST() 362 * @param string $morecss More CSS 363 * @return string HTML code for the edit of alternative language 364 */ 365 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '') 366 { 367 global $conf, $langs, $extralanguages; 368 369 $result = ''; 370 371 // List of extra languages 372 $arrayoflangcode = array(); 373 if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) { 374 $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; 375 } 376 377 if (is_array($arrayoflangcode) && count($arrayoflangcode)) { 378 if (!is_object($extralanguages)) { 379 include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php'; 380 $extralanguages = new ExtraLanguages($this->db); 381 } 382 $extralanguages->fetch_name_extralanguages('societe'); 383 384 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) { 385 return ''; // No extralang field to show 386 } 387 388 $result .= '<!-- Widget for translation -->'."\n"; 389 $result .= '<div class="inline-block paddingleft image-'.$object->element.'-'.$fieldname.'">'; 390 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang'); 391 $result .= $s; 392 $result .= '</div>'; 393 394 $result .= '<div class="inline-block hidden field-'.$object->element.'-'.$fieldname.'">'; 395 396 $resultforextrlang = ''; 397 foreach ($arrayoflangcode as $langcode) { 398 $valuetoshow = GETPOSTISSET('field-'.$object->element."-".$fieldname."-".$langcode) ? GETPOST('field-'.$object->element.'-'.$fieldname."-".$langcode, $check) : ''; 399 if (empty($valuetoshow)) { 400 $object->fetchValuesForExtraLanguages(); 401 //var_dump($object->array_languages); 402 $valuetoshow = $object->array_languages[$fieldname][$langcode]; 403 } 404 405 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"'); 406 $resultforextrlang .= $s; 407 408 // TODO Use the showInputField() method of ExtraLanguages object 409 if ($typeofdata == 'textarea') { 410 $resultforextrlang .= '<textarea name="field-'.$object->element."-".$fieldname."-".$langcode.'" id="'.$fieldname."-".$langcode.'" class="'.$morecss.'" rows="'.ROWS_2.'" wrap="soft">'; 411 $resultforextrlang .= $valuetoshow; 412 $resultforextrlang .= '</textarea>'; 413 } else { 414 $resultforextrlang .= '<input type="text" class="inputfieldforlang '.($morecss ? ' '.$morecss : '').'" name="field-'.$object->element.'-'.$fieldname.'-'.$langcode.'" value="'.$valuetoshow.'">'; 415 } 416 } 417 $result .= $resultforextrlang; 418 419 $result .= '</div>'; 420 $result .= '<script>$(".image-'.$object->element.'-'.$fieldname.'").click(function() { console.log("Toggle lang widget"); jQuery(".field-'.$object->element.'-'.$fieldname.'").toggle(); });</script>'; 421 } 422 423 return $result; 424 } 425 426 /** 427 * Output edit in place form 428 * 429 * @param object $object Object 430 * @param string $value Value to show/edit 431 * @param string $htmlname DIV ID (field name) 432 * @param int $condition Condition to edit 433 * @param string $inputType Type of input ('string', 'numeric', 'datepicker' ('day' do not work, don't know why), 'textarea:rows:cols', 'ckeditor:dolibarr_zzz:width:height:?:1:rows:cols', 'select:loadmethod:savemethod:buttononly') 434 * @param string $editvalue When in edit mode, use this value as $value instead of value 435 * @param object $extObject External object 436 * @param mixed $custommsg String or Array of custom messages : eg array('success' => 'MyMessage', 'error' => 'MyMessage') 437 * @return string HTML edit in place 438 */ 439 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null) 440 { 441 global $conf; 442 443 $out = ''; 444 445 // Check parameters 446 if (preg_match('/^text/', $inputType)) { 447 $value = dol_nl2br($value); 448 } elseif (preg_match('/^numeric/', $inputType)) { 449 $value = price($value); 450 } elseif ($inputType == 'day' || $inputType == 'datepicker') { 451 $value = dol_print_date($value, 'day'); 452 } 453 454 if ($condition) { 455 $element = false; 456 $table_element = false; 457 $fk_element = false; 458 $loadmethod = false; 459 $savemethod = false; 460 $ext_element = false; 461 $button_only = false; 462 $inputOption = ''; 463 464 if (is_object($object)) { 465 $element = $object->element; 466 $table_element = $object->table_element; 467 $fk_element = $object->id; 468 } 469 470 if (is_object($extObject)) { 471 $ext_element = $extObject->element; 472 } 473 474 if (preg_match('/^(string|email|numeric)/', $inputType)) { 475 $tmp = explode(':', $inputType); 476 $inputType = $tmp[0]; 477 if (!empty($tmp[1])) { 478 $inputOption = $tmp[1]; 479 } 480 if (!empty($tmp[2])) { 481 $savemethod = $tmp[2]; 482 } 483 $out .= '<input id="width_'.$htmlname.'" value="'.$inputOption.'" type="hidden"/>'."\n"; 484 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) { 485 $tmp = explode(':', $inputType); 486 $inputType = $tmp[0]; 487 if (!empty($tmp[1])) { 488 $inputOption = $tmp[1]; 489 } 490 if (!empty($tmp[2])) { 491 $savemethod = $tmp[2]; 492 } 493 494 $out .= '<input id="timestamp" type="hidden"/>'."\n"; // Use for timestamp format 495 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) { 496 $tmp = explode(':', $inputType); 497 $inputType = $tmp[0]; 498 $loadmethod = $tmp[1]; 499 if (!empty($tmp[2])) { 500 $savemethod = $tmp[2]; 501 } 502 if (!empty($tmp[3])) { 503 $button_only = true; 504 } 505 } elseif (preg_match('/^textarea/', $inputType)) { 506 $tmp = explode(':', $inputType); 507 $inputType = $tmp[0]; 508 $rows = (empty($tmp[1]) ? '8' : $tmp[1]); 509 $cols = (empty($tmp[2]) ? '80' : $tmp[2]); 510 } elseif (preg_match('/^ckeditor/', $inputType)) { 511 $tmp = explode(':', $inputType); 512 $inputType = $tmp[0]; 513 $toolbar = $tmp[1]; 514 if (!empty($tmp[2])) { 515 $width = $tmp[2]; 516 } 517 if (!empty($tmp[3])) { 518 $heigth = $tmp[3]; 519 } 520 if (!empty($tmp[4])) { 521 $savemethod = $tmp[4]; 522 } 523 524 if (!empty($conf->fckeditor->enabled)) { 525 $out .= '<input id="ckeditor_toolbar" value="'.$toolbar.'" type="hidden"/>'."\n"; 526 } else { 527 $inputType = 'textarea'; 528 } 529 } 530 531 $out .= '<input id="element_'.$htmlname.'" value="'.$element.'" type="hidden"/>'."\n"; 532 $out .= '<input id="table_element_'.$htmlname.'" value="'.$table_element.'" type="hidden"/>'."\n"; 533 $out .= '<input id="fk_element_'.$htmlname.'" value="'.$fk_element.'" type="hidden"/>'."\n"; 534 $out .= '<input id="loadmethod_'.$htmlname.'" value="'.$loadmethod.'" type="hidden"/>'."\n"; 535 if (!empty($savemethod)) { 536 $out .= '<input id="savemethod_'.$htmlname.'" value="'.$savemethod.'" type="hidden"/>'."\n"; 537 } 538 if (!empty($ext_element)) { 539 $out .= '<input id="ext_element_'.$htmlname.'" value="'.$ext_element.'" type="hidden"/>'."\n"; 540 } 541 if (!empty($custommsg)) { 542 if (is_array($custommsg)) { 543 if (!empty($custommsg['success'])) { 544 $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg['success'].'" type="hidden"/>'."\n"; 545 } 546 if (!empty($custommsg['error'])) { 547 $out .= '<input id="errormsg_'.$htmlname.'" value="'.$custommsg['error'].'" type="hidden"/>'."\n"; 548 } 549 } else { 550 $out .= '<input id="successmsg_'.$htmlname.'" value="'.$custommsg.'" type="hidden"/>'."\n"; 551 } 552 } 553 if ($inputType == 'textarea') { 554 $out .= '<input id="textarea_'.$htmlname.'_rows" value="'.$rows.'" type="hidden"/>'."\n"; 555 $out .= '<input id="textarea_'.$htmlname.'_cols" value="'.$cols.'" type="hidden"/>'."\n"; 556 } 557 $out .= '<span id="viewval_'.$htmlname.'" class="viewval_'.$inputType.($button_only ? ' inactive' : ' active').'">'.$value.'</span>'."\n"; 558 $out .= '<span id="editval_'.$htmlname.'" class="editval_'.$inputType.($button_only ? ' inactive' : ' active').' hideobject">'.(!empty($editvalue) ? $editvalue : $value).'</span>'."\n"; 559 } else { 560 $out = $value; 561 } 562 563 return $out; 564 } 565 566 /** 567 * Show a text and picto with tooltip on text or picto. 568 * Can be called by an instancied $form->textwithtooltip or by a static call Form::textwithtooltip 569 * 570 * @param string $text Text to show 571 * @param string $htmltext HTML content of tooltip. Must be HTML/UTF8 encoded. 572 * @param int $tooltipon 1=tooltip on text, 2=tooltip on image, 3=tooltip sur les 2 573 * @param int $direction -1=image is before, 0=no image, 1=image is after 574 * @param string $img Html code for image (use img_xxx() function to get it) 575 * @param string $extracss Add a CSS style to td tags 576 * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span 577 * @param string $incbefore Include code before the text 578 * @param int $noencodehtmltext Do not encode into html entity the htmltext 579 * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key) 580 * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) 581 * @return string Code html du tooltip (texte+picto) 582 * @see textwithpicto() Use thisfunction if you can. 583 */ 584 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0) 585 { 586 if ($incbefore) { 587 $text = $incbefore.$text; 588 } 589 if (!$htmltext) { 590 return $text; 591 } 592 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0 593 594 $tag = 'td'; 595 if ($notabs == 2) { 596 $tag = 'div'; 597 } 598 if ($notabs == 3) { 599 $tag = 'span'; 600 } 601 // Sanitize tooltip 602 $htmltext = str_replace(array("\r", "\n"), '', $htmltext); 603 604 $extrastyle = ''; 605 if ($direction < 0) { 606 $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); 607 $extrastyle = 'padding: 0px; padding-left: 3px !important;'; 608 } 609 if ($direction > 0) { 610 $extracss = ($extracss ? $extracss.' ' : '').($notabs != 3 ? 'inline-block' : ''); 611 $extrastyle = 'padding: 0px; padding-right: 3px !important;'; 612 } 613 614 $classfortooltip = 'classfortooltip'; 615 616 $s = ''; 617 $textfordialog = ''; 618 619 if ($tooltiptrigger == '') { 620 $htmltext = str_replace('"', '"', $htmltext); 621 } else { 622 $classfortooltip = 'classfortooltiponclick'; 623 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_'.$tooltiptrigger.'" class="classfortooltiponclicktext">'.$htmltext.'</div>'; 624 } 625 if ($tooltipon == 2 || $tooltipon == 3) { 626 $paramfortooltipimg = ' class="'.$classfortooltip.($notabs != 3 ? ' inline-block' : '').($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'"'; 627 if ($tooltiptrigger == '') { 628 $paramfortooltipimg .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on img tag to store tooltip 629 } else { 630 $paramfortooltipimg .= ' dolid="'.$tooltiptrigger.'"'; 631 } 632 } else { 633 $paramfortooltipimg = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag 634 } 635 if ($tooltipon == 1 || $tooltipon == 3) { 636 $paramfortooltiptd = ' class="'.($tooltipon == 3 ? 'cursorpointer ' : '').$classfortooltip.' inline-block'.($extracss ? ' '.$extracss : '').'" style="padding: 0px;'.($extrastyle ? ' '.$extrastyle : '').'" '; 637 if ($tooltiptrigger == '') { 638 $paramfortooltiptd .= ' title="'.($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)).'"'; // Attribut to put on td tag to store tooltip 639 } else { 640 $paramfortooltiptd .= ' dolid="'.$tooltiptrigger.'"'; 641 } 642 } else { 643 $paramfortooltiptd = ($extracss ? ' class="'.$extracss.'"' : '').($extrastyle ? ' style="'.$extrastyle.'"' : ''); // Attribut to put on td text tag 644 } 645 if (empty($notabs)) { 646 $s .= '<table class="nobordernopadding"><tr style="height: auto;">'; 647 } elseif ($notabs == 2) { 648 $s .= '<div class="inline-block'.($forcenowrap ? ' nowrap' : '').'">'; 649 } 650 // Define value if value is before 651 if ($direction < 0) { 652 $s .= '<'.$tag.$paramfortooltipimg; 653 if ($tag == 'td') { 654 $s .= ' class=valigntop" width="14"'; 655 } 656 $s .= '>'.$textfordialog.$img.'</'.$tag.'>'; 657 } 658 // Use another method to help avoid having a space in value in order to use this value with jquery 659 // Define label 660 if ((string) $text != '') { 661 $s .= '<'.$tag.$paramfortooltiptd.'>'.$text.'</'.$tag.'>'; 662 } 663 // Define value if value is after 664 if ($direction > 0) { 665 $s .= '<'.$tag.$paramfortooltipimg; 666 if ($tag == 'td') { 667 $s .= ' class="valignmiddle" width="14"'; 668 } 669 $s .= '>'.$textfordialog.$img.'</'.$tag.'>'; 670 } 671 if (empty($notabs)) { 672 $s .= '</tr></table>'; 673 } elseif ($notabs == 2) { 674 $s .= '</div>'; 675 } 676 677 return $s; 678 } 679 680 /** 681 * Show a text with a picto and a tooltip on picto 682 * 683 * @param string $text Text to show 684 * @param string $htmltext Content of tooltip 685 * @param int $direction 1=Icon is after text, -1=Icon is before text, 0=no icon 686 * @param string $type Type of picto ('info', 'infoclickable', 'help', 'helpclickable', 'warning', 'superadmin', 'mypicto@mymodule', ...) or image filepath or 'none' 687 * @param string $extracss Add a CSS style to td, div or span tag 688 * @param int $noencodehtmltext Do not encode into html entity the htmltext 689 * @param int $notabs 0=Include table and tr tags, 1=Do not include table and tr tags, 2=use div, 3=use span 690 * @param string $tooltiptrigger ''=Tooltip on hover, 'abc'=Tooltip on click (abc is a unique key, clickable link is on image or on link if param $type='none' or on both if $type='xxxclickable') 691 * @param int $forcenowrap Force no wrap between text and picto (works with notabs=2 only) 692 * @return string HTML code of text, picto, tooltip 693 */ 694 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0) 695 { 696 global $conf, $langs; 697 698 $alt = ''; 699 if ($tooltiptrigger) { 700 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp"); 701 } 702 703 //For backwards compatibility 704 if ($type == '0') { 705 $type = 'info'; 706 } elseif ($type == '1') { 707 $type = 'help'; 708 } 709 710 // If info or help with no javascript, show only text 711 if (empty($conf->use_javascript_ajax)) { 712 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') { 713 return $text; 714 } else { 715 $alt = $htmltext; 716 $htmltext = ''; 717 } 718 } 719 720 // If info or help with smartphone, show only text (tooltip hover can't works) 721 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) { 722 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') { 723 return $text; 724 } 725 } 726 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone) 727 //if (! empty($conf->dol_no_mouse_hover) && ! empty($tooltiptrigger)) 728 //{ 729 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.''</a>'; 730 //} 731 732 $img = ''; 733 if ($type == 'info') { 734 $img = img_help(0, $alt); 735 } elseif ($type == 'help') { 736 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt); 737 } elseif ($type == 'helpclickable') { 738 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt); 739 } elseif ($type == 'superadmin') { 740 $img = img_picto($alt, 'redstar'); 741 } elseif ($type == 'admin') { 742 $img = img_picto($alt, 'star'); 743 } elseif ($type == 'warning') { 744 $img = img_warning($alt); 745 } elseif ($type != 'none') { 746 $img = img_picto($alt, $type); // $type can be an image path 747 } 748 749 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap); 750 } 751 752 /** 753 * Generate select HTML to choose massaction 754 * 755 * @param string $selected Value auto selected when at least one record is selected. Not a preselected value. Use '0' by default. 756 * @param array $arrayofaction array('code'=>'label', ...). The code is the key stored into the GETPOST('massaction') when submitting action. 757 * @param int $alwaysvisible 1=select button always visible 758 * @param string $name Name for massaction 759 * @param string $cssclass CSS class used to check for select 760 * @return string|void Select list 761 */ 762 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect') 763 { 764 global $conf, $langs, $hookmanager; 765 766 767 $disabled = 0; 768 $ret = '<div class="centpercent center">'; 769 $ret .= '<select class="flat'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'select valignmiddle alignstart" id="'.$name.'" name="'.$name.'"'.($disabled ? ' disabled="disabled"' : '').'>'; 770 771 // Complete list with data from external modules. THe module can use $_SERVER['PHP_SELF'] to know on which page we are, or use the $parameters['currentcontext'] completed by executeHooks. 772 $parameters = array(); 773 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook 774 // check if there is a mass action 775 if (count($arrayofaction) == 0 && empty($hookmanager->resPrint)) { 776 return; 777 } 778 if (empty($reshook)) { 779 $ret .= '<option value="0"'.($disabled ? ' disabled="disabled"' : '').'>-- '.$langs->trans("SelectAction").' --</option>'; 780 foreach ($arrayofaction as $code => $label) { 781 $ret .= '<option value="'.$code.'"'.($disabled ? ' disabled="disabled"' : '').' data-html="'.dol_escape_htmltag($label).'">'.$label.'</option>'; 782 } 783 } 784 $ret .= $hookmanager->resPrint; 785 786 $ret .= '</select>'; 787 788 if (empty($conf->dol_optimize_smallscreen)) { 789 $ret .= ajax_combobox('.'.$name.'select'); 790 } 791 792 // Warning: if you set submit button to disabled, post using 'Enter' will no more work if there is no another input submit. So we add a hidden button 793 $ret .= '<input type="submit" name="confirmmassactioninvisible" style="display: none" tabindex="-1">'; // Hidden button BEFORE so it is the one used when we submit with ENTER. 794 $ret .= '<input type="submit" disabled name="confirmmassaction"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display: none"').' class="button'.(empty($conf->use_javascript_ajax) ? '' : ' hideobject').' '.$name.' '.$name.'confirmed" value="'.dol_escape_htmltag($langs->trans("Confirm")).'">'; 795 $ret .= '</div>'; 796 797 if (!empty($conf->use_javascript_ajax)) { 798 $ret .= '<!-- JS CODE TO ENABLE mass action select --> 799 <script> 800 function initCheckForSelect(mode, name, cssclass) /* mode is 0 during init of page or click all, 1 when we click on 1 checkboxi, "name" refers to the class of the massaction button, "cssclass" to the class of the checkfor select boxes */ 801 { 802 atleastoneselected=0; 803 jQuery("."+cssclass).each(function( index ) { 804 /* console.log( index + ": " + $( this ).text() ); */ 805 if ($(this).is(\':checked\')) atleastoneselected++; 806 }); 807 808 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected); 809 810 if (atleastoneselected || '.$alwaysvisible.') 811 { 812 jQuery("."+name).show(); 813 '.($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("'.$selected.'").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '').' 814 '.($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '').' 815 } 816 else 817 { 818 jQuery("."+name).hide(); 819 jQuery("."+name+"other").hide(); 820 } 821 } 822 823 jQuery(document).ready(function () { 824 initCheckForSelect(0, "' . $name.'", "'.$cssclass.'"); 825 jQuery(".' . $cssclass.'").click(function() { 826 initCheckForSelect(1, "'.$name.'", "'.$cssclass.'"); 827 }); 828 jQuery(".' . $name.'select").change(function() { 829 var massaction = $( this ).val(); 830 var urlform = $( this ).closest("form").attr("action").replace("#show_files",""); 831 if (massaction == "builddoc") 832 { 833 urlform = urlform + "#show_files"; 834 } 835 $( this ).closest("form").attr("action", urlform); 836 console.log("we select a mass action name='.$name.' massaction="+massaction+" - "+urlform); 837 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */ 838 if ($(this).val() != \'0\') 839 { 840 jQuery(".' . $name.'confirmed").prop(\'disabled\', false); 841 jQuery(".' . $name.'other").hide(); /* To disable if another div was open */ 842 jQuery(".' . $name.'"+massaction).show(); 843 } 844 else 845 { 846 jQuery(".' . $name.'confirmed").prop(\'disabled\', true); 847 jQuery(".' . $name.'other").hide(); /* To disable any div open */ 848 } 849 }); 850 }); 851 </script> 852 '; 853 } 854 855 return $ret; 856 } 857 858 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 859 /** 860 * Return combo list of activated countries, into language of user 861 * 862 * @param string $selected Id or Code or Label of preselected country 863 * @param string $htmlname Name of html select object 864 * @param string $htmloption More html options on select object 865 * @param integer $maxlength Max length for labels (0=no limit) 866 * @param string $morecss More css class 867 * @param string $usecodeaskey ''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key 868 * @param int $showempty Show empty choice 869 * @param int $disablefavorites 1=Disable favorites, 870 * @param int $addspecialentries 1=Add dedicated entries for group of countries (like 'European Economic Community', ...) 871 * @param array $exclude_country_code Array of country code (iso2) to exclude 872 * @param int $hideflags Hide flags 873 * @return string HTML string with select 874 */ 875 public function select_country($selected = '', $htmlname = 'country_id', $htmloption = '', $maxlength = 0, $morecss = 'minwidth300', $usecodeaskey = '', $showempty = 1, $disablefavorites = 0, $addspecialentries = 0, $exclude_country_code = array(), $hideflags = 0) 876 { 877 // phpcs:enable 878 global $conf, $langs, $mysoc; 879 880 $langs->load("dict"); 881 882 $out = ''; 883 $countryArray = array(); 884 $favorite = array(); 885 $label = array(); 886 $atleastonefavorite = 0; 887 888 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec"; 889 $sql .= " FROM ".MAIN_DB_PREFIX."c_country"; 890 $sql .= " WHERE active > 0"; 891 //$sql.= " ORDER BY code ASC"; 892 893 dol_syslog(get_class($this)."::select_country", LOG_DEBUG); 894 $resql = $this->db->query($sql); 895 if ($resql) { 896 $out .= '<select id="select'.$htmlname.'" class="flat maxwidth200onsmartphone selectcountry'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" '.$htmloption.'>'; 897 $num = $this->db->num_rows($resql); 898 $i = 0; 899 if ($num) { 900 while ($i < $num) { 901 $obj = $this->db->fetch_object($resql); 902 903 $countryArray[$i]['rowid'] = $obj->rowid; 904 $countryArray[$i]['code_iso'] = $obj->code_iso; 905 $countryArray[$i]['code_iso3'] = $obj->code_iso3; 906 $countryArray[$i]['label'] = ($obj->code_iso && $langs->transnoentitiesnoconv("Country".$obj->code_iso) != "Country".$obj->code_iso ? $langs->transnoentitiesnoconv("Country".$obj->code_iso) : ($obj->label != '-' ? $obj->label : '')); 907 $countryArray[$i]['favorite'] = $obj->favorite; 908 $countryArray[$i]['eec'] = $obj->eec; 909 $favorite[$i] = $obj->favorite; 910 $label[$i] = dol_string_unaccent($countryArray[$i]['label']); 911 $i++; 912 } 913 914 if (empty($disablefavorites)) { 915 array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray); 916 } else { 917 $countryArray = dol_sort_array($countryArray, 'label'); 918 } 919 920 if ($showempty) { 921 $out .= '<option value=""> </option>'."\n"; 922 } 923 924 if ($addspecialentries) { // Add dedicated entries for groups of countries 925 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>'; 926 $out .= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>'; 927 $out .= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>'; 928 if ($mysoc->isInEEC()) { 929 $out .= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>'; 930 } 931 $out .= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>'; 932 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>'; 933 } 934 935 foreach ($countryArray as $row) { 936 //if (empty($showempty) && empty($row['rowid'])) continue; 937 if (empty($row['rowid'])) { 938 continue; 939 } 940 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) { 941 continue; // exclude some countries 942 } 943 944 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) { 945 $atleastonefavorite++; 946 } 947 if (empty($row['favorite']) && $atleastonefavorite) { 948 $atleastonefavorite = 0; 949 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>'; 950 } 951 952 $labeltoshow = ''; 953 if ($row['label']) { 954 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle'); 955 } else { 956 $labeltoshow .= ' '; 957 } 958 if ($row['code_iso']) { 959 $labeltoshow .= ' <span class="opacitymedium">('.$row['code_iso'].')</span>'; 960 if (empty($hideflags)) { 961 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"'); 962 $labeltoshow = $tmpflag.' '.$labeltoshow; 963 } 964 } 965 966 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) { 967 $out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" selected data-html="'.dol_escape_htmltag($labeltoshow).'" data-eec="'.((int) $row['eec']).'">'; 968 } else { 969 $out .= '<option value="'.($usecodeaskey ? ($usecodeaskey == 'code2' ? $row['code_iso'] : $row['code_iso3']) : $row['rowid']).'" data-html="'.dol_escape_htmltag($labeltoshow).'" data-eec="'.((int) $row['eec']).'">'; 970 } 971 $out .= $labeltoshow; 972 $out .= '</option>'."\n"; 973 } 974 } 975 $out .= '</select>'; 976 } else { 977 dol_print_error($this->db); 978 } 979 980 // Make select dynamic 981 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 982 $out .= ajax_combobox('select'.$htmlname, array(), 0, 0, 'resolve'); 983 984 return $out; 985 } 986 987 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 988 /** 989 * Return select list of incoterms 990 * 991 * @param string $selected Id or Code of preselected incoterm 992 * @param string $location_incoterms Value of input location 993 * @param string $page Defined the form action 994 * @param string $htmlname Name of html select object 995 * @param string $htmloption Options html on select object 996 * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) 997 * @param array $events Event options to run on change. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled'))) 998 * @return string HTML string with select and input 999 */ 1000 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array()) 1001 { 1002 // phpcs:enable 1003 global $conf, $langs; 1004 1005 $langs->load("dict"); 1006 1007 $out = ''; 1008 $incotermArray = array(); 1009 1010 $sql = "SELECT rowid, code"; 1011 $sql .= " FROM ".MAIN_DB_PREFIX."c_incoterms"; 1012 $sql .= " WHERE active > 0"; 1013 $sql .= " ORDER BY code ASC"; 1014 1015 dol_syslog(get_class($this)."::select_incoterm", LOG_DEBUG); 1016 $resql = $this->db->query($sql); 1017 if ($resql) { 1018 if ($conf->use_javascript_ajax && !$forcecombo) { 1019 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 1020 $out .= ajax_combobox($htmlname, $events); 1021 } 1022 1023 if (!empty($page)) { 1024 $out .= '<form method="post" action="'.$page.'">'; 1025 $out .= '<input type="hidden" name="action" value="set_incoterms">'; 1026 $out .= '<input type="hidden" name="token" value="'.newToken().'">'; 1027 } 1028 1029 $out .= '<select id="'.$htmlname.'" class="flat selectincoterm width75" name="'.$htmlname.'" '.$htmloption.'>'; 1030 $out .= '<option value="0"> </option>'; 1031 $num = $this->db->num_rows($resql); 1032 $i = 0; 1033 if ($num) { 1034 $foundselected = false; 1035 1036 while ($i < $num) { 1037 $obj = $this->db->fetch_object($resql); 1038 $incotermArray[$i]['rowid'] = $obj->rowid; 1039 $incotermArray[$i]['code'] = $obj->code; 1040 $i++; 1041 } 1042 1043 foreach ($incotermArray as $row) { 1044 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) { 1045 $out .= '<option value="'.$row['rowid'].'" selected>'; 1046 } else { 1047 $out .= '<option value="'.$row['rowid'].'">'; 1048 } 1049 1050 if ($row['code']) { 1051 $out .= $row['code']; 1052 } 1053 1054 $out .= '</option>'; 1055 } 1056 } 1057 $out .= '</select>'; 1058 1059 $out .= '<input id="location_incoterms" class="maxwidth100onsmartphone nomargintop nomarginbottom" name="location_incoterms" value="'.$location_incoterms.'">'; 1060 1061 if (!empty($page)) { 1062 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="'.$langs->trans("Modify").'"></form>'; 1063 } 1064 } else { 1065 dol_print_error($this->db); 1066 } 1067 1068 return $out; 1069 } 1070 1071 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1072 /** 1073 * Return list of types of lines (product or service) 1074 * Example: 0=product, 1=service, 9=other (for external module) 1075 * 1076 * @param string $selected Preselected type 1077 * @param string $htmlname Name of field in html form 1078 * @param int $showempty Add an empty field 1079 * @param int $hidetext Do not show label 'Type' before combo box (used only if there is at least 2 choices to select) 1080 * @param integer $forceall 1=Force to show products and services in combo list, whatever are activated modules, 0=No force, 2=Force to show only Products, 3=Force to show only services, -1=Force none (and set hidden field to 'service') 1081 * @return void 1082 */ 1083 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0) 1084 { 1085 // phpcs:enable 1086 global $db, $langs, $user, $conf; 1087 1088 // If product & services are enabled or both disabled. 1089 if ($forceall == 1 || (empty($forceall) && !empty($conf->product->enabled) && !empty($conf->service->enabled)) 1090 || (empty($forceall) && empty($conf->product->enabled) && empty($conf->service->enabled))) { 1091 if (empty($hidetext)) { 1092 print $langs->trans("Type").': '; 1093 } 1094 print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">'; 1095 if ($showempty) { 1096 print '<option value="-1"'; 1097 if ($selected == -1) { 1098 print ' selected'; 1099 } 1100 print '> </option>'; 1101 } 1102 1103 print '<option value="0"'; 1104 if (0 == $selected) { 1105 print ' selected'; 1106 } 1107 print '>'.$langs->trans("Product"); 1108 1109 print '<option value="1"'; 1110 if (1 == $selected) { 1111 print ' selected'; 1112 } 1113 print '>'.$langs->trans("Service"); 1114 1115 print '</select>'; 1116 print ajax_combobox('select_'.$htmlname); 1117 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); 1118 } 1119 if ((empty($forceall) && empty($conf->product->enabled) && !empty($conf->service->enabled)) || $forceall == 3) { 1120 print $langs->trans("Service"); 1121 print '<input type="hidden" name="'.$htmlname.'" value="1">'; 1122 } 1123 if ((empty($forceall) && !empty($conf->product->enabled) && empty($conf->service->enabled)) || $forceall == 2) { 1124 print $langs->trans("Product"); 1125 print '<input type="hidden" name="'.$htmlname.'" value="0">'; 1126 } 1127 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled. 1128 print '<input type="hidden" name="'.$htmlname.'" value="1">'; // By default we set on service for contract. If CONTRACT_SUPPORT_PRODUCTS is set, forceall should be 1 not -1 1129 } 1130 } 1131 1132 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1133 /** 1134 * Load into cache cache_types_fees, array of types of fees 1135 * 1136 * @return int Nb of lines loaded, <0 if KO 1137 */ 1138 public function load_cache_types_fees() 1139 { 1140 // phpcs:enable 1141 global $langs; 1142 1143 $num = count($this->cache_types_fees); 1144 if ($num > 0) { 1145 return 0; // Cache already loaded 1146 } 1147 1148 dol_syslog(__METHOD__, LOG_DEBUG); 1149 1150 $langs->load("trips"); 1151 1152 $sql = "SELECT c.code, c.label"; 1153 $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as c"; 1154 $sql .= " WHERE active > 0"; 1155 1156 $resql = $this->db->query($sql); 1157 if ($resql) { 1158 $num = $this->db->num_rows($resql); 1159 $i = 0; 1160 1161 while ($i < $num) { 1162 $obj = $this->db->fetch_object($resql); 1163 1164 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut 1165 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label)); 1166 $this->cache_types_fees[$obj->code] = $label; 1167 $i++; 1168 } 1169 1170 asort($this->cache_types_fees); 1171 1172 return $num; 1173 } else { 1174 dol_print_error($this->db); 1175 return -1; 1176 } 1177 } 1178 1179 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1180 /** 1181 * Return list of types of notes 1182 * 1183 * @param string $selected Preselected type 1184 * @param string $htmlname Name of field in form 1185 * @param int $showempty Add an empty field 1186 * @return void 1187 */ 1188 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0) 1189 { 1190 // phpcs:enable 1191 global $user, $langs; 1192 1193 dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG); 1194 1195 $this->load_cache_types_fees(); 1196 1197 print '<select id="select_'.$htmlname.'" class="flat" name="'.$htmlname.'">'; 1198 if ($showempty) { 1199 print '<option value="-1"'; 1200 if ($selected == -1) { 1201 print ' selected'; 1202 } 1203 print '> </option>'; 1204 } 1205 1206 foreach ($this->cache_types_fees as $key => $value) { 1207 print '<option value="'.$key.'"'; 1208 if ($key == $selected) { 1209 print ' selected'; 1210 } 1211 print '>'; 1212 print $value; 1213 print '</option>'; 1214 } 1215 1216 print '</select>'; 1217 if ($user->admin) { 1218 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 1219 } 1220 } 1221 1222 1223 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1224 /** 1225 * Output html form to select a third party 1226 * 1227 * @param string $selected Preselected type 1228 * @param string $htmlname Name of field in form 1229 * @param string $filter Optional filters criteras. WARNING: To avoid SQL injection, only few chars [.a-z0-9 =<>] are allowed here (example: 's.rowid <> x', 's.client IN (1,3)') 1230 * @param string $showempty Add an empty field (Can be '1' or text key to use on empty line like 'SelectThirdParty') 1231 * @param int $showtype Show third party type in combolist (customer, prospect or supplier) 1232 * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) 1233 * @param array $events Ajax event options to run on change. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled'))) 1234 * @param int $limit Maximum number of elements 1235 * @param string $morecss Add more css styles to the SELECT component 1236 * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container 1237 * @param string $selected_input_value Value of preselected input text (for use with ajax) 1238 * @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after) 1239 * @param array $ajaxoptions Options for ajax_autocompleter 1240 * @param bool $multiple add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter) 1241 * @param array $excludeids Exclude IDs from the select combo 1242 * @return string HTML string with select box for thirdparty. 1243 */ 1244 public function select_company($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $limit = 0, $morecss = 'minwidth100', $moreparam = '', $selected_input_value = '', $hidelabel = 1, $ajaxoptions = array(), $multiple = false, $excludeids = array()) 1245 { 1246 // phpcs:enable 1247 global $conf, $user, $langs; 1248 1249 $out = ''; 1250 1251 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT) && !$forcecombo) { 1252 if (is_null($ajaxoptions)) { 1253 $ajaxoptions = array(); 1254 } 1255 1256 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; 1257 1258 // No immediate load of all database 1259 $placeholder = ''; 1260 if ($selected && empty($selected_input_value)) { 1261 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; 1262 $societetmp = new Societe($this->db); 1263 $societetmp->fetch($selected); 1264 $selected_input_value = $societetmp->name; 1265 unset($societetmp); 1266 } 1267 // mode 1 1268 $urloption = 'htmlname='.urlencode($htmlname).'&outjson=1&filter='.urlencode($filter).(empty($excludeids) ? '' : '&excludeids='.join(',', $excludeids)).($showtype ? '&showtype='.urlencode($showtype) : ''); 1269 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, $conf->global->COMPANY_USE_SEARCH_TO_SELECT, 0, $ajaxoptions); 1270 1271 $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>'; 1272 if (empty($hidelabel)) { 1273 print $langs->trans("RefOrLabel").' : '; 1274 } elseif ($hidelabel > 1) { 1275 $placeholder = $langs->trans("RefOrLabel"); 1276 if ($hidelabel == 2) { 1277 $out .= img_picto($langs->trans("Search"), 'search'); 1278 } 1279 } 1280 $out .= '<input type="text" class="'.$morecss.'" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '').' '.(!empty($conf->global->THIRDPARTY_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />'; 1281 if ($hidelabel == 3) { 1282 $out .= img_picto($langs->trans("Search"), 'search'); 1283 } 1284 } else { 1285 // Immediate load of all database 1286 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids); 1287 } 1288 1289 return $out; 1290 } 1291 1292 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1293 /** 1294 * Output html form to select a third party. 1295 * Note, you must use the select_company to get the component to select a third party. This function must only be called by select_company. 1296 * 1297 * @param string $selected Preselected type 1298 * @param string $htmlname Name of field in form 1299 * @param string $filter Optional filters criteras (example: 's.rowid NOT IN (x)', 's.client IN (1,3)'). Do not use a filter coming from input of users. 1300 * @param string $showempty Add an empty field (Can be '1' or text to use on empty line like 'SelectThirdParty') 1301 * @param int $showtype Show third party type in combolist (customer, prospect or supplier) 1302 * @param int $forcecombo Force to use standard HTML select component without beautification 1303 * @param array $events Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled'))) 1304 * @param string $filterkey Filter on key value 1305 * @param int $outputmode 0=HTML select string, 1=Array 1306 * @param int $limit Limit number of answers 1307 * @param string $morecss Add more css styles to the SELECT component 1308 * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container 1309 * @param bool $multiple add [] in the name of element and add 'multiple' attribut 1310 * @param array $excludeids Exclude IDs from the select combo 1311 * @return string HTML string with 1312 */ 1313 public function select_thirdparty_list($selected = '', $htmlname = 'socid', $filter = '', $showempty = '', $showtype = 0, $forcecombo = 0, $events = array(), $filterkey = '', $outputmode = 0, $limit = 0, $morecss = 'minwidth100', $moreparam = '', $multiple = false, $excludeids = array()) 1314 { 1315 // phpcs:enable 1316 global $conf, $user, $langs; 1317 1318 $out = ''; 1319 $num = 0; 1320 $outarray = array(); 1321 1322 if ($selected === '') { 1323 $selected = array(); 1324 } elseif (!is_array($selected)) { 1325 $selected = array($selected); 1326 } 1327 1328 // Clean $filter that may contains sql conditions so sql code 1329 if (function_exists('testSqlAndScriptInject')) { 1330 if (testSqlAndScriptInject($filter, 3) > 0) { 1331 $filter = ''; 1332 } 1333 } 1334 1335 // We search companies 1336 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.client, s.fournisseur, s.code_client, s.code_fournisseur"; 1337 if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { 1338 $sql .= ", s.address, s.zip, s.town"; 1339 $sql .= ", dictp.code as country_code"; 1340 } 1341 $sql .= " FROM ".MAIN_DB_PREFIX."societe as s"; 1342 if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { 1343 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as dictp ON dictp.rowid = s.fk_pays"; 1344 } 1345 if (!$user->rights->societe->client->voir && !$user->socid) { 1346 $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; 1347 } 1348 $sql .= " WHERE s.entity IN (".getEntity('societe').")"; 1349 if (!empty($user->socid)) { 1350 $sql .= " AND s.rowid = ".((int) $user->socid); 1351 } 1352 if ($filter) { 1353 $sql .= " AND (".$filter.")"; 1354 } 1355 if (!$user->rights->societe->client->voir && !$user->socid) { 1356 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id); 1357 } 1358 if (!empty($conf->global->COMPANY_HIDE_INACTIVE_IN_COMBOBOX)) { 1359 $sql .= " AND s.status <> 0"; 1360 } 1361 if (!empty($excludeids)) { 1362 $sql .= " AND s.rowid NOT IN (".$this->db->sanitize(join(',', $excludeids)).")"; 1363 } 1364 // Add criteria 1365 if ($filterkey && $filterkey != '') { 1366 $sql .= " AND ("; 1367 $prefix = empty($conf->global->COMPANY_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on 1368 // For natural search 1369 $scrit = explode(' ', $filterkey); 1370 $i = 0; 1371 if (count($scrit) > 1) { 1372 $sql .= "("; 1373 } 1374 foreach ($scrit as $crit) { 1375 if ($i > 0) { 1376 $sql .= " AND "; 1377 } 1378 $sql .= "(s.nom LIKE '".$this->db->escape($prefix.$crit)."%')"; 1379 $i++; 1380 } 1381 if (count($scrit) > 1) { 1382 $sql .= ")"; 1383 } 1384 if (!empty($conf->barcode->enabled)) { 1385 $sql .= " OR s.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; 1386 } 1387 $sql .= " OR s.code_client LIKE '".$this->db->escape($prefix.$filterkey)."%' OR s.code_fournisseur LIKE '".$this->db->escape($prefix.$filterkey)."%'"; 1388 $sql .= ")"; 1389 } 1390 $sql .= $this->db->order("nom", "ASC"); 1391 $sql .= $this->db->plimit($limit, 0); 1392 1393 // Build output string 1394 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG); 1395 $resql = $this->db->query($sql); 1396 if ($resql) { 1397 if (!$forcecombo) { 1398 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 1399 $out .= ajax_combobox($htmlname, $events, $conf->global->COMPANY_USE_SEARCH_TO_SELECT); 1400 } 1401 1402 // Construct $out and $outarray 1403 $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').'>'."\n"; 1404 1405 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : ''); 1406 if (!empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) { 1407 // Do not use textifempty = ' ' or ' ' here, or search on key will search on ' key'. 1408 //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty=''; 1409 if ($showempty && !is_numeric($showempty)) { 1410 $textifempty = $langs->trans($showempty); 1411 } else { 1412 $textifempty .= $langs->trans("All"); 1413 } 1414 } 1415 if ($showempty) { 1416 $out .= '<option value="-1" data-html="'.dol_escape_htmltag('<span class="opacitymedium">'.($textifempty ? $textifempty : ' ').'</span>').'">'.$textifempty.'</option>'."\n"; 1417 } 1418 1419 $num = $this->db->num_rows($resql); 1420 $i = 0; 1421 if ($num) { 1422 while ($i < $num) { 1423 $obj = $this->db->fetch_object($resql); 1424 $label = ''; 1425 if ($conf->global->SOCIETE_ADD_REF_IN_LIST) { 1426 if (($obj->client) && (!empty($obj->code_client))) { 1427 $label = $obj->code_client.' - '; 1428 } 1429 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) { 1430 $label .= $obj->code_fournisseur.' - '; 1431 } 1432 $label .= ' '.$obj->name; 1433 } else { 1434 $label = $obj->name; 1435 } 1436 1437 if (!empty($obj->name_alias)) { 1438 $label .= ' ('.$obj->name_alias.')'; 1439 } 1440 1441 if ($showtype) { 1442 if ($obj->client || $obj->fournisseur) { 1443 $label .= ' ('; 1444 } 1445 if ($obj->client == 1 || $obj->client == 3) { 1446 $label .= $langs->trans("Customer"); 1447 } 1448 if ($obj->client == 2 || $obj->client == 3) { 1449 $label .= ($obj->client == 3 ? ', ' : '').$langs->trans("Prospect"); 1450 } 1451 if ($obj->fournisseur) { 1452 $label .= ($obj->client ? ', ' : '').$langs->trans("Supplier"); 1453 } 1454 if ($obj->client || $obj->fournisseur) { 1455 $label .= ')'; 1456 } 1457 } 1458 1459 if (!empty($conf->global->COMPANY_SHOW_ADDRESS_SELECTLIST)) { 1460 $label .= ($obj->address ? ' - '.$obj->address : '').($obj->zip ? ' - '.$obj->zip : '').($obj->town ? ' '.$obj->town : ''); 1461 if (!empty($obj->country_code)) { 1462 $label .= ', '.$langs->trans('Country'.$obj->country_code); 1463 } 1464 } 1465 1466 if (empty($outputmode)) { 1467 if (in_array($obj->rowid, $selected)) { 1468 $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>'; 1469 } else { 1470 $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>'; 1471 } 1472 } else { 1473 array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label)); 1474 } 1475 1476 $i++; 1477 if (($i % 10) == 0) { 1478 $out .= "\n"; 1479 } 1480 } 1481 } 1482 $out .= '</select>'."\n"; 1483 } else { 1484 dol_print_error($this->db); 1485 } 1486 1487 $this->result = array('nbofthirdparties'=>$num); 1488 1489 if ($outputmode) { 1490 return $outarray; 1491 } 1492 return $out; 1493 } 1494 1495 1496 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1497 /** 1498 * Return HTML combo list of absolute discounts 1499 * 1500 * @param string $selected Id remise fixe pre-selectionnee 1501 * @param string $htmlname Nom champ formulaire 1502 * @param string $filter Criteres optionnels de filtre 1503 * @param int $socid Id of thirdparty 1504 * @param int $maxvalue Max value for lines that can be selected 1505 * @return int Return number of qualifed lines in list 1506 */ 1507 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0) 1508 { 1509 // phpcs:enable 1510 global $langs, $conf; 1511 1512 // On recherche les remises 1513 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,"; 1514 $sql .= " re.description, re.fk_facture_source"; 1515 $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re"; 1516 $sql .= " WHERE re.fk_soc = ".(int) $socid; 1517 $sql .= " AND re.entity = ".$conf->entity; 1518 if ($filter) { 1519 $sql .= " AND ".$filter; 1520 } 1521 $sql .= " ORDER BY re.description ASC"; 1522 1523 dol_syslog(get_class($this)."::select_remises", LOG_DEBUG); 1524 $resql = $this->db->query($sql); 1525 if ($resql) { 1526 print '<select id="select_'.$htmlname.'" class="flat maxwidthonsmartphone" name="'.$htmlname.'">'; 1527 $num = $this->db->num_rows($resql); 1528 1529 $qualifiedlines = $num; 1530 1531 $i = 0; 1532 if ($num) { 1533 print '<option value="0"> </option>'; 1534 while ($i < $num) { 1535 $obj = $this->db->fetch_object($resql); 1536 $desc = dol_trunc($obj->description, 40); 1537 if (preg_match('/\(CREDIT_NOTE\)/', $desc)) { 1538 $desc = preg_replace('/\(CREDIT_NOTE\)/', $langs->trans("CreditNote"), $desc); 1539 } 1540 if (preg_match('/\(DEPOSIT\)/', $desc)) { 1541 $desc = preg_replace('/\(DEPOSIT\)/', $langs->trans("Deposit"), $desc); 1542 } 1543 if (preg_match('/\(EXCESS RECEIVED\)/', $desc)) { 1544 $desc = preg_replace('/\(EXCESS RECEIVED\)/', $langs->trans("ExcessReceived"), $desc); 1545 } 1546 if (preg_match('/\(EXCESS PAID\)/', $desc)) { 1547 $desc = preg_replace('/\(EXCESS PAID\)/', $langs->trans("ExcessPaid"), $desc); 1548 } 1549 1550 $selectstring = ''; 1551 if ($selected > 0 && $selected == $obj->rowid) { 1552 $selectstring = ' selected'; 1553 } 1554 1555 $disabled = ''; 1556 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) { 1557 $qualifiedlines--; 1558 $disabled = ' disabled'; 1559 } 1560 1561 if (!empty($conf->global->MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST) && !empty($obj->fk_facture_source)) { 1562 $tmpfac = new Facture($this->db); 1563 if ($tmpfac->fetch($obj->fk_facture_source) > 0) { 1564 $desc = $desc.' - '.$tmpfac->ref; 1565 } 1566 } 1567 1568 print '<option value="'.$obj->rowid.'"'.$selectstring.$disabled.'>'.$desc.' ('.price($obj->amount_ht).' '.$langs->trans("HT").' - '.price($obj->amount_ttc).' '.$langs->trans("TTC").')</option>'; 1569 $i++; 1570 } 1571 } 1572 print '</select>'; 1573 return $qualifiedlines; 1574 } else { 1575 dol_print_error($this->db); 1576 return -1; 1577 } 1578 } 1579 1580 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1581 /** 1582 * Return list of all contacts (for a third party or all) 1583 * 1584 * @param int $socid Id ot third party or 0 for all 1585 * @param string $selected Id contact pre-selectionne 1586 * @param string $htmlname Name of HTML field ('none' for a not editable field) 1587 * @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 1588 * @param string $exclude List of contacts id to exclude 1589 * @param string $limitto Disable answers that are not id in this array list 1590 * @param integer $showfunction Add function into label 1591 * @param string $moreclass Add more class to class style 1592 * @param integer $showsoc Add company into label 1593 * @param int $forcecombo Force to use combo box 1594 * @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'))) 1595 * @param bool $options_only Return options only (for ajax treatment) 1596 * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container 1597 * @param string $htmlid Html id to use instead of htmlname 1598 * @return int <0 if KO, Nb of contact in list if OK 1599 * @deprecated You can use selectcontacts directly (warning order of param was changed) 1600 */ 1601 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 = '') 1602 { 1603 // phpcs:enable 1604 print $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $moreclass, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid); 1605 return $this->num; 1606 } 1607 1608 /** 1609 * Return HTML code of the SELECT of list of all contacts (for a third party or all). 1610 * This also set the number of contacts found into $this->num 1611 * 1612 * @since 9.0 Add afterSelectContactOptions hook 1613 * 1614 * @param int $socid Id ot third party or 0 for all or -1 for empty list 1615 * @param array|int $selected Array of ID of pre-selected contact id 1616 * @param string $htmlname Name of HTML field ('none' for a not editable field) 1617 * @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 1618 * @param string $exclude List of contacts id to exclude 1619 * @param string $limitto Disable answers that are not id in this array list 1620 * @param integer $showfunction Add function into label 1621 * @param string $moreclass Add more class to class style 1622 * @param bool $options_only Return options only (for ajax treatment) 1623 * @param integer $showsoc Add company into label 1624 * @param int $forcecombo Force to use combo box (so no ajax beautify effect) 1625 * @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'))) 1626 * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container 1627 * @param string $htmlid Html id to use instead of htmlname 1628 * @param bool $multiple add [] in the name of element and add 'multiple' attribut 1629 * @param integer $disableifempty Set tag 'disabled' on select if there is no choice 1630 * @return int|string <0 if KO, HTML with select string if OK. 1631 */ 1632 public function selectcontacts($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $moreclass = '', $options_only = false, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0) 1633 { 1634 global $conf, $langs, $hookmanager, $action; 1635 1636 $langs->load('companies'); 1637 1638 if (empty($htmlid)) { 1639 $htmlid = $htmlname; 1640 } 1641 $num = 0; 1642 1643 if ($selected === '') { 1644 $selected = array(); 1645 } elseif (!is_array($selected)) { 1646 $selected = array($selected); 1647 } 1648 $out = ''; 1649 1650 if (!is_object($hookmanager)) { 1651 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; 1652 $hookmanager = new HookManager($this->db); 1653 } 1654 1655 // We search third parties 1656 $sql = "SELECT sp.rowid, sp.lastname, sp.statut, sp.firstname, sp.poste, sp.email, sp.phone, sp.phone_perso, sp.phone_mobile, sp.town AS contact_town"; 1657 if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) { 1658 $sql .= ", s.nom as company, s.town AS company_town"; 1659 } 1660 $sql .= " FROM ".MAIN_DB_PREFIX."socpeople as sp"; 1661 if ($showsoc > 0 || !empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) { 1662 $sql .= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid=sp.fk_soc"; 1663 } 1664 $sql .= " WHERE sp.entity IN (".getEntity('socpeople').")"; 1665 if ($socid > 0 || $socid == -1) { 1666 $sql .= " AND sp.fk_soc = ".((int) $socid); 1667 } 1668 if (!empty($conf->global->CONTACT_HIDE_INACTIVE_IN_COMBOBOX)) { 1669 $sql .= " AND sp.statut <> 0"; 1670 } 1671 $sql .= " ORDER BY sp.lastname ASC"; 1672 1673 dol_syslog(get_class($this)."::selectcontacts", LOG_DEBUG); 1674 $resql = $this->db->query($sql); 1675 if ($resql) { 1676 $num = $this->db->num_rows($resql); 1677 1678 if ($htmlname != 'none' && !$options_only) { 1679 $out .= '<select class="flat'.($moreclass ? ' '.$moreclass : '').'" id="'.$htmlid.'" name="'.$htmlname.(($num || empty($disableifempty)) ? '' : ' disabled').($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.(!empty($moreparam) ? $moreparam : '').'>'; 1680 } 1681 1682 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) { 1683 $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'> </option>'; 1684 } 1685 if ($showempty == 2) { 1686 $out .= '<option value="0"'.(in_array(0, $selected) ? ' selected' : '').'>-- '.$langs->trans("Internal").' --</option>'; 1687 } 1688 1689 $i = 0; 1690 if ($num) { 1691 include_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; 1692 $contactstatic = new Contact($this->db); 1693 1694 while ($i < $num) { 1695 $obj = $this->db->fetch_object($resql); 1696 1697 // Set email (or phones) and town extended infos 1698 $extendedInfos = ''; 1699 if (!empty($conf->global->CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST)) { 1700 $extendedInfos = array(); 1701 $email = trim($obj->email); 1702 if (!empty($email)) { 1703 $extendedInfos[] = $email; 1704 } else { 1705 $phone = trim($obj->phone); 1706 $phone_perso = trim($obj->phone_perso); 1707 $phone_mobile = trim($obj->phone_mobile); 1708 if (!empty($phone)) { 1709 $extendedInfos[] = $phone; 1710 } 1711 if (!empty($phone_perso)) { 1712 $extendedInfos[] = $phone_perso; 1713 } 1714 if (!empty($phone_mobile)) { 1715 $extendedInfos[] = $phone_mobile; 1716 } 1717 } 1718 $contact_town = trim($obj->contact_town); 1719 $company_town = trim($obj->company_town); 1720 if (!empty($contact_town)) { 1721 $extendedInfos[] = $contact_town; 1722 } elseif (!empty($company_town)) { 1723 $extendedInfos[] = $company_town; 1724 } 1725 $extendedInfos = implode(' - ', $extendedInfos); 1726 if (!empty($extendedInfos)) { 1727 $extendedInfos = ' - '.$extendedInfos; 1728 } 1729 } 1730 1731 $contactstatic->id = $obj->rowid; 1732 $contactstatic->lastname = $obj->lastname; 1733 $contactstatic->firstname = $obj->firstname; 1734 if ($obj->statut == 1) { 1735 if ($htmlname != 'none') { 1736 $disabled = 0; 1737 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) { 1738 $disabled = 1; 1739 } 1740 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) { 1741 $disabled = 1; 1742 } 1743 if (!empty($selected) && in_array($obj->rowid, $selected)) { 1744 $out .= '<option value="'.$obj->rowid.'"'; 1745 if ($disabled) { 1746 $out .= ' disabled'; 1747 } 1748 $out .= ' selected>'; 1749 $out .= $contactstatic->getFullName($langs).$extendedInfos; 1750 if ($showfunction && $obj->poste) { 1751 $out .= ' ('.$obj->poste.')'; 1752 } 1753 if (($showsoc > 0) && $obj->company) { 1754 $out .= ' - ('.$obj->company.')'; 1755 } 1756 $out .= '</option>'; 1757 } else { 1758 $out .= '<option value="'.$obj->rowid.'"'; 1759 if ($disabled) { 1760 $out .= ' disabled'; 1761 } 1762 $out .= '>'; 1763 $out .= $contactstatic->getFullName($langs).$extendedInfos; 1764 if ($showfunction && $obj->poste) { 1765 $out .= ' ('.$obj->poste.')'; 1766 } 1767 if (($showsoc > 0) && $obj->company) { 1768 $out .= ' - ('.$obj->company.')'; 1769 } 1770 $out .= '</option>'; 1771 } 1772 } else { 1773 if (in_array($obj->rowid, $selected)) { 1774 $out .= $contactstatic->getFullName($langs).$extendedInfos; 1775 if ($showfunction && $obj->poste) { 1776 $out .= ' ('.$obj->poste.')'; 1777 } 1778 if (($showsoc > 0) && $obj->company) { 1779 $out .= ' - ('.$obj->company.')'; 1780 } 1781 } 1782 } 1783 } 1784 $i++; 1785 } 1786 } else { 1787 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst'); 1788 $out .= '<option class="disabled" value="-1"'.(($showempty == 2 || $multiple) ? '' : ' selected').' disabled="disabled">'; 1789 $out .= $labeltoshow; 1790 $out .= '</option>'; 1791 } 1792 1793 $parameters = array( 1794 'socid'=>$socid, 1795 'htmlname'=>$htmlname, 1796 'resql'=>$resql, 1797 'out'=>&$out, 1798 'showfunction'=>$showfunction, 1799 'showsoc'=>$showsoc, 1800 ); 1801 1802 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks 1803 1804 if ($htmlname != 'none' && !$options_only) { 1805 $out .= '</select>'; 1806 } 1807 1808 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) { 1809 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 1810 $out .= ajax_combobox($htmlid, $events, $conf->global->CONTACT_USE_SEARCH_TO_SELECT); 1811 } 1812 1813 $this->num = $num; 1814 return $out; 1815 } else { 1816 dol_print_error($this->db); 1817 return -1; 1818 } 1819 } 1820 1821 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1822 /** 1823 * Return the HTML select list of users 1824 * 1825 * @param string $selected Id user preselected 1826 * @param string $htmlname Field name in form 1827 * @param int $show_empty 0=liste sans valeur nulle, 1=ajoute valeur inconnue 1828 * @param array $exclude Array list of users id to exclude 1829 * @param int $disabled If select list must be disabled 1830 * @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 1831 * @param int $enableonly Array list of users id to be enabled. All other must be disabled 1832 * @param string $force_entity '0' or Ids of environment to force 1833 * @return void 1834 * @deprecated Use select_dolusers instead 1835 * @see select_dolusers() 1836 */ 1837 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '0') 1838 { 1839 // phpcs:enable 1840 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity); 1841 } 1842 1843 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 1844 /** 1845 * Return select list of users 1846 * 1847 * @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) 1848 * @param string $htmlname Field name in form 1849 * @param int|string $show_empty 0=list with no empty value, 1=add also an empty value into list 1850 * @param array $exclude Array list of users id to exclude 1851 * @param int $disabled If select list must be disabled 1852 * @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 1853 * @param array $enableonly Array list of users id to be enabled. If defined, it means that others will be disabled 1854 * @param string $force_entity '0' or Ids of environment to force 1855 * @param int $maxlength Maximum length of string into list (0=no limit) 1856 * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status 1857 * @param string $morefilter Add more filters into sql request (Example: 'employee = 1'). This value must not come from user input. 1858 * @param integer $show_every 0=default list, 1=add also a value "Everybody" at beginning of list 1859 * @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. 1860 * @param string $morecss More css 1861 * @param int $noactive Show only active users (this will also happened whatever is this option if USER_HIDE_INACTIVE_IN_COMBOBOX is on). 1862 * @param int $outputmode 0=HTML select string, 1=Array 1863 * @param bool $multiple add [] in the name of element and add 'multiple' attribut 1864 * @return string HTML select string 1865 * @see select_dolgroups() 1866 */ 1867 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) 1868 { 1869 // phpcs:enable 1870 global $conf, $user, $langs, $hookmanager; 1871 1872 // If no preselected user defined, we take current user 1873 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && empty($conf->global->SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE)) { 1874 $selected = $user->id; 1875 } 1876 1877 if ($selected === '') { 1878 $selected = array(); 1879 } elseif (!is_array($selected)) { 1880 $selected = array($selected); 1881 } 1882 1883 $excludeUsers = null; 1884 $includeUsers = null; 1885 1886 // Permettre l'exclusion d'utilisateurs 1887 if (is_array($exclude)) { 1888 $excludeUsers = implode(",", $exclude); 1889 } 1890 // Permettre l'inclusion d'utilisateurs 1891 if (is_array($include)) { 1892 $includeUsers = implode(",", $include); 1893 } elseif ($include == 'hierarchy') { 1894 // Build list includeUsers to have only hierarchy 1895 $includeUsers = implode(",", $user->getAllChildIds(0)); 1896 } elseif ($include == 'hierarchyme') { 1897 // Build list includeUsers to have only hierarchy and current user 1898 $includeUsers = implode(",", $user->getAllChildIds(1)); 1899 } 1900 1901 $out = ''; 1902 $outarray = array(); 1903 1904 // Forge request to select users 1905 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.photo"; 1906 if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) { 1907 $sql .= ", e.label"; 1908 } 1909 $sql .= " FROM ".MAIN_DB_PREFIX."user as u"; 1910 if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) { 1911 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid = u.entity"; 1912 if ($force_entity) { 1913 $sql .= " WHERE u.entity IN (0, ".$this->db->sanitize($force_entity).")"; 1914 } else { 1915 $sql .= " WHERE u.entity IS NOT NULL"; 1916 } 1917 } else { 1918 if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { 1919 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug"; 1920 $sql .= " ON ug.fk_user = u.rowid"; 1921 $sql .= " WHERE ug.entity = ".$conf->entity; 1922 } else { 1923 $sql .= " WHERE u.entity IN (0, ".$conf->entity.")"; 1924 } 1925 } 1926 if (!empty($user->socid)) { 1927 $sql .= " AND u.fk_soc = ".((int) $user->socid); 1928 } 1929 if (is_array($exclude) && $excludeUsers) { 1930 $sql .= " AND u.rowid NOT IN (".$this->db->sanitize($excludeUsers).")"; 1931 } 1932 if ($includeUsers) { 1933 $sql .= " AND u.rowid IN (".$this->db->sanitize($includeUsers).")"; 1934 } 1935 if (!empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX) || $noactive) { 1936 $sql .= " AND u.statut <> 0"; 1937 } 1938 if (!empty($morefilter)) { 1939 $sql .= " ".$morefilter; 1940 } 1941 1942 //Add hook to filter on user (for exemple on usergroup define in custom modules) 1943 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action); 1944 if (!empty($reshook)) { 1945 $sql .= $hookmanager->resPrint; 1946 } 1947 1948 if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname 1949 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC"; 1950 } else { 1951 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC"; 1952 } 1953 1954 dol_syslog(get_class($this)."::select_dolusers", LOG_DEBUG); 1955 1956 $resql = $this->db->query($sql); 1957 if ($resql) { 1958 $num = $this->db->num_rows($resql); 1959 $i = 0; 1960 if ($num) { 1961 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined 1962 $out .= '<select class="flat'.($morecss ? ' '.$morecss : ' minwidth200').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>'; 1963 if ($show_empty && !$multiple) { 1964 $textforempty = ' '; 1965 if (!empty($conf->use_javascript_ajax)) { 1966 $textforempty = ' '; // If we use ajaxcombo, we need here to avoid to have an empty element that is too small. 1967 } 1968 if (!is_numeric($show_empty)) { 1969 $textforempty = $show_empty; 1970 } 1971 $out .= '<option class="optiongrey" value="'.($show_empty < 0 ? $show_empty : -1).'"'.((empty($selected) || in_array(-1, $selected)) ? ' selected' : '').'>'.$textforempty.'</option>'."\n"; 1972 } 1973 if ($show_every) { 1974 $out .= '<option value="-2"'.((in_array(-2, $selected)) ? ' selected' : '').'>-- '.$langs->trans("Everybody").' --</option>'."\n"; 1975 } 1976 1977 $userstatic = new User($this->db); 1978 1979 while ($i < $num) { 1980 $obj = $this->db->fetch_object($resql); 1981 1982 $userstatic->id = $obj->rowid; 1983 $userstatic->lastname = $obj->lastname; 1984 $userstatic->firstname = $obj->firstname; 1985 $userstatic->photo = $obj->photo; 1986 $userstatic->statut = $obj->status; 1987 $userstatic->entity = $obj->entity; 1988 $userstatic->admin = $obj->admin; 1989 1990 $disableline = ''; 1991 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) { 1992 $disableline = ($enableonlytext ? $enableonlytext : '1'); 1993 } 1994 1995 $labeltoshow = ''; 1996 1997 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0) 1998 $fullNameMode = 0; 1999 if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) { 2000 $fullNameMode = 1; //Firstname+lastname 2001 } 2002 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength); 2003 if (empty($obj->firstname) && empty($obj->lastname)) { 2004 $labeltoshow .= $obj->login; 2005 } 2006 2007 // Complete name with more info 2008 $moreinfo = ''; 2009 if (!empty($conf->global->MAIN_SHOW_LOGIN)) { 2010 $moreinfo .= ($moreinfo ? ' - ' : ' (').$obj->login; 2011 } 2012 if ($showstatus >= 0) { 2013 if ($obj->status == 1 && $showstatus == 1) { 2014 $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Enabled'); 2015 } 2016 if ($obj->status == 0 && $showstatus == 1) { 2017 $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans('Disabled'); 2018 } 2019 } 2020 if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && !$user->entity) { 2021 if (!$obj->entity) { 2022 $moreinfo .= ($moreinfo ? ' - ' : ' (').$langs->trans("AllEntities"); 2023 } else { 2024 if ($obj->entity != $conf->entity) { 2025 $moreinfo .= ($moreinfo ? ' - ' : ' (').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined")); 2026 } 2027 } 2028 } 2029 $moreinfo .= ($moreinfo ? ')' : ''); 2030 if ($disableline && $disableline != '1') { 2031 $moreinfo .= ' - '.$disableline; // This is text from $enableonlytext parameter 2032 } 2033 $labeltoshow .= $moreinfo; 2034 2035 $out .= '<option value="'.$obj->rowid.'"'; 2036 if ($disableline) { 2037 $out .= ' disabled'; 2038 } 2039 if ((is_object($selected) && $selected->id == $obj->rowid) || (!is_object($selected) && in_array($obj->rowid, $selected))) { 2040 $out .= ' selected'; 2041 } 2042 $out .= ' data-html="'; 2043 $outhtml = ''; 2044 // if (!empty($obj->photo)) { 2045 $outhtml .= $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1).' '; 2046 // } 2047 if ($showstatus >= 0 && $obj->status == 0) { 2048 $outhtml .= '<strike class="opacitymediumxxx">'; 2049 } 2050 $outhtml .= $labeltoshow; 2051 if ($showstatus >= 0 && $obj->status == 0) { 2052 $outhtml .= '</strike>'; 2053 } 2054 $out .= dol_escape_htmltag($outhtml); 2055 $out .= '">'; 2056 $out .= $labeltoshow; 2057 $out .= '</option>'; 2058 2059 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength).$moreinfo; 2060 2061 $i++; 2062 } 2063 } else { 2064 $out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'" disabled>'; 2065 $out .= '<option value="">'.$langs->trans("None").'</option>'; 2066 } 2067 $out .= '</select>'; 2068 2069 if ($num) { 2070 // Enhance with select2 2071 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 2072 $out .= ajax_combobox($htmlname); 2073 } 2074 } else { 2075 dol_print_error($this->db); 2076 } 2077 2078 if ($outputmode) { 2079 return $outarray; 2080 } 2081 return $out; 2082 } 2083 2084 2085 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 2086 /** 2087 * Return select list of users. Selected users are stored into session. 2088 * List of users are provided into $_SESSION['assignedtouser']. 2089 * 2090 * @param string $action Value for $action 2091 * @param string $htmlname Field name in form 2092 * @param int $show_empty 0=list without the empty value, 1=add empty value 2093 * @param array $exclude Array list of users id to exclude 2094 * @param int $disabled If select list must be disabled 2095 * @param array $include Array list of users id to include or 'hierarchy' to have only supervised users 2096 * @param array $enableonly Array list of users id to be enabled. All other must be disabled 2097 * @param int $force_entity '0' or Ids of environment to force 2098 * @param int $maxlength Maximum length of string into list (0=no limit) 2099 * @param int $showstatus 0=show user status only if status is disabled, 1=always show user status into label, -1=never show user status 2100 * @param string $morefilter Add more filters into sql request 2101 * @param int $showproperties Show properties of each attendees 2102 * @param array $listofuserid Array with properties of each user 2103 * @param array $listofcontactid Array with properties of each contact 2104 * @param array $listofotherid Array with properties of each other contact 2105 * @return string HTML select string 2106 * @see select_dolgroups() 2107 */ 2108 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()) 2109 { 2110 // phpcs:enable 2111 global $conf, $user, $langs; 2112 2113 $userstatic = new User($this->db); 2114 $out = ''; 2115 2116 2117 $assignedtouser = array(); 2118 if (!empty($_SESSION['assignedtouser'])) { 2119 $assignedtouser = json_decode($_SESSION['assignedtouser'], true); 2120 } 2121 $nbassignetouser = count($assignedtouser); 2122 2123 //if ($nbassignetouser && $action != 'view') $out .= '<br>'; 2124 if ($nbassignetouser) { 2125 $out .= '<ul class="attendees">'; 2126 } 2127 $i = 0; 2128 $ownerid = 0; 2129 foreach ($assignedtouser as $key => $value) { 2130 if ($value['id'] == $ownerid) { 2131 continue; 2132 } 2133 2134 $out .= '<li>'; 2135 $userstatic->fetch($value['id']); 2136 $out .= $userstatic->getNomUrl(-1); 2137 if ($i == 0) { 2138 $ownerid = $value['id']; 2139 $out .= ' ('.$langs->trans("Owner").')'; 2140 } 2141 if ($nbassignetouser > 1 && $action != 'view') { 2142 $out .= ' <input type="image" style="border: 0px;" src="'.img_picto($langs->trans("Remove"), 'delete', '', 0, 1).'" value="'.$userstatic->id.'" class="removedassigned reposition" id="removedassigned_'.$userstatic->id.'" name="removedassigned_'.$userstatic->id.'">'; 2143 } 2144 // Show my availability 2145 if ($showproperties) { 2146 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) { 2147 $out .= '<div class="myavailability inline-block">'; 2148 $out .= '<span class="hideonsmartphone"> - <span class="opacitymedium">'.$langs->trans("Availability").':</span> </span><input id="transparency" class="paddingrightonly" '.($action == 'view' ? 'disabled' : '').' type="checkbox" name="transparency"'.($listofuserid[$ownerid]['transparency'] ? ' checked' : '').'><label for="transparency">'.$langs->trans("Busy").'</label>'; 2149 $out .= '</div>'; 2150 } 2151 } 2152 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional")); 2153 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy")); 2154 2155 $out .= '</li>'; 2156 $i++; 2157 } 2158 if ($nbassignetouser) { 2159 $out .= '</ul>'; 2160 } 2161 2162 // Method with no ajax 2163 if ($action != 'view') { 2164 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">'; 2165 $out .= '<script type="text/javascript" language="javascript">jQuery(document).ready(function () {'; 2166 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });'; 2167 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());'; 2168 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#'.$action.'assignedtouser").attr("disabled", false); }'; 2169 $out .= ' else { jQuery("#'.$action.'assignedtouser").attr("disabled", true); }'; 2170 $out .= '});'; 2171 $out .= '})</script>'; 2172 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter); 2173 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="'.$action.'assignedtouser" name="'.$action.'assignedtouser" value="'.dol_escape_htmltag($langs->trans("Add")).'">'; 2174 $out .= '<br>'; 2175 } 2176 2177 return $out; 2178 } 2179 2180 2181 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 2182 /** 2183 * Return list of products for customer in Ajax if Ajax activated or go to select_produits_list 2184 * 2185 * @param int $selected Preselected products 2186 * @param string $htmlname Name of HTML select field (must be unique in page). 2187 * @param int|string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) 2188 * @param int $limit Limit on number of returned lines 2189 * @param int $price_level Level of price to show 2190 * @param int $status Sell status -1=Return all products, 0=Products not on sell, 1=Products on sell 2191 * @param int $finished 2=all, 1=finished, 0=raw material 2192 * @param string $selected_input_value Value of preselected input text (for use with ajax) 2193 * @param int $hidelabel Hide label (0=no, 1=yes, 2=show search icon (before) and placeholder, 3 search icon after) 2194 * @param array $ajaxoptions Options for ajax_autocompleter 2195 * @param int $socid Thirdparty Id (to get also price dedicated to this customer) 2196 * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text. 2197 * @param int $forcecombo Force to use combo box 2198 * @param string $morecss Add more css on select 2199 * @param int $hidepriceinlabel 1=Hide prices in label 2200 * @param string $warehouseStatus Warehouse status filter to count the quantity in stock. Following comma separated filter options can be used 2201 * 'warehouseopen' = count products from open warehouses, 2202 * 'warehouseclosed' = count products from closed warehouses, 2203 * 'warehouseinternal' = count products from warehouses for internal correct/transfer only 2204 * @param array $selected_combinations Selected combinations. Format: array([attrid] => attrval, [...]) 2205 * @param string $nooutput No print, return the output into a string 2206 * @return void|string 2207 */ 2208 public function select_produits($selected = '', $htmlname = 'productid', $filtertype = '', $limit = 0, $price_level = 0, $status = 1, $finished = 2, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $hidepriceinlabel = 0, $warehouseStatus = '', $selected_combinations = null, $nooutput = 0) 2209 { 2210 // phpcs:enable 2211 global $langs, $conf; 2212 2213 $out = ''; 2214 2215 // check parameters 2216 $price_level = (!empty($price_level) ? $price_level : 0); 2217 if (is_null($ajaxoptions)) { 2218 $ajaxoptions = array(); 2219 } 2220 2221 if (strval($filtertype) === '' && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) { 2222 if (!empty($conf->product->enabled) && empty($conf->service->enabled)) { 2223 $filtertype = '0'; 2224 } elseif (empty($conf->product->enabled) && !empty($conf->service->enabled)) { 2225 $filtertype = '1'; 2226 } 2227 } 2228 2229 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) { 2230 $placeholder = ''; 2231 2232 if ($selected && empty($selected_input_value)) { 2233 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; 2234 $producttmpselect = new Product($this->db); 2235 $producttmpselect->fetch($selected); 2236 $selected_input_value = $producttmpselect->ref; 2237 unset($producttmpselect); 2238 } 2239 // handle case where product or service module is disabled + no filter specified 2240 if ($filtertype == '') { 2241 if (empty($conf->product->enabled)) { // when product module is disabled, show services only 2242 $filtertype = 1; 2243 } elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only 2244 $filtertype = 0; 2245 } 2246 } 2247 // mode=1 means customers products 2248 $urloption = 'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=1&status='.$status.'&finished='.$finished.'&hidepriceinlabel='.$hidepriceinlabel.'&warehousestatus='.$warehouseStatus; 2249 //Price by customer 2250 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) { 2251 $urloption .= '&socid='.$socid; 2252 } 2253 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions); 2254 2255 if (!empty($conf->variants->enabled) && is_array($selected_combinations)) { 2256 // Code to automatically insert with javascript the select of attributes under the select of product 2257 // when a parent of variant has been selected. 2258 $out .= ' 2259 <!-- script to auto show attributes select tags if a variant was selected --> 2260 <script> 2261 // auto show attributes fields 2262 selected = '.json_encode($selected_combinations).'; 2263 combvalues = {}; 2264 2265 jQuery(document).ready(function () { 2266 2267 jQuery("input[name=\'prod_entry_mode\']").change(function () { 2268 if (jQuery(this).val() == \'free\') { 2269 jQuery(\'div#attributes_box\').empty(); 2270 } 2271 }); 2272 2273 jQuery("input#'.$htmlname.'").change(function () { 2274 2275 if (!jQuery(this).val()) { 2276 jQuery(\'div#attributes_box\').empty(); 2277 return; 2278 } 2279 2280 console.log("A change has started. We get variants fields to inject html select"); 2281 2282 jQuery.getJSON("'.DOL_URL_ROOT.'/variants/ajax/getCombinations.php", { 2283 id: jQuery(this).val() 2284 }, function (data) { 2285 jQuery(\'div#attributes_box\').empty(); 2286 2287 jQuery.each(data, function (key, val) { 2288 2289 combvalues[val.id] = val.values; 2290 2291 var span = jQuery(document.createElement(\'div\')).css({ 2292 \'display\': \'table-row\' 2293 }); 2294 2295 span.append( 2296 jQuery(document.createElement(\'div\')).text(val.label).css({ 2297 \'font-weight\': \'bold\', 2298 \'display\': \'table-cell\' 2299 }) 2300 ); 2301 2302 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({ 2303 \'margin-left\': \'15px\', 2304 \'white-space\': \'pre\' 2305 }).append( 2306 jQuery(document.createElement(\'option\')).val(\'\') 2307 ); 2308 2309 jQuery.each(combvalues[val.id], function (key, val) { 2310 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value); 2311 2312 if (selected[val.fk_product_attribute] == val.id) { 2313 tag.attr(\'selected\', \'selected\'); 2314 } 2315 2316 html.append(tag); 2317 }); 2318 2319 span.append(html); 2320 jQuery(\'div#attributes_box\').append(span); 2321 }); 2322 }) 2323 }); 2324 2325 '.($selected ? 'jQuery("input#'.$htmlname.'").change();' : '').' 2326 }); 2327 </script> 2328 '; 2329 } 2330 2331 if (empty($hidelabel)) { 2332 $out .= $langs->trans("RefOrLabel").' : '; 2333 } elseif ($hidelabel > 1) { 2334 $placeholder = ' placeholder="'.$langs->trans("RefOrLabel").'"'; 2335 if ($hidelabel == 2) { 2336 $out .= img_picto($langs->trans("Search"), 'search'); 2337 } 2338 } 2339 $out .= '<input type="text" class="minwidth100" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.$placeholder.' '.(!empty($conf->global->PRODUCT_SEARCH_AUTOFOCUS) ? 'autofocus' : '').' />'; 2340 if ($hidelabel == 3) { 2341 $out .= img_picto($langs->trans("Search"), 'search'); 2342 } 2343 } else { 2344 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus); 2345 } 2346 2347 if (empty($nooutput)) { 2348 print $out; 2349 } else { 2350 return $out; 2351 } 2352 } 2353 2354 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 2355 /** 2356 * Return list of products for a customer. 2357 * Called by select_produits. 2358 * 2359 * @param int $selected Preselected product 2360 * @param string $htmlname Name of select html 2361 * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) 2362 * @param int $limit Limit on number of returned lines 2363 * @param int $price_level Level of price to show 2364 * @param string $filterkey Filter on product 2365 * @param int $status -1=Return all products, 0=Products not on sell, 1=Products on sell 2366 * @param int $finished Filter on finished field: 2=No filter 2367 * @param int $outputmode 0=HTML select string, 1=Array 2368 * @param int $socid Thirdparty Id (to get also price dedicated to this customer) 2369 * @param string $showempty '' to not show empty line. Translation key to show an empty line. '1' show empty line with no text. 2370 * @param int $forcecombo Force to use combo box 2371 * @param string $morecss Add more css on select 2372 * @param int $hidepriceinlabel 1=Hide prices in label 2373 * @param string $warehouseStatus Warehouse status filter to group/count stock. Following comma separated filter options can be used. 2374 * 'warehouseopen' = count products from open warehouses, 2375 * 'warehouseclosed' = count products from closed warehouses, 2376 * 'warehouseinternal' = count products from warehouses for internal correct/transfer only 2377 * @return array Array of keys for json 2378 */ 2379 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 = '') 2380 { 2381 // phpcs:enable 2382 global $langs, $conf, $user, $db; 2383 2384 $out = ''; 2385 $outarray = array(); 2386 2387 // Units 2388 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 2389 $langs->load('other'); 2390 } 2391 2392 $warehouseStatusArray = array(); 2393 if (!empty($warehouseStatus)) { 2394 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; 2395 if (preg_match('/warehouseclosed/', $warehouseStatus)) { 2396 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED; 2397 } 2398 if (preg_match('/warehouseopen/', $warehouseStatus)) { 2399 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL; 2400 } 2401 if (preg_match('/warehouseinternal/', $warehouseStatus)) { 2402 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL; 2403 } 2404 } 2405 2406 $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"; 2407 if (count($warehouseStatusArray)) { 2408 $selectFieldsGrouped = ", sum(".$this->db->ifsql("e.statut IS NULL", "0", "ps.reel").") as stock"; // e.statut is null if there is no record in stock 2409 } else { 2410 $selectFieldsGrouped = ", ".$this->db->ifsql("p.stock IS NULL", 0, "p.stock")." AS stock"; 2411 } 2412 2413 $sql = "SELECT "; 2414 $sql .= $selectFields.$selectFieldsGrouped; 2415 2416 if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) { 2417 //Product category 2418 $sql .= ", (SELECT ".MAIN_DB_PREFIX."categorie_product.fk_categorie 2419 FROM ".MAIN_DB_PREFIX."categorie_product 2420 WHERE ".MAIN_DB_PREFIX."categorie_product.fk_product=p.rowid 2421 LIMIT 1 2422 ) AS categorie_product_id "; 2423 } 2424 2425 //Price by customer 2426 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) { 2427 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,'; 2428 $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.ref_customer as custref'; 2429 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custref"; 2430 } 2431 // Units 2432 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 2433 $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"; 2434 $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'; 2435 } 2436 2437 // Multilang : we add translation 2438 if (!empty($conf->global->MAIN_MULTILANGS)) { 2439 $sql .= ", pl.label as label_translated"; 2440 $sql .= ", pl.description as description_translated"; 2441 $selectFields .= ", label_translated"; 2442 $selectFields .= ", description_translated"; 2443 } 2444 // Price by quantity 2445 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { 2446 $sql .= ", (SELECT pp.rowid FROM ".MAIN_DB_PREFIX."product_price as pp WHERE pp.fk_product = p.rowid"; 2447 if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { 2448 $sql .= " AND price_level = ".((int) $price_level); 2449 } 2450 $sql .= " ORDER BY date_price"; 2451 $sql .= " DESC LIMIT 1) as price_rowid"; 2452 $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 2453 if ($price_level >= 1 && !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) { 2454 $sql .= " AND price_level = ".((int) $price_level); 2455 } 2456 $sql .= " ORDER BY date_price"; 2457 $sql .= " DESC LIMIT 1) as price_by_qty"; 2458 $selectFields .= ", price_rowid, price_by_qty"; 2459 } 2460 $sql .= " FROM ".MAIN_DB_PREFIX."product as p"; 2461 if (count($warehouseStatusArray)) { 2462 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid"; 2463 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (".getEntity('stock').")"; 2464 $sql .= ' AND e.statut IN ('.$this->db->sanitize($this->db->escape(implode(',', $warehouseStatusArray))).')'; // Return line if product is inside the selected stock. If not, an empty line will be returned so we will count 0. 2465 } 2466 2467 // include search in supplier ref 2468 if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) { 2469 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product"; 2470 } 2471 2472 //Price by customer 2473 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) { 2474 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_customer_price as pcp ON pcp.fk_soc=".((int) $socid)." AND pcp.fk_product=p.rowid"; 2475 } 2476 // Units 2477 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 2478 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit"; 2479 } 2480 // Multilang : we add translation 2481 if (!empty($conf->global->MAIN_MULTILANGS)) { 2482 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid "; 2483 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE) && !empty($socid)) { 2484 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; 2485 $soc = new Societe($db); 2486 $result = $soc->fetch($socid); 2487 if ($result > 0 && !empty($soc->default_lang)) { 2488 $sql .= " AND pl.lang='" . $this->db->escape($soc->default_lang) . "'"; 2489 } else { 2490 $sql .= " AND pl.lang='".$this->db->escape($langs->getDefaultLang())."'"; 2491 } 2492 } else { 2493 $sql .= " AND pl.lang='".$this->db->escape($langs->getDefaultLang())."'"; 2494 } 2495 } 2496 2497 if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) { 2498 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid"; 2499 } 2500 2501 $sql .= ' WHERE p.entity IN ('.getEntity('product').')'; 2502 2503 if (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) { 2504 $sql .= " AND pac.rowid IS NULL"; 2505 } 2506 2507 if ($finished == 0) { 2508 $sql .= " AND p.finished = ".((int) $finished); 2509 } elseif ($finished == 1) { 2510 $sql .= " AND p.finished = ".((int) $finished); 2511 if ($status >= 0) { 2512 $sql .= " AND p.tosell = ".((int) $status); 2513 } 2514 } elseif ($status >= 0) { 2515 $sql .= " AND p.tosell = ".((int) $status); 2516 } 2517 // Filter by product type 2518 if (strval($filtertype) != '') { 2519 $sql .= " AND p.fk_product_type = ".((int) $filtertype); 2520 } elseif (empty($conf->product->enabled)) { // when product module is disabled, show services only 2521 $sql .= " AND p.fk_product_type = 1"; 2522 } elseif (empty($conf->service->enabled)) { // when service module is disabled, show products only 2523 $sql .= " AND p.fk_product_type = 0"; 2524 } 2525 // Add criteria on ref/label 2526 if ($filterkey != '') { 2527 $sql .= ' AND ('; 2528 $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on 2529 // For natural search 2530 $scrit = explode(' ', $filterkey); 2531 $i = 0; 2532 if (count($scrit) > 1) { 2533 $sql .= "("; 2534 } 2535 foreach ($scrit as $crit) { 2536 if ($i > 0) { 2537 $sql .= " AND "; 2538 } 2539 $sql .= "(p.ref LIKE '".$this->db->escape($prefix.$crit)."%' OR p.label LIKE '".$this->db->escape($prefix.$crit)."%'"; 2540 if (!empty($conf->global->MAIN_MULTILANGS)) { 2541 $sql .= " OR pl.label LIKE '".$this->db->escape($prefix.$crit)."%'"; 2542 } 2543 if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES) && ! empty($socid)) { 2544 $sql .= " OR pcp.ref_customer LIKE '".$this->db->escape($prefix.$crit)."%'"; 2545 } 2546 if (!empty($conf->global->PRODUCT_AJAX_SEARCH_ON_DESCRIPTION)) { 2547 $sql .= " OR p.description LIKE '".$this->db->escape($prefix.$crit)."%'"; 2548 if (!empty($conf->global->MAIN_MULTILANGS)) { 2549 $sql .= " OR pl.description LIKE '".$this->db->escape($prefix.$crit)."%'"; 2550 } 2551 } 2552 if (!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) { 2553 $sql .= " OR pfp.ref_fourn LIKE '".$this->db->escape($prefix.$crit)."%'"; 2554 } 2555 $sql .= ")"; 2556 $i++; 2557 } 2558 if (count($scrit) > 1) { 2559 $sql .= ")"; 2560 } 2561 if (!empty($conf->barcode->enabled)) { 2562 $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; 2563 } 2564 $sql .= ')'; 2565 } 2566 if (count($warehouseStatusArray)) { 2567 $sql .= ' GROUP BY'.$selectFields; 2568 } 2569 2570 //Sort by category 2571 if (!empty($conf->global->PRODUCT_SORT_BY_CATEGORY)) { 2572 $sql .= " ORDER BY categorie_product_id "; 2573 //ASC OR DESC order 2574 ($conf->global->PRODUCT_SORT_BY_CATEGORY == 1) ? $sql .= "ASC" : $sql .= "DESC"; 2575 } else { 2576 $sql .= $this->db->order("p.ref"); 2577 } 2578 2579 $sql .= $this->db->plimit($limit, 0); 2580 2581 // Build output string 2582 dol_syslog(get_class($this)."::select_produits_list search products", LOG_DEBUG); 2583 $result = $this->db->query($sql); 2584 if ($result) { 2585 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; 2586 require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; 2587 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; 2588 2589 $num = $this->db->num_rows($result); 2590 2591 $events = null; 2592 2593 if (!$forcecombo) { 2594 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 2595 $out .= ajax_combobox($htmlname, $events, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT); 2596 } 2597 2598 $out .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">'; 2599 2600 $textifempty = ''; 2601 // Do not use textifempty = ' ' or ' ' here, or search on key will search on ' key'. 2602 //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty=''; 2603 if (!empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) { 2604 if ($showempty && !is_numeric($showempty)) { 2605 $textifempty = $langs->trans($showempty); 2606 } else { 2607 $textifempty .= $langs->trans("All"); 2608 } 2609 } else { 2610 if ($showempty && !is_numeric($showempty)) { 2611 $textifempty = $langs->trans($showempty); 2612 } 2613 } 2614 if ($showempty) { 2615 $out .= '<option value="-1" selected>'.($textifempty ? $textifempty : ' ').'</option>'; 2616 } 2617 2618 $i = 0; 2619 while ($num && $i < $num) { 2620 $opt = ''; 2621 $optJson = array(); 2622 $objp = $this->db->fetch_object($result); 2623 2624 if ((!empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) && !empty($objp->price_by_qty) && $objp->price_by_qty == 1) { // Price by quantity will return many prices for the same product 2625 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type"; 2626 $sql .= " FROM ".MAIN_DB_PREFIX."product_price_by_qty"; 2627 $sql .= " WHERE fk_product_price=".$objp->price_rowid; 2628 $sql .= " ORDER BY quantity ASC"; 2629 2630 dol_syslog(get_class($this)."::select_produits_list search prices by qty", LOG_DEBUG); 2631 $result2 = $this->db->query($sql); 2632 if ($result2) { 2633 $nb_prices = $this->db->num_rows($result2); 2634 $j = 0; 2635 while ($nb_prices && $j < $nb_prices) { 2636 $objp2 = $this->db->fetch_object($result2); 2637 2638 $objp->price_by_qty_rowid = $objp2->rowid; 2639 $objp->price_by_qty_price_base_type = $objp2->price_base_type; 2640 $objp->price_by_qty_quantity = $objp2->quantity; 2641 $objp->price_by_qty_unitprice = $objp2->unitprice; 2642 $objp->price_by_qty_remise_percent = $objp2->remise_percent; 2643 // For backward compatibility 2644 $objp->quantity = $objp2->quantity; 2645 $objp->price = $objp2->price; 2646 $objp->unitprice = $objp2->unitprice; 2647 $objp->remise_percent = $objp2->remise_percent; 2648 $objp->remise = $objp2->remise; 2649 2650 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey); 2651 2652 $j++; 2653 2654 // Add new entry 2655 // "key" value of json key array is used by jQuery automatically as selected value 2656 // "label" value of json key array is used by jQuery automatically as text for combo box 2657 $out .= $opt; 2658 array_push($outarray, $optJson); 2659 } 2660 } 2661 } else { 2662 if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_price_expression)) { 2663 $price_product = new Product($this->db); 2664 $price_product->fetch($objp->rowid, '', '', 1); 2665 $priceparser = new PriceParser($this->db); 2666 $price_result = $priceparser->parseProduct($price_product); 2667 if ($price_result >= 0) { 2668 $objp->price = $price_result; 2669 $objp->unitprice = $price_result; 2670 //Calculate the VAT 2671 $objp->price_ttc = price2num($objp->price) * (1 + ($objp->tva_tx / 100)); 2672 $objp->price_ttc = price2num($objp->price_ttc, 'MU'); 2673 } 2674 } 2675 2676 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey); 2677 // Add new entry 2678 // "key" value of json key array is used by jQuery automatically as selected value 2679 // "label" value of json key array is used by jQuery automatically as text for combo box 2680 $out .= $opt; 2681 array_push($outarray, $optJson); 2682 } 2683 2684 $i++; 2685 } 2686 2687 $out .= '</select>'; 2688 2689 $this->db->free($result); 2690 2691 if (empty($outputmode)) { 2692 return $out; 2693 } 2694 return $outarray; 2695 } else { 2696 dol_print_error($db); 2697 } 2698 } 2699 2700 /** 2701 * constructProductListOption. 2702 * This define value for &$opt and &$optJson. 2703 * 2704 * @param resource $objp Resultset of fetch 2705 * @param string $opt Option (var used for returned value in string option format) 2706 * @param string $optJson Option (var used for returned value in json format) 2707 * @param int $price_level Price level 2708 * @param string $selected Preselected value 2709 * @param int $hidepriceinlabel Hide price in label 2710 * @param string $filterkey Filter key to highlight 2711 * @param int $novirtualstock Do not load virtual stock, even if slow option STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO is on. 2712 * @return void 2713 */ 2714 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0) 2715 { 2716 global $langs, $conf, $user, $db; 2717 2718 $outkey = ''; 2719 $outval = ''; 2720 $outref = ''; 2721 $outlabel = ''; 2722 $outlabel_translated = ''; 2723 $outdesc = ''; 2724 $outdesc_translated = ''; 2725 $outbarcode = ''; 2726 $outorigin = ''; 2727 $outtype = ''; 2728 $outprice_ht = ''; 2729 $outprice_ttc = ''; 2730 $outpricebasetype = ''; 2731 $outtva_tx = ''; 2732 $outqty = 1; 2733 $outdiscount = 0; 2734 2735 $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO); 2736 2737 $label = $objp->label; 2738 if (!empty($objp->label_translated)) { 2739 $label = $objp->label_translated; 2740 } 2741 if (!empty($filterkey) && $filterkey != '') { 2742 $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1); 2743 } 2744 2745 $outkey = $objp->rowid; 2746 $outref = $objp->ref; 2747 $outrefcust = empty($objp->custref) ? '' : $objp->custref; 2748 $outlabel = $objp->label; 2749 $outdesc = $objp->description; 2750 if (!empty($conf->global->MAIN_MULTILANGS)) { 2751 $outlabel_translated = $objp->label_translated; 2752 $outdesc_translated = $objp->description_translated; 2753 } 2754 $outbarcode = $objp->barcode; 2755 $outorigin = $objp->fk_country; 2756 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid; 2757 2758 $outtype = $objp->fk_product_type; 2759 $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : ''; 2760 $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : ''; 2761 2762 if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) { 2763 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; 2764 } 2765 2766 // Units 2767 $outvalUnits = ''; 2768 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 2769 if (!empty($objp->unit_short)) { 2770 $outvalUnits .= ' - '.$objp->unit_short; 2771 } 2772 } 2773 if (!empty($conf->global->PRODUCT_SHOW_DIMENSIONS_IN_COMBO)) { 2774 if (!empty($objp->weight) && $objp->weight_units !== null) { 2775 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs); 2776 $outvalUnits .= ' - '.$unitToShow; 2777 } 2778 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) { 2779 $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units); 2780 $outvalUnits .= ' - '.$unitToShow; 2781 } 2782 if (!empty($objp->surface) && $objp->surface_units !== null) { 2783 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs); 2784 $outvalUnits .= ' - '.$unitToShow; 2785 } 2786 if (!empty($objp->volume) && $objp->volume_units !== null) { 2787 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs); 2788 $outvalUnits .= ' - '.$unitToShow; 2789 } 2790 } 2791 if ($outdurationvalue && $outdurationunit) { 2792 $da = array( 2793 'h' => $langs->trans('Hour'), 2794 'd' => $langs->trans('Day'), 2795 'w' => $langs->trans('Week'), 2796 'm' => $langs->trans('Month'), 2797 'y' => $langs->trans('Year') 2798 ); 2799 if (isset($da[$outdurationunit])) { 2800 $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : '')); 2801 } 2802 } 2803 2804 $opt = '<option value="'.$objp->rowid.'"'; 2805 $opt .= ($objp->rowid == $selected) ? ' selected' : ''; 2806 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) { 2807 $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.'"'; 2808 } 2809 if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) { 2810 if (!empty($user->rights->stock->lire)) { 2811 if ($objp->stock > 0) { 2812 $opt .= ' class="product_line_stock_ok"'; 2813 } elseif ($objp->stock <= 0) { 2814 $opt .= ' class="product_line_stock_too_low"'; 2815 } 2816 } 2817 } 2818 if (!empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) { 2819 $opt .= ' data-labeltrans="'.$outlabel_translated.'"'; 2820 $opt .= ' data-desctrans="'.dol_escape_htmltag($outdesc_translated).'"'; 2821 } 2822 $opt .= '>'; 2823 $opt .= $objp->ref; 2824 if (! empty($objp->custref)) { 2825 $opt.= ' (' . $objp->custref . ')'; 2826 } 2827 if ($outbarcode) { 2828 $opt .= ' ('.$outbarcode.')'; 2829 } 2830 $opt .= ' - '.dol_trunc($label, $maxlengtharticle); 2831 if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) { 2832 $opt .= ' ('.getCountry($outorigin, 1).')'; 2833 } 2834 2835 $objRef = $objp->ref; 2836 if (! empty($objp->custref)) { 2837 $objRef .= ' (' . $objp->custref . ')'; 2838 } 2839 if (!empty($filterkey) && $filterkey != '') { 2840 $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1); 2841 } 2842 $outval .= $objRef; 2843 if ($outbarcode) { 2844 $outval .= ' ('.$outbarcode.')'; 2845 } 2846 $outval .= ' - '.dol_trunc($label, $maxlengtharticle); 2847 if ($outorigin && !empty($conf->global->PRODUCT_SHOW_ORIGIN_IN_COMBO)) { 2848 $outval .= ' ('.getCountry($outorigin, 1).')'; 2849 } 2850 2851 // Units 2852 $opt .= $outvalUnits; 2853 $outval .= $outvalUnits; 2854 2855 $found = 0; 2856 2857 // Multiprice 2858 // If we need a particular price level (from 1 to 6) 2859 if (empty($hidepriceinlabel) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) { 2860 $sql = "SELECT price, price_ttc, price_base_type, tva_tx"; 2861 $sql .= " FROM ".MAIN_DB_PREFIX."product_price"; 2862 $sql .= " WHERE fk_product = ".((int) $objp->rowid); 2863 $sql .= " AND entity IN (".getEntity('productprice').")"; 2864 $sql .= " AND price_level = ".((int) $price_level); 2865 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid. 2866 $sql .= " LIMIT 1"; 2867 2868 dol_syslog(get_class($this).'::constructProductListOption search price for product '.$objp->rowid.' AND level '.$price_level.'', LOG_DEBUG); 2869 $result2 = $this->db->query($sql); 2870 if ($result2) { 2871 $objp2 = $this->db->fetch_object($result2); 2872 if ($objp2) { 2873 $found = 1; 2874 if ($objp2->price_base_type == 'HT') { 2875 $opt .= ' - '.price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT"); 2876 $outval .= ' - '.price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT"); 2877 } else { 2878 $opt .= ' - '.price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC"); 2879 $outval .= ' - '.price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC"); 2880 } 2881 $outprice_ht = price($objp2->price); 2882 $outprice_ttc = price($objp2->price_ttc); 2883 $outpricebasetype = $objp2->price_base_type; 2884 $outtva_tx = $objp2->tva_tx; 2885 } 2886 } else { 2887 dol_print_error($this->db); 2888 } 2889 } 2890 2891 // Price by quantity 2892 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))) { 2893 $found = 1; 2894 $outqty = $objp->quantity; 2895 $outdiscount = $objp->remise_percent; 2896 if ($objp->quantity == 1) { 2897 $opt .= ' - '.price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/"; 2898 $outval .= ' - '.price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/"; 2899 $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding 2900 $outval .= $langs->transnoentities("Unit"); 2901 } else { 2902 $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity; 2903 $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency)."/".$objp->quantity; 2904 $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding 2905 $outval .= $langs->transnoentities("Units"); 2906 } 2907 2908 $outprice_ht = price($objp->unitprice); 2909 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100))); 2910 $outpricebasetype = $objp->price_base_type; 2911 $outtva_tx = $objp->tva_tx; 2912 } 2913 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) { 2914 $opt .= " (".price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency)."/".$langs->trans("Unit").")"; // Do not use strtolower because it breaks utf8 encoding 2915 $outval .= " (".price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency)."/".$langs->transnoentities("Unit").")"; // Do not use strtolower because it breaks utf8 encoding 2916 } 2917 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) { 2918 $opt .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %'; 2919 $outval .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %'; 2920 } 2921 2922 // Price by customer 2923 if (empty($hidepriceinlabel) && !empty($conf->global->PRODUIT_CUSTOMER_PRICES)) { 2924 if (!empty($objp->idprodcustprice)) { 2925 $found = 1; 2926 2927 if ($objp->custprice_base_type == 'HT') { 2928 $opt .= ' - '.price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT"); 2929 $outval .= ' - '.price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT"); 2930 } else { 2931 $opt .= ' - '.price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC"); 2932 $outval .= ' - '.price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC"); 2933 } 2934 2935 $outprice_ht = price($objp->custprice); 2936 $outprice_ttc = price($objp->custprice_ttc); 2937 $outpricebasetype = $objp->custprice_base_type; 2938 $outtva_tx = $objp->custtva_tx; 2939 } 2940 } 2941 2942 // If level no defined or multiprice not found, we used the default price 2943 if (empty($hidepriceinlabel) && !$found) { 2944 if ($objp->price_base_type == 'HT') { 2945 $opt .= ' - '.price($objp->price, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("HT"); 2946 $outval .= ' - '.price($objp->price, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("HT"); 2947 } else { 2948 $opt .= ' - '.price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency).' '.$langs->trans("TTC"); 2949 $outval .= ' - '.price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency).' '.$langs->transnoentities("TTC"); 2950 } 2951 $outprice_ht = price($objp->price); 2952 $outprice_ttc = price($objp->price_ttc); 2953 $outpricebasetype = $objp->price_base_type; 2954 $outtva_tx = $objp->tva_tx; 2955 } 2956 2957 if (!empty($conf->stock->enabled) && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) { 2958 if (!empty($user->rights->stock->lire)) { 2959 $opt .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS')); 2960 2961 if ($objp->stock > 0) { 2962 $outval .= ' - <span class="product_line_stock_ok">'; 2963 } elseif ($objp->stock <= 0) { 2964 $outval .= ' - <span class="product_line_stock_too_low">'; 2965 } 2966 $outval .= $langs->transnoentities("Stock").': '.price(price2num($objp->stock, 'MS')); 2967 $outval .= '</span>'; 2968 if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation 2969 $langs->load("stocks"); 2970 2971 $tmpproduct = new Product($this->db); 2972 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after) 2973 $tmpproduct->load_virtual_stock(); 2974 $virtualstock = $tmpproduct->stock_theorique; 2975 2976 $opt .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock; 2977 2978 $outval .= ' - '.$langs->transnoentities("VirtualStock").':'; 2979 if ($virtualstock > 0) { 2980 $outval .= '<span class="product_line_stock_ok">'; 2981 } elseif ($virtualstock <= 0) { 2982 $outval .= '<span class="product_line_stock_too_low">'; 2983 } 2984 $outval .= $virtualstock; 2985 $outval .= '</span>'; 2986 2987 unset($tmpproduct); 2988 } 2989 } 2990 } 2991 2992 $opt .= "</option>\n"; 2993 $optJson = array( 2994 'key'=>$outkey, 2995 'value'=>$outref, 2996 'label'=>$outval, 2997 'label2'=>$outlabel, 2998 'desc'=>$outdesc, 2999 'type'=>$outtype, 3000 'price_ht'=>price2num($outprice_ht), 3001 'price_ttc'=>price2num($outprice_ttc), 3002 'pricebasetype'=>$outpricebasetype, 3003 'tva_tx'=>$outtva_tx, 'qty'=>$outqty, 3004 'discount'=>$outdiscount, 3005 'duration_value'=>$outdurationvalue, 3006 'duration_unit'=>$outdurationunit, 3007 'pbq'=>$outpbq, 3008 'labeltrans'=>$outlabel_translated, 3009 'desctrans'=>$outdesc_translated, 3010 'ref_customer'=>$outrefcust 3011 ); 3012 } 3013 3014 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3015 /** 3016 * Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs_list) 3017 * 3018 * @param int $socid Id third party 3019 * @param string $selected Preselected product 3020 * @param string $htmlname Name of HTML Select 3021 * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) 3022 * @param string $filtre For a SQL filter 3023 * @param array $ajaxoptions Options for ajax_autocompleter 3024 * @param int $hidelabel Hide label (0=no, 1=yes) 3025 * @param int $alsoproductwithnosupplierprice 1=Add also product without supplier prices 3026 * @param string $morecss More CSS 3027 * @param string $placeholder Placeholder 3028 * @return void 3029 */ 3030 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '') 3031 { 3032 // phpcs:enable 3033 global $langs, $conf; 3034 global $price_level, $status, $finished; 3035 3036 if (!isset($status)) { 3037 $status = 1; 3038 } 3039 3040 $selected_input_value = ''; 3041 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->PRODUIT_USE_SEARCH_TO_SELECT)) { 3042 if ($selected > 0) { 3043 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; 3044 $producttmpselect = new Product($this->db); 3045 $producttmpselect->fetch($selected); 3046 $selected_input_value = $producttmpselect->ref; 3047 unset($producttmpselect); 3048 } 3049 3050 // mode=2 means suppliers products 3051 $urloption = ($socid > 0 ? 'socid='.$socid.'&' : '').'htmlname='.$htmlname.'&outjson=1&price_level='.$price_level.'&type='.$filtertype.'&mode=2&status='.$status.'&finished='.$finished.'&alsoproductwithnosupplierprice='.$alsoproductwithnosupplierprice; 3052 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 0, $ajaxoptions); 3053 print ($hidelabel ? '' : $langs->trans("RefOrLabel").' : ').'<input type="text" class="minwidth300" name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.$placeholder.'"' : '').'>'; 3054 } else { 3055 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder); 3056 } 3057 } 3058 3059 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3060 /** 3061 * Return list of suppliers products 3062 * 3063 * @param int $socid Id of supplier thirdparty (0 = no filter) 3064 * @param int $selected Product price pre-selected (must be 'id' in product_fournisseur_price or 'idprod_IDPROD') 3065 * @param string $htmlname Name of HTML select 3066 * @param string $filtertype Filter on product type (''=nofilter, 0=product, 1=service) 3067 * @param string $filtre Generic filter. Data must not come from user input. 3068 * @param string $filterkey Filter of produdts 3069 * @param int $statut -1=Return all products, 0=Products not on buy, 1=Products on buy 3070 * @param int $outputmode 0=HTML select string, 1=Array 3071 * @param int $limit Limit of line number 3072 * @param int $alsoproductwithnosupplierprice 1=Add also product without supplier prices 3073 * @param string $morecss Add more CSS 3074 * @param int $showstockinlist Show stock information (slower). 3075 * @param string $placeholder Placeholder 3076 * @return array Array of keys for json 3077 */ 3078 public function select_produits_fournisseurs_list($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $filterkey = '', $statut = -1, $outputmode = 0, $limit = 100, $alsoproductwithnosupplierprice = 0, $morecss = '', $showstockinlist = 0, $placeholder = '') 3079 { 3080 // phpcs:enable 3081 global $langs, $conf, $db, $user; 3082 3083 $out = ''; 3084 $outarray = array(); 3085 3086 $maxlengtharticle = (empty($conf->global->PRODUCT_MAX_LENGTH_COMBO) ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO); 3087 3088 $langs->load('stocks'); 3089 // Units 3090 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 3091 $langs->load('other'); 3092 } 3093 3094 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock,"; 3095 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice,"; 3096 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.fk_soc, s.nom as name,"; 3097 $sql .= " pfp.supplier_reputation"; 3098 // if we use supplier description of the products 3099 if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) { 3100 $sql .= " ,pfp.desc_fourn as description"; 3101 } else { 3102 $sql .= " ,p.description"; 3103 } 3104 // Units 3105 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 3106 $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"; 3107 } 3108 if (!empty($conf->barcode->enabled)) { 3109 $sql .= ", pfp.barcode"; 3110 } 3111 $sql .= " FROM ".MAIN_DB_PREFIX."product as p"; 3112 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (".getEntity('product').") )"; 3113 if ($socid > 0) { 3114 $sql .= " AND pfp.fk_soc = ".((int) $socid); 3115 } 3116 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid"; 3117 // Units 3118 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 3119 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_units u ON u.rowid = p.fk_unit"; 3120 } 3121 $sql .= " WHERE p.entity IN (".getEntity('product').")"; 3122 if ($statut != -1) { 3123 $sql .= " AND p.tobuy = ".((int) $statut); 3124 } 3125 if (strval($filtertype) != '') { 3126 $sql .= " AND p.fk_product_type = ".((int) $filtertype); 3127 } 3128 if (!empty($filtre)) { 3129 $sql .= " ".$filtre; 3130 } 3131 // Add criteria on ref/label 3132 if ($filterkey != '') { 3133 $sql .= ' AND ('; 3134 $prefix = empty($conf->global->PRODUCT_DONOTSEARCH_ANYWHERE) ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on 3135 // For natural search 3136 $scrit = explode(' ', $filterkey); 3137 $i = 0; 3138 if (count($scrit) > 1) { 3139 $sql .= "("; 3140 } 3141 foreach ($scrit as $crit) { 3142 if ($i > 0) { 3143 $sql .= " AND "; 3144 } 3145 $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)."%'"; 3146 if (!empty($conf->global->PRODUIT_FOURN_TEXTS)) { 3147 $sql .= " OR pfp.desc_fourn LIKE '".$this->db->escape($prefix.$crit)."%'"; 3148 } 3149 $sql .= ")"; 3150 $i++; 3151 } 3152 if (count($scrit) > 1) { 3153 $sql .= ")"; 3154 } 3155 if (!empty($conf->barcode->enabled)) { 3156 $sql .= " OR p.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; 3157 $sql .= " OR pfp.barcode LIKE '".$this->db->escape($prefix.$filterkey)."%'"; 3158 } 3159 $sql .= ')'; 3160 } 3161 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC"; 3162 $sql .= $this->db->plimit($limit, 0); 3163 3164 // Build output string 3165 3166 dol_syslog(get_class($this)."::select_produits_fournisseurs_list", LOG_DEBUG); 3167 $result = $this->db->query($sql); 3168 if ($result) { 3169 require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; 3170 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; 3171 3172 $num = $this->db->num_rows($result); 3173 3174 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax 3175 $out .= '<select class="flat '.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'">'; 3176 if (!$selected) { 3177 $out .= '<option value="-1" selected>'.($placeholder ? $placeholder : ' ').'</option>'; 3178 } else { 3179 $out .= '<option value="-1">'.($placeholder ? $placeholder : ' ').'</option>'; 3180 } 3181 3182 $i = 0; 3183 while ($i < $num) { 3184 $objp = $this->db->fetch_object($result); 3185 3186 $outkey = $objp->idprodfournprice; // id in table of price 3187 if (!$outkey && $alsoproductwithnosupplierprice) { 3188 $outkey = 'idprod_'.$objp->rowid; // id of product 3189 } 3190 3191 $outref = $objp->ref; 3192 $outval = ''; 3193 $outbarcode = $objp->barcode; 3194 $outqty = 1; 3195 $outdiscount = 0; 3196 $outtype = $objp->fk_product_type; 3197 $outdurationvalue = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : ''; 3198 $outdurationunit = $outtype == Product::TYPE_SERVICE ?substr($objp->duration, -1) : ''; 3199 3200 // Units 3201 $outvalUnits = ''; 3202 if (!empty($conf->global->PRODUCT_USE_UNITS)) { 3203 if (!empty($objp->unit_short)) { 3204 $outvalUnits .= ' - '.$objp->unit_short; 3205 } 3206 if (!empty($objp->weight) && $objp->weight_units !== null) { 3207 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs); 3208 $outvalUnits .= ' - '.$unitToShow; 3209 } 3210 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) { 3211 $unitToShow = $objp->length.' x '.$objp->width.' x '.$objp->height.' '.measuringUnitString(0, 'size', $objp->length_units); 3212 $outvalUnits .= ' - '.$unitToShow; 3213 } 3214 if (!empty($objp->surface) && $objp->surface_units !== null) { 3215 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs); 3216 $outvalUnits .= ' - '.$unitToShow; 3217 } 3218 if (!empty($objp->volume) && $objp->volume_units !== null) { 3219 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs); 3220 $outvalUnits .= ' - '.$unitToShow; 3221 } 3222 if ($outdurationvalue && $outdurationunit) { 3223 $da = array( 3224 'h' => $langs->trans('Hour'), 3225 'd' => $langs->trans('Day'), 3226 'w' => $langs->trans('Week'), 3227 'm' => $langs->trans('Month'), 3228 'y' => $langs->trans('Year') 3229 ); 3230 if (isset($da[$outdurationunit])) { 3231 $outvalUnits .= ' - '.$outdurationvalue.' '.$langs->transnoentities($da[$outdurationunit].($outdurationvalue > 1 ? 's' : '')); 3232 } 3233 } 3234 } 3235 3236 $objRef = $objp->ref; 3237 if ($filterkey && $filterkey != '') { 3238 $objRef = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRef, 1); 3239 } 3240 $objRefFourn = $objp->ref_fourn; 3241 if ($filterkey && $filterkey != '') { 3242 $objRefFourn = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $objRefFourn, 1); 3243 } 3244 $label = $objp->label; 3245 if ($filterkey && $filterkey != '') { 3246 $label = preg_replace('/('.preg_quote($filterkey, '/').')/i', '<strong>$1</strong>', $label, 1); 3247 } 3248 3249 $optlabel = $objp->ref; 3250 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) { 3251 $optlabel .= ' <span class=\'opacitymedium\'>('.$objp->ref_fourn.')</span>'; 3252 } 3253 if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) { 3254 $optlabel .= ' ('.$outbarcode.')'; 3255 } 3256 $optlabel .= ' - '.dol_trunc($label, $maxlengtharticle); 3257 3258 $outvallabel = $objRef; 3259 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) { 3260 $outvallabel .= ' ('.$objRefFourn.')'; 3261 } 3262 if (!empty($conf->barcode->enabled) && !empty($objp->barcode)) { 3263 $outvallabel .= ' ('.$outbarcode.')'; 3264 } 3265 $outvallabel .= ' - '.dol_trunc($label, $maxlengtharticle); 3266 3267 // Units 3268 $optlabel .= $outvalUnits; 3269 $outvallabel .= $outvalUnits; 3270 3271 if (!empty($objp->idprodfournprice)) { 3272 $outqty = $objp->quantity; 3273 $outdiscount = $objp->remise_percent; 3274 if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) { 3275 $prod_supplier = new ProductFournisseur($this->db); 3276 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice; 3277 $prod_supplier->id = $objp->fk_product; 3278 $prod_supplier->fourn_qty = $objp->quantity; 3279 $prod_supplier->fourn_tva_tx = $objp->tva_tx; 3280 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression; 3281 $priceparser = new PriceParser($this->db); 3282 $price_result = $priceparser->parseProductSupplier($prod_supplier); 3283 if ($price_result >= 0) { 3284 $objp->fprice = $price_result; 3285 if ($objp->quantity >= 1) { 3286 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice 3287 } 3288 } 3289 } 3290 if ($objp->quantity == 1) { 3291 $optlabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/"; 3292 $outvallabel .= ' - '.price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency)."/"; 3293 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding 3294 $outvallabel .= $langs->transnoentities("Unit"); 3295 } else { 3296 $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; 3297 $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; 3298 $optlabel .= ' '.$langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding 3299 $outvallabel .= ' '.$langs->transnoentities("Units"); 3300 } 3301 3302 if ($objp->quantity > 1) { 3303 $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 3304 $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 3305 } 3306 if ($objp->remise_percent >= 1) { 3307 $optlabel .= " - ".$langs->trans("Discount")." : ".vatrate($objp->remise_percent).' %'; 3308 $outvallabel .= " - ".$langs->transnoentities("Discount")." : ".vatrate($objp->remise_percent).' %'; 3309 } 3310 if ($objp->duration) { 3311 $optlabel .= " - ".$objp->duration; 3312 $outvallabel .= " - ".$objp->duration; 3313 } 3314 if (!$socid) { 3315 $optlabel .= " - ".dol_trunc($objp->name, 8); 3316 $outvallabel .= " - ".dol_trunc($objp->name, 8); 3317 } 3318 if ($objp->supplier_reputation) { 3319 //TODO dictionary 3320 $reputations = array(''=>$langs->trans('Standard'), 'FAVORITE'=>$langs->trans('Favorite'), 'NOTTHGOOD'=>$langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER'=>$langs->trans('DoNotOrderThisProductToThisSupplier')); 3321 3322 $optlabel .= " - ".$reputations[$objp->supplier_reputation]; 3323 $outvallabel .= " - ".$reputations[$objp->supplier_reputation]; 3324 } 3325 } else { 3326 if (empty($alsoproductwithnosupplierprice)) { // No supplier price defined for couple product/supplier 3327 $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>'; 3328 $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier"); 3329 } else // No supplier price defined for product, even on other suppliers 3330 { 3331 $optlabel .= " - <span class='opacitymedium'>".$langs->trans("NoPriceDefinedForThisSupplier").'</span>'; 3332 $outvallabel .= ' - '.$langs->transnoentities("NoPriceDefinedForThisSupplier"); 3333 } 3334 } 3335 3336 if (!empty($conf->stock->enabled) && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES))) { 3337 $novirtualstock = ($showstockinlist == 2); 3338 3339 if (!empty($user->rights->stock->lire)) { 3340 $outvallabel .= ' - '.$langs->trans("Stock").': '.price(price2num($objp->stock, 'MS')); 3341 3342 if ($objp->stock > 0) { 3343 $optlabel .= ' - <span class="product_line_stock_ok">'; 3344 } elseif ($objp->stock <= 0) { 3345 $optlabel .= ' - <span class="product_line_stock_too_low">'; 3346 } 3347 $optlabel .= $langs->transnoentities("Stock").':'.price(price2num($objp->stock, 'MS')); 3348 $optlabel .= '</span>'; 3349 if (empty($novirtualstock) && !empty($conf->global->STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO)) { // Warning, this option may slow down combo list generation 3350 $langs->load("stocks"); 3351 3352 $tmpproduct = new Product($this->db); 3353 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after) 3354 $tmpproduct->load_virtual_stock(); 3355 $virtualstock = $tmpproduct->stock_theorique; 3356 3357 $outvallabel .= ' - '.$langs->trans("VirtualStock").':'.$virtualstock; 3358 3359 $optlabel .= ' - '.$langs->transnoentities("VirtualStock").':'; 3360 if ($virtualstock > 0) { 3361 $optlabel .= '<span class="product_line_stock_ok">'; 3362 } elseif ($virtualstock <= 0) { 3363 $optlabel .= '<span class="product_line_stock_too_low">'; 3364 } 3365 $optlabel .= $virtualstock; 3366 $optlabel .= '</span>'; 3367 3368 unset($tmpproduct); 3369 } 3370 } 3371 } 3372 3373 $opt = '<option value="'.$outkey.'"'; 3374 if ($selected && $selected == $objp->idprodfournprice) { 3375 $opt .= ' selected'; 3376 } 3377 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) { 3378 $opt .= ' disabled'; 3379 } 3380 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) { 3381 $opt .= ' data-qty="'.$objp->quantity.'" data-up="'.$objp->unitprice.'" data-discount="'.$outdiscount.'"'; 3382 } 3383 $opt .= ' data-description="'.dol_escape_htmltag($objp->description, 0, 1).'"'; 3384 $opt .= ' data-html="'.dol_escape_htmltag($optlabel).'"'; 3385 $opt .= '>'; 3386 3387 $opt .= $optlabel; 3388 $outval .= $outvallabel; 3389 3390 $opt .= "</option>\n"; 3391 3392 3393 // Add new entry 3394 // "key" value of json key array is used by jQuery automatically as selected value. Example: 'type' = product or service, 'price_ht' = unit price without tax 3395 // "label" value of json key array is used by jQuery automatically as text for combo box 3396 $out .= $opt; 3397 array_push( 3398 $outarray, 3399 array('key'=>$outkey, 3400 'value'=>$outref, 3401 'label'=>$outval, 3402 'qty'=>$outqty, 3403 'price_ht'=>price2num($objp->unitprice, 'MT'), 3404 'discount'=>$outdiscount, 3405 'type'=>$outtype, 3406 'duration_value'=>$outdurationvalue, 3407 'duration_unit'=>$outdurationunit, 3408 'disabled'=>(empty($objp->idprodfournprice) ? true : false), 3409 'description'=>$objp->description 3410 ) 3411 ); 3412 // Exemple of var_dump $outarray 3413 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp" 3414 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)" 3415 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false) 3416 //} 3417 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval)); 3418 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)'); 3419 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval)); 3420 3421 $i++; 3422 } 3423 $out .= '</select>'; 3424 3425 $this->db->free($result); 3426 3427 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 3428 $out .= ajax_combobox($htmlname); 3429 3430 if (empty($outputmode)) { 3431 return $out; 3432 } 3433 return $outarray; 3434 } else { 3435 dol_print_error($this->db); 3436 } 3437 } 3438 3439 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3440 /** 3441 * Return list of suppliers prices for a product 3442 * 3443 * @param int $productid Id of product 3444 * @param string $htmlname Name of HTML field 3445 * @param int $selected_supplier Pre-selected supplier if more than 1 result 3446 * @return string 3447 */ 3448 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = '') 3449 { 3450 // phpcs:enable 3451 global $langs, $conf; 3452 3453 $langs->load('stocks'); 3454 3455 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,"; 3456 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,"; 3457 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name"; 3458 $sql .= " FROM ".MAIN_DB_PREFIX."product as p"; 3459 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product"; 3460 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON pfp.fk_soc = s.rowid"; 3461 $sql .= " WHERE pfp.entity IN (".getEntity('productsupplierprice').")"; 3462 $sql .= " AND p.tobuy = 1"; 3463 $sql .= " AND s.fournisseur = 1"; 3464 $sql .= " AND p.rowid = ".((int) $productid); 3465 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC"; 3466 3467 dol_syslog(get_class($this)."::select_product_fourn_price", LOG_DEBUG); 3468 $result = $this->db->query($sql); 3469 3470 if ($result) { 3471 $num = $this->db->num_rows($result); 3472 3473 $form = '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">'; 3474 3475 if (!$num) { 3476 $form .= '<option value="0">-- '.$langs->trans("NoSupplierPriceDefinedForThisProduct").' --</option>'; 3477 } else { 3478 require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; 3479 $form .= '<option value="0"> </option>'; 3480 3481 $i = 0; 3482 while ($i < $num) { 3483 $objp = $this->db->fetch_object($result); 3484 3485 $opt = '<option value="'.$objp->idprodfournprice.'"'; 3486 //if there is only one supplier, preselect it 3487 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier)) { 3488 $opt .= ' selected'; 3489 } 3490 $opt .= '>'.$objp->name.' - '.$objp->ref_fourn.' - '; 3491 3492 if (!empty($conf->dynamicprices->enabled) && !empty($objp->fk_supplier_price_expression)) { 3493 $prod_supplier = new ProductFournisseur($this->db); 3494 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice; 3495 $prod_supplier->id = $productid; 3496 $prod_supplier->fourn_qty = $objp->quantity; 3497 $prod_supplier->fourn_tva_tx = $objp->tva_tx; 3498 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression; 3499 $priceparser = new PriceParser($this->db); 3500 $price_result = $priceparser->parseProductSupplier($prod_supplier); 3501 if ($price_result >= 0) { 3502 $objp->fprice = $price_result; 3503 if ($objp->quantity >= 1) { 3504 $objp->unitprice = $objp->fprice / $objp->quantity; 3505 } 3506 } 3507 } 3508 if ($objp->quantity == 1) { 3509 $opt .= price($objp->fprice * (!empty($conf->global->DISPLAY_DISCOUNTED_SUPPLIER_PRICE) ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency)."/"; 3510 } 3511 3512 $opt .= $objp->quantity.' '; 3513 3514 if ($objp->quantity == 1) { 3515 $opt .= $langs->trans("Unit"); 3516 } else { 3517 $opt .= $langs->trans("Units"); 3518 } 3519 if ($objp->quantity > 1) { 3520 $opt .= " - "; 3521 $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"); 3522 } 3523 if ($objp->duration) { 3524 $opt .= " - ".$objp->duration; 3525 } 3526 $opt .= "</option>\n"; 3527 3528 $form .= $opt; 3529 $i++; 3530 } 3531 } 3532 3533 $form .= '</select>'; 3534 $this->db->free($result); 3535 return $form; 3536 } else { 3537 dol_print_error($this->db); 3538 } 3539 } 3540 3541 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3542 /** 3543 * Return list of delivery address 3544 * 3545 * @param string $selected Id contact pre-selectionn 3546 * @param int $socid Id of company 3547 * @param string $htmlname Name of HTML field 3548 * @param int $showempty Add an empty field 3549 * @return integer|null 3550 */ 3551 public function select_address($selected, $socid, $htmlname = 'address_id', $showempty = 0) 3552 { 3553 // phpcs:enable 3554 // looking for users 3555 $sql = "SELECT a.rowid, a.label"; 3556 $sql .= " FROM ".MAIN_DB_PREFIX."societe_address as a"; 3557 $sql .= " WHERE a.fk_soc = ".((int) $socid); 3558 $sql .= " ORDER BY a.label ASC"; 3559 3560 dol_syslog(get_class($this)."::select_address", LOG_DEBUG); 3561 $resql = $this->db->query($sql); 3562 if ($resql) { 3563 print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">'; 3564 if ($showempty) { 3565 print '<option value="0"> </option>'; 3566 } 3567 $num = $this->db->num_rows($resql); 3568 $i = 0; 3569 if ($num) { 3570 while ($i < $num) { 3571 $obj = $this->db->fetch_object($resql); 3572 3573 if ($selected && $selected == $obj->rowid) { 3574 print '<option value="'.$obj->rowid.'" selected>'.$obj->label.'</option>'; 3575 } else { 3576 print '<option value="'.$obj->rowid.'">'.$obj->label.'</option>'; 3577 } 3578 $i++; 3579 } 3580 } 3581 print '</select>'; 3582 return $num; 3583 } else { 3584 dol_print_error($this->db); 3585 } 3586 } 3587 3588 3589 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3590 /** 3591 * Load into cache list of payment terms 3592 * 3593 * @return int Nb of lines loaded, <0 if KO 3594 */ 3595 public function load_cache_conditions_paiements() 3596 { 3597 // phpcs:enable 3598 global $langs; 3599 3600 $num = count($this->cache_conditions_paiements); 3601 if ($num > 0) { 3602 return 0; // Cache already loaded 3603 } 3604 3605 dol_syslog(__METHOD__, LOG_DEBUG); 3606 3607 $sql = "SELECT rowid, code, libelle as label"; 3608 $sql .= " FROM ".MAIN_DB_PREFIX.'c_payment_term'; 3609 $sql .= " WHERE entity IN (".getEntity('c_payment_term').")"; 3610 $sql .= " AND active > 0"; 3611 $sql .= " ORDER BY sortorder"; 3612 3613 $resql = $this->db->query($sql); 3614 if ($resql) { 3615 $num = $this->db->num_rows($resql); 3616 $i = 0; 3617 while ($i < $num) { 3618 $obj = $this->db->fetch_object($resql); 3619 3620 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut 3621 $label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : '')); 3622 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code; 3623 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label; 3624 $i++; 3625 } 3626 3627 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table 3628 3629 return $num; 3630 } else { 3631 dol_print_error($this->db); 3632 return -1; 3633 } 3634 } 3635 3636 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3637 /** 3638 * Charge dans cache la liste des délais de livraison possibles 3639 * 3640 * @return int Nb of lines loaded, <0 if KO 3641 */ 3642 public function load_cache_availability() 3643 { 3644 // phpcs:enable 3645 global $langs; 3646 3647 $num = count($this->cache_availability); 3648 if ($num > 0) { 3649 return 0; // Cache already loaded 3650 } 3651 3652 dol_syslog(__METHOD__, LOG_DEBUG); 3653 3654 $langs->load('propal'); 3655 3656 $sql = "SELECT rowid, code, label, position"; 3657 $sql .= " FROM ".MAIN_DB_PREFIX.'c_availability'; 3658 $sql .= " WHERE active > 0"; 3659 3660 $resql = $this->db->query($sql); 3661 if ($resql) { 3662 $num = $this->db->num_rows($resql); 3663 $i = 0; 3664 while ($i < $num) { 3665 $obj = $this->db->fetch_object($resql); 3666 3667 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut 3668 $label = ($langs->trans("AvailabilityType".$obj->code) != ("AvailabilityType".$obj->code) ? $langs->trans("AvailabilityType".$obj->code) : ($obj->label != '-' ? $obj->label : '')); 3669 $this->cache_availability[$obj->rowid]['code'] = $obj->code; 3670 $this->cache_availability[$obj->rowid]['label'] = $label; 3671 $this->cache_availability[$obj->rowid]['position'] = $obj->position; 3672 $i++; 3673 } 3674 3675 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1); 3676 3677 return $num; 3678 } else { 3679 dol_print_error($this->db); 3680 return -1; 3681 } 3682 } 3683 3684 /** 3685 * Retourne la liste des types de delais de livraison possibles 3686 * 3687 * @param int $selected Id du type de delais pre-selectionne 3688 * @param string $htmlname Nom de la zone select 3689 * @param string $filtertype To add a filter 3690 * @param int $addempty Add empty entry 3691 * @param string $morecss More CSS 3692 * @return void 3693 */ 3694 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '') 3695 { 3696 global $langs, $user; 3697 3698 $this->load_cache_availability(); 3699 3700 dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG); 3701 3702 print '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">'; 3703 if ($addempty) { 3704 print '<option value="0"> </option>'; 3705 } 3706 foreach ($this->cache_availability as $id => $arrayavailability) { 3707 if ($selected == $id) { 3708 print '<option value="'.$id.'" selected>'; 3709 } else { 3710 print '<option value="'.$id.'">'; 3711 } 3712 print dol_escape_htmltag($arrayavailability['label']); 3713 print '</option>'; 3714 } 3715 print '</select>'; 3716 if ($user->admin) { 3717 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 3718 } 3719 print ajax_combobox($htmlname); 3720 } 3721 3722 /** 3723 * Load into cache cache_demand_reason, array of input reasons 3724 * 3725 * @return int Nb of lines loaded, <0 if KO 3726 */ 3727 public function loadCacheInputReason() 3728 { 3729 global $langs; 3730 3731 $num = count($this->cache_demand_reason); 3732 if ($num > 0) { 3733 return 0; // Cache already loaded 3734 } 3735 3736 $sql = "SELECT rowid, code, label"; 3737 $sql .= " FROM ".MAIN_DB_PREFIX.'c_input_reason'; 3738 $sql .= " WHERE active > 0"; 3739 3740 $resql = $this->db->query($sql); 3741 if ($resql) { 3742 $num = $this->db->num_rows($resql); 3743 $i = 0; 3744 $tmparray = array(); 3745 while ($i < $num) { 3746 $obj = $this->db->fetch_object($resql); 3747 3748 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut 3749 $label = ($obj->label != '-' ? $obj->label : ''); 3750 if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) { 3751 $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work 3752 } 3753 if ($langs->trans($obj->code) != $obj->code) { 3754 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work 3755 } 3756 3757 $tmparray[$obj->rowid]['id'] = $obj->rowid; 3758 $tmparray[$obj->rowid]['code'] = $obj->code; 3759 $tmparray[$obj->rowid]['label'] = $label; 3760 $i++; 3761 } 3762 3763 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1); 3764 3765 unset($tmparray); 3766 return $num; 3767 } else { 3768 dol_print_error($this->db); 3769 return -1; 3770 } 3771 } 3772 3773 /** 3774 * Return list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...) 3775 * List found into table c_input_reason loaded by loadCacheInputReason 3776 * 3777 * @param int $selected Id or code of type origin to select by default 3778 * @param string $htmlname Nom de la zone select 3779 * @param string $exclude To exclude a code value (Example: SRC_PROP) 3780 * @param int $addempty Add an empty entry 3781 * @param string $morecss Add more css to the HTML select component 3782 * @param int $notooltip Do not show the tooltip for admin 3783 * @return void 3784 */ 3785 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0) 3786 { 3787 global $langs, $user; 3788 3789 $this->loadCacheInputReason(); 3790 3791 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_'.$htmlname.'" name="'.$htmlname.'">'; 3792 if ($addempty) { 3793 print '<option value="0"'.(empty($selected) ? ' selected' : '').'> </option>'; 3794 } 3795 foreach ($this->cache_demand_reason as $id => $arraydemandreason) { 3796 if ($arraydemandreason['code'] == $exclude) { 3797 continue; 3798 } 3799 3800 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) { 3801 print '<option value="'.$arraydemandreason['id'].'" selected>'; 3802 } else { 3803 print '<option value="'.$arraydemandreason['id'].'">'; 3804 } 3805 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason 3806 print $langs->trans($label); 3807 print '</option>'; 3808 } 3809 print '</select>'; 3810 if ($user->admin && empty($notooltip)) { 3811 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 3812 } 3813 print ajax_combobox('select_'.$htmlname); 3814 } 3815 3816 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3817 /** 3818 * Charge dans cache la liste des types de paiements possibles 3819 * 3820 * @return int Nb of lines loaded, <0 if KO 3821 */ 3822 public function load_cache_types_paiements() 3823 { 3824 // phpcs:enable 3825 global $langs; 3826 3827 $num = count($this->cache_types_paiements); 3828 if ($num > 0) { 3829 return $num; // Cache already loaded 3830 } 3831 3832 dol_syslog(__METHOD__, LOG_DEBUG); 3833 3834 $this->cache_types_paiements = array(); 3835 3836 $sql = "SELECT id, code, libelle as label, type, active"; 3837 $sql .= " FROM ".MAIN_DB_PREFIX."c_paiement"; 3838 $sql .= " WHERE entity IN (".getEntity('c_paiement').")"; 3839 3840 $resql = $this->db->query($sql); 3841 if ($resql) { 3842 $num = $this->db->num_rows($resql); 3843 $i = 0; 3844 while ($i < $num) { 3845 $obj = $this->db->fetch_object($resql); 3846 3847 // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut 3848 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : '')); 3849 $this->cache_types_paiements[$obj->id]['id'] = $obj->id; 3850 $this->cache_types_paiements[$obj->id]['code'] = $obj->code; 3851 $this->cache_types_paiements[$obj->id]['label'] = $label; 3852 $this->cache_types_paiements[$obj->id]['type'] = $obj->type; 3853 $this->cache_types_paiements[$obj->id]['active'] = $obj->active; 3854 $i++; 3855 } 3856 3857 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1); 3858 3859 return $num; 3860 } else { 3861 dol_print_error($this->db); 3862 return -1; 3863 } 3864 } 3865 3866 3867 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3868 /** 3869 * Return list of payment modes. 3870 * Constant MAIN_DEFAULT_PAYMENT_TERM_ID can used to set default value but scope is all application, probably not what you want. 3871 * See instead to force the default value by the caller. 3872 * 3873 * @param int $selected Id of payment term to preselect by default 3874 * @param string $htmlname Nom de la zone select 3875 * @param int $filtertype Not used 3876 * @param int $addempty Add an empty entry 3877 * @param int $noinfoadmin 0=Add admin info, 1=Disable admin info 3878 * @param string $morecss Add more CSS on select tag 3879 * @return void 3880 */ 3881 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '') 3882 { 3883 // phpcs:enable 3884 global $langs, $user, $conf; 3885 3886 dol_syslog(__METHOD__." selected=".$selected.", htmlname=".$htmlname, LOG_DEBUG); 3887 3888 $this->load_cache_conditions_paiements(); 3889 3890 // Set default value if not already set by caller 3891 if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID)) { 3892 $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TERM_ID; 3893 } 3894 3895 print '<select id="'.$htmlname.'" class="flat selectpaymentterms'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">'; 3896 if ($addempty) { 3897 print '<option value="0"> </option>'; 3898 } 3899 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) { 3900 if ($selected == $id) { 3901 print '<option value="'.$id.'" selected>'; 3902 } else { 3903 print '<option value="'.$id.'">'; 3904 } 3905 print $arrayconditions['label']; 3906 print '</option>'; 3907 } 3908 print '</select>'; 3909 if ($user->admin && empty($noinfoadmin)) { 3910 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 3911 } 3912 print ajax_combobox($htmlname); 3913 } 3914 3915 3916 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 3917 /** 3918 * Return list of payment methods 3919 * Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value but scope is all application, probably not what you want. 3920 * 3921 * @param string $selected Id or code or preselected payment mode 3922 * @param string $htmlname Name of select field 3923 * @param string $filtertype To filter on field type in llx_c_paiement ('CRDT' or 'DBIT' or array('code'=>xx,'label'=>zz)) 3924 * @param int $format 0=id+label, 1=code+code, 2=code+label, 3=id+code 3925 * @param int $empty 1=can be empty, 0 otherwise 3926 * @param int $noadmininfo 0=Add admin info, 1=Disable admin info 3927 * @param int $maxlength Max length of label 3928 * @param int $active Active or not, -1 = all 3929 * @param string $morecss Add more CSS on select tag 3930 * @return void 3931 */ 3932 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '') 3933 { 3934 // phpcs:enable 3935 global $langs, $user, $conf; 3936 3937 dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$filtertype.", ".$format, LOG_DEBUG); 3938 3939 $filterarray = array(); 3940 if ($filtertype == 'CRDT') { 3941 $filterarray = array(0, 2, 3); 3942 } elseif ($filtertype == 'DBIT') { 3943 $filterarray = array(1, 2, 3); 3944 } elseif ($filtertype != '' && $filtertype != '-1') { 3945 $filterarray = explode(',', $filtertype); 3946 } 3947 3948 $this->load_cache_types_paiements(); 3949 3950 // Set default value if not already set by caller 3951 if (empty($selected) && !empty($conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID)) { 3952 $selected = $conf->global->MAIN_DEFAULT_PAYMENT_TYPE_ID; 3953 } 3954 3955 print '<select id="select'.$htmlname.'" class="flat selectpaymenttypes'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">'; 3956 if ($empty) { 3957 print '<option value=""> </option>'; 3958 } 3959 foreach ($this->cache_types_paiements as $id => $arraytypes) { 3960 // If not good status 3961 if ($active >= 0 && $arraytypes['active'] != $active) { 3962 continue; 3963 } 3964 3965 // On passe si on a demande de filtrer sur des modes de paiments particuliers 3966 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) { 3967 continue; 3968 } 3969 3970 // We discard empty line if showempty is on because an empty line has already been output. 3971 if ($empty && empty($arraytypes['code'])) { 3972 continue; 3973 } 3974 3975 if ($format == 0) { 3976 print '<option value="'.$id.'"'; 3977 } elseif ($format == 1) { 3978 print '<option value="'.$arraytypes['code'].'"'; 3979 } elseif ($format == 2) { 3980 print '<option value="'.$arraytypes['code'].'"'; 3981 } elseif ($format == 3) { 3982 print '<option value="'.$id.'"'; 3983 } 3984 // Print attribute selected or not 3985 if ($format == 1 || $format == 2) { 3986 if ($selected == $arraytypes['code']) { 3987 print ' selected'; 3988 } 3989 } else { 3990 if ($selected == $id) { 3991 print ' selected'; 3992 } 3993 } 3994 print '>'; 3995 if ($format == 0) { 3996 $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']); 3997 } elseif ($format == 1) { 3998 $value = $arraytypes['code']; 3999 } elseif ($format == 2) { 4000 $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']); 4001 } elseif ($format == 3) { 4002 $value = $arraytypes['code']; 4003 } 4004 print $value ? $value : ' '; 4005 print '</option>'; 4006 } 4007 print '</select>'; 4008 if ($user->admin && !$noadmininfo) { 4009 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 4010 } 4011 print ajax_combobox('select'.$htmlname); 4012 } 4013 4014 4015 /** 4016 * Selection HT or TTC 4017 * 4018 * @param string $selected Id pre-selectionne 4019 * @param string $htmlname Nom de la zone select 4020 * @param string $addjscombo Add js combo 4021 * @return string Code of HTML select to chose tax or not 4022 */ 4023 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0) 4024 { 4025 global $langs; 4026 4027 $return = '<select class="flat maxwidth100" id="select_'.$htmlname.'" name="'.$htmlname.'">'; 4028 $options = array( 4029 'HT'=>$langs->trans("HT"), 4030 'TTC'=>$langs->trans("TTC") 4031 ); 4032 foreach ($options as $id => $value) { 4033 if ($selected == $id) { 4034 $return .= '<option value="'.$id.'" selected>'.$value; 4035 } else { 4036 $return .= '<option value="'.$id.'">'.$value; 4037 } 4038 $return .= '</option>'; 4039 } 4040 $return .= '</select>'; 4041 if ($addjscombo) { 4042 $return .= ajax_combobox('select_'.$htmlname); 4043 } 4044 4045 return $return; 4046 } 4047 4048 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 4049 /** 4050 * Load in cache list of transport mode 4051 * 4052 * @return int Nb of lines loaded, <0 if KO 4053 */ 4054 public function load_cache_transport_mode() 4055 { 4056 // phpcs:enable 4057 global $langs; 4058 4059 $num = count($this->cache_transport_mode); 4060 if ($num > 0) { 4061 return $num; // Cache already loaded 4062 } 4063 4064 dol_syslog(__METHOD__, LOG_DEBUG); 4065 4066 $this->cache_transport_mode = array(); 4067 4068 $sql = "SELECT rowid, code, label, active"; 4069 $sql .= " FROM ".MAIN_DB_PREFIX."c_transport_mode"; 4070 $sql .= " WHERE entity IN (".getEntity('c_transport_mode').")"; 4071 4072 $resql = $this->db->query($sql); 4073 if ($resql) { 4074 $num = $this->db->num_rows($resql); 4075 $i = 0; 4076 while ($i < $num) { 4077 $obj = $this->db->fetch_object($resql); 4078 4079 // If traduction exist, we use it else we take the default label 4080 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) != ("PaymentTypeShort".$obj->code) ? $langs->transnoentitiesnoconv("PaymentTypeShort".$obj->code) : ($obj->label != '-' ? $obj->label : '')); 4081 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid; 4082 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code; 4083 $this->cache_transport_mode[$obj->rowid]['label'] = $label; 4084 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active; 4085 $i++; 4086 } 4087 4088 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1); 4089 4090 return $num; 4091 } else { 4092 dol_print_error($this->db); 4093 return -1; 4094 } 4095 } 4096 4097 /** 4098 * Return list of transport mode for intracomm report 4099 * 4100 * @param string $selected Id of the transport mode pre-selected 4101 * @param string $htmlname Name of the select field 4102 * @param int $format 0=id+label, 1=code+code, 2=code+label, 3=id+code 4103 * @param int $empty 1=can be empty, 0 else 4104 * @param int $noadmininfo 0=Add admin info, 1=Disable admin info 4105 * @param int $maxlength Max length of label 4106 * @param int $active Active or not, -1 = all 4107 * @param string $morecss Add more CSS on select tag 4108 * @return void 4109 */ 4110 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '') 4111 { 4112 global $langs, $user; 4113 4114 dol_syslog(__METHOD__." ".$selected.", ".$htmlname.", ".$format, LOG_DEBUG); 4115 4116 $this->load_cache_transport_mode(); 4117 4118 print '<select id="select'.$htmlname.'" class="flat selectmodetransport'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'">'; 4119 if ($empty) { 4120 print '<option value=""> </option>'; 4121 } 4122 foreach ($this->cache_transport_mode as $id => $arraytypes) { 4123 // If not good status 4124 if ($active >= 0 && $arraytypes['active'] != $active) { 4125 continue; 4126 } 4127 4128 // We discard empty line if showempty is on because an empty line has already been output. 4129 if ($empty && empty($arraytypes['code'])) { 4130 continue; 4131 } 4132 4133 if ($format == 0) { 4134 print '<option value="'.$id.'"'; 4135 } elseif ($format == 1) { 4136 print '<option value="'.$arraytypes['code'].'"'; 4137 } elseif ($format == 2) { 4138 print '<option value="'.$arraytypes['code'].'"'; 4139 } elseif ($format == 3) { 4140 print '<option value="'.$id.'"'; 4141 } 4142 // If text is selected, we compare with code, else with id 4143 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) { 4144 print ' selected'; 4145 } elseif ($selected == $id) { 4146 print ' selected'; 4147 } 4148 print '>'; 4149 if ($format == 0) { 4150 $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']); 4151 } elseif ($format == 1) { 4152 $value = $arraytypes['code']; 4153 } elseif ($format == 2) { 4154 $value = ($maxlength ?dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']); 4155 } elseif ($format == 3) { 4156 $value = $arraytypes['code']; 4157 } 4158 print $value ? $value : ' '; 4159 print '</option>'; 4160 } 4161 print '</select>'; 4162 if ($user->admin && !$noadmininfo) { 4163 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 4164 } 4165 } 4166 4167 /** 4168 * Return a HTML select list of shipping mode 4169 * 4170 * @param string $selected Id shipping mode pre-selected 4171 * @param string $htmlname Name of select zone 4172 * @param string $filtre To filter list. This parameter must not come from input of users 4173 * @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. 4174 * @param string $moreattrib To add more attribute on select 4175 * @param int $noinfoadmin 0=Add admin info, 1=Disable admin info 4176 * @param string $morecss More CSS 4177 * @return void 4178 */ 4179 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '') 4180 { 4181 global $langs, $conf, $user; 4182 4183 $langs->load("admin"); 4184 $langs->load("deliveries"); 4185 4186 $sql = "SELECT rowid, code, libelle as label"; 4187 $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode"; 4188 $sql .= " WHERE active > 0"; 4189 if ($filtre) { 4190 $sql .= " AND ".$filtre; 4191 } 4192 $sql .= " ORDER BY libelle ASC"; 4193 4194 dol_syslog(get_class($this)."::selectShippingMode", LOG_DEBUG); 4195 $result = $this->db->query($sql); 4196 if ($result) { 4197 $num = $this->db->num_rows($result); 4198 $i = 0; 4199 if ($num) { 4200 print '<select id="select'.$htmlname.'" class="flat selectshippingmethod'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>'; 4201 if ($useempty == 1 || ($useempty == 2 && $num > 1)) { 4202 print '<option value="-1"> </option>'; 4203 } 4204 while ($i < $num) { 4205 $obj = $this->db->fetch_object($result); 4206 if ($selected == $obj->rowid) { 4207 print '<option value="'.$obj->rowid.'" selected>'; 4208 } else { 4209 print '<option value="'.$obj->rowid.'">'; 4210 } 4211 print ($langs->trans("SendingMethod".strtoupper($obj->code)) != "SendingMethod".strtoupper($obj->code)) ? $langs->trans("SendingMethod".strtoupper($obj->code)) : $obj->label; 4212 print '</option>'; 4213 $i++; 4214 } 4215 print "</select>"; 4216 if ($user->admin && empty($noinfoadmin)) { 4217 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 4218 } 4219 4220 print ajax_combobox('select'.$htmlname); 4221 } else { 4222 print $langs->trans("NoShippingMethodDefined"); 4223 } 4224 } else { 4225 dol_print_error($this->db); 4226 } 4227 } 4228 4229 /** 4230 * Display form to select shipping mode 4231 * 4232 * @param string $page Page 4233 * @param int $selected Id of shipping mode 4234 * @param string $htmlname Name of select html field 4235 * @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. 4236 * @return void 4237 */ 4238 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0) 4239 { 4240 global $langs, $db; 4241 4242 $langs->load("deliveries"); 4243 4244 if ($htmlname != "none") { 4245 print '<form method="POST" action="'.$page.'">'; 4246 print '<input type="hidden" name="action" value="setshippingmethod">'; 4247 print '<input type="hidden" name="token" value="'.newToken().'">'; 4248 $this->selectShippingMethod($selected, $htmlname, '', $addempty); 4249 print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">'; 4250 print '</form>'; 4251 } else { 4252 if ($selected) { 4253 $code = $langs->getLabelFromKey($db, $selected, 'c_shipment_mode', 'rowid', 'code'); 4254 print $langs->trans("SendingMethod".strtoupper($code)); 4255 } else { 4256 print " "; 4257 } 4258 } 4259 } 4260 4261 /** 4262 * Creates HTML last in cycle situation invoices selector 4263 * 4264 * @param string $selected Preselected ID 4265 * @param int $socid Company ID 4266 * 4267 * @return string HTML select 4268 */ 4269 public function selectSituationInvoices($selected = '', $socid = 0) 4270 { 4271 global $langs; 4272 4273 $langs->load('bills'); 4274 4275 $opt = '<option value ="" selected></option>'; 4276 $sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc'; 4277 $sql .= ' FROM '.MAIN_DB_PREFIX.'facture'; 4278 $sql .= ' WHERE entity IN ('.getEntity('invoice').')'; 4279 $sql .= ' AND situation_counter >= 1'; 4280 $sql .= ' AND fk_soc = '.(int) $socid; 4281 $sql .= ' AND type <> 2'; 4282 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc'; 4283 $resql = $this->db->query($sql); 4284 4285 if ($resql && $this->db->num_rows($resql) > 0) { 4286 // Last seen cycle 4287 $ref = 0; 4288 while ($obj = $this->db->fetch_object($resql)) { 4289 //Same cycle ? 4290 if ($obj->situation_cycle_ref != $ref) { 4291 // Just seen this cycle 4292 $ref = $obj->situation_cycle_ref; 4293 //not final ? 4294 if ($obj->situation_final != 1) { 4295 //Not prov? 4296 if (substr($obj->ref, 1, 4) != 'PROV') { 4297 if ($selected == $obj->rowid) { 4298 $opt .= '<option value="'.$obj->rowid.'" selected>'.$obj->ref.'</option>'; 4299 } else { 4300 $opt .= '<option value="'.$obj->rowid.'">'.$obj->ref.'</option>'; 4301 } 4302 } 4303 } 4304 } 4305 } 4306 } else { 4307 dol_syslog("Error sql=".$sql.", error=".$this->error, LOG_ERR); 4308 } 4309 if ($opt == '<option value ="" selected></option>') { 4310 $opt = '<option value ="0" selected>'.$langs->trans('NoSituations').'</option>'; 4311 } 4312 return $opt; 4313 } 4314 4315 /** 4316 * Creates HTML units selector (code => label) 4317 * 4318 * @param string $selected Preselected Unit ID 4319 * @param string $htmlname Select name 4320 * @param int $showempty Add a nempty line 4321 * @param string $unit_type Restrict to one given unit type 4322 * @return string HTML select 4323 */ 4324 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '') 4325 { 4326 global $langs; 4327 4328 $langs->load('products'); 4329 4330 $return = '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">'; 4331 4332 $sql = 'SELECT rowid, label, code from '.MAIN_DB_PREFIX.'c_units'; 4333 $sql .= ' WHERE active > 0'; 4334 if (!empty($unit_type)) { 4335 $sql .= " AND unit_type = '".$this->db->escape($unit_type)."'"; 4336 } 4337 4338 $resql = $this->db->query($sql); 4339 if ($resql && $this->db->num_rows($resql) > 0) { 4340 if ($showempty) { 4341 $return .= '<option value="none"></option>'; 4342 } 4343 4344 while ($res = $this->db->fetch_object($resql)) { 4345 $unitLabel = $res->label; 4346 if (!empty($langs->tab_translate['unit'.$res->code])) { // check if Translation is available before 4347 $unitLabel = $langs->trans('unit'.$res->code) != $res->label ? $langs->trans('unit'.$res->code) : $res->label; 4348 } 4349 4350 if ($selected == $res->rowid) { 4351 $return .= '<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>'; 4352 } else { 4353 $return .= '<option value="'.$res->rowid.'">'.$unitLabel.'</option>'; 4354 } 4355 } 4356 $return .= '</select>'; 4357 } 4358 return $return; 4359 } 4360 4361 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 4362 /** 4363 * Return a HTML select list of bank accounts 4364 * 4365 * @param string $selected Id account pre-selected 4366 * @param string $htmlname Name of select zone 4367 * @param int $status Status of searched accounts (0=open, 1=closed, 2=both) 4368 * @param string $filtre To filter list. This parameter must not come from input of users 4369 * @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. 4370 * @param string $moreattrib To add more attribute on select 4371 * @param int $showcurrency Show currency in label 4372 * @param string $morecss More CSS 4373 * @param int $nooutput 1=Return string, do not send to output 4374 * @return int <0 if error, Num of bank account found if OK (0, 1, 2, ...) 4375 */ 4376 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0) 4377 { 4378 // phpcs:enable 4379 global $langs, $conf; 4380 4381 $out = ''; 4382 4383 $langs->load("admin"); 4384 $num = 0; 4385 4386 $sql = "SELECT rowid, label, bank, clos as status, currency_code"; 4387 $sql .= " FROM ".MAIN_DB_PREFIX."bank_account"; 4388 $sql .= " WHERE entity IN (".getEntity('bank_account').")"; 4389 if ($status != 2) { 4390 $sql .= " AND clos = ".(int) $status; 4391 } 4392 if ($filtre) { 4393 $sql .= " AND ".$filtre; 4394 } 4395 $sql .= " ORDER BY label"; 4396 4397 dol_syslog(get_class($this)."::select_comptes", LOG_DEBUG); 4398 $result = $this->db->query($sql); 4399 if ($result) { 4400 $num = $this->db->num_rows($result); 4401 $i = 0; 4402 if ($num) { 4403 $out .= '<select id="select'.$htmlname.'" class="flat selectbankaccount'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>'; 4404 if ($useempty == 1 || ($useempty == 2 && $num > 1)) { 4405 $out .= '<option value="-1"> </option>'; 4406 } 4407 4408 while ($i < $num) { 4409 $obj = $this->db->fetch_object($result); 4410 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) { 4411 $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'" selected>'; 4412 } else { 4413 $out .= '<option value="'.$obj->rowid.'" data-currency-code="'.$obj->currency_code.'">'; 4414 } 4415 $out .= trim($obj->label); 4416 if ($showcurrency) { 4417 $out .= ' ('.$obj->currency_code.')'; 4418 } 4419 if ($status == 2 && $obj->status == 1) { 4420 $out .= ' ('.$langs->trans("Closed").')'; 4421 } 4422 $out .= '</option>'; 4423 $i++; 4424 } 4425 $out .= "</select>"; 4426 $out .= ajax_combobox('select'.$htmlname); 4427 } else { 4428 if ($status == 0) { 4429 $out .= '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>'; 4430 } else { 4431 $out .= '<span class="opacitymedium">'.$langs->trans("NoBankAccountFound").'</span>'; 4432 } 4433 } 4434 } else { 4435 dol_print_error($this->db); 4436 } 4437 4438 // Output or return 4439 if (empty($nooutput)) { 4440 print $out; 4441 } else { 4442 return $out; 4443 } 4444 4445 return $num; 4446 } 4447 4448 /** 4449 * Return a HTML select list of establishment 4450 * 4451 * @param string $selected Id establishment pre-selected 4452 * @param string $htmlname Name of select zone 4453 * @param int $status Status of searched establishment (0=open, 1=closed, 2=both) 4454 * @param string $filtre To filter list. This parameter must not come from input of users 4455 * @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. 4456 * @param string $moreattrib To add more attribute on select 4457 * @return int <0 if error, Num of establishment found if OK (0, 1, 2, ...) 4458 */ 4459 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '') 4460 { 4461 // phpcs:enable 4462 global $langs, $conf; 4463 4464 $langs->load("admin"); 4465 $num = 0; 4466 4467 $sql = "SELECT rowid, name, fk_country, status, entity"; 4468 $sql .= " FROM ".MAIN_DB_PREFIX."establishment"; 4469 $sql .= " WHERE 1=1"; 4470 if ($status != 2) { 4471 $sql .= " AND status = ".(int) $status; 4472 } 4473 if ($filtre) { 4474 $sql .= " AND ".$filtre; 4475 } 4476 $sql .= " ORDER BY name"; 4477 4478 dol_syslog(get_class($this)."::select_establishment", LOG_DEBUG); 4479 $result = $this->db->query($sql); 4480 if ($result) { 4481 $num = $this->db->num_rows($result); 4482 $i = 0; 4483 if ($num) { 4484 print '<select id="select'.$htmlname.'" class="flat selectestablishment" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>'; 4485 if ($useempty == 1 || ($useempty == 2 && $num > 1)) { 4486 print '<option value="-1"> </option>'; 4487 } 4488 4489 while ($i < $num) { 4490 $obj = $this->db->fetch_object($result); 4491 if ($selected == $obj->rowid) { 4492 print '<option value="'.$obj->rowid.'" selected>'; 4493 } else { 4494 print '<option value="'.$obj->rowid.'">'; 4495 } 4496 print trim($obj->name); 4497 if ($status == 2 && $obj->status == 1) { 4498 print ' ('.$langs->trans("Closed").')'; 4499 } 4500 print '</option>'; 4501 $i++; 4502 } 4503 print "</select>"; 4504 } else { 4505 if ($status == 0) { 4506 print '<span class="opacitymedium">'.$langs->trans("NoActiveEstablishmentDefined").'</span>'; 4507 } else { 4508 print '<span class="opacitymedium">'.$langs->trans("NoEstablishmentFound").'</span>'; 4509 } 4510 } 4511 } else { 4512 dol_print_error($this->db); 4513 } 4514 } 4515 4516 /** 4517 * Display form to select bank account 4518 * 4519 * @param string $page Page 4520 * @param int $selected Id of bank account 4521 * @param string $htmlname Name of select html field 4522 * @param int $addempty 1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries. 4523 * @return void 4524 */ 4525 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0) 4526 { 4527 global $langs; 4528 if ($htmlname != "none") { 4529 print '<form method="POST" action="'.$page.'">'; 4530 print '<input type="hidden" name="action" value="setbankaccount">'; 4531 print '<input type="hidden" name="token" value="'.newToken().'">'; 4532 print img_picto('', 'bank_account', 'class="pictofixedwidth"'); 4533 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty); 4534 if ($nbaccountfound > 0) { 4535 print '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">'; 4536 } 4537 print '</form>'; 4538 } else { 4539 $langs->load('banks'); 4540 4541 if ($selected) { 4542 require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; 4543 $bankstatic = new Account($this->db); 4544 $result = $bankstatic->fetch($selected); 4545 if ($result) { 4546 print $bankstatic->getNomUrl(1); 4547 } 4548 } else { 4549 print " "; 4550 } 4551 } 4552 } 4553 4554 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 4555 /** 4556 * Return list of categories having choosed type 4557 * 4558 * @param string|int $type Type of category ('customer', 'supplier', 'contact', 'product', 'member'). Old mode (0, 1, 2, ...) is deprecated. 4559 * @param string $selected Id of category preselected or 'auto' (autoselect category if there is only one element). Not used if $outputmode = 1. 4560 * @param string $htmlname HTML field name 4561 * @param int $maxlength Maximum length for labels 4562 * @param int|string|array $markafterid Keep only or removed all categories including the leaf $markafterid in category tree (exclude) or Keep only of category is inside the leaf starting with this id. 4563 * $markafterid can be an : 4564 * - int (id of category) 4565 * - string (categories ids seprated by comma) 4566 * - array (list of categories ids) 4567 * @param int $outputmode 0=HTML select string, 1=Array 4568 * @param int $include [=0] Removed or 1=Keep only 4569 * @param string $morecss More CSS 4570 * @return string 4571 * @see select_categories() 4572 */ 4573 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $markafterid = 0, $outputmode = 0, $include = 0, $morecss = '') 4574 { 4575 // phpcs:enable 4576 global $conf, $langs; 4577 $langs->load("categories"); 4578 4579 include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; 4580 4581 // For backward compatibility 4582 if (is_numeric($type)) { 4583 dol_syslog(__METHOD__.': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING); 4584 } 4585 4586 if ($type === Categorie::TYPE_BANK_LINE) { 4587 // TODO Move this into common category feature 4588 $cate_arbo = array(); 4589 $sql = "SELECT c.label, c.rowid"; 4590 $sql .= " FROM ".MAIN_DB_PREFIX."bank_categ as c"; 4591 $sql .= " WHERE entity = ".$conf->entity; 4592 $sql .= " ORDER BY c.label"; 4593 $result = $this->db->query($sql); 4594 if ($result) { 4595 $num = $this->db->num_rows($result); 4596 $i = 0; 4597 while ($i < $num) { 4598 $objp = $this->db->fetch_object($result); 4599 if ($objp) { 4600 $cate_arbo[$objp->rowid] = array('id'=>$objp->rowid, 'fulllabel'=>$objp->label); 4601 } 4602 $i++; 4603 } 4604 $this->db->free($result); 4605 } else { 4606 dol_print_error($this->db); 4607 } 4608 } else { 4609 $cat = new Categorie($this->db); 4610 $cate_arbo = $cat->get_full_arbo($type, $markafterid, $include); 4611 } 4612 4613 $output = '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$htmlname.'" id="'.$htmlname.'">'; 4614 $outarray = array(); 4615 if (is_array($cate_arbo)) { 4616 if (!count($cate_arbo)) { 4617 $output .= '<option value="-1" disabled>'.$langs->trans("NoCategoriesDefined").'</option>'; 4618 } else { 4619 $output .= '<option value="-1"> </option>'; 4620 foreach ($cate_arbo as $key => $value) { 4621 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) { 4622 $add = 'selected '; 4623 } else { 4624 $add = ''; 4625 } 4626 $output .= '<option '.$add.'value="'.$cate_arbo[$key]['id'].'">'.dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle').'</option>'; 4627 4628 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel']; 4629 } 4630 } 4631 } 4632 $output .= '</select>'; 4633 $output .= "\n"; 4634 4635 if ($outputmode) { 4636 return $outarray; 4637 } 4638 return $output; 4639 } 4640 4641 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 4642 /** 4643 * Show a confirmation HTML form or AJAX popup 4644 * 4645 * @param string $page Url of page to call if confirmation is OK 4646 * @param string $title Title 4647 * @param string $question Question 4648 * @param string $action Action 4649 * @param array $formquestion An array with forms complementary inputs 4650 * @param string $selectedchoice "" or "no" or "yes" 4651 * @param int $useajax 0=No, 1=Yes, 2=Yes but submit page with &confirm=no if choice is No, 'xxx'=preoutput confirm box with div id=dialog-confirm-xxx 4652 * @param int $height Force height of box 4653 * @param int $width Force width of box 4654 * @return void 4655 * @deprecated 4656 * @see formconfirm() 4657 */ 4658 public function form_confirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = "", $useajax = 0, $height = 170, $width = 500) 4659 { 4660 // phpcs:enable 4661 dol_syslog(__METHOD__.': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING); 4662 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width); 4663 } 4664 4665 /** 4666 * Show a confirmation HTML form or AJAX popup. 4667 * Easiest way to use this is with useajax=1. 4668 * If you use useajax='xxx', you must also add jquery code to trigger opening of box (with correct parameters) 4669 * just after calling this method. For example: 4670 * print '<script type="text/javascript">'."\n"; 4671 * print 'jQuery(document).ready(function() {'."\n"; 4672 * print 'jQuery(".xxxlink").click(function(e) { jQuery("#aparamid").val(jQuery(this).attr("rel")); jQuery("#dialog-confirm-xxx").dialog("open"); return false; });'."\n"; 4673 * print '});'."\n"; 4674 * print '</script>'."\n"; 4675 * 4676 * @param string $page Url of page to call if confirmation is OK. Can contains parameters (param 'action' and 'confirm' will be reformated) 4677 * @param string $title Title 4678 * @param string $question Question 4679 * @param string $action Action 4680 * @param array|string $formquestion An array with complementary inputs to add into forms: array(array('label'=> ,'type'=> , 'size'=>, 'morecss'=>, 'moreattr'=>)) 4681 * type can be 'hidden', 'text', 'password', 'checkbox', 'radio', 'date', 'morecss', 'other' or 'onecolumn'... 4682 * @param string $selectedchoice '' or 'no', or 'yes' or '1' or '0' 4683 * @param int|string $useajax 0=No, 1=Yes, 2=Yes but submit page with &confirm=no if choice is No, 'xxx'=Yes and preoutput confirm box with div id=dialog-confirm-xxx 4684 * @param int|string $height Force height of box (0 = auto) 4685 * @param int $width Force width of box ('999' or '90%'). Ignored and forced to 90% on smartphones. 4686 * @param int $disableformtag 1=Disable form tag. Can be used if we are already inside a <form> section. 4687 * @return string HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form 4688 */ 4689 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0) 4690 { 4691 global $langs, $conf; 4692 4693 $more = '<!-- formconfirm before calling page='.dol_escape_htmltag($page).' -->'; 4694 $formconfirm = ''; 4695 $inputok = array(); 4696 $inputko = array(); 4697 4698 // Clean parameters 4699 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice; 4700 if ($conf->browser->layout == 'phone') { 4701 $width = '95%'; 4702 } 4703 4704 // Set height automatically if not defined 4705 if (empty($height)) { 4706 $height = 220; 4707 if (is_array($formquestion) && count($formquestion) > 2) { 4708 $height += ((count($formquestion) - 2) * 24); 4709 } 4710 } 4711 4712 if (is_array($formquestion) && !empty($formquestion)) { 4713 // First add hidden fields and value 4714 foreach ($formquestion as $key => $input) { 4715 if (is_array($input) && !empty($input)) { 4716 if ($input['type'] == 'hidden') { 4717 $more .= '<input type="hidden" id="'.$input['name'].'" name="'.$input['name'].'" value="'.dol_escape_htmltag($input['value']).'">'."\n"; 4718 } 4719 } 4720 } 4721 4722 // Now add questions 4723 $moreonecolumn = ''; 4724 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">'."\n"; 4725 foreach ($formquestion as $key => $input) { 4726 if (is_array($input) && !empty($input)) { 4727 $size = (!empty($input['size']) ? ' size="'.$input['size'].'"' : ''); // deprecated. Use morecss instead. 4728 $moreattr = (!empty($input['moreattr']) ? ' '.$input['moreattr'] : ''); 4729 $morecss = (!empty($input['morecss']) ? ' '.$input['morecss'] : ''); 4730 4731 if ($input['type'] == 'text') { 4732 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="text" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n"; 4733 } elseif ($input['type'] == 'password') { 4734 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd"><input type="password" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$size.' value="'.$input['value'].'"'.$moreattr.' /></div></div>'."\n"; 4735 } elseif ($input['type'] == 'select') { 4736 if (empty($morecss)) { 4737 $morecss = 'minwidth100'; 4738 } 4739 4740 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1; 4741 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0; 4742 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0; 4743 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0; 4744 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0; 4745 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0; 4746 $sort = isset($input['select_sort']) ? $input['select_sort'] : ''; 4747 4748 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'; 4749 if (!empty($input['label'])) { 4750 $more .= $input['label'].'</div><div class="tagtd left">'; 4751 } 4752 $more .= $this->selectarray($input['name'], $input['values'], $input['default'], $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss); 4753 $more .= '</div></div>'."\n"; 4754 } elseif ($input['type'] == 'checkbox') { 4755 $more .= '<div class="tagtr">'; 4756 $more .= '<div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].' </div><div class="tagtd">'; 4757 $more .= '<input type="checkbox" class="flat'.$morecss.'" id="'.$input['name'].'" name="'.$input['name'].'"'.$moreattr; 4758 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0') { 4759 $more .= ' checked'; 4760 } 4761 if (is_bool($input['value']) && $input['value']) { 4762 $more .= ' checked'; 4763 } 4764 if (isset($input['disabled'])) { 4765 $more .= ' disabled'; 4766 } 4767 $more .= ' /></div>'; 4768 $more .= '</div>'."\n"; 4769 } elseif ($input['type'] == 'radio') { 4770 $i = 0; 4771 foreach ($input['values'] as $selkey => $selval) { 4772 $more .= '<div class="tagtr">'; 4773 if ($i == 0) { 4774 $more .= '<div class="tagtd'.(empty($input['tdclass']) ? ' tdtop' : (' tdtop '.$input['tdclass'])).'">'.$input['label'].'</div>'; 4775 } else { 4776 $more .= '<div clas="tagtd'.(empty($input['tdclass']) ? '' : (' "'.$input['tdclass'])).'"> </div>'; 4777 } 4778 $more .= '<div class="tagtd'.($i == 0 ? ' tdtop' : '').'"><input type="radio" class="flat'.$morecss.'" id="'.$input['name'].$selkey.'" name="'.$input['name'].'" value="'.$selkey.'"'.$moreattr; 4779 if ($input['disabled']) { 4780 $more .= ' disabled'; 4781 } 4782 if (isset($input['default']) && $input['default'] === $selkey) { 4783 $more .= ' checked="checked"'; 4784 } 4785 $more .= ' /> '; 4786 $more .= '<label for="'.$input['name'].$selkey.'">'.$selval.'</label>'; 4787 $more .= '</div></div>'."\n"; 4788 $i++; 4789 } 4790 } elseif ($input['type'] == 'date') { 4791 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div>'; 4792 $more .= '<div class="tagtd">'; 4793 $more .= $this->selectDate($input['value'], $input['name'], 0, 0, 0, '', 1, 0); 4794 $more .= '</div></div>'."\n"; 4795 $formquestion[] = array('name'=>$input['name'].'day'); 4796 $formquestion[] = array('name'=>$input['name'].'month'); 4797 $formquestion[] = array('name'=>$input['name'].'year'); 4798 $formquestion[] = array('name'=>$input['name'].'hour'); 4799 $formquestion[] = array('name'=>$input['name'].'min'); 4800 } elseif ($input['type'] == 'other') { 4801 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'; 4802 if (!empty($input['label'])) { 4803 $more .= $input['label'].'</div><div class="tagtd">'; 4804 } 4805 $more .= $input['value']; 4806 $more .= '</div></div>'."\n"; 4807 } elseif ($input['type'] == 'onecolumn') { 4808 $moreonecolumn .= '<div class="margintoponly">'; 4809 $moreonecolumn .= $input['value']; 4810 $moreonecolumn .= '</div>'."\n"; 4811 } elseif ($input['type'] == 'hidden') { 4812 // Do nothing more, already added by a previous loop 4813 } else { 4814 $more .= 'Error type '.$input['type'].' for the confirm box is not a supported type'; 4815 } 4816 } 4817 } 4818 $more .= '</div>'."\n"; 4819 $more .= $moreonecolumn; 4820 } 4821 4822 // JQUI method dialog is broken with jmobile, we use standard HTML. 4823 // Note: When using dol_use_jmobile or no js, you must also check code for button use a GET url with action=xxx and check that you also output the confirm code when action=xxx 4824 // See page product/card.php for example 4825 if (!empty($conf->dol_use_jmobile)) { 4826 $useajax = 0; 4827 } 4828 if (empty($conf->use_javascript_ajax)) { 4829 $useajax = 0; 4830 } 4831 4832 if ($useajax) { 4833 $autoOpen = true; 4834 $dialogconfirm = 'dialog-confirm'; 4835 $button = ''; 4836 if (!is_numeric($useajax)) { 4837 $button = $useajax; 4838 $useajax = 1; 4839 $autoOpen = false; 4840 $dialogconfirm .= '-'.$button; 4841 } 4842 $pageyes = $page.(preg_match('/\?/', $page) ? '&' : '?').'action='.$action.'&confirm=yes'; 4843 $pageno = ($useajax == 2 ? $page.(preg_match('/\?/', $page) ? '&' : '?').'confirm=no' : ''); 4844 4845 // Add input fields into list of fields to read during submit (inputok and inputko) 4846 if (is_array($formquestion)) { 4847 foreach ($formquestion as $key => $input) { 4848 //print "xx ".$key." rr ".is_array($input)."<br>\n"; 4849 // Add name of fields to propagate with the GET when submitting the form with button OK. 4850 if (is_array($input) && isset($input['name'])) { 4851 if (strpos($input['name'], ',') > 0) { 4852 $inputok = array_merge($inputok, explode(',', $input['name'])); 4853 } else { 4854 array_push($inputok, $input['name']); 4855 } 4856 } 4857 // Add name of fields to propagate with the GET when submitting the form with button KO. 4858 if (isset($input['inputko']) && $input['inputko'] == 1) { 4859 array_push($inputko, $input['name']); 4860 } 4861 } 4862 } 4863 4864 // Show JQuery confirm box. 4865 $formconfirm .= '<div id="'.$dialogconfirm.'" title="'.dol_escape_htmltag($title).'" style="display: none;">'; 4866 if (is_array($formquestion) && !empty($formquestion['text'])) { 4867 $formconfirm .= '<div class="confirmtext">'.$formquestion['text'].'</div>'."\n"; 4868 } 4869 if (!empty($more)) { 4870 $formconfirm .= '<div class="confirmquestions">'.$more.'</div>'."\n"; 4871 } 4872 $formconfirm .= ($question ? '<div class="confirmmessage">'.img_help('', '').' '.$question.'</div>' : ''); 4873 $formconfirm .= '</div>'."\n"; 4874 4875 $formconfirm .= "\n<!-- begin ajax formconfirm page=".$page." -->\n"; 4876 $formconfirm .= '<script type="text/javascript">'."\n"; 4877 $formconfirm .= 'jQuery(document).ready(function() { 4878 $(function() { 4879 $( "#'.$dialogconfirm.'" ).dialog( 4880 { 4881 autoOpen: '.($autoOpen ? "true" : "false").','; 4882 if ($newselectedchoice == 'no') { 4883 $formconfirm .= ' 4884 open: function() { 4885 $(this).parent().find("button.ui-button:eq(2)").focus(); 4886 },'; 4887 } 4888 $formconfirm .= ' 4889 resizable: false, 4890 height: "'.$height.'", 4891 width: "'.$width.'", 4892 modal: true, 4893 closeOnEscape: false, 4894 buttons: { 4895 "'.dol_escape_js($langs->transnoentities("Yes")).'": function() { 4896 var options = "&token='.urlencode(newToken()).'"; 4897 var inputok = '.json_encode($inputok).'; /* List of fields into form */ 4898 var pageyes = "'.dol_escape_js(!empty($pageyes) ? $pageyes : '').'"; 4899 if (inputok.length>0) { 4900 $.each(inputok, function(i, inputname) { 4901 var more = ""; 4902 var inputvalue; 4903 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") { 4904 inputvalue = $("input[name=\'" + inputname + "\']:checked").val(); 4905 } else { 4906 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; } 4907 inputvalue = $("#" + inputname + more).val(); 4908 } 4909 if (typeof inputvalue == "undefined") { inputvalue=""; } 4910 console.log("check inputname="+inputname+" inputvalue="+inputvalue); 4911 options += "&" + inputname + "=" + encodeURIComponent(inputvalue); 4912 }); 4913 } 4914 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "") + options; 4915 if (pageyes.length > 0) { location.href = urljump; } 4916 $(this).dialog("close"); 4917 }, 4918 "'.dol_escape_js($langs->transnoentities("No")).'": function() { 4919 var options = "&token='.urlencode(newToken()).'"; 4920 var inputko = '.json_encode($inputko).'; /* List of fields into form */ 4921 var pageno="'.dol_escape_js(!empty($pageno) ? $pageno : '').'"; 4922 if (inputko.length>0) { 4923 $.each(inputko, function(i, inputname) { 4924 var more = ""; 4925 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; } 4926 var inputvalue = $("#" + inputname + more).val(); 4927 if (typeof inputvalue == "undefined") { inputvalue=""; } 4928 options += "&" + inputname + "=" + encodeURIComponent(inputvalue); 4929 }); 4930 } 4931 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "") + options; 4932 //alert(urljump); 4933 if (pageno.length > 0) { location.href = urljump; } 4934 $(this).dialog("close"); 4935 } 4936 } 4937 } 4938 ); 4939 4940 var button = "'.$button.'"; 4941 if (button.length > 0) { 4942 $( "#" + button ).click(function() { 4943 $("#'.$dialogconfirm.'").dialog("open"); 4944 }); 4945 } 4946 }); 4947 }); 4948 </script>'; 4949 $formconfirm .= "<!-- end ajax formconfirm -->\n"; 4950 } else { 4951 $formconfirm .= "\n<!-- begin formconfirm page=".dol_escape_htmltag($page)." -->\n"; 4952 4953 if (empty($disableformtag)) { 4954 $formconfirm .= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n"; 4955 } 4956 4957 $formconfirm .= '<input type="hidden" name="action" value="'.$action.'">'."\n"; 4958 $formconfirm .= '<input type="hidden" name="token" value="'.newToken().'">'."\n"; 4959 4960 $formconfirm .= '<table class="valid centpercent">'."\n"; 4961 4962 // Line title 4963 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">'; 4964 $formconfirm .= img_picto('', 'recent').' '.$title; 4965 $formconfirm .= '</td></tr>'."\n"; 4966 4967 // Line text 4968 if (is_array($formquestion) && !empty($formquestion['text'])) { 4969 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'.$formquestion['text'].'</td></tr>'."\n"; 4970 } 4971 4972 // Line form fields 4973 if ($more) { 4974 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">'."\n"; 4975 $formconfirm .= $more; 4976 $formconfirm .= '</td></tr>'."\n"; 4977 } 4978 4979 // Line with question 4980 $formconfirm .= '<tr class="valid">'; 4981 $formconfirm .= '<td class="valid">'.$question.'</td>'; 4982 $formconfirm .= '<td class="valid center">'; 4983 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly'); 4984 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton" type="submit" value="'.$langs->trans("Validate").'">'; 4985 $formconfirm .= '</td>'; 4986 $formconfirm .= '</tr>'."\n"; 4987 4988 $formconfirm .= '</table>'."\n"; 4989 4990 if (empty($disableformtag)) { 4991 $formconfirm .= "</form>\n"; 4992 } 4993 $formconfirm .= '<br>'; 4994 4995 if (empty($conf->use_javascript_ajax)) { 4996 $formconfirm .= '<!-- code to disable button to avoid double clic -->'; 4997 $formconfirm .= '<script type="text/javascript">'."\n"; 4998 $formconfirm .= ' 4999 $(document).ready(function () { 5000 $(".confirmvalidatebutton").on("click", function() { 5001 console.log("We click on button"); 5002 $(this).attr("disabled", "disabled"); 5003 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000); 5004 //console.log($(this).closest("form")); 5005 $(this).closest("form").submit(); 5006 }); 5007 }); 5008 '; 5009 $formconfirm .= '</script>'."\n"; 5010 } 5011 5012 $formconfirm .= "<!-- end formconfirm -->\n"; 5013 } 5014 5015 return $formconfirm; 5016 } 5017 5018 5019 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5020 /** 5021 * Show a form to select a project 5022 * 5023 * @param int $page Page 5024 * @param int $socid Id third party (-1=all, 0=only projects not linked to a third party, id=projects not linked or linked to third party id) 5025 * @param int $selected Id pre-selected project 5026 * @param string $htmlname Name of select field 5027 * @param int $discard_closed Discard closed projects (0=Keep,1=hide completely except $selected,2=Disable) 5028 * @param int $maxlength Max length 5029 * @param int $forcefocus Force focus on field (works with javascript only) 5030 * @param int $nooutput No print is done. String is returned. 5031 * @return string Return html content 5032 */ 5033 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0) 5034 { 5035 // phpcs:enable 5036 global $langs; 5037 5038 require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php'; 5039 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; 5040 5041 $out = ''; 5042 5043 $formproject = new FormProjets($this->db); 5044 5045 $langs->load("project"); 5046 if ($htmlname != "none") { 5047 $out .= "\n"; 5048 $out .= '<form method="post" action="'.$page.'">'; 5049 $out .= '<input type="hidden" name="action" value="classin">'; 5050 $out .= '<input type="hidden" name="token" value="'.newToken().'">'; 5051 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1); 5052 $out .= '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">'; 5053 $out .= '</form>'; 5054 } else { 5055 if ($selected) { 5056 $projet = new Project($this->db); 5057 $projet->fetch($selected); 5058 //print '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$selected.'">'.$projet->title.'</a>'; 5059 $out .= $projet->getNomUrl(0, '', 1); 5060 } else { 5061 $out .= " "; 5062 } 5063 } 5064 5065 if (empty($nooutput)) { 5066 print $out; 5067 return ''; 5068 } 5069 return $out; 5070 } 5071 5072 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5073 /** 5074 * Show a form to select payment conditions 5075 * 5076 * @param int $page Page 5077 * @param string $selected Id condition pre-selectionne 5078 * @param string $htmlname Name of select html field 5079 * @param int $addempty Add empty entry 5080 * @return void 5081 */ 5082 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0) 5083 { 5084 // phpcs:enable 5085 global $langs; 5086 if ($htmlname != "none") { 5087 print '<form method="post" action="'.$page.'">'; 5088 print '<input type="hidden" name="action" value="setconditions">'; 5089 print '<input type="hidden" name="token" value="'.newToken().'">'; 5090 $this->select_conditions_paiements($selected, $htmlname, -1, $addempty); 5091 print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">'; 5092 print '</form>'; 5093 } else { 5094 if ($selected) { 5095 $this->load_cache_conditions_paiements(); 5096 if (isset($this->cache_conditions_paiements[$selected])) { 5097 print $this->cache_conditions_paiements[$selected]['label']; 5098 } else { 5099 $langs->load('errors'); 5100 print $langs->trans('ErrorNotInDictionaryPaymentConditions'); 5101 } 5102 } else { 5103 print " "; 5104 } 5105 } 5106 } 5107 5108 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5109 /** 5110 * Show a form to select a delivery delay 5111 * 5112 * @param int $page Page 5113 * @param string $selected Id condition pre-selectionne 5114 * @param string $htmlname Name of select html field 5115 * @param int $addempty Ajoute entree vide 5116 * @return void 5117 */ 5118 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0) 5119 { 5120 // phpcs:enable 5121 global $langs; 5122 if ($htmlname != "none") { 5123 print '<form method="post" action="'.$page.'">'; 5124 print '<input type="hidden" name="action" value="setavailability">'; 5125 print '<input type="hidden" name="token" value="'.newToken().'">'; 5126 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty); 5127 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">'; 5128 print '</form>'; 5129 } else { 5130 if ($selected) { 5131 $this->load_cache_availability(); 5132 print $this->cache_availability[$selected]['label']; 5133 } else { 5134 print " "; 5135 } 5136 } 5137 } 5138 5139 /** 5140 * Output HTML form to select list of input reason (events that triggered an object creation, like after sending an emailing, making an advert, ...) 5141 * List found into table c_input_reason loaded by loadCacheInputReason 5142 * 5143 * @param string $page Page 5144 * @param string $selected Id condition pre-selectionne 5145 * @param string $htmlname Name of select html field 5146 * @param int $addempty Add empty entry 5147 * @return void 5148 */ 5149 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0) 5150 { 5151 global $langs; 5152 if ($htmlname != "none") { 5153 print '<form method="post" action="'.$page.'">'; 5154 print '<input type="hidden" name="action" value="setdemandreason">'; 5155 print '<input type="hidden" name="token" value="'.newToken().'">'; 5156 $this->selectInputReason($selected, $htmlname, -1, $addempty); 5157 print '<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">'; 5158 print '</form>'; 5159 } else { 5160 if ($selected) { 5161 $this->loadCacheInputReason(); 5162 foreach ($this->cache_demand_reason as $key => $val) { 5163 if ($val['id'] == $selected) { 5164 print $val['label']; 5165 break; 5166 } 5167 } 5168 } else { 5169 print " "; 5170 } 5171 } 5172 } 5173 5174 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5175 /** 5176 * Show a form + html select a date 5177 * 5178 * @param string $page Page 5179 * @param string $selected Date preselected 5180 * @param string $htmlname Html name of date input fields or 'none' 5181 * @param int $displayhour Display hour selector 5182 * @param int $displaymin Display minutes selector 5183 * @param int $nooutput 1=No print output, return string 5184 * @return string 5185 * @see selectDate() 5186 */ 5187 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0) 5188 { 5189 // phpcs:enable 5190 global $langs; 5191 5192 $ret = ''; 5193 5194 if ($htmlname != "none") { 5195 $ret .= '<form method="post" action="'.$page.'" name="form'.$htmlname.'">'; 5196 $ret .= '<input type="hidden" name="action" value="set'.$htmlname.'">'; 5197 $ret .= '<input type="hidden" name="token" value="'.newToken().'">'; 5198 $ret .= '<table class="nobordernopadding">'; 5199 $ret .= '<tr><td>'; 5200 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form'.$htmlname, 1, 0); 5201 $ret .= '</td>'; 5202 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>'; 5203 $ret .= '</tr></table></form>'; 5204 } else { 5205 if ($displayhour) { 5206 $ret .= dol_print_date($selected, 'dayhour'); 5207 } else { 5208 $ret .= dol_print_date($selected, 'day'); 5209 } 5210 } 5211 5212 if (empty($nooutput)) { 5213 print $ret; 5214 } 5215 return $ret; 5216 } 5217 5218 5219 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5220 /** 5221 * Show a select form to choose a user 5222 * 5223 * @param string $page Page 5224 * @param string $selected Id of user preselected 5225 * @param string $htmlname Name of input html field. If 'none', we just output the user link. 5226 * @param array $exclude List of users id to exclude 5227 * @param array $include List of users id to include 5228 * @return void 5229 */ 5230 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = '', $include = '') 5231 { 5232 // phpcs:enable 5233 global $langs; 5234 5235 if ($htmlname != "none") { 5236 print '<form method="POST" action="'.$page.'" name="form'.$htmlname.'">'; 5237 print '<input type="hidden" name="action" value="set'.$htmlname.'">'; 5238 print '<input type="hidden" name="token" value="'.newToken().'">'; 5239 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include); 5240 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">'; 5241 print '</form>'; 5242 } else { 5243 if ($selected) { 5244 require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; 5245 $theuser = new User($this->db); 5246 $theuser->fetch($selected); 5247 print $theuser->getNomUrl(1); 5248 } else { 5249 print " "; 5250 } 5251 } 5252 } 5253 5254 5255 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5256 /** 5257 * Show form with payment mode 5258 * 5259 * @param string $page Page 5260 * @param int $selected Id mode pre-selectionne 5261 * @param string $htmlname Name of select html field 5262 * @param string $filtertype To filter on field type in llx_c_paiement (array('code'=>xx,'label'=>zz)) 5263 * @param int $active Active or not, -1 = all 5264 * @param int $addempty 1=Add empty entry 5265 * @return void 5266 */ 5267 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0) 5268 { 5269 // phpcs:enable 5270 global $langs; 5271 if ($htmlname != "none") { 5272 print '<form method="POST" action="'.$page.'">'; 5273 print '<input type="hidden" name="action" value="setmode">'; 5274 print '<input type="hidden" name="token" value="'.newToken().'">'; 5275 $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active); 5276 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">'; 5277 print '</form>'; 5278 } else { 5279 if ($selected) { 5280 $this->load_cache_types_paiements(); 5281 print $this->cache_types_paiements[$selected]['label']; 5282 } else { 5283 print " "; 5284 } 5285 } 5286 } 5287 5288 /** 5289 * Show form with transport mode 5290 * 5291 * @param string $page Page 5292 * @param int $selected Id mode pre-select 5293 * @param string $htmlname Name of select html field 5294 * @param int $active Active or not, -1 = all 5295 * @param int $addempty 1=Add empty entry 5296 * @return void 5297 */ 5298 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0) 5299 { 5300 global $langs; 5301 if ($htmlname != "none") { 5302 print '<form method="POST" action="'.$page.'">'; 5303 print '<input type="hidden" name="action" value="settransportmode">'; 5304 print '<input type="hidden" name="token" value="'.newToken().'">'; 5305 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active); 5306 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">'; 5307 print '</form>'; 5308 } else { 5309 if ($selected) { 5310 $this->load_cache_transport_mode(); 5311 print $this->cache_transport_mode[$selected]['label']; 5312 } else { 5313 print " "; 5314 } 5315 } 5316 } 5317 5318 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5319 /** 5320 * Show form with multicurrency code 5321 * 5322 * @param string $page Page 5323 * @param string $selected code pre-selectionne 5324 * @param string $htmlname Name of select html field 5325 * @return void 5326 */ 5327 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code') 5328 { 5329 // phpcs:enable 5330 global $langs; 5331 if ($htmlname != "none") { 5332 print '<form method="POST" action="'.$page.'">'; 5333 print '<input type="hidden" name="action" value="setmulticurrencycode">'; 5334 print '<input type="hidden" name="token" value="'.newToken().'">'; 5335 print $this->selectMultiCurrency($selected, $htmlname, 0); 5336 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">'; 5337 print '</form>'; 5338 } else { 5339 dol_include_once('/core/lib/company.lib.php'); 5340 print !empty($selected) ? currency_name($selected, 1) : ' '; 5341 } 5342 } 5343 5344 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5345 /** 5346 * Show form with multicurrency rate 5347 * 5348 * @param string $page Page 5349 * @param double $rate Current rate 5350 * @param string $htmlname Name of select html field 5351 * @param string $currency Currency code to explain the rate 5352 * @return void 5353 */ 5354 public function form_multicurrency_rate($page, $rate = '', $htmlname = 'multicurrency_tx', $currency = '') 5355 { 5356 // phpcs:enable 5357 global $langs, $mysoc, $conf; 5358 5359 if ($htmlname != "none") { 5360 print '<form method="POST" action="'.$page.'">'; 5361 print '<input type="hidden" name="action" value="setmulticurrencyrate">'; 5362 print '<input type="hidden" name="token" value="'.newToken().'">'; 5363 print '<input type="text" class="maxwidth100" name="'.$htmlname.'" value="'.(!empty($rate) ? price(price2num($rate, 'CU')) : 1).'" /> '; 5364 print '<select name="calculation_mode">'; 5365 print '<option value="1">Change '.$langs->trans("PriceUHT").' of lines</option>'; 5366 print '<option value="2">Change '.$langs->trans("PriceUHTCurrency").' of lines</option>'; 5367 print '</select> '; 5368 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">'; 5369 print '</form>'; 5370 } else { 5371 if (!empty($rate)) { 5372 print price($rate, 1, $langs, 1, 0); 5373 if ($currency && $rate != 1) { 5374 print ' ('.price($rate, 1, $langs, 1, 0).' '.$currency.' = 1 '.$conf->currency.')'; 5375 } 5376 } else { 5377 print 1; 5378 } 5379 } 5380 } 5381 5382 5383 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5384 /** 5385 * Show a select box with available absolute discounts 5386 * 5387 * @param string $page Page URL where form is shown 5388 * @param int $selected Value pre-selected 5389 * @param string $htmlname Name of SELECT component. If 'none', not changeable. Example 'remise_id'. 5390 * @param int $socid Third party id 5391 * @param float $amount Total amount available 5392 * @param string $filter SQL filter on discounts 5393 * @param int $maxvalue Max value for lines that can be selected 5394 * @param string $more More string to add 5395 * @param int $hidelist 1=Hide list 5396 * @param int $discount_type 0 => customer discount, 1 => supplier discount 5397 * @return void 5398 */ 5399 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0) 5400 { 5401 // phpcs:enable 5402 global $conf, $langs; 5403 if ($htmlname != "none") { 5404 print '<form method="post" action="'.$page.'">'; 5405 print '<input type="hidden" name="action" value="setabsolutediscount">'; 5406 print '<input type="hidden" name="token" value="'.newToken().'">'; 5407 print '<div class="inline-block">'; 5408 if (!empty($discount_type)) { 5409 if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { 5410 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") { 5411 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be substracted to payments only and not to total of final invoice 5412 } else { 5413 $translationKey = 'HasCreditNoteFromSupplier'; 5414 } 5415 } else { 5416 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") { 5417 $translationKey = 'HasAbsoluteDiscountFromSupplier'; 5418 } else { 5419 $translationKey = 'HasCreditNoteFromSupplier'; 5420 } 5421 } 5422 } else { 5423 if (!empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { 5424 if (!$filter || $filter == "fk_facture_source IS NULL") { 5425 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be substracted to payments only and not to total of final invoice 5426 } else { 5427 $translationKey = 'CompanyHasCreditNote'; 5428 } 5429 } else { 5430 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") { 5431 $translationKey = 'CompanyHasAbsoluteDiscount'; 5432 } else { 5433 $translationKey = 'CompanyHasCreditNote'; 5434 } 5435 } 5436 } 5437 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency)); 5438 if (empty($hidelist)) { 5439 print ' '; 5440 } 5441 print '</div>'; 5442 if (empty($hidelist)) { 5443 print '<div class="inline-block" style="padding-right: 10px">'; 5444 $newfilter = 'discount_type='.intval($discount_type); 5445 if (!empty($discount_type)) { 5446 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available 5447 } else { 5448 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available 5449 } 5450 if ($filter) { 5451 $newfilter .= ' AND ('.$filter.')'; 5452 } 5453 $nbqualifiedlines = $this->select_remises($selected, $htmlname, $newfilter, $socid, $maxvalue); 5454 if ($nbqualifiedlines > 0) { 5455 print ' <input type="submit" class="button smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("UseLine")).'"'; 5456 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") { 5457 print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"'; 5458 } 5459 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") { 5460 print ' title="'.$langs->trans("UseCreditNoteInInvoicePayment").'"'; 5461 } 5462 5463 print '>'; 5464 } 5465 print '</div>'; 5466 } 5467 if ($more) { 5468 print '<div class="inline-block">'; 5469 print $more; 5470 print '</div>'; 5471 } 5472 print '</form>'; 5473 } else { 5474 if ($selected) { 5475 print $selected; 5476 } else { 5477 print "0"; 5478 } 5479 } 5480 } 5481 5482 5483 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5484 /** 5485 * Show forms to select a contact 5486 * 5487 * @param string $page Page 5488 * @param Societe $societe Filter on third party 5489 * @param int $selected Id contact pre-selectionne 5490 * @param string $htmlname Name of HTML select. If 'none', we just show contact link. 5491 * @return void 5492 */ 5493 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid') 5494 { 5495 // phpcs:enable 5496 global $langs, $conf; 5497 5498 if ($htmlname != "none") { 5499 print '<form method="post" action="'.$page.'">'; 5500 print '<input type="hidden" name="action" value="set_contact">'; 5501 print '<input type="hidden" name="token" value="'.newToken().'">'; 5502 print '<table class="nobordernopadding">'; 5503 print '<tr><td>'; 5504 print $this->selectcontacts($societe->id, $selected, $htmlname); 5505 $num = $this->num; 5506 if ($num == 0) { 5507 $addcontact = (!empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("AddContact") : $langs->trans("AddContactAddress")); 5508 print '<a href="'.DOL_URL_ROOT.'/contact/card.php?socid='.$societe->id.'&action=create&backtoreferer=1">'.$addcontact.'</a>'; 5509 } 5510 print '</td>'; 5511 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'"></td>'; 5512 print '</tr></table></form>'; 5513 } else { 5514 if ($selected) { 5515 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; 5516 $contact = new Contact($this->db); 5517 $contact->fetch($selected); 5518 print $contact->getFullName($langs); 5519 } else { 5520 print " "; 5521 } 5522 } 5523 } 5524 5525 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5526 /** 5527 * Output html select to select thirdparty 5528 * 5529 * @param string $page Page 5530 * @param string $selected Id preselected 5531 * @param string $htmlname Name of HTML select 5532 * @param string $filter Optional filters criteras. Do not use a filter coming from input of users. 5533 * @param int $showempty Add an empty field 5534 * @param int $showtype Show third party type in combolist (customer, prospect or supplier) 5535 * @param int $forcecombo Force to use combo box 5536 * @param array $events Event options. Example: array(array('method'=>'getContacts', 'url'=>dol_buildpath('/core/ajax/contacts.php',1), 'htmlname'=>'contactid', 'params'=>array('add-customer-contact'=>'disabled'))) 5537 * @param int $nooutput No print output. Return it only. 5538 * @param array $excludeids Exclude IDs from the select combo 5539 * @return void|string 5540 */ 5541 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array()) 5542 { 5543 // phpcs:enable 5544 global $langs; 5545 5546 $out = ''; 5547 if ($htmlname != "none") { 5548 $out .= '<form method="post" action="'.$page.'">'; 5549 $out .= '<input type="hidden" name="action" value="set_thirdparty">'; 5550 $out .= '<input type="hidden" name="token" value="'.newToken().'">'; 5551 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids); 5552 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="'.$langs->trans("Modify").'">'; 5553 $out .= '</form>'; 5554 } else { 5555 if ($selected) { 5556 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; 5557 $soc = new Societe($this->db); 5558 $soc->fetch($selected); 5559 $out .= $soc->getNomUrl($langs); 5560 } else { 5561 $out .= " "; 5562 } 5563 } 5564 5565 if ($nooutput) { 5566 return $out; 5567 } else { 5568 print $out; 5569 } 5570 } 5571 5572 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5573 /** 5574 * Retourne la liste des devises, dans la langue de l'utilisateur 5575 * 5576 * @param string $selected preselected currency code 5577 * @param string $htmlname name of HTML select list 5578 * @deprecated 5579 * @return void 5580 */ 5581 public function select_currency($selected = '', $htmlname = 'currency_id') 5582 { 5583 // phpcs:enable 5584 print $this->selectCurrency($selected, $htmlname); 5585 } 5586 5587 /** 5588 * Retourne la liste des devises, dans la langue de l'utilisateur 5589 * 5590 * @param string $selected preselected currency code 5591 * @param string $htmlname name of HTML select list 5592 * @param string $mode 0 = Add currency symbol into label, 1 = Add 3 letter iso code 5593 * @return string 5594 */ 5595 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0) 5596 { 5597 global $conf, $langs, $user; 5598 5599 $langs->loadCacheCurrencies(''); 5600 5601 $out = ''; 5602 5603 if ($selected == 'euro' || $selected == 'euros') { 5604 $selected = 'EUR'; // Pour compatibilite 5605 } 5606 5607 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="'.$htmlname.'" id="'.$htmlname.'">'; 5608 foreach ($langs->cache_currencies as $code_iso => $currency) { 5609 $labeltoshow = $currency['label']; 5610 if ($mode == 1) { 5611 $labeltoshow .= ' <span class="opacitymedium">('.$code_iso.')</span>'; 5612 } else { 5613 $labeltoshow .= ' <span class="opacitymedium">('.$langs->getCurrencySymbol($code_iso).')</span>'; 5614 } 5615 5616 if ($selected && $selected == $code_iso) { 5617 $out .= '<option value="'.$code_iso.'" selected data-html="'.dol_escape_htmltag($labeltoshow).'">'; 5618 } else { 5619 $out .= '<option value="'.$code_iso.'" data-html="'.dol_escape_htmltag($labeltoshow).'">'; 5620 } 5621 $out .= $labeltoshow; 5622 $out .= '</option>'; 5623 } 5624 $out .= '</select>'; 5625 if ($user->admin) { 5626 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 5627 } 5628 5629 // Make select dynamic 5630 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 5631 $out .= ajax_combobox($htmlname); 5632 5633 return $out; 5634 } 5635 5636 /** 5637 * Return array of currencies in user language 5638 * 5639 * @param string $selected preselected currency code 5640 * @param string $htmlname name of HTML select list 5641 * @param integer $useempty 1=Add empty line 5642 * @param string $filter Optional filters criteras (example: 'code <> x', ' in (1,3)') 5643 * @param bool $excludeConfCurrency false = If company current currency not in table, we add it into list. Should always be available. true = we are in currency_rate update , we don't want to see conf->currency in select 5644 * @return string 5645 */ 5646 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false) 5647 { 5648 global $db, $conf, $langs, $user; 5649 5650 $langs->loadCacheCurrencies(''); // Load ->cache_currencies 5651 5652 $TCurrency = array(); 5653 5654 $sql = 'SELECT code FROM '.MAIN_DB_PREFIX.'multicurrency'; 5655 $sql .= " WHERE entity IN ('".getEntity('mutlicurrency')."')"; 5656 if ($filter) { 5657 $sql .= " AND ".$filter; 5658 } 5659 $resql = $this->db->query($sql); 5660 if ($resql) { 5661 while ($obj = $this->db->fetch_object($resql)) { 5662 $TCurrency[$obj->code] = $obj->code; 5663 } 5664 } 5665 5666 $out = ''; 5667 $out .= '<select class="flat" name="'.$htmlname.'" id="'.$htmlname.'">'; 5668 if ($useempty) { 5669 $out .= '<option value=""> </option>'; 5670 } 5671 // If company current currency not in table, we add it into list. Should always be available. 5672 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) { 5673 $TCurrency[$conf->currency] = $conf->currency; 5674 } 5675 if (count($TCurrency) > 0) { 5676 foreach ($langs->cache_currencies as $code_iso => $currency) { 5677 if (isset($TCurrency[$code_iso])) { 5678 if (!empty($selected) && $selected == $code_iso) { 5679 $out .= '<option value="'.$code_iso.'" selected="selected">'; 5680 } else { 5681 $out .= '<option value="'.$code_iso.'">'; 5682 } 5683 5684 $out .= $currency['label']; 5685 $out .= ' ('.$langs->getCurrencySymbol($code_iso).')'; 5686 $out .= '</option>'; 5687 } 5688 } 5689 } 5690 5691 $out .= '</select>'; 5692 // Make select dynamic 5693 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 5694 $out .= ajax_combobox($htmlname); 5695 5696 return $out; 5697 } 5698 5699 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5700 /** 5701 * Load into the cache vat rates of a country 5702 * 5703 * @param string $country_code Country code with quotes ("'CA'", or "'CA,IN,...'") 5704 * @return int Nb of loaded lines, 0 if already loaded, <0 if KO 5705 */ 5706 public function load_cache_vatrates($country_code) 5707 { 5708 // phpcs:enable 5709 global $langs; 5710 5711 $num = count($this->cache_vatrates); 5712 if ($num > 0) { 5713 return $num; // Cache already loaded 5714 } 5715 5716 dol_syslog(__METHOD__, LOG_DEBUG); 5717 5718 $sql = "SELECT DISTINCT t.rowid, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly"; 5719 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c"; 5720 $sql .= " WHERE t.fk_pays = c.rowid"; 5721 $sql .= " AND t.active > 0"; 5722 $sql .= " AND c.code IN (".$this->db->sanitize($country_code, 1).")"; 5723 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC"; 5724 5725 $resql = $this->db->query($sql); 5726 if ($resql) { 5727 $num = $this->db->num_rows($resql); 5728 if ($num) { 5729 for ($i = 0; $i < $num; $i++) { 5730 $obj = $this->db->fetch_object($resql); 5731 $this->cache_vatrates[$i]['rowid'] = $obj->rowid; 5732 $this->cache_vatrates[$i]['code'] = $obj->code; 5733 $this->cache_vatrates[$i]['txtva'] = $obj->taux; 5734 $this->cache_vatrates[$i]['nprtva'] = $obj->recuperableonly; 5735 $this->cache_vatrates[$i]['localtax1'] = $obj->localtax1; 5736 $this->cache_vatrates[$i]['localtax1_type'] = $obj->localtax1_type; 5737 $this->cache_vatrates[$i]['localtax2'] = $obj->localtax2; 5738 $this->cache_vatrates[$i]['localtax2_type'] = $obj->localtax1_type; 5739 5740 $this->cache_vatrates[$i]['label'] = $obj->taux.'%'.($obj->code ? ' ('.$obj->code.')' : ''); // Label must contains only 0-9 , . % or * 5741 $this->cache_vatrates[$i]['labelallrates'] = $obj->taux.'/'.($obj->localtax1 ? $obj->localtax1 : '0').'/'.($obj->localtax2 ? $obj->localtax2 : '0').($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label 5742 $positiverates = ''; 5743 if ($obj->taux) { 5744 $positiverates .= ($positiverates ? '/' : '').$obj->taux; 5745 } 5746 if ($obj->localtax1) { 5747 $positiverates .= ($positiverates ? '/' : '').$obj->localtax1; 5748 } 5749 if ($obj->localtax2) { 5750 $positiverates .= ($positiverates ? '/' : '').$obj->localtax2; 5751 } 5752 if (empty($positiverates)) { 5753 $positiverates = '0'; 5754 } 5755 $this->cache_vatrates[$i]['labelpositiverates'] = $positiverates.($obj->code ? ' ('.$obj->code.')' : ''); // Must never be used as key, only label 5756 } 5757 5758 return $num; 5759 } else { 5760 $this->error = '<font class="error">'.$langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code).'</font>'; 5761 return -1; 5762 } 5763 } else { 5764 $this->error = '<font class="error">'.$this->db->error().'</font>'; 5765 return -2; 5766 } 5767 } 5768 5769 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5770 /** 5771 * Output an HTML select vat rate. 5772 * The name of this function should be selectVat. We keep bad name for compatibility purpose. 5773 * 5774 * @param string $htmlname Name of HTML select field 5775 * @param float|string $selectedrate Force preselected vat rate. Can be '8.5' or '8.5 (NOO)' for example. Use '' for no forcing. 5776 * @param Societe $societe_vendeuse Thirdparty seller 5777 * @param Societe $societe_acheteuse Thirdparty buyer 5778 * @param int $idprod Id product. O if unknown of NA. 5779 * @param int $info_bits Miscellaneous information on line (1 for NPR) 5780 * @param int|string $type ''=Unknown, 0=Product, 1=Service (Used if idprod not defined) 5781 * Si vendeur non assujeti a TVA, TVA par defaut=0. Fin de regle. 5782 * Si le (pays vendeur = pays acheteur) alors la TVA par defaut=TVA du produit vendu. Fin de regle. 5783 * Si (vendeur et acheteur dans Communaute europeenne) et bien vendu = moyen de transports neuf (auto, bateau, avion), TVA par defaut=0 (La TVA doit etre paye par l'acheteur au centre d'impots de son pays et non au vendeur). Fin de regle. 5784 * Si vendeur et acheteur dans Communauté européenne et acheteur= particulier alors TVA par défaut=TVA du produit vendu. Fin de règle. 5785 * Si vendeur et acheteur dans Communauté européenne et acheteur= entreprise alors TVA par défaut=0. Fin de règle. 5786 * Sinon la TVA proposee par defaut=0. Fin de regle. 5787 * @param bool $options_only Return HTML options lines only (for ajax treatment) 5788 * @param int $mode 0=Use vat rate as key in combo list, 1=Add VAT code after vat rate into key, -1=Use id of vat line as key 5789 * @return string 5790 */ 5791 public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = '', $societe_acheteuse = '', $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0) 5792 { 5793 // phpcs:enable 5794 global $langs, $conf, $mysoc; 5795 5796 $langs->load('errors'); 5797 5798 $return = ''; 5799 5800 // Define defaultnpr, defaultttx and defaultcode 5801 $defaultnpr = ($info_bits & 0x01); 5802 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr); 5803 $defaulttx = str_replace('*', '', $selectedrate); 5804 $defaultcode = ''; 5805 $reg = array(); 5806 if (preg_match('/\((.*)\)/', $defaulttx, $reg)) { 5807 $defaultcode = $reg[1]; 5808 $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx); 5809 } 5810 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode); 5811 5812 // Check parameters 5813 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) { 5814 if ($societe_vendeuse->id == $mysoc->id) { 5815 $return .= '<font class="error">'.$langs->trans("ErrorYourCountryIsNotDefined").'</font>'; 5816 } else { 5817 $return .= '<font class="error">'.$langs->trans("ErrorSupplierCountryIsNotDefined").'</font>'; 5818 } 5819 return $return; 5820 } 5821 5822 //var_dump($societe_acheteuse); 5823 //print "name=$name, selectedrate=$selectedrate, seller=".$societe_vendeuse->country_code." buyer=".$societe_acheteuse->country_code." buyer is company=".$societe_acheteuse->isACompany()." idprod=$idprod, info_bits=$info_bits type=$type"; 5824 //exit; 5825 5826 // Define list of countries to use to search VAT rates to show 5827 // First we defined code_country to use to find list 5828 if (is_object($societe_vendeuse)) { 5829 $code_country = "'".$societe_vendeuse->country_code."'"; 5830 } else { 5831 $code_country = "'".$mysoc->country_code."'"; // Pour compatibilite ascendente 5832 } 5833 if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) { // If option to have vat for end customer for services is on 5834 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; 5835 if (!isInEEC($societe_vendeuse) && (!is_object($societe_acheteuse) || (isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()))) { 5836 // We also add the buyer 5837 if (is_numeric($type)) { 5838 if ($type == 1) { // We know product is a service 5839 $code_country .= ",'".$societe_acheteuse->country_code."'"; 5840 } 5841 } elseif (!$idprod) { // We don't know type of product 5842 $code_country .= ",'".$societe_acheteuse->country_code."'"; 5843 } else { 5844 $prodstatic = new Product($this->db); 5845 $prodstatic->fetch($idprod); 5846 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service 5847 $code_country .= ",'".$societe_acheteuse->country_code."'"; 5848 } 5849 } 5850 } 5851 } 5852 5853 // Now we get list 5854 $num = $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error 5855 5856 if ($num > 0) { 5857 // Definition du taux a pre-selectionner (si defaulttx non force et donc vaut -1 ou '') 5858 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) { 5859 $tmpthirdparty = new Societe($this->db); 5860 $defaulttx = get_default_tva($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod); 5861 $defaultnpr = get_default_npr($societe_vendeuse, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod); 5862 if (preg_match('/\((.*)\)/', $defaulttx, $reg)) { 5863 $defaultcode = $reg[1]; 5864 $defaulttx = preg_replace('/\s*\(.*\)/', '', $defaulttx); 5865 } 5866 if (empty($defaulttx)) { 5867 $defaultnpr = 0; 5868 } 5869 } 5870 5871 // Si taux par defaut n'a pu etre determine, on prend dernier de la liste. 5872 // Comme ils sont tries par ordre croissant, dernier = plus eleve = taux courant 5873 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) { 5874 if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) { 5875 $defaulttx = $this->cache_vatrates[$num - 1]['txtva']; 5876 } else { 5877 $defaulttx = ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS == 'none' ? '' : $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS); 5878 } 5879 } 5880 5881 // Disabled if seller is not subject to VAT 5882 $disabled = false; 5883 $title = ''; 5884 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") { 5885 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead 5886 // of using supplier invoices (this is a very bad idea !) 5887 if (empty($conf->global->EXPENSEREPORT_OVERRIDE_VAT)) { 5888 $title = ' title="'.$langs->trans('VATIsNotUsed').'"'; 5889 $disabled = true; 5890 } 5891 } 5892 5893 if (!$options_only) { 5894 $return .= '<select class="flat minwidth75imp" id="'.$htmlname.'" name="'.$htmlname.'"'.($disabled ? ' disabled' : '').$title.'>'; 5895 } 5896 5897 $selectedfound = false; 5898 foreach ($this->cache_vatrates as $rate) { 5899 // Keep only 0 if seller is not subject to VAT 5900 if ($disabled && $rate['txtva'] != 0) { 5901 continue; 5902 } 5903 5904 // Define key to use into select list 5905 $key = $rate['txtva']; 5906 $key .= $rate['nprtva'] ? '*' : ''; 5907 if ($mode > 0 && $rate['code']) { 5908 $key .= ' ('.$rate['code'].')'; 5909 } 5910 if ($mode < 0) { 5911 $key = $rate['rowid']; 5912 } 5913 5914 $return .= '<option value="'.$key.'"'; 5915 if (!$selectedfound) { 5916 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag 5917 if ($defaultcode == $rate['code']) { 5918 $return .= ' selected'; 5919 $selectedfound = true; 5920 } 5921 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) { 5922 $return .= ' selected'; 5923 $selectedfound = true; 5924 } 5925 } 5926 $return .= '>'; 5927 //if (! empty($conf->global->MAIN_VAT_SHOW_POSITIVE_RATES)) 5928 if ($mysoc->country_code == 'IN' || !empty($conf->global->MAIN_VAT_LABEL_IS_POSITIVE_RATES)) { 5929 $return .= $rate['labelpositiverates']; 5930 } else { 5931 $return .= vatrate($rate['label']); 5932 } 5933 //$return.=($rate['code']?' '.$rate['code']:''); 5934 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used) 5935 5936 $return .= '</option>'; 5937 } 5938 5939 if (!$options_only) { 5940 $return .= '</select>'; 5941 } 5942 } else { 5943 $return .= $this->error; 5944 } 5945 5946 $this->num = $num; 5947 return $return; 5948 } 5949 5950 5951 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 5952 /** 5953 * Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes. 5954 * Fields are preselected with : 5955 * - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM') 5956 * - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location) 5957 * - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1) 5958 * 5959 * @param integer $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). 5960 * @param string $prefix Prefix for fields name 5961 * @param int $h 1 or 2=Show also hours (2=hours on a new line), -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show hour always empty 5962 * @param int $m 1=Show also minutes, -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show minutes always empty 5963 * @param int $empty 0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only 5964 * @param string $form_name Not used 5965 * @param int $d 1=Show days, month, years 5966 * @param int $addnowlink Add a link "Now" 5967 * @param int $nooutput Do not output html string but return it 5968 * @param int $disabled Disable input fields 5969 * @param int $fullday When a checkbox with this html name is on, hour and day are set with 00:00 or 23:59 5970 * @param string $addplusone Add a link "+1 hour". Value must be name of another select_date field. 5971 * @param datetime $adddateof Add a link "Date of invoice" using the following date. 5972 * @return string|void Nothing or string if nooutput is 1 5973 * @deprecated 5974 * @see selectDate(), form_date(), select_month(), select_year(), select_dayofweek() 5975 */ 5976 public function select_date($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $nooutput = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '') 5977 { 5978 // phpcs:enable 5979 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof); 5980 if (!empty($nooutput)) { 5981 return $retstring; 5982 } 5983 print $retstring; 5984 return; 5985 } 5986 5987 /** 5988 * Show 2 HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes. 5989 * Fields are preselected with : 5990 * - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM') 5991 * - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location) 5992 * - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1) 5993 * 5994 * @param integer $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). 5995 * @param integer $set_time_end Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). 5996 * @param string $prefix Prefix for fields name 5997 * @param string $empty 0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only 5998 * @return string Html for selectDate 5999 * @see form_date(), select_month(), select_year(), select_dayofweek() 6000 */ 6001 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0) 6002 { 6003 global $langs; 6004 6005 $ret = $this->selectDate($set_time, $prefix.'_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel'); 6006 $ret .= '<br>'; 6007 $ret .= $this->selectDate($set_time_end, $prefix.'_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel'); 6008 return $ret; 6009 } 6010 6011 /** 6012 * Show a HTML widget to input a date or combo list for day, month, years and optionaly hours and minutes. 6013 * Fields are preselected with : 6014 * - set_time date (must be a local PHP server timestamp or string date with format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM') 6015 * - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location) 6016 * - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1) 6017 * 6018 * @param integer $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). 6019 * @param string $prefix Prefix for fields name 6020 * @param int $h 1 or 2=Show also hours (2=hours on a new line), -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show hour always empty 6021 * @param int $m 1=Show also minutes, -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show minutes always empty 6022 * @param int $empty 0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only 6023 * @param string $form_name Not used 6024 * @param int $d 1=Show days, month, years 6025 * @param int $addnowlink Add a link "Now", 1 with server time, 2 with local computer time 6026 * @param int $disabled Disable input fields 6027 * @param int $fullday When a checkbox with id #fullday is checked, hours are set with 00:00 (if value if 'fulldaystart') or 23:59 (if value is 'fulldayend') 6028 * @param string $addplusone Add a link "+1 hour". Value must be name of another selectDate field. 6029 * @param datetime $adddateof Add a link "Date of ..." using the following date. See also $labeladddateof for the label used. 6030 * @param string $openinghours Specify hour start and hour end for the select ex 8,20 6031 * @param int $stepminutes Specify step for minutes between 1 and 30 6032 * @param string $labeladddateof Label to use for the $adddateof parameter. 6033 * @param string $placeholder Placeholder 6034 * @param mixed $gm 'auto' (for backward compatibility, avoid this), 'gmt' or 'tzserver' or 'tzuserrel' 6035 * @return string Html for selectDate 6036 * @see form_date(), select_month(), select_year(), select_dayofweek() 6037 */ 6038 public function selectDate($set_time = '', $prefix = 're', $h = 0, $m = 0, $empty = 0, $form_name = "", $d = 1, $addnowlink = 0, $disabled = 0, $fullday = '', $addplusone = '', $adddateof = '', $openinghours = '', $stepminutes = 1, $labeladddateof = '', $placeholder = '', $gm = 'auto') 6039 { 6040 global $conf, $langs; 6041 6042 if ($gm === 'auto') { 6043 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey); 6044 } 6045 6046 $retstring = ''; 6047 6048 if ($prefix == '') { 6049 $prefix = 're'; 6050 } 6051 if ($h == '') { 6052 $h = 0; 6053 } 6054 if ($m == '') { 6055 $m = 0; 6056 } 6057 $emptydate = 0; 6058 $emptyhours = 0; 6059 if ($stepminutes <= 0 || $stepminutes > 30) { 6060 $stepminutes = 1; 6061 } 6062 if ($empty == 1) { 6063 $emptydate = 1; 6064 $emptyhours = 1; 6065 } 6066 if ($empty == 2) { 6067 $emptydate = 0; 6068 $emptyhours = 1; 6069 } 6070 $orig_set_time = $set_time; 6071 6072 if ($set_time === '' && $emptydate == 0) { 6073 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; 6074 if ($gm == 'tzuser' || $gm == 'tzuserrel') { 6075 $set_time = dol_now($gm); 6076 } else { 6077 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone 6078 } 6079 } 6080 6081 // Analysis of the pre-selection date 6082 $reg = array(); 6083 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage 6084 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS' 6085 $syear = (!empty($reg[1]) ? $reg[1] : ''); 6086 $smonth = (!empty($reg[2]) ? $reg[2] : ''); 6087 $sday = (!empty($reg[3]) ? $reg[3] : ''); 6088 $shour = (!empty($reg[4]) ? $reg[4] : ''); 6089 $smin = (!empty($reg[5]) ? $reg[5] : ''); 6090 } elseif (strval($set_time) != '' && $set_time != -1) { 6091 // set_time est un timestamps (0 possible) 6092 $syear = dol_print_date($set_time, "%Y", $gm); 6093 $smonth = dol_print_date($set_time, "%m", $gm); 6094 $sday = dol_print_date($set_time, "%d", $gm); 6095 if ($orig_set_time != '') { 6096 $shour = dol_print_date($set_time, "%H", $gm); 6097 $smin = dol_print_date($set_time, "%M", $gm); 6098 $ssec = dol_print_date($set_time, "%S", $gm); 6099 } else { 6100 $shour = ''; 6101 $smin = ''; 6102 $ssec = ''; 6103 } 6104 } else { 6105 // Date est '' ou vaut -1 6106 $syear = ''; 6107 $smonth = ''; 6108 $sday = ''; 6109 $shour = !isset($conf->global->MAIN_DEFAULT_DATE_HOUR) ? ($h == -1 ? '23' : '') : $conf->global->MAIN_DEFAULT_DATE_HOUR; 6110 $smin = !isset($conf->global->MAIN_DEFAULT_DATE_MIN) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_MIN; 6111 $ssec = !isset($conf->global->MAIN_DEFAULT_DATE_SEC) ? ($h == -1 ? '59' : '') : $conf->global->MAIN_DEFAULT_DATE_SEC; 6112 } 6113 if ($h == 3) { 6114 $shour = ''; 6115 } 6116 if ($m == 3) { 6117 $smin = ''; 6118 } 6119 6120 $nowgmt = dol_now('gmt'); 6121 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel')); 6122 6123 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery' 6124 $usecalendar = 'combo'; 6125 if (!empty($conf->use_javascript_ajax) && (empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR != "none")) { 6126 $usecalendar = ((empty($conf->global->MAIN_POPUP_CALENDAR) || $conf->global->MAIN_POPUP_CALENDAR == 'eldy') ? 'jquery' : $conf->global->MAIN_POPUP_CALENDAR); 6127 } 6128 6129 if ($d) { 6130 // Show date with popup 6131 if ($usecalendar != 'combo') { 6132 $formated_date = ''; 6133 //print "e".$set_time." t ".$conf->format_date_short; 6134 if (strval($set_time) != '' && $set_time != -1) { 6135 //$formated_date=dol_print_date($set_time,$conf->format_date_short); 6136 $formated_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript 6137 } 6138 6139 // Calendrier popup version eldy 6140 if ($usecalendar == "eldy") { 6141 // Input area to enter date manually 6142 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"'; 6143 $retstring .= ($disabled ? ' disabled' : ''); 6144 $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript 6145 $retstring .= '>'; 6146 6147 // Icon calendar 6148 $retstringbuttom = ''; 6149 if (!$disabled) { 6150 $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons"'; 6151 $base = DOL_URL_ROOT.'/core/'; 6152 $retstringbuttom .= ' onClick="showDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');"'; 6153 $retstringbuttom .= '>'.img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"').'</button>'; 6154 } else { 6155 $retstringbuttom = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>'; 6156 } 6157 $retstring = $retstringbuttom.$retstring; 6158 6159 $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n"; 6160 $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n"; 6161 $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n"; 6162 } elseif ($usecalendar == 'jquery') { 6163 if (!$disabled) { 6164 // Output javascript for datepicker 6165 $retstring .= "<script type='text/javascript'>"; 6166 $retstring .= "$(function(){ $('#".$prefix."').datepicker({ 6167 dateFormat: '".$langs->trans("FormatDateShortJQueryInput")."', 6168 autoclose: true, 6169 todayHighlight: true,"; 6170 if (!empty($conf->dol_use_jmobile)) { 6171 $retstring .= " 6172 beforeShow: function (input, datePicker) { 6173 input.disabled = true; 6174 }, 6175 onClose: function (dateText, datePicker) { 6176 this.disabled = false; 6177 }, 6178 "; 6179 } 6180 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php 6181 if (empty($conf->global->MAIN_POPUP_CALENDAR_ON_FOCUS)) { 6182 $retstring .= " 6183 showOn: 'button', /* both has problem with autocompletion */ 6184 buttonImage: '".DOL_URL_ROOT."/theme/".$conf->theme."/img/object_calendarday.png', 6185 buttonImageOnly: true"; 6186 } 6187 $retstring .= " 6188 }) });"; 6189 $retstring .= "</script>"; 6190 } 6191 6192 // Zone de saisie manuelle de la date 6193 $retstring .= '<div class="nowrap inline-block divfordateinput">'; 6194 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="text" class="maxwidthdate" maxlength="11" value="'.$formated_date.'"'; 6195 $retstring .= ($disabled ? ' disabled' : ''); 6196 $retstring .= ($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : ''); 6197 $retstring .= ' onChange="dpChangeDay(\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript 6198 $retstring .= '>'; 6199 6200 // Icone calendrier 6201 if (!$disabled) { 6202 /* Not required. Managed by option buttonImage of jquery 6203 $retstring.=img_object($langs->trans("SelectDate"),'calendarday','id="'.$prefix.'id" class="datecallink"'); 6204 $retstring.="<script type='text/javascript'>"; 6205 $retstring.="jQuery(document).ready(function() {"; 6206 $retstring.=' jQuery("#'.$prefix.'id").click(function() {'; 6207 $retstring.=" jQuery('#".$prefix."').focus();"; 6208 $retstring.=' });'; 6209 $retstring.='});'; 6210 $retstring.="</script>";*/ 6211 } else { 6212 $retstringbutton = '<button id="'.$prefix.'Button" type="button" class="dpInvisibleButtons">'.img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"').'</button>'; 6213 $retsring = $retstringbutton.$retstring; 6214 } 6215 6216 $retstring .= '</div>'; 6217 $retstring .= '<input type="hidden" id="'.$prefix.'day" name="'.$prefix.'day" value="'.$sday.'">'."\n"; 6218 $retstring .= '<input type="hidden" id="'.$prefix.'month" name="'.$prefix.'month" value="'.$smonth.'">'."\n"; 6219 $retstring .= '<input type="hidden" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'."\n"; 6220 } else { 6221 $retstring .= "Bad value of MAIN_POPUP_CALENDAR"; 6222 } 6223 } else { 6224 // Show date with combo selects 6225 // Day 6226 $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50imp" id="'.$prefix.'day" name="'.$prefix.'day">'; 6227 6228 if ($emptydate || $set_time == -1) { 6229 $retstring .= '<option value="0" selected> </option>'; 6230 } 6231 6232 for ($day = 1; $day <= 31; $day++) { 6233 $retstring .= '<option value="'.$day.'"'.($day == $sday ? ' selected' : '').'>'.$day.'</option>'; 6234 } 6235 6236 $retstring .= "</select>"; 6237 6238 $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'month" name="'.$prefix.'month">'; 6239 if ($emptydate || $set_time == -1) { 6240 $retstring .= '<option value="0" selected> </option>'; 6241 } 6242 6243 // Month 6244 for ($month = 1; $month <= 12; $month++) { 6245 $retstring .= '<option value="'.$month.'"'.($month == $smonth ? ' selected' : '').'>'; 6246 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b"); 6247 $retstring .= "</option>"; 6248 } 6249 $retstring .= "</select>"; 6250 6251 // Year 6252 if ($emptydate || $set_time == -1) { 6253 $retstring .= '<input'.($disabled ? ' disabled' : '').' placeholder="'.dol_escape_htmltag($langs->trans("Year")).'" class="flat maxwidth50imp valignmiddle" type="number" min="0" max="3000" maxlength="4" id="'.$prefix.'year" name="'.$prefix.'year" value="'.$syear.'">'; 6254 } else { 6255 $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">'; 6256 6257 for ($year = $syear - 10; $year < $syear + 10; $year++) { 6258 $retstring .= '<option value="'.$year.'"'.($year == $syear ? ' selected' : '').'>'.$year.'</option>'; 6259 } 6260 $retstring .= "</select>\n"; 6261 } 6262 } 6263 } 6264 6265 if ($d && $h) { 6266 $retstring .= ($h == 2 ? '<br>' : ' '); 6267 $retstring .= '<span class="nowraponall">'; 6268 } 6269 6270 if ($h) { 6271 $hourstart = 0; 6272 $hourend = 24; 6273 if ($openinghours != '') { 6274 $openinghours = explode(',', $openinghours); 6275 $hourstart = $openinghours[0]; 6276 $hourend = $openinghours[1]; 6277 if ($hourend < $hourstart) { 6278 $hourend = $hourstart; 6279 } 6280 } 6281 // Show hour 6282 $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'hour' : '').'" id="'.$prefix.'hour" name="'.$prefix.'hour">'; 6283 if ($emptyhours) { 6284 $retstring .= '<option value="-1"> </option>'; 6285 } 6286 for ($hour = $hourstart; $hour < $hourend; $hour++) { 6287 if (strlen($hour) < 2) { 6288 $hour = "0".$hour; 6289 } 6290 $retstring .= '<option value="'.$hour.'"'.(($hour == $shour) ? ' selected' : '').'>'.$hour; 6291 //$retstring .= (empty($conf->dol_optimize_smallscreen) ? '' : 'H'); 6292 $retstring .= '</option>'; 6293 } 6294 $retstring .= '</select>'; 6295 //if ($m && empty($conf->dol_optimize_smallscreen)) $retstring .= ":"; 6296 if ($m) { 6297 $retstring .= ":"; 6298 } 6299 } 6300 6301 if ($m) { 6302 // Show minutes 6303 $retstring .= '<select'.($disabled ? ' disabled' : '').' class="flat valignmiddle maxwidth50 '.($fullday ? $fullday.'min' : '').'" id="'.$prefix.'min" name="'.$prefix.'min">'; 6304 if ($emptyhours) { 6305 $retstring .= '<option value="-1"> </option>'; 6306 } 6307 for ($min = 0; $min < 60; $min += $stepminutes) { 6308 if (strlen($min) < 2) { 6309 $min = "0".$min; 6310 } 6311 $retstring .= '<option value="'.$min.'"'.(($min == $smin) ? ' selected' : '').'>'.$min.(empty($conf->dol_optimize_smallscreen) ? '' : '').'</option>'; 6312 } 6313 $retstring .= '</select>'; 6314 6315 $retstring .= '<input type="hidden" name="'.$prefix.'sec" value="'.$ssec.'">'; 6316 } 6317 6318 if ($d && $h) { 6319 $retstring .= '</span>'; 6320 } 6321 6322 // Add a "Now" link 6323 if ($conf->use_javascript_ajax && $addnowlink) { 6324 // Script which will be inserted in the onClick of the "Now" link 6325 $reset_scripts = ""; 6326 if ($addnowlink == 2) { // local computer time 6327 // pad add leading 0 on numbers 6328 $reset_scripts .= "Number.prototype.pad = function(size) { 6329 var s = String(this); 6330 while (s.length < (size || 2)) {s = '0' + s;} 6331 return s; 6332 }; 6333 var d = new Date();"; 6334 } 6335 6336 // Generate the date part, depending on the use or not of the javascript calendar 6337 if ($addnowlink == 1) { // server time expressed in user time setup 6338 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');'; 6339 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');'; 6340 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');'; 6341 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');'; 6342 } elseif ($addnowlink == 2) { 6343 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix. 6344 * This break application for foreign languages. 6345 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));'; 6346 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());'; 6347 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);'; 6348 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());'; 6349 */ 6350 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'day', 'tzuserrel').'\');'; 6351 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');'; 6352 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');'; 6353 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');'; 6354 } 6355 /*if ($usecalendar == "eldy") 6356 { 6357 $base=DOL_URL_ROOT.'/core/'; 6358 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');'; 6359 } 6360 else 6361 { 6362 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); '; 6363 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); '; 6364 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); '; 6365 }*/ 6366 // Update the hour part 6367 if ($h) { 6368 if ($fullday) { 6369 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; 6370 } 6371 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); '; 6372 if ($addnowlink == 1) { 6373 $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');'; 6374 $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();'; 6375 } elseif ($addnowlink == 2) { 6376 $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(d.getHours().pad());'; 6377 $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').change();'; 6378 } 6379 6380 if ($fullday) { 6381 $reset_scripts .= ' } '; 6382 } 6383 } 6384 // Update the minute part 6385 if ($m) { 6386 if ($fullday) { 6387 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; 6388 } 6389 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); '; 6390 if ($addnowlink == 1) { 6391 $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');'; 6392 $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();'; 6393 } elseif ($addnowlink == 2) { 6394 $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(d.getMinutes().pad());'; 6395 $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').change();'; 6396 } 6397 if ($fullday) { 6398 $reset_scripts .= ' } '; 6399 } 6400 } 6401 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick 6402 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) { 6403 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonNow" type="button" name="_useless" value="now" onClick="'.$reset_scripts.'">'; 6404 $retstring .= $langs->trans("Now"); 6405 $retstring .= '</button> '; 6406 } 6407 } 6408 6409 // Add a "Plus one hour" link 6410 if ($conf->use_javascript_ajax && $addplusone) { 6411 // Script which will be inserted in the onClick of the "Add plusone" link 6412 $reset_scripts = ""; 6413 6414 // Generate the date part, depending on the use or not of the javascript calendar 6415 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel').'\');'; 6416 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.dol_print_date($nowgmt, '%d', 'tzuserrel').'\');'; 6417 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.dol_print_date($nowgmt, '%m', 'tzuserrel').'\');'; 6418 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.dol_print_date($nowgmt, '%Y', 'tzuserrel').'\');'; 6419 // Update the hour part 6420 if ($h) { 6421 if ($fullday) { 6422 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; 6423 } 6424 $reset_scripts .= 'jQuery(\'#'.$prefix.'hour\').val(\''.dol_print_date($nowgmt, '%H', 'tzuserrel').'\');'; 6425 if ($fullday) { 6426 $reset_scripts .= ' } '; 6427 } 6428 } 6429 // Update the minute part 6430 if ($m) { 6431 if ($fullday) { 6432 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {"; 6433 } 6434 $reset_scripts .= 'jQuery(\'#'.$prefix.'min\').val(\''.dol_print_date($nowgmt, '%M', 'tzuserrel').'\');'; 6435 if ($fullday) { 6436 $reset_scripts .= ' } '; 6437 } 6438 } 6439 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick 6440 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) { 6441 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="'.$prefix.'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="'.$reset_scripts.'">'; 6442 $retstring .= $langs->trans("DateStartPlusOne"); 6443 $retstring .= '</button> '; 6444 } 6445 } 6446 6447 // Add a link to set data 6448 if ($conf->use_javascript_ajax && $adddateof) { 6449 $tmparray = dol_getdate($adddateof); 6450 if (empty($labeladddateof)) { 6451 $labeladddateof = $langs->trans("DateInvoice"); 6452 } 6453 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="console.log(\'Click on now link\'); jQuery(\'#re\').val(\''.dol_print_date($adddateof, 'dayinputnoreduce').'\');jQuery(\'#reday\').val(\''.$tmparray['mday'].'\');jQuery(\'#remonth\').val(\''.$tmparray['mon'].'\');jQuery(\'#reyear\').val(\''.$tmparray['year'].'\');">'.$labeladddateof.'</a>'; 6454 } 6455 6456 return $retstring; 6457 } 6458 6459 /** 6460 * selectTypeDuration 6461 * 6462 * @param string $prefix Prefix 6463 * @param string $selected Selected duration type 6464 * @param array $excludetypes Array of duration types to exclude. Example array('y', 'm') 6465 * @return string HTML select string 6466 */ 6467 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array()) 6468 { 6469 global $langs; 6470 6471 $TDurationTypes = array( 6472 'y'=>$langs->trans('Years'), 6473 'm'=>$langs->trans('Month'), 6474 'w'=>$langs->trans('Weeks'), 6475 'd'=>$langs->trans('Days'), 6476 'h'=>$langs->trans('Hours'), 6477 'i'=>$langs->trans('Minutes') 6478 ); 6479 6480 // Removed undesired duration types 6481 foreach ($excludetypes as $value) { 6482 unset($TDurationTypes[$value]); 6483 } 6484 6485 $retstring = '<select class="flat" id="select_'.$prefix.'type_duration" name="'.$prefix.'type_duration">'; 6486 foreach ($TDurationTypes as $key => $typeduration) { 6487 $retstring .= '<option value="'.$key.'"'; 6488 if ($key == $selected) { 6489 $retstring .= " selected"; 6490 } 6491 $retstring .= ">".$typeduration."</option>"; 6492 } 6493 $retstring .= "</select>"; 6494 6495 $retstring .= ajax_combobox('select_'.$prefix.'type_duration'); 6496 6497 return $retstring; 6498 } 6499 6500 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 6501 /** 6502 * Function to show a form to select a duration on a page 6503 * 6504 * @param string $prefix Prefix for input fields 6505 * @param int $iSecond Default preselected duration (number of seconds or '') 6506 * @param int $disabled Disable the combo box 6507 * @param string $typehour If 'select' then input hour and input min is a combo, 6508 * If 'text' input hour is in text and input min is a text, 6509 * If 'textselect' input hour is in text and input min is a combo 6510 * @param integer $minunderhours If 1, show minutes selection under the hours 6511 * @param int $nooutput Do not output html string but return it 6512 * @return string|void 6513 */ 6514 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0) 6515 { 6516 // phpcs:enable 6517 global $langs; 6518 6519 $retstring = ''; 6520 6521 $hourSelected = 0; 6522 $minSelected = 0; 6523 6524 // Hours 6525 if ($iSecond != '') { 6526 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; 6527 6528 $hourSelected = convertSecondToTime($iSecond, 'allhour'); 6529 $minSelected = convertSecondToTime($iSecond, 'min'); 6530 } 6531 6532 if ($typehour == 'select') { 6533 $retstring .= '<select class="flat" id="select_'.$prefix.'hour" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').'>'; 6534 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours 6535 $retstring .= '<option value="'.$hour.'"'; 6536 if ($hourSelected == $hour) { 6537 $retstring .= " selected"; 6538 } 6539 $retstring .= ">".$hour."</option>"; 6540 } 6541 $retstring .= "</select>"; 6542 } elseif ($typehour == 'text' || $typehour == 'textselect') { 6543 $retstring .= '<input placeholder="'.$langs->trans('HourShort').'" type="number" min="0" name="'.$prefix.'hour"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputhour" value="'.(($hourSelected != '') ? ((int) $hourSelected) : '').'">'; 6544 } else { 6545 return 'BadValueForParameterTypeHour'; 6546 } 6547 6548 if ($typehour != 'text') { 6549 $retstring .= ' '.$langs->trans('HourShort'); 6550 } else { 6551 $retstring .= '<span class="hideonsmartphone">:</span>'; 6552 } 6553 6554 // Minutes 6555 if ($minunderhours) { 6556 $retstring .= '<br>'; 6557 } else { 6558 $retstring .= '<span class="hideonsmartphone"> </span>'; 6559 } 6560 6561 if ($typehour == 'select' || $typehour == 'textselect') { 6562 $retstring .= '<select class="flat" id="select_'.$prefix.'min" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').'>'; 6563 for ($min = 0; $min <= 55; $min = $min + 5) { 6564 $retstring .= '<option value="'.$min.'"'; 6565 if ($minSelected == $min) { 6566 $retstring .= ' selected'; 6567 } 6568 $retstring .= '>'.$min.'</option>'; 6569 } 6570 $retstring .= "</select>"; 6571 } elseif ($typehour == 'text') { 6572 $retstring .= '<input placeholder="'.$langs->trans('MinuteShort').'" type="number" min="0" name="'.$prefix.'min"'.($disabled ? ' disabled' : '').' class="flat maxwidth50 inputminute" value="'.(($minSelected != '') ? ((int) $minSelected) : '').'">'; 6573 } 6574 6575 if ($typehour != 'text') { 6576 $retstring .= ' '.$langs->trans('MinuteShort'); 6577 } 6578 6579 //$retstring.=" "; 6580 6581 if (!empty($nooutput)) { 6582 return $retstring; 6583 } 6584 6585 print $retstring; 6586 return; 6587 } 6588 6589 6590 /** 6591 * Generic method to select a component from a combo list. 6592 * Can use autocomplete with ajax after x key pressed or a full combo, depending on setup. 6593 * This is the generic method that will replace all specific existing methods. 6594 * 6595 * @param string $objectdesc ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]] 6596 * @param string $htmlname Name of HTML select component 6597 * @param int $preselectedvalue Preselected value (ID of element) 6598 * @param string $showempty ''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...) 6599 * @param string $searchkey Search criteria 6600 * @param string $placeholder Place holder 6601 * @param string $morecss More CSS 6602 * @param string $moreparams More params provided to ajax call 6603 * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) 6604 * @param int $disabled 1=Html component is disabled 6605 * @param string $selected_input_value Value of preselected input text (for use with ajax) 6606 * @return string Return HTML string 6607 * @see selectForFormsList() select_thirdparty_list() 6608 */ 6609 public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '') 6610 { 6611 global $conf, $user; 6612 6613 $objecttmp = null; 6614 6615 $InfoFieldList = explode(":", $objectdesc); 6616 $classname = $InfoFieldList[0]; 6617 $classpath = $InfoFieldList[1]; 6618 $addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2]; 6619 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]; 6620 6621 if (!empty($classpath)) { 6622 dol_include_once($classpath); 6623 6624 if ($classname && class_exists($classname)) { 6625 $objecttmp = new $classname($this->db); 6626 // Make some replacement 6627 $sharedentities = getEntity(strtolower($classname)); 6628 $objecttmp->filter = str_replace( 6629 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'), 6630 array($conf->entity, $sharedentities, $user->id), 6631 $filter 6632 ); 6633 } 6634 } 6635 if (!is_object($objecttmp)) { 6636 dol_syslog('Error bad setup of type for field '.$InfoFieldList, LOG_WARNING); 6637 return 'Error bad setup of type for field '.join(',', $InfoFieldList); 6638 } 6639 6640 //var_dump($objecttmp->filter); 6641 $prefixforautocompletemode = $objecttmp->element; 6642 if ($prefixforautocompletemode == 'societe') { 6643 $prefixforautocompletemode = 'company'; 6644 } 6645 if ($prefixforautocompletemode == 'product') { 6646 $prefixforautocompletemode = 'produit'; 6647 } 6648 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT 6649 6650 dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG); 6651 $out = ''; 6652 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->$confkeyforautocompletemode) && !$forcecombo) { 6653 // No immediate load of all database 6654 $placeholder = ''; 6655 if ($preselectedvalue && empty($selected_input_value)) { 6656 $objecttmp->fetch($preselectedvalue); 6657 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref); 6658 //unset($objecttmp); 6659 } 6660 6661 $objectdesc = $classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter; 6662 $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php'; 6663 6664 // No immediate load of all database 6665 $urloption = 'htmlname='.$htmlname.'&outjson=1&objectdesc='.$objectdesc.'&filter='.urlencode($objecttmp->filter); 6666 // Activate the auto complete using ajax call. 6667 $out .= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array()); 6668 $out .= '<style type="text/css">.ui-autocomplete { z-index: 1003; }</style>'; 6669 $out .= '<input type="text" class="'.$morecss.'"'.($disabled ? ' disabled="disabled"' : '').' name="search_'.$htmlname.'" id="search_'.$htmlname.'" value="'.$selected_input_value.'"'.($placeholder ? ' placeholder="'.dol_escape_htmltag($placeholder).'"' : '') .' />'; 6670 } else { 6671 // Immediate load of table record. Note: filter is inside $objecttmp->filter 6672 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled); 6673 } 6674 6675 return $out; 6676 } 6677 6678 /** 6679 * Function to forge a SQL criteria 6680 * 6681 * @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" 6682 * @return string Forged criteria. Example: "t.field like 'abc%'" 6683 */ 6684 protected static function forgeCriteriaCallback($matches) 6685 { 6686 global $db; 6687 6688 //dol_syslog("Convert matches ".$matches[1]); 6689 if (empty($matches[1])) { 6690 return ''; 6691 } 6692 $tmp = explode(':', $matches[1]); 6693 if (count($tmp) < 3) { 6694 return ''; 6695 } 6696 6697 $tmpescaped = $tmp[2]; 6698 $regbis = array(); 6699 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) { 6700 $tmpescaped = "'".$db->escape($regbis[1])."'"; 6701 } else { 6702 $tmpescaped = $db->escape($tmpescaped); 6703 } 6704 return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped; 6705 } 6706 6707 /** 6708 * Output html form to select an object. 6709 * Note, this function is called by selectForForms or by ajax selectobject.php 6710 * 6711 * @param Object $objecttmp Object to knwo the table to scan for combo. 6712 * @param string $htmlname Name of HTML select component 6713 * @param int $preselectedvalue Preselected value (ID of element) 6714 * @param string $showempty ''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...) 6715 * @param string $searchkey Search value 6716 * @param string $placeholder Place holder 6717 * @param string $morecss More CSS 6718 * @param string $moreparams More params provided to ajax call 6719 * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) 6720 * @param int $outputmode 0=HTML select string, 1=Array 6721 * @param int $disabled 1=Html component is disabled 6722 * @return string|array Return HTML string 6723 * @see selectForForms() 6724 */ 6725 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0) 6726 { 6727 global $conf, $langs, $user, $hookmanager; 6728 6729 //print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled"; 6730 6731 $prefixforautocompletemode = $objecttmp->element; 6732 if ($prefixforautocompletemode == 'societe') { 6733 $prefixforautocompletemode = 'company'; 6734 } 6735 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT 6736 6737 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...) 6738 $tmpfieldstoshow = ''; 6739 foreach ($objecttmp->fields as $key => $val) { 6740 if (!dol_eval($val['enabled'], 1, 1)) { 6741 continue; 6742 } 6743 if (!empty($val['showoncombobox'])) { 6744 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '').'t.'.$key; 6745 } 6746 } 6747 if ($tmpfieldstoshow) { 6748 $fieldstoshow = $tmpfieldstoshow; 6749 } 6750 } else { 6751 // For backward compatibility 6752 $objecttmp->fields['ref'] = array('type'=>'varchar(30)', 'label'=>'Ref', 'showoncombobox'=>1); 6753 } 6754 6755 if (empty($fieldstoshow)) { 6756 if (isset($objecttmp->fields['ref'])) { 6757 $fieldstoshow = 't.ref'; 6758 } else { 6759 $langs->load("errors"); 6760 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox"); 6761 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox'); 6762 } 6763 } 6764 6765 $out = ''; 6766 $outarray = array(); 6767 6768 $num = 0; 6769 6770 // Search data 6771 $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX.$objecttmp->table_element." as t"; 6772 if (isset($objecttmp->ismultientitymanaged)) { 6773 if (!is_numeric($objecttmp->ismultientitymanaged)) { 6774 $tmparray = explode('@', $objecttmp->ismultientitymanaged); 6775 $sql .= " INNER JOIN ".MAIN_DB_PREFIX.$tmparray[1]." as parenttable ON parenttable.rowid = t.".$tmparray[0]; 6776 } 6777 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') { 6778 if (!$user->rights->societe->client->voir && !$user->socid) { 6779 $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; 6780 } 6781 } 6782 } 6783 6784 // Add where from hooks 6785 $parameters = array(); 6786 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook 6787 if (!empty($hookmanager->resPrint)) { 6788 $sql .= $hookmanager->resPrint; 6789 } else { 6790 $sql .= " WHERE 1=1"; 6791 if (isset($objecttmp->ismultientitymanaged)) { 6792 if ($objecttmp->ismultientitymanaged == 1) { 6793 $sql .= " AND t.entity IN (".getEntity($objecttmp->table_element).")"; 6794 } 6795 if (!is_numeric($objecttmp->ismultientitymanaged)) { 6796 $sql .= " AND parenttable.entity = t.".$tmparray[0]; 6797 } 6798 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) { 6799 if ($objecttmp->element == 'societe') { 6800 $sql .= " AND t.rowid = ".((int) $user->socid); 6801 } else { 6802 $sql .= " AND t.fk_soc = ".((int) $user->socid); 6803 } 6804 } 6805 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') { 6806 if (!$user->rights->societe->client->voir && !$user->socid) { 6807 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id); 6808 } 6809 } 6810 } 6811 if ($searchkey != '') { 6812 $sql .= natural_search(explode(',', $fieldstoshow), $searchkey); 6813 } 6814 if ($objecttmp->ismultientitymanaged == 'fk_soc@societe') { 6815 if (!$user->rights->societe->client->voir && !$user->socid) { 6816 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = ".((int) $user->id); 6817 } 6818 } 6819 if ($objecttmp->filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" 6820 /*if (! DolibarrApi::_checkFilters($objecttmp->filter)) 6821 { 6822 throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter); 6823 }*/ 6824 $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; 6825 $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")"; 6826 } 6827 } 6828 $sql .= $this->db->order($fieldstoshow, "ASC"); 6829 //$sql.=$this->db->plimit($limit, 0); 6830 //print $sql; 6831 6832 // Build output string 6833 $resql = $this->db->query($sql); 6834 if ($resql) { 6835 // Construct $out and $outarray 6836 $out .= '<select id="'.$htmlname.'" class="flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').($moreparams ? ' '.$moreparams : '').' name="'.$htmlname.'">'."\n"; 6837 6838 // Warning: Do not use textifempty = ' ' or ' ' here, or search on key will search on ' key'. Seems it is no more true with selec2 v4 6839 $textifempty = ' '; 6840 6841 //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty=''; 6842 if (!empty($conf->global->$confkeyforautocompletemode)) { 6843 if ($showempty && !is_numeric($showempty)) { 6844 $textifempty = $langs->trans($showempty); 6845 } else { 6846 $textifempty .= $langs->trans("All"); 6847 } 6848 } 6849 if ($showempty) { 6850 $out .= '<option value="-1">'.$textifempty.'</option>'."\n"; 6851 } 6852 6853 $num = $this->db->num_rows($resql); 6854 $i = 0; 6855 if ($num) { 6856 while ($i < $num) { 6857 $obj = $this->db->fetch_object($resql); 6858 $label = ''; 6859 $tmparray = explode(',', $fieldstoshow); 6860 $oldvalueforshowoncombobox = 0; 6861 foreach ($tmparray as $key => $val) { 6862 $val = preg_replace('/t\./', '', $val); 6863 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : ''); 6864 $label .= $obj->$val; 6865 $oldvalueforshowoncombobox = $objecttmp->fields[$val]['showoncombobox']; 6866 } 6867 if (empty($outputmode)) { 6868 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) { 6869 $out .= '<option value="'.$obj->rowid.'" selected>'.$label.'</option>'; 6870 } else { 6871 $out .= '<option value="'.$obj->rowid.'">'.$label.'</option>'; 6872 } 6873 } else { 6874 array_push($outarray, array('key'=>$obj->rowid, 'value'=>$label, 'label'=>$label)); 6875 } 6876 6877 $i++; 6878 if (($i % 10) == 0) { 6879 $out .= "\n"; 6880 } 6881 } 6882 } 6883 6884 $out .= '</select>'."\n"; 6885 6886 if (!$forcecombo) { 6887 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 6888 $out .= ajax_combobox($htmlname, null, (!empty($conf->global->$confkeyforautocompletemode) ? $conf->global->$confkeyforautocompletemode : 0)); 6889 } 6890 } else { 6891 dol_print_error($this->db); 6892 } 6893 6894 $this->result = array('nbofelement'=>$num); 6895 6896 if ($outputmode) { 6897 return $outarray; 6898 } 6899 return $out; 6900 } 6901 6902 6903 /** 6904 * Return a HTML select string, built from an array of key+value. 6905 * Note: Do not apply langs->trans function on returned content, content may be entity encoded twice. 6906 * 6907 * @param string $htmlname Name of html select area. Must start with "multi" if this is a multiselect 6908 * @param array $array Array like array(key => value) or array(key=>array('label'=>..., 'data-...'=>..., 'disabled'=>..., 'css'=>...)) 6909 * @param string|string[] $id Preselected key or preselected keys for multiselect 6910 * @param int|string $show_empty 0 no empty value allowed, 1 or string to add an empty value into list (If 1: key is -1 and value is '' or ' ', If placeholder string: key is -1 and value is the string), <0 to add an empty value with key that is this value. 6911 * @param int $key_in_label 1 to show key into label with format "[key] value" 6912 * @param int $value_as_key 1 to use value as key 6913 * @param string $moreparam Add more parameters onto the select tag. For example 'style="width: 95%"' to avoid select2 component to go over parent container 6914 * @param int $translate 1=Translate and encode value 6915 * @param int $maxlen Length maximum for labels 6916 * @param int $disabled Html select box is disabled 6917 * @param string $sort 'ASC' or 'DESC' = Sort on label, '' or 'NONE' or 'POS' = Do not sort, we keep original order 6918 * @param string $morecss Add more class to css styles 6919 * @param int $addjscombo Add js combo 6920 * @param string $moreparamonempty Add more param on the empty option line. Not used if show_empty not set 6921 * @param int $disablebademail 1=Check if a not valid email, 2=Check string '---', and if found into value, disable and colorize entry 6922 * @param int $nohtmlescape No html escaping. 6923 * @return string HTML select string. 6924 * @see multiselectarray(), selectArrayAjax(), selectArrayFilter() 6925 */ 6926 public static function selectarray($htmlname, $array, $id = '', $show_empty = 0, $key_in_label = 0, $value_as_key = 0, $moreparam = '', $translate = 0, $maxlen = 0, $disabled = 0, $sort = '', $morecss = '', $addjscombo = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0) 6927 { 6928 global $conf, $langs; 6929 6930 // Do we want a multiselect ? 6931 //$jsbeautify = 0; 6932 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1; 6933 $jsbeautify = 1; 6934 6935 if ($value_as_key) { 6936 $array = array_combine($array, $array); 6937 } 6938 6939 $out = ''; 6940 6941 if ($addjscombo < 0) { 6942 if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { 6943 $addjscombo = 1; 6944 } else { 6945 $addjscombo = 0; 6946 } 6947 } 6948 6949 // Add code for jquery to use multiselect 6950 if ($addjscombo && $jsbeautify) { 6951 // Enhance with select2 6952 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 6953 $out .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', $show_empty < 0 ? (string) $show_empty : '-1'); 6954 } 6955 6956 $out .= '<select id="'.preg_replace('/^\./', '', $htmlname).'" '.($disabled ? 'disabled="disabled" ' : '').'class="flat '.(preg_replace('/^\./', '', $htmlname)).($morecss ? ' '.$morecss : '').'"'; 6957 $out .= ' name="'.preg_replace('/^\./', '', $htmlname).'" '.($moreparam ? $moreparam : ''); 6958 $out .= '>'; 6959 6960 if ($show_empty) { 6961 $textforempty = ' '; 6962 if (!empty($conf->use_javascript_ajax)) { 6963 $textforempty = ' '; // If we use ajaxcombo, we need here to avoid to have an empty element that is too small. 6964 } 6965 if (!is_numeric($show_empty)) { 6966 $textforempty = $show_empty; 6967 } 6968 $out .= '<option class="optiongrey" '.($moreparamonempty ? $moreparamonempty.' ' : '').'value="'.($show_empty < 0 ? $show_empty : -1).'"'.($id == $show_empty ? ' selected' : '').'>'.$textforempty.'</option>'."\n"; 6969 } 6970 6971 if (is_array($array)) { 6972 // Translate 6973 if ($translate) { 6974 foreach ($array as $key => $value) { 6975 if (!is_array($value)) { 6976 $array[$key] = $langs->trans($value); 6977 } else { 6978 $array[$key]['label'] = $langs->trans($value['label']); 6979 } 6980 } 6981 } 6982 6983 // Sort 6984 if ($sort == 'ASC') { 6985 asort($array); 6986 } elseif ($sort == 'DESC') { 6987 arsort($array); 6988 } 6989 6990 foreach ($array as $key => $tmpvalue) { 6991 if (is_array($tmpvalue)) { 6992 $value = $tmpvalue['label']; 6993 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled'; 6994 $style = empty($tmpvalue['css']) ? ' class="'.$tmpvalue['css'].'"' : ''; 6995 } else { 6996 $value = $tmpvalue; 6997 $disabled = ''; 6998 $style = ''; 6999 } 7000 if (!empty($disablebademail)) { 7001 if (($disablebademail == 1 && !preg_match('/<.+@.+>/', $value)) 7002 || ($disablebademail == 2 && preg_match('/---/', $value))) { 7003 $disabled = ' disabled'; 7004 $style = ' class="warning"'; 7005 } 7006 } 7007 7008 if ($key_in_label) { 7009 if (empty($nohtmlescape)) { 7010 $selectOptionValue = dol_escape_htmltag($key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value)); 7011 } else { 7012 $selectOptionValue = $key.' - '.($maxlen ?dol_trunc($value, $maxlen) : $value); 7013 } 7014 } else { 7015 if (empty($nohtmlescape)) { 7016 $selectOptionValue = dol_escape_htmltag($maxlen ?dol_trunc($value, $maxlen) : $value); 7017 } else { 7018 $selectOptionValue = $maxlen ?dol_trunc($value, $maxlen) : $value; 7019 } 7020 if ($value == '' || $value == '-') { 7021 $selectOptionValue = ' '; 7022 } 7023 } 7024 7025 $out .= '<option value="'.$key.'"'; 7026 $out .= $style.$disabled; 7027 if (is_array($id)) { 7028 if (in_array($key, $id) && !$disabled) { 7029 $out .= ' selected'; // To preselect a value 7030 } 7031 } else { 7032 $id = (string) $id; // if $id = 0, then $id = '0' 7033 if ($id != '' && $id == $key && !$disabled) { 7034 $out .= ' selected'; // To preselect a value 7035 } 7036 } 7037 if ($nohtmlescape) { 7038 $out .= ' data-html="'.dol_escape_htmltag($selectOptionValue).'"'; 7039 } 7040 if (is_array($tmpvalue)) { 7041 foreach ($tmpvalue as $keyforvalue => $valueforvalue) { 7042 if (preg_match('/^data-/', $keyforvalue)) { 7043 $out .= ' '.$keyforvalue.'="'.$valueforvalue.'"'; 7044 } 7045 } 7046 } 7047 $out .= '>'; 7048 //var_dump($selectOptionValue); 7049 $out .= $selectOptionValue; 7050 $out .= "</option>\n"; 7051 } 7052 } 7053 7054 $out .= "</select>"; 7055 return $out; 7056 } 7057 7058 7059 /** 7060 * 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. 7061 * Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice. 7062 * 7063 * @param string $htmlname Name of html select area 7064 * @param string $url Url. Must return a json_encode of array(key=>array('text'=>'A text', 'url'=>'An url'), ...) 7065 * @param string $id Preselected key 7066 * @param string $moreparam Add more parameters onto the select tag 7067 * @param string $moreparamtourl Add more parameters onto the Ajax called URL 7068 * @param int $disabled Html select box is disabled 7069 * @param int $minimumInputLength Minimum Input Length 7070 * @param string $morecss Add more class to css styles 7071 * @param int $callurlonselect If set to 1, some code is added so an url return by the ajax is called when value is selected. 7072 * @param string $placeholder String to use as placeholder 7073 * @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) 7074 * @return string HTML select string 7075 * @see selectArrayFilter(), ajax_combobox() in ajax.lib.php 7076 */ 7077 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0) 7078 { 7079 global $conf, $langs; 7080 global $delayedhtmlcontent; // Will be used later outside of this function 7081 7082 // TODO Use an internal dolibarr component instead of select2 7083 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) { 7084 return ''; 7085 } 7086 7087 $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"></select>'; 7088 7089 $outdelayed = ''; 7090 if (!empty($conf->use_javascript_ajax)) { 7091 $tmpplugin = 'select2'; 7092 $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' --> 7093 <script> 7094 $(document).ready(function () { 7095 7096 '.($callurlonselect ? 'var saveRemoteData = [];' : '').' 7097 7098 $(".'.$htmlname.'").select2({ 7099 ajax: { 7100 dir: "ltr", 7101 url: "'.$url.'", 7102 dataType: \'json\', 7103 delay: 250, 7104 data: function (params) { 7105 return { 7106 q: params.term, // search term 7107 page: params.page 7108 }; 7109 }, 7110 processResults: function (data) { 7111 // parse the results into the format expected by Select2. 7112 // since we are using custom formatting functions we do not need to alter the remote JSON data 7113 //console.log(data); 7114 saveRemoteData = data; 7115 /* format json result for select2 */ 7116 result = [] 7117 $.each( data, function( key, value ) { 7118 result.push({id: key, text: value.text}); 7119 }); 7120 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false} 7121 //console.log(result); 7122 return {results: result, more: false} 7123 }, 7124 cache: true 7125 }, 7126 language: select2arrayoflanguage, 7127 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */ 7128 placeholder: "'.dol_escape_js($placeholder).'", 7129 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work 7130 minimumInputLength: '.$minimumInputLength.', 7131 formatResult: function(result, container, query, escapeMarkup) { 7132 return escapeMarkup(result.text); 7133 }, 7134 }); 7135 7136 '.($callurlonselect ? ' 7137 /* Code to execute a GET when we select a value */ 7138 $(".'.$htmlname.'").change(function() { 7139 var selected = $(".'.$htmlname.'").val(); 7140 console.log("We select in selectArrayAjax the entry "+selected) 7141 $(".'.$htmlname.'").val(""); /* reset visible combo value */ 7142 $.each( saveRemoteData, function( key, value ) { 7143 if (key == selected) 7144 { 7145 console.log("selectArrayAjax - Do a redirect to "+value.url) 7146 location.assign(value.url); 7147 } 7148 }); 7149 });' : '').' 7150 7151 }); 7152 </script>'; 7153 } 7154 7155 if ($acceptdelayedhtml) { 7156 $delayedhtmlcontent .= $outdelayed; 7157 } else { 7158 $out .= $outdelayed; 7159 } 7160 return $out; 7161 } 7162 7163 /** 7164 * Return a HTML select string, built from an array of key+value, but content returned into select is defined into $array parameter. 7165 * Note: Do not apply langs->trans function on returned content of Ajax service, content may be entity encoded twice. 7166 * 7167 * @param string $htmlname Name of html select area 7168 * @param array $array Array (key=>array('text'=>'A text', 'url'=>'An url'), ...) 7169 * @param string $id Preselected key 7170 * @param string $moreparam Add more parameters onto the select tag 7171 * @param int $disableFiltering If set to 1, results are not filtered with searched string 7172 * @param int $disabled Html select box is disabled 7173 * @param int $minimumInputLength Minimum Input Length 7174 * @param string $morecss Add more class to css styles 7175 * @param int $callurlonselect If set to 1, some code is added so an url return by the ajax is called when value is selected. 7176 * @param string $placeholder String to use as placeholder 7177 * @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) 7178 * @return string HTML select string 7179 * @see selectArrayAjax(), ajax_combobox() in ajax.lib.php 7180 */ 7181 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0) 7182 { 7183 global $conf, $langs; 7184 global $delayedhtmlcontent; // Will be used later outside of this function 7185 7186 // TODO Use an internal dolibarr component instead of select2 7187 if (empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) && !defined('REQUIRE_JQUERY_MULTISELECT')) { 7188 return ''; 7189 } 7190 7191 $out = '<select type="text" class="'.$htmlname.($morecss ? ' '.$morecss : '').'" '.($moreparam ? $moreparam.' ' : '').'name="'.$htmlname.'"><option></option></select>'; 7192 7193 $formattedarrayresult = array(); 7194 7195 foreach ($array as $key => $value) { 7196 $o = new stdClass(); 7197 $o->id = $key; 7198 $o->text = $value['text']; 7199 $o->url = $value['url']; 7200 $formattedarrayresult[] = $o; 7201 } 7202 7203 $outdelayed = ''; 7204 if (!empty($conf->use_javascript_ajax)) { 7205 $tmpplugin = 'select2'; 7206 $outdelayed = "\n".'<!-- JS CODE TO ENABLE '.$tmpplugin.' for id '.$htmlname.' --> 7207 <script> 7208 $(document).ready(function () { 7209 var data = '.json_encode($formattedarrayresult).'; 7210 7211 '.($callurlonselect ? 'var saveRemoteData = '.json_encode($array).';' : '').' 7212 7213 $(".'.$htmlname.'").select2({ 7214 data: data, 7215 language: select2arrayoflanguage, 7216 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag */ 7217 placeholder: "'.dol_escape_js($placeholder).'", 7218 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work 7219 minimumInputLength: '.$minimumInputLength.', 7220 formatResult: function(result, container, query, escapeMarkup) { 7221 return escapeMarkup(result.text); 7222 }, 7223 matcher: function (params, data) { 7224 7225 if(! data.id) return null;'; 7226 7227 if ($callurlonselect) { 7228 $outdelayed .= ' 7229 7230 var urlBase = data.url; 7231 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?"; 7232 /* console.log("params.term="+params.term); */ 7233 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */ 7234 saveRemoteData[data.id].url = urlBase + separ + "sall=" + encodeURIComponent(params.term.replace(/\"/g, ""));'; 7235 } 7236 7237 if (!$disableFiltering) { 7238 $outdelayed .= ' 7239 7240 if(data.text.match(new RegExp(params.term))) { 7241 return data; 7242 } 7243 7244 return null;'; 7245 } else { 7246 $outdelayed .= ' 7247 7248 return data;'; 7249 } 7250 7251 $outdelayed .= ' 7252 } 7253 }); 7254 7255 '.($callurlonselect ? ' 7256 /* Code to execute a GET when we select a value */ 7257 $(".'.$htmlname.'").change(function() { 7258 var selected = $(".'.$htmlname.'").val(); 7259 console.log("We select "+selected) 7260 7261 $(".'.$htmlname.'").val(""); /* reset visible combo value */ 7262 $.each( saveRemoteData, function( key, value ) { 7263 if (key == selected) 7264 { 7265 console.log("selectArrayFilter - Do a redirect to "+value.url) 7266 location.assign(value.url); 7267 } 7268 }); 7269 });' : '').' 7270 7271 }); 7272 </script>'; 7273 } 7274 7275 if ($acceptdelayedhtml) { 7276 $delayedhtmlcontent .= $outdelayed; 7277 } else { 7278 $out .= $outdelayed; 7279 } 7280 return $out; 7281 } 7282 7283 /** 7284 * Show a multiselect form from an array. WARNING: Use this only for short lists. 7285 * 7286 * @param string $htmlname Name of select 7287 * @param array $array Array with key+value 7288 * @param array $selected Array with key+value preselected 7289 * @param int $key_in_label 1 to show key like in "[key] value" 7290 * @param int $value_as_key 1 to use value as key 7291 * @param string $morecss Add more css style 7292 * @param int $translate Translate and encode value 7293 * @param int $width Force width of select box. May be used only when using jquery couch. Example: 250, 95% 7294 * @param string $moreattrib Add more options on select component. Example: 'disabled' 7295 * @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. 7296 * @param string $placeholder String to use as placeholder 7297 * @param int $addjscombo Add js combo 7298 * @return string HTML multiselect string 7299 * @see selectarray(), selectArrayAjax(), selectArrayFilter() 7300 */ 7301 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) 7302 { 7303 global $conf, $langs; 7304 7305 $out = ''; 7306 7307 if ($addjscombo < 0) { 7308 if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { 7309 $addjscombo = 1; 7310 } else { 7311 $addjscombo = 0; 7312 } 7313 } 7314 7315 // Add code for jquery to use multiselect 7316 if (!empty($conf->use_javascript_ajax) && !empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT')) { 7317 $out .= "\n".'<!-- JS CODE TO ENABLE select for id '.$htmlname.', addjscombo='.$addjscombo.' -->'; 7318 $out .= "\n".'<script>'."\n"; 7319 if ($addjscombo == 1) { 7320 $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT; 7321 $out .= 'function formatResult(record) {'."\n"; 7322 if ($elemtype == 'category') { 7323 $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';'; 7324 } else { 7325 $out .= 'return record.text;'; 7326 } 7327 $out .= '};'."\n"; 7328 $out .= 'function formatSelection(record) {'."\n"; 7329 if ($elemtype == 'category') { 7330 $out .= 'return \'<span><img src="'.DOL_URL_ROOT.'/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';'; 7331 } else { 7332 $out .= 'return record.text;'; 7333 } 7334 $out .= '};'."\n"; 7335 $out .= '$(document).ready(function () { 7336 $(\'#'.$htmlname.'\').'.$tmpplugin.'({ 7337 dir: \'ltr\', 7338 // Specify format function for dropdown item 7339 formatResult: formatResult, 7340 templateResult: formatResult, /* For 4.0 */ 7341 // Specify format function for selected item 7342 formatSelection: formatSelection, 7343 templateSelection: formatSelection /* For 4.0 */ 7344 }); 7345 7346 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set 7347 the size only if component is not hidden by default on load */ 7348 $(\'#'.$htmlname.' + .select2\').addClass(\''.$morecss.'\'); 7349 });'."\n"; 7350 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) { 7351 // Add other js lib 7352 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin 7353 // ... 7354 $out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');'; 7355 $out .= '$(document).ready(function () { 7356 $(\'#'.$htmlname.'\').multiSelect({ 7357 containerHTML: \'<div class="multi-select-container">\', 7358 menuHTML: \'<div class="multi-select-menu">\', 7359 buttonHTML: \'<span class="multi-select-button '.$morecss.'">\', 7360 menuItemHTML: \'<label class="multi-select-menuitem">\', 7361 activeClass: \'multi-select-container--open\', 7362 noneText: \''.$placeholder.'\' 7363 }); 7364 })'; 7365 } 7366 $out .= '</script>'; 7367 } 7368 7369 // Try also magic suggest 7370 $out .= '<select id="'.$htmlname.'" class="multiselect'.($morecss ? ' '.$morecss : '').'" multiple name="'.$htmlname.'[]"'.($moreattrib ? ' '.$moreattrib : '').($width ? ' style="width: '.(preg_match('/%/', $width) ? $width : $width.'px').'"' : '').'>'."\n"; 7371 if (is_array($array) && !empty($array)) { 7372 if ($value_as_key) { 7373 $array = array_combine($array, $array); 7374 } 7375 7376 if (!empty($array)) { 7377 foreach ($array as $key => $value) { 7378 $newval = ($translate ? $langs->trans($value) : $value); 7379 $newval = ($key_in_label ? $key.' - '.$newval : $newval); 7380 7381 $out .= '<option value="'.$key.'"'; 7382 if (is_array($selected) && !empty($selected) && in_array((string) $key, $selected) && ((string) $key != '')) { 7383 $out .= ' selected'; 7384 } 7385 $out .= ' data-html="'.dol_escape_htmltag($newval).'"'; 7386 $out .= '>'; 7387 $out .= dol_htmlentitiesbr($newval); 7388 $out .= '</option>'."\n"; 7389 } 7390 } 7391 } 7392 $out .= '</select>'."\n"; 7393 7394 return $out; 7395 } 7396 7397 7398 /** 7399 * Show a multiselect dropbox from an array. If a saved selection of fields exists for user (into $user->conf->MAIN_SELECTEDFIELDS_contextofpage), we use this one instead of default. 7400 * 7401 * @param string $htmlname Name of HTML field 7402 * @param array $array Array with array of fields we could show. This array may be modified according to setup of user. 7403 * @param string $varpage Id of context for page. Can be set by caller with $varpage=(empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage); 7404 * @return string HTML multiselect string 7405 * @see selectarray() 7406 */ 7407 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage) 7408 { 7409 global $conf, $langs, $user, $extrafields; 7410 7411 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { 7412 return ''; 7413 } 7414 7415 $tmpvar = "MAIN_SELECTEDFIELDS_".$varpage; // To get list of saved selected fields to show 7416 7417 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user 7418 $tmparray = explode(',', $user->conf->$tmpvar); 7419 foreach ($array as $key => $val) { 7420 //var_dump($key); 7421 //var_dump($tmparray); 7422 if (in_array($key, $tmparray)) { 7423 $array[$key]['checked'] = 1; 7424 } else { 7425 $array[$key]['checked'] = 0; 7426 } 7427 } 7428 } else { // There is no list of fields already customized for user 7429 foreach ($array as $key => $val) { 7430 if ($array[$key]['checked'] < 0) { 7431 $array[$key]['checked'] = 0; 7432 } 7433 } 7434 } 7435 7436 $listoffieldsforselection = ''; 7437 $listcheckedstring = ''; 7438 7439 foreach ($array as $key => $val) { 7440 /* var_dump($val); 7441 var_dump(array_key_exists('enabled', $val)); 7442 var_dump(!$val['enabled']);*/ 7443 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) { 7444 unset($array[$key]); // We don't want this field 7445 continue; 7446 } 7447 if (!empty($val['type']) && $val['type'] == 'separate') { 7448 // Field remains in array but we don't add it into $listoffieldsforselection 7449 //$listoffieldsforselection .= '<li>-----</li>'; 7450 continue; 7451 } 7452 if ($val['label']) { 7453 if (!empty($val['langfile']) && is_object($langs)) { 7454 $langs->load($val['langfile']); 7455 } 7456 7457 // Note: $val['checked'] <> 0 means we must show the field into the combo list 7458 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox'.$key.'" value="'.$key.'"'.((empty($val['checked']) && $val['checked'] != '-1') ? '' : ' checked="checked"').'/><label for="checkbox'.$key.'">'.dol_escape_htmltag($langs->trans($val['label'])).'</label></li>'; 7459 $listcheckedstring .= (empty($val['checked']) ? '' : $key.','); 7460 } 7461 } 7462 7463 $out = '<!-- Component multiSelectArrayWithCheckbox '.$htmlname.' --> 7464 7465 <dl class="dropdown"> 7466 <dt> 7467 <a href="#'.$htmlname.'"> 7468 '.img_picto('', 'list').' 7469 </a> 7470 <input type="hidden" class="'.$htmlname.'" name="'.$htmlname.'" value="'.$listcheckedstring.'"> 7471 </dt> 7472 <dd class="dropdowndd"> 7473 <div class="multiselectcheckbox'.$htmlname.'"> 7474 <ul class="ul'.$htmlname.'"> 7475 '.$listoffieldsforselection.' 7476 </ul> 7477 </div> 7478 </dd> 7479 </dl> 7480 7481 <script type="text/javascript"> 7482 jQuery(document).ready(function () { 7483 $(\'.multiselectcheckbox'.$htmlname.' input[type="checkbox"]\').on(\'click\', function () { 7484 console.log("A new field was added/removed, we edit field input[name=formfilteraction]"); 7485 7486 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST 7487 7488 var title = $(this).val() + ","; 7489 if ($(this).is(\':checked\')) { 7490 $(\'.'.$htmlname.'\').val(title + $(\'.'.$htmlname.'\').val()); 7491 } 7492 else { 7493 $(\'.'.$htmlname.'\').val( $(\'.'.$htmlname.'\').val().replace(title, \'\') ) 7494 } 7495 // Now, we submit page 7496 //$(this).parents(\'form:first\').submit(); 7497 }); 7498 7499 7500 }); 7501 </script> 7502 7503 '; 7504 return $out; 7505 } 7506 7507 /** 7508 * Render list of categories linked to object with id $id and type $type 7509 * 7510 * @param int $id Id of object 7511 * @param string $type Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated. 7512 * @param int $rendermode 0=Default, use multiselect. 1=Emulate multiselect (recommended) 7513 * @param int $nolink 1=Do not add html links 7514 * @return string String with categories 7515 */ 7516 public function showCategories($id, $type, $rendermode = 0, $nolink = 0) 7517 { 7518 global $db; 7519 7520 include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; 7521 7522 $cat = new Categorie($db); 7523 $categories = $cat->containing($id, $type); 7524 7525 if ($rendermode == 1) { 7526 $toprint = array(); 7527 foreach ($categories as $c) { 7528 $ways = $c->print_all_ways(' >> ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formated text 7529 foreach ($ways as $way) { 7530 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"'.($c->color ? ' style="background: #'.$c->color.';"' : ' style="background: #bbb"').'>'.$way.'</li>'; 7531 } 7532 } 7533 return '<div class="select2-container-multi-dolibarr" style="width: 90%;"><ul class="select2-choices-dolibarr">'.implode(' ', $toprint).'</ul></div>'; 7534 } 7535 7536 if ($rendermode == 0) { 7537 $arrayselected = array(); 7538 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 1); 7539 foreach ($categories as $c) { 7540 $arrayselected[] = $c->id; 7541 } 7542 7543 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%', 'disabled', 'category'); 7544 } 7545 7546 return 'ErrorBadValueForParameterRenderMode'; // Should not happened 7547 } 7548 7549 /** 7550 * Show linked object block. 7551 * 7552 * @param CommonObject $object Object we want to show links to 7553 * @param string $morehtmlright More html to show on right of title 7554 * @param array $compatibleImportElementsList Array of compatibles elements object for "import from" action 7555 * @return int <0 if KO, >=0 if OK 7556 */ 7557 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = false) 7558 { 7559 global $conf, $langs, $hookmanager; 7560 global $bc, $action; 7561 7562 $object->fetchObjectLinked(); 7563 7564 // Bypass the default method 7565 $hookmanager->initHooks(array('commonobject')); 7566 $parameters = array( 7567 'morehtmlright' => $morehtmlright, 7568 'compatibleImportElementsList' => &$compatibleImportElementsList, 7569 ); 7570 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook 7571 7572 if (empty($reshook)) { 7573 $nbofdifferenttypes = count($object->linkedObjects); 7574 7575 print '<!-- showLinkedObjectBlock -->'; 7576 print load_fiche_titre($langs->trans('RelatedObjects'), $morehtmlright, '', 0, 0, 'showlinkedobjectblock'); 7577 7578 7579 print '<div class="div-table-responsive-no-min">'; 7580 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="'.$object->element.'" data-elementid="'.$object->id.'" >'; 7581 7582 print '<tr class="liste_titre">'; 7583 print '<td>'.$langs->trans("Type").'</td>'; 7584 print '<td>'.$langs->trans("Ref").'</td>'; 7585 print '<td class="center"></td>'; 7586 print '<td class="center">'.$langs->trans("Date").'</td>'; 7587 print '<td class="right">'.$langs->trans("AmountHTShort").'</td>'; 7588 print '<td class="right">'.$langs->trans("Status").'</td>'; 7589 print '<td></td>'; 7590 print '</tr>'; 7591 7592 $nboftypesoutput = 0; 7593 7594 foreach ($object->linkedObjects as $objecttype => $objects) { 7595 $tplpath = $element = $subelement = $objecttype; 7596 7597 // to display inport button on tpl 7598 $showImportButton = false; 7599 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) { 7600 $showImportButton = true; 7601 } 7602 7603 $regs = array(); 7604 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) { 7605 $element = $regs[1]; 7606 $subelement = $regs[2]; 7607 $tplpath = $element.'/'.$subelement; 7608 } 7609 $tplname = 'linkedobjectblock'; 7610 7611 // To work with non standard path 7612 if ($objecttype == 'facture') { 7613 $tplpath = 'compta/'.$element; 7614 if (empty($conf->facture->enabled)) { 7615 continue; // Do not show if module disabled 7616 } 7617 } elseif ($objecttype == 'facturerec') { 7618 $tplpath = 'compta/facture'; 7619 $tplname = 'linkedobjectblockForRec'; 7620 if (empty($conf->facture->enabled)) { 7621 continue; // Do not show if module disabled 7622 } 7623 } elseif ($objecttype == 'propal') { 7624 $tplpath = 'comm/'.$element; 7625 if (empty($conf->propal->enabled)) { 7626 continue; // Do not show if module disabled 7627 } 7628 } elseif ($objecttype == 'supplier_proposal') { 7629 if (empty($conf->supplier_proposal->enabled)) { 7630 continue; // Do not show if module disabled 7631 } 7632 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment') { 7633 $tplpath = 'expedition'; 7634 if (empty($conf->expedition->enabled)) { 7635 continue; // Do not show if module disabled 7636 } 7637 } elseif ($objecttype == 'reception') { 7638 $tplpath = 'reception'; 7639 if (empty($conf->reception->enabled)) { 7640 continue; // Do not show if module disabled 7641 } 7642 } elseif ($objecttype == 'delivery') { 7643 $tplpath = 'delivery'; 7644 if (empty($conf->expedition->enabled)) { 7645 continue; // Do not show if module disabled 7646 } 7647 } elseif ($objecttype == 'invoice_supplier') { 7648 $tplpath = 'fourn/facture'; 7649 } elseif ($objecttype == 'order_supplier') { 7650 $tplpath = 'fourn/commande'; 7651 } elseif ($objecttype == 'expensereport') { 7652 $tplpath = 'expensereport'; 7653 } elseif ($objecttype == 'subscription') { 7654 $tplpath = 'adherents'; 7655 } elseif ($objecttype == 'conferenceorbooth') { 7656 $tplpath = 'eventorganization'; 7657 } elseif ($objecttype == 'conferenceorboothattendee') { 7658 $tplpath = 'eventorganization'; 7659 } 7660 7661 global $linkedObjectBlock; 7662 $linkedObjectBlock = $objects; 7663 7664 7665 // Output template part (modules that overwrite templates must declare this into descriptor) 7666 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/'.$tplpath.'/tpl')); 7667 foreach ($dirtpls as $reldir) { 7668 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after 7669 global $noMoreLinkedObjectBlockAfter; 7670 $noMoreLinkedObjectBlockAfter = 1; 7671 } 7672 7673 $res = @include dol_buildpath($reldir.'/'.$tplname.'.tpl.php'); 7674 if ($res) { 7675 $nboftypesoutput++; 7676 break; 7677 } 7678 } 7679 } 7680 7681 if (!$nboftypesoutput) { 7682 print '<tr><td class="impair opacitymedium" colspan="7">'.$langs->trans("None").'</td></tr>'; 7683 } 7684 7685 print '</table>'; 7686 7687 if (!empty($compatibleImportElementsList)) { 7688 $res = @include dol_buildpath('core/tpl/ajax/objectlinked_lineimport.tpl.php'); 7689 } 7690 7691 7692 print '</div>'; 7693 7694 return $nbofdifferenttypes; 7695 } 7696 } 7697 7698 /** 7699 * Show block with links to link to other objects. 7700 * 7701 * @param CommonObject $object Object we want to show links to 7702 * @param array $restrictlinksto Restrict links to some elements, for exemple array('order') or array('supplier_order'). null or array() if no restriction. 7703 * @param array $excludelinksto Do not show links of this type, for exemple array('order') or array('supplier_order'). null or array() if no exclusion. 7704 * @return string <0 if KO, >0 if OK 7705 */ 7706 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array()) 7707 { 7708 global $conf, $langs, $hookmanager; 7709 global $bc, $action; 7710 7711 $linktoelem = ''; 7712 $linktoelemlist = ''; 7713 $listofidcompanytoscan = ''; 7714 7715 if (!is_object($object->thirdparty)) { 7716 $object->fetch_thirdparty(); 7717 } 7718 7719 $possiblelinks = array(); 7720 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) { 7721 $listofidcompanytoscan = $object->thirdparty->id; 7722 if (($object->thirdparty->parent > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PARENT_IN_LINKTO)) { 7723 $listofidcompanytoscan .= ','.$object->thirdparty->parent; 7724 } 7725 if (($object->fk_project > 0) && !empty($conf->global->THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO)) { 7726 include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; 7727 $tmpproject = new Project($this->db); 7728 $tmpproject->fetch($object->fk_project); 7729 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) { 7730 $listofidcompanytoscan .= ','.$tmpproject->socid; 7731 } 7732 unset($tmpproject); 7733 } 7734 7735 $possiblelinks = array( 7736 'propal'=>array('enabled'=>$conf->propal->enabled, 'perms'=>1, 'label'=>'LinkToProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('propal').')'), 7737 'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande').')'), 7738 'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('invoice').')'), 7739 'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('invoice').')'), 7740 'contrat'=>array( 7741 'enabled'=>$conf->contrat->enabled, 7742 'perms'=>1, 7743 'label'=>'LinkToContract', 7744 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, SUM(td.total_ht) as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t, ".MAIN_DB_PREFIX."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('contract').') GROUP BY s.rowid, s.nom, s.client, t.rowid, t.ref, t.ref_customer, t.ref_supplier' 7745 ), 7746 'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('intervention').')'), 7747 'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled, 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('supplier_proposal').')'), 7748 'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled, 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('commande_fournisseur').')'), 7749 'invoice_supplier'=>array('enabled'=>$conf->supplier_invoice->enabled, 'perms'=>1, 'label'=>'LinkToSupplierInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_fourn as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('facture_fourn').')'), 7750 'ticket'=>array('enabled'=>$conf->ticket->enabled, 'perms'=>1, 'label'=>'LinkToTicket', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."ticket as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$this->db->sanitize($listofidcompanytoscan).') AND t.entity IN ('.getEntity('ticket').')') 7751 ); 7752 } 7753 7754 // Can complete the possiblelink array 7755 $hookmanager->initHooks(array('commonobject')); 7756 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan); 7757 7758 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to 7759 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook 7760 } 7761 7762 if (empty($reshook)) { 7763 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) { 7764 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray); 7765 } 7766 } elseif ($reshook > 0) { 7767 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) { 7768 $possiblelinks = $hookmanager->resArray; 7769 } 7770 } 7771 7772 foreach ($possiblelinks as $key => $possiblelink) { 7773 $num = 0; 7774 7775 if (empty($possiblelink['enabled'])) { 7776 continue; 7777 } 7778 7779 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) { 7780 print '<div id="'.$key.'list"'.(empty($conf->use_javascript_ajax) ? '' : ' style="display:none"').'>'; 7781 $sql = $possiblelink['sql']; 7782 7783 $resqllist = $this->db->query($sql); 7784 if ($resqllist) { 7785 $num = $this->db->num_rows($resqllist); 7786 $i = 0; 7787 7788 print '<br>'; 7789 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formlinked'.$key.'">'; 7790 print '<input type="hidden" name="action" value="addlink">'; 7791 print '<input type="hidden" name="token" value="'.newToken().'">'; 7792 print '<input type="hidden" name="id" value="'.$object->id.'">'; 7793 print '<input type="hidden" name="addlink" value="'.$key.'">'; 7794 print '<table class="noborder">'; 7795 print '<tr class="liste_titre">'; 7796 print '<td class="nowrap"></td>'; 7797 print '<td class="center">'.$langs->trans("Ref").'</td>'; 7798 print '<td class="left">'.$langs->trans("RefCustomer").'</td>'; 7799 print '<td class="right">'.$langs->trans("AmountHTShort").'</td>'; 7800 print '<td class="left">'.$langs->trans("Company").'</td>'; 7801 print '</tr>'; 7802 while ($i < $num) { 7803 $objp = $this->db->fetch_object($resqllist); 7804 7805 print '<tr class="oddeven">'; 7806 print '<td class="left">'; 7807 print '<input type="radio" name="idtolinkto" id="'.$key.'_'.$objp->rowid.'" value="'.$objp->rowid.'">'; 7808 print '</td>'; 7809 print '<td class="center"><label for="'.$key.'_'.$objp->rowid.'">'.$objp->ref.'</label></td>'; 7810 print '<td>'.(!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')).'</td>'; 7811 print '<td class="right">'; 7812 if ($possiblelink['label'] == 'LinkToContract') { 7813 $form = new Form($this->db); 7814 print $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")).' '; 7815 } 7816 print '<span class="amount">'.price($objp->total_ht).'</span>'; 7817 print '</td>'; 7818 print '<td>'.$objp->name.'</td>'; 7819 print '</tr>'; 7820 $i++; 7821 } 7822 print '</table>'; 7823 print '<div class="center">'; 7824 print '<input type="submit" class="button valignmiddle marginleftonly marginrightonly" value="'.$langs->trans('ToLink').'">'; 7825 if (empty($conf->use_javascript_ajax)) { 7826 print '<input type="submit" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>'; 7827 } else { 7828 print '<input type="submit"; onclick="javascript:jQuery(\'#'.$key.'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly" name="cancel" value="'.$langs->trans("Cancel").'"></div>'; 7829 } 7830 print '</form>'; 7831 $this->db->free($resqllist); 7832 } else { 7833 dol_print_error($this->db); 7834 } 7835 print '</div>'; 7836 7837 //$linktoelem.=($linktoelem?' ':''); 7838 if ($num > 0) { 7839 $linktoelemlist .= '<li><a href="#linkto'.$key.'" class="linkto dropdowncloseonclick" rel="'.$key.'">'.$langs->trans($possiblelink['label']).' ('.$num.')</a></li>'; 7840 // } else $linktoelem.=$langs->trans($possiblelink['label']); 7841 } else { 7842 $linktoelemlist .= '<li><span class="linktodisabled">'.$langs->trans($possiblelink['label']).' (0)</span></li>'; 7843 } 7844 } 7845 } 7846 7847 if ($linktoelemlist) { 7848 $linktoelem = ' 7849 <dl class="dropdown" id="linktoobjectname"> 7850 '; 7851 if (!empty($conf->use_javascript_ajax)) { 7852 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>'.$langs->trans("LinkTo").'...</a></dt>'; 7853 } 7854 $linktoelem .= '<dd> 7855 <div class="multiselectlinkto"> 7856 <ul class="ulselectedfields">'.$linktoelemlist.' 7857 </ul> 7858 </div> 7859 </dd> 7860 </dl>'; 7861 } else { 7862 $linktoelem = ''; 7863 } 7864 7865 if (!empty($conf->use_javascript_ajax)) { 7866 print '<!-- Add js to show linkto box --> 7867 <script> 7868 jQuery(document).ready(function() { 7869 jQuery(".linkto").click(function() { 7870 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list"); 7871 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle(); 7872 }); 7873 }); 7874 </script> 7875 '; 7876 } 7877 7878 return $linktoelem; 7879 } 7880 7881 /** 7882 * Return an html string with a select combo box to choose yes or no 7883 * 7884 * @param string $htmlname Name of html select field 7885 * @param string $value Pre-selected value 7886 * @param int $option 0 return yes/no, 1 return 1/0 7887 * @param bool $disabled true or false 7888 * @param int $useempty 1=Add empty line 7889 * @param int $addjscombo 1=Add js beautifier on combo box 7890 * @param string $morecss More CSS 7891 * @return string See option 7892 */ 7893 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = '') 7894 { 7895 global $langs; 7896 7897 $yes = "yes"; 7898 $no = "no"; 7899 if ($option) { 7900 $yes = "1"; 7901 $no = "0"; 7902 } 7903 7904 $disabled = ($disabled ? ' disabled' : ''); 7905 7906 $resultyesno = '<select class="flat width75'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.'"'.$disabled.'>'."\n"; 7907 if ($useempty) { 7908 $resultyesno .= '<option value="-1"'.(($value < 0) ? ' selected' : '').'> </option>'."\n"; 7909 } 7910 if (("$value" == 'yes') || ($value == 1)) { 7911 $resultyesno .= '<option value="'.$yes.'" selected>'.$langs->trans("Yes").'</option>'."\n"; 7912 $resultyesno .= '<option value="'.$no.'">'.$langs->trans("No").'</option>'."\n"; 7913 } else { 7914 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected'); 7915 $resultyesno .= '<option value="'.$yes.'">'.$langs->trans("Yes").'</option>'."\n"; 7916 $resultyesno .= '<option value="'.$no.'"'.$selected.'>'.$langs->trans("No").'</option>'."\n"; 7917 } 7918 $resultyesno .= '</select>'."\n"; 7919 7920 if ($addjscombo) { 7921 $resultyesno .= ajax_combobox($htmlname); 7922 } 7923 7924 return $resultyesno; 7925 } 7926 7927 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 7928 /** 7929 * Return list of export templates 7930 * 7931 * @param string $selected Id modele pre-selectionne 7932 * @param string $htmlname Name of HTML select 7933 * @param string $type Type of searched templates 7934 * @param int $useempty Affiche valeur vide dans liste 7935 * @return void 7936 */ 7937 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0) 7938 { 7939 // phpcs:enable 7940 $sql = "SELECT rowid, label"; 7941 $sql .= " FROM ".MAIN_DB_PREFIX."export_model"; 7942 $sql .= " WHERE type = '".$this->db->escape($type)."'"; 7943 $sql .= " ORDER BY rowid"; 7944 $result = $this->db->query($sql); 7945 if ($result) { 7946 print '<select class="flat" id="select_'.$htmlname.'" name="'.$htmlname.'">'; 7947 if ($useempty) { 7948 print '<option value="-1"> </option>'; 7949 } 7950 7951 $num = $this->db->num_rows($result); 7952 $i = 0; 7953 while ($i < $num) { 7954 $obj = $this->db->fetch_object($result); 7955 if ($selected == $obj->rowid) { 7956 print '<option value="'.$obj->rowid.'" selected>'; 7957 } else { 7958 print '<option value="'.$obj->rowid.'">'; 7959 } 7960 print $obj->label; 7961 print '</option>'; 7962 $i++; 7963 } 7964 print "</select>"; 7965 } else { 7966 dol_print_error($this->db); 7967 } 7968 } 7969 7970 /** 7971 * Return a HTML area with the reference of object and a navigation bar for a business object 7972 * Note: To complete search with a particular filter on select, you can set $object->next_prev_filter set to define SQL criterias. 7973 * 7974 * @param object $object Object to show. 7975 * @param string $paramid Name of parameter to use to name the id into the URL next/previous link. 7976 * @param string $morehtml More html content to output just before the nav bar. 7977 * @param int $shownav Show Condition (navigation is shown if value is 1). 7978 * @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. 7979 * @param string $fieldref Name of field ref of object (object->ref) to show or 'none' to not show ref. 7980 * @param string $morehtmlref More html to show after ref. 7981 * @param string $moreparam More param to add in nav link url. Must start with '&...'. 7982 * @param int $nodbprefix Do not include DB prefix to forge table name. 7983 * @param string $morehtmlleft More html code to show before ref. 7984 * @param string $morehtmlstatus More html code to show under navigation arrows (status place). 7985 * @param string $morehtmlright More html code to show after ref. 7986 * @return string Portion HTML with ref + navigation buttons 7987 */ 7988 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '') 7989 { 7990 global $langs, $conf, $hookmanager, $extralanguages; 7991 7992 $ret = ''; 7993 if (empty($fieldid)) { 7994 $fieldid = 'rowid'; 7995 } 7996 if (empty($fieldref)) { 7997 $fieldref = 'ref'; 7998 } 7999 8000 // Preparing gender's display if there is one 8001 $addgendertxt = ''; 8002 if (!empty($object->gender)) { 8003 $addgendertxt = ' '; 8004 switch ($object->gender) { 8005 case 'man': 8006 $addgendertxt .= '<i class="fas fa-mars"></i>'; 8007 break; 8008 case 'woman': 8009 $addgendertxt .= '<i class="fas fa-venus"></i>'; 8010 break; 8011 case 'other': 8012 $addgendertxt .= '<i class="fas fa-genderless"></i>'; 8013 break; 8014 } 8015 } 8016 8017 // Add where from hooks 8018 if (is_object($hookmanager)) { 8019 $parameters = array(); 8020 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook 8021 $object->next_prev_filter .= $hookmanager->resPrint; 8022 } 8023 $previous_ref = $next_ref = ''; 8024 if ($shownav) { 8025 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam"; 8026 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix); 8027 8028 $navurl = $_SERVER["PHP_SELF"]; 8029 // Special case for project/task page 8030 if ($paramid == 'project_ref') { 8031 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok 8032 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl); 8033 $paramid = 'ref'; 8034 } 8035 } 8036 8037 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox 8038 // accesskey is for Mac: CTRL + key for all browsers 8039 $stringforfirstkey = $langs->trans("KeyboardShortcut"); 8040 if ($conf->browser->name == 'chrome') { 8041 $stringforfirstkey .= ' ALT +'; 8042 } elseif ($conf->browser->name == 'firefox') { 8043 $stringforfirstkey .= ' ALT + SHIFT +'; 8044 } else { 8045 $stringforfirstkey .= ' CTL +'; 8046 } 8047 8048 $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>'; 8049 $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>'; 8050 } 8051 8052 //print "xx".$previous_ref."x".$next_ref; 8053 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">'; 8054 8055 // Right part of banner 8056 if ($morehtmlright) { 8057 $ret .= '<div class="inline-block floatleft">'.$morehtmlright.'</div>'; 8058 } 8059 8060 if ($previous_ref || $next_ref || $morehtml) { 8061 $ret .= '<div class="pagination paginationref"><ul class="right">'; 8062 } 8063 if ($morehtml) { 8064 $ret .= '<li class="noborder litext'.(($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '').'">'.$morehtml.'</li>'; 8065 } 8066 if ($shownav && ($previous_ref || $next_ref)) { 8067 $ret .= '<li class="pagination">'.$previous_ref.'</li>'; 8068 $ret .= '<li class="pagination">'.$next_ref.'</li>'; 8069 } 8070 if ($previous_ref || $next_ref || $morehtml) { 8071 $ret .= '</ul></div>'; 8072 } 8073 8074 $parameters = array(); 8075 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook 8076 if (empty($reshook)) { 8077 $morehtmlstatus .= $hookmanager->resPrint; 8078 } else { 8079 $morehtmlstatus = $hookmanager->resPrint; 8080 } 8081 if ($morehtmlstatus) { 8082 $ret .= '<div class="statusref">'.$morehtmlstatus.'</div>'; 8083 } 8084 8085 $parameters = array(); 8086 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook 8087 if (empty($reshook)) { 8088 $morehtmlref .= $hookmanager->resPrint; 8089 } elseif ($reshook > 0) { 8090 $morehtmlref = $hookmanager->resPrint; 8091 } 8092 8093 // Left part of banner 8094 if ($morehtmlleft) { 8095 if ($conf->browser->layout == 'phone') { 8096 $ret .= '<!-- morehtmlleft --><div class="floatleft">'.$morehtmlleft.'</div>'; // class="center" to have photo in middle 8097 } else { 8098 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">'.$morehtmlleft.'</div>'; 8099 } 8100 } 8101 8102 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>'; 8103 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">'; 8104 8105 // For thirdparty, contact, user, member, the ref is the id, so we show something else 8106 if ($object->element == 'societe') { 8107 $ret .= dol_htmlentities($object->name); 8108 8109 // List of extra languages 8110 $arrayoflangcode = array(); 8111 if (!empty($conf->global->PDF_USE_ALSO_LANGUAGE_CODE)) { 8112 $arrayoflangcode[] = $conf->global->PDF_USE_ALSO_LANGUAGE_CODE; 8113 } 8114 8115 if (is_array($arrayoflangcode) && count($arrayoflangcode)) { 8116 if (!is_object($extralanguages)) { 8117 include_once DOL_DOCUMENT_ROOT.'/core/class/extralanguages.class.php'; 8118 $extralanguages = new ExtraLanguages($this->db); 8119 } 8120 $extralanguages->fetch_name_extralanguages('societe'); 8121 8122 if (!empty($extralanguages->attributes['societe']['name'])) { 8123 $object->fetchValuesForExtraLanguages(); 8124 8125 $htmltext = ''; 8126 // If there is extra languages 8127 foreach ($arrayoflangcode as $extralangcode) { 8128 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"'); 8129 if ($object->array_languages['name'][$extralangcode]) { 8130 $htmltext .= $object->array_languages['name'][$extralangcode]; 8131 } else { 8132 $htmltext .= '<span class="opacitymedium">'.$langs->trans("SwitchInEditModeToAddTranslation").'</span>'; 8133 } 8134 } 8135 $ret .= '<!-- Show translations of name -->'."\n"; 8136 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft'); 8137 } 8138 } 8139 } elseif ($object->element == 'member') { 8140 $ret .= $object->ref.'<br>'; 8141 $fullname = $object->getFullName($langs); 8142 if ($object->morphy == 'mor' && $object->societe) { 8143 $ret .= dol_htmlentities($object->societe).((!empty($fullname) && $object->societe != $fullname) ? ' ('.dol_htmlentities($fullname).$addgendertxt.')' : ''); 8144 } else { 8145 $ret .= dol_htmlentities($fullname).$addgendertxt.((!empty($object->societe) && $object->societe != $fullname) ? ' ('.dol_htmlentities($object->societe).')' : ''); 8146 } 8147 } elseif (in_array($object->element, array('contact', 'user', 'usergroup'))) { 8148 $ret .= dol_htmlentities($object->getFullName($langs)).$addgendertxt; 8149 } elseif (in_array($object->element, array('action', 'agenda'))) { 8150 $ret .= $object->ref.'<br>'.$object->label; 8151 } elseif (in_array($object->element, array('adherent_type'))) { 8152 $ret .= $object->label; 8153 } elseif ($object->element == 'ecm_directories') { 8154 $ret .= ''; 8155 } elseif ($fieldref != 'none') { 8156 $ret .= dol_htmlentities($object->$fieldref); 8157 } 8158 8159 if ($morehtmlref) { 8160 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag 8161 if (substr($morehtmlref, 0, 4) != '<div') { 8162 $ret .= ' '; 8163 } 8164 8165 $ret .= $morehtmlref; 8166 } 8167 8168 $ret .= '</div>'; 8169 8170 $ret .= '</div><!-- End banner content -->'; 8171 8172 return $ret; 8173 } 8174 8175 8176 /** 8177 * Return HTML code to output a barcode 8178 * 8179 * @param Object $object Object containing data to retrieve file name 8180 * @param int $width Width of photo 8181 * @param string $morecss More CSS on img of barcode 8182 * @return string HTML code to output barcode 8183 */ 8184 public function showbarcode(&$object, $width = 100, $morecss = '') 8185 { 8186 global $conf; 8187 8188 //Check if barcode is filled in the card 8189 if (empty($object->barcode)) { 8190 return ''; 8191 } 8192 8193 // Complete object if not complete 8194 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) { 8195 $result = $object->fetch_barcode(); 8196 //Check if fetch_barcode() failed 8197 if ($result < 1) { 8198 return '<!-- ErrorFetchBarcode -->'; 8199 } 8200 } 8201 8202 // Barcode image 8203 $url = DOL_URL_ROOT.'/viewimage.php?modulepart=barcode&generator='.urlencode($object->barcode_type_coder).'&code='.urlencode($object->barcode).'&encoding='.urlencode($object->barcode_type_code); 8204 $out = '<!-- url barcode = '.$url.' -->'; 8205 $out .= '<img src="'.$url.'"'.($morecss ? ' class="'.$morecss.'"' : '').'>'; 8206 return $out; 8207 } 8208 8209 /** 8210 * Return HTML code to output a photo 8211 * 8212 * @param string $modulepart Key to define module concerned ('societe', 'userphoto', 'memberphoto') 8213 * @param object $object Object containing data to retrieve file name 8214 * @param int $width Width of photo 8215 * @param int $height Height of photo (auto if 0) 8216 * @param int $caneditfield Add edit fields 8217 * @param string $cssclass CSS name to use on img for photo 8218 * @param string $imagesize 'mini', 'small' or '' (original) 8219 * @param int $addlinktofullsize Add link to fullsize image 8220 * @param int $cache 1=Accept to use image in cache 8221 * @param string $forcecapture '', 'user' or 'environment'. Force parameter capture on HTML input file element to ask a smartphone to allow to open camera to take photo. Auto if ''. 8222 * @param int $noexternsourceoverwrite No overwrite image with extern source (like 'gravatar' or other module) 8223 * @return string HTML code to output photo 8224 */ 8225 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0) 8226 { 8227 global $conf, $langs; 8228 8229 $entity = (!empty($object->entity) ? $object->entity : $conf->entity); 8230 $id = (!empty($object->id) ? $object->id : $object->rowid); 8231 8232 $ret = ''; 8233 $dir = ''; 8234 $file = ''; 8235 $originalfile = ''; 8236 $altfile = ''; 8237 $email = ''; 8238 $capture = ''; 8239 if ($modulepart == 'societe') { 8240 $dir = $conf->societe->multidir_output[$entity]; 8241 if (!empty($object->logo)) { 8242 if (dolIsAllowedForPreview($object->logo)) { 8243 if ((string) $imagesize == 'mini') { 8244 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs 8245 } elseif ((string) $imagesize == 'small') { 8246 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.getImageFileNameForSize($object->logo, '_small'); 8247 } else { 8248 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo; 8249 } 8250 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty').'logos/'.$object->logo; 8251 } 8252 } 8253 $email = $object->email; 8254 } elseif ($modulepart == 'contact') { 8255 $dir = $conf->societe->multidir_output[$entity].'/contact'; 8256 if (!empty($object->photo)) { 8257 if (dolIsAllowedForPreview($object->photo)) { 8258 if ((string) $imagesize == 'mini') { 8259 $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_mini'); 8260 } elseif ((string) $imagesize == 'small') { 8261 $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.getImageFileNameForSize($object->photo, '_small'); 8262 } else { 8263 $file = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo; 8264 } 8265 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact').'photos/'.$object->photo; 8266 } 8267 } 8268 $email = $object->email; 8269 $capture = 'user'; 8270 } elseif ($modulepart == 'userphoto') { 8271 $dir = $conf->user->dir_output; 8272 if (!empty($object->photo)) { 8273 if (dolIsAllowedForPreview($object->photo)) { 8274 if ((string) $imagesize == 'mini') { 8275 $file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_mini'); 8276 } elseif ((string) $imagesize == 'small') { 8277 $file = get_exdir(0, 0, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_small'); 8278 } else { 8279 $file = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo; 8280 } 8281 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user').$object->photo; 8282 } 8283 } 8284 if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) { 8285 $altfile = $object->id.".jpg"; // For backward compatibility 8286 } 8287 $email = $object->email; 8288 $capture = 'user'; 8289 } elseif ($modulepart == 'memberphoto') { 8290 $dir = $conf->adherent->dir_output; 8291 if (!empty($object->photo)) { 8292 if (dolIsAllowedForPreview($object->photo)) { 8293 if ((string) $imagesize == 'mini') { 8294 $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_mini'); 8295 } elseif ((string) $imagesize == 'small') { 8296 $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.getImageFileNameForSize($object->photo, '_small'); 8297 } else { 8298 $file = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo; 8299 } 8300 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member').'photos/'.$object->photo; 8301 } 8302 } 8303 if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) { 8304 $altfile = $object->id.".jpg"; // For backward compatibility 8305 } 8306 $email = $object->email; 8307 $capture = 'user'; 8308 } else { 8309 // Generic case to show photos 8310 $dir = $conf->$modulepart->dir_output; 8311 if (!empty($object->photo)) { 8312 if (dolIsAllowedForPreview($object->photo)) { 8313 if ((string) $imagesize == 'mini') { 8314 $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_mini'); 8315 } elseif ((string) $imagesize == 'small') { 8316 $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.getImageFileNameForSize($object->photo, '_small'); 8317 } else { 8318 $file = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo; 8319 } 8320 $originalfile = get_exdir($id, 2, 0, 0, $object, $modulepart).'photos/'.$object->photo; 8321 } 8322 } 8323 if (!empty($conf->global->MAIN_OLD_IMAGE_LINKS)) { 8324 $altfile = $object->id.".jpg"; // For backward compatibility 8325 } 8326 $email = $object->email; 8327 } 8328 8329 if ($forcecapture) { 8330 $capture = $forcecapture; 8331 } 8332 8333 if ($dir) { 8334 if ($file && file_exists($dir."/".$file)) { 8335 if ($addlinktofullsize) { 8336 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity); 8337 if ($urladvanced) { 8338 $ret .= '<a href="'.$urladvanced.'">'; 8339 } else { 8340 $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">'; 8341 } 8342 } 8343 $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.'">'; 8344 if ($addlinktofullsize) { 8345 $ret .= '</a>'; 8346 } 8347 } elseif ($altfile && file_exists($dir."/".$altfile)) { 8348 if ($addlinktofullsize) { 8349 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity='.$entity); 8350 if ($urladvanced) { 8351 $ret .= '<a href="'.$urladvanced.'">'; 8352 } else { 8353 $ret .= '<a href="'.DOL_URL_ROOT.'/viewimage.php?modulepart='.$modulepart.'&entity='.$entity.'&file='.urlencode($originalfile).'&cache='.$cache.'">'; 8354 } 8355 } 8356 $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.'">'; 8357 if ($addlinktofullsize) { 8358 $ret .= '</a>'; 8359 } 8360 } else { 8361 $nophoto = '/public/theme/common/nophoto.png'; 8362 $defaultimg = 'identicon'; // For gravatar 8363 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found 8364 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && strpos($object->morphy, 'mor')) !== false) { 8365 $nophoto = 'company'; 8366 } else { 8367 $nophoto = '/public/theme/common/user_anonymous.png'; 8368 if (!empty($object->gender) && $object->gender == 'man') { 8369 $nophoto = '/public/theme/common/user_man.png'; 8370 } 8371 if (!empty($object->gender) && $object->gender == 'woman') { 8372 $nophoto = '/public/theme/common/user_woman.png'; 8373 } 8374 } 8375 } 8376 8377 if (!empty($conf->gravatar->enabled) && $email && empty($noexternsourceoverwrite)) { 8378 // see https://gravatar.com/site/implement/images/php/ 8379 $ret .= '<!-- Put link to gravatar -->'; 8380 $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 8381 } else { 8382 if ($nophoto == 'company') { 8383 $ret .= '<div class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').'">'.img_picto('', 'company').'</div>'; 8384 } else { 8385 $ret .= '<img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo" '.($width ? ' width="'.$width.'"' : '').($height ? ' height="'.$height.'"' : '').' src="'.DOL_URL_ROOT.$nophoto.'">'; 8386 } 8387 } 8388 } 8389 8390 if ($caneditfield) { 8391 if ($object->photo) { 8392 $ret .= "<br>\n"; 8393 } 8394 $ret .= '<table class="nobordernopadding centpercent">'; 8395 if ($object->photo) { 8396 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> '.$langs->trans("Delete").'<br><br></td></tr>'; 8397 } 8398 $ret .= '<tr><td class="tdoverflow"><input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"'.($capture ? ' capture="'.$capture.'"' : '').'></td></tr>'; 8399 $ret .= '</table>'; 8400 } 8401 } else { 8402 dol_print_error('', 'Call of showphoto with wrong parameters modulepart='.$modulepart); 8403 } 8404 8405 return $ret; 8406 } 8407 8408 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps 8409 /** 8410 * Return select list of groups 8411 * 8412 * @param string $selected Id group preselected 8413 * @param string $htmlname Field name in form 8414 * @param int $show_empty 0=liste sans valeur nulle, 1=ajoute valeur inconnue 8415 * @param string $exclude Array list of groups id to exclude 8416 * @param int $disabled If select list must be disabled 8417 * @param string $include Array list of groups id to include 8418 * @param int $enableonly Array list of groups id to be enabled. All other must be disabled 8419 * @param string $force_entity '0' or Ids of environment to force 8420 * @param bool $multiple add [] in the name of element and add 'multiple' attribut (not working with ajax_autocompleter) 8421 * @param string $morecss More css to add to html component 8422 * @return string 8423 * @see select_dolusers() 8424 */ 8425 public function select_dolgroups($selected = '', $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = '', $force_entity = '0', $multiple = false, $morecss = '') 8426 { 8427 // phpcs:enable 8428 global $conf, $user, $langs; 8429 8430 // Permettre l'exclusion de groupes 8431 if (is_array($exclude)) { 8432 $excludeGroups = implode(",", $exclude); 8433 } 8434 // Permettre l'inclusion de groupes 8435 if (is_array($include)) { 8436 $includeGroups = implode(",", $include); 8437 } 8438 8439 if (!is_array($selected)) { 8440 $selected = array($selected); 8441 } 8442 8443 $out = ''; 8444 8445 // On recherche les groupes 8446 $sql = "SELECT ug.rowid, ug.nom as name"; 8447 if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) { 8448 $sql .= ", e.label"; 8449 } 8450 $sql .= " FROM ".MAIN_DB_PREFIX."usergroup as ug "; 8451 if (!empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) { 8452 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entity as e ON e.rowid=ug.entity"; 8453 if ($force_entity) { 8454 $sql .= " WHERE ug.entity IN (0, ".$force_entity.")"; 8455 } else { 8456 $sql .= " WHERE ug.entity IS NOT NULL"; 8457 } 8458 } else { 8459 $sql .= " WHERE ug.entity IN (0, ".$conf->entity.")"; 8460 } 8461 if (is_array($exclude) && $excludeGroups) { 8462 $sql .= " AND ug.rowid NOT IN (".$this->db->sanitize($excludeGroups).")"; 8463 } 8464 if (is_array($include) && $includeGroups) { 8465 $sql .= " AND ug.rowid IN (".$this->db->sanitize($includeGroups).")"; 8466 } 8467 $sql .= " ORDER BY ug.nom ASC"; 8468 8469 dol_syslog(get_class($this)."::select_dolgroups", LOG_DEBUG); 8470 $resql = $this->db->query($sql); 8471 if ($resql) { 8472 // Enhance with select2 8473 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 8474 $out .= ajax_combobox($htmlname); 8475 8476 $out .= '<select class="flat minwidth200'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiple ? '[]' : '').'" '.($multiple ? 'multiple' : '').' '.($disabled ? ' disabled' : '').'>'; 8477 8478 $num = $this->db->num_rows($resql); 8479 $i = 0; 8480 if ($num) { 8481 if ($show_empty && !$multiple) { 8482 $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'> </option>'."\n"; 8483 } 8484 8485 while ($i < $num) { 8486 $obj = $this->db->fetch_object($resql); 8487 $disableline = 0; 8488 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) { 8489 $disableline = 1; 8490 } 8491 8492 $out .= '<option value="'.$obj->rowid.'"'; 8493 if ($disableline) { 8494 $out .= ' disabled'; 8495 } 8496 if ((is_object($selected[0]) && $selected[0]->id == $obj->rowid) || (!is_object($selected[0]) && in_array($obj->rowid, $selected))) { 8497 $out .= ' selected'; 8498 } 8499 $out .= '>'; 8500 8501 $out .= $obj->name; 8502 if (!empty($conf->multicompany->enabled) && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1) { 8503 $out .= " (".$obj->label.")"; 8504 } 8505 8506 $out .= '</option>'; 8507 $i++; 8508 } 8509 } else { 8510 if ($show_empty) { 8511 $out .= '<option value="-1"'.(in_array(-1, $selected) ? ' selected' : '').'></option>'."\n"; 8512 } 8513 $out .= '<option value="" disabled>'.$langs->trans("NoUserGroupDefined").'</option>'; 8514 } 8515 $out .= '</select>'; 8516 } else { 8517 dol_print_error($this->db); 8518 } 8519 8520 return $out; 8521 } 8522 8523 8524 /** 8525 * Return HTML to show the search and clear seach button 8526 * 8527 * @return string 8528 */ 8529 public function showFilterButtons() 8530 { 8531 $out = '<div class="nowraponall">'; 8532 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fa fa-search"></span></button>'; 8533 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>'; 8534 $out .= '</div>'; 8535 8536 return $out; 8537 } 8538 8539 /** 8540 * Return HTML to show the search and clear search button 8541 * 8542 * @param string $cssclass CSS class 8543 * @param int $calljsfunction 0=default. 1=call function initCheckForSelect() after changing status of checkboxes 8544 * @param string $massactionname Mass action button name that will launch an action on the selected items 8545 * @return string 8546 */ 8547 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction") 8548 { 8549 global $conf, $langs; 8550 8551 $out = ''; 8552 8553 if (!empty($conf->use_javascript_ajax)) { 8554 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="'.$cssclass.'s" name="'.$cssclass.'s" class="checkallactions"></div>'; 8555 } 8556 $out .= '<script> 8557 $(document).ready(function() { 8558 $("#' . $cssclass.'s").click(function() { 8559 if($(this).is(\':checked\')){ 8560 console.log("We check all '.$cssclass.' and trigger the change method"); 8561 $(".'.$cssclass.'").prop(\'checked\', true).trigger(\'change\'); 8562 } 8563 else 8564 { 8565 console.log("We uncheck all"); 8566 $(".'.$cssclass.'").prop(\'checked\', false).trigger(\'change\'); 8567 }'."\n"; 8568 if ($calljsfunction) { 8569 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "'.$massactionname.'", "'.$cssclass.'"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }'; 8570 } 8571 $out .= ' }); 8572 $(".' . $cssclass.'").change(function() { 8573 $(this).closest("tr").toggleClass("highlight", this.checked); 8574 }); 8575 }); 8576 </script>'; 8577 8578 return $out; 8579 } 8580 8581 /** 8582 * Return HTML to show the search and clear seach button 8583 * 8584 * @param int $addcheckuncheckall Add the check all/uncheck all checkbox (use javascript) and code to manage this 8585 * @param string $cssclass CSS class 8586 * @param int $calljsfunction 0=default. 1=call function initCheckForSelect() after changing status of checkboxes 8587 * @param string $massactionname Mass action name 8588 * @return string 8589 */ 8590 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction") 8591 { 8592 $out = $this->showFilterButtons(); 8593 if ($addcheckuncheckall) { 8594 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname); 8595 } 8596 return $out; 8597 } 8598 8599 /** 8600 * Return HTML to show the select of expense categories 8601 * 8602 * @param string $selected preselected category 8603 * @param string $htmlname name of HTML select list 8604 * @param integer $useempty 1=Add empty line 8605 * @param array $excludeid id to exclude 8606 * @param string $target htmlname of target select to bind event 8607 * @param int $default_selected default category to select if fk_c_type_fees change = EX_KME 8608 * @param array $params param to give 8609 * @param int $info_admin Show the tooltip help picto to setup list 8610 * @return string 8611 */ 8612 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1) 8613 { 8614 global $db, $langs, $user; 8615 8616 $out = ''; 8617 $sql = 'SELECT rowid, label FROM '.MAIN_DB_PREFIX.'c_exp_tax_cat WHERE active = 1'; 8618 $sql .= ' AND entity IN (0,'.getEntity('exp_tax_cat').')'; 8619 if (!empty($excludeid)) { 8620 $sql .= ' AND rowid NOT IN ('.$this->db->sanitize(implode(',', $excludeid)).')'; 8621 } 8622 $sql .= ' ORDER BY label'; 8623 8624 $resql = $db->query($sql); 8625 if ($resql) { 8626 $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp maxwidth200">'; 8627 if ($useempty) { 8628 $out .= '<option value="0"> </option>'; 8629 } 8630 8631 while ($obj = $db->fetch_object($resql)) { 8632 $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.$langs->trans($obj->label).'</option>'; 8633 } 8634 $out .= '</select>'; 8635 $out .= ajax_combobox('select_'.$htmlname); 8636 8637 if (!empty($htmlname) && $user->admin && $info_admin) { 8638 $out .= ' '.info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); 8639 } 8640 8641 if (!empty($target)) { 8642 $sql = "SELECT c.id FROM ".MAIN_DB_PREFIX."c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1"; 8643 $resql = $db->query($sql); 8644 if ($resql) { 8645 if ($db->num_rows($resql) > 0) { 8646 $obj = $db->fetch_object($resql); 8647 $out .= '<script> 8648 $(function() { 8649 $("select[name='.$target.']").on("change", function() { 8650 var current_val = $(this).val(); 8651 if (current_val == '.$obj->id.') {'; 8652 if (!empty($default_selected) || !empty($selected)) { 8653 $out .= '$("select[name='.$htmlname.']").val("'.($default_selected > 0 ? $default_selected : $selected).'");'; 8654 } 8655 8656 $out .= ' 8657 $("select[name='.$htmlname.']").change(); 8658 } 8659 }); 8660 8661 $("select[name='.$htmlname.']").change(function() { 8662 8663 if ($("select[name='.$target.']").val() == '.$obj->id.') { 8664 // get price of kilometer to fill the unit price 8665 $.ajax({ 8666 method: "POST", 8667 dataType: "json", 8668 data: { fk_c_exp_tax_cat: $(this).val(), token: \''.currentToken().'\' }, 8669 url: "'.(DOL_URL_ROOT.'/expensereport/ajax/ajaxik.php?'.$params).'", 8670 }).done(function( data, textStatus, jqXHR ) { 8671 console.log(data); 8672 if (typeof data.up != "undefined") { 8673 $("input[name=value_unit]").val(data.up); 8674 $("select[name='.$htmlname.']").attr("title", data.title); 8675 } else { 8676 $("input[name=value_unit]").val(""); 8677 $("select[name='.$htmlname.']").attr("title", ""); 8678 } 8679 }); 8680 } 8681 }); 8682 }); 8683 </script>'; 8684 } 8685 } 8686 } 8687 } else { 8688 dol_print_error($db); 8689 } 8690 8691 return $out; 8692 } 8693 8694 /** 8695 * Return HTML to show the select ranges of expense range 8696 * 8697 * @param string $selected preselected category 8698 * @param string $htmlname name of HTML select list 8699 * @param integer $useempty 1=Add empty line 8700 * @return string 8701 */ 8702 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0) 8703 { 8704 global $db, $conf, $langs; 8705 8706 $out = ''; 8707 $sql = 'SELECT rowid, range_ik FROM '.MAIN_DB_PREFIX.'c_exp_tax_range'; 8708 $sql .= ' WHERE entity = '.$conf->entity.' AND active = 1'; 8709 8710 $resql = $db->query($sql); 8711 if ($resql) { 8712 $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">'; 8713 if ($useempty) { 8714 $out .= '<option value="0"></option>'; 8715 } 8716 8717 while ($obj = $db->fetch_object($resql)) { 8718 $out .= '<option '.($selected == $obj->rowid ? 'selected="selected"' : '').' value="'.$obj->rowid.'">'.price($obj->range_ik, 0, $langs, 1, 0).'</option>'; 8719 } 8720 $out .= '</select>'; 8721 } else { 8722 dol_print_error($db); 8723 } 8724 8725 return $out; 8726 } 8727 8728 /** 8729 * Return HTML to show a select of expense 8730 * 8731 * @param string $selected preselected category 8732 * @param string $htmlname name of HTML select list 8733 * @param integer $useempty 1=Add empty choice 8734 * @param integer $allchoice 1=Add all choice 8735 * @param integer $useid 0=use 'code' as key, 1=use 'id' as key 8736 * @return string 8737 */ 8738 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0) 8739 { 8740 global $db, $langs; 8741 8742 $out = ''; 8743 $sql = 'SELECT id, code, label FROM '.MAIN_DB_PREFIX.'c_type_fees'; 8744 $sql .= ' WHERE active = 1'; 8745 8746 $resql = $db->query($sql); 8747 if ($resql) { 8748 $out = '<select id="select_'.$htmlname.'" name="'.$htmlname.'" class="'.$htmlname.' flat minwidth75imp">'; 8749 if ($useempty) { 8750 $out .= '<option value="0"></option>'; 8751 } 8752 if ($allchoice) { 8753 $out .= '<option value="-1">'.$langs->trans('AllExpenseReport').'</option>'; 8754 } 8755 8756 $field = 'code'; 8757 if ($useid) { 8758 $field = 'id'; 8759 } 8760 8761 while ($obj = $db->fetch_object($resql)) { 8762 $key = $langs->trans($obj->code); 8763 $out .= '<option '.($selected == $obj->{$field} ? 'selected="selected"' : '').' value="'.$obj->{$field}.'">'.($key != $obj->code ? $key : $obj->label).'</option>'; 8764 } 8765 $out .= '</select>'; 8766 } else { 8767 dol_print_error($db); 8768 } 8769 8770 return $out; 8771 } 8772 8773 /** 8774 * Output a combo list with invoices qualified for a third party 8775 * 8776 * @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) 8777 * @param int $selected Id invoice preselected 8778 * @param string $htmlname Name of HTML select 8779 * @param int $maxlength Maximum length of label 8780 * @param int $option_only Return only html options lines without the select tag 8781 * @param string $show_empty Add an empty line ('1' or string to show for empty line) 8782 * @param int $discard_closed Discard closed projects (0=Keep,1=hide completely,2=Disable) 8783 * @param int $forcefocus Force focus on field (works with javascript only) 8784 * @param int $disabled Disabled 8785 * @param string $morecss More css added to the select component 8786 * @param string $projectsListId ''=Automatic filter on project allowed. List of id=Filter on project ids. 8787 * @param string $showproject 'all' = Show project info, ''=Hide project info 8788 * @param User $usertofilter User object to use for filtering 8789 * @return int Nbr of project if OK, <0 if KO 8790 */ 8791 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) 8792 { 8793 global $user, $conf, $langs; 8794 8795 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; 8796 8797 if (is_null($usertofilter)) { 8798 $usertofilter = $user; 8799 } 8800 8801 $out = ''; 8802 8803 $hideunselectables = false; 8804 if (!empty($conf->global->PROJECT_HIDE_UNSELECTABLES)) { 8805 $hideunselectables = true; 8806 } 8807 8808 if (empty($projectsListId)) { 8809 if (empty($usertofilter->rights->projet->all->lire)) { 8810 $projectstatic = new Project($this->db); 8811 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1); 8812 } 8813 } 8814 8815 // Search all projects 8816 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref, 8817 p.title, p.fk_soc, p.fk_statut, p.public,"; 8818 $sql .= ' s.nom as name'; 8819 $sql .= ' FROM '.MAIN_DB_PREFIX.'projet as p'; 8820 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON s.rowid = p.fk_soc,'; 8821 $sql .= ' '.MAIN_DB_PREFIX.'facture as f'; 8822 $sql .= " WHERE p.entity IN (".getEntity('project').")"; 8823 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement 8824 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")"; 8825 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)"; 8826 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)"; 8827 $sql .= " ORDER BY p.ref, f.ref ASC"; 8828 8829 $resql = $this->db->query($sql); 8830 if ($resql) { 8831 // Use select2 selector 8832 if (!empty($conf->use_javascript_ajax)) { 8833 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; 8834 $comboenhancement = ajax_combobox($htmlname, '', 0, $forcefocus); 8835 $out .= $comboenhancement; 8836 $morecss = 'minwidth200imp maxwidth500'; 8837 } 8838 8839 if (empty($option_only)) { 8840 $out .= '<select class="valignmiddle flat'.($morecss ? ' '.$morecss : '').'"'.($disabled ? ' disabled="disabled"' : '').' id="'.$htmlname.'" name="'.$htmlname.'">'; 8841 } 8842 if (!empty($show_empty)) { 8843 $out .= '<option value="0" class="optiongrey">'; 8844 if (!is_numeric($show_empty)) { 8845 $out .= $show_empty; 8846 } else { 8847 $out .= ' '; 8848 } 8849 $out .= '</option>'; 8850 } 8851 $num = $this->db->num_rows($resql); 8852 $i = 0; 8853 if ($num) { 8854 while ($i < $num) { 8855 $obj = $this->db->fetch_object($resql); 8856 // 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. 8857 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && empty($usertofilter->rights->societe->lire)) { 8858 // Do nothing 8859 } else { 8860 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) { 8861 $i++; 8862 continue; 8863 } 8864 8865 $labeltoshow = ''; 8866 8867 if ($showproject == 'all') { 8868 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref 8869 if ($obj->name) { 8870 $labeltoshow .= ' - '.$obj->name; // Soc name 8871 } 8872 8873 $disabled = 0; 8874 if ($obj->fk_statut == Project::STATUS_DRAFT) { 8875 $disabled = 1; 8876 $labeltoshow .= ' - '.$langs->trans("Draft"); 8877 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) { 8878 if ($discard_closed == 2) { 8879 $disabled = 1; 8880 } 8881 $labeltoshow .= ' - '.$langs->trans("Closed"); 8882 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) { 8883 $disabled = 1; 8884 $labeltoshow .= ' - '.$langs->trans("LinkedToAnotherCompany"); 8885 } 8886 } 8887 8888 if (!empty($selected) && $selected == $obj->rowid) { 8889 $out .= '<option value="'.$obj->rowid.'" selected'; 8890 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled 8891 $out .= '>'.$labeltoshow.'</option>'; 8892 } else { 8893 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) { 8894 $resultat = ''; 8895 } else { 8896 $resultat = '<option value="'.$obj->rowid.'"'; 8897 if ($disabled) { 8898 $resultat .= ' disabled'; 8899 } 8900 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')'; 8901 //else $labeltoshow.=' ('.$langs->trans("Private").')'; 8902 $resultat .= '>'; 8903 $resultat .= $labeltoshow; 8904 $resultat .= '</option>'; 8905 } 8906 $out .= $resultat; 8907 } 8908 } 8909 $i++; 8910 } 8911 } 8912 if (empty($option_only)) { 8913 $out .= '</select>'; 8914 } 8915 8916 print $out; 8917 8918 $this->db->free($resql); 8919 return $num; 8920 } else { 8921 dol_print_error($this->db); 8922 return -1; 8923 } 8924 } 8925 8926 /** 8927 * Output the component to make advanced search criteries 8928 * 8929 * @param array $arrayofcriterias Array of available search criterias. Example: array($object->element => $object->fields, 'otherfamily' => otherarrayoffields, ...) 8930 * @param array $search_component_params Array of selected search criterias 8931 * @param array $arrayofinputfieldsalreadyoutput Array of input fields already inform. The component will not generate a hidden input field if it is in this list. 8932 * @return string HTML component for advanced search 8933 */ 8934 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array()) 8935 { 8936 global $langs; 8937 8938 $ret = ''; 8939 8940 $ret .= '<div class="nowrap centpercent">'; 8941 //$ret .= '<button type="submit" class="liste_titre button_removefilter" name="button_removefilter_x" value="x"><span class="fa fa-remove"></span></button>'; 8942 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor paddingright">'; 8943 $ret .= '<span class="fas fa-filter linkobject boxfilter" title="Filter" id="idsubimgproductdistribution"></span>'; 8944 $ret .= $langs->trans("Filters"); 8945 $ret .= '</a>'; 8946 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>'; 8947 $ret .= '<div name="search_component_params" class="search_component_params inline-block minwidth500 maxwidth300onsmartphone valignmiddle">'; 8948 $texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>'; 8949 8950 $ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>'; 8951 $ret .= '</div>'; 8952 $ret .= '<input type="hidden" name="search_component_params_hidden" class="search_component_params_hidden" value="'.GETPOST("search_component_params_hidden").'">'; 8953 // For compatibility with forms that show themself the search criteria in addition of this component, we output the fields 8954 foreach ($arrayofcriterias as $criterias) { 8955 foreach ($criterias as $criteriafamilykey => $criteriafamilyval) { 8956 if (in_array('search_'.$criteriafamilykey, $arrayofinputfieldsalreadyoutput)) { 8957 continue; 8958 } 8959 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) { 8960 continue; 8961 } 8962 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) { 8963 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_start">'; 8964 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startyear">'; 8965 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startmonth">'; 8966 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_startday">'; 8967 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_end">'; 8968 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endyear">'; 8969 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endmonth">'; 8970 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'_endday">'; 8971 } else { 8972 $ret .= '<input type="hidden" name="search_'.$criteriafamilykey.'">'; 8973 } 8974 } 8975 } 8976 $ret .= '</div>'; 8977 8978 8979 return $ret; 8980 } 8981 8982 /** 8983 * selectModelMail 8984 * 8985 * @param string $prefix Prefix 8986 * @param string $modelType Model type 8987 * @param int $default 1=Show also Default mail template 8988 * @param int $addjscombo Add js combobox 8989 * @return string HTML select string 8990 */ 8991 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0) 8992 { 8993 global $langs, $db, $user; 8994 8995 $retstring = ''; 8996 8997 $TModels = array(); 8998 8999 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; 9000 $formmail = new FormMail($db); 9001 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs); 9002 9003 if ($default) { 9004 $TModels[0] = $langs->trans('DefaultMailModel'); 9005 } 9006 if ($result > 0) { 9007 foreach ($formmail->lines_model as $model) { 9008 $TModels[$model->id] = $model->label; 9009 } 9010 } 9011 9012 $retstring .= '<select class="flat" id="select_'.$prefix.'model_mail" name="'.$prefix.'model_mail">'; 9013 9014 foreach ($TModels as $id_model => $label_model) { 9015 $retstring .= '<option value="'.$id_model.'"'; 9016 $retstring .= ">".$label_model."</option>"; 9017 } 9018 9019 $retstring .= "</select>"; 9020 9021 if ($addjscombo) { 9022 $retstring .= ajax_combobox('select_'.$prefix.'model_mail'); 9023 } 9024 9025 return $retstring; 9026 } 9027} 9028