dolibarr 21.0.4
html.form.class.php
Go to the documentation of this file.
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-2021 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-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.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 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
27 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 3 of the License, or
32 * (at your option) any later version.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program. If not, see <https://www.gnu.org/licenses/>.
41 */
42
56class Form
57{
61 public $db;
62
66 public $error = '';
67
71 public $errors = array();
72
73 // Some properties used to return data by some methods
75 public $result;
77 public $num;
78
79 // Cache arrays
80 public $cache_types_paiements = array();
81 public $cache_conditions_paiements = array();
82 public $cache_transport_mode = array();
83 public $cache_availability = array();
84 public $cache_demand_reason = array();
85 public $cache_types_fees = array();
86 public $cache_vatrates = array();
87 public $cache_invoice_subtype = array();
88
89
95 public function __construct($db)
96 {
97 $this->db = $db;
98 }
99
116 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
117 {
118 global $langs;
119
120 $ret = '';
121
122 // TODO change for compatibility
123 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
124 if (!empty($perm)) {
125 $tmp = explode(':', $typeofdata);
126 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
127 if ($fieldrequired) {
128 $ret .= '<span class="fieldrequired">';
129 }
130 if ($help) {
131 $ret .= $this->textwithpicto($langs->trans($text), $help);
132 } else {
133 $ret .= $langs->trans($text);
134 }
135 if ($fieldrequired) {
136 $ret .= '</span>';
137 }
138 $ret .= '</div>' . "\n";
139 } else {
140 if ($fieldrequired) {
141 $ret .= '<span class="fieldrequired">';
142 }
143 if ($help) {
144 $ret .= $this->textwithpicto($langs->trans($text), $help);
145 } else {
146 $ret .= $langs->trans($text);
147 }
148 if ($fieldrequired) {
149 $ret .= '</span>';
150 }
151 }
152 } else {
153 if (empty($notabletag) && $perm) {
154 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
155 }
156 if ($fieldrequired) {
157 $ret .= '<span class="fieldrequired">';
158 }
159 if ($help) {
160 $ret .= $this->textwithpicto($langs->trans($text), $help);
161 } else {
162 $ret .= $langs->trans($text);
163 }
164 if ($fieldrequired) {
165 $ret .= '</span>';
166 }
167 if (!empty($notabletag)) {
168 $ret .= ' ';
169 }
170 if (empty($notabletag) && $perm) {
171 $ret .= '</td>';
172 }
173 if (empty($notabletag) && $perm) {
174 $ret .= '<td class="right">';
175 }
176 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
177 $ret .= '<a class="editfielda reposition" href="' . $_SERVER["PHP_SELF"] . '?action=edit' . $htmlname . '&token=' . newToken() . '&' . $paramid . '=' . $object->id . $moreparam . '">' . img_edit($langs->trans('Edit'), ($notabletag ? 0 : 1)) . '</a>';
178 }
179 if (!empty($notabletag) && $notabletag == 1) {
180 if ($text) {
181 $ret .= ' : ';
182 } else {
183 $ret .= ' ';
184 }
185 }
186 if (!empty($notabletag) && $notabletag == 3) {
187 $ret .= ' ';
188 }
189 if (empty($notabletag) && $perm) {
190 $ret .= '</td>';
191 }
192 if (empty($notabletag) && $perm) {
193 $ret .= '</tr></table>';
194 }
195 }
196
197 return $ret;
198 }
199
223 public function editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata = 'string', $editvalue = '', $extObject = null, $custommsg = null, $moreparam = '', $notabletag = 1, $formatfunc = '', $paramid = 'id', $gm = 'auto', $moreoptions = array(), $editaction = '')
224 {
225 global $conf, $langs;
226
227 $ret = '';
228
229 // Check parameters
230 if (empty($typeofdata)) {
231 return 'ErrorBadParameter typeofdata is empty';
232 }
233 // Clean parameter $typeofdata
234 if ($typeofdata == 'datetime') {
235 $typeofdata = 'dayhour';
236 }
237 $reg = array();
238 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
239 if ($reg[1] == 'varchar') {
240 $typeofdata = 'string';
241 } elseif ($reg[1] == 'int') {
242 $typeofdata = 'numeric';
243 } else {
244 return 'ErrorBadParameter ' . $typeofdata;
245 }
246 }
247
248 // When option to edit inline is activated
249 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
250 $ret .= $this->editInPlace($object, $value, $htmlname, ($perm ? 1 : 0), $typeofdata, $editvalue, $extObject, $custommsg);
251 } else {
252 if ($editaction == '') {
253 $editaction = GETPOST('action', 'aZ09');
254 }
255 $editmode = ($editaction == 'edit' . $htmlname);
256 if ($editmode) { // edit mode
257 $ret .= "<!-- formeditfieldval -->\n";
258 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
259 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
260 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
261 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
262 if (empty($notabletag)) {
263 $ret .= '<table class="nobordernopadding centpercent">';
264 }
265 if (empty($notabletag)) {
266 $ret .= '<tr><td>';
267 }
268 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
269 $tmp = explode(':', $typeofdata);
270 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
271 } elseif (preg_match('/^(integer)/', $typeofdata)) {
272 $tmp = explode(':', $typeofdata);
273 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
274 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
275 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
276 $tmp = explode(':', $typeofdata);
277 $valuetoshow = price2num($editvalue ? $editvalue : $value);
278 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
279 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
280 $tmp = explode(':', $typeofdata);
281 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
282 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
283 $tmp = explode(':', $typeofdata);
284 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
285 $morealt = '';
286 if (preg_match('/%/', $cols)) {
287 $morealt = ' style="width: ' . $cols . '"';
288 $cols = '';
289 }
290 $valuetoshow = ($editvalue ? $editvalue : $value);
291 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
292 // textarea convert automatically entities chars into simple chars.
293 // So we convert & into &amp; so a string like 'a &lt; <b>b</b><br>é<br>&lt;script&gt;alert('X');&lt;script&gt;' stay a correct html and is not converted by textarea component when wysiwyg is off.
294 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
295 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
296 $ret .= '</textarea><div class="clearboth"></div>';
297 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
298 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
299 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
300 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
301 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
302 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
303 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
304 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
305 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
306 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
307 } elseif (preg_match('/^select;/', $typeofdata)) {
308 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
309 $arraylist = array();
310 foreach ($arraydata as $val) {
311 $tmp = explode(':', $val);
312 $tmpkey = str_replace('|', ':', $tmp[0]);
313 $arraylist[$tmpkey] = $tmp[1];
314 }
315 $ret .= $this->selectarray($htmlname, $arraylist, $value);
316 } elseif (preg_match('/^link/', $typeofdata)) {
317 // TODO Not yet implemented. See code for extrafields
318 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
319 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
320 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
321 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? 100 : (int) $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? false : (bool) $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? 20 : (int) $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
322 $ret .= $doleditor->Create(1);
323 } elseif ($typeofdata == 'asis') {
324 $ret .= ($editvalue ? $editvalue : $value);
325 }
326 if (empty($notabletag)) {
327 $ret .= '</td>';
328 }
329
330 // Button save-cancel
331 if (empty($notabletag)) {
332 $ret .= '<td>';
333 }
334 //else $ret.='<div class="clearboth"></div>';
335 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
336 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
337 $ret .= '<br>' . "\n";
338 }
339 $ret .= '<input type="submit" class="smallpaddingimp nomargingtop nomarginbottom button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
340 if (empty($notabletag)) {
341 $ret .= '</td>';
342 }
343
344 if (empty($notabletag)) {
345 $ret .= '</tr></table>' . "\n";
346 }
347 $ret .= '</form>' . "\n";
348 } else { // view mode
349 if (preg_match('/^email/', $typeofdata)) {
350 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
351 } elseif (preg_match('/^phone/', $typeofdata)) {
352 $ret .= dol_print_phone($value, '_blank', 32, 1);
353 } elseif (preg_match('/^url/', $typeofdata)) {
354 $ret .= dol_print_url($value, '_blank', 32, 1);
355 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
356 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
357 } elseif (preg_match('/^checkbox/', $typeofdata)) {
358 $tmp = explode(':', $typeofdata);
359 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
360 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
362 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
364 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
365 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
366 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
367 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
368 } elseif (preg_match('/^select;/', $typeofdata)) {
369 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
370 $arraylist = array();
371 foreach ($arraydata as $val) {
372 $tmp = explode(':', $val);
373 $arraylist[$tmp[0]] = $tmp[1];
374 }
375 $ret .= $arraylist[$value];
376 if ($htmlname == 'fk_product_type') {
377 if ($value == 0) {
378 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
379 } else {
380 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
381 }
382 }
383 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
384 $tmpcontent = dol_htmlentitiesbr($value);
385 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
386 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
387 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
388 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
389 }
390 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
391 // clean data from some dangerous html
393 } else {
394 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
395 $ret .= dol_escape_htmltag($value);
396 } else {
397 $ret .= $value; // $value must be already html escaped.
398 }
399 }
400
401 // Custom format if parameter $formatfunc has been provided
402 if ($formatfunc && method_exists($object, $formatfunc)) {
403 $ret = $object->$formatfunc($ret);
404 }
405 }
406 }
407 return $ret;
408 }
409
421 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
422 {
423 global $conf, $langs, $extralanguages;
424
425 $result = '';
426
427 // List of extra languages
428 $arrayoflangcode = array();
429 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
430 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
431 }
432
433 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
434 if (!is_object($extralanguages)) {
435 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
436 $extralanguages = new ExtraLanguages($this->db);
437 }
438 $extralanguages->fetch_name_extralanguages('societe');
439
440 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
441 return ''; // No extralang field to show
442 }
443
444 $result .= '<!-- Widget for translation -->' . "\n";
445 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
446 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', 0, 0, 0, '', 'fa-15 editfieldlang');
447 $result .= $s;
448 $result .= '</div>';
449
450 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
451
452 $resultforextrlang = '';
453 foreach ($arrayoflangcode as $langcode) {
454 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
455 if (empty($valuetoshow)) {
456 $object->fetchValuesForExtraLanguages();
457 //var_dump($object->array_languages);
458 $valuetoshow = $object->array_languages[$fieldname][$langcode];
459 }
460
461 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
462 $resultforextrlang .= $s;
463
464 // TODO Use the showInputField() method of ExtraLanguages object
465 if ($typeofdata == 'textarea') {
466 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
467 $resultforextrlang .= $valuetoshow;
468 $resultforextrlang .= '</textarea>';
469 } else {
470 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
471 }
472 }
473 $result .= $resultforextrlang;
474
475 $result .= '</div>';
476 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
477 }
478
479 return $result;
480 }
481
495 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
496 {
497 $out = '';
498
499 // Check parameters
500 if (preg_match('/^text/', $inputType)) {
501 $value = dol_nl2br($value);
502 } elseif (preg_match('/^numeric/', $inputType)) {
503 $value = price($value);
504 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
505 $value = dol_print_date($value, 'day');
506 }
507
508 if ($condition) {
509 $element = false;
510 $table_element = false;
511 $fk_element = false;
512 $loadmethod = false;
513 $savemethod = false;
514 $ext_element = false;
515 $button_only = false;
516 $inputOption = '';
517 $rows = '';
518 $cols = '';
519
520 if (is_object($object)) {
521 $element = $object->element;
522 $table_element = $object->table_element;
523 $fk_element = $object->id;
524 }
525
526 if (is_object($extObject)) {
527 $ext_element = $extObject->element;
528 }
529
530 if (preg_match('/^(string|email|numeric)/', $inputType)) {
531 $tmp = explode(':', $inputType);
532 $inputType = $tmp[0];
533 if (!empty($tmp[1])) {
534 $inputOption = $tmp[1];
535 }
536 if (!empty($tmp[2])) {
537 $savemethod = $tmp[2];
538 }
539 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
540 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
541 $tmp = explode(':', $inputType);
542 $inputType = $tmp[0];
543 if (!empty($tmp[1])) {
544 $inputOption = $tmp[1];
545 }
546 if (!empty($tmp[2])) {
547 $savemethod = $tmp[2];
548 }
549
550 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
551 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
552 $tmp = explode(':', $inputType);
553 $inputType = $tmp[0];
554 $loadmethod = $tmp[1];
555 if (!empty($tmp[2])) {
556 $savemethod = $tmp[2];
557 }
558 if (!empty($tmp[3])) {
559 $button_only = true;
560 }
561 } elseif (preg_match('/^textarea/', $inputType)) {
562 $tmp = explode(':', $inputType);
563 $inputType = $tmp[0];
564 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
565 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
566 } elseif (preg_match('/^ckeditor/', $inputType)) {
567 $tmp = explode(':', $inputType);
568 $inputType = $tmp[0];
569 $toolbar = $tmp[1];
570 if (!empty($tmp[2])) {
571 $width = $tmp[2];
572 }
573 if (!empty($tmp[3])) {
574 $height = $tmp[3];
575 }
576 if (!empty($tmp[4])) {
577 $savemethod = $tmp[4];
578 }
579
580 if (isModEnabled('fckeditor')) {
581 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
582 } else {
583 $inputType = 'textarea';
584 }
585 }
586
587 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
590 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
591 if (!empty($savemethod)) {
592 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
593 }
594 if (!empty($ext_element)) {
595 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
596 }
597 if (!empty($custommsg)) {
598 if (is_array($custommsg)) {
599 if (!empty($custommsg['success'])) {
600 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
601 }
602 if (!empty($custommsg['error'])) {
603 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
604 }
605 } else {
606 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
607 }
608 }
609 if ($inputType == 'textarea') {
610 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
611 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
612 }
613 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
614 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
615 } else {
616 $out = $value;
617 }
618
619 return $out;
620 }
621
640 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
641 {
642 if ($incbefore) {
643 $text = $incbefore . $text;
644 }
645 if (!$htmltext) {
646 return $text;
647 }
648 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
649
650 $tag = 'td';
651 if ($notabs == 2) {
652 $tag = 'div';
653 }
654 if ($notabs == 3) {
655 $tag = 'span';
656 }
657 // Sanitize tooltip
658 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
659
660 $extrastyle = '';
661 if ($direction < 0) {
662 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
663 $extrastyle = 'padding: 0px; padding-left: 2px;';
664 }
665 if ($direction > 0) {
666 $extracss = ($extracss ? $extracss : '') . ($notabs != 3 ? ' inline-block' : '');
667 $extrastyle = 'padding: 0px; padding-right: 2px;';
668 }
669
670 $classfortooltip = 'classfortooltip';
671
672 $s = '';
673 $textfordialog = '';
674
675 if ($tooltiptrigger == '') {
676 $htmltext = str_replace('"', '&quot;', $htmltext);
677 } else {
678 $classfortooltip = 'classfortooltiponclick';
679 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
680 }
681 if ($tooltipon == 2 || $tooltipon == 3) {
682 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
683 if ($tooltiptrigger == '') {
684 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
685 } else {
686 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
687 }
688 } else {
689 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
690 }
691 if ($tooltipon == 1 || $tooltipon == 3) {
692 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ($tag != 'td' ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
693 if ($tooltiptrigger == '') {
694 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
695 } else {
696 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
697 }
698 } else {
699 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
700 }
701 if (empty($notabs)) {
702 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
703 } elseif ($notabs == 2) {
704 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
705 }
706 // Define value if value is before
707 if ($direction < 0) {
708 $s .= '<' . $tag . $paramfortooltipimg;
709 if ($tag == 'td') {
710 $s .= ' class="valigntop" width="14"';
711 }
712 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
713 }
714 // Use another method to help avoid having a space in value in order to use this value with jquery
715 // Define label
716 if ((string) $text != '') {
717 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
718 }
719 // Define value if value is after
720 if ($direction > 0) {
721 $s .= '<' . $tag . $paramfortooltipimg;
722 if ($tag == 'td') {
723 $s .= ' class="valignmiddle" width="14"';
724 }
725 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
726 }
727 if (empty($notabs)) {
728 $s .= '</tr></table>';
729 } elseif ($notabs == 2) {
730 $s .= '</div>';
731 }
732
733 return $s;
734 }
735
750 public function textwithpicto($text, $htmltooltip, $direction = 1, $type = 'help', $extracss = 'valignmiddle', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
751 {
752 global $conf, $langs;
753
754 //For backwards compatibility
755 if ($type == '0') {
756 $type = 'info';
757 } elseif ($type == '1') {
758 $type = 'help';
759 }
760 // Clean parameters
761 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
762
763 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
764 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
765 }
766 $alt = '';
767 if ($tooltiptrigger) {
768 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
769 }
770
771 // If info or help with no javascript, show only text
772 if (empty($conf->use_javascript_ajax)) {
773 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
774 return $text;
775 } else {
776 $alt = $htmltooltip;
777 $htmltooltip = '';
778 }
779 }
780
781 // If info or help with smartphone, show only text (tooltip hover can't works)
782 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
783 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
784 return $text;
785 }
786 }
787 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
788 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
789 //{
790 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
791 //}
792
793 $img = '';
794 if ($type == 'info') {
795 $img = img_help(0, $alt);
796 } elseif ($type == 'help') {
797 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
798 } elseif ($type == 'helpclickable') {
799 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
800 } elseif ($type == 'superadmin') {
801 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
802 $img = img_picto($alt, 'redstar');
803 } elseif ($type == 'admin') {
804 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
805 $img = img_picto($alt, 'star');
806 } elseif ($type == 'warning') {
807 $img = img_warning($alt);
808 } elseif ($type != 'none') {
809 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
810 $img = img_picto($alt, $type); // $type can be an image path
811 }
812
813 return $this->textwithtooltip($text, $htmltooltip, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
814 }
815
826 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
827 {
828 global $conf, $langs, $hookmanager;
829
830 $disabled = 0;
831 $ret = '<div class="centpercent center">';
832 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
833
834 // 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.
835 $parameters = array();
836 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
837 // check if there is a mass action
838
839 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
840 return;
841 }
842 if (empty($reshook)) {
843 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
844 if (is_array($arrayofaction)) {
845 foreach ($arrayofaction as $code => $label) {
846 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
847 }
848 }
849 }
850 $ret .= $hookmanager->resPrint;
851
852 $ret .= '</select>';
853
854 if (empty($conf->dol_optimize_smallscreen)) {
855 $ret .= ajax_combobox('.' . $name . 'select');
856 }
857
858 // 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
859 $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.
860 $ret .= '<input type="submit" disabled name="confirmmassaction"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display: none"') . ' class="reposition button smallpaddingimp' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'confirmed" value="' . dol_escape_htmltag($langs->trans("Confirm")) . '">';
861 $ret .= '</div>';
862
863 if (!empty($conf->use_javascript_ajax)) {
864 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
865 <script nonce="' . getNonce() . '">
866 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 */
867 {
868 atleastoneselected=0;
869 jQuery("."+cssclass).each(function( index ) {
870 /* console.log( index + ": " + $( this ).text() ); */
871 if ($(this).is(\':checked\')) atleastoneselected++;
872 });
873
874 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
875
876 if (atleastoneselected || ' . ((int) $alwaysvisible) . ')
877 {
878 jQuery("."+name).show();
879 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
880 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
881 }
882 else
883 {
884 jQuery("."+name).hide();
885 jQuery("."+name+"other").hide();
886 }
887 }
888
889 jQuery(document).ready(function () {
890 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
891 jQuery(".' . $cssclass . '").click(function() {
892 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
893 });
894 jQuery(".' . $name . 'select").change(function() {
895 var massaction = $( this ).val();
896 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
897 if (massaction == "builddoc") {
898 urlform = urlform + "#show_files";
899 }
900 $( this ).closest("form").attr("action", urlform);
901 console.log("we select a mass action name=' . $name . ' massaction="+massaction+" - "+urlform);
902 /* Warning: if you set submit button to disabled, post using Enter will no more work if there is no other button */
903 if ($(this).val() != \'0\') {
904 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
905 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
906 jQuery(".' . $name . '"+massaction).show();
907 } else {
908 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
909 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
910 }
911 });
912 });
913 </script>
914 ';
915 }
916
917 return $ret;
918 }
919
920 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
921
939 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, $forcecombo = 0)
940 {
941 // phpcs:enable
942 global $conf, $langs, $mysoc;
943
944 $langs->load("dict");
945
946 $out = '';
947 $countryArray = array();
948 $favorite = array();
949 $label = array();
950 $atleastonefavorite = 0;
951
952 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
953 $sql .= " FROM " . $this->db->prefix() . "c_country";
954 $sql .= " WHERE active > 0";
955 //$sql.= " ORDER BY code ASC";
956
957 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
958 $resql = $this->db->query($sql);
959 if ($resql) {
960 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
961 $num = $this->db->num_rows($resql);
962 $i = 0;
963 if ($num) {
964 while ($i < $num) {
965 $obj = $this->db->fetch_object($resql);
966
967 $countryArray[$i]['rowid'] = $obj->rowid;
968 $countryArray[$i]['code_iso'] = $obj->code_iso;
969 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
970 $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 : ''));
971 $countryArray[$i]['favorite'] = $obj->favorite;
972 $countryArray[$i]['eec'] = $obj->eec;
973 $favorite[$i] = $obj->favorite;
974 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
975 $i++;
976 }
977
978 if (empty($disablefavorites)) {
979 $array1_sort_order = SORT_DESC;
980 $array2_sort_order = SORT_ASC;
981 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
982 } else {
983 $countryArray = dol_sort_array($countryArray, 'label');
984 }
985
986 if ($showempty) {
987 if (is_numeric($showempty)) {
988 $out .= '<option value="">&nbsp;</option>' . "\n";
989 } else {
990 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
991 }
992 }
993
994 if ($addspecialentries) { // Add dedicated entries for groups of countries
995 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
996 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
997 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
998 if ($mysoc->isInEEC()) {
999 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1000 }
1001 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1002 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1003 }
1004
1005 foreach ($countryArray as $row) {
1006 //if (empty($showempty) && empty($row['rowid'])) continue;
1007 if (empty($row['rowid'])) {
1008 continue;
1009 }
1010 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1011 continue; // exclude some countries
1012 }
1013
1014 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1015 $atleastonefavorite++;
1016 }
1017 if (empty($row['favorite']) && $atleastonefavorite) {
1018 $atleastonefavorite = 0;
1019 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1020 }
1021
1022 $labeltoshow = '';
1023 if ($row['label']) {
1024 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1025 } else {
1026 $labeltoshow .= '&nbsp;';
1027 }
1028 if ($row['code_iso']) {
1029 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1030 if (empty($hideflags)) {
1031 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1032 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1033 }
1034 }
1035
1036 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1037 $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']) . '">';
1038 } else {
1039 $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']) . '">';
1040 }
1041 $out .= $labeltoshow;
1042 $out .= '</option>' . "\n";
1043 }
1044 }
1045 $out .= '</select>';
1046 } else {
1047 dol_print_error($this->db);
1048 }
1049
1050 // Make select dynamic
1051 if (empty($forcecombo)) {
1052 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1053 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1054 }
1055
1056 return $out;
1057 }
1058
1059 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1060
1074 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1075 {
1076 // phpcs:enable
1077 global $conf, $langs;
1078
1079 $langs->load("dict");
1080
1081 $out = '';
1082 //$moreattrib = '';
1083 $incotermArray = array();
1084
1085 $sql = "SELECT rowid, code";
1086 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1087 $sql .= " WHERE active > 0";
1088 $sql .= " ORDER BY code ASC";
1089
1090 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1091 $resql = $this->db->query($sql);
1092 if ($resql) {
1093 if ($conf->use_javascript_ajax && !$forcecombo) {
1094 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1095 $out .= ajax_combobox($htmlname, $events);
1096 }
1097
1098 if (!empty($page)) {
1099 $out .= '<form method="post" action="' . $page . '">';
1100 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1101 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1102 }
1103
1104 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1105 $out .= '<option value="0">&nbsp;</option>';
1106 $num = $this->db->num_rows($resql);
1107 $i = 0;
1108 if ($num) {
1109 while ($i < $num) {
1110 $obj = $this->db->fetch_object($resql);
1111 $incotermArray[$i]['rowid'] = $obj->rowid;
1112 $incotermArray[$i]['code'] = $obj->code;
1113 $i++;
1114 }
1115
1116 foreach ($incotermArray as $row) {
1117 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1118 $out .= '<option value="' . $row['rowid'] . '" selected>';
1119 } else {
1120 $out .= '<option value="' . $row['rowid'] . '">';
1121 }
1122
1123 if ($row['code']) {
1124 $out .= $row['code'];
1125 }
1126
1127 $out .= '</option>';
1128 }
1129 }
1130 $out .= '</select>';
1131 $out .= ajax_combobox($htmlname);
1132
1133 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1134 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1135 //$moreattrib .= ' autocomplete="off"';
1136 }
1137 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1138
1139 if (!empty($page)) {
1140 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1141 }
1142 } else {
1143 dol_print_error($this->db);
1144 }
1145
1146 return $out;
1147 }
1148
1149 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1150
1164 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1165 {
1166 // phpcs:enable
1167 global $langs;
1168
1169 // If product & services are enabled or both disabled.
1170 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1171 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1172 if (empty($hidetext)) {
1173 print $langs->trans("Type").'...';
1174 }
1175 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1176 if ($showempty) {
1177 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1178 if ($selected == -1) {
1179 print ' selected';
1180 }
1181 print '>';
1182 if (is_numeric($showempty)) {
1183 print '&nbsp;';
1184 } else {
1185 print $showempty;
1186 }
1187 print '</option>';
1188 }
1189
1190 print '<option value="0"';
1191 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1192 print ' selected';
1193 }
1194 print '>' . $langs->trans("Product");
1195
1196 print '<option value="1"';
1197 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1198 print ' selected';
1199 }
1200 print '>' . $langs->trans("Service");
1201
1202 print '</select>';
1203
1204 if ($useajaxcombo) {
1205 print ajax_combobox('select_' . $htmlname);
1206 }
1207 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1208 }
1209 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1210 print $langs->trans("Service");
1211 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1212 }
1213 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1214 print $langs->trans("Product");
1215 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1216 }
1217 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1218 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
1219 }
1220 }
1221
1222 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1223
1229 public function load_cache_types_fees()
1230 {
1231 // phpcs:enable
1232 global $langs;
1233
1234 $num = count($this->cache_types_fees);
1235 if ($num > 0) {
1236 return 0; // Cache already loaded
1237 }
1238
1239 dol_syslog(__METHOD__, LOG_DEBUG);
1240
1241 $langs->load("trips");
1242
1243 $sql = "SELECT c.code, c.label";
1244 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1245 $sql .= " WHERE active > 0";
1246
1247 $resql = $this->db->query($sql);
1248 if ($resql) {
1249 $num = $this->db->num_rows($resql);
1250 $i = 0;
1251
1252 while ($i < $num) {
1253 $obj = $this->db->fetch_object($resql);
1254
1255 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1256 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1257 $this->cache_types_fees[$obj->code] = $label;
1258 $i++;
1259 }
1260
1261 asort($this->cache_types_fees);
1262
1263 return $num;
1264 } else {
1265 dol_print_error($this->db);
1266 return -1;
1267 }
1268 }
1269
1270 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1271
1280 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1281 {
1282 // phpcs:enable
1283 global $user, $langs;
1284
1285 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1286
1287 $this->load_cache_types_fees();
1288
1289 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1290 if ($showempty) {
1291 print '<option value="-1"';
1292 if ($selected == -1) {
1293 print ' selected';
1294 }
1295 print '>&nbsp;</option>';
1296 }
1297
1298 foreach ($this->cache_types_fees as $key => $value) {
1299 print '<option value="' . $key . '"';
1300 if ($key == $selected) {
1301 print ' selected';
1302 }
1303 print '>';
1304 print $value;
1305 print '</option>';
1306 }
1307
1308 print '</select>';
1309 if ($user->admin) {
1310 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1311 }
1312 }
1313
1314
1315 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1316
1339 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(), $showcode = 0)
1340 {
1341 // phpcs:enable
1342 global $conf, $langs;
1343
1344 $out = '';
1345
1346 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1347 if (is_null($ajaxoptions)) {
1348 $ajaxoptions = array();
1349 }
1350
1351 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1352
1353 // No immediate load of all database
1354 $placeholder = '';
1355 if ($selected && empty($selected_input_value)) {
1356 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1357 $societetmp = new Societe($this->db);
1358 $societetmp->fetch($selected);
1359 $selected_input_value = $societetmp->name;
1360 unset($societetmp);
1361 }
1362
1363 // mode 1
1364 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($excludeids) ? '' : '&excludeids=' . implode(',', $excludeids)) . ($showtype ? '&showtype=' . urlencode((string) ($showtype)) : '') . ($showcode ? '&showcode=' . urlencode((string) ($showcode)) : '');
1365
1366 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1367 if (empty($hidelabel)) {
1368 $out .= $langs->trans("RefOrLabel") . ' : ';
1369 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1370 $placeholder = $langs->trans($showempty);
1371 } elseif ($hidelabel > 1) {
1372 $placeholder = $langs->trans("RefOrLabel");
1373 if ($hidelabel == 2) {
1374 $out .= img_picto($langs->trans("Search"), 'search');
1375 }
1376 }
1377 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('THIRDPARTY_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1378 if ($hidelabel == 3) {
1379 $out .= img_picto($langs->trans("Search"), 'search');
1380 }
1381
1382 $out .= ajax_event($htmlname, $events);
1383
1384 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1385 } else {
1386 // Immediate load of all database
1387 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1388 }
1389
1390 return $out;
1391 }
1392
1393
1394 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1395
1421 public function select_contact($socid, $selected = '', $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $nokeyifsocid = true, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $selected_input_value = '', $filter = '')
1422 {
1423 // phpcs:enable
1424
1425 global $conf, $langs;
1426
1427 $out = '';
1428
1429 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1430 if ($nokeyifsocid && $socid > 0) {
1431 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1432 }
1433
1434 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1435 if (is_null($events)) {
1436 $events = array();
1437 }
1438
1439 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1440
1441 // No immediate load of all database
1442 $placeholder = '';
1443 if ($selected && empty($selected_input_value)) {
1444 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1445 $contacttmp = new Contact($this->db);
1446 $contacttmp->fetch($selected);
1447 $selected_input_value = $contacttmp->getFullName($langs);
1448 unset($contacttmp);
1449 }
1450 if (!is_numeric($showempty)) {
1451 $placeholder = $showempty;
1452 }
1453
1454 // mode 1
1455 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1456
1457 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1458
1459 $out .= '<input type="text" class="' . $morecss . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '') . ' ' . (getDolGlobalString('CONTACT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
1460
1461 $out .= ajax_event($htmlname, $events);
1462
1463 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1464 } else {
1465 // Immediate load of all database
1466 $multiple = false;
1467 $disableifempty = 0;
1468 $options_only = 0;
1469 $limitto = '';
1470
1471 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1472 }
1473
1474 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1475
1476 return $out;
1477 }
1478
1479
1480 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1481
1506 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(), $showcode = 0)
1507 {
1508 // phpcs:enable
1509 global $user, $langs;
1510 global $hookmanager;
1511
1512 $langs->loadLangs(array("companies", "suppliers"));
1513
1514 $out = '';
1515 $num = 0;
1516 $outarray = array();
1517
1518 if ($selected === '') {
1519 $selected = array();
1520 } elseif (!is_array($selected)) {
1521 $selected = array($selected);
1522 }
1523
1524 // Clean $filter that may contains sql conditions so sql code
1525 if (function_exists('testSqlAndScriptInject')) {
1526 if (testSqlAndScriptInject($filter, 3) > 0) {
1527 $filter = '';
1528 return 'SQLInjectionTryDetected';
1529 }
1530 }
1531
1532 if ($filter != '') { // If a filter was provided
1533 if (preg_match('/[\‍(\‍)]/', $filter)) {
1534 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1535 $errormsg = '';
1536 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1537
1538 // Redo clean $filter that may contains sql conditions so sql code
1539 if (function_exists('testSqlAndScriptInject')) {
1540 if (testSqlAndScriptInject($filter, 3) > 0) {
1541 $filter = '';
1542 return 'SQLInjectionTryDetected';
1543 }
1544 }
1545 } else {
1546 // If not, we do nothing. We already know that there is no parenthesis
1547 // TODO Disallow this case in a future.
1548 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1549 }
1550 }
1551
1552 // We search companies
1553 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1554 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1555 $sql .= ", s.address, s.zip, s.town";
1556 $sql .= ", dictp.code as country_code";
1557 }
1558 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1559 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1560 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1561 }
1562 if (!$user->hasRight('societe', 'client', 'voir')) {
1563 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1564 }
1565 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1566 if (!empty($user->socid)) {
1567 $sql .= " AND s.rowid = " . ((int) $user->socid);
1568 }
1569 if ($filter) {
1570 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1571 // if not, by testSqlAndScriptInject() only.
1572 $sql .= " AND (" . $filter . ")";
1573 }
1574 if (!$user->hasRight('societe', 'client', 'voir')) {
1575 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1576 }
1577 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1578 $sql .= " AND s.status <> 0";
1579 }
1580 if (!empty($excludeids)) {
1581 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1582 }
1583 // Add where from hooks
1584 $parameters = array();
1585 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1586 $sql .= $hookmanager->resPrint;
1587 // Add criteria
1588 if ($filterkey && $filterkey != '') {
1589 $sql .= " AND (";
1590 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1591 // For natural search
1592 $search_crit = explode(' ', $filterkey);
1593 $i = 0;
1594 if (count($search_crit) > 1) {
1595 $sql .= "(";
1596 }
1597 foreach ($search_crit as $crit) {
1598 if ($i > 0) {
1599 $sql .= " AND ";
1600 }
1601 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1602 $i++;
1603 }
1604 if (count($search_crit) > 1) {
1605 $sql .= ")";
1606 }
1607 if (isModEnabled('barcode')) {
1608 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1609 }
1610 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1611 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1612 $sql .= ")";
1613 }
1614 $sql .= $this->db->order("nom", "ASC");
1615 $sql .= $this->db->plimit($limit, 0);
1616
1617 // Build output string
1618 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1619 $resql = $this->db->query($sql);
1620 if ($resql) {
1621 // Construct $out and $outarray
1622 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1623
1624 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1625 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1626 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1627 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1628 if ($showempty && !is_numeric($showempty)) {
1629 $textifempty = $langs->trans($showempty);
1630 } else {
1631 $textifempty .= $langs->trans("All");
1632 }
1633 }
1634 if ($showempty) {
1635 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1636 }
1637
1638 $companytemp = new Societe($this->db);
1639
1640 $num = $this->db->num_rows($resql);
1641 $i = 0;
1642 if ($num) {
1643 while ($i < $num) {
1644 $obj = $this->db->fetch_object($resql);
1645 $label = '';
1646 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1647 if (($obj->client) && (!empty($obj->code_client))) {
1648 $label = $obj->code_client . ' - ';
1649 }
1650 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1651 $label .= $obj->code_fournisseur . ' - ';
1652 }
1653 $label .= ' ' . $obj->name;
1654 } else {
1655 $label = $obj->name;
1656 }
1657
1658 if (!empty($obj->name_alias)) {
1659 $label .= ' (' . $obj->name_alias . ')';
1660 }
1661
1662 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1663 $label .= ' - '.$obj->tva_intra;
1664 }
1665
1666 $labelhtml = $label;
1667
1668 if ($showtype) {
1669 $companytemp->id = $obj->rowid;
1670 $companytemp->client = $obj->client;
1671 $companytemp->fournisseur = $obj->fournisseur;
1672 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1673 if ($tmptype) {
1674 $labelhtml .= ' ' . $tmptype;
1675 }
1676
1677 if ($obj->client || $obj->fournisseur) {
1678 $label .= ' (';
1679 }
1680 if ($obj->client == 1 || $obj->client == 3) {
1681 $label .= $langs->trans("Customer");
1682 }
1683 if ($obj->client == 2 || $obj->client == 3) {
1684 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1685 }
1686 if ($obj->fournisseur) {
1687 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1688 }
1689 if ($obj->client || $obj->fournisseur) {
1690 $label .= ')';
1691 }
1692 }
1693
1694 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1695 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1696 if (!empty($obj->country_code)) {
1697 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1698 }
1699 $label .= $s;
1700 $labelhtml .= $s;
1701 }
1702
1703 if (empty($outputmode)) {
1704 if (in_array($obj->rowid, $selected)) {
1705 $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1706 } else {
1707 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1708 }
1709 } else {
1710 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1711 }
1712
1713 $i++;
1714 if (($i % 10) == 0) {
1715 $out .= "\n";
1716 }
1717 }
1718 }
1719 $out .= '</select>' . "\n";
1720 if (!$forcecombo) {
1721 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1722 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1723 }
1724 } else {
1725 dol_print_error($this->db);
1726 }
1727
1728 $this->result = array('nbofthirdparties' => $num);
1729
1730 if ($outputmode) {
1731 return $outarray;
1732 }
1733 return $out;
1734 }
1735
1736
1762 public function selectcontacts($socid, $selected = array(), $htmlname = 'contactid', $showempty = 0, $exclude = '', $limitto = '', $showfunction = 0, $morecss = '', $options_only = 0, $showsoc = 0, $forcecombo = 0, $events = array(), $moreparam = '', $htmlid = '', $multiple = false, $disableifempty = 0, $filter = '')
1763 {
1764 global $conf, $user, $langs, $hookmanager, $action;
1765
1766 $langs->load('companies');
1767
1768 if (empty($htmlid)) {
1769 $htmlid = $htmlname;
1770 }
1771 $num = 0;
1772 $out = '';
1773 $outarray = array();
1774
1775 if ($selected === '') {
1776 $selected = array();
1777 } elseif (!is_array($selected)) {
1778 $selected = array((int) $selected);
1779 }
1780
1781 // Clean $filter that may contains sql conditions so sql code
1782 if (function_exists('testSqlAndScriptInject')) {
1783 if (testSqlAndScriptInject($filter, 3) > 0) {
1784 $filter = '';
1785 return 'SQLInjectionTryDetected';
1786 }
1787 }
1788
1789 if ($filter != '') { // If a filter was provided
1790 if (preg_match('/[\‍(\‍)]/', $filter)) {
1791 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1792 $errormsg = '';
1793 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1794
1795 // Redo clean $filter that may contains sql conditions so sql code
1796 if (function_exists('testSqlAndScriptInject')) {
1797 if (testSqlAndScriptInject($filter, 3) > 0) {
1798 $filter = '';
1799 return 'SQLInjectionTryDetected';
1800 }
1801 }
1802 } else {
1803 // If not, we do nothing. We already know that there is no parenthesis
1804 // TODO Disallow this case in a future by returning an error here.
1805 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1806 }
1807 }
1808
1809 if (!is_object($hookmanager)) {
1810 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1811 $hookmanager = new HookManager($this->db);
1812 }
1813
1814 // We search third parties
1815 $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";
1816 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1817 $sql .= ", s.nom as company, s.town AS company_town";
1818 }
1819 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1820 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1821 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1822 }
1823 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1824 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1825 if ($socid > 0 || $socid == -1) {
1826 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1827 }
1828 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1829 $sql .= " AND sp.statut <> 0";
1830 }
1831 if ($filter) {
1832 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1833 // if not, by testSqlAndScriptInject() only.
1834 $sql .= " AND (" . $filter . ")";
1835 }
1836 // Add where from hooks
1837 $parameters = array();
1838 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1839 $sql .= $hookmanager->resPrint;
1840 $sql .= " ORDER BY sp.lastname ASC";
1841
1842 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1843 $resql = $this->db->query($sql);
1844 if ($resql) {
1845 $num = $this->db->num_rows($resql);
1846
1847 if ($htmlname != 'none' && !$options_only) {
1848 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1849 }
1850
1851 if ($showempty && !is_numeric($showempty)) {
1852 $textforempty = $showempty;
1853 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1854 } else {
1855 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1856 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1857 }
1858 if ($showempty == 2) {
1859 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1860 }
1861 }
1862
1863 $i = 0;
1864 if ($num) {
1865 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1866 $contactstatic = new Contact($this->db);
1867
1868 while ($i < $num) {
1869 $obj = $this->db->fetch_object($resql);
1870
1871 // Set email (or phones) and town extended infos
1872 $extendedInfos = '';
1873 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1874 $extendedInfos = array();
1875 $email = trim($obj->email);
1876 if (!empty($email)) {
1877 $extendedInfos[] = $email;
1878 } else {
1879 $phone = trim($obj->phone);
1880 $phone_perso = trim($obj->phone_perso);
1881 $phone_mobile = trim($obj->phone_mobile);
1882 if (!empty($phone)) {
1883 $extendedInfos[] = $phone;
1884 }
1885 if (!empty($phone_perso)) {
1886 $extendedInfos[] = $phone_perso;
1887 }
1888 if (!empty($phone_mobile)) {
1889 $extendedInfos[] = $phone_mobile;
1890 }
1891 }
1892 $contact_town = trim($obj->contact_town);
1893 $company_town = trim($obj->company_town);
1894 if (!empty($contact_town)) {
1895 $extendedInfos[] = $contact_town;
1896 } elseif (!empty($company_town)) {
1897 $extendedInfos[] = $company_town;
1898 }
1899 $extendedInfos = implode(' - ', $extendedInfos);
1900 if (!empty($extendedInfos)) {
1901 $extendedInfos = ' - ' . $extendedInfos;
1902 }
1903 }
1904
1905 $contactstatic->id = $obj->rowid;
1906 $contactstatic->lastname = $obj->lastname;
1907 $contactstatic->firstname = $obj->firstname;
1908 if ($obj->statut == 1) {
1909 $tmplabel = '';
1910 if ($htmlname != 'none') {
1911 $disabled = 0;
1912 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1913 $disabled = 1;
1914 }
1915 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1916 $disabled = 1;
1917 }
1918 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1919 $out .= '<option value="' . $obj->rowid . '"';
1920 if ($disabled) {
1921 $out .= ' disabled';
1922 }
1923 $out .= ' selected>';
1924
1925 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1926 if ($showfunction && $obj->poste) {
1927 $tmplabel .= ' (' . $obj->poste . ')';
1928 }
1929 if (($showsoc > 0) && $obj->company) {
1930 $tmplabel .= ' - (' . $obj->company . ')';
1931 }
1932
1933 $out .= $tmplabel;
1934 $out .= '</option>';
1935 } else {
1936 $out .= '<option value="' . $obj->rowid . '"';
1937 if ($disabled) {
1938 $out .= ' disabled';
1939 }
1940 $out .= '>';
1941
1942 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1943 if ($showfunction && $obj->poste) {
1944 $tmplabel .= ' (' . $obj->poste . ')';
1945 }
1946 if (($showsoc > 0) && $obj->company) {
1947 $tmplabel .= ' - (' . $obj->company . ')';
1948 }
1949
1950 $out .= $tmplabel;
1951 $out .= '</option>';
1952 }
1953 } else {
1954 if (in_array($obj->rowid, $selected)) {
1955 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1956 if ($showfunction && $obj->poste) {
1957 $tmplabel .= ' (' . $obj->poste . ')';
1958 }
1959 if (($showsoc > 0) && $obj->company) {
1960 $tmplabel .= ' - (' . $obj->company . ')';
1961 }
1962
1963 $out .= $tmplabel;
1964 }
1965 }
1966
1967 if ($tmplabel != '') {
1968 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1969 }
1970 }
1971 $i++;
1972 }
1973 } else {
1974 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1975 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1976 $out .= $labeltoshow;
1977 $out .= '</option>';
1978 }
1979
1980 $parameters = array(
1981 'socid' => $socid,
1982 'htmlname' => $htmlname,
1983 'resql' => $resql,
1984 'out' => &$out,
1985 'showfunction' => $showfunction,
1986 'showsoc' => $showsoc,
1987 );
1988
1989 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1990
1991 if ($htmlname != 'none' && !$options_only) {
1992 $out .= '</select>';
1993 }
1994
1995 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1996 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1997 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1998 }
1999
2000 $this->num = $num;
2001
2002 if ($options_only === 2) {
2003 // Return array of options
2004 return $outarray;
2005 } else {
2006 return $out;
2007 }
2008 } else {
2009 dol_print_error($this->db);
2010 return -1;
2011 }
2012 }
2013
2014
2015 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2016
2027 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2028 {
2029 // phpcs:enable
2030 global $langs, $conf;
2031
2032 // On recherche les remises
2033 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2034 $sql .= " re.description, re.fk_facture_source";
2035 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2036 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2037 $sql .= " AND re.entity = " . $conf->entity;
2038 if ($filter) {
2039 $sql .= " AND " . $filter;
2040 }
2041 $sql .= " ORDER BY re.description ASC";
2042
2043 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2044 $resql = $this->db->query($sql);
2045 if ($resql) {
2046 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2047 $num = $this->db->num_rows($resql);
2048
2049 $qualifiedlines = $num;
2050
2051 $i = 0;
2052 if ($num) {
2053 print '<option value="0">&nbsp;</option>';
2054 while ($i < $num) {
2055 $obj = $this->db->fetch_object($resql);
2056 $desc = dol_trunc($obj->description, 40);
2057 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2058 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2059 }
2060 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2061 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2062 }
2063 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2064 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2065 }
2066 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2067 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2068 }
2069
2070 $selectstring = '';
2071 if ($selected > 0 && $selected == $obj->rowid) {
2072 $selectstring = ' selected';
2073 }
2074
2075 $disabled = '';
2076 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2077 $qualifiedlines--;
2078 $disabled = ' disabled';
2079 }
2080
2081 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2082 $tmpfac = new Facture($this->db);
2083 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2084 $desc = $desc . ' - ' . $tmpfac->ref;
2085 }
2086 }
2087
2088 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2089 $i++;
2090 }
2091 }
2092 print '</select>';
2093 print ajax_combobox('select_' . $htmlname);
2094
2095 return $qualifiedlines;
2096 } else {
2097 dol_print_error($this->db);
2098 return -1;
2099 }
2100 }
2101
2102
2103 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2104
2120 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2121 {
2122 // phpcs:enable
2123 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2124 }
2125
2126 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2127
2152 public function select_dolusers($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = '', $force_entity = '', $maxlength = 0, $showstatus = 0, $morefilter = '', $show_every = 0, $enableonlytext = '', $morecss = '', $notdisabled = 0, $outputmode = 0, $multiple = false, $forcecombo = 0)
2153 {
2154 // phpcs:enable
2155 global $conf, $user, $langs, $hookmanager;
2156 global $action;
2157
2158 // If no preselected user defined, we take current user
2159 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2160 $selected = $user->id;
2161 }
2162
2163 if ($selected === '') {
2164 $selected = array();
2165 } elseif (!is_array($selected)) {
2166 $selected = array($selected);
2167 }
2168
2169 $excludeUsers = null;
2170 $includeUsers = null;
2171
2172 // Exclude some users
2173 if (is_array($exclude)) {
2174 $excludeUsers = implode(",", $exclude);
2175 }
2176 // Include some uses
2177 if (is_array($include)) {
2178 $includeUsers = implode(",", $include);
2179 } elseif ($include == 'hierarchy') {
2180 // Build list includeUsers to have only hierarchy
2181 $includeUsers = implode(",", $user->getAllChildIds(0));
2182 } elseif ($include == 'hierarchyme') {
2183 // Build list includeUsers to have only hierarchy and current user
2184 $includeUsers = implode(",", $user->getAllChildIds(1));
2185 }
2186
2187 $num = 0;
2188
2189 $out = '';
2190 $outarray = array();
2191 $outarray2 = array();
2192
2193 // Do we want to show the label of entity into the combo list ?
2194 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2195 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2196
2197 // Forge request to select users
2198 $sql = "SELECT DISTINCT u.rowid, u.lastname as lastname, u.firstname, u.statut as status, u.login, u.admin, u.entity, u.gender, u.photo";
2199 if ($showlabelofentity) {
2200 $sql .= ", e.label";
2201 }
2202 $sql .= " FROM " . $this->db->prefix() . "user as u";
2203 if ($showlabelofentity) {
2204 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2205 }
2206 // Condition here should be the same than into societe->getSalesRepresentatives().
2207 if ($userissuperadminentityone && $force_entity !== 'default') {
2208 if (!empty($force_entity)) {
2209 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2210 } else {
2211 $sql .= " WHERE u.entity IS NOT NULL";
2212 }
2213 } else {
2214 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2215 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2216 } else {
2217 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2218 }
2219 }
2220
2221 if (!empty($user->socid)) {
2222 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2223 }
2224 if (is_array($exclude) && $excludeUsers) {
2225 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2226 }
2227 if ($includeUsers) {
2228 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2229 }
2230 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2231 $sql .= " AND u.statut <> 0";
2232 }
2233 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2234 $sql .= " AND u.employee <> 0";
2235 }
2236 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2237 $sql .= " AND u.fk_soc IS NULL";
2238 }
2239 if (!empty($morefilter)) {
2240 $errormessage = '';
2241 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2242 if ($errormessage) {
2243 $this->errors[] = $errormessage;
2244 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2245 if ($outputmode == 0) {
2246 return 'Error bad param $morefilter';
2247 } else {
2248 return array();
2249 }
2250 }
2251 }
2252
2253 //Add hook to filter on user (for example on usergroup define in custom modules)
2254 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2255 if (!empty($reshook)) {
2256 $sql .= $hookmanager->resPrint;
2257 }
2258
2259 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2260 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2261 } else {
2262 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2263 }
2264
2265 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2266
2267 $resql = $this->db->query($sql);
2268 if ($resql) {
2269 $num = $this->db->num_rows($resql);
2270 $i = 0;
2271 if ($num) {
2272 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2273 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2274 if ($show_empty && !$multiple) {
2275 $textforempty = ' ';
2276 if (!empty($conf->use_javascript_ajax)) {
2277 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2278 }
2279 if (!is_numeric($show_empty)) {
2280 $textforempty = $show_empty;
2281 }
2282 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2283
2284 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2285 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2286 'id' => ($show_empty < 0 ? $show_empty : -1),
2287 'label' => $textforempty,
2288 'labelhtml' => $textforempty,
2289 'color' => '',
2290 'picto' => ''
2291 );
2292 }
2293 if ($show_every) {
2294 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2295
2296 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2297 $outarray2[-2] = array(
2298 'id' => -2,
2299 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2300 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2301 'color' => '',
2302 'picto' => ''
2303 );
2304 }
2305
2306 $userstatic = new User($this->db);
2307
2308 while ($i < $num) {
2309 $obj = $this->db->fetch_object($resql);
2310
2311 $userstatic->id = $obj->rowid;
2312 $userstatic->lastname = $obj->lastname;
2313 $userstatic->firstname = $obj->firstname;
2314 $userstatic->photo = $obj->photo;
2315 $userstatic->status = $obj->status;
2316 $userstatic->entity = $obj->entity;
2317 $userstatic->admin = $obj->admin;
2318 $userstatic->gender = $obj->gender;
2319
2320 $disableline = '';
2321 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2322 $disableline = ($enableonlytext ? $enableonlytext : '1');
2323 }
2324
2325 $labeltoshow = '';
2326 $labeltoshowhtml = '';
2327
2328 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2329 $fullNameMode = 0;
2330 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2331 $fullNameMode = 1; //Firstname+lastname
2332 }
2333 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2334 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2335 if (empty($obj->firstname) && empty($obj->lastname)) {
2336 $labeltoshow .= $obj->login;
2337 $labeltoshowhtml .= $obj->login;
2338 }
2339
2340 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2341 $moreinfo = '';
2342 $moreinfohtml = '';
2343 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2344 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2345 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2346 $moreinfo .= $obj->login;
2347 $moreinfohtml .= $obj->login;
2348 }
2349 if ($showstatus >= 0) {
2350 if ($obj->status == 1 && $showstatus == 1) {
2351 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2352 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2353 }
2354 if ($obj->status == 0 && $showstatus == 1) {
2355 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2356 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2357 }
2358 }
2359 if ($showlabelofentity) {
2360 if (empty($obj->entity)) {
2361 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2362 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2363 } else {
2364 if ($obj->entity != $conf->entity) {
2365 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2366 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2367 }
2368 }
2369 }
2370 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2371 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2372 if (!empty($disableline) && $disableline != '1') {
2373 // Add text from $enableonlytext parameter
2374 $moreinfo .= ' - ' . $disableline;
2375 $moreinfohtml .= ' - ' . $disableline;
2376 }
2377 $labeltoshow .= $moreinfo;
2378 $labeltoshowhtml .= $moreinfohtml;
2379
2380 $out .= '<option value="' . $obj->rowid . '"';
2381 if (!empty($disableline)) {
2382 $out .= ' disabled';
2383 }
2384 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2385 $out .= ' selected';
2386 }
2387 $out .= ' data-html="';
2388
2389 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2390 if ($showstatus >= 0 && $obj->status == 0) {
2391 $outhtml .= '<strike class="opacitymediumxxx">';
2392 }
2393 $outhtml .= $labeltoshowhtml;
2394 if ($showstatus >= 0 && $obj->status == 0) {
2395 $outhtml .= '</strike>';
2396 }
2397 $labeltoshowhtml = $outhtml;
2398
2399 $out .= dol_escape_htmltag($outhtml);
2400 $out .= '">';
2401 $out .= $labeltoshow;
2402 $out .= '</option>';
2403
2404 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2405 $outarray2[$userstatic->id] = array(
2406 'id' => $userstatic->id,
2407 'label' => $labeltoshow,
2408 'labelhtml' => $labeltoshowhtml,
2409 'color' => '',
2410 'picto' => ''
2411 );
2412
2413 $i++;
2414 }
2415 } else {
2416 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2417 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2418 }
2419 $out .= '</select>';
2420
2421 if ($num && !$forcecombo) {
2422 // Enhance with select2
2423 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2424 $out .= ajax_combobox($htmlname);
2425 }
2426 } else {
2427 dol_print_error($this->db);
2428 }
2429
2430 $this->num = $num;
2431
2432 if ($outputmode == 2) {
2433 return $outarray2;
2434 } elseif ($outputmode) {
2435 return $outarray;
2436 }
2437
2438 return $out;
2439 }
2440
2441
2442 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2466 public function select_dolusers_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofuserid = array(), $listofcontactid = array(), $listofotherid = array(), $canremoveowner = 1)
2467 {
2468 // phpcs:enable
2469 global $langs, $user;
2470
2471 $userstatic = new User($this->db);
2472 $out = '';
2473
2474 if (!empty($_SESSION['assignedtouser'])) {
2475 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2476 if (!is_array($assignedtouser)) {
2477 $assignedtouser = array();
2478 }
2479 } else {
2480 $assignedtouser = array();
2481 }
2482 $nbassignetouser = count($assignedtouser);
2483
2484 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2485 if ($nbassignetouser) {
2486 $out .= '<ul class="attendees">';
2487 }
2488 $i = 0;
2489 $ownerid = 0;
2490 foreach ($assignedtouser as $key => $value) {
2491 if ($value['id'] == $ownerid) {
2492 continue;
2493 }
2494
2495 $out .= '<li>';
2496 $userstatic->fetch($value['id']);
2497 $out .= $userstatic->getNomUrl(-1);
2498 if ($i == 0) {
2499 $ownerid = $value['id'];
2500 $out .= ' (' . $langs->trans("Owner") . ')';
2501 }
2502 // Add picto to delete owner/assignee
2503 if ($nbassignetouser > 1 && $action != 'view') {
2504 $canremoveassignee = 1;
2505 if ($i == 0) {
2506 // We are on the owner of the event
2507 if (!$canremoveowner) {
2508 $canremoveassignee = 0;
2509 }
2510 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2511 $canremoveassignee = 0; // Can't remove the owner
2512 }
2513 } else {
2514 // We are not on the owner of the event but on a secondary assignee
2515 }
2516 if ($canremoveassignee) {
2517 // If user has all permission, he should be ableto remove a assignee.
2518 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2519 $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 . '">';
2520 }
2521 }
2522 // Show my availability
2523 if ($showproperties) {
2524 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2525 $out .= '<div class="myavailability inline-block">';
2526 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<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>';
2527 $out .= '</div>';
2528 }
2529 }
2530 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2531 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2532
2533 $out .= '</li>';
2534 $i++;
2535 }
2536 if ($nbassignetouser) {
2537 $out .= '</ul>';
2538 }
2539
2540 // Method with no ajax
2541 if ($action != 'view') {
2542 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2543 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2544 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2545 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2546 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2547 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2548 $out .= '});';
2549 $out .= '})</script>';
2550 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2551 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2552 $out .= '<br>';
2553 }
2554
2555 return $out;
2556 }
2557
2558 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2578 public function select_dolresources_forevent($action = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = array(), $enableonly = array(), $force_entity = '0', $maxlength = 0, $showstatus = 0, $morefilter = '', $showproperties = 0, $listofresourceid = array())
2579 {
2580 // phpcs:enable
2581 global $langs;
2582
2583 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2584 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2585 $formresources = new FormResource($this->db);
2586 $resourcestatic = new Dolresource($this->db);
2587
2588 $out = '';
2589 if (!empty($_SESSION['assignedtoresource'])) {
2590 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2591 if (!is_array($assignedtoresource)) {
2592 $assignedtoresource = array();
2593 }
2594 } else {
2595 $assignedtoresource = array();
2596 }
2597 $nbassignetoresource = count($assignedtoresource);
2598
2599 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2600 if ($nbassignetoresource) {
2601 $out .= '<ul class="attendees">';
2602 }
2603 $i = 0;
2604
2605 foreach ($assignedtoresource as $key => $value) {
2606 $out .= '<li>';
2607 $resourcestatic->fetch($value['id']);
2608 $out .= $resourcestatic->getNomUrl(-1);
2609 if ($nbassignetoresource >= 1 && $action != 'view') {
2610 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassignedresource reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2611 }
2612 // Show my availability
2613 if ($showproperties) {
2614 if (is_array($listofresourceid) && count($listofresourceid)) {
2615 $out .= '<div class="myavailability inline-block">';
2616 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource'.$value['id'].'" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparencyresource'.$value['id'].'">' . $langs->trans("Busy") . '</label>';
2617 $out .= '</div>';
2618 }
2619 }
2620 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2621 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2622
2623 $out .= '</li>';
2624 $i++;
2625 }
2626 if ($nbassignetoresource) {
2627 $out .= '</ul>';
2628 }
2629
2630 // Method with no ajax
2631 if ($action != 'view') {
2632 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2633 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2634 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2635 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2636 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2637 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2638 $out .= '});';
2639 $out .= '})</script>';
2640
2641 $events = array();
2642 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2643 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2644 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2645 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2646 $out .= '<br>';
2647 }
2648
2649 return $out;
2650 }
2651
2652 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2653
2683 public function select_produits($selected = 0, $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, $status_purchase = -1, $warehouseId = 0)
2684 {
2685 // phpcs:enable
2686 global $langs, $conf;
2687
2688 $out = '';
2689
2690 // check parameters
2691 $price_level = (!empty($price_level) ? $price_level : 0);
2692 if (is_null($ajaxoptions)) {
2693 $ajaxoptions = array();
2694 }
2695
2696 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2697 if (isModEnabled("product") && !isModEnabled('service')) {
2698 $filtertype = '0';
2699 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2700 $filtertype = '1';
2701 }
2702 }
2703
2704 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2705 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2706
2707 if ($selected && empty($selected_input_value)) {
2708 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2709 $producttmpselect = new Product($this->db);
2710 $producttmpselect->fetch($selected);
2711 $selected_input_value = $producttmpselect->ref;
2712 unset($producttmpselect);
2713 }
2714 // handle case where product or service module is disabled + no filter specified
2715 if ($filtertype == '') {
2716 if (!isModEnabled('product')) { // when product module is disabled, show services only
2717 $filtertype = 1;
2718 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2719 $filtertype = 0;
2720 }
2721 }
2722 // mode=1 means customers products
2723 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=1&status=' . $status . '&status_purchase=' . $status_purchase . '&finished=' . $finished . '&hidepriceinlabel=' . $hidepriceinlabel . '&warehousestatus=' . $warehouseStatus;
2724 if ((int) $warehouseId > 0) {
2725 $urloption .= '&warehouseid=' . (int) $warehouseId;
2726 }
2727
2728 $out .= ajax_autocompleter((string) $selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), getDolGlobalInt('PRODUCT_SEARCH_AUTO_SELECT_IF_ONLY_ONE', 1), $ajaxoptions);
2729
2730 if (isModEnabled('variants') && is_array($selected_combinations)) {
2731 // Code to automatically insert with javascript the select of attributes under the select of product
2732 // when a parent of variant has been selected.
2733 $out .= '
2734 <!-- script to auto show attributes select tags if a variant was selected -->
2735 <script nonce="' . getNonce() . '">
2736 // auto show attributes fields
2737 selected = ' . json_encode($selected_combinations) . ';
2738 combvalues = {};
2739
2740 jQuery(document).ready(function () {
2741
2742 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2743 if (jQuery(this).val() == \'free\') {
2744 jQuery(\'div#attributes_box\').empty();
2745 }
2746 });
2747
2748 jQuery("input#' . $htmlname . '").change(function () {
2749
2750 if (!jQuery(this).val()) {
2751 jQuery(\'div#attributes_box\').empty();
2752 return;
2753 }
2754
2755 console.log("A change has started. We get variants fields to inject html select");
2756
2757 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2758 id: jQuery(this).val()
2759 }, function (data) {
2760 jQuery(\'div#attributes_box\').empty();
2761
2762 jQuery.each(data, function (key, val) {
2763
2764 combvalues[val.id] = val.values;
2765
2766 var span = jQuery(document.createElement(\'div\')).css({
2767 \'display\': \'table-row\'
2768 });
2769
2770 span.append(
2771 jQuery(document.createElement(\'div\')).text(val.label).css({
2772 \'font-weight\': \'bold\',
2773 \'display\': \'table-cell\'
2774 })
2775 );
2776
2777 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2778 \'margin-left\': \'15px\',
2779 \'white-space\': \'pre\'
2780 }).append(
2781 jQuery(document.createElement(\'option\')).val(\'\')
2782 );
2783
2784 jQuery.each(combvalues[val.id], function (key, val) {
2785 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2786
2787 if (selected[val.fk_product_attribute] == val.id) {
2788 tag.attr(\'selected\', \'selected\');
2789 }
2790
2791 html.append(tag);
2792 });
2793
2794 span.append(html);
2795 jQuery(\'div#attributes_box\').append(span);
2796 });
2797 })
2798 });
2799
2800 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2801 });
2802 </script>
2803 ';
2804 }
2805
2806 if (empty($hidelabel)) {
2807 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2808 } elseif ($hidelabel > 1) {
2809 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2810 if ($hidelabel == 2) {
2811 $out .= img_picto($langs->trans("Search"), 'search');
2812 }
2813 }
2814
2815 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2816 if ($hidelabel == 3) {
2817 $out .= img_picto($langs->trans("Search"), 'search');
2818 }
2819 } else {
2820 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2821 }
2822
2823 if (empty($nooutput)) {
2824 print $out;
2825 } else {
2826 return $out;
2827 }
2828 }
2829
2830 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2831
2847 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2848 {
2849 // phpcs:enable
2850 global $db;
2851
2852 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2853
2854 $error = 0;
2855 $out = '';
2856
2857 if (!$forcecombo) {
2858 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2859 $events = array();
2860 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2861 }
2862
2863 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2864
2865 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2866 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2867 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2868 if (!empty($status)) {
2869 $sql .= ' AND status = ' . (int) $status;
2870 }
2871 if (!empty($type)) {
2872 $sql .= ' AND bomtype = ' . (int) $type;
2873 }
2874 if (!empty($TProducts)) {
2875 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2876 }
2877 if (!empty($limit)) {
2878 $sql .= ' LIMIT ' . (int) $limit;
2879 }
2880 $resql = $db->query($sql);
2881 if ($resql) {
2882 if ($showempty) {
2883 $out .= '<option value="-1"';
2884 if (empty($selected)) {
2885 $out .= ' selected';
2886 }
2887 $out .= '>&nbsp;</option>';
2888 }
2889 while ($obj = $db->fetch_object($resql)) {
2890 $product = new Product($db);
2891 $res = $product->fetch($obj->fk_product);
2892 $out .= '<option value="' . $obj->rowid . '"';
2893 if ($obj->rowid == $selected) {
2894 $out .= 'selected';
2895 }
2896 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2897 }
2898 } else {
2899 $error++;
2900 dol_print_error($db);
2901 }
2902 $out .= '</select>';
2903 if (empty($nooutput)) {
2904 print $out;
2905 } else {
2906 return $out;
2907 }
2908 }
2909
2910 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2911
2938 public function select_produits_list($selected = 0, $htmlname = 'productid', $filtertype = '', $limit = 20, $price_level = 0, $filterkey = '', $status = 1, $finished = 2, $outputmode = 0, $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = 'maxwidth500', $hidepriceinlabel = 0, $warehouseStatus = '', $status_purchase = -1, $warehouseId = 0)
2939 {
2940 // phpcs:enable
2941 global $langs;
2942 global $hookmanager;
2943
2944 $out = '';
2945 $outarray = array();
2946
2947 // Units
2948 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2949 $langs->load('other');
2950 }
2951
2952 $warehouseStatusArray = array();
2953 if (!empty($warehouseStatus)) {
2954 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2955 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2956 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2957 }
2958 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2959 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2960 }
2961 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2962 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2963 }
2964 }
2965
2966 $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.default_vat_code, p.duration, p.fk_price_expression";
2967 if (count($warehouseStatusArray)) {
2968 $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
2969 } else {
2970 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2971 }
2972
2973 $sql = "SELECT ";
2974
2975 // Add select from hooks
2976 $parameters = array();
2977 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2978 if (empty($reshook)) {
2979 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2980 } else {
2981 $sql .= $hookmanager->resPrint;
2982 }
2983
2984 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2985 //Product category
2986 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2987 FROM " . $this->db->prefix() . "categorie_product
2988 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2989 LIMIT 1
2990 ) AS categorie_product_id ";
2991 }
2992
2993 //Price by customer
2994 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
2995 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2996 $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref';
2997 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2998 }
2999 // Units
3000 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3001 $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";
3002 $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';
3003 }
3004
3005 // Multilang : we add translation
3006 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3007 $sql .= ", pl.label as label_translated";
3008 $sql .= ", pl.description as description_translated";
3009 $selectFields .= ", label_translated";
3010 $selectFields .= ", description_translated";
3011 }
3012 // Price by quantity
3013 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3014 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3015 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3016 $sql .= " AND price_level = " . ((int) $price_level);
3017 }
3018 $sql .= " ORDER BY date_price";
3019 $sql .= " DESC LIMIT 1) as price_rowid";
3020 $sql .= ", (SELECT pp.price_by_qty FROM " . $this->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
3021 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3022 $sql .= " AND price_level = " . ((int) $price_level);
3023 }
3024 $sql .= " ORDER BY date_price";
3025 $sql .= " DESC LIMIT 1) as price_by_qty";
3026 $selectFields .= ", price_rowid, price_by_qty";
3027 }
3028
3029 $sql .= " FROM ".$this->db->prefix()."product as p";
3030
3031 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3032 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3033 }
3034
3035 // Add from (left join) from hooks
3036 $parameters = array();
3037 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3038 $sql .= $hookmanager->resPrint;
3039
3040 if (count($warehouseStatusArray)) {
3041 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3042 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3043 $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.
3044 }
3045
3046 //Price by customer
3047 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3048 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3049 }
3050 // Units
3051 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3052 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3053 }
3054 // Multilang : we add translation
3055 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3056 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3057 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3058 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3059 $soc = new Societe($this->db);
3060 $result = $soc->fetch($socid);
3061 if ($result > 0 && !empty($soc->default_lang)) {
3062 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3063 } else {
3064 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3065 }
3066 } else {
3067 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3068 }
3069 }
3070
3071 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3072 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3073 }
3074
3075 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3076
3077 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3078 $sql .= " AND pac.rowid IS NULL";
3079 }
3080
3081 if ($finished == 0) {
3082 $sql .= " AND p.finished = " . ((int) $finished);
3083 } elseif ($finished == 1) {
3084 $sql .= " AND p.finished = ".((int) $finished);
3085 }
3086 if ($status >= 0) {
3087 $sql .= " AND p.tosell = ".((int) $status);
3088 }
3089 if ($status_purchase >= 0) {
3090 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3091 }
3092 // Filter by product type
3093 if (strval($filtertype) != '') {
3094 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3095 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3096 $sql .= " AND p.fk_product_type = 1";
3097 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3098 $sql .= " AND p.fk_product_type = 0";
3099 }
3100
3101 if ((int) $warehouseId > 0) {
3102 $sql .= " AND EXISTS (SELECT psw.fk_product FROM " . $this->db->prefix() . "product_stock as psw WHERE psw.reel>0 AND psw.fk_entrepot=".(int) $warehouseId." AND psw.fk_product = p.rowid)";
3103 }
3104
3105 // Add where from hooks
3106 $parameters = array();
3107 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3108 $sql .= $hookmanager->resPrint;
3109 // Add criteria on ref/label
3110 if ($filterkey != '') {
3111 $sqlSupplierSearch= '';
3112
3113 $sql .= ' AND (';
3114 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3115 // For natural search
3116 $search_crit = explode(' ', $filterkey);
3117 $i = 0;
3118 if (count($search_crit) > 1) {
3119 $sql .= "(";
3120 }
3121 foreach ($search_crit as $crit) {
3122 if ($i > 0) {
3123 $sql .= " AND ";
3124 }
3125 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3126 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3127 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3128 }
3129 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3130 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3131 }
3132 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3133 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3134 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3135 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3136 }
3137 }
3138
3139 // include search in supplier ref
3140 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3141 $sqlSupplierSearch .= !empty($sqlSupplierSearch) ? ' AND ':'';
3142 $sqlSupplierSearch .= " pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3143 }
3144 $sql .= ")";
3145 $i++;
3146 }
3147 if (count($search_crit) > 1) {
3148 $sql .= ")";
3149 }
3150 if (isModEnabled('barcode')) {
3151 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3152 }
3153
3154 // include search in supplier ref
3155 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3156 $sql .= " OR EXISTS (SELECT pfp.fk_product FROM " . $this->db->prefix() . "product_fournisseur_price as pfp WHERE p.rowid = pfp.fk_product";
3157 $sql .= " AND (";
3158 $sql .= $sqlSupplierSearch;
3159 $sql .= "))";
3160 }
3161
3162 $sql .= ')';
3163 }
3164 if (count($warehouseStatusArray)) {
3165 $sql .= " GROUP BY " . $selectFields;
3166 }
3167
3168 //Sort by category
3169 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3170 $sql .= " ORDER BY categorie_product_id ";
3171 //ASC OR DESC order
3172 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3173 } else {
3174 $sql .= $this->db->order("p.ref");
3175 }
3176
3177 $sql .= $this->db->plimit($limit, 0);
3178
3179 // Build output string
3180 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3181 $result = $this->db->query($sql);
3182 if ($result) {
3183 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3184 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3185 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3186
3187 $num = $this->db->num_rows($result);
3188
3189 $events = array();
3190
3191 if (!$forcecombo) {
3192 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3193 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3194 }
3195
3196 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3197
3198 $textifempty = '';
3199 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3200 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3201 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3202 if ($showempty && !is_numeric($showempty)) {
3203 $textifempty = $langs->trans($showempty);
3204 } else {
3205 $textifempty .= $langs->trans("All");
3206 }
3207 } else {
3208 if ($showempty && !is_numeric($showempty)) {
3209 $textifempty = $langs->trans($showempty);
3210 }
3211 }
3212 if ($showempty) {
3213 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3214 }
3215
3216 $i = 0;
3217 while ($num && $i < $num) {
3218 $opt = '';
3219 $optJson = array();
3220 $objp = $this->db->fetch_object($result);
3221
3222 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('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
3223 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3224 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3225 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3226 $sql .= " ORDER BY quantity ASC";
3227
3228 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3229 $result2 = $this->db->query($sql);
3230 if ($result2) {
3231 $nb_prices = $this->db->num_rows($result2);
3232 $j = 0;
3233 while ($nb_prices && $j < $nb_prices) {
3234 $objp2 = $this->db->fetch_object($result2);
3235
3236 $objp->price_by_qty_rowid = $objp2->rowid;
3237 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3238 $objp->price_by_qty_quantity = $objp2->quantity;
3239 $objp->price_by_qty_unitprice = $objp2->unitprice;
3240 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3241 // For backward compatibility
3242 $objp->quantity = $objp2->quantity;
3243 $objp->price = $objp2->price;
3244 $objp->unitprice = $objp2->unitprice;
3245 $objp->remise_percent = $objp2->remise_percent;
3246
3247 //$objp->tva_tx is not overwritten by $objp2 value
3248 //$objp->default_vat_code is not overwritten by $objp2 value
3249
3250 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3251 '@phan-var-force array{key:string,value:string,label:string,label2:string,desc:string,type:string,price_ht:string,price_ttc:string,price_ht_locale:string,price_ttc_locale:string,pricebasetype:string,tva_tx:string,default_vat_code:string,qty:string,discount:string,duration_value:string,duration_unit:string,pbq:string,labeltrans:string,desctrans:string,ref_customer:string} $optJson';
3252 $j++;
3253
3254 // Add new entry
3255 // "key" value of json key array is used by jQuery automatically as selected value
3256 // "label" value of json key array is used by jQuery automatically as text for combo box
3257 $out .= $opt;
3258 array_push($outarray, $optJson);
3259 }
3260 }
3261 } else {
3262 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3263 $price_product = new Product($this->db);
3264 $price_product->fetch($objp->rowid, '', '', 1);
3265
3266 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3267 $priceparser = new PriceParser($this->db);
3268 $price_result = $priceparser->parseProduct($price_product);
3269 if ($price_result >= 0) {
3270 $objp->price = $price_result;
3271 $objp->unitprice = $price_result;
3272 //Calculate the VAT
3273 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3274 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3275 }
3276 }
3277 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3278 $price_level = '';
3279 }
3280 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3281 // Add new entry
3282 // "key" value of json key array is used by jQuery automatically as selected value
3283 // "label" value of json key array is used by jQuery automatically as text for combo box
3284 $out .= $opt;
3285 array_push($outarray, $optJson);
3286 }
3287
3288 $i++;
3289 }
3290
3291 $out .= '</select>';
3292
3293 $this->db->free($result);
3294
3295 if (empty($outputmode)) {
3296 return $out;
3297 }
3298
3299 return $outarray;
3300 } else {
3301 dol_print_error($this->db);
3302 }
3303
3304 return '';
3305 }
3306
3322 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3323 {
3324 global $langs, $conf, $user;
3325 global $hookmanager;
3326
3327 $outkey = '';
3328 $outval = '';
3329 $outref = '';
3330 $outlabel = '';
3331 $outlabel_translated = '';
3332 $outdesc = '';
3333 $outdesc_translated = '';
3334 $outbarcode = '';
3335 $outorigin = '';
3336 $outtype = '';
3337 $outprice_ht = '';
3338 $outprice_ttc = '';
3339 $outpricebasetype = '';
3340 $outtva_tx = '';
3341 $outdefault_vat_code = '';
3342 $outqty = 1;
3343 $outdiscount = 0;
3344
3345 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3346
3347 $label = $objp->label;
3348 if (!empty($objp->label_translated)) {
3349 $label = $objp->label_translated;
3350 }
3351 if (!empty($filterkey) && $filterkey != '') {
3352 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3353 }
3354
3355 $outkey = $objp->rowid;
3356 $outref = $objp->ref;
3357 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3358 $outlabel = $objp->label;
3359 $outdesc = $objp->description;
3360 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3361 $outlabel_translated = $objp->label_translated;
3362 $outdesc_translated = $objp->description_translated;
3363 }
3364 $outbarcode = $objp->barcode;
3365 $outorigin = $objp->fk_country;
3366 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3367
3368 $outtype = $objp->fk_product_type;
3369 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3370 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3371
3372 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3373 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3374 }
3375
3376 // Units
3377 $outvalUnits = '';
3378 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3379 if (!empty($objp->unit_short)) {
3380 $outvalUnits .= ' - ' . $objp->unit_short;
3381 }
3382 }
3383 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3384 if (!empty($objp->weight) && $objp->weight_units !== null) {
3385 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3386 $outvalUnits .= ' - ' . $unitToShow;
3387 }
3388 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3389 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3390 $outvalUnits .= ' - ' . $unitToShow;
3391 }
3392 if (!empty($objp->surface) && $objp->surface_units !== null) {
3393 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3394 $outvalUnits .= ' - ' . $unitToShow;
3395 }
3396 if (!empty($objp->volume) && $objp->volume_units !== null) {
3397 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3398 $outvalUnits .= ' - ' . $unitToShow;
3399 }
3400 }
3401 if ($outdurationvalue && $outdurationunit) {
3402 $da = array(
3403 'h' => $langs->trans('Hour'),
3404 'd' => $langs->trans('Day'),
3405 'w' => $langs->trans('Week'),
3406 'm' => $langs->trans('Month'),
3407 'y' => $langs->trans('Year')
3408 );
3409 if (isset($da[$outdurationunit])) {
3410 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3411 }
3412 }
3413
3414 // Set stocktag (stock too low or not or unknown)
3415 $stocktag = 0;
3416 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3417 if ($user->hasRight('stock', 'lire')) {
3418 if ($objp->stock > 0) {
3419 $stocktag = 1;
3420 } elseif ($objp->stock <= 0) {
3421 $stocktag = -1;
3422 }
3423 }
3424 }
3425
3426 // Set $labeltoshow
3427 $labeltoshow = '';
3428 $labeltoshow .= $objp->ref;
3429 if (!empty($objp->custref)) {
3430 $labeltoshow .= ' (' . $objp->custref . ')';
3431 }
3432 if ($outbarcode) {
3433 $labeltoshow .= ' (' . $outbarcode . ')';
3434 }
3435 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3436 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3437 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3438 }
3439
3440 // Set $labltoshowhtml
3441 $labeltoshowhtml = '';
3442 $labeltoshowhtml .= $objp->ref;
3443 if (!empty($objp->custref)) {
3444 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3445 }
3446 if (!empty($filterkey) && $filterkey != '') {
3447 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3448 }
3449 if ($outbarcode) {
3450 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3451 }
3452 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3453 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3454 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3455 }
3456
3457 // Stock
3458 $labeltoshowstock = '';
3459 $labeltoshowhtmlstock = '';
3460 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3461 if ($user->hasRight('stock', 'lire')) {
3462 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3463
3464 if ($objp->stock > 0) {
3465 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3466 } elseif ($objp->stock <= 0) {
3467 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3468 }
3469 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3470 $labeltoshowhtmlstock .= '</span>';
3471
3472 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3473 $langs->load("stocks");
3474
3475 $tmpproduct = new Product($this->db);
3476 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3477 $tmpproduct->load_virtual_stock();
3478 $virtualstock = $tmpproduct->stock_theorique;
3479
3480 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3481
3482 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3483 if ($virtualstock > 0) {
3484 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3485 } elseif ($virtualstock <= 0) {
3486 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3487 }
3488 $labeltoshowhtmlstock .= $virtualstock;
3489 $labeltoshowhtmlstock .= '</span>';
3490
3491 unset($tmpproduct);
3492 }
3493 }
3494 }
3495
3496 // Price
3497 $found = 0;
3498 $labeltoshowprice = '';
3499 $labeltoshowhtmlprice = '';
3500 // If we need a particular price level (from 1 to n)
3501 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3502 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3503 $sql .= " FROM " . $this->db->prefix() . "product_price";
3504 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3505 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3506 $sql .= " AND price_level = " . ((int) $price_level);
3507 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3508 $sql .= " LIMIT 1";
3509
3510 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3511 $result2 = $this->db->query($sql);
3512 if ($result2) {
3513 $objp2 = $this->db->fetch_object($result2);
3514 if ($objp2) {
3515 $found = 1;
3516 if ($objp2->price_base_type == 'HT') {
3517 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3518 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3519 } else {
3520 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3521 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3522 }
3523 $outprice_ht = price($objp2->price);
3524 $outprice_ttc = price($objp2->price_ttc);
3525 $outpricebasetype = $objp2->price_base_type;
3526 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3527 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3528 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3529 } else {
3530 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3531 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3532 }
3533 }
3534 } else {
3535 dol_print_error($this->db);
3536 }
3537 }
3538
3539 // Price by quantity
3540 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3541 $found = 1;
3542 $outqty = $objp->quantity;
3543 $outdiscount = $objp->remise_percent;
3544 if ($objp->quantity == 1) {
3545 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3546 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3547 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3548 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3549 } else {
3550 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3551 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3552 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3553 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3554 }
3555
3556 $outprice_ht = price($objp->unitprice);
3557 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3558 $outpricebasetype = $objp->price_base_type;
3559 $outtva_tx = $objp->tva_tx; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3560 $outdefault_vat_code = $objp->default_vat_code; // This value is the value on product when constructProductListOption is called by select_produits_list even if other field $objp-> are from table price_by_qty
3561 }
3562 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3563 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3564 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3565 }
3566 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3567 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3568 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3569 }
3570
3571 // Price by customer
3572 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3573 if (!empty($objp->idprodcustprice)) {
3574 $found = 1;
3575
3576 if ($objp->custprice_base_type == 'HT') {
3577 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3578 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3579 } else {
3580 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3581 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3582 }
3583
3584 $outprice_ht = price($objp->custprice);
3585 $outprice_ttc = price($objp->custprice_ttc);
3586 $outpricebasetype = $objp->custprice_base_type;
3587 $outtva_tx = $objp->custtva_tx;
3588 $outdefault_vat_code = $objp->custdefault_vat_code;
3589 }
3590 }
3591
3592 // If level no defined or multiprice not found, we used the default price
3593 if (empty($hidepriceinlabel) && !$found) {
3594 if ($objp->price_base_type == 'HT') {
3595 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3596 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3597 } else {
3598 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3599 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3600 }
3601 $outprice_ht = price($objp->price);
3602 $outprice_ttc = price($objp->price_ttc);
3603 $outpricebasetype = $objp->price_base_type;
3604 $outtva_tx = $objp->tva_tx;
3605 $outdefault_vat_code = $objp->default_vat_code;
3606 }
3607
3608 // Build options
3609 $opt = '<option value="' . $objp->rowid . '"';
3610 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3611 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3612 $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 . '"';
3613 }
3614 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3615 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3616 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3617 }
3618
3619 if ($stocktag == 1) {
3620 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3621 //$opt .= ' class="product_line_stock_ok"';
3622 }
3623 if ($stocktag == -1) {
3624 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3625 //$opt .= ' class="product_line_stock_too_low"';
3626 }
3627
3628 $opt .= '>';
3629
3630 // Ref, barcode, country
3631 $opt .= $labeltoshow;
3632 $outval .= $labeltoshowhtml;
3633
3634 // Units
3635 $opt .= $outvalUnits;
3636 $outval .= $outvalUnits;
3637
3638 // Price
3639 $opt .= $labeltoshowprice;
3640 $outval .= $labeltoshowhtmlprice;
3641
3642 // Stock
3643 $opt .= $labeltoshowstock;
3644 $outval .= $labeltoshowhtmlstock;
3645
3646
3647 $parameters = array('objp' => $objp);
3648 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3649 if (empty($reshook)) {
3650 $opt .= $hookmanager->resPrint;
3651 } else {
3652 $opt = $hookmanager->resPrint;
3653 }
3654
3655 $opt .= "</option>\n";
3656 $optJson = array(
3657 'key' => $outkey,
3658 'value' => $outref,
3659 'label' => $outval,
3660 'label2' => $outlabel,
3661 'desc' => $outdesc,
3662 'type' => $outtype,
3663 'price_ht' => price2num($outprice_ht),
3664 'price_ttc' => price2num($outprice_ttc),
3665 'price_ht_locale' => price(price2num($outprice_ht)),
3666 'price_ttc_locale' => price(price2num($outprice_ttc)),
3667 'pricebasetype' => $outpricebasetype,
3668 'tva_tx' => $outtva_tx,
3669 'default_vat_code' => $outdefault_vat_code,
3670 'qty' => $outqty,
3671 'discount' => $outdiscount,
3672 'duration_value' => $outdurationvalue,
3673 'duration_unit' => $outdurationunit,
3674 'pbq' => $outpbq,
3675 'labeltrans' => $outlabel_translated,
3676 'desctrans' => $outdesc_translated,
3677 'ref_customer' => $outrefcust
3678 );
3679 }
3680
3681 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3682
3698 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3699 {
3700 // phpcs:enable
3701 global $langs, $conf;
3702 global $price_level, $status, $finished;
3703
3704 if (!isset($status)) {
3705 $status = 1;
3706 }
3707
3708 $selected_input_value = '';
3709 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3710 if ($selected > 0) {
3711 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3712 $producttmpselect = new Product($this->db);
3713 $producttmpselect->fetch($selected);
3714 $selected_input_value = $producttmpselect->ref;
3715 unset($producttmpselect);
3716 }
3717
3718 // mode=2 means suppliers products
3719 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3720 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3721
3722 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3723 } else {
3724 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3725 }
3726 }
3727
3728 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3729
3748 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 = '')
3749 {
3750 // phpcs:enable
3751 global $langs, $conf, $user;
3752 global $hookmanager;
3753
3754 $out = '';
3755 $outarray = array();
3756
3757 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3758
3759 $langs->load('stocks');
3760 // Units
3761 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3762 $langs->load('other');
3763 }
3764
3765 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, p.fk_product_type, p.stock, p.tva_tx as tva_tx_sale, p.default_vat_code as default_vat_code_sale,";
3766 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3767 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3768 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3769 $sql .= ", pfp.supplier_reputation";
3770 // if we use supplier description of the products
3771 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3772 $sql .= ", pfp.desc_fourn as description";
3773 } else {
3774 $sql .= ", p.description";
3775 }
3776 // Units
3777 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3778 $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";
3779 }
3780 $sql .= " FROM " . $this->db->prefix() . "product as p";
3781 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3782 if ($socid > 0) {
3783 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3784 }
3785 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3786 // Units
3787 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3788 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3789 }
3790 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3791 if ($statut != -1) {
3792 $sql .= " AND p.tobuy = " . ((int) $statut);
3793 }
3794 if (strval($filtertype) != '') {
3795 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3796 }
3797 if (!empty($filtre)) {
3798 $sql .= " " . $filtre;
3799 }
3800 // Add where from hooks
3801 $parameters = array();
3802 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3803 $sql .= $hookmanager->resPrint;
3804 // Add criteria on ref/label
3805 if ($filterkey != '') {
3806 $sql .= ' AND (';
3807 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3808 // For natural search
3809 $search_crit = explode(' ', $filterkey);
3810 $i = 0;
3811 if (count($search_crit) > 1) {
3812 $sql .= "(";
3813 }
3814 foreach ($search_crit as $crit) {
3815 if ($i > 0) {
3816 $sql .= " AND ";
3817 }
3818 $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) . "%'";
3819 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3820 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3821 }
3822 $sql .= ")";
3823 $i++;
3824 }
3825 if (count($search_crit) > 1) {
3826 $sql .= ")";
3827 }
3828 if (isModEnabled('barcode')) {
3829 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3830 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3831 }
3832 $sql .= ')';
3833 }
3834 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3835 $sql .= $this->db->plimit($limit, 0);
3836
3837 // Build output string
3838
3839 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3840 $result = $this->db->query($sql);
3841 if ($result) {
3842 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3843 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3844
3845 $num = $this->db->num_rows($result);
3846
3847 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3848 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3849 if (!$selected) {
3850 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3851 } else {
3852 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3853 }
3854
3855 $i = 0;
3856 while ($i < $num) {
3857 $objp = $this->db->fetch_object($result);
3858
3859 if (is_null($objp->idprodfournprice)) {
3860 // There is no supplier price found, we will use the vat rate for sale
3861 $objp->tva_tx = $objp->tva_tx_sale;
3862 $objp->default_vat_code = $objp->default_vat_code_sale;
3863 }
3864
3865 $outkey = $objp->idprodfournprice; // id in table of price
3866 if (!$outkey && $alsoproductwithnosupplierprice) {
3867 $outkey = 'idprod_' . $objp->rowid; // id of product
3868 }
3869
3870 $outref = $objp->ref;
3871 $outbarcode = $objp->barcode;
3872 $outqty = 1;
3873 $outdiscount = 0;
3874 $outtype = $objp->fk_product_type;
3875 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3876 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3877
3878 // Units
3879 $outvalUnits = '';
3880 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3881 if (!empty($objp->unit_short)) {
3882 $outvalUnits .= ' - ' . $objp->unit_short;
3883 }
3884 if (!empty($objp->weight) && $objp->weight_units !== null) {
3885 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3886 $outvalUnits .= ' - ' . $unitToShow;
3887 }
3888 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3889 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3890 $outvalUnits .= ' - ' . $unitToShow;
3891 }
3892 if (!empty($objp->surface) && $objp->surface_units !== null) {
3893 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3894 $outvalUnits .= ' - ' . $unitToShow;
3895 }
3896 if (!empty($objp->volume) && $objp->volume_units !== null) {
3897 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3898 $outvalUnits .= ' - ' . $unitToShow;
3899 }
3900 if ($outdurationvalue && $outdurationunit) {
3901 $da = array(
3902 'h' => $langs->trans('Hour'),
3903 'd' => $langs->trans('Day'),
3904 'w' => $langs->trans('Week'),
3905 'm' => $langs->trans('Month'),
3906 'y' => $langs->trans('Year')
3907 );
3908 if (isset($da[$outdurationunit])) {
3909 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3910 }
3911 }
3912 }
3913
3914 $objRef = $objp->ref;
3915 if ($filterkey && $filterkey != '') {
3916 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3917 }
3918 $objRefFourn = $objp->ref_fourn;
3919 if ($filterkey && $filterkey != '') {
3920 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3921 }
3922 $label = $objp->label;
3923 if ($filterkey && $filterkey != '') {
3924 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3925 }
3926
3927 switch ($objp->fk_product_type) {
3929 $picto = 'product';
3930 break;
3932 $picto = 'service';
3933 break;
3934 default:
3935 $picto = '';
3936 break;
3937 }
3938
3939 if (empty($picto)) {
3940 $optlabel = '';
3941 } else {
3942 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3943 }
3944
3945 $optlabel .= $objp->ref;
3946 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3947 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3948 }
3949 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3950 $optlabel .= ' (' . $outbarcode . ')';
3951 }
3952 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3953
3954 $outvallabel = $objRef;
3955 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3956 $outvallabel .= ' (' . $objRefFourn . ')';
3957 }
3958 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3959 $outvallabel .= ' (' . $outbarcode . ')';
3960 }
3961 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3962
3963 // Units
3964 $optlabel .= $outvalUnits;
3965 $outvallabel .= $outvalUnits;
3966
3967 if (!empty($objp->idprodfournprice)) {
3968 $outqty = $objp->quantity;
3969 $outdiscount = $objp->remise_percent;
3970 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3971 $prod_supplier = new ProductFournisseur($this->db);
3972 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3973 $prod_supplier->id = $objp->fk_product;
3974 $prod_supplier->fourn_qty = $objp->quantity;
3975 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3976 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3977
3978 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3979 $priceparser = new PriceParser($this->db);
3980 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3981 if ($price_result >= 0) {
3982 $objp->fprice = $price_result;
3983 if ($objp->quantity >= 1) {
3984 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3985 }
3986 }
3987 }
3988 if ($objp->quantity == 1) {
3989 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3990 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3991 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3992 $outvallabel .= $langs->transnoentities("Unit");
3993 } else {
3994 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3995 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3996 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3997 $outvallabel .= ' ' . $langs->transnoentities("Units");
3998 }
3999
4000 if ($objp->quantity > 1) {
4001 $optlabel .= " (" . price($objp->unitprice * (getDolGlobalString('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
4002 $outvallabel .= " (" . price($objp->unitprice * (getDolGlobalString('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
4003 }
4004 if ($objp->remise_percent >= 1) {
4005 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4006 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
4007 }
4008 if ($objp->duration) {
4009 $optlabel .= " - " . $objp->duration;
4010 $outvallabel .= " - " . $objp->duration;
4011 }
4012 if (!$socid) {
4013 $optlabel .= " - " . dol_trunc($objp->name, 8);
4014 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4015 }
4016 if ($objp->supplier_reputation) {
4017 //TODO dictionary
4018 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4019
4020 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4021 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4022 }
4023 } else {
4024 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4025 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4026 }
4027
4028 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4029 $novirtualstock = ($showstockinlist == 2);
4030
4031 if ($user->hasRight('stock', 'lire')) {
4032 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4033
4034 if ($objp->stock > 0) {
4035 $optlabel .= ' - <span class="product_line_stock_ok">';
4036 } elseif ($objp->stock <= 0) {
4037 $optlabel .= ' - <span class="product_line_stock_too_low">';
4038 }
4039 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4040 $optlabel .= '</span>';
4041 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4042 $langs->load("stocks");
4043
4044 $tmpproduct = new Product($this->db);
4045 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4046 $tmpproduct->load_virtual_stock();
4047 $virtualstock = $tmpproduct->stock_theorique;
4048
4049 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4050
4051 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4052 if ($virtualstock > 0) {
4053 $optlabel .= '<span class="product_line_stock_ok">';
4054 } elseif ($virtualstock <= 0) {
4055 $optlabel .= '<span class="product_line_stock_too_low">';
4056 }
4057 $optlabel .= $virtualstock;
4058 $optlabel .= '</span>';
4059
4060 unset($tmpproduct);
4061 }
4062 }
4063 }
4064
4065 $optstart = '<option value="' . $outkey . '"';
4066 if ($selected && $selected == $objp->idprodfournprice) {
4067 $optstart .= ' selected';
4068 }
4069 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4070 $optstart .= ' disabled';
4071 }
4072
4073 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4074 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4075 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4076 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4077 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"'; // the price with numeric international format
4078 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"'; // the price formatted in user language
4079 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4080 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"'; // the rate with numeric international format
4081 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"'; // the rate formatted in user language
4082 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4083 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4084 if (isModEnabled('multicurrency')) {
4085 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4086 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag(price2num($objp->multicurrency_unitprice)) . '"'; // the price with numeric international format
4087 }
4088 }
4089 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4090
4091 // set $parameters to call hook
4092 $outarrayentry = array(
4093 'key' => $outkey,
4094 'value' => $outref,
4095 'label' => $outvallabel,
4096 'labelhtml' => $optlabel,
4097 'qty' => $outqty,
4098 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4099 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4100 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4101 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4102 'tva_tx' => price2num($objp->tva_tx),
4103 'default_vat_code' => $objp->default_vat_code,
4104 'supplier_ref' => $objp->ref_fourn,
4105 'discount' => $outdiscount,
4106 'type' => $outtype,
4107 'duration_value' => $outdurationvalue,
4108 'duration_unit' => $outdurationunit,
4109 'disabled' => empty($objp->idprodfournprice),
4110 'description' => $objp->description
4111 );
4112 if (isModEnabled('multicurrency')) {
4113 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4114 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4115 }
4116 $parameters = array(
4117 'objp' => &$objp,
4118 'optstart' => &$optstart,
4119 'optlabel' => &$optlabel,
4120 'outvallabel' => &$outvallabel,
4121 'outarrayentry' => &$outarrayentry,
4122 'fk_soc' => $socid
4123 );
4124 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4125
4126
4127 // Add new entry
4128 // "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
4129 // "label" value of json key array is used by jQuery automatically as text for combo box
4130 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4131 $outarraypush = array(
4132 'key' => $outkey,
4133 'value' => $outref,
4134 'label' => $outvallabel,
4135 'labelhtml' => $optlabel,
4136 'qty' => $outqty,
4137 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4138 'price_qty_ht_locale' => price($objp->fprice),
4139 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4140 'price_unit_ht_locale' => price($objp->unitprice),
4141 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4142 'tva_tx_formated' => price($objp->tva_tx),
4143 'tva_tx' => price2num($objp->tva_tx),
4144 'default_vat_code' => $objp->default_vat_code,
4145 'supplier_ref' => $objp->ref_fourn,
4146 'discount' => $outdiscount,
4147 'type' => $outtype,
4148 'duration_value' => $outdurationvalue,
4149 'duration_unit' => $outdurationunit,
4150 'disabled' => empty($objp->idprodfournprice),
4151 'description' => $objp->description
4152 );
4153 if (isModEnabled('multicurrency')) {
4154 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4155 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4156 }
4157 array_push($outarray, $outarraypush);
4158
4159 // Example of var_dump $outarray
4160 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4161 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4162 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4163 //}
4164 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4165 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4166 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4167
4168 $i++;
4169 }
4170 $out .= '</select>';
4171
4172 $this->db->free($result);
4173
4174 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4175 $out .= ajax_combobox($htmlname);
4176 } else {
4177 dol_print_error($this->db);
4178 }
4179
4180 if (empty($outputmode)) {
4181 return $out;
4182 }
4183 return $outarray;
4184 }
4185
4186 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4187
4196 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4197 {
4198 // phpcs:enable
4199 global $langs, $conf;
4200
4201 $langs->load('stocks');
4202
4203 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4204 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4205 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4206 $sql .= " FROM " . $this->db->prefix() . "product as p";
4207 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4208 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4209 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4210 $sql .= " AND p.tobuy = 1";
4211 $sql .= " AND s.fournisseur = 1";
4212 $sql .= " AND p.rowid = " . ((int) $productid);
4213 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4214 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4215 } else {
4216 $sql .= " ORDER BY pfp.unitprice ASC";
4217 }
4218
4219 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4220 $result = $this->db->query($sql);
4221
4222 if ($result) {
4223 $num = $this->db->num_rows($result);
4224
4225 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4226
4227 if (!$num) {
4228 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4229 } else {
4230 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4231 $form .= '<option value="0">&nbsp;</option>';
4232
4233 $i = 0;
4234 while ($i < $num) {
4235 $objp = $this->db->fetch_object($result);
4236
4237 $opt = '<option value="' . $objp->idprodfournprice . '"';
4238 //if there is only one supplier, preselect it
4239 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4240 $opt .= ' selected';
4241 }
4242 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4243
4244 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4245 $prod_supplier = new ProductFournisseur($this->db);
4246 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4247 $prod_supplier->id = $productid;
4248 $prod_supplier->fourn_qty = $objp->quantity;
4249 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4250 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4251
4252 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4253 $priceparser = new PriceParser($this->db);
4254 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4255 if ($price_result >= 0) {
4256 $objp->fprice = $price_result;
4257 if ($objp->quantity >= 1) {
4258 $objp->unitprice = $objp->fprice / $objp->quantity;
4259 }
4260 }
4261 }
4262 if ($objp->quantity == 1) {
4263 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4264 }
4265
4266 $opt .= $objp->quantity . ' ';
4267
4268 if ($objp->quantity == 1) {
4269 $opt .= $langs->trans("Unit");
4270 } else {
4271 $opt .= $langs->trans("Units");
4272 }
4273 if ($objp->quantity > 1) {
4274 $opt .= " - ";
4275 $opt .= price($objp->unitprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit");
4276 }
4277 if ($objp->duration) {
4278 $opt .= " - " . $objp->duration;
4279 }
4280 $opt .= "</option>\n";
4281
4282 $form .= $opt;
4283 $i++;
4284 }
4285 }
4286
4287 $form .= '</select>';
4288 $this->db->free($result);
4289 return $form;
4290 } else {
4291 dol_print_error($this->db);
4292 return '';
4293 }
4294 }
4295
4296
4297 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4304 {
4305 // phpcs:enable
4306 global $langs;
4307
4308 $num = count($this->cache_conditions_paiements);
4309 if ($num > 0) {
4310 return 0; // Cache already loaded
4311 }
4312
4313 dol_syslog(__METHOD__, LOG_DEBUG);
4314
4315 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4316 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4317 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4318 $sql .= " AND active > 0";
4319 $sql .= " ORDER BY sortorder";
4320
4321 $resql = $this->db->query($sql);
4322 if ($resql) {
4323 $num = $this->db->num_rows($resql);
4324 $i = 0;
4325 while ($i < $num) {
4326 $obj = $this->db->fetch_object($resql);
4327
4328 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4329 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4330 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4331 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4332 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4333 $i++;
4334 }
4335
4336 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4337
4338 return $num;
4339 } else {
4340 dol_print_error($this->db);
4341 return -1;
4342 }
4343 }
4344
4345 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4346
4352 public function load_cache_availability()
4353 {
4354 // phpcs:enable
4355 global $langs;
4356
4357 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4358 if ($num > 0) {
4359 return 0; // Cache already loaded
4360 }
4361
4362 dol_syslog(__METHOD__, LOG_DEBUG);
4363
4364 $langs->load('propal');
4365
4366 $sql = "SELECT rowid, code, label, position";
4367 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4368 $sql .= " WHERE active > 0";
4369
4370 $resql = $this->db->query($sql);
4371 if ($resql) {
4372 $num = $this->db->num_rows($resql);
4373 $i = 0;
4374 while ($i < $num) {
4375 $obj = $this->db->fetch_object($resql);
4376
4377 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4378 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4379 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4380 $this->cache_availability[$obj->rowid]['label'] = $label;
4381 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4382 $i++;
4383 }
4384
4385 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4386
4387 return $num;
4388 } else {
4389 dol_print_error($this->db);
4390 return -1;
4391 }
4392 }
4393
4404 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4405 {
4406 global $langs, $user;
4407
4408 $this->load_cache_availability();
4409
4410 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4411
4412 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4413 if ($addempty) {
4414 print '<option value="0">&nbsp;</option>';
4415 }
4416 foreach ($this->cache_availability as $id => $arrayavailability) {
4417 if ($selected == $id) {
4418 print '<option value="' . $id . '" selected>';
4419 } else {
4420 print '<option value="' . $id . '">';
4421 }
4422 print dol_escape_htmltag($arrayavailability['label']);
4423 print '</option>';
4424 }
4425 print '</select>';
4426 if ($user->admin) {
4427 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4428 }
4429 print ajax_combobox($htmlname);
4430 }
4431
4437 public function loadCacheInputReason()
4438 {
4439 global $langs;
4440
4441 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4442 if ($num > 0) {
4443 return 0; // Cache already loaded
4444 }
4445
4446 $sql = "SELECT rowid, code, label";
4447 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4448 $sql .= " WHERE active > 0";
4449
4450 $resql = $this->db->query($sql);
4451 if ($resql) {
4452 $num = $this->db->num_rows($resql);
4453 $i = 0;
4454 $tmparray = array();
4455 while ($i < $num) {
4456 $obj = $this->db->fetch_object($resql);
4457
4458 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4459 $label = ($obj->label != '-' ? $obj->label : '');
4460 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4461 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4462 }
4463 if ($langs->trans($obj->code) != $obj->code) {
4464 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4465 }
4466
4467 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4468 $tmparray[$obj->rowid]['code'] = $obj->code;
4469 $tmparray[$obj->rowid]['label'] = $label;
4470 $i++;
4471 }
4472
4473 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4474
4475 unset($tmparray);
4476 return $num;
4477 } else {
4478 dol_print_error($this->db);
4479 return -1;
4480 }
4481 }
4482
4495 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4496 {
4497 global $langs, $user;
4498
4499 $this->loadCacheInputReason();
4500
4501 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4502 if ($addempty) {
4503 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4504 }
4505 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4506 if ($arraydemandreason['code'] == $exclude) {
4507 continue;
4508 }
4509
4510 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4511 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4512 } else {
4513 print '<option value="' . $arraydemandreason['id'] . '">';
4514 }
4515 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4516 print $langs->trans($label);
4517 print '</option>';
4518 }
4519 print '</select>';
4520 if ($user->admin && empty($notooltip)) {
4521 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4522 }
4523 print ajax_combobox('select_' . $htmlname);
4524 }
4525
4526 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4527
4534 {
4535 // phpcs:enable
4536 global $langs;
4537
4538 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4539 if ($num > 0) {
4540 return $num; // Cache already loaded
4541 }
4542
4543 dol_syslog(__METHOD__, LOG_DEBUG);
4544
4545 $this->cache_types_paiements = array();
4546
4547 $sql = "SELECT id, code, libelle as label, type, active";
4548 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4549 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4550
4551 $resql = $this->db->query($sql);
4552 if ($resql) {
4553 $num = $this->db->num_rows($resql);
4554 $i = 0;
4555 while ($i < $num) {
4556 $obj = $this->db->fetch_object($resql);
4557
4558 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4559 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4560 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4561 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4562 $this->cache_types_paiements[$obj->id]['label'] = $label;
4563 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4564 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4565 $i++;
4566 }
4567
4568 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4569
4570 return $num;
4571 } else {
4572 dol_print_error($this->db);
4573 return -1;
4574 }
4575 }
4576
4577
4578 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4579
4598 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4599 {
4600 // phpcs:enable
4601 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4602 if (empty($noprint)) {
4603 print $out;
4604 } else {
4605 return $out;
4606 }
4607 }
4608
4609
4626 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4627 {
4628 global $langs, $user, $conf;
4629
4630 $out = '';
4631 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4632
4634
4635 // Set default value if not already set by caller
4636 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4637 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4638 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4639 }
4640
4641 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4642 if ($addempty) {
4643 $out .= '<option value="0">&nbsp;</option>';
4644 }
4645
4646 $selectedDepositPercent = null;
4647
4648 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4649 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4650 continue;
4651 }
4652
4653 if ($selected == $id) {
4654 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4655 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4656 } else {
4657 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4658 }
4659 $label = $arrayconditions['label'];
4660
4661 if (!empty($arrayconditions['deposit_percent'])) {
4662 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4663 }
4664
4665 $out .= $label;
4666 $out .= '</option>';
4667 }
4668 $out .= '</select>';
4669 if ($user->admin && empty($noinfoadmin)) {
4670 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4671 }
4672 $out .= ajax_combobox($htmlname);
4673
4674 if ($deposit_percent >= 0) {
4675 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4676 $out .= $langs->trans('DepositPercent') . ' : ';
4677 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4678 $out .= '</span>';
4679 $out .= '
4680 <script nonce="' . getNonce() . '">
4681 $(document).ready(function () {
4682 $("#' . $htmlname . '").change(function () {
4683 let $selected = $(this).find("option:selected");
4684 let depositPercent = $selected.attr("data-deposit_percent");
4685
4686 if (depositPercent.length > 0) {
4687 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4688 } else {
4689 $("#' . $htmlname . '_deposit_percent_container").hide();
4690 }
4691
4692 return true;
4693 });
4694 });
4695 </script>';
4696 }
4697
4698 return $out;
4699 }
4700
4701
4702 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4703
4720 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4721 {
4722 // phpcs:enable
4723 global $langs, $user, $conf;
4724
4725 $out = '';
4726
4727 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4728
4729 $filterarray = array();
4730 if ($filtertype == 'CRDT') {
4731 $filterarray = array(0, 2, 3);
4732 } elseif ($filtertype == 'DBIT') {
4733 $filterarray = array(1, 2, 3);
4734 } elseif ($filtertype != '' && $filtertype != '-1') {
4735 $filterarray = explode(',', $filtertype);
4736 }
4737
4739
4740 // Set default value if not already set by caller
4741 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4742 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4743 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4744 }
4745
4746 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4747 if ($empty) {
4748 $out .= '<option value="">&nbsp;</option>';
4749 }
4750 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4751 // If not good status
4752 if ($active >= 0 && $arraytypes['active'] != $active) {
4753 continue;
4754 }
4755
4756 // We skip of the user requested to filter on specific payment methods
4757 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4758 continue;
4759 }
4760
4761 // We discard empty lines if showempty is on because an empty line has already been output.
4762 if ($empty && empty($arraytypes['code'])) {
4763 continue;
4764 }
4765
4766 if ($format == 0) {
4767 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
4768 } elseif ($format == 1) {
4769 $out .= '<option value="' . $arraytypes['code'] . '"';
4770 } elseif ($format == 2) {
4771 $out .= '<option value="' . $arraytypes['code'] . '"';
4772 } elseif ($format == 3) {
4773 $out .= '<option value="' . $id . '"';
4774 }
4775 // Print attribute selected or not
4776 if ($format == 1 || $format == 2) {
4777 if ($selected == $arraytypes['code']) {
4778 $out .= ' selected';
4779 }
4780 } else {
4781 if ($selected == $id) {
4782 $out .= ' selected';
4783 }
4784 }
4785 $out .= '>';
4786 $value = '';
4787 if ($format == 0) {
4788 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4789 } elseif ($format == 1) {
4790 $value = $arraytypes['code'];
4791 } elseif ($format == 2) {
4792 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4793 } elseif ($format == 3) {
4794 $value = $arraytypes['code'];
4795 }
4796 $out .= $value ? $value : '&nbsp;';
4797 $out .= '</option>';
4798 }
4799 $out .= '</select>';
4800 if ($user->admin && !$noadmininfo) {
4801 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4802 }
4803 $out .= ajax_combobox('select' . $htmlname);
4804
4805 if (empty($nooutput)) {
4806 print $out;
4807 } else {
4808 return $out;
4809 }
4810 }
4811
4812
4821 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4822 {
4823 global $langs;
4824
4825 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4826 $options = array(
4827 'HT' => $langs->trans("HT"),
4828 'TTC' => $langs->trans("TTC")
4829 );
4830 foreach ($options as $id => $value) {
4831 if ($selected == $id) {
4832 $return .= '<option value="' . $id . '" selected>' . $value;
4833 } else {
4834 $return .= '<option value="' . $id . '">' . $value;
4835 }
4836 $return .= '</option>';
4837 }
4838 $return .= '</select>';
4839 if ($addjscombo) {
4840 $return .= ajax_combobox('select_' . $htmlname);
4841 }
4842
4843 return $return;
4844 }
4845
4846 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4847
4854 {
4855 // phpcs:enable
4856 global $langs;
4857
4858 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4859 if ($num > 0) {
4860 return $num; // Cache already loaded
4861 }
4862
4863 dol_syslog(__METHOD__, LOG_DEBUG);
4864
4865 $this->cache_transport_mode = array();
4866
4867 $sql = "SELECT rowid, code, label, active";
4868 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4869 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4870
4871 $resql = $this->db->query($sql);
4872 if ($resql) {
4873 $num = $this->db->num_rows($resql);
4874 $i = 0;
4875 while ($i < $num) {
4876 $obj = $this->db->fetch_object($resql);
4877
4878 // If traduction exist, we use it else we take the default label
4879 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4880 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4881 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4882 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4883 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4884 $i++;
4885 }
4886
4887 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4888
4889 return $num;
4890 } else {
4891 dol_print_error($this->db);
4892 return -1;
4893 }
4894 }
4895
4909 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4910 {
4911 global $langs, $user;
4912
4913 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4914
4916
4917 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4918 if ($empty) {
4919 print '<option value="">&nbsp;</option>';
4920 }
4921 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4922 // If not good status
4923 if ($active >= 0 && $arraytypes['active'] != $active) {
4924 continue;
4925 }
4926
4927 // We discard empty line if showempty is on because an empty line has already been output.
4928 if ($empty && empty($arraytypes['code'])) {
4929 continue;
4930 }
4931
4932 if ($format == 0) {
4933 print '<option value="' . $id . '"';
4934 } elseif ($format == 1) {
4935 print '<option value="' . $arraytypes['code'] . '"';
4936 } elseif ($format == 2) {
4937 print '<option value="' . $arraytypes['code'] . '"';
4938 } elseif ($format == 3) {
4939 print '<option value="' . $id . '"';
4940 }
4941 // If text is selected, we compare with code, else with id
4942 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4943 print ' selected';
4944 } elseif ($selected == $id) {
4945 print ' selected';
4946 }
4947 print '>';
4948 $value = '';
4949 if ($format == 0) {
4950 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4951 } elseif ($format == 1) {
4952 $value = $arraytypes['code'];
4953 } elseif ($format == 2) {
4954 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4955 } elseif ($format == 3) {
4956 $value = $arraytypes['code'];
4957 }
4958 print $value ? $value : '&nbsp;';
4959 print '</option>';
4960 }
4961 print '</select>';
4962
4963 print ajax_combobox("select".$htmlname);
4964
4965 if ($user->admin && !$noadmininfo) {
4966 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4967 }
4968 }
4969
4982 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4983 {
4984 global $langs, $user;
4985
4986 $langs->load("admin");
4987 $langs->load("deliveries");
4988
4989 $sql = "SELECT rowid, code, libelle as label";
4990 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4991 $sql .= " WHERE active > 0";
4992 if ($filtre) {
4993 $sql .= " AND " . $filtre;
4994 }
4995 $sql .= " ORDER BY libelle ASC";
4996
4997 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4998 $result = $this->db->query($sql);
4999 if ($result) {
5000 $num = $this->db->num_rows($result);
5001 $i = 0;
5002 if ($num) {
5003 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5004 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5005 print '<option value="-1">&nbsp;</option>';
5006 }
5007 while ($i < $num) {
5008 $obj = $this->db->fetch_object($result);
5009 if ($selected == $obj->rowid) {
5010 print '<option value="' . $obj->rowid . '" selected>';
5011 } else {
5012 print '<option value="' . $obj->rowid . '">';
5013 }
5014 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5015 print '</option>';
5016 $i++;
5017 }
5018 print "</select>";
5019 if ($user->admin && empty($noinfoadmin)) {
5020 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5021 }
5022
5023 print ajax_combobox('select' . $htmlname);
5024 } else {
5025 print $langs->trans("NoShippingMethodDefined");
5026 }
5027 } else {
5028 dol_print_error($this->db);
5029 }
5030 }
5031
5041 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5042 {
5043 global $langs;
5044
5045 $langs->load("deliveries");
5046
5047 if ($htmlname != "none") {
5048 print '<form method="POST" action="' . $page . '">';
5049 print '<input type="hidden" name="action" value="setshippingmethod">';
5050 print '<input type="hidden" name="token" value="' . newToken() . '">';
5051 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5052 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5053 print '</form>';
5054 } else {
5055 if ($selected) {
5056 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5057 print $langs->trans("SendingMethod" . strtoupper($code));
5058 } else {
5059 print "&nbsp;";
5060 }
5061 }
5062 }
5063
5072 public function selectSituationInvoices($selected = '', $socid = 0)
5073 {
5074 global $langs;
5075
5076 $langs->load('bills');
5077
5078 $opt = '<option value="" selected></option>';
5079 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5080 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5081 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5082 $sql .= ' AND situation_counter >= 1';
5083 $sql .= ' AND fk_soc = ' . (int) $socid;
5084 $sql .= ' AND type <> 2';
5085 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5086 $resql = $this->db->query($sql);
5087
5088 if ($resql && $this->db->num_rows($resql) > 0) {
5089 // Last seen cycle
5090 $ref = 0;
5091 while ($obj = $this->db->fetch_object($resql)) {
5092 //Same cycle ?
5093 if ($obj->situation_cycle_ref != $ref) {
5094 // Just seen this cycle
5095 $ref = $obj->situation_cycle_ref;
5096 //not final ?
5097 if ($obj->situation_final != 1) {
5098 //Not prov?
5099 if (substr($obj->ref, 1, 4) != 'PROV') {
5100 if ($selected == $obj->rowid) {
5101 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5102 } else {
5103 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5104 }
5105 }
5106 }
5107 }
5108 }
5109 } else {
5110 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5111 }
5112 if ($opt == '<option value ="" selected></option>') {
5113 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5114 }
5115 return $opt;
5116 }
5117
5127 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5128 {
5129 global $langs;
5130
5131 $langs->load('products');
5132
5133 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5134
5135 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5136 $sql .= ' WHERE active > 0';
5137 if (!empty($unit_type)) {
5138 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5139 }
5140 $sql .= " ORDER BY sortorder";
5141
5142 $resql = $this->db->query($sql);
5143 if ($resql && $this->db->num_rows($resql) > 0) {
5144 if ($showempty) {
5145 $return .= '<option value="-1"></option>';
5146 }
5147
5148 while ($res = $this->db->fetch_object($resql)) {
5149 $unitLabel = $res->label;
5150 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5151 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5152 }
5153
5154 if ($selected == $res->rowid) {
5155 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5156 } else {
5157 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5158 }
5159 }
5160 $return .= '</select>';
5161
5162 $return .= ajax_combobox($htmlname);
5163 }
5164 return $return;
5165 }
5166
5167 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5168
5183 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5184 {
5185 // phpcs:enable
5186 global $langs;
5187
5188 $out = '';
5189
5190 $langs->loadLangs(array("admin", "banks"));
5191 $num = 0;
5192
5193 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5194 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5195 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5196 if ($status != 2) {
5197 $sql .= " AND clos = " . (int) $status;
5198 }
5199 if ($filtre) { // TODO Support USF
5200 $sql .= " AND " . $filtre;
5201 }
5202 $sql .= " ORDER BY label";
5203
5204 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5205 $result = $this->db->query($sql);
5206 if ($result) {
5207 $num = $this->db->num_rows($result);
5208 $i = 0;
5209
5210 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5211
5212 if ($num == 0) {
5213 if ($status == 0) {
5214 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5215 } else {
5216 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5217 }
5218 } else {
5219 if (!empty($useempty) && !is_numeric($useempty)) {
5220 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5221 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5222 $out .= '<option value="-1">&nbsp;</option>';
5223 }
5224 }
5225
5226 while ($i < $num) {
5227 $obj = $this->db->fetch_object($result);
5228
5229 $labeltoshow = trim($obj->label);
5230 $labeltoshowhtml = trim($obj->label);
5231 if ($showcurrency) {
5232 $labeltoshow .= ' (' . $obj->currency_code . ')';
5233 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5234 }
5235 if ($status == 2 && $obj->status == 1) {
5236 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5237 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5238 }
5239
5240 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5241 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5242 } else {
5243 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5244 }
5245 $out .= $labeltoshow;
5246 $out .= '</option>';
5247 $i++;
5248 }
5249 $out .= "</select>";
5250 $out .= ajax_combobox('select' . $htmlname);
5251 } else {
5252 dol_print_error($this->db);
5253 }
5254
5255 // Output or return
5256 if (empty($nooutput)) {
5257 print $out;
5258 } else {
5259 return $out;
5260 }
5261
5262 return $num;
5263 }
5264
5278 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5279 {
5280 // phpcs:enable
5281 global $langs;
5282
5283 $out = '';
5284
5285 $langs->loadLangs(array("admin", "banks"));
5286 $num = 0;
5287
5288 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5289 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5290 $sql .= " WHERE type = 'ban'";
5291 if ($filtre) { // TODO Support USF
5292 $sql .= " AND " . $filtre;
5293 }
5294 $sql .= " ORDER BY label";
5295 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5296 $result = $this->db->query($sql);
5297 if ($result) {
5298 $num = $this->db->num_rows($result);
5299 $i = 0;
5300
5301 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5302
5303 if ($num == 0) {
5304 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5305 } else {
5306 if (!empty($useempty) && !is_numeric($useempty)) {
5307 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5308 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5309 $out .= '<option value="-1">&nbsp;</option>';
5310 }
5311 }
5312
5313 while ($i < $num) {
5314 $obj = $this->db->fetch_object($result);
5315 $iban = dolDecrypt($obj->iban_prefix);
5316 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5317 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5318 } else {
5319 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5320 }
5321 $out .= trim($obj->label);
5322 if ($showibanbic) {
5323 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5324 }
5325 $out .= '</option>';
5326 $i++;
5327 }
5328 $out .= "</select>";
5329 $out .= ajax_combobox('select' . $htmlname);
5330 } else {
5331 dol_print_error($this->db);
5332 }
5333
5334 // Output or return
5335 if (empty($nooutput)) {
5336 print $out;
5337 } else {
5338 return $out;
5339 }
5340
5341 return $num;
5342 }
5343
5355 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5356 {
5357 global $langs;
5358
5359 $langs->load("admin");
5360 $num = 0;
5361
5362 $sql = "SELECT rowid, name, fk_country, status, entity";
5363 $sql .= " FROM " . $this->db->prefix() . "establishment";
5364 $sql .= " WHERE 1=1";
5365 if ($status != 2) {
5366 $sql .= " AND status = " . (int) $status;
5367 }
5368 if ($filtre) { // TODO Support USF
5369 $sql .= " AND " . $filtre;
5370 }
5371 $sql .= " ORDER BY name";
5372
5373 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5374 $result = $this->db->query($sql);
5375 if ($result) {
5376 $num = $this->db->num_rows($result);
5377 $i = 0;
5378 if ($num) {
5379 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5380 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5381 print '<option value="-1">&nbsp;</option>';
5382 }
5383
5384 while ($i < $num) {
5385 $obj = $this->db->fetch_object($result);
5386 if ($selected == $obj->rowid) {
5387 print '<option value="' . $obj->rowid . '" selected>';
5388 } else {
5389 print '<option value="' . $obj->rowid . '">';
5390 }
5391 print trim($obj->name);
5392 if ($status == 2 && $obj->status == 1) {
5393 print ' (' . $langs->trans("Closed") . ')';
5394 }
5395 print '</option>';
5396 $i++;
5397 }
5398 print "</select>";
5399 } else {
5400 if ($status == 0) {
5401 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5402 } else {
5403 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5404 }
5405 }
5406
5407 return $num;
5408 } else {
5409 dol_print_error($this->db);
5410 return -1;
5411 }
5412 }
5413
5423 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5424 {
5425 global $langs;
5426 if ($htmlname != "none") {
5427 print '<form method="POST" action="' . $page . '">';
5428 print '<input type="hidden" name="action" value="setbankaccount">';
5429 print '<input type="hidden" name="token" value="' . newToken() . '">';
5430 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5431 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5432 if ($nbaccountfound > 0) {
5433 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5434 }
5435 print '</form>';
5436 } else {
5437 $langs->load('banks');
5438
5439 if ($selected) {
5440 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5441 $bankstatic = new Account($this->db);
5442 $result = $bankstatic->fetch($selected);
5443 if ($result) {
5444 print $bankstatic->getNomUrl(1);
5445 }
5446 } else {
5447 print "&nbsp;";
5448 }
5449 }
5450 }
5451
5463 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5464 {
5465 global $langs;
5466 if ($htmlname != "none") {
5467 print '<form method="POST" action="' . $page . '">';
5468 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5469 print '<input type="hidden" name="token" value="' . newToken() . '">';
5470 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5471 if ($nbaccountfound > 0) {
5472 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5473 }
5474 print '</form>';
5475 } else {
5476 $langs->load('banks');
5477
5478 if ($selected) {
5479 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5480 $bankstatic = new CompanyBankAccount($this->db);
5481 $result = $bankstatic->fetch($selected);
5482 if ($result) {
5483 print $bankstatic->label;
5484 if ($showibanbic) {
5485 print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5486 }
5487 }
5488 } else {
5489 print "&nbsp;";
5490 }
5491 }
5492 }
5493
5494 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5495
5515 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5516 {
5517 // phpcs:enable
5518 global $conf, $langs;
5519 $langs->load("categories");
5520
5521 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5522
5523 // For backward compatibility
5524 if (is_numeric($type)) {
5525 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5526 }
5527
5528 if ($type === Categorie::TYPE_BANK_LINE) {
5529 // TODO Move this into common category feature after migration of llx_category_bankline into llx_categorie_bankline
5530 $cat = new Categorie($this->db);
5531 $cate_arbo = array();
5532 $sql = "SELECT c.label, c.rowid";
5533 $sql .= " FROM " . $this->db->prefix() . "categorie as c";
5534 $sql .= " WHERE entity = " . $conf->entity . " AND type = " . ((int) $cat->getMapId()[$type]);
5535 $sql .= " ORDER BY c.label";
5536 $result = $this->db->query($sql);
5537 if ($result) {
5538 $num = $this->db->num_rows($result);
5539 $i = 0;
5540 while ($i < $num) {
5541 $objp = $this->db->fetch_object($result);
5542 if ($objp) {
5543 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5544 }
5545 $i++;
5546 }
5547 $this->db->free($result);
5548 } else {
5549 dol_print_error($this->db);
5550 }
5551 } else {
5552 $cat = new Categorie($this->db);
5553 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5554 }
5555
5556 $outarray = array();
5557 $outarrayrichhtml = array();
5558
5559
5560 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5561 if (is_array($cate_arbo)) {
5562 $num = count($cate_arbo);
5563
5564 if (!$num) {
5565 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5566 } else {
5567 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5568 $output .= '<option value="-1">&nbsp;</option>';
5569 }
5570 foreach ($cate_arbo as $key => $value) {
5571 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5572 $add = 'selected ';
5573 } else {
5574 $add = '';
5575 }
5576
5577 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5578 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5579
5580 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5581
5582 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5583
5584 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5585 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5586 $output .= '>';
5587 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5588 $output .= '</option>';
5589
5590 $cate_arbo[$key]['data-html'] = $labeltoshow;
5591 }
5592 }
5593 }
5594 $output .= '</select>';
5595 $output .= "\n";
5596
5597 if ($outputmode == 2) {
5598 // TODO: handle error when $cate_arbo is not an array
5599 return $cate_arbo;
5600 } elseif ($outputmode == 1) {
5601 return $outarray;
5602 } elseif ($outputmode == 3) {
5603 return $outarrayrichhtml;
5604 }
5605 return $output;
5606 }
5607
5608 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5609
5628 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5629 {
5630 // phpcs:enable
5631 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5632 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5633 }
5634
5662 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5663 {
5664 global $langs, $conf;
5665
5666 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5667 $formconfirm = '';
5668 $inputok = array();
5669 $inputko = array();
5670
5671 // Clean parameters
5672 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5673 if ($conf->browser->layout == 'phone') {
5674 $width = '95%';
5675 }
5676
5677 // Set height automatically if not defined
5678 if (empty($height)) {
5679 $height = 220;
5680 if (is_array($formquestion) && count($formquestion) > 2) {
5681 $height += ((count($formquestion) - 2) * 24);
5682 }
5683 }
5684
5685 if (is_array($formquestion) && !empty($formquestion)) {
5686 // First add hidden fields and value
5687 foreach ($formquestion as $key => $input) {
5688 if (is_array($input) && !empty($input)) {
5689 if ($input['type'] == 'hidden') {
5690 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5691 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5692
5693 $more .= '<input type="hidden" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '" value="' . dol_escape_htmltag($input['value']) . '" class="' . $morecss . '"' . $moreattr . '>' . "\n";
5694 }
5695 }
5696 }
5697
5698 // Now add questions
5699 $moreonecolumn = '';
5700 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5701 foreach ($formquestion as $key => $input) {
5702 if (is_array($input) && !empty($input)) {
5703 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5704 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5705 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5706
5707 if ($input['type'] == 'text') {
5708 $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="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
5709 } elseif ($input['type'] == 'password') {
5710 $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="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $size . ' value="' . (empty($input['value']) ? '' : $input['value']) . '"' . $moreattr . ' /></div></div>' . "\n";
5711 } elseif ($input['type'] == 'textarea') {
5712 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5713 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5714 $more .= $input['value'];
5715 $more .= '</textarea>';
5716 $more .= '</div></div>'."\n";*/
5717 $moreonecolumn .= '<div class="margintoponly">';
5718 $moreonecolumn .= $input['label'] . '<br>';
5719 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5720 $moreonecolumn .= $input['value'];
5721 $moreonecolumn .= '</textarea>';
5722 $moreonecolumn .= '</div>';
5723 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5724 if (empty($morecss)) {
5725 $morecss = 'minwidth100';
5726 }
5727
5728 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5729 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5730 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5731 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5732 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5733 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5734 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5735
5736 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5737 if (!empty($input['label'])) {
5738 $more .= $input['label'] . '</div><div class="tagtd left">';
5739 }
5740 if ($input['type'] == 'select') {
5741 $more .= $this->selectarray($input['name'], $input['values'], isset($input['default']) ? $input['default'] : '-1', $show_empty, $key_in_label, $value_as_key, $moreattr, $translate, $maxlen, $disabled, $sort, $morecss);
5742 } else {
5743 $more .= $this->multiselectarray($input['name'], $input['values'], is_array($input['default']) ? $input['default'] : [$input['default']], $key_in_label, $value_as_key, $morecss, $translate, $maxlen, $moreattr);
5744 }
5745 $more .= '</div></div>' . "\n";
5746 } elseif ($input['type'] == 'checkbox') {
5747 $more .= '<div class="tagtr">';
5748 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5749 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5750 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5751 $more .= ' checked';
5752 }
5753 if (is_bool($input['value']) && $input['value']) {
5754 $more .= ' checked';
5755 }
5756 if (isset($input['disabled'])) {
5757 $more .= ' disabled';
5758 }
5759 $more .= ' /></div>';
5760 $more .= '</div>' . "\n";
5761 } elseif ($input['type'] == 'radio') {
5762 $i = 0;
5763 foreach ($input['values'] as $selkey => $selval) {
5764 $more .= '<div class="tagtr">';
5765 if (isset($input['label'])) {
5766 if ($i == 0) {
5767 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5768 } else {
5769 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5770 }
5771 }
5772 $more .= '<div class="tagtd' . ($i == 0 ? ' tdtop' : '') . '"><input type="radio" class="flat' . $morecss . '" id="' . dol_escape_htmltag($input['name'] . $selkey) . '" name="' . dol_escape_htmltag($input['name']) . '" value="' . $selkey . '"' . $moreattr;
5773 if (!empty($input['disabled'])) {
5774 $more .= ' disabled';
5775 }
5776 if (isset($input['default']) && $input['default'] === $selkey) {
5777 $more .= ' checked="checked"';
5778 }
5779 $more .= ' /> ';
5780 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5781 $more .= '</div></div>' . "\n";
5782 $i++;
5783 }
5784 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5785 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5786 $more .= '<div class="tagtd">';
5787 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5788 $h = $m = 0;
5789 if ($input['type'] == 'datetime') {
5790 $h = isset($input['hours']) ? $input['hours'] : 1;
5791 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5792 }
5793 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5794 $more .= '</div></div>'."\n";
5795 $formquestion[] = array('name' => $input['name'].'day');
5796 $formquestion[] = array('name' => $input['name'].'month');
5797 $formquestion[] = array('name' => $input['name'].'year');
5798 $formquestion[] = array('name' => $input['name'].'hour');
5799 $formquestion[] = array('name' => $input['name'].'min');
5800 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5801 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5802 if (!empty($input['label'])) {
5803 $more .= $input['label'] . '</div><div class="tagtd">';
5804 }
5805 $more .= $input['value'];
5806 $more .= '</div></div>' . "\n";
5807 } elseif ($input['type'] == 'onecolumn') {
5808 $moreonecolumn .= '<div class="margintoponly">';
5809 $moreonecolumn .= $input['value'];
5810 $moreonecolumn .= '</div>' . "\n";
5811 } elseif ($input['type'] == 'hidden') {
5812 // Do nothing more, already added by a previous loop
5813 } elseif ($input['type'] == 'separator') {
5814 $more .= '<br>';
5815 } else {
5816 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5817 }
5818 }
5819 }
5820 $more .= '</div>' . "\n";
5821 $more .= $moreonecolumn;
5822 }
5823
5824 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5825 // 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
5826 // See page product/card.php for example
5827 if (!empty($conf->dol_use_jmobile)) {
5828 $useajax = 0;
5829 }
5830 if (empty($conf->use_javascript_ajax)) {
5831 $useajax = 0;
5832 }
5833
5834 if ($useajax) {
5835 $autoOpen = true;
5836 $dialogconfirm = 'dialog-confirm';
5837 $button = '';
5838 if (!is_numeric($useajax)) {
5839 $button = $useajax;
5840 $useajax = 1;
5841 $autoOpen = false;
5842 $dialogconfirm .= '-' . $button;
5843 }
5844 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5845 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5846
5847 // Add input fields into list of fields to read during submit (inputok and inputko)
5848 if (is_array($formquestion)) {
5849 foreach ($formquestion as $key => $input) {
5850 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5851 // Add name of fields to propagate with the GET when submitting the form with button OK.
5852 if (is_array($input) && isset($input['name'])) {
5853 if (strpos($input['name'], ',') > 0) {
5854 $inputok = array_merge($inputok, explode(',', $input['name']));
5855 } else {
5856 array_push($inputok, $input['name']);
5857 }
5858 }
5859 // Add name of fields to propagate with the GET when submitting the form with button KO.
5860 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5861 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5862 array_push($inputko, $input['name']);
5863 }
5864 }
5865 }
5866
5867 // Show JQuery confirm box.
5868 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5869 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5870 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5871 }
5872 if (!empty($more)) {
5873 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5874 }
5875 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5876 $formconfirm .= '</div>' . "\n";
5877
5878 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5879 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5880 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5881 $formconfirm .= 'jQuery(document).ready(function() {
5882 $(function() {
5883 $( "#' . $dialogconfirm . '" ).dialog(
5884 {
5885 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5886 if ($newselectedchoice == 'no') {
5887 $formconfirm .= '
5888 open: function() {
5889 $(this).parent().find("button.ui-button:eq(2)").focus();
5890 },';
5891 }
5892
5893 $jsforcursor = '';
5894 if ($useajax == 1) {
5895 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5896 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5897 }
5898
5899 $postconfirmas = 'GET';
5900
5901 $formconfirm .= '
5902 resizable: false,
5903 height: \'' . dol_escape_js($height) . '\',
5904 width: \'' . dol_escape_js($width) . '\',
5905 modal: true,
5906 closeOnEscape: false,
5907 buttons: {
5908 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5909 var options = "token=' . urlencode(newToken()) . '";
5910 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5911 var page = \'' . dol_escape_js(!empty($page) ? $page : '') . '\';
5912 var pageyes = \'' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '\';
5913
5914 if (inputok.length > 0) {
5915 $.each(inputok, function(i, inputname) {
5916 var more = "";
5917 var inputvalue;
5918 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5919 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5920 } else {
5921 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5922 inputvalue = $("#" + inputname + more).val();
5923 }
5924 if (typeof inputvalue == "undefined") { inputvalue=""; }
5925 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5926 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5927 });
5928 }
5929 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5930 if (pageyes.length > 0) {';
5931 if ($postconfirmas == 'GET') {
5932 $formconfirm .= 'location.href = urljump;';
5933 } else {
5934 $formconfirm .= $jsforcursor;
5935 $formconfirm .= 'var post = $.post(
5936 pageyes,
5937 options,
5938 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5939 );';
5940 }
5941 $formconfirm .= '
5942 console.log("after post ok");
5943 }
5944 $(this).dialog("close");
5945 },
5946 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5947 var options = "token=' . urlencode(newToken()) . '";
5948 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5949 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5950 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5951 if (inputko.length > 0) {
5952 $.each(inputko, function(i, inputname) {
5953 var more = "";
5954 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5955 var inputvalue = $("#" + inputname + more).val();
5956 if (typeof inputvalue == "undefined") { inputvalue=""; }
5957 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5958 });
5959 }
5960 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5961 //alert(urljump);
5962 if (pageno.length > 0) {';
5963 if ($postconfirmas == 'GET') {
5964 $formconfirm .= 'location.href = urljump;';
5965 } else {
5966 $formconfirm .= $jsforcursor;
5967 $formconfirm .= 'var post = $.post(
5968 pageno,
5969 options,
5970 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5971 );';
5972 }
5973 $formconfirm .= '
5974 console.log("after post ko");
5975 }
5976 $(this).dialog("close");
5977 }
5978 }
5979 }
5980 );
5981
5982 var button = "' . $button . '";
5983 if (button.length > 0) {
5984 $( "#" + button ).click(function() {
5985 $("#' . $dialogconfirm . '").dialog("open");
5986 });
5987 }
5988 });
5989 });
5990 </script>';
5991 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5992 } else {
5993 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5994
5995 if (empty($disableformtag)) {
5996 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
5997 }
5998
5999 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
6000 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
6001
6002 $formconfirm .= '<table class="valid centpercent">' . "\n";
6003
6004 // Line title
6005 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
6006 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
6007 $formconfirm .= '</td></tr>' . "\n";
6008
6009 // Line text
6010 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
6011 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
6012 }
6013
6014 // Line form fields
6015 if ($more) {
6016 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6017 $formconfirm .= $more;
6018 $formconfirm .= '</td></tr>' . "\n";
6019 }
6020
6021 // Line with question
6022 $formconfirm .= '<tr class="valid">';
6023 $formconfirm .= '<td class="valid">' . $question . '</td>';
6024 $formconfirm .= '<td class="valid center">';
6025 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6026 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6027 $formconfirm .= '</td>';
6028 $formconfirm .= '</tr>' . "\n";
6029
6030 $formconfirm .= '</table>' . "\n";
6031
6032 if (empty($disableformtag)) {
6033 $formconfirm .= "</form>\n";
6034 }
6035 $formconfirm .= '<br>';
6036
6037 if (!empty($conf->use_javascript_ajax)) {
6038 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6039 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6040 $formconfirm .= '
6041 $(document).ready(function () {
6042 $(".confirmvalidatebutton").on("click", function() {
6043 console.log("We click on button confirmvalidatebutton");
6044 $(this).attr("disabled", "disabled");
6045 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6046 //console.log($(this).closest("form"));
6047 $(this).closest("form").submit();
6048 });
6049 });
6050 ';
6051 $formconfirm .= '</script>' . "\n";
6052 }
6053
6054 $formconfirm .= "<!-- end formconfirm -->\n";
6055 }
6056
6057 return $formconfirm;
6058 }
6059
6060
6061 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6062
6078 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6079 {
6080 // phpcs:enable
6081 global $langs;
6082
6083 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6084 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6085
6086 $out = '';
6087
6088 $formproject = new FormProjets($this->db);
6089
6090 $langs->load("project");
6091 if ($htmlname != "none") {
6092 $out .= '<form method="post" action="' . $page . '">';
6093 $out .= '<input type="hidden" name="action" value="classin">';
6094 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6095 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6096 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6097 $out .= '</form>';
6098 } else {
6099 $out .= '<span class="project_head_block">';
6100 if ($selected) {
6101 $projet = new Project($this->db);
6102 $projet->fetch($selected);
6103 $out .= $projet->getNomUrl(0, '', 1);
6104 } else {
6105 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6106 }
6107 $out .= '</span>';
6108 }
6109
6110 if (empty($nooutput)) {
6111 print $out;
6112 return '';
6113 }
6114 return $out;
6115 }
6116
6117 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6118
6134 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6135 {
6136 // phpcs:enable
6137 global $langs;
6138
6139 $out = '';
6140
6141 if ($htmlname != "none") {
6142 $out .= '<form method="POST" action="' . $page . '">';
6143 $out .= '<input type="hidden" name="action" value="setconditions">';
6144 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6145 if ($type) {
6146 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6147 }
6148 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6149 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6150 $out .= '</form>';
6151 } else {
6152 if ($selected) {
6153 $this->load_cache_conditions_paiements();
6154 if (isset($this->cache_conditions_paiements[$selected])) {
6155 $label = $this->cache_conditions_paiements[$selected]['label'];
6156
6157 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6158 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6159 }
6160
6161 $out .= $label;
6162 } else {
6163 $langs->load('errors');
6164 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6165 }
6166 } else {
6167 $out .= '&nbsp;';
6168 }
6169 }
6170
6171 if (empty($nooutput)) {
6172 print $out;
6173 return '';
6174 }
6175 return $out;
6176 }
6177
6178 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6179
6189 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
6190 {
6191 // phpcs:enable
6192 global $langs;
6193 if ($htmlname != "none") {
6194 print '<form method="post" action="' . $page . '">';
6195 print '<input type="hidden" name="action" value="setavailability">';
6196 print '<input type="hidden" name="token" value="' . newToken() . '">';
6197 $this->selectAvailabilityDelay($selected, $htmlname, '', $addempty);
6198 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6199 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
6200 print '</form>';
6201 } else {
6202 if ($selected) {
6203 $this->load_cache_availability();
6204 print $this->cache_availability[$selected]['label'];
6205 } else {
6206 print "&nbsp;";
6207 }
6208 }
6209 }
6210
6221 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
6222 {
6223 global $langs;
6224 if ($htmlname != "none") {
6225 print '<form method="post" action="' . $page . '">';
6226 print '<input type="hidden" name="action" value="setdemandreason">';
6227 print '<input type="hidden" name="token" value="' . newToken() . '">';
6228 $this->selectInputReason($selected, $htmlname, '-1', $addempty);
6229 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6230 print '</form>';
6231 } else {
6232 if ($selected) {
6233 $this->loadCacheInputReason();
6234 foreach ($this->cache_demand_reason as $key => $val) {
6235 if ($val['id'] == $selected) {
6236 print $val['label'];
6237 break;
6238 }
6239 }
6240 } else {
6241 print "&nbsp;";
6242 }
6243 }
6244 }
6245
6246 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6247
6261 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6262 {
6263 // phpcs:enable
6264 global $langs;
6265
6266 $ret = '';
6267
6268 if ($htmlname != "none") {
6269 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6270 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6271 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6272 if ($type) {
6273 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6274 }
6275 $ret .= '<table class="nobordernopadding">';
6276 $ret .= '<tr><td>';
6277 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6278 $ret .= '</td>';
6279 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6280 $ret .= '</tr></table></form>';
6281 } else {
6282 if ($displayhour) {
6283 $ret .= dol_print_date($selected, 'dayhour');
6284 } else {
6285 $ret .= dol_print_date($selected, 'day');
6286 }
6287 }
6288
6289 if (empty($nooutput)) {
6290 print $ret;
6291 }
6292 return $ret;
6293 }
6294
6295
6296 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6297
6308 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6309 {
6310 // phpcs:enable
6311 global $langs;
6312
6313 if ($htmlname != "none") {
6314 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6315 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6316 print '<input type="hidden" name="token" value="' . newToken() . '">';
6317 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6318 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6319 print '</form>';
6320 } else {
6321 if ($selected) {
6322 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6323 $theuser = new User($this->db);
6324 $theuser->fetch($selected);
6325 print $theuser->getNomUrl(1);
6326 } else {
6327 print "&nbsp;";
6328 }
6329 }
6330 }
6331
6332
6333 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6334
6348 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6349 {
6350 // phpcs:enable
6351 global $langs;
6352
6353 $out = '';
6354 if ($htmlname != "none") {
6355 $out .= '<form method="POST" action="' . $page . '">';
6356 $out .= '<input type="hidden" name="action" value="setmode">';
6357 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6358 if ($type) {
6359 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6360 }
6361 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6362 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6363 $out .= '</form>';
6364 } else {
6365 if ($selected) {
6366 $this->load_cache_types_paiements();
6367 $out .= $this->cache_types_paiements[$selected]['label'];
6368 } else {
6369 $out .= "&nbsp;";
6370 }
6371 }
6372
6373 if ($nooutput) {
6374 return $out;
6375 } else {
6376 print $out;
6377 }
6378 return '';
6379 }
6380
6391 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6392 {
6393 global $langs;
6394 if ($htmlname != "none") {
6395 print '<form method="POST" action="' . $page . '">';
6396 print '<input type="hidden" name="action" value="settransportmode">';
6397 print '<input type="hidden" name="token" value="' . newToken() . '">';
6398 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6399 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6400 print '</form>';
6401 } else {
6402 if ($selected) {
6403 $this->load_cache_transport_mode();
6404 print $this->cache_transport_mode[$selected]['label'];
6405 } else {
6406 print "&nbsp;";
6407 }
6408 }
6409 }
6410
6411 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6412
6421 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6422 {
6423 // phpcs:enable
6424 global $langs;
6425 if ($htmlname != "none") {
6426 print '<form method="POST" action="' . $page . '">';
6427 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6428 print '<input type="hidden" name="token" value="' . newToken() . '">';
6429 print $this->selectMultiCurrency($selected, $htmlname, 0);
6430 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6431 print '</form>';
6432 } else {
6433 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6434 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6435 }
6436 }
6437
6438 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6439
6449 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6450 {
6451 // phpcs:enable
6452 global $langs, $mysoc, $conf;
6453
6454 if ($htmlname != "none") {
6455 print '<form method="POST" action="' . $page . '">';
6456 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6457 print '<input type="hidden" name="token" value="' . newToken() . '">';
6458 print '<input type="text" class="maxwidth75" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6459 print '<select name="calculation_mode" id="calculation_mode">';
6460 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6461 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6462 print '</select> ';
6463 print ajax_combobox("calculation_mode");
6464 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6465 print '</form>';
6466 } else {
6467 if (!empty($rate)) {
6468 print price($rate, 1, $langs, 0, 0);
6469 if ($currency && $rate != 1) {
6470 print ' &nbsp; <span class="opacitymedium">(' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')</span>';
6471 }
6472 } else {
6473 print 1;
6474 }
6475 }
6476 }
6477
6478 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6479
6495 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6496 {
6497 // phpcs:enable
6498 global $conf, $langs;
6499 if ($htmlname != "none") {
6500 print '<form method="post" action="' . $page . '">';
6501 print '<input type="hidden" name="action" value="setabsolutediscount">';
6502 print '<input type="hidden" name="token" value="' . newToken() . '">';
6503 print '<div class="inline-block">';
6504 if (!empty($discount_type)) {
6505 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6506 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6507 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6508 } else {
6509 $translationKey = 'HasCreditNoteFromSupplier';
6510 }
6511 } else {
6512 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6513 $translationKey = 'HasAbsoluteDiscountFromSupplier';
6514 } else {
6515 $translationKey = 'HasCreditNoteFromSupplier';
6516 }
6517 }
6518 } else {
6519 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
6520 if (!$filter || $filter == "fk_facture_source IS NULL") {
6521 $translationKey = 'CompanyHasAbsoluteDiscount'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6522 } else {
6523 $translationKey = 'CompanyHasCreditNote';
6524 }
6525 } else {
6526 if (!$filter || $filter == "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6527 $translationKey = 'CompanyHasAbsoluteDiscount';
6528 } else {
6529 $translationKey = 'CompanyHasCreditNote';
6530 }
6531 }
6532 }
6533 print $langs->trans($translationKey, price($amount, 0, $langs, 0, 0, -1, $conf->currency));
6534 if (empty($hidelist)) {
6535 print ' ';
6536 }
6537 print '</div>';
6538 if (empty($hidelist)) {
6539 print '<div class="inline-block" style="padding-right: 10px">';
6540 $newfilter = 'discount_type=' . intval($discount_type);
6541 if (!empty($discount_type)) {
6542 $newfilter .= ' AND fk_invoice_supplier IS NULL AND fk_invoice_supplier_line IS NULL'; // Supplier discounts available
6543 } else {
6544 $newfilter .= ' AND fk_facture IS NULL AND fk_facture_line IS NULL'; // Customer discounts available
6545 }
6546 if ($filter) {
6547 $newfilter .= ' AND (' . $filter . ')';
6548 }
6549 // output the combo of discounts
6550 $nbqualifiedlines = $this->select_remises((string) $selected, $htmlname, $newfilter, $socid, $maxvalue);
6551 if ($nbqualifiedlines > 0) {
6552 print ' &nbsp; <input type="submit" class="button smallpaddingimp" value="' . dol_escape_htmltag($langs->trans("UseLine")) . '"';
6553 if (!empty($discount_type) && $filter && $filter != "fk_invoice_supplier_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS PAID)%')") {
6554 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6555 }
6556 if (empty($discount_type) && $filter && $filter != "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')") {
6557 print ' title="' . $langs->trans("UseCreditNoteInInvoicePayment") . '"';
6558 }
6559
6560 print '>';
6561 }
6562 print '</div>';
6563 }
6564 if ($more) {
6565 print '<div class="inline-block">';
6566 print $more;
6567 print '</div>';
6568 }
6569 print '</form>';
6570 } else {
6571 if ($selected) {
6572 print $selected;
6573 } else {
6574 print "0";
6575 }
6576 }
6577 }
6578
6579
6580 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6581
6591 public function form_contacts($page, $societe, $selected = '', $htmlname = 'contactid')
6592 {
6593 // phpcs:enable
6594 global $langs;
6595
6596 if ($htmlname != "none") {
6597 print '<form method="post" action="' . $page . '">';
6598 print '<input type="hidden" name="action" value="set_contact">';
6599 print '<input type="hidden" name="token" value="' . newToken() . '">';
6600 print '<table class="nobordernopadding">';
6601 print '<tr><td>';
6602 print $this->selectcontacts($societe->id, $selected, $htmlname);
6603 $num = $this->num;
6604 if ($num == 0) {
6605 $addcontact = (getDolGlobalString('SOCIETE_ADDRESSES_MANAGEMENT') ? $langs->trans("AddContact") : $langs->trans("AddContactAddress"));
6606 print '<a href="' . DOL_URL_ROOT . '/contact/card.php?socid=' . $societe->id . '&action=create&backtoreferer=1">' . $addcontact . '</a>';
6607 }
6608 print '</td>';
6609 print '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6610 print '</tr></table></form>';
6611 } else {
6612 if ($selected) {
6613 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
6614 $contact = new Contact($this->db);
6615 $contact->fetch($selected);
6616 print $contact->getFullName($langs);
6617 } else {
6618 print "&nbsp;";
6619 }
6620 }
6621 }
6622
6623 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6624
6641 public function form_thirdparty($page, $selected = '', $htmlname = 'socid', $filter = '', $showempty = 0, $showtype = 0, $forcecombo = 0, $events = array(), $nooutput = 0, $excludeids = array(), $textifnothirdparty = '')
6642 {
6643 // phpcs:enable
6644 global $langs;
6645
6646 $out = '';
6647 if ($htmlname != "none") {
6648 $out .= '<form method="post" action="' . $page . '">';
6649 $out .= '<input type="hidden" name="action" value="set_thirdparty">';
6650 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6651 $out .= $this->select_company($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, 0, 'minwidth100', '', '', 1, array(), false, $excludeids);
6652 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6653 $out .= '</form>';
6654 } else {
6655 if ($selected) {
6656 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
6657 $soc = new Societe($this->db);
6658 $soc->fetch($selected);
6659 $out .= $soc->getNomUrl(0, '');
6660 } else {
6661 $out .= '<span class="opacitymedium">' . $textifnothirdparty . '</span>';
6662 }
6663 }
6664
6665 if ($nooutput) {
6666 return $out;
6667 } else {
6668 print $out;
6669 }
6670
6671 return '';
6672 }
6673
6674 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6675
6684 public function select_currency($selected = '', $htmlname = 'currency_id')
6685 {
6686 // phpcs:enable
6687 print $this->selectCurrency($selected, $htmlname);
6688 }
6689
6699 public function selectCurrency($selected = '', $htmlname = 'currency_id', $mode = 0, $useempty = '')
6700 {
6701 global $langs, $user;
6702
6703 $langs->loadCacheCurrencies('');
6704
6705 $out = '';
6706
6707 if ($selected == 'euro' || $selected == 'euros') {
6708 $selected = 'EUR'; // Pour compatibilite
6709 }
6710
6711 $out .= '<select class="flat maxwidth200onsmartphone minwidth300" name="' . $htmlname . '" id="' . $htmlname . '">';
6712 if ($useempty) {
6713 $out .= '<option value="-1" selected></option>';
6714 }
6715 foreach ($langs->cache_currencies as $code_iso => $currency) {
6716 $labeltoshow = $currency['label'];
6717 if ($mode == 1) {
6718 $labeltoshow .= ' <span class="opacitymedium">(' . $code_iso . ')</span>';
6719 } else {
6720 $labeltoshow .= ' <span class="opacitymedium">(' . $langs->getCurrencySymbol($code_iso) . ')</span>';
6721 }
6722
6723 if ($selected && $selected == $code_iso) {
6724 $out .= '<option value="' . $code_iso . '" selected data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6725 } else {
6726 $out .= '<option value="' . $code_iso . '" data-html="' . dol_escape_htmltag($labeltoshow) . '">';
6727 }
6728 $out .= $labeltoshow;
6729 $out .= '</option>';
6730 }
6731 $out .= '</select>';
6732 if ($user->admin) {
6733 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
6734 }
6735
6736 // Make select dynamic
6737 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6738 $out .= ajax_combobox($htmlname);
6739
6740 return $out;
6741 }
6742
6755 public function selectMultiCurrency($selected = '', $htmlname = 'multicurrency_code', $useempty = 0, $filter = '', $excludeConfCurrency = false, $morecss = '')
6756 {
6757 global $conf, $langs;
6758
6759 $langs->loadCacheCurrencies(''); // Load ->cache_currencies
6760
6761 $TCurrency = array();
6762
6763 $sql = "SELECT code FROM " . $this->db->prefix() . "multicurrency";
6764 $sql .= " WHERE entity IN ('" . getEntity('multicurrency') . "')";
6765 if ($filter) {
6766 $sql .= " AND " . $filter;
6767 }
6768 $resql = $this->db->query($sql);
6769 if ($resql) {
6770 while ($obj = $this->db->fetch_object($resql)) {
6771 $TCurrency[$obj->code] = $obj->code;
6772 }
6773 }
6774
6775 $out = '';
6776 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
6777 if ($useempty) {
6778 $out .= '<option value="">&nbsp;</option>';
6779 }
6780 // If company current currency not in table, we add it into list. Should always be available.
6781 if (!in_array($conf->currency, $TCurrency) && !$excludeConfCurrency) {
6782 $TCurrency[$conf->currency] = $conf->currency;
6783 }
6784 if (count($TCurrency) > 0) {
6785 foreach ($langs->cache_currencies as $code_iso => $currency) {
6786 if (isset($TCurrency[$code_iso])) {
6787 if (!empty($selected) && $selected == $code_iso) {
6788 $out .= '<option value="' . $code_iso . '" selected="selected">';
6789 } else {
6790 $out .= '<option value="' . $code_iso . '">';
6791 }
6792
6793 $out .= $currency['label'];
6794 $out .= ' (' . $langs->getCurrencySymbol($code_iso) . ')';
6795 $out .= '</option>';
6796 }
6797 }
6798 }
6799
6800 $out .= '</select>';
6801
6802 // Make select dynamic
6803 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
6804 $out .= ajax_combobox($htmlname);
6805
6806 return $out;
6807 }
6808
6809 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6810
6817 public function load_cache_vatrates($country_code)
6818 {
6819 // phpcs:enable
6820 global $langs, $user;
6821
6822 $num = count($this->cache_vatrates);
6823 if ($num > 0) {
6824 return $num; // Cache already loaded
6825 }
6826
6827 dol_syslog(__METHOD__, LOG_DEBUG);
6828
6829 $sql = "SELECT t.rowid, t.type_vat, t.code, t.taux, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.recuperableonly";
6830 $sql .= " FROM ".$this->db->prefix()."c_tva as t, ".$this->db->prefix()."c_country as c";
6831 $sql .= " WHERE t.fk_pays = c.rowid";
6832 $sql .= " AND t.active > 0";
6833 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6834 $sql .= " AND c.code IN (" . $this->db->sanitize($country_code, 1) . ")";
6835 $sql .= " ORDER BY t.code ASC, t.taux ASC, t.recuperableonly ASC";
6836
6837 $resql = $this->db->query($sql);
6838 if ($resql) {
6839 $num = $this->db->num_rows($resql);
6840 if ($num) {
6841 for ($i = 0; $i < $num; $i++) {
6842 $obj = $this->db->fetch_object($resql);
6843
6844 $tmparray = array();
6845 $tmparray['rowid'] = $obj->rowid;
6846 $tmparray['type_vat'] = ($obj->type_vat <= 0 ? 0 : $obj->type_vat); // Some version have type_vat corrupted with value -1
6847 $tmparray['code'] = $obj->code;
6848 $tmparray['txtva'] = $obj->taux;
6849 $tmparray['nprtva'] = $obj->recuperableonly;
6850 $tmparray['localtax1'] = $obj->localtax1;
6851 $tmparray['localtax1_type'] = $obj->localtax1_type;
6852 $tmparray['localtax2'] = $obj->localtax2;
6853 $tmparray['localtax2_type'] = $obj->localtax1_type;
6854 $tmparray['label'] = $obj->taux . '%' . ($obj->code ? ' (' . $obj->code . ')' : ''); // Label must contains only 0-9 , . % or *
6855 $tmparray['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
6856 $positiverates = '';
6857 if ($obj->taux) {
6858 $positiverates .= ($positiverates ? '/' : '') . $obj->taux;
6859 }
6860 if ($obj->localtax1) {
6861 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax1;
6862 }
6863 if ($obj->localtax2) {
6864 $positiverates .= ($positiverates ? '/' : '') . $obj->localtax2;
6865 }
6866 if (empty($positiverates)) {
6867 $positiverates = '0';
6868 }
6869 $tmparray['labelpositiverates'] = $positiverates . ($obj->code ? ' (' . $obj->code . ')' : ''); // Must never be used as key, only label
6870
6871 $this->cache_vatrates[$obj->rowid] = $tmparray;
6872 }
6873
6874 return $num;
6875 } else {
6876 $this->error = '<span class="error">';
6877 $this->error .= $langs->trans("ErrorNoVATRateDefinedForSellerCountry", $country_code);
6878 $reg = array();
6879 if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
6880 $langs->load("errors");
6881 $new_country_code = $reg[1];
6882 $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
6883 $this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
6884 }
6885 $this->error .= '</span>';
6886 return -1;
6887 }
6888 } else {
6889 $this->error = '<span class="error">' . $this->db->error() . '</span>';
6890 return -2;
6891 }
6892 }
6893
6894 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6895
6918 public function load_tva($htmlname = 'tauxtva', $selectedrate = '', $societe_vendeuse = null, $societe_acheteuse = null, $idprod = 0, $info_bits = 0, $type = '', $options_only = false, $mode = 0, $type_vat = 0)
6919 {
6920 // phpcs:enable
6921 global $langs, $mysoc;
6922
6923 $langs->load('errors');
6924
6925 $return = '';
6926
6927 // Define defaultnpr, defaultttx and defaultcode
6928 $defaultnpr = ($info_bits & 0x01);
6929 $defaultnpr = (preg_match('/\*/', $selectedrate) ? 1 : $defaultnpr);
6930 $defaulttx = str_replace('*', '', $selectedrate);
6931 $defaultcode = '';
6932 $reg = array();
6933 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6934 $defaultcode = $reg[1];
6935 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6936 }
6937 //var_dump($selectedrate.'-'.$defaulttx.'-'.$defaultnpr.'-'.$defaultcode);
6938
6939 // Check parameters
6940 if (is_object($societe_vendeuse) && !$societe_vendeuse->country_code) {
6941 if ($societe_vendeuse->id == $mysoc->id) {
6942 $return .= '<span class="error">' . $langs->trans("ErrorYourCountryIsNotDefined") . '</span>';
6943 } else {
6944 $return .= '<span class="error">' . $langs->trans("ErrorSupplierCountryIsNotDefined") . '</span>';
6945 }
6946 return $return;
6947 }
6948
6949 //var_dump($societe_acheteuse);
6950 //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";
6951 //exit;
6952
6953 // Define list of countries to use to search VAT rates to show
6954 // First we defined code_country to use to find list
6955 if (is_object($societe_vendeuse)) {
6956 $code_country = "'" . $societe_vendeuse->country_code . "'";
6957 } else {
6958 $code_country = "'" . $mysoc->country_code . "'"; // Pour compatibilite ascendente
6959 }
6960
6961 if ($societe_vendeuse == $mysoc && getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) { // If option to have vat for end customer for services is on
6962 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6963 // If SERVICE_ARE_ECOMMERCE_200238EC=1 combo list vat rate of purchaser and seller countries
6964 // If SERVICE_ARE_ECOMMERCE_200238EC=2 combo list only the vat rate of the purchaser country
6965 $selectVatComboMode = getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC');
6966 if (is_object($societe_vendeuse) && is_object($societe_acheteuse) && isInEEC($societe_vendeuse) && isInEEC($societe_acheteuse) && !$societe_acheteuse->isACompany()) {
6967 // We also add the buyer country code
6968 if (is_numeric($type)) {
6969 if ($type == 1) { // We know product is a service
6970 switch ($selectVatComboMode) {
6971 case '1':
6972 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6973 break;
6974 case '2':
6975 $code_country = "'" . $societe_acheteuse->country_code . "'";
6976 break;
6977 }
6978 }
6979 } elseif (!$idprod) { // We don't know type of product
6980 switch ($selectVatComboMode) {
6981 case '1':
6982 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6983 break;
6984 case '2':
6985 $code_country = "'" . $societe_acheteuse->country_code . "'";
6986 break;
6987 }
6988 } else {
6989 $prodstatic = new Product($this->db);
6990 $prodstatic->fetch($idprod);
6991 if ($prodstatic->type == Product::TYPE_SERVICE) { // We know product is a service
6992 $code_country .= ",'" . $societe_acheteuse->country_code . "'";
6993 }
6994 }
6995 }
6996 }
6997
6998 // Now we load the list of VAT
6999 $this->load_cache_vatrates($code_country); // If no vat defined, return -1 with message into this->error
7000
7001 // Keep only the VAT qualified for $type_vat
7002 $arrayofvatrates = array();
7003 foreach ($this->cache_vatrates as $cachevalue) {
7004 if (empty($cachevalue['type_vat']) || $cachevalue['type_vat'] == $type_vat) {
7005 $arrayofvatrates[] = $cachevalue;
7006 }
7007 }
7008
7009 $num = count($arrayofvatrates);
7010 if ($num > 0) {
7011 // Define the rate to pre-select (if defaulttx not forced so is -1 or '')
7012 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7013 // Define a default thirdparty to use if the seller or buyer is not defined
7014 $tmpthirdparty = new Societe($this->db);
7015 $tmpthirdparty->country_code = $mysoc->country_code;
7016
7017 $defaulttx = get_default_tva(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7018 $defaultnpr = get_default_npr(is_object($societe_vendeuse) ? $societe_vendeuse : $tmpthirdparty, (is_object($societe_acheteuse) ? $societe_acheteuse : $tmpthirdparty), $idprod);
7019
7020 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7021 $defaultcode = $reg[1];
7022 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7023 }
7024 if (empty($defaulttx)) {
7025 $defaultnpr = 0;
7026 }
7027 }
7028
7029 // If we fails to find a default vat rate, we take the last one in list
7030 // Because they are sorted in ascending order, the last one will be the higher one (we suppose the higher one is the current rate)
7031 if ($defaulttx < 0 || dol_strlen($defaulttx) == 0) {
7032 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7033 // We take the last one found in list
7034 $defaulttx = $arrayofvatrates[$num - 1]['txtva'];
7035 } else {
7036 // We will use the rate defined into MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS
7037 $defaulttx = '';
7038 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7039 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7040 }
7041 if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7042 $defaultcode = $reg[1];
7043 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7044 }
7045 }
7046 }
7047
7048 // Disabled if seller is not subject to VAT
7049 $disabled = false;
7050 $title = '';
7051 if (is_object($societe_vendeuse) && $societe_vendeuse->id == $mysoc->id && $societe_vendeuse->tva_assuj == "0") {
7052 // Override/enable VAT for expense report regardless of global setting - needed if expense report used for business expenses instead
7053 // of using supplier invoices (this is a very bad idea !)
7054 if (!getDolGlobalString('EXPENSEREPORT_OVERRIDE_VAT')) {
7055 $title = ' title="' . dol_escape_htmltag($langs->trans('VATIsNotUsed')) . '"';
7056 $disabled = true;
7057 }
7058 }
7059
7060 if (!$options_only) {
7061 $return .= '<select class="flat minwidth75imp maxwidth100 right" id="' . $htmlname . '" name="' . $htmlname . '"' . ($disabled ? ' disabled' : '') . $title . '>';
7062 }
7063
7064 $selectedfound = false;
7065 foreach ($arrayofvatrates as $rate) {
7066 // Keep only 0 if seller is not subject to VAT
7067 if ($disabled && $rate['txtva'] != 0) {
7068 continue;
7069 }
7070
7071 // Define key to use into select list
7072 $key = $rate['txtva'];
7073 $key .= $rate['nprtva'] ? '*' : '';
7074 if ($mode > 0 && $rate['code']) {
7075 $key .= ' (' . $rate['code'] . ')';
7076 }
7077 if ($mode < 0) {
7078 $key = $rate['rowid'];
7079 }
7080
7081 $return .= '<option value="' . $key . '"';
7082 if (!$selectedfound) {
7083 if ($defaultcode) { // If defaultcode is defined, we used it in priority to select combo option instead of using rate+npr flag
7084 if ($defaultcode == $rate['code']) {
7085 $return .= ' selected';
7086 $selectedfound = true;
7087 }
7088 } elseif ($rate['txtva'] == $defaulttx && $rate['nprtva'] == $defaultnpr) {
7089 $return .= ' selected';
7090 $selectedfound = true;
7091 }
7092 }
7093 $return .= '>';
7094
7095 // Show label of VAT
7096 if ($mysoc->country_code == 'IN' || getDolGlobalString('MAIN_VAT_LABEL_IS_POSITIVE_RATES')) {
7097 // Label with all localtax and code. For example: x.y / a.b / c.d (CODE)'
7098 $return .= $rate['labelpositiverates'];
7099 } else {
7100 // Simple label
7101 $return .= vatrate($rate['label']);
7102 }
7103
7104 //$return.=($rate['code']?' '.$rate['code']:'');
7105 $return .= (empty($rate['code']) && $rate['nprtva']) ? ' *' : ''; // We show the * (old behaviour only if new vat code is not used)
7106
7107 $return .= '</option>';
7108 }
7109
7110 if (!$options_only) {
7111 $return .= '</select>';
7112 //$return .= ajax_combobox($htmlname); // This break for the moment the dynamic autoselection of a value when selecting a product in object lines
7113 }
7114 } else {
7115 $return .= $this->error;
7116 }
7117
7118 $this->num = $num;
7119 return $return;
7120 }
7121
7122
7123 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7124
7149 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 = 0, $addplusone = '', $adddateof = '')
7150 {
7151 // phpcs:enable
7152 dol_syslog(__METHOD__ . ': using select_date is deprecated. Use selectDate instead.', LOG_WARNING);
7153 $retstring = $this->selectDate($set_time, $prefix, $h, $m, $empty, $form_name, $d, $addnowlink, $disabled, $fullday, $addplusone, $adddateof);
7154 if (!empty($nooutput)) {
7155 return $retstring;
7156 }
7157 print $retstring;
7158
7159 return '';
7160 }
7161
7177 public function selectDateToDate($set_time = '', $set_time_end = '', $prefix = 're', $empty = 0, $forcenewline = 0)
7178 {
7179 global $langs;
7180
7181 $ret = $this->selectDate($set_time, $prefix . '_start', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("from"), 'tzuserrel');
7182 if ($forcenewline) {
7183 $ret .= '<br>';
7184 }
7185 $ret .= $this->selectDate($set_time_end, $prefix . '_end', 0, 0, $empty, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"), 'tzuserrel');
7186 return $ret;
7187 }
7188
7217 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', $calendarpicto = '')
7218 {
7219 global $conf, $langs;
7220
7221 if ($gm === 'auto') {
7222 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
7223 }
7224
7225 $retstring = '';
7226
7227 if ($prefix == '') {
7228 $prefix = 're';
7229 }
7230 if ($h == '') {
7231 $h = 0;
7232 }
7233 if ($m == '') {
7234 $m = 0;
7235 }
7236 $emptydate = 0;
7237 $emptyhours = 0;
7238 if ($stepminutes <= 0 || $stepminutes > 30) {
7239 $stepminutes = 1;
7240 }
7241 if ($empty == 1) {
7242 $emptydate = 1;
7243 $emptyhours = 1;
7244 }
7245 if ($empty == 2) {
7246 $emptydate = 0;
7247 $emptyhours = 1;
7248 }
7249 $orig_set_time = $set_time;
7250
7251 if ($set_time === '' && $emptydate == 0) {
7252 include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7253 if ($gm == 'tzuser' || $gm == 'tzuserrel') {
7254 $set_time = dol_now($gm);
7255 } else {
7256 $set_time = dol_now('tzuser') - (getServerTimeZoneInt('now') * 3600); // set_time must be relative to PHP server timezone
7257 }
7258 }
7259
7260 // Analysis of the pre-selection date
7261 $reg = array();
7262 $shour = '';
7263 $smin = '';
7264 $ssec = '';
7265 if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage
7266 // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
7267 $syear = (!empty($reg[1]) ? $reg[1] : '');
7268 $smonth = (!empty($reg[2]) ? $reg[2] : '');
7269 $sday = (!empty($reg[3]) ? $reg[3] : '');
7270 $shour = (!empty($reg[4]) ? $reg[4] : '');
7271 $smin = (!empty($reg[5]) ? $reg[5] : '');
7272 } elseif (strval($set_time) != '' && $set_time != -1) {
7273 // set_time est un timestamps (0 possible)
7274 $syear = dol_print_date($set_time, "%Y", $gm);
7275 $smonth = dol_print_date($set_time, "%m", $gm);
7276 $sday = dol_print_date($set_time, "%d", $gm);
7277 if ($orig_set_time != '') {
7278 $shour = dol_print_date($set_time, "%H", $gm);
7279 $smin = dol_print_date($set_time, "%M", $gm);
7280 $ssec = dol_print_date($set_time, "%S", $gm);
7281 }
7282 } else {
7283 // Date est '' ou vaut -1
7284 $syear = '';
7285 $smonth = '';
7286 $sday = '';
7287 $shour = getDolGlobalString('MAIN_DEFAULT_DATE_HOUR', ($h == -1 ? '23' : ''));
7288 $smin = getDolGlobalString('MAIN_DEFAULT_DATE_MIN', ($h == -1 ? '59' : ''));
7289 $ssec = getDolGlobalString('MAIN_DEFAULT_DATE_SEC', ($h == -1 ? '59' : ''));
7290 }
7291 if ($h == 3 || $h == 4) {
7292 $shour = '';
7293 }
7294 if ($m == 3) {
7295 $smin = '';
7296 }
7297
7298 $nowgmt = dol_now('gmt');
7299 //var_dump(dol_print_date($nowgmt, 'dayhourinputnoreduce', 'tzuserrel'));
7300
7301 // You can set MAIN_POPUP_CALENDAR to 'eldy' or 'jquery'
7302 $usecalendar = 'combo';
7303 if (!empty($conf->use_javascript_ajax) && (!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') != "none")) {
7304 $usecalendar = ((!getDolGlobalString('MAIN_POPUP_CALENDAR') || getDolGlobalString('MAIN_POPUP_CALENDAR') == 'eldy') ? 'jquery' : getDolGlobalString("MAIN_POPUP_CALENDAR"));
7305 }
7306 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7307 // If we use a text browser or screen reader, we use the 'combo' date selector
7308 $usecalendar = 'html';
7309 }
7310
7311 if ($d) {
7312 // Show date with popup
7313 if ($usecalendar != 'combo') {
7314 $formatted_date = '';
7315 //print "e".$set_time." t ".$conf->format_date_short;
7316 if (strval($set_time) != '' && $set_time != -1) {
7317 //$formatted_date=dol_print_date($set_time,$conf->format_date_short);
7318 $formatted_date = dol_print_date($set_time, $langs->trans("FormatDateShortInput"), $gm); // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7319 }
7320
7321 // Calendrier popup version eldy
7322 if ($usecalendar == "eldy") {
7323 // Input area to enter date manually
7324 $retstring .= '<input id="' . $prefix . '" name="' . $prefix . '" type="text" class="maxwidthdate center" maxlength="11" value="' . $formatted_date . '"';
7325 $retstring .= ($disabled ? ' disabled' : '');
7326 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7327 $retstring .= ' autocomplete="off">';
7328
7329 // Icon calendar
7330 $retstringbuttom = '';
7331 if (!$disabled) {
7332 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons"';
7333 $base = DOL_URL_ROOT . '/core/';
7334 $retstringbuttom .= ' onClick="showDP(\'' . dol_escape_js($base) . '\',\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\',\'' . dol_escape_js($langs->defaultlang) . '\');"';
7335 $retstringbuttom .= '>' . img_object($langs->trans("SelectDate"), 'calendarday', 'class="datecallink"') . '</button>';
7336 } else {
7337 $retstringbuttom = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7338 }
7339 $retstring = $retstringbuttom . $retstring;
7340
7341 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7342 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7343 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7344 } elseif ($usecalendar == 'jquery' || $usecalendar == 'html') {
7345 if (!$disabled && $usecalendar != 'html') {
7346 // Output javascript for datepicker
7347 $minYear = getDolGlobalInt('MIN_YEAR_SELECT_DATE', (idate('Y') - 100));
7348 $maxYear = getDolGlobalInt('MAX_YEAR_SELECT_DATE', (idate('Y') + 100));
7349
7350 $retstring .= '<script nonce="' . getNonce() . '" type="text/javascript">';
7351 $retstring .= "$(function(){ $('#" . $prefix . "').datepicker({
7352 dateFormat: '" . $langs->trans("FormatDateShortJQueryInput") . "',
7353 autoclose: true,
7354 todayHighlight: true,
7355 yearRange: '" . $minYear . ":" . $maxYear . "',";
7356 if (!empty($conf->dol_use_jmobile)) {
7357 $retstring .= "
7358 beforeShow: function (input, datePicker) {
7359 input.disabled = true;
7360 },
7361 onClose: function (dateText, datePicker) {
7362 this.disabled = false;
7363 },
7364 ";
7365 }
7366 // Note: We don't need monthNames, monthNamesShort, dayNames, dayNamesShort, dayNamesMin, they are set globally on datepicker component in lib_head.js.php
7367 if (!getDolGlobalString('MAIN_POPUP_CALENDAR_ON_FOCUS')) {
7368 $buttonImage = $calendarpicto ?: DOL_URL_ROOT . "/theme/" . dol_escape_js($conf->theme) . "/img/object_calendarday.png";
7369 $retstring .= "
7370 showOn: 'button', /* both has problem with autocompletion */
7371 buttonImage: '" . $buttonImage . "',
7372 buttonImageOnly: true";
7373 }
7374 $retstring .= "
7375 }) });";
7376 $retstring .= "</script>";
7377 }
7378
7379 // Input area to enter date manually
7380 $retstring .= '<div class="nowraponall inline-block divfordateinput">';
7381 $retstring .= '<input id="'.$prefix.'" name="'.$prefix.'" type="'.($usecalendar == 'html' ? "date" : "text").'" class="maxwidthdate center" maxlength="11" value="'.$formatted_date.'"';
7382 $retstring .= ($disabled ? ' disabled' : '');
7383 $retstring .= ($placeholder ? ' placeholder="' . dol_escape_htmltag($placeholder) . '"' : '');
7384 $retstring .= ' onChange="dpChangeDay(\'' . dol_escape_js($prefix) . '\',\'' . dol_escape_js($langs->trans("FormatDateShortJavaInput")) . '\'); "'; // FormatDateShortInput for dol_print_date / FormatDateShortJavaInput that is same for javascript
7385 $retstring .= ' autocomplete="off">';
7386
7387 // Icon calendar
7388 if ($disabled) {
7389 $retstringbutton = '<button id="' . $prefix . 'Button" type="button" class="dpInvisibleButtons">' . img_object($langs->trans("Disabled"), 'calendarday', 'class="datecallink"') . '</button>';
7390 $retstring = $retstringbutton . $retstring;
7391 }
7392
7393 $retstring .= '</div>';
7394 $retstring .= '<input type="hidden" id="' . $prefix . 'day" name="' . $prefix . 'day" value="' . $sday . '">' . "\n";
7395 $retstring .= '<input type="hidden" id="' . $prefix . 'month" name="' . $prefix . 'month" value="' . $smonth . '">' . "\n";
7396 $retstring .= '<input type="hidden" id="' . $prefix . 'year" name="' . $prefix . 'year" value="' . $syear . '">' . "\n";
7397 } else {
7398 $retstring .= "Bad value of MAIN_POPUP_CALENDAR";
7399 }
7400 } else {
7401 // Show date with combo selects
7402 // Day
7403 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50imp" id="' . $prefix . 'day" name="' . $prefix . 'day">';
7404
7405 if ($emptydate || $set_time == -1) {
7406 $retstring .= '<option value="0" selected>&nbsp;</option>';
7407 }
7408
7409 for ($day = 1; $day <= 31; $day++) {
7410 $retstring .= '<option value="' . $day . '"' . ($day == $sday ? ' selected' : '') . '>' . $day . '</option>';
7411 }
7412
7413 $retstring .= "</select>";
7414
7415 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'month" name="' . $prefix . 'month">';
7416 if ($emptydate || $set_time == -1) {
7417 $retstring .= '<option value="0" selected>&nbsp;</option>';
7418 }
7419
7420 // Month
7421 for ($month = 1; $month <= 12; $month++) {
7422 $retstring .= '<option value="' . $month . '"' . ($month == $smonth ? ' selected' : '') . '>';
7423 $retstring .= dol_print_date(mktime(12, 0, 0, $month, 1, 2000), "%b");
7424 $retstring .= "</option>";
7425 }
7426 $retstring .= "</select>";
7427
7428 // Year
7429 if ($emptydate || $set_time == -1) {
7430 $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 . '">';
7431 } else {
7432 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth75imp" id="' . $prefix . 'year" name="' . $prefix . 'year">';
7433
7434 $syear = (int) $syear;
7435 for ($year = $syear - 10; $year < (int) $syear + 10; $year++) {
7436 $retstring .= '<option value="' . $year . '"' . ($year == $syear ? ' selected' : '') . '>' . $year . '</option>';
7437 }
7438 $retstring .= "</select>\n";
7439 }
7440 }
7441 }
7442
7443 if ($d && $h) {
7444 $retstring .= (($h == 2 || $h == 4) ? '<br>' : ' ');
7445 $retstring .= '<span class="nowraponall">';
7446 }
7447
7448 if ($h) {
7449 $hourstart = 0;
7450 $hourend = 24;
7451 if ($openinghours != '') {
7452 $openinghours = explode(',', $openinghours);
7453 $hourstart = $openinghours[0];
7454 $hourend = $openinghours[1];
7455 if ($hourend < $hourstart) {
7456 $hourend = $hourstart;
7457 }
7458 }
7459
7460 // Show hour
7461 $retstring .= '<select' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'hour' : '') . '" id="' . $prefix . 'hour" name="' . $prefix . 'hour">';
7462 if ($emptyhours) {
7463 $retstring .= '<option value="-1">&nbsp;</option>';
7464 }
7465 for ($hour = $hourstart; $hour < $hourend; $hour++) {
7466 if (strlen($hour) < 2) {
7467 $hour = "0" . $hour;
7468 }
7469 $retstring .= '<option value="' . $hour . '"' . (($hour == $shour) ? ' selected' : '') . '>' . $hour;
7470 $retstring .= '</option>';
7471 }
7472 $retstring .= '</select>';
7473 if ($disabled) {
7474 $retstring .= '<input type="hidden" id="' . $prefix . 'hour" name="' . $prefix . 'hour" value="' . $shour . '">' . "\n";
7475 }
7476 if ($m) {
7477 $retstring .= ":";
7478 }
7479 }
7480
7481 if ($m) {
7482 // Show minutes
7483 $retstring .= '<select ' . ($disabled ? ' disabled' : '') . ' class="flat valignmiddle maxwidth50 ' . ($fullday ? $fullday . 'min' : '') . '" id="' . $prefix . 'min" name="' . $prefix . 'min">';
7484 if ($emptyhours) {
7485 $retstring .= '<option value="-1">&nbsp;</option>';
7486 }
7487 for ($min = 0; $min < 60; $min += $stepminutes) {
7488 $min_str = sprintf("%02d", $min);
7489 $retstring .= '<option value="' . $min_str . '"' . (($min_str == $smin) ? ' selected' : '') . '>' . $min_str . '</option>';
7490 }
7491 $retstring .= '</select>';
7492 if ($disabled) {
7493 $retstring .= '<input type="hidden" id="' . $prefix . 'min" name="' . $prefix . 'min" value="' . $smin . '">' . "\n";
7494 }
7495 // Add also seconds
7496 $retstring .= '<input type="hidden" name="' . $prefix . 'sec" value="' . $ssec . '">';
7497 }
7498
7499 if ($d && $h) {
7500 $retstring .= '</span>';
7501 }
7502
7503 // Add a "Now" link
7504 if (!empty($conf->use_javascript_ajax) && $addnowlink && !$disabled) {
7505 // Script which will be inserted in the onClick of the "Now" link
7506 $reset_scripts = "";
7507 if ($addnowlink == 2) { // local computer time
7508 // pad add leading 0 on numbers
7509 $reset_scripts .= "Number.prototype.pad = function(size) {
7510 var s = String(this);
7511 while (s.length < (size || 2)) {s = '0' + s;}
7512 return s;
7513 };
7514 var d = new Date();";
7515 }
7516
7517 // Generate the date part, depending on the use or not of the javascript calendar
7518 if ($addnowlink == 1) { // server time expressed in user time setup
7519 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7520 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7521 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7522 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7523 } elseif ($addnowlink == 2) {
7524 /* Disabled because the output does not use the string format defined by FormatDateShort key to forge the value into #prefix.
7525 * This break application for foreign languages.
7526 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(d.toLocaleDateString(\''.str_replace('_', '-', $langs->defaultlang).'\'));';
7527 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(d.getDate().pad());';
7528 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(parseInt(d.getMonth().pad()) + 1);';
7529 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(d.getFullYear());';
7530 */
7531 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'day', 'tzuserrel') . '\');';
7532 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7533 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7534 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7535 }
7536 /*if ($usecalendar == "eldy")
7537 {
7538 $base=DOL_URL_ROOT.'/core/';
7539 $reset_scripts .= 'resetDP(\''.$base.'\',\''.$prefix.'\',\''.$langs->trans("FormatDateShortJavaInput").'\',\''.$langs->defaultlang.'\');';
7540 }
7541 else
7542 {
7543 $reset_scripts .= 'this.form.elements[\''.$prefix.'day\'].value=formatDate(new Date(), \'d\'); ';
7544 $reset_scripts .= 'this.form.elements[\''.$prefix.'month\'].value=formatDate(new Date(), \'M\'); ';
7545 $reset_scripts .= 'this.form.elements[\''.$prefix.'year\'].value=formatDate(new Date(), \'yyyy\'); ';
7546 }*/
7547 // Update the hour part
7548 if ($h) {
7549 if ($fullday) {
7550 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7551 }
7552 //$reset_scripts .= 'this.form.elements[\''.$prefix.'hour\'].value=formatDate(new Date(), \'HH\'); ';
7553 if ($addnowlink == 1) {
7554 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7555 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7556 } elseif ($addnowlink == 2) {
7557 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(d.getHours().pad());';
7558 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').change();';
7559 }
7560
7561 if ($fullday) {
7562 $reset_scripts .= ' } ';
7563 }
7564 }
7565 // Update the minute part
7566 if ($m) {
7567 if ($fullday) {
7568 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7569 }
7570 //$reset_scripts .= 'this.form.elements[\''.$prefix.'min\'].value=formatDate(new Date(), \'mm\'); ';
7571 if ($addnowlink == 1) {
7572 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7573 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7574 } elseif ($addnowlink == 2) {
7575 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(d.getMinutes().pad());';
7576 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').change();';
7577 }
7578 if ($fullday) {
7579 $reset_scripts .= ' } ';
7580 }
7581 }
7582 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7583 if ($reset_scripts && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
7584 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonNow" type="button" name="_useless" value="now" onClick="' . $reset_scripts . '">';
7585 $retstring .= $langs->trans("Now");
7586 $retstring .= '</button> ';
7587 }
7588 }
7589
7590 // Add a "Plus one hour" link
7591 if ($conf->use_javascript_ajax && $addplusone && !$disabled) {
7592 // Script which will be inserted in the onClick of the "Add plusone" link
7593 $reset_scripts = "";
7594
7595 // Generate the date part, depending on the use or not of the javascript calendar
7596 $reset_scripts .= 'jQuery(\'#' . $prefix . '\').val(\'' . dol_print_date($nowgmt, 'dayinputnoreduce', 'tzuserrel') . '\');';
7597 $reset_scripts .= 'jQuery(\'#' . $prefix . 'day\').val(\'' . dol_print_date($nowgmt, '%d', 'tzuserrel') . '\');';
7598 $reset_scripts .= 'jQuery(\'#' . $prefix . 'month\').val(\'' . dol_print_date($nowgmt, '%m', 'tzuserrel') . '\');';
7599 $reset_scripts .= 'jQuery(\'#' . $prefix . 'year\').val(\'' . dol_print_date($nowgmt, '%Y', 'tzuserrel') . '\');';
7600 // Update the hour part
7601 if ($h) {
7602 if ($fullday) {
7603 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7604 }
7605 $reset_scripts .= 'jQuery(\'#' . $prefix . 'hour\').val(\'' . dol_print_date($nowgmt, '%H', 'tzuserrel') . '\');';
7606 if ($fullday) {
7607 $reset_scripts .= ' } ';
7608 }
7609 }
7610 // Update the minute part
7611 if ($m) {
7612 if ($fullday) {
7613 $reset_scripts .= " if (jQuery('#fullday:checked').val() == null) {";
7614 }
7615 $reset_scripts .= 'jQuery(\'#' . $prefix . 'min\').val(\'' . dol_print_date($nowgmt, '%M', 'tzuserrel') . '\');';
7616 if ($fullday) {
7617 $reset_scripts .= ' } ';
7618 }
7619 }
7620 // If reset_scripts is not empty, print the link with the reset_scripts in the onClick
7621 if ($reset_scripts && empty($conf->dol_optimize_smallscreen)) {
7622 $retstring .= ' <button class="dpInvisibleButtons datenowlink" id="' . $prefix . 'ButtonPlusOne" type="button" name="_useless2" value="plusone" onClick="' . $reset_scripts . '">';
7623 $retstring .= $langs->trans("DateStartPlusOne");
7624 $retstring .= '</button> ';
7625 }
7626 }
7627
7628 // Add a link to set data
7629 if ($conf->use_javascript_ajax && !empty($adddateof) && !$disabled) {
7630 if (!is_array($adddateof)) {
7631 $arrayofdateof = array(array('adddateof' => $adddateof, 'labeladddateof' => $labeladddateof));
7632 } else {
7633 $arrayofdateof = $adddateof;
7634 }
7635 foreach ($arrayofdateof as $valuedateof) {
7636 $tmpadddateof = empty($valuedateof['adddateof']) ? 0 : $valuedateof['adddateof'];
7637 $tmplabeladddateof = empty($valuedateof['labeladddateof']) ? '' : $valuedateof['labeladddateof'];
7638 $tmparray = dol_getdate($tmpadddateof);
7639 if (empty($tmplabeladddateof)) {
7640 $tmplabeladddateof = $langs->trans("DateInvoice");
7641 }
7642 $reset_scripts = 'console.log(\'Click on now link\'); ';
7643 $reset_scripts .= 'jQuery(\'#'.$prefix.'\').val(\''.dol_print_date($tmpadddateof, 'dayinputnoreduce').'\');';
7644 $reset_scripts .= 'jQuery(\'#'.$prefix.'day\').val(\''.$tmparray['mday'].'\');';
7645 $reset_scripts .= 'jQuery(\'#'.$prefix.'month\').val(\''.$tmparray['mon'].'\');';
7646 $reset_scripts .= 'jQuery(\'#'.$prefix.'year\').val(\''.$tmparray['year'].'\');';
7647 $retstring .= ' - <button class="dpInvisibleButtons datenowlink" id="dateofinvoice" type="button" name="_dateofinvoice" value="now" onclick="'.$reset_scripts.'">'.$tmplabeladddateof.'</button>';
7648 }
7649 }
7650
7651 return $retstring;
7652 }
7653
7662 public function selectTypeDuration($prefix, $selected = 'i', $excludetypes = array())
7663 {
7664 global $langs;
7665
7666 $TDurationTypes = array(
7667 'y' => $langs->trans('Years'),
7668 'm' => $langs->trans('Month'),
7669 'w' => $langs->trans('Weeks'),
7670 'd' => $langs->trans('Days'),
7671 'h' => $langs->trans('Hours'),
7672 'i' => $langs->trans('Minutes')
7673 );
7674
7675 // Removed undesired duration types
7676 foreach ($excludetypes as $value) {
7677 unset($TDurationTypes[$value]);
7678 }
7679
7680 $retstring = '<select class="flat minwidth75 maxwidth100" id="select_' . $prefix . 'type_duration" name="' . $prefix . 'type_duration">';
7681 foreach ($TDurationTypes as $key => $typeduration) {
7682 $retstring .= '<option value="' . $key . '"';
7683 if ($key == $selected) {
7684 $retstring .= " selected";
7685 }
7686 $retstring .= ">" . $typeduration . "</option>";
7687 }
7688 $retstring .= "</select>";
7689
7690 $retstring .= ajax_combobox('select_' . $prefix . 'type_duration');
7691
7692 return $retstring;
7693 }
7694
7695 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
7696
7710 public function select_duration($prefix, $iSecond = '', $disabled = 0, $typehour = 'select', $minunderhours = 0, $nooutput = 0)
7711 {
7712 // phpcs:enable
7713 global $langs;
7714
7715 $retstring = '<span class="nowraponall">';
7716
7717 $hourSelected = '';
7718 $minSelected = '';
7719
7720 // Hours
7721 if ($iSecond != '') {
7722 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
7723
7724 $hourSelected = convertSecondToTime($iSecond, 'allhour');
7725 $minSelected = convertSecondToTime($iSecond, 'min');
7726 }
7727
7728 if ($typehour == 'select') {
7729 $retstring .= '<select class="flat" id="select_' . $prefix . 'hour" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . '>';
7730 for ($hour = 0; $hour < 25; $hour++) { // For a duration, we allow 24 hours
7731 $retstring .= '<option value="' . $hour . '"';
7732 if (is_numeric($hourSelected) && $hourSelected == $hour) {
7733 $retstring .= " selected";
7734 }
7735 $retstring .= ">" . $hour . "</option>";
7736 }
7737 $retstring .= "</select>";
7738 } elseif ($typehour == 'text' || $typehour == 'textselect') {
7739 $retstring .= '<input placeholder="' . $langs->trans('HourShort') . '" type="number" min="0" name="' . $prefix . 'hour"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputhour right" value="' . (($hourSelected != '') ? ((int) $hourSelected) : '') . '">';
7740 } else {
7741 return 'BadValueForParameterTypeHour';
7742 }
7743
7744 if ($typehour != 'text') {
7745 $retstring .= ' ' . $langs->trans('HourShort');
7746 } else {
7747 $retstring .= '<span class="">:</span>';
7748 }
7749
7750 // Minutes
7751 if ($minunderhours) {
7752 $retstring .= '<br>';
7753 } else {
7754 if ($typehour != 'text') {
7755 $retstring .= '<span class="hideonsmartphone">&nbsp;</span>';
7756 }
7757 }
7758
7759 if ($typehour == 'select' || $typehour == 'textselect') {
7760 $retstring .= '<select class="flat" id="select_' . $prefix . 'min" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . '>';
7761 for ($min = 0; $min <= 55; $min += 5) {
7762 $retstring .= '<option value="' . $min . '"';
7763 if (is_numeric($minSelected) && $minSelected == $min) {
7764 $retstring .= ' selected';
7765 }
7766 $retstring .= '>' . $min . '</option>';
7767 }
7768 $retstring .= "</select>";
7769 } elseif ($typehour == 'text') {
7770 $retstring .= '<input placeholder="' . $langs->trans('MinuteShort') . '" type="number" min="0" name="' . $prefix . 'min"' . ($disabled ? ' disabled' : '') . ' class="flat maxwidth50 inputminute right" value="' . (($minSelected != '') ? ((int) $minSelected) : '') . '">';
7771 }
7772
7773 if ($typehour != 'text') {
7774 $retstring .= ' ' . $langs->trans('MinuteShort');
7775 }
7776
7777 $retstring .= "</span>";
7778
7779 if (!empty($nooutput)) {
7780 return $retstring;
7781 }
7782
7783 print $retstring;
7784
7785 return '';
7786 }
7787
7807 public function selectTickets($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
7808 {
7809 global $langs, $conf;
7810
7811 $out = '';
7812
7813 // check parameters
7814 if (is_null($ajaxoptions)) {
7815 $ajaxoptions = array();
7816 }
7817
7818 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7819 $placeholder = '';
7820
7821 if ($selected && empty($selected_input_value)) {
7822 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7823 $tickettmpselect = new Ticket($this->db);
7824 $tickettmpselect->fetch($selected);
7825 $selected_input_value = $tickettmpselect->ref;
7826 unset($tickettmpselect);
7827 }
7828
7829 $urloption = '';
7830 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/ticket/ajax/tickets.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
7831
7832 if (empty($hidelabel)) {
7833 $out .= $langs->trans("RefOrLabel") . ' : ';
7834 } elseif ($hidelabel > 1) {
7835 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
7836 if ($hidelabel == 2) {
7837 $out .= img_picto($langs->trans("Search"), 'search');
7838 }
7839 }
7840 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
7841 if ($hidelabel == 3) {
7842 $out .= img_picto($langs->trans("Search"), 'search');
7843 }
7844 } else {
7845 $out .= $this->selectTicketsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
7846 }
7847
7848 if (empty($nooutput)) {
7849 print $out;
7850 } else {
7851 return $out;
7852 }
7853 return '';
7854 }
7855
7856
7873 public function selectTicketsList($selected = '', $htmlname = 'ticketid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
7874 {
7875 global $langs, $conf;
7876
7877 $out = '';
7878 $outarray = array();
7879
7880 $selectFields = " p.rowid, p.ref, p.message";
7881
7882 $sql = "SELECT ";
7883 $sql .= $selectFields;
7884 $sql .= " FROM " . $this->db->prefix() . "ticket as p";
7885 $sql .= ' WHERE p.entity IN (' . getEntity('ticket') . ')';
7886
7887 // Add criteria on ref/label
7888 if ($filterkey != '') {
7889 $sql .= ' AND (';
7890 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
7891 // For natural search
7892 $search_crit = explode(' ', $filterkey);
7893 $i = 0;
7894 if (count($search_crit) > 1) {
7895 $sql .= "(";
7896 }
7897 foreach ($search_crit as $crit) {
7898 if ($i > 0) {
7899 $sql .= " AND ";
7900 }
7901 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.subject LIKE '" . $this->db->escape($prefix . $crit) . "%'";
7902 $sql .= ")";
7903 $i++;
7904 }
7905 if (count($search_crit) > 1) {
7906 $sql .= ")";
7907 }
7908 $sql .= ')';
7909 }
7910
7911 $sql .= $this->db->plimit($limit, 0);
7912
7913 // Build output string
7914 dol_syslog(get_class($this) . "::selectTicketsList search tickets", LOG_DEBUG);
7915 $result = $this->db->query($sql);
7916 if ($result) {
7917 require_once DOL_DOCUMENT_ROOT . '/ticket/class/ticket.class.php';
7918 require_once DOL_DOCUMENT_ROOT . '/core/lib/ticket.lib.php';
7919
7920 $num = $this->db->num_rows($result);
7921
7922 $events = array();
7923
7924 if (!$forcecombo) {
7925 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
7926 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('TICKET_USE_SEARCH_TO_SELECT'));
7927 }
7928
7929 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
7930
7931 $textifempty = '';
7932 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
7933 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
7934 if (getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
7935 if ($showempty && !is_numeric($showempty)) {
7936 $textifempty = $langs->trans($showempty);
7937 } else {
7938 $textifempty .= $langs->trans("All");
7939 }
7940 } else {
7941 if ($showempty && !is_numeric($showempty)) {
7942 $textifempty = $langs->trans($showempty);
7943 }
7944 }
7945 if ($showempty) {
7946 $out .= '<option value="0" selected>' . $textifempty . '</option>';
7947 }
7948
7949 $i = 0;
7950 while ($num && $i < $num) {
7951 $opt = '';
7952 $optJson = array();
7953 $objp = $this->db->fetch_object($result);
7954
7955 $this->constructTicketListOption($objp, $opt, $optJson, $selected, $filterkey);
7956 '@phan-var-force array{key:string,value:mixed,type:int} $optJson';
7957 // Add new entry
7958 // "key" value of json key array is used by jQuery automatically as selected value
7959 // "label" value of json key array is used by jQuery automatically as text for combo box
7960 $out .= $opt;
7961 array_push($outarray, $optJson);
7962
7963 $i++;
7964 }
7965
7966 $out .= '</select>';
7967
7968 $this->db->free($result);
7969
7970 if (empty($outputmode)) {
7971 return $out;
7972 }
7973 return $outarray;
7974 } else {
7975 dol_print_error($this->db);
7976 }
7977
7978 return array();
7979 }
7980
7992 protected function constructTicketListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
7993 {
7994 $outkey = '';
7995 $outref = '';
7996 $outtype = '';
7997
7998 $outkey = $objp->rowid;
7999 $outref = $objp->ref;
8000
8001 $opt = '<option value="' . $objp->rowid . '"';
8002 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8003 $opt .= '>';
8004 $opt .= $objp->ref;
8005 $objRef = $objp->ref;
8006 if (!empty($filterkey) && $filterkey != '') {
8007 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8008 }
8009
8010 $opt .= "</option>\n";
8011 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8012 }
8013
8033 public function selectProjects($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
8034 {
8035 global $langs, $conf;
8036
8037 $out = '';
8038
8039 // check parameters
8040 if (is_null($ajaxoptions)) {
8041 $ajaxoptions = array();
8042 }
8043
8044 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8045 $placeholder = '';
8046
8047 if ($selected && empty($selected_input_value)) {
8048 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8049 $projecttmpselect = new Project($this->db);
8050 $projecttmpselect->fetch($selected);
8051 $selected_input_value = $projecttmpselect->ref;
8052 unset($projecttmpselect);
8053 }
8054
8055 $urloption = '';
8056 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/projet/ajax/projects.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8057
8058 if (empty($hidelabel)) {
8059 $out .= $langs->trans("RefOrLabel") . ' : ';
8060 } elseif ($hidelabel > 1) {
8061 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8062 if ($hidelabel == 2) {
8063 $out .= img_picto($langs->trans("Search"), 'search');
8064 }
8065 }
8066 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8067 if ($hidelabel == 3) {
8068 $out .= img_picto($langs->trans("Search"), 'search');
8069 }
8070 } else {
8071 $out .= $this->selectProjectsList($selected, $htmlname, $filtertype, $limit, '', $status, 0, $showempty, $forcecombo, $morecss);
8072 }
8073
8074 if (empty($nooutput)) {
8075 print $out;
8076 } else {
8077 return $out;
8078 }
8079 return '';
8080 }
8081
8098 public function selectProjectsList($selected = '', $htmlname = 'projectid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8099 {
8100 global $langs, $conf;
8101
8102 $out = '';
8103 $outarray = array();
8104
8105 $selectFields = " p.rowid, p.ref";
8106
8107 $sql = "SELECT ";
8108 $sql .= $selectFields;
8109 $sql .= " FROM " . $this->db->prefix() . "projet as p";
8110 $sql .= ' WHERE p.entity IN (' . getEntity('project') . ')';
8111
8112 // Add criteria on ref/label
8113 if ($filterkey != '') {
8114 $sql .= ' AND (';
8115 $prefix = !getDolGlobalString('TICKET_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8116 // For natural search
8117 $search_crit = explode(' ', $filterkey);
8118 $i = 0;
8119 if (count($search_crit) > 1) {
8120 $sql .= "(";
8121 }
8122 foreach ($search_crit as $crit) {
8123 if ($i > 0) {
8124 $sql .= " AND ";
8125 }
8126 $sql .= "p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8127 $sql .= "";
8128 $i++;
8129 }
8130 if (count($search_crit) > 1) {
8131 $sql .= ")";
8132 }
8133 $sql .= ')';
8134 }
8135
8136 $sql .= $this->db->plimit($limit, 0);
8137
8138 // Build output string
8139 dol_syslog(get_class($this) . "::selectProjectsList search projects", LOG_DEBUG);
8140 $result = $this->db->query($sql);
8141 if ($result) {
8142 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
8143 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
8144
8145 $num = $this->db->num_rows($result);
8146
8147 $events = array();
8148
8149 if (!$forcecombo) {
8150 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8151 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt('PROJECT_USE_SEARCH_TO_SELECT'));
8152 }
8153
8154 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8155
8156 $textifempty = '';
8157 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8158 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8159 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8160 if ($showempty && !is_numeric($showempty)) {
8161 $textifempty = $langs->trans($showempty);
8162 } else {
8163 $textifempty .= $langs->trans("All");
8164 }
8165 } else {
8166 if ($showempty && !is_numeric($showempty)) {
8167 $textifempty = $langs->trans($showempty);
8168 }
8169 }
8170 if ($showempty) {
8171 $out .= '<option value="0" selected>' . $textifempty . '</option>';
8172 }
8173
8174 $i = 0;
8175 while ($num && $i < $num) {
8176 $opt = '';
8177 $optJson = array();
8178 $objp = $this->db->fetch_object($result);
8179
8180 $this->constructProjectListOption($objp, $opt, $optJson, $selected, $filterkey);
8181 // Add new entry
8182 // "key" value of json key array is used by jQuery automatically as selected value
8183 // "label" value of json key array is used by jQuery automatically as text for combo box
8184 $out .= $opt;
8185 array_push($outarray, $optJson);
8186
8187 $i++;
8188 }
8189
8190 $out .= '</select>';
8191
8192 $this->db->free($result);
8193
8194 if (empty($outputmode)) {
8195 return $out;
8196 }
8197 return $outarray;
8198 } else {
8199 dol_print_error($this->db);
8200 }
8201
8202 return array();
8203 }
8204
8216 protected function constructProjectListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8217 {
8218 $outkey = '';
8219 $outref = '';
8220 $outtype = '';
8221
8222 $label = $objp->label;
8223
8224 $outkey = $objp->rowid;
8225 $outref = $objp->ref;
8226 $outlabel = $objp->label;
8227 $outtype = $objp->fk_product_type;
8228
8229 $opt = '<option value="' . $objp->rowid . '"';
8230 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8231 $opt .= '>';
8232 $opt .= $objp->ref;
8233 $objRef = $objp->ref;
8234 if (!empty($filterkey) && $filterkey != '') {
8235 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
8236 }
8237
8238 $opt .= "</option>\n";
8239 $optJson = array('key' => $outkey, 'value' => $outref, 'type' => $outtype);
8240 }
8241
8242
8262 public function selectMembers($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 0, $status = 1, $selected_input_value = '', $hidelabel = 0, $ajaxoptions = array(), $socid = 0, $showempty = '1', $forcecombo = 0, $morecss = '', $selected_combinations = null, $nooutput = 0)
8263 {
8264 global $langs, $conf;
8265
8266 $out = '';
8267
8268 // check parameters
8269 if (is_null($ajaxoptions)) {
8270 $ajaxoptions = array();
8271 }
8272
8273 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('TICKET_USE_SEARCH_TO_SELECT')) {
8274 $placeholder = '';
8275
8276 if ($selected && empty($selected_input_value)) {
8277 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8278 $adherenttmpselect = new Adherent($this->db);
8279 $adherenttmpselect->fetch($selected);
8280 $selected_input_value = $adherenttmpselect->ref;
8281 unset($adherenttmpselect);
8282 }
8283
8284 $urloption = '';
8285
8286 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/adherents/ajax/adherents.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
8287
8288 if (empty($hidelabel)) {
8289 $out .= $langs->trans("RefOrLabel") . ' : ';
8290 } elseif ($hidelabel > 1) {
8291 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
8292 if ($hidelabel == 2) {
8293 $out .= img_picto($langs->trans("Search"), 'search');
8294 }
8295 }
8296 $out .= '<input type="text" class="minwidth100" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
8297 if ($hidelabel == 3) {
8298 $out .= img_picto($langs->trans("Search"), 'search');
8299 }
8300 } else {
8301 $filterkey = '';
8302
8303 $out .= $this->selectMembersList($selected, $htmlname, $filtertype, $limit, $filterkey, $status, 0, $showempty, $forcecombo, $morecss);
8304 }
8305
8306 if (empty($nooutput)) {
8307 print $out;
8308 } else {
8309 return $out;
8310 }
8311 return '';
8312 }
8313
8330 public function selectMembersList($selected = '', $htmlname = 'adherentid', $filtertype = '', $limit = 20, $filterkey = '', $status = 1, $outputmode = 0, $showempty = '1', $forcecombo = 0, $morecss = '')
8331 {
8332 global $langs, $conf;
8333
8334 $out = '';
8335 $outarray = array();
8336
8337 $selectFields = " p.rowid, p.ref, p.firstname, p.lastname, p.fk_adherent_type";
8338
8339 $sql = "SELECT ";
8340 $sql .= $selectFields;
8341 $sql .= " FROM " . $this->db->prefix() . "adherent as p";
8342 $sql .= ' WHERE p.entity IN (' . getEntity('adherent') . ')';
8343
8344 // Add criteria on ref/label
8345 if ($filterkey != '') {
8346 $sql .= ' AND (';
8347 $prefix = !getDolGlobalString('MEMBER_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
8348 // For natural search
8349 $search_crit = explode(' ', $filterkey);
8350 $i = 0;
8351 if (count($search_crit) > 1) {
8352 $sql .= "(";
8353 }
8354 foreach ($search_crit as $crit) {
8355 if ($i > 0) {
8356 $sql .= " AND ";
8357 }
8358 $sql .= "(p.firstname LIKE '" . $this->db->escape($prefix . $crit) . "%'";
8359 $sql .= " OR p.lastname LIKE '" . $this->db->escape($prefix . $crit) . "%')";
8360 $i++;
8361 }
8362 if (count($search_crit) > 1) {
8363 $sql .= ")";
8364 }
8365 $sql .= ')';
8366 }
8367 if ($status != -1) {
8368 $sql .= ' AND statut = ' . ((int) $status);
8369 }
8370 $sql .= $this->db->plimit($limit, 0);
8371
8372 // Build output string
8373 dol_syslog(get_class($this) . "::selectMembersList search adherents", LOG_DEBUG);
8374 $result = $this->db->query($sql);
8375 if ($result) {
8376 require_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
8377 require_once DOL_DOCUMENT_ROOT . '/core/lib/member.lib.php';
8378
8379 $num = $this->db->num_rows($result);
8380
8381 $events = array();
8382
8383 if (!$forcecombo) {
8384 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8385 $out .= ajax_combobox($htmlname, $events, getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT') ? $conf->global->PROJECT_USE_SEARCH_TO_SELECT : '');
8386 }
8387
8388 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
8389
8390 $textifempty = '';
8391 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
8392 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8393 if (getDolGlobalString('PROJECT_USE_SEARCH_TO_SELECT')) {
8394 if ($showempty && !is_numeric($showempty)) {
8395 $textifempty = $langs->trans($showempty);
8396 } else {
8397 $textifempty .= $langs->trans("All");
8398 }
8399 } else {
8400 if ($showempty && !is_numeric($showempty)) {
8401 $textifempty = $langs->trans($showempty);
8402 }
8403 }
8404 if ($showempty) {
8405 $out .= '<option value="-1" selected>' . $textifempty . '</option>';
8406 }
8407
8408 $i = 0;
8409 while ($num && $i < $num) {
8410 $opt = '';
8411 $optJson = array();
8412 $objp = $this->db->fetch_object($result);
8413
8414 $this->constructMemberListOption($objp, $opt, $optJson, $selected, $filterkey);
8415
8416 // Add new entry
8417 // "key" value of json key array is used by jQuery automatically as selected value
8418 // "label" value of json key array is used by jQuery automatically as text for combo box
8419 $out .= $opt;
8420 array_push($outarray, $optJson);
8421
8422 $i++;
8423 }
8424
8425 $out .= '</select>';
8426
8427 $this->db->free($result);
8428
8429 if (empty($outputmode)) {
8430 return $out;
8431 }
8432 return $outarray;
8433 } else {
8434 dol_print_error($this->db);
8435 }
8436
8437 return array();
8438 }
8439
8451 protected function constructMemberListOption(&$objp, &$opt, &$optJson, $selected, $filterkey = '')
8452 {
8453 $outkey = '';
8454 $outlabel = '';
8455 $outtype = '';
8456
8457 $outkey = $objp->rowid;
8458 $outlabel = dolGetFirstLastname($objp->firstname, $objp->lastname);
8459 $outtype = $objp->fk_adherent_type;
8460
8461 $opt = '<option value="' . $objp->rowid . '"';
8462 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
8463 $opt .= '>';
8464 if (!empty($filterkey) && $filterkey != '') {
8465 $outlabel = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $outlabel, 1);
8466 }
8467 $opt .= $outlabel;
8468 $opt .= "</option>\n";
8469
8470 $optJson = array('key' => $outkey, 'value' => $outlabel, 'type' => $outtype);
8471 }
8472
8493 public function selectForForms($objectdesc, $htmlname, $preSelectedValue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0, $selected_input_value = '', $objectfield = '')
8494 {
8495 global $conf, $extrafields, $user;
8496
8497 // Example of common usage for a link to a thirdparty
8498
8499 // We got this in a modulebuilder form of "MyObject" of module "mymodule".
8500 // ->fields is array( ... "fk_soc" => array("type"=>"integer:Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)
8501 // $objectdesc = 'Societe'
8502 // $objectfield = 'myobject@mymodule:fk_soc' ('fk_soc' is code to retrieve myobject->fields['fk_soc'])
8503
8504 // We got this when showing an extrafields on resource that is a link to societe
8505 // extrafields 'link_to_societe' of Resource is 'link' to 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))" ...)'
8506 // $objectdesc = 'Societe'
8507 // $objectfield = 'resource:options_link_to_societe'
8508
8509 // With old usage:
8510 // $objectdesc = 'Societe:societe/class/societe.class.php:1:((status:=:1) AND (entity:IN:__SHARED_ENTITIES__))'
8511 // $objectfield = ''
8512
8513 //var_dump($objectdesc.' '.$objectfield);
8514 //debug_print_backtrace();
8515
8516 $objectdescorig = $objectdesc;
8517 $objecttmp = null;
8518 $InfoFieldList = array();
8519 $classname = '';
8520 $filter = ''; // Ensure filter has value (for static analysis)
8521 $sortfield = ''; // Ensure filter has value (for static analysis)
8522
8523 if ($objectfield) { // We must retrieve the objectdesc from the field or extrafield
8524 // Example: $objectfield = 'product:options_package' or 'myobject@mymodule:options_myfield'
8525 $tmparray = explode(':', $objectfield);
8526
8527 // Get instance of object from $element
8528 $objectforfieldstmp = fetchObjectByElement(0, strtolower($tmparray[0]));
8529
8530 if (is_object($objectforfieldstmp)) {
8531 $objectdesc = '';
8532
8533 $reg = array();
8534 if (preg_match('/^options_(.*)$/', $tmparray[1], $reg)) {
8535 // For a property in extrafields
8536 $key = $reg[1];
8537 // fetch optionals attributes and labels
8538 $extrafields->fetch_name_optionals_label($objectforfieldstmp->table_element);
8539
8540 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key]) && $extrafields->attributes[$objectforfieldstmp->table_element]['type'][$key] == 'link') {
8541 if (!empty($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options'])) {
8542 $tmpextrafields = array_keys($extrafields->attributes[$objectforfieldstmp->table_element]['param'][$key]['options']);
8543 $objectdesc = $tmpextrafields[0];
8544 }
8545 }
8546 } else {
8547 // For a property in ->fields
8548 if (array_key_exists($tmparray[1], $objectforfieldstmp->fields)) {
8549 $objectdesc = $objectforfieldstmp->fields[$tmparray[1]]['type'];
8550 $objectdesc = preg_replace('/^integer[^:]*:/', '', $objectdesc);
8551 }
8552 }
8553 }
8554 }
8555
8556 if ($objectdesc) {
8557 // Example of value for $objectdesc:
8558 // Bom:bom/class/bom.class.php:0:t.status=1
8559 // Bom:bom/class/bom.class.php:0:t.status=1:ref
8560 // Bom:bom/class/bom.class.php:0:(t.status:=:1) OR (t.field2:=:2):ref
8561 $InfoFieldList = explode(":", $objectdesc, 4);
8562 $vartmp = (empty($InfoFieldList[3]) ? '' : $InfoFieldList[3]);
8563 $reg = array();
8564 if (preg_match('/^.*:(\w*)$/', $vartmp, $reg)) {
8565 $InfoFieldList[4] = $reg[1]; // take the sort field
8566 }
8567 $InfoFieldList[3] = preg_replace('/:\w*$/', '', $vartmp); // take the filter field
8568
8569 $classname = $InfoFieldList[0];
8570 $classpath = empty($InfoFieldList[1]) ? '' : $InfoFieldList[1];
8571 //$addcreatebuttonornot = empty($InfoFieldList[2]) ? 0 : $InfoFieldList[2];
8572 $filter = empty($InfoFieldList[3]) ? '' : $InfoFieldList[3];
8573 $sortfield = empty($InfoFieldList[4]) ? '' : $InfoFieldList[4];
8574
8575 // Load object according to $id and $element
8576 $objecttmp = fetchObjectByElement(0, strtolower($InfoFieldList[0]));
8577
8578 // Fallback to another solution to get $objecttmp
8579 if (empty($objecttmp) && !empty($classpath)) {
8580 dol_include_once($classpath);
8581
8582 if ($classname && class_exists($classname)) {
8583 $objecttmp = new $classname($this->db);
8584 }
8585 }
8586 }
8587
8588 // Make some replacement in $filter. May not be used if we used the ajax mode with $objectfield. In such a case
8589 // we propagate the $objectfield and not the filter and replacement is done by the ajax/selectobject.php component.
8590 $sharedentities = (is_object($objecttmp) && property_exists($objecttmp, 'element')) ? getEntity($objecttmp->element) : strtolower($classname);
8591 $filter = str_replace(
8592 array('__ENTITY__', '__SHARED_ENTITIES__', '__USER_ID__'),
8593 array($conf->entity, $sharedentities, $user->id),
8594 $filter
8595 );
8596
8597 if (!is_object($objecttmp)) {
8598 dol_syslog('selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc, LOG_WARNING);
8599 return 'selectForForms: Error bad setup of field objectdescorig=' . $objectdescorig.', objectfield='.$objectfield.', objectdesc='.$objectdesc;
8600 }
8601 '@phan-var-force CommonObject $objecttmp';
8603 //var_dump($filter);
8604 $prefixforautocompletemode = $objecttmp->element;
8605 if ($prefixforautocompletemode == 'societe') {
8606 $prefixforautocompletemode = 'company';
8607 }
8608 if ($prefixforautocompletemode == 'product') {
8609 $prefixforautocompletemode = 'produit';
8610 }
8611 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8612
8613 dol_syslog(get_class($this) . "::selectForForms filter=" . $filter, LOG_DEBUG);
8614
8615 // Generate the combo HTML component
8616 $out = '';
8617 if (!empty($conf->use_javascript_ajax) && getDolGlobalString($confkeyforautocompletemode) && !$forcecombo) {
8618 // No immediate load of all database
8619 $placeholder = '';
8620
8621 if ($preSelectedValue && empty($selected_input_value)) {
8622 $objecttmp->fetch($preSelectedValue);
8623 $selected_input_value = ($prefixforautocompletemode == 'company' ? $objecttmp->name : $objecttmp->ref);
8624
8625 $oldValueForShowOnCombobox = 0;
8626 foreach ($objecttmp->fields as $fieldK => $fielV) {
8627 if (!array_key_exists('showoncombobox', $fielV) || !$fielV['showoncombobox'] || empty($objecttmp->$fieldK)) {
8628 continue;
8629 }
8630
8631 if (!$oldValueForShowOnCombobox) {
8632 $selected_input_value = '';
8633 }
8634
8635 $selected_input_value .= $oldValueForShowOnCombobox ? ' - ' : '';
8636 $selected_input_value .= $objecttmp->$fieldK;
8637 $oldValueForShowOnCombobox = empty($fielV['showoncombobox']) ? 0 : $fielV['showoncombobox'];
8638 }
8639 }
8640
8641 // Set url and param to call to get json of the search results
8642 $urlforajaxcall = DOL_URL_ROOT . '/core/ajax/selectobject.php';
8643 $urloption = 'htmlname=' . urlencode($htmlname) . '&outjson=1&objectdesc=' . urlencode($objectdescorig) . '&objectfield='.urlencode($objectfield) . ($sortfield ? '&sortfield=' . urlencode($sortfield) : '');
8644
8645 // Activate the auto complete using ajax call.
8646 $out .= ajax_autocompleter((string) $preSelectedValue, $htmlname, $urlforajaxcall, $urloption, getDolGlobalInt($confkeyforautocompletemode), 0);
8647 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
8648 $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) . '"' : '') . ' />';
8649 } else {
8650 // Immediate load of table record.
8651 $out .= $this->selectForFormsList($objecttmp, $htmlname, $preSelectedValue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled, $sortfield, $filter);
8652 }
8653
8654 return $out;
8655 }
8656
8657
8678 public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0, $sortfield = '', $filter = '')
8679 {
8680 global $langs, $user, $hookmanager;
8681
8682 //print "$htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, $outputmode, $disabled";
8683
8684 $prefixforautocompletemode = $objecttmp->element;
8685 if ($prefixforautocompletemode == 'societe') {
8686 $prefixforautocompletemode = 'company';
8687 }
8688 $confkeyforautocompletemode = strtoupper($prefixforautocompletemode) . '_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT
8689
8690 if (!empty($objecttmp->fields)) { // For object that declare it, it is better to use declared fields (like societe, contact, ...)
8691 $tmpfieldstoshow = '';
8692 foreach ($objecttmp->fields as $key => $val) {
8693 if (! (int) dol_eval($val['enabled'], 1, 1, '1')) {
8694 continue;
8695 }
8696 if (!empty($val['showoncombobox'])) {
8697 $tmpfieldstoshow .= ($tmpfieldstoshow ? ',' : '') . 't.' . $key;
8698 }
8699 }
8700 if ($tmpfieldstoshow) {
8701 $fieldstoshow = $tmpfieldstoshow;
8702 }
8703 } elseif ($objecttmp->element === 'category') {
8704 $fieldstoshow = 't.label';
8705 } else {
8706 // For backward compatibility
8707 $objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);
8708 }
8709
8710 if (empty($fieldstoshow)) {
8711 if (!empty($objecttmp->parent_element)) {
8712 $fieldstoshow = 'o.ref';
8713 if (empty($sortfield)) {
8714 $sortfield = 'o.ref';
8715 }
8716 if (in_array($objecttmp->element, ['commandedet', 'propaldet', 'facturedet', 'expeditiondet'])) {
8717 $fieldstoshow .= ',p.ref AS p_ref,p.label,t.description';
8718 $sortfield .= ', p.ref';
8719 }
8720 } elseif (isset($objecttmp->fields['ref'])) {
8721 $fieldstoshow = 't.ref';
8722 } else {
8723 $langs->load("errors");
8724 $this->error = $langs->trans("ErrorNoFieldWithAttributeShowoncombobox");
8725 return $langs->trans('ErrorNoFieldWithAttributeShowoncombobox');
8726 }
8727 }
8728
8729 $out = '';
8730 $outarray = array();
8731 $tmparray = array();
8732
8733 $num = 0;
8734
8735 // Search data
8736 $sql = "SELECT t.rowid, " . $fieldstoshow . " FROM " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . " as t";
8737 if (!empty($objecttmp->isextrafieldmanaged)) {
8738 $sql .= " LEFT JOIN " . $this->db->prefix() . $this->db->sanitize($objecttmp->table_element) . "_extrafields as e ON t.rowid = e.fk_object";
8739 }
8740 if (!empty($objecttmp->parent_element)) {
8741 $parent_properties = getElementProperties($objecttmp->parent_element);
8742 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($parent_properties['table_element']) . " as o ON o.rowid = t.".$objecttmp->fk_parent_attribute;
8743 }
8744 if (in_array($objecttmp->parent_element, ['commande', 'propal', 'facture', 'expedition'])) {
8745 $sql .= " LEFT JOIN " . $this->db->prefix() . "product as p ON p.rowid = t.fk_product";
8746 }
8747 if (isset($objecttmp->ismultientitymanaged)) {
8748 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8749 $tmparray = explode('@', $objecttmp->ismultientitymanaged);
8750 $sql .= " INNER JOIN " . $this->db->prefix() . $this->db->sanitize($tmparray[1]) . " as parenttable ON parenttable.rowid = t." . $this->db->sanitize($tmparray[0]);
8751 }
8752 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8753 if (!$user->hasRight('societe', 'client', 'voir')) {
8754 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
8755 }
8756 }
8757 }
8758
8759 // Add where from hooks
8760 $parameters = array(
8761 'object' => $objecttmp,
8762 'htmlname' => $htmlname,
8763 'filter' => $filter,
8764 'searchkey' => $searchkey
8765 );
8766
8767 $reshook = $hookmanager->executeHooks('selectForFormsListWhere', $parameters); // Note that $action and $object may have been modified by hook
8768 if (!empty($hookmanager->resPrint)) {
8769 $sql .= $hookmanager->resPrint;
8770 } else {
8771 $sql .= " WHERE 1=1";
8772 if (isset($objecttmp->ismultientitymanaged)) {
8773 if ($objecttmp->ismultientitymanaged == 1) {
8774 $sql .= " AND t.entity IN (" . getEntity($objecttmp->table_element) . ")";
8775 }
8776 if (!is_numeric($objecttmp->ismultientitymanaged)) {
8777 $sql .= " AND parenttable.entity = t." . $this->db->sanitize($tmparray[0]);
8778 }
8779 if ($objecttmp->ismultientitymanaged == 1 && !empty($user->socid)) {
8780 if ($objecttmp->element == 'societe') {
8781 $sql .= " AND t.rowid = " . ((int) $user->socid);
8782 } else {
8783 $sql .= " AND t.fk_soc = " . ((int) $user->socid);
8784 }
8785 }
8786 if ($objecttmp->ismultientitymanaged === 'fk_soc@societe') {
8787 if (!$user->hasRight('societe', 'client', 'voir')) {
8788 $sql .= " AND t.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
8789 }
8790 }
8791 }
8792 $splittedfieldstoshow = explode(',', $fieldstoshow);
8793 foreach ($splittedfieldstoshow as &$field2) {
8794 if (is_numeric($pos = strpos($field2, ' '))) {
8795 $field2 = substr($field2, 0, $pos);
8796 }
8797 }
8798 if ($searchkey != '') {
8799 $sql .= natural_search($splittedfieldstoshow, $searchkey);
8800 }
8801
8802 if ($filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
8803 $errormessage = '';
8804 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
8805 if ($errormessage) {
8806 return 'Error forging a SQL request from an universal criteria: ' . $errormessage;
8807 }
8808 }
8809 }
8810 $sql .= $this->db->order($sortfield ? $sortfield : $fieldstoshow, "ASC");
8811 //$sql.=$this->db->plimit($limit, 0);
8812 //print $sql;
8813
8814 // Build output string
8815 $resql = $this->db->query($sql);
8816 if ($resql) {
8817 // Construct $out and $outarray
8818 $out .= '<select id="' . $htmlname . '" class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ($moreparams ? ' ' . $moreparams : '') . ' name="' . $htmlname . '">' . "\n";
8819
8820 // Warning: Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'. Seems it is no more true with selec2 v4
8821 $textifempty = '&nbsp;';
8822
8823 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
8824 if (getDolGlobalInt($confkeyforautocompletemode)) {
8825 if ($showempty && !is_numeric($showempty)) {
8826 $textifempty = $langs->trans($showempty);
8827 } else {
8828 $textifempty .= $langs->trans("All");
8829 }
8830 }
8831 if ($showempty) {
8832 $out .= '<option value="-1">' . $textifempty . '</option>' . "\n";
8833 }
8834
8835 $num = $this->db->num_rows($resql);
8836 $i = 0;
8837 if ($num) {
8838 while ($i < $num) {
8839 $obj = $this->db->fetch_object($resql);
8840 $label = '';
8841 $labelhtml = '';
8842 $tmparray = explode(',', $fieldstoshow);
8843 $oldvalueforshowoncombobox = 0;
8844 foreach ($tmparray as $key => $val) {
8845 $val = preg_replace('/(t|p|o)\./', '', $val);
8846 $label .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8847 $labelhtml .= (($label && $obj->$val) ? ($oldvalueforshowoncombobox != $objecttmp->fields[$val]['showoncombobox'] ? ' - ' : ' ') : '');
8848 $label .= $obj->$val;
8849 $labelhtml .= $obj->$val;
8850
8851 $oldvalueforshowoncombobox = empty($objecttmp->fields[$val]['showoncombobox']) ? 0 : $objecttmp->fields[$val]['showoncombobox'];
8852 }
8853 if (empty($outputmode)) {
8854 if ($preselectedvalue > 0 && $preselectedvalue == $obj->rowid) {
8855 $out .= '<option value="' . $obj->rowid . '" selected data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8856 } else {
8857 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
8858 }
8859 } else {
8860 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label));
8861 }
8862
8863 $i++;
8864 if (($i % 10) == 0) {
8865 $out .= "\n";
8866 }
8867 }
8868 }
8869
8870 $out .= '</select>' . "\n";
8871
8872 if (!$forcecombo) {
8873 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
8874 $out .= ajax_combobox($htmlname, array(), getDolGlobalInt($confkeyforautocompletemode, 0));
8875 }
8876 } else {
8877 dol_print_error($this->db);
8878 }
8879
8880 $this->result = array('nbofelement' => $num);
8881
8882 if ($outputmode) {
8883 return $outarray;
8884 }
8885 return $out;
8886 }
8887
8888
8912 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 = 'minwidth75', $addjscombo = 1, $moreparamonempty = '', $disablebademail = 0, $nohtmlescape = 0)
8913 {
8914 global $conf, $langs;
8915
8916 // Do we want a multiselect ?
8917 //$jsbeautify = 0;
8918 //if (preg_match('/^multi/',$htmlname)) $jsbeautify = 1;
8919 $jsbeautify = 1;
8920
8921 if ($value_as_key) {
8922 $array = array_combine($array, $array);
8923 }
8924
8925 '@phan-var-force array{label:string,data-html:string,disable?:int<0,1>,css?:string} $array'; // Array combine breaks information
8926
8927 $out = '';
8928
8929 if ($addjscombo < 0) {
8930 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
8931 $addjscombo = 1;
8932 } else {
8933 $addjscombo = 0;
8934 }
8935 }
8936 $idname = str_replace(array('[', ']'), array('', ''), $htmlname);
8937 $out .= '<select id="' . preg_replace('/^\./', '', $idname) . '" ' . ($disabled ? 'disabled="disabled" ' : '') . 'class="flat ' . (preg_replace('/^\./', '', $htmlname)) . ($morecss ? ' ' . $morecss : '') . ' selectformat"';
8938 $out .= ' name="' . preg_replace('/^\./', '', $htmlname) . '" ' . ($moreparam ? $moreparam : '');
8939 $out .= '>'."\n";
8940
8941 if ($show_empty) {
8942 $textforempty = ' ';
8943 if (!empty($conf->use_javascript_ajax)) {
8944 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
8945 }
8946 if (!is_numeric($show_empty)) {
8947 $textforempty = $show_empty;
8948 }
8949 $out .= '<option class="optiongrey" ' . ($moreparamonempty ? $moreparamonempty . ' ' : '') . 'value="' . (((int) $show_empty) < 0 ? $show_empty : -1) . '"' . ($id == $show_empty ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
8950 }
8951 if (is_array($array)) {
8952 // Translate
8953 if ($translate) {
8954 foreach ($array as $key => $value) {
8955 if (!is_array($value)) {
8956 $array[$key] = $langs->trans($value);
8957 } else {
8958 $array[$key]['label'] = $langs->trans($value['label']);
8959 }
8960 }
8961 }
8962 // Sort
8963 if ($sort == 'ASC') {
8964 asort($array);
8965 } elseif ($sort == 'DESC') {
8966 arsort($array);
8967 }
8968
8969 foreach ($array as $key => $tmpvalue) {
8970 if (is_array($tmpvalue)) {
8971 $value = $tmpvalue['label'];
8972 //$valuehtml = empty($tmpvalue['data-html']) ? $value : $tmpvalue['data-html'];
8973 $disabled = empty($tmpvalue['disabled']) ? '' : ' disabled';
8974 $style = empty($tmpvalue['css']) ? '' : ' class="' . $tmpvalue['css'] . '"';
8975 } else {
8976 $value = $tmpvalue;
8977 //$valuehtml = $tmpvalue;
8978 $disabled = '';
8979 $style = '';
8980 }
8981 if (!empty($disablebademail)) {
8982 if (($disablebademail == 1 && !preg_match('/&lt;.+@.+&gt;/', $value))
8983 || ($disablebademail == 2 && preg_match('/---/', $value))) {
8984 $disabled = ' disabled';
8985 $style = ' class="warning"';
8986 }
8987 }
8988 if ($key_in_label) {
8989 if (empty($nohtmlescape)) {
8990 $selectOptionValue = dol_escape_htmltag($key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value));
8991 } else {
8992 $selectOptionValue = $key . ' - ' . ($maxlen ? dol_trunc($value, $maxlen) : $value);
8993 }
8994 } else {
8995 if (empty($nohtmlescape)) {
8996 $selectOptionValue = dol_escape_htmltag($maxlen ? dol_trunc($value, $maxlen) : $value);
8997 } else {
8998 $selectOptionValue = $maxlen ? dol_trunc($value, $maxlen) : $value;
8999 }
9000 if ($value == '' || $value == '-') {
9001 $selectOptionValue = '&nbsp;';
9002 }
9003 }
9004 $out .= '<option value="' . $key . '"';
9005 $out .= $style . $disabled;
9006 if (is_array($id)) {
9007 if (in_array($key, $id) && !$disabled) {
9008 $out .= ' selected'; // To preselect a value
9009 }
9010 } else {
9011 $id = (string) $id; // if $id = 0, then $id = '0'
9012 if ($id != '' && (($id == (string) $key) || ($id == 'ifone' && count($array) == 1)) && !$disabled) {
9013 $out .= ' selected'; // To preselect a value
9014 }
9015 }
9016 if (!empty($nohtmlescape)) { // deprecated. Use instead the key 'data-html' into input $array, managed at next step to use HTML content.
9017 $out .= ' data-html="' . dol_escape_htmltag($selectOptionValue) . '"';
9018 }
9019
9020 if (is_array($tmpvalue)) {
9021 foreach ($tmpvalue as $keyforvalue => $valueforvalue) {
9022 if ($keyforvalue == 'labelhtml') {
9023 $keyforvalue = 'data-html';
9024 }
9025 if (preg_match('/^data-/', $keyforvalue)) { // The best solution if you want to use HTML values into the list is to use data-html.
9026 $out .= ' '.dol_escape_htmltag($keyforvalue).'="'.dol_escape_htmltag($valueforvalue).'"';
9027 }
9028 }
9029 }
9030 $out .= '>';
9031 $out .= $selectOptionValue;
9032 $out .= "</option>\n";
9033 }
9034 }
9035 $out .= "</select>";
9036
9037 // Add code for jquery to use multiselect
9038 if ($addjscombo && $jsbeautify) {
9039 // Enhance with select2
9040 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
9041 $out .= ajax_combobox($idname, array(), 0, 0, 'resolve', (((int) $show_empty) < 0 ? (string) $show_empty : '-1'), $morecss);
9042 }
9043
9044 return $out;
9045 }
9046
9065 public static function selectArrayAjax($htmlname, $url, $id = '', $moreparam = '', $moreparamtourl = '', $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0)
9066 {
9067 global $conf;
9068 global $delayedhtmlcontent; // Will be used later outside of this function
9069
9070 // TODO Use an internal dolibarr component instead of select2
9071 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9072 return '';
9073 }
9074
9075 $out = '<select type="text" class="' . $htmlname . ($morecss ? ' ' . $morecss : '') . '" ' . ($moreparam ? $moreparam . ' ' : '') . 'name="' . $htmlname . '"></select>';
9076
9077 $outdelayed = '';
9078 if (!empty($conf->use_javascript_ajax)) {
9079 $tmpplugin = 'select2';
9080 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9081 <script nonce="' . getNonce() . '">
9082 $(document).ready(function () {
9083
9084 ' . ($callurlonselect ? 'var saveRemoteData = [];' : '') . '
9085
9086 $(".' . $htmlname . '").select2({
9087 ajax: {
9088 dir: "ltr",
9089 url: "' . $url . '",
9090 dataType: \'json\',
9091 delay: 250,
9092 data: function (params) {
9093 return {
9094 q: params.term, // search term
9095 page: params.page
9096 }
9097 },
9098 processResults: function (data) {
9099 // parse the results into the format expected by Select2.
9100 // since we are using custom formatting functions we do not need to alter the remote JSON data
9101 //console.log(data);
9102 saveRemoteData = data;
9103 /* format json result for select2 */
9104 result = []
9105 $.each( data, function( key, value ) {
9106 result.push({id: key, text: value.text});
9107 });
9108 //return {results:[{id:\'none\', text:\'aa\'}, {id:\'rrr\', text:\'Red\'},{id:\'bbb\', text:\'Search a into projects\'}], more:false}
9109 //console.log(result);
9110 return {results: result, more: false}
9111 },
9112 cache: true
9113 },
9114 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9115 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9116 placeholder: \'' . dol_escape_js($placeholder) . '\',
9117 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9118 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9119 formatResult: function (result, container, query, escapeMarkup) {
9120 return escapeMarkup(result.text);
9121 },
9122 });
9123
9124 ' . ($callurlonselect ? '
9125 /* Code to execute a GET when we select a value */
9126 $(".' . $htmlname . '").change(function() {
9127 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9128 console.log("We select in selectArrayAjax the entry "+selected)
9129 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9130 $.each( saveRemoteData, function( key, value ) {
9131 if (key == selected)
9132 {
9133 console.log("selectArrayAjax - Do a redirect to "+value.url)
9134 location.assign(value.url);
9135 }
9136 });
9137 });' : '') . '
9138
9139 });
9140 </script>';
9141 }
9142
9143 if ($acceptdelayedhtml) {
9144 $delayedhtmlcontent .= $outdelayed;
9145 } else {
9146 $out .= $outdelayed;
9147 }
9148 return $out;
9149 }
9150
9170 public static function selectArrayFilter($htmlname, $array, $id = '', $moreparam = '', $disableFiltering = 0, $disabled = 0, $minimumInputLength = 1, $morecss = '', $callurlonselect = 0, $placeholder = '', $acceptdelayedhtml = 0, $textfortitle = '')
9171 {
9172 global $conf;
9173 global $delayedhtmlcontent; // Will be used later outside of this function
9174
9175 // TODO Use an internal dolibarr component instead of select2
9176 if (!getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') && !defined('REQUIRE_JQUERY_MULTISELECT')) {
9177 return '';
9178 }
9179
9180 $out = '<select type="text"'.($textfortitle ? ' title="'.dol_escape_htmltag($textfortitle).'"' : '').' id="'.$htmlname.'" class="'.$htmlname.($morecss ? ' ' . $morecss : '').'"'.($moreparam ? ' '.$moreparam : '').' name="'.$htmlname.'"><option></option></select>';
9181
9182 $formattedarrayresult = array();
9183
9184 foreach ($array as $key => $value) {
9185 $o = new stdClass();
9186 $o->id = $key;
9187 $o->text = $value['text'];
9188 $o->url = $value['url'];
9189 $formattedarrayresult[] = $o;
9190 }
9191
9192 $outdelayed = '';
9193 if (!empty($conf->use_javascript_ajax)) {
9194 $tmpplugin = 'select2';
9195 $outdelayed = "\n" . '<!-- JS CODE TO ENABLE ' . $tmpplugin . ' for id ' . $htmlname . ' -->
9196 <script nonce="' . getNonce() . '">
9197 $(document).ready(function () {
9198 var data = ' . json_encode($formattedarrayresult) . ';
9199
9200 ' . ($callurlonselect ? 'var saveRemoteData = ' . json_encode($array) . ';' : '') . '
9201
9202 $(\'.' . dol_escape_js($htmlname) . '\').select2({
9203 data: data,
9204 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage,
9205 containerCssClass: \':all:\', /* Line to add class from the original SELECT propagated to the new <span class="select2-selection...> tag */
9206 placeholder: \'' . dol_escape_js($placeholder) . '\',
9207 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9208 minimumInputLength: ' . ((int) $minimumInputLength) . ',
9209 formatResult: function (result, container, query, escapeMarkup) {
9210 return escapeMarkup(result.text);
9211 },
9212 matcher: function (params, data) {
9213
9214 if(! data.id) return null;';
9215
9216 if ($callurlonselect) {
9217 // We forge the url with 'sall='
9218 $outdelayed .= '
9219
9220 var urlBase = data.url;
9221 var separ = urlBase.indexOf("?") >= 0 ? "&" : "?";
9222 /* console.log("params.term="+params.term); */
9223 /* console.log("params.term encoded="+encodeURIComponent(params.term)); */
9224 saveRemoteData[data.id].url = urlBase + separ + "search_all=" + encodeURIComponent(params.term.replace(/\"/g, ""));';
9225 }
9226
9227 if (!$disableFiltering) {
9228 $outdelayed .= '
9229
9230 if(data.text.match(new RegExp(params.term))) {
9231 return data;
9232 }
9233
9234 return null;';
9235 } else {
9236 $outdelayed .= '
9237
9238 return data;';
9239 }
9240
9241 $outdelayed .= '
9242 }
9243 });
9244
9245 ' . ($callurlonselect ? '
9246 /* Code to execute a GET when we select a value */
9247 $(\'.' . dol_escape_js($htmlname) . '\').change(function() {
9248 var selected = $(\'.' . dol_escape_js($htmlname) . '\').val();
9249 console.log("We select "+selected)
9250
9251 $(\'.' . dol_escape_js($htmlname) . '\').val(""); /* reset visible combo value */
9252 $.each( saveRemoteData, function( key, value ) {
9253 if (key == selected)
9254 {
9255 console.log("selectArrayFilter - Do a redirect to "+value.url)
9256 location.assign(value.url);
9257 }
9258 });
9259 });' : '') . '
9260
9261 });
9262 </script>';
9263 }
9264
9265 if ($acceptdelayedhtml) {
9266 $delayedhtmlcontent .= $outdelayed;
9267 } else {
9268 $out .= $outdelayed;
9269 }
9270 return $out;
9271 }
9272
9291 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)
9292 {
9293 global $conf, $langs;
9294 $out = '';
9295
9296 if ($addjscombo < 0) {
9297 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9298 $addjscombo = 1;
9299 } else {
9300 $addjscombo = 0;
9301 }
9302 }
9303
9304 $useenhancedmultiselect = 0;
9305 if (!empty($conf->use_javascript_ajax) && !defined('MAIN_DO_NOT_USE_JQUERY_MULTISELECT') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
9306 if ($addjscombo) {
9307 $useenhancedmultiselect = 1; // Use the js multiselect in one line. Possible only if $addjscombo not 0.
9308 }
9309 }
9310
9311 // We need a hidden field because when using the multiselect, if we unselect all, there is no
9312 // variable submitted at all, so no way to make a difference between variable not submitted and variable
9313 // submitted to nothing.
9314 $out .= '<input type="hidden" name="'.$htmlname.'_multiselect" value="1">';
9315 // Output select component
9316 $out .= '<select id="' . $htmlname . '" class="multiselect' . ($useenhancedmultiselect ? ' multiselectononeline' : '') . ($morecss ? ' ' . $morecss : '') . '" multiple name="' . $htmlname . '[]"' . ($moreattrib ? ' ' . $moreattrib : '') . ($width ? ' style="width: ' . (preg_match('/%/', (string) $width) ? $width : $width . 'px') . '"' : '') . '>' . "\n";
9317 if (is_array($array) && !empty($array)) {
9318 if ($value_as_key) {
9319 $array = array_combine($array, $array);
9320 }
9321
9322 if (!empty($array)) {
9323 foreach ($array as $key => $value) {
9324 $tmpkey = $key;
9325 $tmpvalue = $value;
9326 $tmpcolor = '';
9327 $tmppicto = '';
9328 $tmplabelhtml = '';
9329 if (is_array($value) && array_key_exists('id', $value) && array_key_exists('label', $value)) {
9330 $tmpkey = $value['id'];
9331 $tmpvalue = empty($value['label']) ? '' : $value['label'];
9332 $tmpcolor = empty($value['color']) ? '' : $value['color'];
9333 $tmppicto = empty($value['picto']) ? '' : $value['picto'];
9334 $tmplabelhtml = empty($value['labelhtml']) ? (empty($value['data-html']) ? '' : $value['data-html']) : $value['labelhtml'];
9335 }
9336 $newval = ($translate ? $langs->trans($tmpvalue) : $tmpvalue);
9337 $newval = ($key_in_label ? $tmpkey . ' - ' . $newval : $newval);
9338
9339 $out .= '<option value="' . $tmpkey . '"';
9340 if (is_array($selected) && !empty($selected) && in_array((string) $tmpkey, $selected) && ((string) $tmpkey != '')) {
9341 $out .= ' selected';
9342 }
9343 if (!empty($tmplabelhtml)) {
9344 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9345 } else {
9346 $tmplabelhtml = ($tmppicto ? img_picto('', $tmppicto, 'class="pictofixedwidth" style="color: #' . $tmpcolor . '"') : '') . $newval;
9347 $out .= ' data-html="' . dol_escape_htmltag($tmplabelhtml, 0, 0, '', 0, 1) . '"';
9348 }
9349 $out .= '>';
9350 $out .= dol_htmlentitiesbr($newval);
9351 $out .= '</option>' . "\n";
9352 }
9353 }
9354 }
9355 $out .= '</select>' . "\n";
9356
9357 // Add code for jquery to use multiselect
9358 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT')) {
9359 $out .= "\n" . '<!-- JS CODE TO ENABLE select for id ' . $htmlname . ', addjscombo=' . $addjscombo . ' -->';
9360 $out .= "\n" . '<script nonce="' . getNonce() . '">' . "\n";
9361 if ($addjscombo == 1) {
9362 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
9363 $out .= 'function formatResult(record, container) {' . "\n";
9364 // If property data-html set, we decode html entities and use this.
9365 // Note that HTML content must have been sanitized from js with dol_escape_htmltag(xxx, 0, 0, '', 0, 1) when building the select option.
9366 $out .= ' if ($(record.element).attr("data-html") != undefined && typeof htmlEntityDecodeJs === "function") {';
9367 //$out .= ' console.log("aaa");';
9368 $out .= ' return htmlEntityDecodeJs($(record.element).attr("data-html"));';
9369 $out .= ' }'."\n";
9370 $out .= ' return record.text;';
9371 $out .= '}' . "\n";
9372 $out .= 'function formatSelection(record) {' . "\n";
9373 if ($elemtype == 'category') {
9374 $out .= 'return \'<span><img src="' . DOL_URL_ROOT . '/theme/eldy/img/object_category.png"> \'+record.text+\'</span>\';';
9375 } else {
9376 $out .= 'return record.text;';
9377 }
9378 $out .= '}' . "\n";
9379 $out .= '$(document).ready(function () {
9380 $(\'#' . dol_escape_js($htmlname) . '\').' . $tmpplugin . '({';
9381 if ($placeholder) {
9382 $out .= '
9383 placeholder: {
9384 id: \'-1\',
9385 text: \'' . dol_escape_js($placeholder) . '\'
9386 },';
9387 }
9388 $out .= ' dir: \'ltr\',
9389 containerCssClass: \':all:\', /* Line to add class of origin SELECT propagated to the new <span class="select2-selection...> tag (ko with multiselect) */
9390 dropdownCssClass: \'' . dol_escape_js($morecss) . '\', /* Line to add class on the new <span class="select2-selection...> tag (ok with multiselect). Need full version of select2. */
9391 // Specify format function for dropdown item
9392 formatResult: formatResult,
9393 templateResult: formatResult, /* For 4.0 */
9394 escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
9395 // Specify format function for selected item
9396 formatSelection: formatSelection,
9397 templateSelection: formatSelection, /* For 4.0 */
9398 language: (typeof select2arrayoflanguage === \'undefined\') ? \'en\' : select2arrayoflanguage
9399 });
9400
9401 /* Add also morecss to the css .select2 that is after the #htmlname, for component that are show dynamically after load, because select2 set
9402 the size only if component is not hidden by default on load */
9403 $(\'#' . dol_escape_js($htmlname) . ' + .select2\').addClass(\'' . dol_escape_js($morecss) . '\');
9404 });' . "\n";
9405 } elseif ($addjscombo == 2 && !defined('DISABLE_MULTISELECT')) {
9406 // Add other js lib
9407 // TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
9408 // ...
9409 $out .= 'console.log(\'addjscombo=2 for htmlname=' . dol_escape_js($htmlname) . '\');';
9410 $out .= '$(document).ready(function () {
9411 $(\'#' . dol_escape_js($htmlname) . '\').multiSelect({
9412 containerHTML: \'<div class="multi-select-container">\',
9413 menuHTML: \'<div class="multi-select-menu">\',
9414 buttonHTML: \'<span class="multi-select-button ' . dol_escape_js($morecss) . '">\',
9415 menuItemHTML: \'<label class="multi-select-menuitem">\',
9416 activeClass: \'multi-select-container--open\',
9417 noneText: \'' . dol_escape_js($placeholder) . '\'
9418 });
9419 })';
9420 }
9421 $out .= '</script>';
9422 }
9423
9424 return $out;
9425 }
9426
9427
9439 public static function multiSelectArrayWithCheckbox($htmlname, &$array, $varpage, $pos = '')
9440 {
9441 global $langs, $user;
9442
9443 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
9444 return '';
9445 }
9446 if (empty($array)) {
9447 return '';
9448 }
9449
9450 $tmpvar = "MAIN_SELECTEDFIELDS_" . $varpage; // To get list of saved selected fields to show
9451
9452 if (!empty($user->conf->$tmpvar)) { // A list of fields was already customized for user
9453 $tmparray = explode(',', $user->conf->$tmpvar);
9454 foreach ($array as $key => $val) {
9455 //var_dump($key);
9456 //var_dump($tmparray);
9457 if (in_array($key, $tmparray)) {
9458 $array[$key]['checked'] = 1;
9459 } else {
9460 $array[$key]['checked'] = 0;
9461 }
9462 }
9463 } else { // There is no list of fields already customized for user
9464 foreach ($array as $key => $val) {
9465 if (!empty($array[$key]['checked']) && $array[$key]['checked'] < 0) {
9466 $array[$key]['checked'] = 0;
9467 }
9468 }
9469 }
9470
9471 $listoffieldsforselection = '';
9472 $listcheckedstring = '';
9473
9474 foreach ($array as $key => $val) {
9475 // var_dump($val);
9476 // var_dump(array_key_exists('enabled', $val));
9477 // var_dump(!$val['enabled']);
9478 if (array_key_exists('enabled', $val) && isset($val['enabled']) && !$val['enabled']) {
9479 unset($array[$key]); // We don't want this field
9480 continue;
9481 }
9482 if (!empty($val['type']) && $val['type'] == 'separate') {
9483 // Field remains in array but we don't add it into $listoffieldsforselection
9484 //$listoffieldsforselection .= '<li>-----</li>';
9485 continue;
9486 }
9487 if (!empty($val['label']) && $val['label']) {
9488 if (!empty($val['langfile']) && is_object($langs)) {
9489 $langs->load($val['langfile']);
9490 }
9491
9492 // Note: $val['checked'] <> 0 means we must show the field into the combo list @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
9493 $listoffieldsforselection .= '<li><input type="checkbox" id="checkbox' . $key . '" value="' . $key . '"' . ((!array_key_exists('checked', $val) || empty($val['checked']) || $val['checked'] == '-1') ? '' : ' checked="checked"') . '/>';
9494 $listoffieldsforselection .= '<label for="checkbox' . $key . '">'.dol_string_nohtmltag($langs->trans($val['label'])) . '</label></li>';
9495 $listcheckedstring .= (empty($val['checked']) ? '' : $key . ',');
9496 }
9497 }
9498
9499 $out = '<!-- Component multiSelectArrayWithCheckbox ' . $htmlname . ' -->
9500
9501 <dl class="dropdown">
9502 <dt>
9503 <a href="#' . $htmlname . '">
9504 ' . img_picto('', 'list') . '
9505 </a>
9506 <input type="hidden" class="' . $htmlname . '" name="' . $htmlname . '" value="' . $listcheckedstring . '">
9507 </dt>
9508 <dd class="dropdowndd">
9509 <div class="multiselectcheckbox'.$htmlname.'">
9510 <ul class="'.$htmlname.(((string) $pos == '1' || (string) $pos == 'left') ? 'left' : '').'">
9511 <li class="liinputsearch"><input class="inputsearch_dropdownselectedfields width90p minwidth200imp" style="width:90%;" type="text" placeholder="'.$langs->trans('Search').'"></li>
9512 '.$listoffieldsforselection.'
9513 </ul>
9514 </div>
9515 </dd>
9516 </dl>
9517
9518 <script nonce="' . getNonce() . '" type="text/javascript">
9519 jQuery(document).ready(function () {
9520 $(\'.multiselectcheckbox' . $htmlname . ' input[type="checkbox"]\').on(\'click\', function () {
9521 console.log("A new field was added/removed, we edit field input[name=formfilteraction]");
9522
9523 $("input:hidden[name=formfilteraction]").val(\'listafterchangingselectedfields\'); // Update field so we know we changed something on selected fields after POST
9524
9525 var title = $(this).val() + ",";
9526 if ($(this).is(\':checked\')) {
9527 $(\'.' . $htmlname . '\').val(title + $(\'.' . $htmlname . '\').val());
9528 }
9529 else {
9530 $(\'.' . $htmlname . '\').val( $(\'.' . $htmlname . '\').val().replace(title, \'\') )
9531 }
9532 // Now, we submit page
9533 //$(this).parents(\'form:first\').submit();
9534 });
9535 $("input.inputsearch_dropdownselectedfields").on("keyup", function() {
9536 var value = $(this).val().toLowerCase();
9537 $(\'.multiselectcheckbox'.$htmlname.' li > label\').filter(function() {
9538 $(this).parent().toggle($(this).text().toLowerCase().indexOf(value) > -1)
9539 });
9540 });
9541
9542
9543 });
9544 </script>
9545
9546 ';
9547 return $out;
9548 }
9549
9559 public function showCategories($id, $type, $rendermode = 0, $nolink = 0)
9560 {
9561 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
9562
9563 $cat = new Categorie($this->db);
9564 $categories = $cat->containing($id, $type);
9565
9566 if ($rendermode == 1) {
9567 $toprint = array();
9568 foreach ($categories as $c) {
9569 $ways = $c->print_all_ways(' &gt;&gt; ', ($nolink ? 'none' : ''), 0, 1); // $ways[0] = "ccc2 >> ccc2a >> ccc2a1" with html formatted text
9570 foreach ($ways as $way) {
9571 $toprint[] = '<li class="select2-search-choice-dolibarr noborderoncategories"' . ($c->color ? ' style="background: #' . $c->color . ';"' : ' style="background: #bbb"') . '>' . $way . '</li>';
9572 }
9573 }
9574 if (empty($toprint)) {
9575 return '';
9576 } else {
9577 return '<div class="select2-container-multi-dolibarr"><ul class="select2-choices-dolibarr">' . implode(' ', $toprint) . '</ul></div>';
9578 }
9579 }
9580
9581 if ($rendermode == 0) {
9582 $arrayselected = array();
9583 $cate_arbo = $this->select_all_categories($type, '', 'parent', 64, 0, 3);
9584 foreach ($categories as $c) {
9585 $arrayselected[] = $c->id;
9586 }
9587
9588 return $this->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, '', 0, '100%', 'disabled', 'category');
9589 }
9590
9591 return 'ErrorBadValueForParameterRenderMode'; // Should not happened
9592 }
9593
9603 public function showLinkedObjectBlock($object, $morehtmlright = '', $compatibleImportElementsList = array(), $title = 'RelatedObjects')
9604 {
9605 global $conf, $langs, $hookmanager;
9606 global $action;
9607
9608 $object->fetchObjectLinked();
9609
9610 // Bypass the default method
9611 $hookmanager->initHooks(array('commonobject'));
9612 $parameters = array(
9613 'morehtmlright' => $morehtmlright,
9614 'compatibleImportElementsList' => &$compatibleImportElementsList,
9615 );
9616 $reshook = $hookmanager->executeHooks('showLinkedObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9617
9618 $nbofdifferenttypes = count($object->linkedObjects);
9619
9620 if (empty($reshook)) {
9621 print '<!-- showLinkedObjectBlock -->';
9622 print load_fiche_titre($langs->trans($title), $morehtmlright, '', 0, '', 'showlinkedobjectblock');
9623
9624
9625 print '<div class="div-table-responsive-no-min">';
9626 print '<table class="noborder allwidth" data-block="showLinkedObject" data-element="' . $object->element . '" data-elementid="' . $object->id . '" >';
9627
9628 print '<tr class="liste_titre">';
9629 print '<td>' . $langs->trans("Type") . '</td>';
9630 print '<td>' . $langs->trans("Ref") . '</td>';
9631 print '<td class="center"></td>';
9632 print '<td class="center">' . $langs->trans("Date") . '</td>';
9633 print '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9634 print '<td class="right">' . $langs->trans("Status") . '</td>';
9635 print '<td></td>';
9636 print '</tr>';
9637
9638 $nboftypesoutput = 0;
9639
9640 foreach ($object->linkedObjects as $objecttype => $objects) {
9641 $tplpath = $element = $subelement = $objecttype;
9642
9643 // to display import button on tpl
9644 $showImportButton = false;
9645 if (!empty($compatibleImportElementsList) && in_array($element, $compatibleImportElementsList)) {
9646 $showImportButton = true;
9647 }
9648
9649 $regs = array();
9650 if ($objecttype != 'supplier_proposal' && preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
9651 $element = $regs[1];
9652 $subelement = $regs[2];
9653 $tplpath = $element . '/' . $subelement;
9654 }
9655 $tplname = 'linkedobjectblock';
9656
9657 // To work with non standard path
9658 if ($objecttype == 'facture') {
9659 $tplpath = 'compta/' . $element;
9660 if (!isModEnabled('invoice')) {
9661 continue; // Do not show if module disabled
9662 }
9663 } elseif ($objecttype == 'facturerec') {
9664 $tplpath = 'compta/facture';
9665 $tplname = 'linkedobjectblockForRec';
9666 if (!isModEnabled('invoice')) {
9667 continue; // Do not show if module disabled
9668 }
9669 } elseif ($objecttype == 'propal') {
9670 $tplpath = 'comm/' . $element;
9671 if (!isModEnabled('propal')) {
9672 continue; // Do not show if module disabled
9673 }
9674 } elseif ($objecttype == 'supplier_proposal') {
9675 if (!isModEnabled('supplier_proposal')) {
9676 continue; // Do not show if module disabled
9677 }
9678 } elseif ($objecttype == 'shipping' || $objecttype == 'shipment' || $objecttype == 'expedition') {
9679 $tplpath = 'expedition';
9680 if (!isModEnabled('shipping')) {
9681 continue; // Do not show if module disabled
9682 }
9683 } elseif ($objecttype == 'reception') {
9684 $tplpath = 'reception';
9685 if (!isModEnabled('reception')) {
9686 continue; // Do not show if module disabled
9687 }
9688 } elseif ($objecttype == 'delivery') {
9689 $tplpath = 'delivery';
9690 if (!getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) {
9691 continue; // Do not show if sub module disabled
9692 }
9693 } elseif ($objecttype == 'ficheinter') {
9694 $tplpath = 'fichinter';
9695 if (!isModEnabled('intervention')) {
9696 continue; // Do not show if module disabled
9697 }
9698 } elseif ($objecttype == 'invoice_supplier') {
9699 $tplpath = 'fourn/facture';
9700 } elseif ($objecttype == 'order_supplier') {
9701 $tplpath = 'fourn/commande';
9702 } elseif ($objecttype == 'expensereport') {
9703 $tplpath = 'expensereport';
9704 } elseif ($objecttype == 'subscription') {
9705 $tplpath = 'adherents';
9706 } elseif ($objecttype == 'conferenceorbooth') {
9707 $tplpath = 'eventorganization';
9708 } elseif ($objecttype == 'conferenceorboothattendee') {
9709 $tplpath = 'eventorganization';
9710 } elseif ($objecttype == 'mo') {
9711 $tplpath = 'mrp';
9712 if (!isModEnabled('mrp')) {
9713 continue; // Do not show if module disabled
9714 }
9715 } elseif ($objecttype == 'project_task') {
9716 $tplpath = 'projet/tasks';
9717 }
9718
9719 global $linkedObjectBlock;
9720 $linkedObjectBlock = $objects;
9721
9722 // Output template part (modules that overwrite templates must declare this into descriptor)
9723 $dirtpls = array_merge($conf->modules_parts['tpl'], array('/' . $tplpath . '/tpl'));
9724 foreach ($dirtpls as $reldir) {
9725 $reldir = rtrim($reldir, '/');
9726 if ($nboftypesoutput == ($nbofdifferenttypes - 1)) { // No more type to show after
9727 global $noMoreLinkedObjectBlockAfter;
9728 $noMoreLinkedObjectBlockAfter = 1;
9729 }
9730
9731 $res = @include dol_buildpath($reldir . '/' . $tplname . '.tpl.php');
9732 if ($res) {
9733 $nboftypesoutput++;
9734 break;
9735 }
9736 }
9737 }
9738
9739 if (!$nboftypesoutput) {
9740 print '<tr><td colspan="7"><span class="opacitymedium">' . $langs->trans("None") . '</span></td></tr>';
9741 }
9742
9743 print '</table>';
9744
9745 if (!empty($compatibleImportElementsList)) {
9746 $res = @include dol_buildpath('core/tpl/objectlinked_lineimport.tpl.php');
9747 }
9748
9749 print '</div>';
9750 }
9751
9752 return $nbofdifferenttypes;
9753 }
9754
9764 public function showLinkToObjectBlock($object, $restrictlinksto = array(), $excludelinksto = array(), $nooutput = 0)
9765 {
9766 global $conf, $langs, $hookmanager, $form;
9767 global $action;
9768
9769 if (empty($form)) {
9770 $form = new Form($this->db);
9771 }
9772
9773 $linktoelem = '';
9774 $linktoelemlist = '';
9775 $listofidcompanytoscan = '';
9776
9777 if (!is_object($object->thirdparty)) {
9778 $object->fetch_thirdparty();
9779 }
9780
9781 $possiblelinks = array();
9782
9783 $dontIncludeCompletedItems = getDolGlobalString('DONT_INCLUDE_COMPLETED_ELEMENTS_LINKS');
9784
9785 if (is_object($object->thirdparty) && !empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
9786 $listofidcompanytoscan = (int) $object->thirdparty->id;
9787 if (($object->thirdparty->parent > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PARENT_IN_LINKTO')) {
9788 $listofidcompanytoscan .= ',' . (int) $object->thirdparty->parent;
9789 }
9790 if (($object->fk_project > 0) && getDolGlobalString('THIRDPARTY_INCLUDE_PROJECT_THIRDPARY_IN_LINKTO')) {
9791 include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
9792 $tmpproject = new Project($this->db);
9793 $tmpproject->fetch($object->fk_project);
9794 if ($tmpproject->socid > 0 && ($tmpproject->socid != $object->thirdparty->id)) {
9795 $listofidcompanytoscan .= ',' . (int) $tmpproject->socid;
9796 }
9797 unset($tmpproject);
9798 }
9799
9800 $possiblelinks = array(
9801 'propal' => array(
9802 'enabled' => isModEnabled('propal'),
9803 'perms' => 1,
9804 'label' => 'LinkToProposal',
9805 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 4' : ''),
9806 ),
9807 'shipping' => array(
9808 'enabled' => isModEnabled('shipping'),
9809 'perms' => 1,
9810 'label' => 'LinkToExpedition',
9811 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "expedition as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('shipping') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 2' : ''),
9812 ),
9813 'order' => array(
9814 'enabled' => isModEnabled('order'),
9815 'perms' => 1,
9816 'label' => 'LinkToOrder',
9817 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.facture < 1' : ''),
9818 'linkname' => 'commande',
9819 ),
9820 'invoice' => array(
9821 'enabled' => isModEnabled('invoice'),
9822 'perms' => 1,
9823 'label' => 'LinkToInvoice',
9824 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
9825 'linkname' => 'facture',
9826 ),
9827 'invoice_template' => array(
9828 'enabled' => isModEnabled('invoice'),
9829 'perms' => 1,
9830 'label' => 'LinkToTemplateInvoice',
9831 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')',
9832 ),
9833 'contrat' => array(
9834 'enabled' => isModEnabled('contract'),
9835 'perms' => 1,
9836 'label' => 'LinkToContract',
9837 '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
9838 FROM " . $this->db->prefix() . "societe as s, " . $this->db->prefix() . "contrat as t, " . $this->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',
9839 ),
9840 'fichinter' => array(
9841 'enabled' => isModEnabled('intervention'),
9842 'perms' => 1,
9843 'label' => 'LinkToIntervention',
9844 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')',
9845 ),
9846 'supplier_proposal' => array(
9847 'enabled' => isModEnabled('supplier_proposal'),
9848 'perms' => 1,
9849 'label' => 'LinkToSupplierProposal',
9850 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 4' : ''),
9851 ),
9852 'order_supplier' => array(
9853 'enabled' => isModEnabled("supplier_order"),
9854 'perms' => 1,
9855 'label' => 'LinkToSupplierOrder',
9856 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.billed < 1' : ''),
9857 ),
9858 'invoice_supplier' => array(
9859 'enabled' => isModEnabled("supplier_invoice"),
9860 'perms' => 1, 'label' => 'LinkToSupplierInvoice',
9861 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.paye < 1' : ''),
9862 ),
9863 'ticket' => array(
9864 'enabled' => isModEnabled('ticket'),
9865 'perms' => 1,
9866 'label' => 'LinkToTicket',
9867 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.track_id, '0' as total_ht FROM " . $this->db->prefix() . "societe as s, " . $this->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') . ')'.($dontIncludeCompletedItems ? ' AND t.fk_statut < 8' : ''),
9868 ),
9869 'mo' => array(
9870 'enabled' => isModEnabled('mrp'),
9871 'perms' => 1,
9872 'label' => 'LinkToMo',
9873 'sql' => "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM " . $this->db->prefix() . "societe as s INNER JOIN " . $this->db->prefix() . "mrp_mo as t ON t.fk_soc = s.rowid WHERE t.fk_soc IN (" . $this->db->sanitize($listofidcompanytoscan) . ') AND t.entity IN (' . getEntity('mo') . ')'.($dontIncludeCompletedItems ? ' AND t.status < 3' : ''),
9874 ),
9875 );
9876 }
9877
9878 if ($object->table_element == 'commande_fournisseur') {
9879 $possiblelinks['mo']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.rowid, '0' as total_ht FROM ".$this->db->prefix()."societe as s INNER JOIN ".$this->db->prefix().'mrp_mo as t ON t.fk_soc = s.rowid WHERE t.entity IN ('.getEntity('mo').')'.($dontIncludeCompletedItems ? ' AND t.status < 3' : '');
9880 } elseif ($object->table_element == 'mrp_mo') {
9881 $possiblelinks['order_supplier']['sql'] = "SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".$this->db->prefix()."societe as s, ".$this->db->prefix().'commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.entity IN ('.getEntity('commande_fournisseur').')'.($dontIncludeCompletedItems ? ' AND t.billed < 1' : '');
9882 }
9883
9884 $reshook = 0; // Ensure $reshook is defined for static analysis
9885 if (!empty($listofidcompanytoscan)) { // If empty, we don't have criteria to scan the object we can link to
9886 // Can complete the possiblelink array
9887 $hookmanager->initHooks(array('commonobject'));
9888 $parameters = array('listofidcompanytoscan' => $listofidcompanytoscan, 'possiblelinks' => $possiblelinks);
9889 $reshook = $hookmanager->executeHooks('showLinkToObjectBlock', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
9890 }
9891
9892 if (empty($reshook)) {
9893 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9894 $possiblelinks = array_merge($possiblelinks, $hookmanager->resArray);
9895 }
9896 } elseif ($reshook > 0) {
9897 if (is_array($hookmanager->resArray) && count($hookmanager->resArray)) {
9898 $possiblelinks = $hookmanager->resArray;
9899 }
9900 }
9901
9902 if (!empty($possiblelinks)) {
9903 $object->fetchObjectLinked();
9904 }
9905
9906 // Build the html part with possible suggested links
9907 $htmltoenteralink = '';
9908 foreach ($possiblelinks as $key => $possiblelink) {
9909 $num = 0;
9910 if (empty($possiblelink['enabled'])) {
9911 continue;
9912 }
9913
9914 if (!empty($possiblelink['perms']) && (empty($restrictlinksto) || in_array($key, $restrictlinksto)) && (empty($excludelinksto) || !in_array($key, $excludelinksto))) {
9915 $htmltoenteralink .= '<div id="' . $key . 'list"' . (empty($conf->use_javascript_ajax) ? '' : ' style="display:none"') . '>';
9916
9917 // Section for free ref input
9918 if (!getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9919 $htmltoenteralink .= '<br>'."\n";
9920 $htmltoenteralink .= '<!-- form to add a link from anywhere -->'."\n";
9921 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinkedbyref' . $key . '">';
9922 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9923 $htmltoenteralink .= '<input type="hidden" name="action" value="addlinkbyref">';
9924 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9925 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9926 $htmltoenteralink .= '<table class="noborder">';
9927 $htmltoenteralink .= '<tr class="liste_titre">';
9928 //print '<td>' . $langs->trans("Ref") . '</td>';
9929 $htmltoenteralink .= '<td class="center"><input type="text" placeholder="'.dol_escape_htmltag($langs->trans("Ref")).'" name="reftolinkto" value="' . dol_escape_htmltag(GETPOST('reftolinkto', 'alpha')) . '">&nbsp;';
9930 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans('ToLink') . '">&nbsp;';
9931 $htmltoenteralink .= '<input type="submit" class="button smallpaddingimp" name="cancel" value="' . $langs->trans('Cancel') . '"></td>';
9932 $htmltoenteralink .= '</tr>';
9933 $htmltoenteralink .= '</table>';
9934 $htmltoenteralink .= '</form>';
9935 }
9936
9937 $sql = $possiblelink['sql'];
9938
9939 $resqllist = $this->db->query($sql);
9940 if ($resqllist) {
9941 $num = $this->db->num_rows($resqllist);
9942 $i = 0;
9943
9944 if ($num > 0) {
9945 // Section for free predefined list
9946 if (getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
9947 $htmltoenteralink .= '<br>';
9948 }
9949 $htmltoenteralink .= '<!-- form to add a link from object to same thirdparty -->'."\n";
9950 $htmltoenteralink .= '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formlinked' . $key . '">';
9951 $htmltoenteralink .= '<input type="hidden" name="token" value="' . newToken() . '">';
9952 $htmltoenteralink .= '<input type="hidden" name="action" value="addlink">';
9953 $htmltoenteralink .= '<input type="hidden" name="id" value="' . $object->id . '">';
9954 $htmltoenteralink .= '<input type="hidden" name="addlink" value="' . $key . '">';
9955 $htmltoenteralink .= '<table class="noborder">';
9956 $htmltoenteralink .= '<tr class="liste_titre">';
9957 $htmltoenteralink .= '<td class="nowrap"></td>';
9958 $htmltoenteralink .= '<td>' . $langs->trans("Ref") . '</td>';
9959 $htmltoenteralink .= '<td>' . $langs->trans("RefCustomer") . '</td>';
9960 $htmltoenteralink .= '<td class="right">' . $langs->trans("AmountHTShort") . '</td>';
9961 $htmltoenteralink .= '<td>' . $langs->trans("Company") . '</td>';
9962 $htmltoenteralink .= '</tr>';
9963 while ($i < $num) {
9964 $objp = $this->db->fetch_object($resqllist);
9965 $alreadylinked = false;
9966 if (!empty($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key])) {
9967 if (in_array($objp->rowid, array_values($object->linkedObjectsIds[$possiblelink['linkname'] ?? $key]))) {
9968 $alreadylinked = true;
9969 }
9970 }
9971 $htmltoenteralink .= '<tr class="oddeven">';
9972 $htmltoenteralink .= '<td>';
9973 if ($alreadylinked) {
9974 $htmltoenteralink .= img_picto('', 'link');
9975 } else {
9976 $htmltoenteralink .= '<input type="checkbox" name="idtolinkto[' . $key . '_' . $objp->rowid . ']" id="' . $key . '_' . $objp->rowid . '" value="' . $objp->rowid . '">';
9977 }
9978 $htmltoenteralink .= '</td>';
9979 $htmltoenteralink .= '<td><label for="' . $key . '_' . $objp->rowid . '">' . $objp->ref . '</label></td>';
9980 $htmltoenteralink .= '<td>' . (!empty($objp->ref_client) ? $objp->ref_client : (!empty($objp->ref_supplier) ? $objp->ref_supplier : '')) . '</td>';
9981 $htmltoenteralink .= '<td class="right">';
9982 if ($possiblelink['label'] == 'LinkToContract') {
9983 $htmltoenteralink .= $form->textwithpicto('', $langs->trans("InformationOnLinkToContract")) . ' ';
9984 }
9985 $htmltoenteralink .= '<span class="amount">' . (isset($objp->total_ht) ? price($objp->total_ht) : '') . '</span>';
9986 $htmltoenteralink .= '</td>';
9987 $htmltoenteralink .= '<td>' . $objp->name . '</td>';
9988 $htmltoenteralink .= '</tr>';
9989 $i++;
9990 }
9991 $htmltoenteralink .= '</table>';
9992 $htmltoenteralink .= '<div class="center">';
9993 if ($num) {
9994 $htmltoenteralink .= '<input type="submit" class="button valignmiddle marginleftonly marginrightonly smallpaddingimp" value="' . $langs->trans('ToLink') . '">';
9995 }
9996 if (empty($conf->use_javascript_ajax)) {
9997 $htmltoenteralink .= '<input type="submit" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
9998 } else {
9999 $htmltoenteralink .= '<input type="submit" onclick="jQuery(\'#' . $key . 'list\').toggle(); return false;" class="button button-cancel marginleftonly marginrightonly smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '"></div>';
10000 }
10001 $htmltoenteralink .= '</form>';
10002 }
10003
10004 $this->db->free($resqllist);
10005 } else {
10006 dol_print_error($this->db);
10007 }
10008 $htmltoenteralink .= '</div>';
10009
10010
10011 // Complete the list for the combo box
10012 if ($num > 0 || !getDolGlobalString('MAIN_HIDE_LINK_BY_REF_IN_LINKTO')) {
10013 $linktoelemlist .= '<li><a href="#linkto' . $key . '" class="linkto dropdowncloseonclick" rel="' . $key . '">' . $langs->trans($possiblelink['label']) . ' (' . $num . ')</a></li>';
10014 // } else $linktoelem.=$langs->trans($possiblelink['label']);
10015 } else {
10016 $linktoelemlist .= '<li><span class="linktodisabled">' . $langs->trans($possiblelink['label']) . ' (0)</span></li>';
10017 }
10018 }
10019 }
10020
10021 if ($linktoelemlist) {
10022 $linktoelem = '
10023 <dl class="dropdown" id="linktoobjectname">
10024 ';
10025 if (!empty($conf->use_javascript_ajax)) {
10026 $linktoelem .= '<dt><a href="#linktoobjectname"><span class="fas fa-link paddingrightonly"></span>' . $langs->trans("LinkTo") . '...</a></dt>';
10027 }
10028 $linktoelem .= '<dd>
10029 <div class="multiselectlinkto">
10030 <ul class="ulselectedfields">' . $linktoelemlist . '
10031 </ul>
10032 </div>
10033 </dd>
10034 </dl>';
10035 } else {
10036 $linktoelem = '';
10037 }
10038
10039 if (!empty($conf->use_javascript_ajax)) {
10040 print '<!-- Add js to show linkto box -->
10041 <script nonce="' . getNonce() . '">
10042 jQuery(document).ready(function() {
10043 jQuery(".linkto").click(function() {
10044 console.log("We choose to show/hide links for rel="+jQuery(this).attr(\'rel\')+" so #"+jQuery(this).attr(\'rel\')+"list");
10045 jQuery("#"+jQuery(this).attr(\'rel\')+"list").toggle();
10046 });
10047 });
10048 </script>
10049 ';
10050 }
10051
10052 if ($nooutput) {
10053 return array('linktoelem' => $linktoelem, 'htmltoenteralink' => $htmltoenteralink);
10054 } else {
10055 print $htmltoenteralink;
10056 }
10057
10058 return $linktoelem;
10059 }
10060
10075 public function selectyesno($htmlname, $value = '', $option = 0, $disabled = false, $useempty = 0, $addjscombo = 0, $morecss = 'width75', $labelyes = 'Yes', $labelno = 'No')
10076 {
10077 global $langs;
10078
10079 $yes = "yes";
10080 $no = "no";
10081 if ($option) {
10082 $yes = "1";
10083 $no = "0";
10084 }
10085
10086 $disabled = ($disabled ? ' disabled' : '');
10087
10088 $resultyesno = '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '"' . $disabled . '>' . "\n";
10089 if ($useempty) {
10090 $resultyesno .= '<option value="-1"' . (($value < 0) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10091 }
10092 if (("$value" == 'yes') || ($value == 1)) {
10093 $resultyesno .= '<option value="' . $yes . '" selected>' . $langs->trans($labelyes) . '</option>' . "\n";
10094 $resultyesno .= '<option value="' . $no . '">' . $langs->trans($labelno) . '</option>' . "\n";
10095 } else {
10096 $selected = (($useempty && $value != '0' && $value != 'no') ? '' : ' selected');
10097 $resultyesno .= '<option value="' . $yes . '">' . $langs->trans($labelyes) . '</option>' . "\n";
10098 $resultyesno .= '<option value="' . $no . '"' . $selected . '>' . $langs->trans($labelno) . '</option>' . "\n";
10099 }
10100 $resultyesno .= '</select>' . "\n";
10101
10102 if ($addjscombo) {
10103 $resultyesno .= ajax_combobox($htmlname, array(), 0, 0, 'resolve', ($useempty < 0 ? (string) $useempty : '-1'), $morecss);
10104 }
10105
10106 return $resultyesno;
10107 }
10108
10109 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10110
10120 public function select_export_model($selected = '', $htmlname = 'exportmodelid', $type = '', $useempty = 0)
10121 {
10122 // phpcs:enable
10123 $sql = "SELECT rowid, label";
10124 $sql .= " FROM " . $this->db->prefix() . "export_model";
10125 $sql .= " WHERE type = '" . $this->db->escape($type) . "'";
10126 $sql .= " ORDER BY rowid";
10127 $result = $this->db->query($sql);
10128 if ($result) {
10129 print '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
10130 if ($useempty) {
10131 print '<option value="-1">&nbsp;</option>';
10132 }
10133
10134 $num = $this->db->num_rows($result);
10135 $i = 0;
10136 while ($i < $num) {
10137 $obj = $this->db->fetch_object($result);
10138 if ($selected == $obj->rowid) {
10139 print '<option value="' . $obj->rowid . '" selected>';
10140 } else {
10141 print '<option value="' . $obj->rowid . '">';
10142 }
10143 print $obj->label;
10144 print '</option>';
10145 $i++;
10146 }
10147 print "</select>";
10148 } else {
10149 dol_print_error($this->db);
10150 }
10151 }
10152
10171 public function showrefnav($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $morehtmlright = '')
10172 {
10173 global $conf, $langs, $hookmanager, $extralanguages;
10174
10175 $ret = '';
10176 if (empty($fieldid)) {
10177 $fieldid = 'rowid';
10178 }
10179 if (empty($fieldref)) {
10180 $fieldref = 'ref';
10181 }
10182
10183 // Preparing gender's display if there is one
10184 $addgendertxt = '';
10185 if (property_exists($object, 'gender') && !empty($object->gender)) {
10186 $addgendertxt = ' ';
10187 switch ($object->gender) {
10188 case 'man':
10189 $addgendertxt .= '<i class="fas fa-mars valignmiddle"></i>';
10190 break;
10191 case 'woman':
10192 $addgendertxt .= '<i class="fas fa-venus valignmiddle"></i>';
10193 break;
10194 case 'other':
10195 $addgendertxt .= '<i class="fas fa-transgender valignmiddle"></i>';
10196 break;
10197 }
10198 }
10199
10200 // Add where from hooks
10201 if (is_object($hookmanager)) {
10202 $parameters = array('showrefnav' => true);
10203 $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object); // Note that $action and $object may have been modified by hook
10204 if (!empty($hookmanager->resPrint)) {
10205 if (empty($object->next_prev_filter) && preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10206 $object->next_prev_filter = preg_replace('/^\s*AND\s*/i', '', $hookmanager->resPrint);
10207 } elseif (!empty($object->next_prev_filter) && !preg_match('/^\s*AND/i', $hookmanager->resPrint)) {
10208 $object->next_prev_filter .= ' AND '.$hookmanager->resPrint;
10209 } else {
10210 $object->next_prev_filter .= $hookmanager->resPrint;
10211 }
10212 }
10213 }
10214
10215 $previous_ref = $next_ref = '';
10216 if ($shownav) {
10217 //print "paramid=$paramid,morehtml=$morehtml,shownav=$shownav,$fieldid,$fieldref,$morehtmlref,$moreparam";
10218 $object->load_previous_next_ref((isset($object->next_prev_filter) ? $object->next_prev_filter : ''), $fieldid, $nodbprefix);
10219
10220 $navurl = $_SERVER["PHP_SELF"];
10221 // Special case for project/task page
10222 if ($paramid == 'project_ref') {
10223 if (preg_match('/\/tasks\/(task|contact|note|document)\.php/', $navurl)) { // TODO Remove this when nav with project_ref on task pages are ok
10224 $navurl = preg_replace('/\/tasks\/(task|contact|time|note|document)\.php/', '/tasks.php', $navurl);
10225 $paramid = 'ref';
10226 }
10227 }
10228
10229 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
10230 // accesskey is for Mac: CTRL + key for all browsers
10231 $stringforfirstkey = $langs->trans("KeyboardShortcut");
10232 if ($conf->browser->name == 'chrome') {
10233 $stringforfirstkey .= ' ALT +';
10234 } elseif ($conf->browser->name == 'firefox') {
10235 $stringforfirstkey .= ' ALT + SHIFT +';
10236 } else {
10237 $stringforfirstkey .= ' CTL +';
10238 }
10239
10240 $previous_ref = $object->ref_previous ? '<a accesskey="p" alt="'.dol_escape_htmltag($langs->trans("Previous")).'" 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>';
10241 $next_ref = $object->ref_next ? '<a accesskey="n" alt="'.dol_escape_htmltag($langs->trans("Next")).'" 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>';
10242 }
10243
10244 //print "xx".$previous_ref."x".$next_ref;
10245 $ret .= '<!-- Start banner content --><div style="vertical-align: middle">';
10246
10247 // Right part of banner
10248 if ($morehtmlright) {
10249 $ret .= '<div class="inline-block floatleft">' . $morehtmlright . '</div>';
10250 }
10251
10252 if ($previous_ref || $next_ref || $morehtml) {
10253 $ret .= '<div class="pagination paginationref"><ul class="right">';
10254 }
10255 if ($morehtml && getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
10256 $ret .= '<!-- morehtml --><li class="noborder litext' . (($shownav && $previous_ref && $next_ref) ? ' clearbothonsmartphone' : '') . '">' . $morehtml . '</li>';
10257 }
10258 if ($shownav && ($previous_ref || $next_ref)) {
10259 $ret .= '<li class="pagination">' . $previous_ref . '</li>';
10260 $ret .= '<li class="pagination">' . $next_ref . '</li>';
10261 }
10262 if ($previous_ref || $next_ref || $morehtml) {
10263 $ret .= '</ul></div>';
10264 }
10265
10266 // Status
10267 $parameters = array('morehtmlstatus' => $morehtmlstatus);
10268 $reshook = $hookmanager->executeHooks('moreHtmlStatus', $parameters, $object); // Note that $action and $object may have been modified by hook
10269 if (empty($reshook)) {
10270 $morehtmlstatus .= $hookmanager->resPrint;
10271 } else {
10272 $morehtmlstatus = $hookmanager->resPrint;
10273 }
10274 if ($morehtmlstatus) {
10275 $ret .= '<div class="statusref">' . $morehtmlstatus . '</div>';
10276 }
10277
10278 $parameters = array();
10279 $reshook = $hookmanager->executeHooks('moreHtmlRef', $parameters, $object); // Note that $action and $object may have been modified by hook
10280 if (empty($reshook)) {
10281 $morehtmlref .= $hookmanager->resPrint;
10282 } elseif ($reshook > 0) {
10283 $morehtmlref = $hookmanager->resPrint;
10284 }
10285
10286 // Left part of banner
10287 if ($morehtmlleft) {
10288 if ($conf->browser->layout == 'phone') {
10289 $ret .= '<!-- morehtmlleft --><div class="floatleft">' . $morehtmlleft . '</div>';
10290 } else {
10291 $ret .= '<!-- morehtmlleft --><div class="inline-block floatleft">' . $morehtmlleft . '</div>';
10292 }
10293 }
10294
10295 //if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
10296 $ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid' . (($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '') . '">';
10297
10298 // For thirdparty, contact, user, member, the ref is the id, so we show something else
10299 if ($object->element == 'societe') {
10300 $ret .= dol_htmlentities($object->name);
10301
10302 // List of extra languages
10303 $arrayoflangcode = array();
10304 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
10305 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
10306 }
10307
10308 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
10309 if (!is_object($extralanguages)) {
10310 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
10311 $extralanguages = new ExtraLanguages($this->db);
10312 }
10313 $extralanguages->fetch_name_extralanguages('societe');
10314
10315 if (!empty($extralanguages->attributes['societe']['name'])) {
10316 $object->fetchValuesForExtraLanguages();
10317
10318 $htmltext = '';
10319 // If there is extra languages
10320 foreach ($arrayoflangcode as $extralangcode) {
10321 $htmltext .= picto_from_langcode($extralangcode, 'class="pictoforlang paddingright"');
10322 if ($object->array_languages['name'][$extralangcode]) {
10323 $htmltext .= $object->array_languages['name'][$extralangcode];
10324 } else {
10325 $htmltext .= '<span class="opacitymedium">' . $langs->trans("SwitchInEditModeToAddTranslation") . '</span>';
10326 }
10327 }
10328 $ret .= '<!-- Show translations of name -->' . "\n";
10329 $ret .= $this->textwithpicto('', $htmltext, -1, 'language', 'opacitymedium paddingleft');
10330 }
10331 }
10332 } elseif ($object->element == 'member') {
10333 '@phan-var-force Adherent $object';
10334 $ret .= $object->ref . '<br>';
10335 $fullname = $object->getFullName($langs);
10336 if ($object->morphy == 'mor' && $object->societe) {
10337 $ret .= dol_htmlentities($object->societe) . ((!empty($fullname) && $object->societe != $fullname) ? ' (' . dol_htmlentities($fullname) . $addgendertxt . ')' : '');
10338 } else {
10339 $ret .= dol_htmlentities($fullname) . $addgendertxt . ((!empty($object->societe) && $object->societe != $fullname) ? ' (' . dol_htmlentities($object->societe) . ')' : '');
10340 }
10341 } elseif (in_array($object->element, array('contact', 'user'))) {
10342 $ret .= '<span class="valignmiddle">'.dol_htmlentities($object->getFullName($langs)).'</span>'.$addgendertxt;
10343 } elseif ($object->element == 'usergroup') {
10344 $ret .= dol_htmlentities($object->name);
10345 } elseif (in_array($object->element, array('action', 'agenda'))) {
10346 '@phan-var-force ActionComm $object';
10347 $ret .= $object->ref . '<br>' . $object->label;
10348 } elseif (in_array($object->element, array('adherent_type'))) {
10349 $ret .= $object->label;
10350 } elseif ($object->element == 'ecm_directories') {
10351 $ret .= '';
10352 } elseif ($fieldref != 'none') {
10353 $ret .= dol_htmlentities(!empty($object->$fieldref) ? $object->$fieldref : "");
10354 }
10355 if ($morehtmlref) {
10356 // don't add a additional space, when "$morehtmlref" starts with a HTML div tag
10357 if (substr($morehtmlref, 0, 4) != '<div') {
10358 $ret .= ' ';
10359 }
10360
10361 $ret .= '<!-- morehtmlref -->'.$morehtmlref;
10362 }
10363
10364 $ret .= '</div>';
10365
10366 $ret .= '</div><!-- End banner content -->';
10367
10368 return $ret;
10369 }
10370
10371
10380 public function showbarcode(&$object, $width = 100, $morecss = '')
10381 {
10382 global $conf;
10383
10384 //Check if barcode is filled in the card
10385 if (empty($object->barcode)) {
10386 return '';
10387 }
10388
10389 // Complete object if not complete
10390 if (empty($object->barcode_type_code) || empty($object->barcode_type_coder)) {
10391 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10392 $result = $object->fetchBarCode();
10393 //Check if fetchBarCode() failed
10394 if ($result < 1) {
10395 return '<!-- ErrorFetchBarcode -->';
10396 }
10397 }
10398
10399 // Barcode image @phan-suppress-next-line PhanUndeclaredProperty
10400 $url = DOL_URL_ROOT . '/viewimage.php?modulepart=barcode&generator=' . urlencode($object->barcode_type_coder) . '&code=' . urlencode($object->barcode) . '&encoding=' . urlencode($object->barcode_type_code);
10401 $out = '<!-- url barcode = ' . $url . ' -->';
10402 $out .= '<img src="' . $url . '"' . ($morecss ? ' class="' . $morecss . '"' : '') . '>';
10403
10404 return $out;
10405 }
10406
10424 public static function showphoto($modulepart, $object, $width = 100, $height = 0, $caneditfield = 0, $cssclass = 'photowithmargin', $imagesize = '', $addlinktofullsize = 1, $cache = 0, $forcecapture = '', $noexternsourceoverwrite = 0)
10425 {
10426 global $conf, $langs;
10427
10428 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
10429 $id = (empty($object->id) ? $object->rowid : $object->id); // @phan-suppress-current-line PhanUndeclaredProperty (->rowid)
10430
10431 $dir = '';
10432 $file = '';
10433 $originalfile = '';
10434 $altfile = '';
10435 $email = '';
10436 $capture = '';
10437 if ($modulepart == 'societe') {
10438 $dir = $conf->societe->multidir_output[$entity];
10439 if (!empty($object->logo)) {
10440 if (dolIsAllowedForPreview($object->logo)) {
10441 if ((string) $imagesize == 'mini') {
10442 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_mini'); // getImageFileNameForSize include the thumbs
10443 } elseif ((string) $imagesize == 'small') {
10444 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . getImageFileNameForSize($object->logo, '_small');
10445 } else {
10446 $file = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10447 }
10448 $originalfile = get_exdir(0, 0, 0, 0, $object, 'thirdparty') . 'logos/' . $object->logo;
10449 }
10450 }
10451 $email = $object->email;
10452 } elseif ($modulepart == 'contact') {
10453 $dir = $conf->societe->multidir_output[$entity] . '/contact';
10454 if (!empty($object->photo)) {
10455 if (dolIsAllowedForPreview($object->photo)) {
10456 if ((string) $imagesize == 'mini') {
10457 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10458 } elseif ((string) $imagesize == 'small') {
10459 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10460 } else {
10461 $file = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10462 }
10463 $originalfile = get_exdir(0, 0, 0, 0, $object, 'contact') . 'photos/' . $object->photo;
10464 }
10465 }
10466 $email = $object->email;
10467 $capture = 'user';
10468 } elseif ($modulepart == 'userphoto') {
10469 $dir = $conf->user->dir_output;
10470 if (!empty($object->photo)) {
10471 if (dolIsAllowedForPreview($object->photo)) {
10472 if ((string) $imagesize == 'mini') {
10473 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10474 } elseif ((string) $imagesize == 'small') {
10475 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10476 } else {
10477 $file = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10478 }
10479 $originalfile = get_exdir(0, 0, 0, 0, $object, 'user') . 'photos/' . $object->photo;
10480 }
10481 }
10482 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10483 $altfile = $object->id . ".jpg"; // For backward compatibility
10484 }
10485 $email = $object->email;
10486 $capture = 'user';
10487 } elseif ($modulepart == 'memberphoto') {
10488 $dir = $conf->adherent->dir_output;
10489 if (!empty($object->photo)) {
10490 if (dolIsAllowedForPreview($object->photo)) {
10491 if ((string) $imagesize == 'mini') {
10492 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_mini');
10493 } elseif ((string) $imagesize == 'small') {
10494 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . getImageFileNameForSize($object->photo, '_small');
10495 } else {
10496 $file = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10497 }
10498 $originalfile = get_exdir(0, 0, 0, 0, $object, 'member') . 'photos/' . $object->photo;
10499 }
10500 }
10501 if (getDolGlobalString('MAIN_OLD_IMAGE_LINKS')) {
10502 $altfile = $object->id . ".jpg"; // For backward compatibility
10503 }
10504 $email = $object->email;
10505 $capture = 'user';
10506 } else {
10507 // Generic case to show photos
10508 // TODO Implement this method in previous objects so we can always use this generic method.
10509 if ($modulepart != "unknown" && method_exists($object, 'getDataToShowPhoto')) {
10510 $tmpdata = $object->getDataToShowPhoto($modulepart, $imagesize);
10511
10512 $dir = $tmpdata['dir'];
10513 $file = $tmpdata['file'];
10514 $originalfile = $tmpdata['originalfile'];
10515 $altfile = $tmpdata['altfile'];
10516 $email = $tmpdata['email'];
10517 $capture = $tmpdata['capture'];
10518 }
10519 }
10520
10521 if ($forcecapture) {
10522 $capture = $forcecapture;
10523 }
10524
10525 $ret = '';
10526
10527 if ($dir) {
10528 if ($file && file_exists($dir . "/" . $file)) {
10529 if ($addlinktofullsize) {
10530 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10531 if ($urladvanced) {
10532 $ret .= '<a href="' . $urladvanced . '">';
10533 } else {
10534 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10535 }
10536 }
10537 $ret .= '<img alt="" 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 . '">';
10538 if ($addlinktofullsize) {
10539 $ret .= '</a>';
10540 }
10541 } elseif ($altfile && file_exists($dir . "/" . $altfile)) {
10542 if ($addlinktofullsize) {
10543 $urladvanced = getAdvancedPreviewUrl($modulepart, $originalfile, 0, '&entity=' . $entity);
10544 if ($urladvanced) {
10545 $ret .= '<a href="' . $urladvanced . '">';
10546 } else {
10547 $ret .= '<a href="' . DOL_URL_ROOT . '/viewimage.php?modulepart=' . $modulepart . '&entity=' . $entity . '&file=' . urlencode($originalfile) . '&cache=' . $cache . '">';
10548 }
10549 }
10550 $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 . '">';
10551 if ($addlinktofullsize) {
10552 $ret .= '</a>';
10553 }
10554 } else {
10555 $nophoto = '/public/theme/common/nophoto.png';
10556 $defaultimg = 'identicon'; // For gravatar
10557 if (in_array($modulepart, array('societe', 'userphoto', 'contact', 'memberphoto'))) { // For modules that need a special image when photo not found
10558 if ($modulepart == 'societe' || ($modulepart == 'memberphoto' && !empty($object->morphy) && strpos($object->morphy, 'mor') !== false)) {
10559 $nophoto = 'company';
10560 } else {
10561 $nophoto = '/public/theme/common/user_anonymous.png';
10562 if (!empty($object->gender) && $object->gender == 'man') {
10563 $nophoto = '/public/theme/common/user_man.png';
10564 }
10565 if (!empty($object->gender) && $object->gender == 'woman') {
10566 $nophoto = '/public/theme/common/user_woman.png';
10567 }
10568 }
10569 }
10570
10571 if (isModEnabled('gravatar') && $email && empty($noexternsourceoverwrite)) {
10572 // see https://gravatar.com/site/implement/images/php/
10573 $ret .= '<!-- Put link to gravatar -->';
10574 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" title="' . $email . ' Gravatar avatar" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="https://www.gravatar.com/avatar/' . dol_hash(strtolower(trim($email)), 'sha256', 1) . '?s=' . $width . '&d=' . $defaultimg . '">'; // gravatar need md5 hash
10575 } else {
10576 if ($nophoto == 'company') {
10577 $ret .= '<div class="divforspanimg valignmiddle center photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . '>' . img_picto('', 'company') . '</div>';
10578 //$ret .= '<div class="difforspanimgright"></div>';
10579 } else {
10580 $ret .= '<img class="photo' . $modulepart . ($cssclass ? ' ' . $cssclass : '') . '" alt="" ' . ($width ? ' width="' . $width . '"' : '') . ($height ? ' height="' . $height . '"' : '') . ' src="' . DOL_URL_ROOT . $nophoto . '">';
10581 }
10582 }
10583 }
10584
10585 if ($caneditfield) {
10586 if ($object->photo) {
10587 $ret .= "<br>\n";
10588 }
10589 $ret .= '<table class="nobordernopadding centpercent">';
10590 if ($object->photo) {
10591 $ret .= '<tr><td><input type="checkbox" class="flat photodelete" name="deletephoto" id="photodelete"> <label for="photodelete">' . $langs->trans("Delete") . '</label><br><br></td></tr>';
10592 }
10593 $ret .= '<tr><td class="tdoverflow">';
10594 $maxfilesizearray = getMaxFileSizeArray();
10595 $maxmin = $maxfilesizearray['maxmin'];
10596 if ($maxmin > 0) {
10597 $ret .= '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; // MAX_FILE_SIZE must precede the field type=file
10598 }
10599 $ret .= '<input type="file" class="flat maxwidth200onsmartphone" name="photo" id="photoinput" accept="image/*"' . ($capture ? ' capture="' . $capture . '"' : '') . '>';
10600 $ret .= '</td></tr>';
10601 $ret .= '</table>';
10602 }
10603 }
10604
10605 return $ret;
10606 }
10607
10608 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
10609
10626 public function select_dolgroups($selected = 0, $htmlname = 'groupid', $show_empty = 0, $exclude = '', $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0', $multiple = false, $morecss = 'minwidth200')
10627 {
10628 // phpcs:enable
10629 global $conf, $user, $langs;
10630
10631 // Allow excluding groups
10632 $excludeGroups = null;
10633 if (is_array($exclude)) {
10634 $excludeGroups = implode(",", $exclude);
10635 }
10636 // Allow including groups
10637 $includeGroups = null;
10638 if (is_array($include)) {
10639 $includeGroups = implode(",", $include);
10640 }
10641
10642 if (!is_array($selected)) {
10643 $selected = array($selected);
10644 }
10645
10646 $out = '';
10647
10648 // Build sql to search groups
10649 $sql = "SELECT ug.rowid, ug.nom as name";
10650 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10651 $sql .= ", e.label";
10652 }
10653 $sql .= " FROM " . $this->db->prefix() . "usergroup as ug ";
10654 if (isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && !$user->entity) {
10655 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid=ug.entity";
10656 if ($force_entity) {
10657 $sql .= " WHERE ug.entity IN (0, " . $force_entity . ")";
10658 } else {
10659 $sql .= " WHERE ug.entity IS NOT NULL";
10660 }
10661 } else {
10662 $sql .= " WHERE ug.entity IN (0, " . $conf->entity . ")";
10663 }
10664 if (is_array($exclude) && $excludeGroups) {
10665 $sql .= " AND ug.rowid NOT IN (" . $this->db->sanitize($excludeGroups) . ")";
10666 }
10667 if (is_array($include) && $includeGroups) {
10668 $sql .= " AND ug.rowid IN (" . $this->db->sanitize($includeGroups) . ")";
10669 }
10670 $sql .= " ORDER BY ug.nom ASC";
10671
10672 dol_syslog(get_class($this) . "::select_dolgroups", LOG_DEBUG);
10673 $resql = $this->db->query($sql);
10674 if ($resql) {
10675 // Enhance with select2
10676 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
10677
10678 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
10679
10680 $num = $this->db->num_rows($resql);
10681 $i = 0;
10682 if ($num) {
10683 if ($show_empty && !$multiple) {
10684 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>&nbsp;</option>' . "\n";
10685 }
10686
10687 while ($i < $num) {
10688 $obj = $this->db->fetch_object($resql);
10689 $disableline = 0;
10690 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
10691 $disableline = 1;
10692 }
10693
10694 $label = $obj->name;
10695 $labelhtml = $obj->name;
10696 if (isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1) {
10697 $label .= " (" . $obj->label . ")";
10698 $labelhtml .= ' <span class="opacitymedium">(' . $obj->label . ')</span>';
10699 }
10700
10701 $out .= '<option value="' . $obj->rowid . '"';
10702 if ($disableline) {
10703 $out .= ' disabled';
10704 }
10705 if ((isset($selected[0]) && is_object($selected[0]) && $selected[0]->id == $obj->rowid)
10706 || ((!isset($selected[0]) || !is_object($selected[0])) && !empty($selected) && in_array($obj->rowid, $selected))) {
10707 $out .= ' selected';
10708 }
10709 $out .= ' data-html="'.dol_escape_htmltag($labelhtml).'"';
10710 $out .= '>';
10711 $out .= $label;
10712 $out .= '</option>';
10713 $i++;
10714 }
10715 } else {
10716 if ($show_empty) {
10717 $out .= '<option value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '></option>' . "\n";
10718 }
10719 $out .= '<option value="" disabled>' . $langs->trans("NoUserGroupDefined") . '</option>';
10720 }
10721 $out .= '</select>';
10722
10723 $out .= ajax_combobox($htmlname);
10724 } else {
10725 dol_print_error($this->db);
10726 }
10727
10728 return $out;
10729 }
10730
10731
10738 public function showFilterButtons($pos = '')
10739 {
10740 $out = '<div class="nowraponall">';
10741 $out .= '<button type="submit" class="liste_titre button_search reposition" name="button_search_x" value="x"><span class="fas fa-search"></span></button>';
10742 $out .= '<button type="submit" class="liste_titre button_removefilter reposition" name="button_removefilter_x" value="x"><span class="fas fa-times"></span></button>';
10743 $out .= '</div>';
10744
10745 return $out;
10746 }
10747
10756 public function showCheckAddButtons($cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10757 {
10758 global $conf;
10759
10760 $out = '';
10761
10762 if (!empty($conf->use_javascript_ajax)) {
10763 $out .= '<div class="inline-block checkallactions"><input type="checkbox" id="' . $cssclass . 's" name="' . $cssclass . 's" class="checkallactions"></div>';
10764 }
10765 $out .= '<script nonce="' . getNonce() . '">
10766 $(document).ready(function() {
10767 $("#' . $cssclass . 's").click(function() {
10768 if($(this).is(\':checked\')){
10769 console.log("We check all ' . $cssclass . ' and trigger the change method");
10770 $(".' . $cssclass . '").prop(\'checked\', true).trigger(\'change\');
10771 }
10772 else
10773 {
10774 console.log("We uncheck all");
10775 $(".' . $cssclass . '").prop(\'checked\', false).trigger(\'change\');
10776 }' . "\n";
10777 if ($calljsfunction) {
10778 $out .= 'if (typeof initCheckForSelect == \'function\') { initCheckForSelect(0, "' . $massactionname . '", "' . $cssclass . '"); } else { console.log("No function initCheckForSelect found. Call won\'t be done."); }';
10779 }
10780 $out .= ' });
10781 $(".' . $cssclass . '").change(function() {
10782 $(this).closest("tr").toggleClass("highlight", this.checked);
10783 });
10784 });
10785 </script>';
10786
10787 return $out;
10788 }
10789
10799 public function showFilterAndCheckAddButtons($addcheckuncheckall = 0, $cssclass = 'checkforaction', $calljsfunction = 0, $massactionname = "massaction")
10800 {
10801 $out = $this->showFilterButtons();
10802 if ($addcheckuncheckall) {
10803 $out .= $this->showCheckAddButtons($cssclass, $calljsfunction, $massactionname);
10804 }
10805 return $out;
10806 }
10807
10821 public function selectExpenseCategories($selected = '', $htmlname = 'fk_c_exp_tax_cat', $useempty = 0, $excludeid = array(), $target = '', $default_selected = 0, $params = array(), $info_admin = 1)
10822 {
10823 global $langs, $user;
10824
10825 $out = '';
10826 $sql = "SELECT rowid, label FROM " . $this->db->prefix() . "c_exp_tax_cat WHERE active = 1";
10827 $sql .= " AND entity IN (0," . getEntity('exp_tax_cat') . ")";
10828 if (!empty($excludeid)) {
10829 $sql .= " AND rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeid)) . ")";
10830 }
10831 $sql .= " ORDER BY label";
10832
10833 $resql = $this->db->query($sql);
10834 if ($resql) {
10835 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp maxwidth200">';
10836 if ($useempty) {
10837 $out .= '<option value="0">&nbsp;</option>';
10838 }
10839
10840 while ($obj = $this->db->fetch_object($resql)) {
10841 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . $langs->trans($obj->label) . '</option>';
10842 }
10843 $out .= '</select>';
10844 $out .= ajax_combobox('select_' . $htmlname);
10845
10846 if (!empty($htmlname) && $user->admin && $info_admin) {
10847 $out .= ' ' . info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
10848 }
10849
10850 if (!empty($target)) {
10851 $sql = "SELECT c.id FROM " . $this->db->prefix() . "c_type_fees as c WHERE c.code = 'EX_KME' AND c.active = 1";
10852 $resql = $this->db->query($sql);
10853 if ($resql) {
10854 if ($this->db->num_rows($resql) > 0) {
10855 $obj = $this->db->fetch_object($resql);
10856 $out .= '<script nonce="' . getNonce() . '">
10857 $(function() {
10858 $("select[name=' . $target . ']").on("change", function() {
10859 var current_val = $(this).val();
10860 if (current_val == ' . $obj->id . ') {';
10861 if (!empty($default_selected) || !empty($selected)) {
10862 $out .= '$("select[name=' . $htmlname . ']").val("' . ($default_selected > 0 ? $default_selected : $selected) . '");';
10863 }
10864
10865 $out .= '
10866 $("select[name=' . $htmlname . ']").change();
10867 }
10868 });
10869
10870 $("select[name=' . $htmlname . ']").change(function() {
10871
10872 if ($("select[name=' . $target . ']").val() == ' . $obj->id . ') {
10873 // get price of kilometer to fill the unit price
10874 $.ajax({
10875 method: "POST",
10876 dataType: "json",
10877 data: { fk_c_exp_tax_cat: $(this).val(), token: \'' . currentToken() . '\' },
10878 url: "' . (DOL_URL_ROOT . '/expensereport/ajax/ajaxik.php?' . implode('&', $params)) . '",
10879 }).done(function( data, textStatus, jqXHR ) {
10880 console.log(data);
10881 if (typeof data.up != "undefined") {
10882 $("input[name=value_unit]").val(data.up);
10883 $("select[name=' . $htmlname . ']").attr("title", data.title);
10884 } else {
10885 $("input[name=value_unit]").val("");
10886 $("select[name=' . $htmlname . ']").attr("title", "");
10887 }
10888 });
10889 }
10890 });
10891 });
10892 </script>';
10893 }
10894 }
10895 }
10896 } else {
10897 dol_print_error($this->db);
10898 }
10899
10900 return $out;
10901 }
10902
10911 public function selectExpenseRanges($selected = '', $htmlname = 'fk_range', $useempty = 0)
10912 {
10913 global $conf, $langs;
10914
10915 $out = '';
10916 $sql = "SELECT rowid, range_ik FROM " . $this->db->prefix() . "c_exp_tax_range";
10917 $sql .= " WHERE entity = " . $conf->entity . " AND active = 1";
10918
10919 $resql = $this->db->query($sql);
10920 if ($resql) {
10921 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10922 if ($useempty) {
10923 $out .= '<option value="0"></option>';
10924 }
10925
10926 while ($obj = $this->db->fetch_object($resql)) {
10927 $out .= '<option ' . ($selected == $obj->rowid ? 'selected="selected"' : '') . ' value="' . $obj->rowid . '">' . price($obj->range_ik, 0, $langs, 1, 0) . '</option>';
10928 }
10929 $out .= '</select>';
10930 } else {
10931 dol_print_error($this->db);
10932 }
10933
10934 return $out;
10935 }
10936
10947 public function selectExpense($selected = '', $htmlname = 'fk_c_type_fees', $useempty = 0, $allchoice = 1, $useid = 0)
10948 {
10949 global $langs;
10950
10951 $out = '';
10952 $sql = "SELECT id, code, label";
10953 $sql .= " FROM ".$this->db->prefix()."c_type_fees";
10954 $sql .= " WHERE active = 1";
10955
10956 $resql = $this->db->query($sql);
10957 if ($resql) {
10958 $out = '<select id="select_' . $htmlname . '" name="' . $htmlname . '" class="' . $htmlname . ' flat minwidth75imp">';
10959 if ($useempty) {
10960 $out .= '<option value="0"></option>';
10961 }
10962 if ($allchoice) {
10963 $out .= '<option value="-1">' . $langs->trans('AllExpenseReport') . '</option>';
10964 }
10965
10966 $field = 'code';
10967 if ($useid) {
10968 $field = 'id';
10969 }
10970
10971 while ($obj = $this->db->fetch_object($resql)) {
10972 $key = $langs->trans($obj->code);
10973 $out .= '<option ' . ($selected == $obj->{$field} ? 'selected="selected"' : '') . ' value="' . $obj->{$field} . '">' . ($key != $obj->code ? $key : $obj->label) . '</option>';
10974 }
10975 $out .= '</select>';
10976
10977 $out .= ajax_combobox('select_'.$htmlname);
10978 } else {
10979 dol_print_error($this->db);
10980 }
10981
10982 return $out;
10983 }
10984
11003 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)
11004 {
11005 global $user, $conf, $langs;
11006
11007 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
11008
11009 if (is_null($usertofilter)) {
11010 $usertofilter = $user;
11011 }
11012
11013 $out = '';
11014
11015 $hideunselectables = false;
11016 if (getDolGlobalString('PROJECT_HIDE_UNSELECTABLES')) {
11017 $hideunselectables = true;
11018 }
11019
11020 if (empty($projectsListId)) {
11021 if (!$usertofilter->hasRight('projet', 'all', 'lire')) {
11022 $projectstatic = new Project($this->db);
11023 $projectsListId = $projectstatic->getProjectsAuthorizedForUser($usertofilter, 0, 1);
11024 }
11025 }
11026
11027 // Search all projects
11028 $sql = "SELECT f.rowid, f.ref as fref, 'nolabel' as flabel, p.rowid as pid, f.ref,
11029 p.title, p.fk_soc, p.fk_statut, p.public,";
11030 $sql .= ' s.nom as name';
11031 $sql .= ' FROM ' . $this->db->prefix() . 'projet as p';
11032 $sql .= ' LEFT JOIN ' . $this->db->prefix() . 'societe as s ON s.rowid = p.fk_soc,';
11033 $sql .= ' ' . $this->db->prefix() . 'facture as f';
11034 $sql .= " WHERE p.entity IN (" . getEntity('project') . ")";
11035 $sql .= " AND f.fk_projet = p.rowid AND f.fk_statut=0"; //Brouillons seulement
11036 //if ($projectsListId) $sql.= " AND p.rowid IN (".$this->db->sanitize($projectsListId).")";
11037 //if ($socid == 0) $sql.= " AND (p.fk_soc=0 OR p.fk_soc IS NULL)";
11038 //if ($socid > 0) $sql.= " AND (p.fk_soc=".((int) $socid)." OR p.fk_soc IS NULL)";
11039 $sql .= " ORDER BY p.ref, f.ref ASC";
11040
11041 $resql = $this->db->query($sql);
11042 if ($resql) {
11043 // Use select2 selector
11044 if (!empty($conf->use_javascript_ajax)) {
11045 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11046 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11047 $out .= $comboenhancement;
11048 $morecss = 'minwidth200imp maxwidth500';
11049 }
11050
11051 if (empty($option_only)) {
11052 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11053 }
11054 if (!empty($show_empty)) {
11055 $out .= '<option value="0" class="optiongrey">';
11056 if (!is_numeric($show_empty)) {
11057 $out .= $show_empty;
11058 } else {
11059 $out .= '&nbsp;';
11060 }
11061 $out .= '</option>';
11062 }
11063 $num = $this->db->num_rows($resql);
11064 $i = 0;
11065 if ($num) {
11066 while ($i < $num) {
11067 $obj = $this->db->fetch_object($resql);
11068 // 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.
11069 if ($socid > 0 && (empty($obj->fk_soc) || $obj->fk_soc == $socid) && !$usertofilter->hasRight('societe', 'lire')) {
11070 // Do nothing
11071 } else {
11072 if ($discard_closed == 1 && $obj->fk_statut == Project::STATUS_CLOSED) {
11073 $i++;
11074 continue;
11075 }
11076
11077 $labeltoshow = '';
11078
11079 if ($showproject == 'all') {
11080 $labeltoshow .= dol_trunc($obj->ref, 18); // Invoice ref
11081 if ($obj->name) {
11082 $labeltoshow .= ' - ' . $obj->name; // Soc name
11083 }
11084
11085 $disabled = 0;
11086 if ($obj->fk_statut == Project::STATUS_DRAFT) {
11087 $disabled = 1;
11088 $labeltoshow .= ' - ' . $langs->trans("Draft");
11089 } elseif ($obj->fk_statut == Project::STATUS_CLOSED) {
11090 if ($discard_closed == 2) {
11091 $disabled = 1;
11092 }
11093 $labeltoshow .= ' - ' . $langs->trans("Closed");
11094 } elseif ($socid > 0 && (!empty($obj->fk_soc) && $obj->fk_soc != $socid)) {
11095 $disabled = 1;
11096 $labeltoshow .= ' - ' . $langs->trans("LinkedToAnotherCompany");
11097 }
11098 }
11099
11100 if (!empty($selected) && $selected == $obj->rowid) {
11101 $out .= '<option value="' . $obj->rowid . '" selected';
11102 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11103 $out .= '>' . $labeltoshow . '</option>';
11104 } else {
11105 if ($hideunselectables && $disabled && ($selected != $obj->rowid)) {
11106 $resultat = '';
11107 } else {
11108 $resultat = '<option value="' . $obj->rowid . '"';
11109 if ($disabled) {
11110 $resultat .= ' disabled';
11111 }
11112 //if ($obj->public) $labeltoshow.=' ('.$langs->trans("Public").')';
11113 //else $labeltoshow.=' ('.$langs->trans("Private").')';
11114 $resultat .= '>';
11115 $resultat .= $labeltoshow;
11116 $resultat .= '</option>';
11117 }
11118 $out .= $resultat;
11119 }
11120 }
11121 $i++;
11122 }
11123 }
11124 if (empty($option_only)) {
11125 $out .= '</select>';
11126 }
11127
11128 $this->db->free($resql);
11129
11130 return $out;
11131 } else {
11132 dol_print_error($this->db);
11133 return '';
11134 }
11135 }
11136
11150 public function selectInvoiceRec($selected = '', $htmlname = 'facrecid', $maxlength = 24, $option_only = 0, $show_empty = '1', $forcefocus = 0, $disabled = 0, $morecss = 'maxwidth500')
11151 {
11152 global $conf, $langs;
11153
11154 $out = '';
11155
11156 dol_syslog('FactureRec::fetch', LOG_DEBUG);
11157
11158 $sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc';
11159 //$sql.= ', el.fk_source';
11160 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as f';
11161 $sql .= " WHERE f.entity IN (" . getEntity('invoice') . ")";
11162 $sql .= " ORDER BY f.titre ASC";
11163
11164 $resql = $this->db->query($sql);
11165 if ($resql) {
11166 // Use select2 selector
11167 if (!empty($conf->use_javascript_ajax)) {
11168 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
11169 $comboenhancement = ajax_combobox($htmlname, array(), 0, $forcefocus);
11170 $out .= $comboenhancement;
11171 $morecss = 'minwidth200imp maxwidth500';
11172 }
11173
11174 if (empty($option_only)) {
11175 $out .= '<select class="valignmiddle flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($disabled ? ' disabled="disabled"' : '') . ' id="' . $htmlname . '" name="' . $htmlname . '">';
11176 }
11177 if (!empty($show_empty)) {
11178 $out .= '<option value="0" class="optiongrey">';
11179 if (!is_numeric($show_empty)) {
11180 $out .= $show_empty;
11181 } else {
11182 $out .= '&nbsp;';
11183 }
11184 $out .= '</option>';
11185 }
11186 $num = $this->db->num_rows($resql);
11187 if ($num) {
11188 while ($obj = $this->db->fetch_object($resql)) {
11189 $labeltoshow = dol_trunc($obj->title, 18); // Invoice ref
11190
11191 $disabled = 0;
11192 if (!empty($obj->suspended)) {
11193 $disabled = 1;
11194 $labeltoshow .= ' - ' . $langs->trans("Closed");
11195 }
11196
11197
11198 if (!empty($selected) && $selected == $obj->rowid) {
11199 $out .= '<option value="' . $obj->rowid . '" selected';
11200 //if ($disabled) $out.=' disabled'; // with select2, field can't be preselected if disabled
11201 $out .= '>' . $labeltoshow . '</option>';
11202 } else {
11203 if ($disabled && ($selected != $obj->rowid)) {
11204 $resultat = '';
11205 } else {
11206 $resultat = '<option value="' . $obj->rowid . '"';
11207 if ($disabled) {
11208 $resultat .= ' disabled';
11209 }
11210 $resultat .= '>';
11211 $resultat .= $labeltoshow;
11212 $resultat .= '</option>';
11213 }
11214 $out .= $resultat;
11215 }
11216 }
11217 }
11218 if (empty($option_only)) {
11219 $out .= '</select>';
11220 }
11221
11222 print $out;
11223
11224 $this->db->free($resql);
11225 return $num;
11226 } else {
11227 $this->errors[] = $this->db->lasterror;
11228 return -1;
11229 }
11230 }
11231
11242 public function searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput = array(), $search_component_params_hidden = '', $arrayoffiltercriterias = array())
11243 {
11244 // TODO: Use $arrayoffiltercriterias param instead of $arrayofcriterias to include linked object fields in search
11245 global $langs, $form;
11246
11247 require_once DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php";
11248 $formother = new FormOther($this->db);
11249
11250 if ($search_component_params_hidden != '' && !preg_match('/^\‍(.*\‍)$/', $search_component_params_hidden)) { // If $search_component_params_hidden does not start and end with ()
11251 $search_component_params_hidden = '(' . $search_component_params_hidden . ')';
11252 }
11253
11254 $ret = '<!-- searchComponent -->';
11255
11256 $ret .= '<div class="divadvancedsearchfieldcomp centpercent inline-block">';
11257 $ret .= '<a href="#" class="dropdownsearch-toggle unsetcolor">';
11258 $ret .= '<span class="fas fa-filter linkobject boxfilter paddingright pictofixedwidth" title="' . dol_escape_htmltag($langs->trans("Filters")) . '" id="idsubimgproductdistribution"></span>';
11259 $ret .= '</a>';
11260
11261 $ret .= '<div class="divadvancedsearchfieldcompinput inline-block minwidth500 maxwidth300onsmartphone">';
11262
11263 // Show select fields as tags.
11264 $ret .= '<div id="divsearch_component_params" name="divsearch_component_params" class="noborderbottom search_component_params inline-block valignmiddle">';
11265
11266 if ($search_component_params_hidden) {
11267 // Split the criteria on each AND
11268 //var_dump($search_component_params_hidden);
11269
11270 $arrayofandtags = dolForgeExplodeAnd($search_component_params_hidden);
11271
11272 // $arrayofandtags is now array( '...' , '...', ...)
11273 // Show each AND part
11274 foreach ($arrayofandtags as $tmpkey => $tmpval) {
11275 $errormessage = '';
11276 $searchtags = forgeSQLFromUniversalSearchCriteria($tmpval, $errormessage, 1, 1);
11277 if ($errormessage) {
11278 $this->error = 'ERROR in parsing search string: '.$errormessage;
11279 }
11280 // Remove first and last parenthesis but only if first is the opening and last the closing of the same group
11281 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
11282 $searchtags = removeGlobalParenthesis($searchtags);
11283
11284 $ret .= '<span class="marginleftonlyshort valignmiddle tagsearch" data-ufilterid="'.($tmpkey + 1).'" data-ufilter="'.dol_escape_htmltag($tmpval).'">';
11285 $ret .= '<span class="tagsearchdelete select2-selection__choice__remove" data-ufilterid="'.($tmpkey + 1).'">x</span> ';
11286 $ret .= dol_escape_htmltag($searchtags);
11287 $ret .= '</span>';
11288 }
11289 }
11290
11291 //$ret .= '<button type="submit" class="liste_titre button_search paddingleftonly" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
11292
11293 //$ret .= search_component_params
11294 //$texttoshow = '<div class="opacitymedium inline-block search_component_searchtext">'.$langs->trans("Search").'</div>';
11295 //$ret .= '<div class="search_component inline-block valignmiddle">'.$texttoshow.'</div>';
11296
11297 $show_search_component_params_hidden = 1;
11298 if ($show_search_component_params_hidden) {
11299 $ret .= '<input type="hidden" name="show_search_component_params_hidden" value="1">';
11300 }
11301 $ret .= "<!-- We store the full Universal Search String into this field. For example: (t.ref:like:'SO-%') AND ((t.ref:like:'CO-%') OR (t.ref:like:'AA%')) -->";
11302 $ret .= '<input type="hidden" id="search_component_params_hidden" name="search_component_params_hidden" value="' . dol_escape_htmltag($search_component_params_hidden) . '">';
11303 // $ret .= "<!-- sql= ".forgeSQLFromUniversalSearchCriteria($search_component_params_hidden, $errormessage)." -->";
11304
11305 // TODO : Use $arrayoffiltercriterias instead of $arrayofcriterias
11306 // For compatibility with forms that show themself the search criteria in addition of this component, we output these fields
11307 foreach ($arrayofcriterias as $criteria) {
11308 foreach ($criteria as $criteriafamilykey => $criteriafamilyval) {
11309 if (in_array('search_' . $criteriafamilykey, $arrayofinputfieldsalreadyoutput)) {
11310 continue;
11311 }
11312 if (in_array($criteriafamilykey, array('rowid', 'ref_ext', 'entity', 'extraparams'))) {
11313 continue;
11314 }
11315 if (in_array($criteriafamilyval['type'], array('date', 'datetime', 'timestamp'))) {
11316 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_start">';
11317 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startyear">';
11318 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startmonth">';
11319 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_startday">';
11320 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_end">';
11321 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endyear">';
11322 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endmonth">';
11323 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '_endday">';
11324 } else {
11325 $ret .= '<input type="hidden" name="search_' . $criteriafamilykey . '">';
11326 }
11327 }
11328 }
11329
11330 $ret .= '</div>';
11331
11332 $ret .= "<!-- Field to enter a generic filter string: t.ref:like:'SO-%', t.date_creation:<:'20160101', t.date_creation:<:'2016-01-01 12:30:00', t.nature:is:NULL, t.field2:isnot:NULL -->\n";
11333 $ret .= '<input type="text" placeholder="' . $langs->trans("Filters") . '" id="search_component_params_input" name="search_component_params_input" class="noborderbottom search_component_input" value="">';
11334
11335 $ret .= '</div>';
11336 $ret .= '</div>';
11337
11338 $ret .= '<script>
11339 jQuery(".tagsearchdelete").click(function(e) {
11340 var filterid = $(this).parents().attr("data-ufilterid");
11341 console.log("We click to delete the criteria nb "+filterid);
11342
11343 // Regenerate the search_component_params_hidden with all data-ufilter except the one to delete, and post the page
11344 var newparamstring = \'\';
11345 $(\'.tagsearch\').each(function(index, element) {
11346 tmpfilterid = $(this).attr("data-ufilterid");
11347 if (tmpfilterid != filterid) {
11348 // We keep this criteria
11349 if (newparamstring == \'\') {
11350 newparamstring = $(this).attr("data-ufilter");
11351 } else {
11352 newparamstring = newparamstring + \' AND \' + $(this).attr("data-ufilter");
11353 }
11354 }
11355 });
11356 console.log("newparamstring = "+newparamstring);
11357
11358 jQuery("#search_component_params_hidden").val(newparamstring);
11359
11360 // We repost the form
11361 $(this).closest(\'form\').submit();
11362 });
11363
11364 jQuery("#search_component_params_input").keydown(function(e) {
11365 console.log("We press a key on the filter field that is "+jQuery("#search_component_params_input").val());
11366 console.log(e.which);
11367 if (jQuery("#search_component_params_input").val() == "" && e.which == 8) {
11368 /* We click on back when the input field is already empty */
11369 event.preventDefault();
11370 jQuery("#divsearch_component_params .tagsearch").last().remove();
11371 /* Regenerate content of search_component_params_hidden from remaining .tagsearch */
11372 var s = "";
11373 jQuery("#divsearch_component_params .tagsearch").each(function( index ) {
11374 if (s != "") {
11375 s = s + " AND ";
11376 }
11377 s = s + $(this).attr("data-ufilter");
11378 });
11379 console.log("New value for search_component_params_hidden = "+s);
11380 jQuery("#search_component_params_hidden").val(s);
11381 }
11382 });
11383
11384 </script>
11385 ';
11386
11387 // Convert $arrayoffiltercriterias into a json object that can be used in jquery to build the search component dynamically
11388 $arrayoffiltercriterias_json = json_encode($arrayoffiltercriterias);
11389 $ret .= '<script>
11390 var arrayoffiltercriterias = ' . $arrayoffiltercriterias_json . ';
11391 </script>';
11392
11393
11394 $arrayoffilterfieldslabel = array();
11395 foreach ($arrayoffiltercriterias as $key => $val) {
11396 $arrayoffilterfieldslabel[$key]['label'] = $val['label'];
11397 $arrayoffilterfieldslabel[$key]['data-type'] = $val['type'];
11398 }
11399
11400 // Adding the div for search assistance
11401 $ret .= '<div class="search-component-assistance">';
11402 $ret .= '<div>';
11403
11404 $ret .= '<p class="assistance-title">' . img_picto('', 'filter') . ' ' . $langs->trans('FilterAssistance') . ' </p>';
11405
11406 $ret .= '<p class="assistance-errors error" style="display:none">' . $langs->trans('AllFieldsRequired') . ' </p>';
11407
11408 $ret .= '<div class="operand">';
11409 $ret .= $form->selectarray('search_filter_field', $arrayoffilterfieldslabel, '', $langs->trans("Fields"), 0, 0, '', 0, 0, 0, '', 'width200 combolargeelem', 1);
11410 $ret .= '</div>';
11411
11412 $ret .= '<span class="separator"></span>';
11413
11414 // Operator selector (will be populated dynamically)
11415 $ret .= '<div class="operator">';
11416 $ret .= '<select class="operator-selector width150" id="operator-selector"">';
11417 $ret .= '</select>';
11418 $ret .= '<script>$(document).ready(function() {';
11419 $ret .= ' $(".operator-selector").select2({';
11420 $ret .= ' placeholder: \'' . dol_escape_js($langs->trans('Operator')) . '\'';
11421 $ret .= ' });';
11422 $ret .= '});</script>';
11423 $ret .= '</div>';
11424
11425 $ret .= '<span class="separator"></span>';
11426
11427 $ret .= '<div class="value">';
11428 // Input field for entering values
11429 $ret .= '<input type="text" class="flat width100 value-input" placeholder="' . dolPrintHTML($langs->trans('Value')) . '">';
11430
11431 // Date selector
11432 $dateOne = '';
11433 $ret .= '<span class="date-one" style="display:none">';
11434 $ret .= $form->selectDate(($dateOne ? $dateOne : -1), 'dateone', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '');
11435 $ret .= '</span>';
11436
11437 // Value selector (will be populated dynamically) based on search_filter_field value if a selected value has an array of values
11438 $ret .= '<select class="value-selector width150" id="value-selector" style="display:none">';
11439 $ret .= '</select>';
11440 $ret .= '<script>
11441 $(document).ready(function() {
11442 $("#value-selector").select2({
11443 placeholder: "' . dol_escape_js($langs->trans('Value')) . '"
11444 });
11445 $("#value-selector").hide();
11446 $("#value-selector").next(".select2-container").hide();
11447 });
11448 </script>';
11449
11450 $ret .= '</div>';
11451
11452 $ret .= '<div class="btn-div">';
11453 $ret .= '<button class="button buttongen button-save add-filter-btn" type="button">' . $langs->trans("addToFilter") . '</button>';
11454 $ret .= '</div>';
11455
11456 $ret .= '</div>';
11457 //$ret .= '</tbody></table>';
11458
11459 // End of the assistance div
11460 $ret .= '</div>';
11461
11462 // Script jQuery to show/hide the floating assistance
11463 $ret .= '<script>
11464 $(document).ready(function() {
11465 $("#search_component_params_input").on("click", function() {
11466 const inputPosition = $(this).offset();
11467 const inputHeight = $(this).outerHeight();
11468 $(".search-component-assistance").css({
11469 top: inputPosition.top + inputHeight + 5 + "px",
11470 left: $("#divsearch_component_params").position().left
11471 }).slideToggle(200);
11472 });
11473 $(document).on("click", function(e) {
11474 if (!$(e.target).closest("#search_component_params_input, .search-component-assistance, #ui-datepicker-div").length) {
11475 $(".search-component-assistance").hide();
11476 }
11477 });
11478 });
11479 </script>';
11480
11481 $ret .= '<script>
11482 $(document).ready(function() {
11483 $(".search_filter_field").on("change", function() {
11484 let maybenull = 0;
11485 const selectedField = $(this).find(":selected");
11486 let fieldType = selectedField.data("type");
11487 const selectedFieldValue = selectedField.val();
11488
11489 // If the selected field has an array of values then ask toshow the value selector instead of the value input
11490 if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
11491 fieldType = "select";
11492 }
11493
11494 // If the selected field may be null then ask to append the "IsDefined" and "IsNotDefined" operators
11495 if (arrayoffiltercriterias[selectedFieldValue]["maybenull"] !== undefined) {
11496 maybenull = 1;
11497 }
11498 const operators = getOperatorsForFieldType(fieldType, maybenull);
11499 const operatorSelector = $(".operator-selector");
11500
11501 // Clear existing options
11502 operatorSelector.empty();
11503
11504 // Populate operators
11505 Object.entries(operators).forEach(function([operator, label]) {
11506 operatorSelector.append("<option value=\'" + operator + "\'>" + label + "</option>");
11507 });
11508
11509 operatorSelector.trigger("change.select2");
11510
11511 // Clear and hide all input elements initially
11512 $(".value-input, .dateone, .datemonth, .dateyear").val("").hide();
11513 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11514 $("#dateone").datepicker("setDate", null);
11515 $(".date-one, .date-month, .date-year").hide();
11516 $("#value-selector").val("").hide();
11517 $("#value-selector").next(".select2-container").hide();
11518 $("#value-selector").val(null).trigger("change.select2");
11519
11520 if (fieldType === "date" || fieldType === "datetime" || fieldType === "timestamp") {
11521 $(".date-one").show();
11522 } else if (arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"] !== undefined) {
11523 var arrayofkeyval = arrayoffiltercriterias[selectedFieldValue]["arrayofkeyval"];
11524 var valueSelector = $("#value-selector");
11525 valueSelector.empty();
11526 Object.entries(arrayofkeyval).forEach(function([key, val]) {
11527 valueSelector.append("<option value=\'" + key + "\'>" + val + "</option>");
11528 });
11529 valueSelector.trigger("change.select2");
11530
11531 $("#value-selector").show();
11532 $("#value-selector").next(".select2-container").show();
11533 } else {
11534 $(".value-input").show();
11535 }
11536 });
11537
11538 $("#operator-selector").on("change", function() {
11539 const selectedOperator = $(this).find(":selected").val();
11540 if (selectedOperator === "IsDefined" || selectedOperator === "IsNotDefined") {
11541 // Disable all value input elements
11542 $(".value-input, .dateone, .datemonth, .dateyear").val("").prop("disabled", true);
11543 $("#datemonth, #dateyear").val(null).trigger("change.select2");
11544 $("#dateone").datepicker("setDate", null).datepicker("option", "disabled", true);
11545 $(".date-one, .date-month, .date-year").prop("disabled", true);
11546 $("#value-selector").val("").prop("disabled", true);
11547 $("#value-selector").val(null).trigger("change.select2");
11548 } else {
11549 // Enable all value input elements
11550 $(".value-input, .dateone, .datemonth, .dateyear").prop("disabled", false);
11551 $(".date-one, .date-month, .date-year").prop("disabled", false);
11552 $("#dateone").datepicker("option", "disabled", false);
11553 $("#value-selector").prop("disabled", false);
11554 }
11555 });
11556
11557 $(".add-filter-btn").on("click", function(event) {
11558 event.preventDefault();
11559
11560 const field = $(".search_filter_field").val();
11561 const operator = $(".operator-selector").val();
11562 let value = $(".value-input").val();
11563 const fieldType = $(".search_filter_field").find(":selected").data("type");
11564
11565 if (["date", "datetime", "timestamp"].includes(fieldType)) {
11566 const parsedDate = new Date($("#dateone").val());
11567 if (!isNaN(parsedDate)) {
11568 const year = parsedDate.getFullYear();
11569 const month = String(parsedDate.getMonth() + 1).padStart(2, "0");
11570 const day = String(parsedDate.getDate()).padStart(2, "0");
11571 value = `${year}-${month}-${day}`;
11572 }
11573 }
11574
11575 // If the selected field has an array of values then take the selected value
11576 if (arrayoffiltercriterias[field]["arrayofkeyval"] !== undefined) {
11577 value = $("#value-selector").val();
11578 }
11579
11580 // If the operator is "IsDefined" or "IsNotDefined" then set the value to 1 (it will not be used)
11581 if (operator === "IsDefined" || operator === "IsNotDefined") {
11582 value = "1";
11583 }
11584
11585 const filterString = generateFilterString(field, operator, value, fieldType);
11586
11587 // Submit the form
11588 if (filterString !== "" && field !== "" && operator !== "" && value !== "") {
11589 $("#search_component_params_input").val($("#search_component_params_input").val() + " " + filterString);
11590 $("#search_component_params_input").closest("form").submit();
11591 } else {
11592 $(".assistance-errors").show();
11593 }
11594 });
11595 });
11596 </script>';
11597
11598 return $ret;
11599 }
11600
11611 public function selectModelMail($prefix, $modelType = '', $default = 0, $addjscombo = 0, $selected = '')
11612 {
11613 global $langs, $user;
11614
11615 $retstring = '';
11616
11617 $TModels = array();
11618
11619 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
11620 $formmail = new FormMail($this->db);
11621 $result = $formmail->fetchAllEMailTemplate($modelType, $user, $langs);
11622
11623 if ($default) {
11624 $TModels[0] = $langs->trans('DefaultMailModel');
11625 }
11626 if ($result > 0) {
11627 foreach ($formmail->lines_model as $model) {
11628 $TModels[$model->id] = $model->label;
11629 }
11630 }
11631
11632 $retstring .= '<select class="flat" id="select_' . $prefix . 'model_mail" name="' . $prefix . 'model_mail">';
11633
11634 foreach ($TModels as $id_model => $label_model) {
11635 $retstring .= '<option value="' . $id_model . '"';
11636 if (!empty($selected) && $selected == $id_model) {
11637 $retstring .= "selected";
11638 }
11639 $retstring .= ">" . $label_model . "</option>";
11640 }
11641
11642 $retstring .= "</select>";
11643
11644 if ($addjscombo) {
11645 $retstring .= ajax_combobox('select_' . $prefix . 'model_mail');
11646 }
11647
11648 return $retstring;
11649 }
11650
11662 public function buttonsSaveCancel($save_label = 'Save', $cancel_label = 'Cancel', $morebuttons = array(), $withoutdiv = false, $morecss = '', $dol_openinpopup = '')
11663 {
11664 global $langs;
11665
11666 $buttons = array();
11667
11668 $save = array(
11669 'name' => 'save',
11670 'label_key' => $save_label,
11671 );
11672
11673 if ($save_label == 'Create' || $save_label == 'Add') {
11674 $save['name'] = 'add';
11675 } elseif ($save_label == 'Modify') {
11676 $save['name'] = 'edit';
11677 }
11678
11679 $cancel = array(
11680 'name' => 'cancel',
11681 'label_key' => 'Cancel',
11682 );
11683
11684 !empty($save_label) ? $buttons[] = $save : '';
11685
11686 if (!empty($morebuttons)) {
11687 $buttons[] = $morebuttons;
11688 }
11689
11690 !empty($cancel_label) ? $buttons[] = $cancel : '';
11691
11692 $retstring = $withoutdiv ? '' : '<div class="center">';
11693
11694 foreach ($buttons as $button) {
11695 $addclass = empty($button['addclass']) ? '' : $button['addclass'];
11696 $retstring .= '<input type="submit" class="button button-' . $button['name'] . ($morecss ? ' ' . $morecss : '') . ' ' . $addclass . '" name="' . $button['name'] . '" value="' . dol_escape_htmltag($langs->trans($button['label_key'])) . '">';
11697 }
11698 $retstring .= $withoutdiv ? '' : '</div>';
11699
11700 if ($dol_openinpopup) {
11701 $retstring .= '<!-- buttons are shown into a $dol_openinpopup=' . dol_escape_htmltag($dol_openinpopup) . ' context, so we enable the close of dialog on cancel -->' . "\n";
11702 $retstring .= '<script nonce="' . getNonce() . '">';
11703 $retstring .= 'jQuery(".button-cancel").click(function(e) {
11704 e.preventDefault(); console.log(\'We click on cancel in iframe popup ' . dol_escape_js($dol_openinpopup) . '\');
11705 window.parent.jQuery(\'#idfordialog' . dol_escape_js($dol_openinpopup) . '\').dialog(\'close\');
11706 });';
11707 $retstring .= '</script>';
11708 }
11709
11710 return $retstring;
11711 }
11712
11713
11714 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
11715
11722 {
11723 // phpcs:enable
11724 global $langs;
11725
11726 $num = count($this->cache_invoice_subtype);
11727 if ($num > 0) {
11728 return 0; // Cache already loaded
11729 }
11730
11731 dol_syslog(__METHOD__, LOG_DEBUG);
11732
11733 $sql = "SELECT rowid, code, label as label";
11734 $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype';
11735 $sql .= " WHERE active = 1";
11736
11737 $resql = $this->db->query($sql);
11738 if ($resql) {
11739 $num = $this->db->num_rows($resql);
11740 $i = 0;
11741 while ($i < $num) {
11742 $obj = $this->db->fetch_object($resql);
11743
11744 // If translation exists, we use it, otherwise we take the default wording
11745 $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != "InvoiceSubtype" . $obj->rowid) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : '');
11746 $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid;
11747 $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code;
11748 $this->cache_invoice_subtype[$obj->rowid]['label'] = $label;
11749 $i++;
11750 }
11751
11752 $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1);
11753
11754 return $num;
11755 } else {
11756 dol_print_error($this->db);
11757 return -1;
11758 }
11759 }
11760
11761
11772 public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '')
11773 {
11774 global $langs, $user;
11775
11776 $out = '';
11777 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
11778
11779 $this->load_cache_invoice_subtype();
11780
11781 $out .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
11782 if ($addempty) {
11783 $out .= '<option value="0">&nbsp;</option>';
11784 }
11785
11786 foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
11787 $label = $subtype['label'];
11788 $out .= '<option value="' . $subtype['rowid'] . '"';
11789 if ($selected == $subtype['rowid']) {
11790 $out .= ' selected="selected"';
11791 }
11792 $out .= '>';
11793 $out .= $label;
11794 $out .= '</option>';
11795 }
11796
11797 $out .= '</select>';
11798 if ($user->admin && empty($noinfoadmin)) {
11799 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
11800 }
11801 $out .= ajax_combobox($htmlname);
11802
11803 return $out;
11804 }
11805}
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
ajax_autocompleter($selected, $htmlname, $url, $urloption='', $minLength=2, $autoselect=0, $ajaxoptions=array(), $moreparams='')
Generic function that return javascript to add to transform a common input text or select field into ...
Definition ajax.lib.php:49
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:459
ajax_multiautocompleter($htmlname, $fields, $url, $option='', $minLength=2, $autoselect=0)
Generic function that return javascript to add to a page to transform a common input text field into ...
Definition ajax.lib.php:308
ajax_event($htmlname, $events)
Add event management script.
Definition ajax.lib.php:562
$c
Definition line.php:327
$object ref
Definition info.php:89
Class to manage bank accounts.
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage bank accounts description of third parties.
Class to manage contact/addresses.
Class to manage a WYSIWYG editor.
DAO Resource object.
const STATUS_OPEN_INTERNAL
Warehouse open and only operations for stock transfers/corrections allowed (not for customer shipping...
const STATUS_OPEN_ALL
Warehouse open and any operations are allowed (customer shipping, supplier dispatch,...
const STATUS_CLOSED
Warehouse closed, inactive.
Class to manage standard extra languages.
Class to manage invoices.
Class to manage generation of HTML components Only common components must be here.
showLinkToObjectBlock($object, $restrictlinksto=array(), $excludelinksto=array(), $nooutput=0)
Show block with links "to link to" other objects.
showFilterButtons($pos='')
Return HTML to show the search and clear search button.
select_dolusers_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofuserid=array(), $listofcontactid=array(), $listofotherid=array(), $canremoveowner=1)
Return select list of users.
load_cache_vatrates($country_code)
Load into the cache ->cache_vatrates, all the vat rates of a country.
formInputReason($page, $selected='', $htmlname='demandreason', $addempty=0)
Output HTML form to select list of input reason (events that triggered an object creation,...
editfieldval($text, $htmlname, $value, $object, $perm, $typeofdata='string', $editvalue='', $extObject=null, $custommsg=null, $moreparam='', $notabletag=1, $formatfunc='', $paramid='id', $gm='auto', $moreoptions=array(), $editaction='')
Output value of a field for an editable field.
form_availability($page, $selected='', $htmlname='availability', $addempty=0)
Show a form to select a delivery delay.
showLinkedObjectBlock($object, $morehtmlright='', $compatibleImportElementsList=array(), $title='RelatedObjects')
Show linked object block.
select_produits_fournisseurs($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $ajaxoptions=array(), $hidelabel=0, $alsoproductwithnosupplierprice=0, $morecss='', $placeholder='')
Return list of products for customer (in Ajax if Ajax activated or go to select_produits_fournisseurs...
selectMassAction($selected, $arrayofaction, $alwaysvisible=0, $name='massaction', $cssclass='checkforselect')
Generate select HTML to choose massaction.
select_dolresources_forevent($action='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include=array(), $enableonly=array(), $force_entity='0', $maxlength=0, $showstatus=0, $morefilter='', $showproperties=0, $listofresourceid=array())
Return select list of resources.
formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=0, $width=500, $disableformtag=0, $labelbuttonyes='Yes', $labelbuttonno='No')
form_multicurrency_code($page, $selected='', $htmlname='multicurrency_code')
Show form with multicurrency code.
formRib($page, $selected='', $htmlname='ribcompanyid', $filtre='', $addempty=0, $showibanbic=0)
Display form to select bank customer account.
showFilterAndCheckAddButtons($addcheckuncheckall=0, $cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
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(), $showcode=0)
Output html form to select a third party This call select_thirdparty_list() or ajax depending on setu...
select_produits($selected=0, $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, $status_purchase=-1, $warehouseId=0)
Return list of products for customer.
select_dolgroups($selected=0, $htmlname='groupid', $show_empty=0, $exclude='', $disabled=0, $include='', $enableonly=array(), $force_entity='0', $multiple=false, $morecss='minwidth200')
Return select list of user groups.
selectInputReason($selected='', $htmlname='demandreasonid', $exclude='', $addempty=0, $morecss='', $notooltip=0)
Return list of input reason (events that triggered an object creation, like after sending an emailing...
select_contact($socid, $selected='', $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $nokeyifsocid=true, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $selected_input_value='', $filter='')
Output html form to select a contact This call select_contacts() or ajax depending on setup.
select_incoterms($selected='', $location_incoterms='', $page='', $htmlname='incoterm_id', $htmloption='', $forcecombo=1, $events=array(), $disableautocomplete=0)
Return select list of incoterms.
select_type_of_lines($selected='', $htmlname='type', $showempty=0, $hidetext=0, $forceall=0, $morecss="", $useajaxcombo=1)
Return list of types of lines (product or service) Example: 0=product, 1=service, 9=other (for extern...
select_types_paiements($selected='', $htmlname='paiementtype', $filtertype='', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='', $nooutput=0)
Return list of payment methods Constant MAIN_DEFAULT_PAYMENT_TYPE_ID can used to set default value bu...
select_currency($selected='', $htmlname='currency_id')
Retourne la liste des devises, dans la langue de l'utilisateur.
formSelectTransportMode($page, $selected='', $htmlname='transport_mode_id', $active=1, $addempty=0)
Show form with transport mode.
selectShippingMethod($selected='', $htmlname='shipping_method_id', $filtre='', $useempty=0, $moreattrib='', $noinfoadmin=0, $morecss='')
Return a HTML select list of shipping mode.
selectRib($selected='', $htmlname='ribcompanyid', $filtre='', $useempty=0, $moreattrib='', $showibanbic=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts customer.
formSelectShippingMethod($page, $selected='', $htmlname='shipping_method_id', $addempty=0)
Display form to select shipping mode.
getSelectInvoiceSubtype($selected=0, $htmlname='subtypeid', $addempty=0, $noinfoadmin=0, $morecss='')
Return list of invoice subtypes.
select_produits_list($selected=0, $htmlname='productid', $filtertype='', $limit=20, $price_level=0, $filterkey='', $status=1, $finished=2, $outputmode=0, $socid=0, $showempty='1', $forcecombo=0, $morecss='maxwidth500', $hidepriceinlabel=0, $warehouseStatus='', $status_purchase=-1, $warehouseId=0)
Return list of products for a customer.
form_contacts($page, $societe, $selected='', $htmlname='contactid')
Show forms to select a contact.
selectMultiCurrency($selected='', $htmlname='multicurrency_code', $useempty=0, $filter='', $excludeConfCurrency=false, $morecss='')
Return array of currencies in user language.
load_tva($htmlname='tauxtva', $selectedrate='', $societe_vendeuse=null, $societe_acheteuse=null, $idprod=0, $info_bits=0, $type='', $options_only=false, $mode=0, $type_vat=0)
Output an HTML select vat rate.
form_multicurrency_rate($page, $rate=0.0, $htmlname='multicurrency_tx', $currency='')
Show form with multicurrency rate.
load_cache_availability()
select_bom($selected='', $htmlname='bom_id', $limit=0, $status=1, $type=0, $showempty='1', $morecss='', $nooutput='', $forcecombo=0, $TProducts=[])
Return list of BOM for customer in Ajax if Ajax activated or go to select_produits_list.
selectcontacts($socid, $selected=array(), $htmlname='contactid', $showempty=0, $exclude='', $limitto='', $showfunction=0, $morecss='', $options_only=0, $showsoc=0, $forcecombo=0, $events=array(), $moreparam='', $htmlid='', $multiple=false, $disableifempty=0, $filter='')
Return HTML code of the SELECT of list of all contacts (for a third party or all).
static selectarray($htmlname, $array, $id='', $show_empty=0, $key_in_label=0, $value_as_key=0, $moreparam='', $translate=0, $maxlen=0, $disabled=0, $sort='', $morecss='minwidth75', $addjscombo=1, $moreparamonempty='', $disablebademail=0, $nohtmlescape=0)
Return a HTML select string, built from an array of key+value.
select_type_fees($selected='', $htmlname='type', $showempty=0)
Return list of types of notes.
selectInvoiceRec($selected='', $htmlname='facrecid', $maxlength=24, $option_only=0, $show_empty='1', $forcefocus=0, $disabled=0, $morecss='maxwidth500')
Output a combo list with invoices qualified for a third party.
editInPlace($object, $value, $htmlname, $condition, $inputType='textarea', $editvalue=null, $extObject=null, $custommsg=null)
Output edit in place form.
selectUnits($selected='', $htmlname='units', $showempty=0, $unit_type='')
Creates HTML units selector (code => label)
select_produits_fournisseurs_list($socid, $selected='', $htmlname='productid', $filtertype='', $filtre='', $filterkey='', $statut=-1, $outputmode=0, $limit=100, $alsoproductwithnosupplierprice=0, $morecss='', $showstockinlist=0, $placeholder='')
Return list of suppliers products.
form_modes_reglement($page, $selected='', $htmlname='mode_reglement_id', $filtertype='', $active=1, $addempty=0, $type='', $nooutput=0)
Show form with payment mode.
constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel=0, $filterkey='', $novirtualstock=0)
Function to forge the string with OPTIONs of SELECT.
form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter='', $maxvalue=0, $more='', $hidelist=0, $discount_type=0)
Show a select box with available absolute discounts.
buttonsSaveCancel($save_label='Save', $cancel_label='Cancel', $morebuttons=array(), $withoutdiv=false, $morecss='', $dol_openinpopup='')
Output the buttons to submit a creation/edit form.
select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0, $exclude_country_code=array(), $hideflags=0, $forcecombo=0)
Return combo list of activated countries, into language of user.
selectTransportMode($selected='', $htmlname='transportmode', $format=0, $empty=1, $noadmininfo=0, $maxlength=0, $active=1, $morecss='')
Return list of transport mode for intracomm report.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
form_conditions_reglement($page, $selected='', $htmlname='cond_reglement_id', $addempty=0, $type='', $filtertype=-1, $deposit_percent=-1, $nooutput=0)
Show a form to select payment conditions.
selectSituationInvoices($selected='', $socid=0)
Creates HTML last in cycle situation invoices selector.
loadCacheInputReason()
Load into cache cache_demand_reason, array of input reasons.
selectModelMail($prefix, $modelType='', $default=0, $addjscombo=0, $selected='')
selectModelMail
selectPriceBaseType($selected='', $htmlname='price_base_type', $addjscombo=0)
Selection HT or TTC.
load_cache_transport_mode()
select_conditions_paiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1, $noprint=0)
print list of payment modes.
select_remises($selected, $htmlname, $filter, $socid, $maxvalue=0)
Return HTML combo list of absolute discounts.
showbarcode(&$object, $width=100, $morecss='')
Return HTML code to output a barcode.
form_confirm($page, $title, $question, $action, $formquestion=array(), $selectedchoice="", $useajax=0, $height=170, $width=500)
load_cache_conditions_paiements()
form_project($page, $socid, $selected='', $htmlname='projectid', $discard_closed=0, $maxlength=20, $forcefocus=0, $nooutput=0, $textifnoproject='', $morecss='')
Show a form to select a project.
selectExpenseCategories($selected='', $htmlname='fk_c_exp_tax_cat', $useempty=0, $excludeid=array(), $target='', $default_selected=0, $params=array(), $info_admin=1)
Return HTML to show the select of expense categories.
select_product_fourn_price($productid, $htmlname='productfournpriceid', $selected_supplier=0)
Return list of suppliers prices for a product.
selectyesno($htmlname, $value='', $option=0, $disabled=false, $useempty=0, $addjscombo=0, $morecss='width75', $labelyes='Yes', $labelno='No')
Return an html string with a select combo box to choose yes or no.
form_date($page, $selected, $htmlname, $displayhour=0, $displaymin=0, $nooutput=0, $type='')
Show a form + html select a date.
showCheckAddButtons($cssclass='checkforaction', $calljsfunction=0, $massactionname="massaction")
Return HTML to show the search and clear search button.
__construct($db)
Constructor.
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(), $showcode=0)
Output html form to select a third party.
select_users($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly=array(), $force_entity='0')
Return the HTML select list of users.
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', $calendarpicto='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $fromid=0, $outputmode=0, $include=0, $morecss='', $useempty=1)
Return list of categories having chosen type.
textwithpicto($text, $htmltooltip, $direction=1, $type='help', $extracss='valignmiddle', $noencodehtmltext=0, $notabs=3, $tooltiptrigger='', $forcenowrap=0)
Show a text with a picto and a tooltip on picto.
select_date($set_time='', $prefix='re', $h=0, $m=0, $empty=0, $form_name="", $d=1, $addnowlink=0, $nooutput=0, $disabled=0, $fullday=0, $addplusone='', $adddateof='')
Show a HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
load_cache_invoice_subtype()
Load into cache list of invoice subtypes.
select_export_model($selected='', $htmlname='exportmodelid', $type='', $useempty=0)
Return list of export templates.
selectDateToDate($set_time='', $set_time_end='', $prefix='re', $empty=0, $forcenewline=0)
Show 2 HTML widget to input a date or combo list for day, month, years and optionally hours and minut...
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=3, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.
select_dolusers($selected='', $htmlname='userid', $show_empty=0, $exclude=null, $disabled=0, $include='', $enableonly='', $force_entity='', $maxlength=0, $showstatus=0, $morefilter='', $show_every=0, $enableonlytext='', $morecss='', $notdisabled=0, $outputmode=0, $multiple=false, $forcecombo=0)
Return select list of users.
getSelectConditionsPaiements($selected=0, $htmlname='condid', $filtertype=-1, $addempty=0, $noinfoadmin=0, $morecss='', $deposit_percent=-1)
Return list of payment modes.
widgetForTranslation($fieldname, $object, $perm, $typeofdata='string', $check='', $morecss='')
Output edit in place form.
load_cache_types_fees()
Load into cache cache_types_fees, array of types of fees.
static multiselectarray($htmlname, $array, $selected=array(), $key_in_label=0, $value_as_key=0, $morecss='', $translate=0, $width=0, $moreattrib='', $elemtype='', $placeholder='', $addjscombo=-1)
Show a multiselect form from an array.
form_thirdparty($page, $selected='', $htmlname='socid', $filter='', $showempty=0, $showtype=0, $forcecombo=0, $events=array(), $nooutput=0, $excludeids=array(), $textifnothirdparty='')
Output html select to select thirdparty.
selectEstablishments($selected='', $htmlname='entity', $status=0, $filtre='', $useempty=0, $moreattrib='')
Return a HTML select list of establishment.
formSelectAccount($page, $selected='', $htmlname='fk_account', $addempty=0)
Display form to select bank account.
form_users($page, $selected='', $htmlname='userid', $exclude=array(), $include=array())
Show a select form to choose a user.
editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata='string', $moreparam='', $fieldrequired=0, $notabletag=0, $paramid='id', $help='')
Output key field for an editable field.
showCategories($id, $type, $rendermode=0, $nolink=0)
Render list of categories linked to object with id $id and type $type.
load_cache_types_paiements()
selectAvailabilityDelay($selected='', $htmlname='availid', $filtertype='', $addempty=0, $morecss='')
Return the list of type of delay available.
selectCurrency($selected='', $htmlname='currency_id', $mode=0, $useempty='')
Retourne la liste des devises, dans la langue de l'utilisateur.
select_comptes($selected='', $htmlname='accountid', $status=0, $filtre='', $useempty=0, $moreattrib='', $showcurrency=0, $morecss='', $nooutput=0)
Return a HTML select list of bank accounts.
showrefnav($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $morehtmlright='')
Return a HTML area with the reference of object and a navigation bar for a business object Note: To c...
searchComponent($arrayofcriterias, $search_component_params, $arrayofinputfieldsalreadyoutput=array(), $search_component_params_hidden='', $arrayoffiltercriterias=array())
Output the component to make advanced search criteries.
Class permettant la generation du formulaire html d'envoi de mail unitaire Usage: $formail = new Form...
Class permettant la generation de composants html autre Only common components are here.
Class to manage building of HTML components.
Class to manage forms for the module resource.
Class to manage hooks.
Class for MyObject.
Class to parse product price expressions.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class to manage projects.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Class toolbox to validate values.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:171
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
currency_name($code_iso, $withcode=0, $outputlangs=null)
Return label of currency or code+label.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0, $morecss='paddingrightonly')
Show EMail link formatted for HTML output.
getImageFileNameForSize($file, $extName, $extImgTarget='')
Return the filename of file to get the thumbs.
getAdvancedPreviewUrl($modulepart, $relativepath, $alldata=0, $param='')
Return URL we can use for advanced preview links.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
getNonce()
Return a random string to be used as a nonce value for js.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0, $allowscript=0, $allowstyle=0, $allowphp=0)
Clean a string to keep only desirable HTML tags.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
a disabled
treeview li table
No Email.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition main.inc.php:123
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
measuringUnitString($unitid, $measuring_style='', $unitscale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:150
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:153
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
getMaxFileSizeArray()
Return the max allowed for file upload.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.