dolibarr 21.0.0-beta
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, $htmltext, $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 = $htmltext;
777 $htmltext = '';
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, $htmltext, ((($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 || ' . $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
938 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)
939 {
940 // phpcs:enable
941 global $conf, $langs, $mysoc;
942
943 $langs->load("dict");
944
945 $out = '';
946 $countryArray = array();
947 $favorite = array();
948 $label = array();
949 $atleastonefavorite = 0;
950
951 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
952 $sql .= " FROM " . $this->db->prefix() . "c_country";
953 $sql .= " WHERE active > 0";
954 //$sql.= " ORDER BY code ASC";
955
956 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
957 $resql = $this->db->query($sql);
958 if ($resql) {
959 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
960 $num = $this->db->num_rows($resql);
961 $i = 0;
962 if ($num) {
963 while ($i < $num) {
964 $obj = $this->db->fetch_object($resql);
965
966 $countryArray[$i]['rowid'] = $obj->rowid;
967 $countryArray[$i]['code_iso'] = $obj->code_iso;
968 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
969 $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 : ''));
970 $countryArray[$i]['favorite'] = $obj->favorite;
971 $countryArray[$i]['eec'] = $obj->eec;
972 $favorite[$i] = $obj->favorite;
973 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
974 $i++;
975 }
976
977 if (empty($disablefavorites)) {
978 $array1_sort_order = SORT_DESC;
979 $array2_sort_order = SORT_ASC;
980 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
981 } else {
982 $countryArray = dol_sort_array($countryArray, 'label');
983 }
984
985 if ($showempty) {
986 if (is_numeric($showempty)) {
987 $out .= '<option value="">&nbsp;</option>' . "\n";
988 } else {
989 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
990 }
991 }
992
993 if ($addspecialentries) { // Add dedicated entries for groups of countries
994 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
995 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
996 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
997 if ($mysoc->isInEEC()) {
998 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 }
1000 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1001 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1002 }
1003
1004 foreach ($countryArray as $row) {
1005 //if (empty($showempty) && empty($row['rowid'])) continue;
1006 if (empty($row['rowid'])) {
1007 continue;
1008 }
1009 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1010 continue; // exclude some countries
1011 }
1012
1013 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1014 $atleastonefavorite++;
1015 }
1016 if (empty($row['favorite']) && $atleastonefavorite) {
1017 $atleastonefavorite = 0;
1018 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1019 }
1020
1021 $labeltoshow = '';
1022 if ($row['label']) {
1023 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1024 } else {
1025 $labeltoshow .= '&nbsp;';
1026 }
1027 if ($row['code_iso']) {
1028 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1029 if (empty($hideflags)) {
1030 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1031 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1032 }
1033 }
1034
1035 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1036 $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']) . '">';
1037 } else {
1038 $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']) . '">';
1039 }
1040 $out .= $labeltoshow;
1041 $out .= '</option>' . "\n";
1042 }
1043 }
1044 $out .= '</select>';
1045 } else {
1046 dol_print_error($this->db);
1047 }
1048
1049 // Make select dynamic
1050 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1051 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1052
1053 return $out;
1054 }
1055
1056 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1057
1071 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1072 {
1073 // phpcs:enable
1074 global $conf, $langs;
1075
1076 $langs->load("dict");
1077
1078 $out = '';
1079 $moreattrib = '';
1080 $incotermArray = array();
1081
1082 $sql = "SELECT rowid, code";
1083 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1084 $sql .= " WHERE active > 0";
1085 $sql .= " ORDER BY code ASC";
1086
1087 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1088 $resql = $this->db->query($sql);
1089 if ($resql) {
1090 if ($conf->use_javascript_ajax && !$forcecombo) {
1091 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1092 $out .= ajax_combobox($htmlname, $events);
1093 }
1094
1095 if (!empty($page)) {
1096 $out .= '<form method="post" action="' . $page . '">';
1097 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1098 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1099 }
1100
1101 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1102 $out .= '<option value="0">&nbsp;</option>';
1103 $num = $this->db->num_rows($resql);
1104 $i = 0;
1105 if ($num) {
1106 while ($i < $num) {
1107 $obj = $this->db->fetch_object($resql);
1108 $incotermArray[$i]['rowid'] = $obj->rowid;
1109 $incotermArray[$i]['code'] = $obj->code;
1110 $i++;
1111 }
1112
1113 foreach ($incotermArray as $row) {
1114 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1115 $out .= '<option value="' . $row['rowid'] . '" selected>';
1116 } else {
1117 $out .= '<option value="' . $row['rowid'] . '">';
1118 }
1119
1120 if ($row['code']) {
1121 $out .= $row['code'];
1122 }
1123
1124 $out .= '</option>';
1125 }
1126 }
1127 $out .= '</select>';
1128 $out .= ajax_combobox($htmlname);
1129
1130 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1131 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1132 $moreattrib .= ' autocomplete="off"';
1133 }
1134 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1135
1136 if (!empty($page)) {
1137 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1138 }
1139 } else {
1140 dol_print_error($this->db);
1141 }
1142
1143 return $out;
1144 }
1145
1146 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1147
1161 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "", $useajaxcombo = 1)
1162 {
1163 // phpcs:enable
1164 global $langs;
1165
1166 // If product & services are enabled or both disabled.
1167 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1168 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1169 if (empty($hidetext)) {
1170 print $langs->trans("Type").'...';
1171 }
1172 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1173 if ($showempty) {
1174 print '<option value="-1" class="opacitymedium"'.($useajaxcombo ? '' : ' disabled="disabled"');
1175 if ($selected == -1) {
1176 print ' selected';
1177 }
1178 print '>';
1179 if (is_numeric($showempty)) {
1180 print '&nbsp;';
1181 } else {
1182 print $showempty;
1183 }
1184 print '</option>';
1185 }
1186
1187 print '<option value="0"';
1188 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1189 print ' selected';
1190 }
1191 print '>' . $langs->trans("Product");
1192
1193 print '<option value="1"';
1194 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1195 print ' selected';
1196 }
1197 print '>' . $langs->trans("Service");
1198
1199 print '</select>';
1200
1201 if ($useajaxcombo) {
1202 print ajax_combobox('select_' . $htmlname);
1203 }
1204 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1205 }
1206 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1207 print $langs->trans("Service");
1208 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1209 }
1210 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1211 print $langs->trans("Product");
1212 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1213 }
1214 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1215 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
1216 }
1217 }
1218
1219 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1220
1226 public function load_cache_types_fees()
1227 {
1228 // phpcs:enable
1229 global $langs;
1230
1231 $num = count($this->cache_types_fees);
1232 if ($num > 0) {
1233 return 0; // Cache already loaded
1234 }
1235
1236 dol_syslog(__METHOD__, LOG_DEBUG);
1237
1238 $langs->load("trips");
1239
1240 $sql = "SELECT c.code, c.label";
1241 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1242 $sql .= " WHERE active > 0";
1243
1244 $resql = $this->db->query($sql);
1245 if ($resql) {
1246 $num = $this->db->num_rows($resql);
1247 $i = 0;
1248
1249 while ($i < $num) {
1250 $obj = $this->db->fetch_object($resql);
1251
1252 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1253 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1254 $this->cache_types_fees[$obj->code] = $label;
1255 $i++;
1256 }
1257
1258 asort($this->cache_types_fees);
1259
1260 return $num;
1261 } else {
1262 dol_print_error($this->db);
1263 return -1;
1264 }
1265 }
1266
1267 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1268
1277 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1278 {
1279 // phpcs:enable
1280 global $user, $langs;
1281
1282 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1283
1284 $this->load_cache_types_fees();
1285
1286 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1287 if ($showempty) {
1288 print '<option value="-1"';
1289 if ($selected == -1) {
1290 print ' selected';
1291 }
1292 print '>&nbsp;</option>';
1293 }
1294
1295 foreach ($this->cache_types_fees as $key => $value) {
1296 print '<option value="' . $key . '"';
1297 if ($key == $selected) {
1298 print ' selected';
1299 }
1300 print '>';
1301 print $value;
1302 print '</option>';
1303 }
1304
1305 print '</select>';
1306 if ($user->admin) {
1307 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1308 }
1309 }
1310
1311
1312 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1313
1336 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)
1337 {
1338 // phpcs:enable
1339 global $conf, $langs;
1340
1341 $out = '';
1342
1343 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1344 if (is_null($ajaxoptions)) {
1345 $ajaxoptions = array();
1346 }
1347
1348 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1349
1350 // No immediate load of all database
1351 $placeholder = '';
1352 if ($selected && empty($selected_input_value)) {
1353 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1354 $societetmp = new Societe($this->db);
1355 $societetmp->fetch($selected);
1356 $selected_input_value = $societetmp->name;
1357 unset($societetmp);
1358 }
1359
1360 // mode 1
1361 $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)) : '');
1362
1363 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1364 if (empty($hidelabel)) {
1365 $out .= $langs->trans("RefOrLabel") . ' : ';
1366 } elseif ($hidelabel == 1 && !is_numeric($showempty)) {
1367 $placeholder = $langs->trans($showempty);
1368 } elseif ($hidelabel > 1) {
1369 $placeholder = $langs->trans("RefOrLabel");
1370 if ($hidelabel == 2) {
1371 $out .= img_picto($langs->trans("Search"), 'search');
1372 }
1373 }
1374 $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' : '') . ' />';
1375 if ($hidelabel == 3) {
1376 $out .= img_picto($langs->trans("Search"), 'search');
1377 }
1378
1379 $out .= ajax_event($htmlname, $events);
1380
1381 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalInt('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1382 } else {
1383 // Immediate load of all database
1384 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1385 }
1386
1387 return $out;
1388 }
1389
1390
1391 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1392
1418 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 = '')
1419 {
1420 // phpcs:enable
1421
1422 global $conf, $langs;
1423
1424 $out = '';
1425
1426 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1427 if ($nokeyifsocid && $socid > 0) {
1428 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1429 }
1430
1431 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1432 if (is_null($events)) {
1433 $events = array();
1434 }
1435
1436 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1437
1438 // No immediate load of all database
1439 $placeholder = '';
1440 if ($selected && empty($selected_input_value)) {
1441 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1442 $contacttmp = new Contact($this->db);
1443 $contacttmp->fetch($selected);
1444 $selected_input_value = $contacttmp->getFullName($langs);
1445 unset($contacttmp);
1446 }
1447 if (!is_numeric($showempty)) {
1448 $placeholder = $showempty;
1449 }
1450
1451 // mode 1
1452 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1453
1454 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1455
1456 $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' : '') . ' />';
1457
1458 $out .= ajax_event($htmlname, $events);
1459
1460 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalInt('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1461 } else {
1462 // Immediate load of all database
1463 $multiple = false;
1464 $disableifempty = 0;
1465 $options_only = 0;
1466 $limitto = '';
1467
1468 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1469 }
1470
1471 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1472
1473 return $out;
1474 }
1475
1476
1477 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1478
1503 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)
1504 {
1505 // phpcs:enable
1506 global $user, $langs;
1507 global $hookmanager;
1508
1509 $langs->loadLangs(array("companies", "suppliers"));
1510
1511 $out = '';
1512 $num = 0;
1513 $outarray = array();
1514
1515 if ($selected === '') {
1516 $selected = array();
1517 } elseif (!is_array($selected)) {
1518 $selected = array($selected);
1519 }
1520
1521 // Clean $filter that may contains sql conditions so sql code
1522 if (function_exists('testSqlAndScriptInject')) {
1523 if (testSqlAndScriptInject($filter, 3) > 0) {
1524 $filter = '';
1525 return 'SQLInjectionTryDetected';
1526 }
1527 }
1528
1529 if ($filter != '') { // If a filter was provided
1530 if (preg_match('/[\‍(\‍)]/', $filter)) {
1531 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1532 $errormsg = '';
1533 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1534
1535 // Redo clean $filter that may contains sql conditions so sql code
1536 if (function_exists('testSqlAndScriptInject')) {
1537 if (testSqlAndScriptInject($filter, 3) > 0) {
1538 $filter = '';
1539 return 'SQLInjectionTryDetected';
1540 }
1541 }
1542 } else {
1543 // If not, we do nothing. We already know that there is no parenthesis
1544 // TODO Disallow this case in a future.
1545 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1546 }
1547 }
1548
1549 // We search companies
1550 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1551 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1552 $sql .= ", s.address, s.zip, s.town";
1553 $sql .= ", dictp.code as country_code";
1554 }
1555 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1556 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1557 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1558 }
1559 if (!$user->hasRight('societe', 'client', 'voir')) {
1560 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1561 }
1562 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1563 if (!empty($user->socid)) {
1564 $sql .= " AND s.rowid = " . ((int) $user->socid);
1565 }
1566 if ($filter) {
1567 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1568 // if not, by testSqlAndScriptInject() only.
1569 $sql .= " AND (" . $filter . ")";
1570 }
1571 if (!$user->hasRight('societe', 'client', 'voir')) {
1572 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1573 }
1574 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1575 $sql .= " AND s.status <> 0";
1576 }
1577 if (!empty($excludeids)) {
1578 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1579 }
1580 // Add where from hooks
1581 $parameters = array();
1582 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1583 $sql .= $hookmanager->resPrint;
1584 // Add criteria
1585 if ($filterkey && $filterkey != '') {
1586 $sql .= " AND (";
1587 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1588 // For natural search
1589 $search_crit = explode(' ', $filterkey);
1590 $i = 0;
1591 if (count($search_crit) > 1) {
1592 $sql .= "(";
1593 }
1594 foreach ($search_crit as $crit) {
1595 if ($i > 0) {
1596 $sql .= " AND ";
1597 }
1598 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1599 $i++;
1600 }
1601 if (count($search_crit) > 1) {
1602 $sql .= ")";
1603 }
1604 if (isModEnabled('barcode')) {
1605 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1606 }
1607 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1608 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1609 $sql .= ")";
1610 }
1611 $sql .= $this->db->order("nom", "ASC");
1612 $sql .= $this->db->plimit($limit, 0);
1613
1614 // Build output string
1615 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1616 $resql = $this->db->query($sql);
1617 if ($resql) {
1618 // Construct $out and $outarray
1619 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1620
1621 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1622 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1623 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1624 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1625 if ($showempty && !is_numeric($showempty)) {
1626 $textifempty = $langs->trans($showempty);
1627 } else {
1628 $textifempty .= $langs->trans("All");
1629 }
1630 }
1631 if ($showempty) {
1632 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1633 }
1634
1635 $companytemp = new Societe($this->db);
1636
1637 $num = $this->db->num_rows($resql);
1638 $i = 0;
1639 if ($num) {
1640 while ($i < $num) {
1641 $obj = $this->db->fetch_object($resql);
1642 $label = '';
1643 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1644 if (($obj->client) && (!empty($obj->code_client))) {
1645 $label = $obj->code_client . ' - ';
1646 }
1647 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1648 $label .= $obj->code_fournisseur . ' - ';
1649 }
1650 $label .= ' ' . $obj->name;
1651 } else {
1652 $label = $obj->name;
1653 }
1654
1655 if (!empty($obj->name_alias)) {
1656 $label .= ' (' . $obj->name_alias . ')';
1657 }
1658
1659 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1660 $label .= ' - '.$obj->tva_intra;
1661 }
1662
1663 $labelhtml = $label;
1664
1665 if ($showtype) {
1666 $companytemp->id = $obj->rowid;
1667 $companytemp->client = $obj->client;
1668 $companytemp->fournisseur = $obj->fournisseur;
1669 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1670 if ($tmptype) {
1671 $labelhtml .= ' ' . $tmptype;
1672 }
1673
1674 if ($obj->client || $obj->fournisseur) {
1675 $label .= ' (';
1676 }
1677 if ($obj->client == 1 || $obj->client == 3) {
1678 $label .= $langs->trans("Customer");
1679 }
1680 if ($obj->client == 2 || $obj->client == 3) {
1681 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1682 }
1683 if ($obj->fournisseur) {
1684 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1685 }
1686 if ($obj->client || $obj->fournisseur) {
1687 $label .= ')';
1688 }
1689 }
1690
1691 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1692 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1693 if (!empty($obj->country_code)) {
1694 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1695 }
1696 $label .= $s;
1697 $labelhtml .= $s;
1698 }
1699
1700 if (empty($outputmode)) {
1701 if (in_array($obj->rowid, $selected)) {
1702 $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>';
1703 } else {
1704 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1705 }
1706 } else {
1707 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1708 }
1709
1710 $i++;
1711 if (($i % 10) == 0) {
1712 $out .= "\n";
1713 }
1714 }
1715 }
1716 $out .= '</select>' . "\n";
1717 if (!$forcecombo) {
1718 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1719 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1720 }
1721 } else {
1722 dol_print_error($this->db);
1723 }
1724
1725 $this->result = array('nbofthirdparties' => $num);
1726
1727 if ($outputmode) {
1728 return $outarray;
1729 }
1730 return $out;
1731 }
1732
1733
1759 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 = '')
1760 {
1761 global $conf, $user, $langs, $hookmanager, $action;
1762
1763 $langs->load('companies');
1764
1765 if (empty($htmlid)) {
1766 $htmlid = $htmlname;
1767 }
1768 $num = 0;
1769 $out = '';
1770 $outarray = array();
1771
1772 if ($selected === '') {
1773 $selected = array();
1774 } elseif (!is_array($selected)) {
1775 $selected = array((int) $selected);
1776 }
1777
1778 // Clean $filter that may contains sql conditions so sql code
1779 if (function_exists('testSqlAndScriptInject')) {
1780 if (testSqlAndScriptInject($filter, 3) > 0) {
1781 $filter = '';
1782 return 'SQLInjectionTryDetected';
1783 }
1784 }
1785
1786 if ($filter != '') { // If a filter was provided
1787 if (preg_match('/[\‍(\‍)]/', $filter)) {
1788 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1789 $errormsg = '';
1790 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1791
1792 // Redo clean $filter that may contains sql conditions so sql code
1793 if (function_exists('testSqlAndScriptInject')) {
1794 if (testSqlAndScriptInject($filter, 3) > 0) {
1795 $filter = '';
1796 return 'SQLInjectionTryDetected';
1797 }
1798 }
1799 } else {
1800 // If not, we do nothing. We already know that there is no parenthesis
1801 // TODO Disallow this case in a future by returning an error here.
1802 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1803 }
1804 }
1805
1806 if (!is_object($hookmanager)) {
1807 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1808 $hookmanager = new HookManager($this->db);
1809 }
1810
1811 // We search third parties
1812 $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";
1813 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1814 $sql .= ", s.nom as company, s.town AS company_town";
1815 }
1816 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1817 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1818 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1819 }
1820 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1821 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1822 if ($socid > 0 || $socid == -1) {
1823 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1824 }
1825 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1826 $sql .= " AND sp.statut <> 0";
1827 }
1828 if ($filter) {
1829 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1830 // if not, by testSqlAndScriptInject() only.
1831 $sql .= " AND (" . $filter . ")";
1832 }
1833 // Add where from hooks
1834 $parameters = array();
1835 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1836 $sql .= $hookmanager->resPrint;
1837 $sql .= " ORDER BY sp.lastname ASC";
1838
1839 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1840 $resql = $this->db->query($sql);
1841 if ($resql) {
1842 $num = $this->db->num_rows($resql);
1843
1844 if ($htmlname != 'none' && !$options_only) {
1845 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1846 }
1847
1848 if ($showempty && !is_numeric($showempty)) {
1849 $textforempty = $showempty;
1850 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1851 } else {
1852 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1853 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1854 }
1855 if ($showempty == 2) {
1856 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1857 }
1858 }
1859
1860 $i = 0;
1861 if ($num) {
1862 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1863 $contactstatic = new Contact($this->db);
1864
1865 while ($i < $num) {
1866 $obj = $this->db->fetch_object($resql);
1867
1868 // Set email (or phones) and town extended infos
1869 $extendedInfos = '';
1870 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1871 $extendedInfos = array();
1872 $email = trim($obj->email);
1873 if (!empty($email)) {
1874 $extendedInfos[] = $email;
1875 } else {
1876 $phone = trim($obj->phone);
1877 $phone_perso = trim($obj->phone_perso);
1878 $phone_mobile = trim($obj->phone_mobile);
1879 if (!empty($phone)) {
1880 $extendedInfos[] = $phone;
1881 }
1882 if (!empty($phone_perso)) {
1883 $extendedInfos[] = $phone_perso;
1884 }
1885 if (!empty($phone_mobile)) {
1886 $extendedInfos[] = $phone_mobile;
1887 }
1888 }
1889 $contact_town = trim($obj->contact_town);
1890 $company_town = trim($obj->company_town);
1891 if (!empty($contact_town)) {
1892 $extendedInfos[] = $contact_town;
1893 } elseif (!empty($company_town)) {
1894 $extendedInfos[] = $company_town;
1895 }
1896 $extendedInfos = implode(' - ', $extendedInfos);
1897 if (!empty($extendedInfos)) {
1898 $extendedInfos = ' - ' . $extendedInfos;
1899 }
1900 }
1901
1902 $contactstatic->id = $obj->rowid;
1903 $contactstatic->lastname = $obj->lastname;
1904 $contactstatic->firstname = $obj->firstname;
1905 if ($obj->statut == 1) {
1906 $tmplabel = '';
1907 if ($htmlname != 'none') {
1908 $disabled = 0;
1909 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1910 $disabled = 1;
1911 }
1912 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1913 $disabled = 1;
1914 }
1915 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1916 $out .= '<option value="' . $obj->rowid . '"';
1917 if ($disabled) {
1918 $out .= ' disabled';
1919 }
1920 $out .= ' selected>';
1921
1922 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1923 if ($showfunction && $obj->poste) {
1924 $tmplabel .= ' (' . $obj->poste . ')';
1925 }
1926 if (($showsoc > 0) && $obj->company) {
1927 $tmplabel .= ' - (' . $obj->company . ')';
1928 }
1929
1930 $out .= $tmplabel;
1931 $out .= '</option>';
1932 } else {
1933 $out .= '<option value="' . $obj->rowid . '"';
1934 if ($disabled) {
1935 $out .= ' disabled';
1936 }
1937 $out .= '>';
1938
1939 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1940 if ($showfunction && $obj->poste) {
1941 $tmplabel .= ' (' . $obj->poste . ')';
1942 }
1943 if (($showsoc > 0) && $obj->company) {
1944 $tmplabel .= ' - (' . $obj->company . ')';
1945 }
1946
1947 $out .= $tmplabel;
1948 $out .= '</option>';
1949 }
1950 } else {
1951 if (in_array($obj->rowid, $selected)) {
1952 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1953 if ($showfunction && $obj->poste) {
1954 $tmplabel .= ' (' . $obj->poste . ')';
1955 }
1956 if (($showsoc > 0) && $obj->company) {
1957 $tmplabel .= ' - (' . $obj->company . ')';
1958 }
1959
1960 $out .= $tmplabel;
1961 }
1962 }
1963
1964 if ($tmplabel != '') {
1965 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1966 }
1967 }
1968 $i++;
1969 }
1970 } else {
1971 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1972 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1973 $out .= $labeltoshow;
1974 $out .= '</option>';
1975 }
1976
1977 $parameters = array(
1978 'socid' => $socid,
1979 'htmlname' => $htmlname,
1980 'resql' => $resql,
1981 'out' => &$out,
1982 'showfunction' => $showfunction,
1983 'showsoc' => $showsoc,
1984 );
1985
1986 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1987
1988 if ($htmlname != 'none' && !$options_only) {
1989 $out .= '</select>';
1990 }
1991
1992 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1993 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1994 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1995 }
1996
1997 $this->num = $num;
1998
1999 if ($options_only === 2) {
2000 // Return array of options
2001 return $outarray;
2002 } else {
2003 return $out;
2004 }
2005 } else {
2006 dol_print_error($this->db);
2007 return -1;
2008 }
2009 }
2010
2011
2012 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2013
2024 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2025 {
2026 // phpcs:enable
2027 global $langs, $conf;
2028
2029 // On recherche les remises
2030 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2031 $sql .= " re.description, re.fk_facture_source";
2032 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2033 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2034 $sql .= " AND re.entity = " . $conf->entity;
2035 if ($filter) {
2036 $sql .= " AND " . $filter;
2037 }
2038 $sql .= " ORDER BY re.description ASC";
2039
2040 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2041 $resql = $this->db->query($sql);
2042 if ($resql) {
2043 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2044 $num = $this->db->num_rows($resql);
2045
2046 $qualifiedlines = $num;
2047
2048 $i = 0;
2049 if ($num) {
2050 print '<option value="0">&nbsp;</option>';
2051 while ($i < $num) {
2052 $obj = $this->db->fetch_object($resql);
2053 $desc = dol_trunc($obj->description, 40);
2054 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2055 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2056 }
2057 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2058 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2059 }
2060 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2061 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2062 }
2063 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2064 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2065 }
2066
2067 $selectstring = '';
2068 if ($selected > 0 && $selected == $obj->rowid) {
2069 $selectstring = ' selected';
2070 }
2071
2072 $disabled = '';
2073 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2074 $qualifiedlines--;
2075 $disabled = ' disabled';
2076 }
2077
2078 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2079 $tmpfac = new Facture($this->db);
2080 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2081 $desc = $desc . ' - ' . $tmpfac->ref;
2082 }
2083 }
2084
2085 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2086 $i++;
2087 }
2088 }
2089 print '</select>';
2090 print ajax_combobox('select_' . $htmlname);
2091
2092 return $qualifiedlines;
2093 } else {
2094 dol_print_error($this->db);
2095 return -1;
2096 }
2097 }
2098
2099
2100 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2101
2117 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2118 {
2119 // phpcs:enable
2120 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2121 }
2122
2123 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2124
2149 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)
2150 {
2151 // phpcs:enable
2152 global $conf, $user, $langs, $hookmanager;
2153 global $action;
2154
2155 // If no preselected user defined, we take current user
2156 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2157 $selected = $user->id;
2158 }
2159
2160 if ($selected === '') {
2161 $selected = array();
2162 } elseif (!is_array($selected)) {
2163 $selected = array($selected);
2164 }
2165
2166 $excludeUsers = null;
2167 $includeUsers = null;
2168
2169 // Exclude some users
2170 if (is_array($exclude)) {
2171 $excludeUsers = implode(",", $exclude);
2172 }
2173 // Include some uses
2174 if (is_array($include)) {
2175 $includeUsers = implode(",", $include);
2176 } elseif ($include == 'hierarchy') {
2177 // Build list includeUsers to have only hierarchy
2178 $includeUsers = implode(",", $user->getAllChildIds(0));
2179 } elseif ($include == 'hierarchyme') {
2180 // Build list includeUsers to have only hierarchy and current user
2181 $includeUsers = implode(",", $user->getAllChildIds(1));
2182 }
2183
2184 $num = 0;
2185
2186 $out = '';
2187 $outarray = array();
2188 $outarray2 = array();
2189
2190 // Do we want to show the label of entity into the combo list ?
2191 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2192 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2193
2194 // Forge request to select users
2195 $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";
2196 if ($showlabelofentity) {
2197 $sql .= ", e.label";
2198 }
2199 $sql .= " FROM " . $this->db->prefix() . "user as u";
2200 if ($showlabelofentity) {
2201 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2202 }
2203 // Condition here should be the same than into societe->getSalesRepresentatives().
2204 if ($userissuperadminentityone && $force_entity != 'default') {
2205 if (!empty($force_entity)) {
2206 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2207 } else {
2208 $sql .= " WHERE u.entity IS NOT NULL";
2209 }
2210 } else {
2211 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2212 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2213 } else {
2214 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2215 }
2216 }
2217
2218 if (!empty($user->socid)) {
2219 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2220 }
2221 if (is_array($exclude) && $excludeUsers) {
2222 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2223 }
2224 if ($includeUsers) {
2225 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2226 }
2227 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2228 $sql .= " AND u.statut <> 0";
2229 }
2230 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2231 $sql .= " AND u.employee <> 0";
2232 }
2233 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2234 $sql .= " AND u.fk_soc IS NULL";
2235 }
2236 if (!empty($morefilter)) {
2237 $errormessage = '';
2238 $sql .= forgeSQLFromUniversalSearchCriteria($morefilter, $errormessage);
2239 if ($errormessage) {
2240 $this->errors[] = $errormessage;
2241 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
2242 if ($outputmode == 0) {
2243 return 'Error bad param $morefilter';
2244 } else {
2245 return array();
2246 }
2247 }
2248 }
2249
2250 //Add hook to filter on user (for example on usergroup define in custom modules)
2251 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2252 if (!empty($reshook)) {
2253 $sql .= $hookmanager->resPrint;
2254 }
2255
2256 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2257 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2258 } else {
2259 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2260 }
2261
2262 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2263
2264 $resql = $this->db->query($sql);
2265 if ($resql) {
2266 $num = $this->db->num_rows($resql);
2267 $i = 0;
2268 if ($num) {
2269 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2270 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2271 if ($show_empty && !$multiple) {
2272 $textforempty = ' ';
2273 if (!empty($conf->use_javascript_ajax)) {
2274 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2275 }
2276 if (!is_numeric($show_empty)) {
2277 $textforempty = $show_empty;
2278 }
2279 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2280
2281 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2282 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2283 'id' => ($show_empty < 0 ? $show_empty : -1),
2284 'label' => $textforempty,
2285 'labelhtml' => $textforempty,
2286 'color' => '',
2287 'picto' => ''
2288 );
2289 }
2290 if ($show_every) {
2291 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2292
2293 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2294 $outarray2[-2] = array(
2295 'id' => -2,
2296 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2297 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2298 'color' => '',
2299 'picto' => ''
2300 );
2301 }
2302
2303 $userstatic = new User($this->db);
2304
2305 while ($i < $num) {
2306 $obj = $this->db->fetch_object($resql);
2307
2308 $userstatic->id = $obj->rowid;
2309 $userstatic->lastname = $obj->lastname;
2310 $userstatic->firstname = $obj->firstname;
2311 $userstatic->photo = $obj->photo;
2312 $userstatic->status = $obj->status;
2313 $userstatic->entity = $obj->entity;
2314 $userstatic->admin = $obj->admin;
2315 $userstatic->gender = $obj->gender;
2316
2317 $disableline = '';
2318 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2319 $disableline = ($enableonlytext ? $enableonlytext : '1');
2320 }
2321
2322 $labeltoshow = '';
2323 $labeltoshowhtml = '';
2324
2325 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2326 $fullNameMode = 0;
2327 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2328 $fullNameMode = 1; //Firstname+lastname
2329 }
2330 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2331 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2332 if (empty($obj->firstname) && empty($obj->lastname)) {
2333 $labeltoshow .= $obj->login;
2334 $labeltoshowhtml .= $obj->login;
2335 }
2336
2337 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2338 $moreinfo = '';
2339 $moreinfohtml = '';
2340 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2341 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2342 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2343 $moreinfo .= $obj->login;
2344 $moreinfohtml .= $obj->login;
2345 }
2346 if ($showstatus >= 0) {
2347 if ($obj->status == 1 && $showstatus == 1) {
2348 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2349 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2350 }
2351 if ($obj->status == 0 && $showstatus == 1) {
2352 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2353 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2354 }
2355 }
2356 if ($showlabelofentity) {
2357 if (empty($obj->entity)) {
2358 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2359 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2360 } else {
2361 if ($obj->entity != $conf->entity) {
2362 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2363 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2364 }
2365 }
2366 }
2367 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2368 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2369 if (!empty($disableline) && $disableline != '1') {
2370 // Add text from $enableonlytext parameter
2371 $moreinfo .= ' - ' . $disableline;
2372 $moreinfohtml .= ' - ' . $disableline;
2373 }
2374 $labeltoshow .= $moreinfo;
2375 $labeltoshowhtml .= $moreinfohtml;
2376
2377 $out .= '<option value="' . $obj->rowid . '"';
2378 if (!empty($disableline)) {
2379 $out .= ' disabled';
2380 }
2381 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2382 $out .= ' selected';
2383 }
2384 $out .= ' data-html="';
2385
2386 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2387 if ($showstatus >= 0 && $obj->status == 0) {
2388 $outhtml .= '<strike class="opacitymediumxxx">';
2389 }
2390 $outhtml .= $labeltoshowhtml;
2391 if ($showstatus >= 0 && $obj->status == 0) {
2392 $outhtml .= '</strike>';
2393 }
2394 $labeltoshowhtml = $outhtml;
2395
2396 $out .= dol_escape_htmltag($outhtml);
2397 $out .= '">';
2398 $out .= $labeltoshow;
2399 $out .= '</option>';
2400
2401 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2402 $outarray2[$userstatic->id] = array(
2403 'id' => $userstatic->id,
2404 'label' => $labeltoshow,
2405 'labelhtml' => $labeltoshowhtml,
2406 'color' => '',
2407 'picto' => ''
2408 );
2409
2410 $i++;
2411 }
2412 } else {
2413 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2414 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2415 }
2416 $out .= '</select>';
2417
2418 if ($num && !$forcecombo) {
2419 // Enhance with select2
2420 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2421 $out .= ajax_combobox($htmlname);
2422 }
2423 } else {
2424 dol_print_error($this->db);
2425 }
2426
2427 $this->num = $num;
2428
2429 if ($outputmode == 2) {
2430 return $outarray2;
2431 } elseif ($outputmode) {
2432 return $outarray;
2433 }
2434
2435 return $out;
2436 }
2437
2438
2439 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2463 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)
2464 {
2465 // phpcs:enable
2466 global $langs, $user;
2467
2468 $userstatic = new User($this->db);
2469 $out = '';
2470
2471 if (!empty($_SESSION['assignedtouser'])) {
2472 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2473 if (!is_array($assignedtouser)) {
2474 $assignedtouser = array();
2475 }
2476 } else {
2477 $assignedtouser = array();
2478 }
2479 $nbassignetouser = count($assignedtouser);
2480
2481 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2482 if ($nbassignetouser) {
2483 $out .= '<ul class="attendees">';
2484 }
2485 $i = 0;
2486 $ownerid = 0;
2487 foreach ($assignedtouser as $key => $value) {
2488 if ($value['id'] == $ownerid) {
2489 continue;
2490 }
2491
2492 $out .= '<li>';
2493 $userstatic->fetch($value['id']);
2494 $out .= $userstatic->getNomUrl(-1);
2495 if ($i == 0) {
2496 $ownerid = $value['id'];
2497 $out .= ' (' . $langs->trans("Owner") . ')';
2498 }
2499 // Add picto to delete owner/assignee
2500 if ($nbassignetouser > 1 && $action != 'view') {
2501 $canremoveassignee = 1;
2502 if ($i == 0) {
2503 // We are on the owner of the event
2504 if (!$canremoveowner) {
2505 $canremoveassignee = 0;
2506 }
2507 if (!$user->hasRight('agenda', 'allactions', 'create')) {
2508 $canremoveassignee = 0; // Can't remove the owner
2509 }
2510 } else {
2511 // We are not on the owner of the event but on a secondary assignee
2512 }
2513 if ($canremoveassignee) {
2514 // If user has all permission, he should be ableto remove a assignee.
2515 // If user has not all permission, he can onlyremove assignee of other (he can't remove itself)
2516 $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 . '">';
2517 }
2518 }
2519 // Show my availability
2520 if ($showproperties) {
2521 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2522 $out .= '<div class="myavailability inline-block">';
2523 $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>';
2524 $out .= '</div>';
2525 }
2526 }
2527 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2528 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2529
2530 $out .= '</li>';
2531 $i++;
2532 }
2533 if ($nbassignetouser) {
2534 $out .= '</ul>';
2535 }
2536
2537 // Method with no ajax
2538 if ($action != 'view') {
2539 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2540 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2541 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2542 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2543 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2544 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2545 $out .= '});';
2546 $out .= '})</script>';
2547 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2548 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2549 $out .= '<br>';
2550 }
2551
2552 return $out;
2553 }
2554
2555 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2575 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())
2576 {
2577 // phpcs:enable
2578 global $langs;
2579
2580 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2581 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2582 $formresources = new FormResource($this->db);
2583 $resourcestatic = new Dolresource($this->db);
2584
2585 $out = '';
2586 if (!empty($_SESSION['assignedtoresource'])) {
2587 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2588 if (!is_array($assignedtoresource)) {
2589 $assignedtoresource = array();
2590 }
2591 } else {
2592 $assignedtoresource = array();
2593 }
2594 $nbassignetoresource = count($assignedtoresource);
2595
2596 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2597 if ($nbassignetoresource) {
2598 $out .= '<ul class="attendees">';
2599 }
2600 $i = 0;
2601
2602 foreach ($assignedtoresource as $key => $value) {
2603 $out .= '<li>';
2604 $resourcestatic->fetch($value['id']);
2605 $out .= $resourcestatic->getNomUrl(-1);
2606 if ($nbassignetoresource >= 1 && $action != 'view') {
2607 $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 . '">';
2608 }
2609 // Show my availability
2610 if ($showproperties) {
2611 if (is_array($listofresourceid) && count($listofresourceid)) {
2612 $out .= '<div class="myavailability inline-block">';
2613 $out .= '<span class="hideonsmartphone">&nbsp;-&nbsp;<span class="opacitymedium">' . $langs->trans("Availability") . ':</span> </span><input id="transparencyresource" class="paddingrightonly" ' . ($action == 'view' ? 'disabled' : '') . ' type="checkbox" name="transparency"' . ($listofresourceid[$value['id']]['transparency'] ? ' checked' : '') . '><label for="transparency">' . $langs->trans("Busy") . '</label>';
2614 $out .= '</div>';
2615 }
2616 }
2617 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2618 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2619
2620 $out .= '</li>';
2621 $i++;
2622 }
2623 if ($nbassignetoresource) {
2624 $out .= '</ul>';
2625 }
2626
2627 // Method with no ajax
2628 if ($action != 'view') {
2629 $out .= '<input type="hidden" class="removedassignedresourcehidden" name="removedassignedresource" value="">';
2630 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2631 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2632 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2633 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2634 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2635 $out .= '});';
2636 $out .= '})</script>';
2637
2638 $events = array();
2639 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2640 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2641 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2642 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2643 $out .= '<br>';
2644 }
2645
2646 return $out;
2647 }
2648
2649 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2650
2680 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)
2681 {
2682 // phpcs:enable
2683 global $langs, $conf;
2684
2685 $out = '';
2686
2687 // check parameters
2688 $price_level = (!empty($price_level) ? $price_level : 0);
2689 if (is_null($ajaxoptions)) {
2690 $ajaxoptions = array();
2691 }
2692
2693 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2694 if (isModEnabled("product") && !isModEnabled('service')) {
2695 $filtertype = '0';
2696 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2697 $filtertype = '1';
2698 }
2699 }
2700
2701 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2702 $placeholder = (is_numeric($showempty) ? '' : 'placeholder="'.dolPrintHTML($showempty).'"');
2703
2704 if ($selected && empty($selected_input_value)) {
2705 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2706 $producttmpselect = new Product($this->db);
2707 $producttmpselect->fetch($selected);
2708 $selected_input_value = $producttmpselect->ref;
2709 unset($producttmpselect);
2710 }
2711 // handle case where product or service module is disabled + no filter specified
2712 if ($filtertype == '') {
2713 if (!isModEnabled('product')) { // when product module is disabled, show services only
2714 $filtertype = 1;
2715 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2716 $filtertype = 0;
2717 }
2718 }
2719 // mode=1 means customers products
2720 $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;
2721 if ((int) $warehouseId > 0) {
2722 $urloption .= '&warehouseid=' . (int) $warehouseId;
2723 }
2724
2725 $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);
2726
2727 if (isModEnabled('variants') && is_array($selected_combinations)) {
2728 // Code to automatically insert with javascript the select of attributes under the select of product
2729 // when a parent of variant has been selected.
2730 $out .= '
2731 <!-- script to auto show attributes select tags if a variant was selected -->
2732 <script nonce="' . getNonce() . '">
2733 // auto show attributes fields
2734 selected = ' . json_encode($selected_combinations) . ';
2735 combvalues = {};
2736
2737 jQuery(document).ready(function () {
2738
2739 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2740 if (jQuery(this).val() == \'free\') {
2741 jQuery(\'div#attributes_box\').empty();
2742 }
2743 });
2744
2745 jQuery("input#' . $htmlname . '").change(function () {
2746
2747 if (!jQuery(this).val()) {
2748 jQuery(\'div#attributes_box\').empty();
2749 return;
2750 }
2751
2752 console.log("A change has started. We get variants fields to inject html select");
2753
2754 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2755 id: jQuery(this).val()
2756 }, function (data) {
2757 jQuery(\'div#attributes_box\').empty();
2758
2759 jQuery.each(data, function (key, val) {
2760
2761 combvalues[val.id] = val.values;
2762
2763 var span = jQuery(document.createElement(\'div\')).css({
2764 \'display\': \'table-row\'
2765 });
2766
2767 span.append(
2768 jQuery(document.createElement(\'div\')).text(val.label).css({
2769 \'font-weight\': \'bold\',
2770 \'display\': \'table-cell\'
2771 })
2772 );
2773
2774 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2775 \'margin-left\': \'15px\',
2776 \'white-space\': \'pre\'
2777 }).append(
2778 jQuery(document.createElement(\'option\')).val(\'\')
2779 );
2780
2781 jQuery.each(combvalues[val.id], function (key, val) {
2782 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2783
2784 if (selected[val.fk_product_attribute] == val.id) {
2785 tag.attr(\'selected\', \'selected\');
2786 }
2787
2788 html.append(tag);
2789 });
2790
2791 span.append(html);
2792 jQuery(\'div#attributes_box\').append(span);
2793 });
2794 })
2795 });
2796
2797 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2798 });
2799 </script>
2800 ';
2801 }
2802
2803 if (empty($hidelabel)) {
2804 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2805 } elseif ($hidelabel > 1) {
2806 $placeholder = ' placeholder="' . dolPrintHTMLForAttribute($langs->trans("RefOrLabel")) . '"';
2807 if ($hidelabel == 2) {
2808 $out .= img_picto($langs->trans("Search"), 'search');
2809 }
2810 }
2811
2812 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2813 if ($hidelabel == 3) {
2814 $out .= img_picto($langs->trans("Search"), 'search');
2815 }
2816 } else {
2817 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase, $warehouseId);
2818 }
2819
2820 if (empty($nooutput)) {
2821 print $out;
2822 } else {
2823 return $out;
2824 }
2825 }
2826
2827 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2828
2844 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2845 {
2846 // phpcs:enable
2847 global $db;
2848
2849 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2850
2851 $error = 0;
2852 $out = '';
2853
2854 if (!$forcecombo) {
2855 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2856 $events = array();
2857 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2858 }
2859
2860 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2861
2862 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2863 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2864 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2865 if (!empty($status)) {
2866 $sql .= ' AND status = ' . (int) $status;
2867 }
2868 if (!empty($type)) {
2869 $sql .= ' AND bomtype = ' . (int) $type;
2870 }
2871 if (!empty($TProducts)) {
2872 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2873 }
2874 if (!empty($limit)) {
2875 $sql .= ' LIMIT ' . (int) $limit;
2876 }
2877 $resql = $db->query($sql);
2878 if ($resql) {
2879 if ($showempty) {
2880 $out .= '<option value="-1"';
2881 if (empty($selected)) {
2882 $out .= ' selected';
2883 }
2884 $out .= '>&nbsp;</option>';
2885 }
2886 while ($obj = $db->fetch_object($resql)) {
2887 $product = new Product($db);
2888 $res = $product->fetch($obj->fk_product);
2889 $out .= '<option value="' . $obj->rowid . '"';
2890 if ($obj->rowid == $selected) {
2891 $out .= 'selected';
2892 }
2893 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2894 }
2895 } else {
2896 $error++;
2897 dol_print_error($db);
2898 }
2899 $out .= '</select>';
2900 if (empty($nooutput)) {
2901 print $out;
2902 } else {
2903 return $out;
2904 }
2905 }
2906
2907 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2908
2935 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)
2936 {
2937 // phpcs:enable
2938 global $langs;
2939 global $hookmanager;
2940
2941 $out = '';
2942 $outarray = array();
2943
2944 // Units
2945 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2946 $langs->load('other');
2947 }
2948
2949 $warehouseStatusArray = array();
2950 if (!empty($warehouseStatus)) {
2951 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2952 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2953 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2954 }
2955 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2956 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2957 }
2958 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2959 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2960 }
2961 }
2962
2963 $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";
2964 if (count($warehouseStatusArray)) {
2965 $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
2966 } else {
2967 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2968 }
2969
2970 $sql = "SELECT ";
2971
2972 // Add select from hooks
2973 $parameters = array();
2974 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2975 if (empty($reshook)) {
2976 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2977 } else {
2978 $sql .= $hookmanager->resPrint;
2979 }
2980
2981 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2982 //Product category
2983 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2984 FROM " . $this->db->prefix() . "categorie_product
2985 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2986 LIMIT 1
2987 ) AS categorie_product_id ";
2988 }
2989
2990 //Price by customer
2991 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
2992 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2993 $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';
2994 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2995 }
2996 // Units
2997 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2998 $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";
2999 $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';
3000 }
3001
3002 // Multilang : we add translation
3003 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3004 $sql .= ", pl.label as label_translated";
3005 $sql .= ", pl.description as description_translated";
3006 $selectFields .= ", label_translated";
3007 $selectFields .= ", description_translated";
3008 }
3009 // Price by quantity
3010 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3011 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
3012 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3013 $sql .= " AND price_level = " . ((int) $price_level);
3014 }
3015 $sql .= " ORDER BY date_price";
3016 $sql .= " DESC LIMIT 1) as price_rowid";
3017 $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
3018 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
3019 $sql .= " AND price_level = " . ((int) $price_level);
3020 }
3021 $sql .= " ORDER BY date_price";
3022 $sql .= " DESC LIMIT 1) as price_by_qty";
3023 $selectFields .= ", price_rowid, price_by_qty";
3024 }
3025
3026 $sql .= " FROM ".$this->db->prefix()."product as p";
3027
3028 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
3029 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
3030 }
3031
3032 // Add from (left join) from hooks
3033 $parameters = array();
3034 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
3035 $sql .= $hookmanager->resPrint;
3036
3037 if (count($warehouseStatusArray)) {
3038 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
3039 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
3040 $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.
3041 }
3042
3043 // include search in supplier ref
3044 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3045 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3046 }
3047
3048 //Price by customer
3049 if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) {
3050 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3051 }
3052 // Units
3053 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3054 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3055 }
3056 // Multilang : we add translation
3057 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3058 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3059 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3060 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3061 $soc = new Societe($this->db);
3062 $result = $soc->fetch($socid);
3063 if ($result > 0 && !empty($soc->default_lang)) {
3064 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3065 } else {
3066 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3067 }
3068 } else {
3069 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3070 }
3071 }
3072
3073 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3074 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3075 }
3076
3077 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3078
3079 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3080 $sql .= " AND pac.rowid IS NULL";
3081 }
3082
3083 if ($finished == 0) {
3084 $sql .= " AND p.finished = " . ((int) $finished);
3085 } elseif ($finished == 1) {
3086 $sql .= " AND p.finished = ".((int) $finished);
3087 }
3088 if ($status >= 0) {
3089 $sql .= " AND p.tosell = ".((int) $status);
3090 }
3091 if ($status_purchase >= 0) {
3092 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3093 }
3094 // Filter by product type
3095 if (strval($filtertype) != '') {
3096 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3097 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3098 $sql .= " AND p.fk_product_type = 1";
3099 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3100 $sql .= " AND p.fk_product_type = 0";
3101 }
3102
3103 if ((int) $warehouseId > 0) {
3104 $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)";
3105 }
3106
3107 // Add where from hooks
3108 $parameters = array();
3109 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3110 $sql .= $hookmanager->resPrint;
3111 // Add criteria on ref/label
3112 if ($filterkey != '') {
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 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3139 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3140 }
3141 $sql .= ")";
3142 $i++;
3143 }
3144 if (count($search_crit) > 1) {
3145 $sql .= ")";
3146 }
3147 if (isModEnabled('barcode')) {
3148 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3149 }
3150 $sql .= ')';
3151 }
3152 if (count($warehouseStatusArray)) {
3153 $sql .= " GROUP BY " . $selectFields;
3154 }
3155
3156 //Sort by category
3157 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3158 $sql .= " ORDER BY categorie_product_id ";
3159 //ASC OR DESC order
3160 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3161 } else {
3162 $sql .= $this->db->order("p.ref");
3163 }
3164
3165 $sql .= $this->db->plimit($limit, 0);
3166
3167 // Build output string
3168 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3169 $result = $this->db->query($sql);
3170 if ($result) {
3171 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3172 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3173 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3174
3175 $num = $this->db->num_rows($result);
3176
3177 $events = array();
3178
3179 if (!$forcecombo) {
3180 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3181 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3182 }
3183
3184 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3185
3186 $textifempty = '';
3187 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3188 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3189 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3190 if ($showempty && !is_numeric($showempty)) {
3191 $textifempty = $langs->trans($showempty);
3192 } else {
3193 $textifempty .= $langs->trans("All");
3194 }
3195 } else {
3196 if ($showempty && !is_numeric($showempty)) {
3197 $textifempty = $langs->trans($showempty);
3198 }
3199 }
3200 if ($showempty) {
3201 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3202 }
3203
3204 $i = 0;
3205 while ($num && $i < $num) {
3206 $opt = '';
3207 $optJson = array();
3208 $objp = $this->db->fetch_object($result);
3209
3210 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
3211 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3212 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3213 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3214 $sql .= " ORDER BY quantity ASC";
3215
3216 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3217 $result2 = $this->db->query($sql);
3218 if ($result2) {
3219 $nb_prices = $this->db->num_rows($result2);
3220 $j = 0;
3221 while ($nb_prices && $j < $nb_prices) {
3222 $objp2 = $this->db->fetch_object($result2);
3223
3224 $objp->price_by_qty_rowid = $objp2->rowid;
3225 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3226 $objp->price_by_qty_quantity = $objp2->quantity;
3227 $objp->price_by_qty_unitprice = $objp2->unitprice;
3228 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3229 // For backward compatibility
3230 $objp->quantity = $objp2->quantity;
3231 $objp->price = $objp2->price;
3232 $objp->unitprice = $objp2->unitprice;
3233 $objp->remise_percent = $objp2->remise_percent;
3234
3235 //$objp->tva_tx is not overwritten by $objp2 value
3236 //$objp->default_vat_code is not overwritten by $objp2 value
3237
3238 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3239 '@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';
3240 $j++;
3241
3242 // Add new entry
3243 // "key" value of json key array is used by jQuery automatically as selected value
3244 // "label" value of json key array is used by jQuery automatically as text for combo box
3245 $out .= $opt;
3246 array_push($outarray, $optJson);
3247 }
3248 }
3249 } else {
3250 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3251 $price_product = new Product($this->db);
3252 $price_product->fetch($objp->rowid, '', '', 1);
3253
3254 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3255 $priceparser = new PriceParser($this->db);
3256 $price_result = $priceparser->parseProduct($price_product);
3257 if ($price_result >= 0) {
3258 $objp->price = $price_result;
3259 $objp->unitprice = $price_result;
3260 //Calculate the VAT
3261 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3262 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3263 }
3264 }
3265 if (getDolGlobalInt('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES') && !empty($objp->custprice)) {
3266 $price_level = '';
3267 }
3268 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3269 // Add new entry
3270 // "key" value of json key array is used by jQuery automatically as selected value
3271 // "label" value of json key array is used by jQuery automatically as text for combo box
3272 $out .= $opt;
3273 array_push($outarray, $optJson);
3274 }
3275
3276 $i++;
3277 }
3278
3279 $out .= '</select>';
3280
3281 $this->db->free($result);
3282
3283 if (empty($outputmode)) {
3284 return $out;
3285 }
3286
3287 return $outarray;
3288 } else {
3289 dol_print_error($this->db);
3290 }
3291
3292 return '';
3293 }
3294
3310 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3311 {
3312 global $langs, $conf, $user;
3313 global $hookmanager;
3314
3315 $outkey = '';
3316 $outval = '';
3317 $outref = '';
3318 $outlabel = '';
3319 $outlabel_translated = '';
3320 $outdesc = '';
3321 $outdesc_translated = '';
3322 $outbarcode = '';
3323 $outorigin = '';
3324 $outtype = '';
3325 $outprice_ht = '';
3326 $outprice_ttc = '';
3327 $outpricebasetype = '';
3328 $outtva_tx = '';
3329 $outdefault_vat_code = '';
3330 $outqty = 1;
3331 $outdiscount = 0;
3332
3333 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3334
3335 $label = $objp->label;
3336 if (!empty($objp->label_translated)) {
3337 $label = $objp->label_translated;
3338 }
3339 if (!empty($filterkey) && $filterkey != '') {
3340 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3341 }
3342
3343 $outkey = $objp->rowid;
3344 $outref = $objp->ref;
3345 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3346 $outlabel = $objp->label;
3347 $outdesc = $objp->description;
3348 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3349 $outlabel_translated = $objp->label_translated;
3350 $outdesc_translated = $objp->description_translated;
3351 }
3352 $outbarcode = $objp->barcode;
3353 $outorigin = $objp->fk_country;
3354 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3355
3356 $outtype = $objp->fk_product_type;
3357 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3358 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3359
3360 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3361 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3362 }
3363
3364 // Units
3365 $outvalUnits = '';
3366 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3367 if (!empty($objp->unit_short)) {
3368 $outvalUnits .= ' - ' . $objp->unit_short;
3369 }
3370 }
3371 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3372 if (!empty($objp->weight) && $objp->weight_units !== null) {
3373 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3374 $outvalUnits .= ' - ' . $unitToShow;
3375 }
3376 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3377 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3378 $outvalUnits .= ' - ' . $unitToShow;
3379 }
3380 if (!empty($objp->surface) && $objp->surface_units !== null) {
3381 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3382 $outvalUnits .= ' - ' . $unitToShow;
3383 }
3384 if (!empty($objp->volume) && $objp->volume_units !== null) {
3385 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3386 $outvalUnits .= ' - ' . $unitToShow;
3387 }
3388 }
3389 if ($outdurationvalue && $outdurationunit) {
3390 $da = array(
3391 'h' => $langs->trans('Hour'),
3392 'd' => $langs->trans('Day'),
3393 'w' => $langs->trans('Week'),
3394 'm' => $langs->trans('Month'),
3395 'y' => $langs->trans('Year')
3396 );
3397 if (isset($da[$outdurationunit])) {
3398 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3399 }
3400 }
3401
3402 // Set stocktag (stock too low or not or unknown)
3403 $stocktag = 0;
3404 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3405 if ($user->hasRight('stock', 'lire')) {
3406 if ($objp->stock > 0) {
3407 $stocktag = 1;
3408 } elseif ($objp->stock <= 0) {
3409 $stocktag = -1;
3410 }
3411 }
3412 }
3413
3414 // Set $labeltoshow
3415 $labeltoshow = '';
3416 $labeltoshow .= $objp->ref;
3417 if (!empty($objp->custref)) {
3418 $labeltoshow .= ' (' . $objp->custref . ')';
3419 }
3420 if ($outbarcode) {
3421 $labeltoshow .= ' (' . $outbarcode . ')';
3422 }
3423 $labeltoshow .= ' - ' . dol_trunc($label, $maxlengtharticle);
3424 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3425 $labeltoshow .= ' (' . getCountry($outorigin, '1') . ')';
3426 }
3427
3428 // Set $labltoshowhtml
3429 $labeltoshowhtml = '';
3430 $labeltoshowhtml .= $objp->ref;
3431 if (!empty($objp->custref)) {
3432 $labeltoshowhtml .= ' (' . $objp->custref . ')';
3433 }
3434 if (!empty($filterkey) && $filterkey != '') {
3435 $labeltoshowhtml = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $labeltoshowhtml, 1);
3436 }
3437 if ($outbarcode) {
3438 $labeltoshowhtml .= ' (' . $outbarcode . ')';
3439 }
3440 $labeltoshowhtml .= ' - ' . dol_trunc($label, $maxlengtharticle);
3441 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3442 $labeltoshowhtml .= ' (' . getCountry($outorigin, '1') . ')';
3443 }
3444
3445 // Stock
3446 $labeltoshowstock = '';
3447 $labeltoshowhtmlstock = '';
3448 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3449 if ($user->hasRight('stock', 'lire')) {
3450 $labeltoshowstock .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3451
3452 if ($objp->stock > 0) {
3453 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_ok">';
3454 } elseif ($objp->stock <= 0) {
3455 $labeltoshowhtmlstock .= ' - <span class="product_line_stock_too_low">';
3456 }
3457 $labeltoshowhtmlstock .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3458 $labeltoshowhtmlstock .= '</span>';
3459
3460 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3461 $langs->load("stocks");
3462
3463 $tmpproduct = new Product($this->db);
3464 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3465 $tmpproduct->load_virtual_stock();
3466 $virtualstock = $tmpproduct->stock_theorique;
3467
3468 $labeltoshowstock .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3469
3470 $labeltoshowhtmlstock .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3471 if ($virtualstock > 0) {
3472 $labeltoshowhtmlstock .= '<span class="product_line_stock_ok">';
3473 } elseif ($virtualstock <= 0) {
3474 $labeltoshowhtmlstock .= '<span class="product_line_stock_too_low">';
3475 }
3476 $labeltoshowhtmlstock .= $virtualstock;
3477 $labeltoshowhtmlstock .= '</span>';
3478
3479 unset($tmpproduct);
3480 }
3481 }
3482 }
3483
3484 // Price
3485 $found = 0;
3486 $labeltoshowprice = '';
3487 $labeltoshowhtmlprice = '';
3488 // If we need a particular price level (from 1 to n)
3489 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3490 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3491 $sql .= " FROM " . $this->db->prefix() . "product_price";
3492 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3493 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3494 $sql .= " AND price_level = " . ((int) $price_level);
3495 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3496 $sql .= " LIMIT 1";
3497
3498 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3499 $result2 = $this->db->query($sql);
3500 if ($result2) {
3501 $objp2 = $this->db->fetch_object($result2);
3502 if ($objp2) {
3503 $found = 1;
3504 if ($objp2->price_base_type == 'HT') {
3505 $labeltoshowprice .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3506 $labeltoshowhtmlprice .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3507 } else {
3508 $labeltoshowprice .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3509 $labeltoshowhtmlprice .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3510 }
3511 $outprice_ht = price($objp2->price);
3512 $outprice_ttc = price($objp2->price_ttc);
3513 $outpricebasetype = $objp2->price_base_type;
3514 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3515 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3516 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3517 } else {
3518 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3519 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3520 }
3521 }
3522 } else {
3523 dol_print_error($this->db);
3524 }
3525 }
3526
3527 // Price by quantity
3528 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3529 $found = 1;
3530 $outqty = $objp->quantity;
3531 $outdiscount = $objp->remise_percent;
3532 if ($objp->quantity == 1) {
3533 $labeltoshowprice .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3534 $labeltoshowhtmlprice .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3535 $labeltoshowprice .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3536 $labeltoshowhtmlprice .= $langs->transnoentities("Unit");
3537 } else {
3538 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3539 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3540 $labeltoshowprice .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3541 $labeltoshowhtmlprice .= $langs->transnoentities("Units");
3542 }
3543
3544 $outprice_ht = price($objp->unitprice);
3545 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3546 $outpricebasetype = $objp->price_base_type;
3547 $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
3548 $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
3549 }
3550 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3551 $labeltoshowprice .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3552 $labeltoshowhtmlprice .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3553 }
3554 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3555 $labeltoshowprice .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3556 $labeltoshowhtmlprice .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3557 }
3558
3559 // Price by customer
3560 if (empty($hidepriceinlabel) && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES'))) {
3561 if (!empty($objp->idprodcustprice)) {
3562 $found = 1;
3563
3564 if ($objp->custprice_base_type == 'HT') {
3565 $labeltoshowprice .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3566 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3567 } else {
3568 $labeltoshowprice .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3569 $labeltoshowhtmlprice .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3570 }
3571
3572 $outprice_ht = price($objp->custprice);
3573 $outprice_ttc = price($objp->custprice_ttc);
3574 $outpricebasetype = $objp->custprice_base_type;
3575 $outtva_tx = $objp->custtva_tx;
3576 $outdefault_vat_code = $objp->custdefault_vat_code;
3577 }
3578 }
3579
3580 // If level no defined or multiprice not found, we used the default price
3581 if (empty($hidepriceinlabel) && !$found) {
3582 if ($objp->price_base_type == 'HT') {
3583 $labeltoshowprice .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3584 $labeltoshowhtmlprice .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3585 } else {
3586 $labeltoshowprice .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3587 $labeltoshowhtmlprice .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3588 }
3589 $outprice_ht = price($objp->price);
3590 $outprice_ttc = price($objp->price_ttc);
3591 $outpricebasetype = $objp->price_base_type;
3592 $outtva_tx = $objp->tva_tx;
3593 $outdefault_vat_code = $objp->default_vat_code;
3594 }
3595
3596 // Build options
3597 $opt = '<option value="' . $objp->rowid . '"';
3598 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3599 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3600 $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 . '"';
3601 }
3602 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3603 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3604 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3605 }
3606
3607 if ($stocktag == 1) {
3608 $opt .= ' class="product_line_stock_ok" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3609 //$opt .= ' class="product_line_stock_ok"';
3610 }
3611 if ($stocktag == -1) {
3612 $opt .= ' class="product_line_stock_too_low" data-html="'.$labeltoshowhtml.$outvalUnits.$labeltoshowhtmlprice.dolPrintHTMLForAttribute($labeltoshowhtmlstock).'"';
3613 //$opt .= ' class="product_line_stock_too_low"';
3614 }
3615
3616 $opt .= '>';
3617
3618 // Ref, barcode, country
3619 $opt .= $labeltoshow;
3620 $outval .= $labeltoshowhtml;
3621
3622 // Units
3623 $opt .= $outvalUnits;
3624 $outval .= $outvalUnits;
3625
3626 // Price
3627 $opt .= $labeltoshowprice;
3628 $outval .= $labeltoshowhtmlprice;
3629
3630 // Stock
3631 $opt .= $labeltoshowstock;
3632 $outval .= $labeltoshowhtmlstock;
3633
3634
3635 $parameters = array('objp' => $objp);
3636 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3637 if (empty($reshook)) {
3638 $opt .= $hookmanager->resPrint;
3639 } else {
3640 $opt = $hookmanager->resPrint;
3641 }
3642
3643 $opt .= "</option>\n";
3644 $optJson = array(
3645 'key' => $outkey,
3646 'value' => $outref,
3647 'label' => $outval,
3648 'label2' => $outlabel,
3649 'desc' => $outdesc,
3650 'type' => $outtype,
3651 'price_ht' => price2num($outprice_ht),
3652 'price_ttc' => price2num($outprice_ttc),
3653 'price_ht_locale' => price(price2num($outprice_ht)),
3654 'price_ttc_locale' => price(price2num($outprice_ttc)),
3655 'pricebasetype' => $outpricebasetype,
3656 'tva_tx' => $outtva_tx,
3657 'default_vat_code' => $outdefault_vat_code,
3658 'qty' => $outqty,
3659 'discount' => $outdiscount,
3660 'duration_value' => $outdurationvalue,
3661 'duration_unit' => $outdurationunit,
3662 'pbq' => $outpbq,
3663 'labeltrans' => $outlabel_translated,
3664 'desctrans' => $outdesc_translated,
3665 'ref_customer' => $outrefcust
3666 );
3667 }
3668
3669 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3670
3686 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3687 {
3688 // phpcs:enable
3689 global $langs, $conf;
3690 global $price_level, $status, $finished;
3691
3692 if (!isset($status)) {
3693 $status = 1;
3694 }
3695
3696 $selected_input_value = '';
3697 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3698 if ($selected > 0) {
3699 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3700 $producttmpselect = new Product($this->db);
3701 $producttmpselect->fetch($selected);
3702 $selected_input_value = $producttmpselect->ref;
3703 unset($producttmpselect);
3704 }
3705
3706 // mode=2 means suppliers products
3707 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3708 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalInt('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3709
3710 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3711 } else {
3712 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3713 }
3714 }
3715
3716 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3717
3736 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 = '')
3737 {
3738 // phpcs:enable
3739 global $langs, $conf, $user;
3740 global $hookmanager;
3741
3742 $out = '';
3743 $outarray = array();
3744
3745 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3746
3747 $langs->load('stocks');
3748 // Units
3749 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3750 $langs->load('other');
3751 }
3752
3753 $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,";
3754 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3755 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3756 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3757 $sql .= ", pfp.supplier_reputation";
3758 // if we use supplier description of the products
3759 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3760 $sql .= ", pfp.desc_fourn as description";
3761 } else {
3762 $sql .= ", p.description";
3763 }
3764 // Units
3765 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3766 $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";
3767 }
3768 $sql .= " FROM " . $this->db->prefix() . "product as p";
3769 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3770 if ($socid > 0) {
3771 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3772 }
3773 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3774 // Units
3775 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3776 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3777 }
3778 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3779 if ($statut != -1) {
3780 $sql .= " AND p.tobuy = " . ((int) $statut);
3781 }
3782 if (strval($filtertype) != '') {
3783 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3784 }
3785 if (!empty($filtre)) {
3786 $sql .= " " . $filtre;
3787 }
3788 // Add where from hooks
3789 $parameters = array();
3790 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3791 $sql .= $hookmanager->resPrint;
3792 // Add criteria on ref/label
3793 if ($filterkey != '') {
3794 $sql .= ' AND (';
3795 $prefix = getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '' : '%'; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3796 // For natural search
3797 $search_crit = explode(' ', $filterkey);
3798 $i = 0;
3799 if (count($search_crit) > 1) {
3800 $sql .= "(";
3801 }
3802 foreach ($search_crit as $crit) {
3803 if ($i > 0) {
3804 $sql .= " AND ";
3805 }
3806 $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) . "%'";
3807 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3808 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3809 }
3810 $sql .= ")";
3811 $i++;
3812 }
3813 if (count($search_crit) > 1) {
3814 $sql .= ")";
3815 }
3816 if (isModEnabled('barcode')) {
3817 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3818 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3819 }
3820 $sql .= ')';
3821 }
3822 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3823 $sql .= $this->db->plimit($limit, 0);
3824
3825 // Build output string
3826
3827 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3828 $result = $this->db->query($sql);
3829 if ($result) {
3830 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3831 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3832
3833 $num = $this->db->num_rows($result);
3834
3835 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3836 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3837 if (!$selected) {
3838 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3839 } else {
3840 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3841 }
3842
3843 $i = 0;
3844 while ($i < $num) {
3845 $objp = $this->db->fetch_object($result);
3846
3847 if (is_null($objp->idprodfournprice)) {
3848 // There is no supplier price found, we will use the vat rate for sale
3849 $objp->tva_tx = $objp->tva_tx_sale;
3850 $objp->default_vat_code = $objp->default_vat_code_sale;
3851 }
3852
3853 $outkey = $objp->idprodfournprice; // id in table of price
3854 if (!$outkey && $alsoproductwithnosupplierprice) {
3855 $outkey = 'idprod_' . $objp->rowid; // id of product
3856 }
3857
3858 $outref = $objp->ref;
3859 $outbarcode = $objp->barcode;
3860 $outqty = 1;
3861 $outdiscount = 0;
3862 $outtype = $objp->fk_product_type;
3863 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3864 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3865
3866 // Units
3867 $outvalUnits = '';
3868 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3869 if (!empty($objp->unit_short)) {
3870 $outvalUnits .= ' - ' . $objp->unit_short;
3871 }
3872 if (!empty($objp->weight) && $objp->weight_units !== null) {
3873 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3874 $outvalUnits .= ' - ' . $unitToShow;
3875 }
3876 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3877 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3878 $outvalUnits .= ' - ' . $unitToShow;
3879 }
3880 if (!empty($objp->surface) && $objp->surface_units !== null) {
3881 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3882 $outvalUnits .= ' - ' . $unitToShow;
3883 }
3884 if (!empty($objp->volume) && $objp->volume_units !== null) {
3885 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3886 $outvalUnits .= ' - ' . $unitToShow;
3887 }
3888 if ($outdurationvalue && $outdurationunit) {
3889 $da = array(
3890 'h' => $langs->trans('Hour'),
3891 'd' => $langs->trans('Day'),
3892 'w' => $langs->trans('Week'),
3893 'm' => $langs->trans('Month'),
3894 'y' => $langs->trans('Year')
3895 );
3896 if (isset($da[$outdurationunit])) {
3897 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3898 }
3899 }
3900 }
3901
3902 $objRef = $objp->ref;
3903 if ($filterkey && $filterkey != '') {
3904 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3905 }
3906 $objRefFourn = $objp->ref_fourn;
3907 if ($filterkey && $filterkey != '') {
3908 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3909 }
3910 $label = $objp->label;
3911 if ($filterkey && $filterkey != '') {
3912 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3913 }
3914
3915 switch ($objp->fk_product_type) {
3917 $picto = 'product';
3918 break;
3920 $picto = 'service';
3921 break;
3922 default:
3923 $picto = '';
3924 break;
3925 }
3926
3927 if (empty($picto)) {
3928 $optlabel = '';
3929 } else {
3930 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3931 }
3932
3933 $optlabel .= $objp->ref;
3934 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3935 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3936 }
3937 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3938 $optlabel .= ' (' . $outbarcode . ')';
3939 }
3940 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3941
3942 $outvallabel = $objRef;
3943 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3944 $outvallabel .= ' (' . $objRefFourn . ')';
3945 }
3946 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3947 $outvallabel .= ' (' . $outbarcode . ')';
3948 }
3949 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3950
3951 // Units
3952 $optlabel .= $outvalUnits;
3953 $outvallabel .= $outvalUnits;
3954
3955 if (!empty($objp->idprodfournprice)) {
3956 $outqty = $objp->quantity;
3957 $outdiscount = $objp->remise_percent;
3958 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3959 $prod_supplier = new ProductFournisseur($this->db);
3960 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3961 $prod_supplier->id = $objp->fk_product;
3962 $prod_supplier->fourn_qty = $objp->quantity;
3963 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3964 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3965
3966 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3967 $priceparser = new PriceParser($this->db);
3968 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3969 if ($price_result >= 0) {
3970 $objp->fprice = $price_result;
3971 if ($objp->quantity >= 1) {
3972 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3973 }
3974 }
3975 }
3976 if ($objp->quantity == 1) {
3977 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3978 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3979 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3980 $outvallabel .= $langs->transnoentities("Unit");
3981 } else {
3982 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3983 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3984 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3985 $outvallabel .= ' ' . $langs->transnoentities("Units");
3986 }
3987
3988 if ($objp->quantity > 1) {
3989 $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
3990 $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
3991 }
3992 if ($objp->remise_percent >= 1) {
3993 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3994 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3995 }
3996 if ($objp->duration) {
3997 $optlabel .= " - " . $objp->duration;
3998 $outvallabel .= " - " . $objp->duration;
3999 }
4000 if (!$socid) {
4001 $optlabel .= " - " . dol_trunc($objp->name, 8);
4002 $outvallabel .= " - " . dol_trunc($objp->name, 8);
4003 }
4004 if ($objp->supplier_reputation) {
4005 //TODO dictionary
4006 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
4007
4008 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
4009 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
4010 }
4011 } else {
4012 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
4013 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
4014 }
4015
4016 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
4017 $novirtualstock = ($showstockinlist == 2);
4018
4019 if ($user->hasRight('stock', 'lire')) {
4020 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
4021
4022 if ($objp->stock > 0) {
4023 $optlabel .= ' - <span class="product_line_stock_ok">';
4024 } elseif ($objp->stock <= 0) {
4025 $optlabel .= ' - <span class="product_line_stock_too_low">';
4026 }
4027 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
4028 $optlabel .= '</span>';
4029 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
4030 $langs->load("stocks");
4031
4032 $tmpproduct = new Product($this->db);
4033 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
4034 $tmpproduct->load_virtual_stock();
4035 $virtualstock = $tmpproduct->stock_theorique;
4036
4037 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
4038
4039 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
4040 if ($virtualstock > 0) {
4041 $optlabel .= '<span class="product_line_stock_ok">';
4042 } elseif ($virtualstock <= 0) {
4043 $optlabel .= '<span class="product_line_stock_too_low">';
4044 }
4045 $optlabel .= $virtualstock;
4046 $optlabel .= '</span>';
4047
4048 unset($tmpproduct);
4049 }
4050 }
4051 }
4052
4053 $optstart = '<option value="' . $outkey . '"';
4054 if ($selected && $selected == $objp->idprodfournprice) {
4055 $optstart .= ' selected';
4056 }
4057 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
4058 $optstart .= ' disabled';
4059 }
4060
4061 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
4062 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
4063 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
4064 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
4065 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
4066 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
4067 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
4068 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
4069 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
4070 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
4071 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
4072 if (isModEnabled('multicurrency')) {
4073 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
4074 $optstart .= ' data-multicurrency-unitprice="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
4075 }
4076 }
4077 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
4078
4079 // set $parameters to call hook
4080 $outarrayentry = array(
4081 'key' => $outkey,
4082 'value' => $outref,
4083 'label' => $outvallabel,
4084 'labelhtml' => $optlabel,
4085 'qty' => $outqty,
4086 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4087 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4088 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4089 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4090 'tva_tx' => price2num($objp->tva_tx),
4091 'default_vat_code' => $objp->default_vat_code,
4092 'supplier_ref' => $objp->ref_fourn,
4093 'discount' => $outdiscount,
4094 'type' => $outtype,
4095 'duration_value' => $outdurationvalue,
4096 'duration_unit' => $outdurationunit,
4097 'disabled' => empty($objp->idprodfournprice),
4098 'description' => $objp->description
4099 );
4100 if (isModEnabled('multicurrency')) {
4101 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4102 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4103 }
4104 $parameters = array(
4105 'objp' => &$objp,
4106 'optstart' => &$optstart,
4107 'optlabel' => &$optlabel,
4108 'outvallabel' => &$outvallabel,
4109 'outarrayentry' => &$outarrayentry,
4110 'fk_soc' => $socid
4111 );
4112 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4113
4114
4115 // Add new entry
4116 // "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
4117 // "label" value of json key array is used by jQuery automatically as text for combo box
4118 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4119 $outarraypush = array(
4120 'key' => $outkey,
4121 'value' => $outref,
4122 'label' => $outvallabel,
4123 'labelhtml' => $optlabel,
4124 'qty' => $outqty,
4125 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4126 'price_qty_ht_locale' => price($objp->fprice),
4127 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4128 'price_unit_ht_locale' => price($objp->unitprice),
4129 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4130 'tva_tx_formated' => price($objp->tva_tx),
4131 'tva_tx' => price2num($objp->tva_tx),
4132 'default_vat_code' => $objp->default_vat_code,
4133 'supplier_ref' => $objp->ref_fourn,
4134 'discount' => $outdiscount,
4135 'type' => $outtype,
4136 'duration_value' => $outdurationvalue,
4137 'duration_unit' => $outdurationunit,
4138 'disabled' => empty($objp->idprodfournprice),
4139 'description' => $objp->description
4140 );
4141 if (isModEnabled('multicurrency')) {
4142 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4143 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4144 }
4145 array_push($outarray, $outarraypush);
4146
4147 // Example of var_dump $outarray
4148 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4149 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4150 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4151 //}
4152 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4153 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4154 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4155
4156 $i++;
4157 }
4158 $out .= '</select>';
4159
4160 $this->db->free($result);
4161
4162 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4163 $out .= ajax_combobox($htmlname);
4164 } else {
4165 dol_print_error($this->db);
4166 }
4167
4168 if (empty($outputmode)) {
4169 return $out;
4170 }
4171 return $outarray;
4172 }
4173
4174 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4175
4184 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4185 {
4186 // phpcs:enable
4187 global $langs, $conf;
4188
4189 $langs->load('stocks');
4190
4191 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4192 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4193 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4194 $sql .= " FROM " . $this->db->prefix() . "product as p";
4195 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4196 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4197 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4198 $sql .= " AND p.tobuy = 1";
4199 $sql .= " AND s.fournisseur = 1";
4200 $sql .= " AND p.rowid = " . ((int) $productid);
4201 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4202 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4203 } else {
4204 $sql .= " ORDER BY pfp.unitprice ASC";
4205 }
4206
4207 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4208 $result = $this->db->query($sql);
4209
4210 if ($result) {
4211 $num = $this->db->num_rows($result);
4212
4213 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4214
4215 if (!$num) {
4216 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4217 } else {
4218 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4219 $form .= '<option value="0">&nbsp;</option>';
4220
4221 $i = 0;
4222 while ($i < $num) {
4223 $objp = $this->db->fetch_object($result);
4224
4225 $opt = '<option value="' . $objp->idprodfournprice . '"';
4226 //if there is only one supplier, preselect it
4227 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4228 $opt .= ' selected';
4229 }
4230 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4231
4232 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4233 $prod_supplier = new ProductFournisseur($this->db);
4234 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4235 $prod_supplier->id = $productid;
4236 $prod_supplier->fourn_qty = $objp->quantity;
4237 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4238 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4239
4240 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4241 $priceparser = new PriceParser($this->db);
4242 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4243 if ($price_result >= 0) {
4244 $objp->fprice = $price_result;
4245 if ($objp->quantity >= 1) {
4246 $objp->unitprice = $objp->fprice / $objp->quantity;
4247 }
4248 }
4249 }
4250 if ($objp->quantity == 1) {
4251 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4252 }
4253
4254 $opt .= $objp->quantity . ' ';
4255
4256 if ($objp->quantity == 1) {
4257 $opt .= $langs->trans("Unit");
4258 } else {
4259 $opt .= $langs->trans("Units");
4260 }
4261 if ($objp->quantity > 1) {
4262 $opt .= " - ";
4263 $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");
4264 }
4265 if ($objp->duration) {
4266 $opt .= " - " . $objp->duration;
4267 }
4268 $opt .= "</option>\n";
4269
4270 $form .= $opt;
4271 $i++;
4272 }
4273 }
4274
4275 $form .= '</select>';
4276 $this->db->free($result);
4277 return $form;
4278 } else {
4279 dol_print_error($this->db);
4280 return '';
4281 }
4282 }
4283
4284
4285 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4292 {
4293 // phpcs:enable
4294 global $langs;
4295
4296 $num = count($this->cache_conditions_paiements);
4297 if ($num > 0) {
4298 return 0; // Cache already loaded
4299 }
4300
4301 dol_syslog(__METHOD__, LOG_DEBUG);
4302
4303 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4304 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4305 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4306 $sql .= " AND active > 0";
4307 $sql .= " ORDER BY sortorder";
4308
4309 $resql = $this->db->query($sql);
4310 if ($resql) {
4311 $num = $this->db->num_rows($resql);
4312 $i = 0;
4313 while ($i < $num) {
4314 $obj = $this->db->fetch_object($resql);
4315
4316 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4317 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4318 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4319 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4320 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4321 $i++;
4322 }
4323
4324 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4325
4326 return $num;
4327 } else {
4328 dol_print_error($this->db);
4329 return -1;
4330 }
4331 }
4332
4333 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4334
4340 public function load_cache_availability()
4341 {
4342 // phpcs:enable
4343 global $langs;
4344
4345 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4346 if ($num > 0) {
4347 return 0; // Cache already loaded
4348 }
4349
4350 dol_syslog(__METHOD__, LOG_DEBUG);
4351
4352 $langs->load('propal');
4353
4354 $sql = "SELECT rowid, code, label, position";
4355 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4356 $sql .= " WHERE active > 0";
4357
4358 $resql = $this->db->query($sql);
4359 if ($resql) {
4360 $num = $this->db->num_rows($resql);
4361 $i = 0;
4362 while ($i < $num) {
4363 $obj = $this->db->fetch_object($resql);
4364
4365 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4366 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4367 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4368 $this->cache_availability[$obj->rowid]['label'] = $label;
4369 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4370 $i++;
4371 }
4372
4373 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4374
4375 return $num;
4376 } else {
4377 dol_print_error($this->db);
4378 return -1;
4379 }
4380 }
4381
4392 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4393 {
4394 global $langs, $user;
4395
4396 $this->load_cache_availability();
4397
4398 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4399
4400 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4401 if ($addempty) {
4402 print '<option value="0">&nbsp;</option>';
4403 }
4404 foreach ($this->cache_availability as $id => $arrayavailability) {
4405 if ($selected == $id) {
4406 print '<option value="' . $id . '" selected>';
4407 } else {
4408 print '<option value="' . $id . '">';
4409 }
4410 print dol_escape_htmltag($arrayavailability['label']);
4411 print '</option>';
4412 }
4413 print '</select>';
4414 if ($user->admin) {
4415 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4416 }
4417 print ajax_combobox($htmlname);
4418 }
4419
4425 public function loadCacheInputReason()
4426 {
4427 global $langs;
4428
4429 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4430 if ($num > 0) {
4431 return 0; // Cache already loaded
4432 }
4433
4434 $sql = "SELECT rowid, code, label";
4435 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4436 $sql .= " WHERE active > 0";
4437
4438 $resql = $this->db->query($sql);
4439 if ($resql) {
4440 $num = $this->db->num_rows($resql);
4441 $i = 0;
4442 $tmparray = array();
4443 while ($i < $num) {
4444 $obj = $this->db->fetch_object($resql);
4445
4446 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4447 $label = ($obj->label != '-' ? $obj->label : '');
4448 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4449 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4450 }
4451 if ($langs->trans($obj->code) != $obj->code) {
4452 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4453 }
4454
4455 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4456 $tmparray[$obj->rowid]['code'] = $obj->code;
4457 $tmparray[$obj->rowid]['label'] = $label;
4458 $i++;
4459 }
4460
4461 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4462
4463 unset($tmparray);
4464 return $num;
4465 } else {
4466 dol_print_error($this->db);
4467 return -1;
4468 }
4469 }
4470
4483 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4484 {
4485 global $langs, $user;
4486
4487 $this->loadCacheInputReason();
4488
4489 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4490 if ($addempty) {
4491 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4492 }
4493 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4494 if ($arraydemandreason['code'] == $exclude) {
4495 continue;
4496 }
4497
4498 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4499 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4500 } else {
4501 print '<option value="' . $arraydemandreason['id'] . '">';
4502 }
4503 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4504 print $langs->trans($label);
4505 print '</option>';
4506 }
4507 print '</select>';
4508 if ($user->admin && empty($notooltip)) {
4509 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4510 }
4511 print ajax_combobox('select_' . $htmlname);
4512 }
4513
4514 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4515
4522 {
4523 // phpcs:enable
4524 global $langs;
4525
4526 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4527 if ($num > 0) {
4528 return $num; // Cache already loaded
4529 }
4530
4531 dol_syslog(__METHOD__, LOG_DEBUG);
4532
4533 $this->cache_types_paiements = array();
4534
4535 $sql = "SELECT id, code, libelle as label, type, active";
4536 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4537 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4538
4539 $resql = $this->db->query($sql);
4540 if ($resql) {
4541 $num = $this->db->num_rows($resql);
4542 $i = 0;
4543 while ($i < $num) {
4544 $obj = $this->db->fetch_object($resql);
4545
4546 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4547 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4548 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4549 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4550 $this->cache_types_paiements[$obj->id]['label'] = $label;
4551 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4552 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4553 $i++;
4554 }
4555
4556 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4557
4558 return $num;
4559 } else {
4560 dol_print_error($this->db);
4561 return -1;
4562 }
4563 }
4564
4565
4566 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4567
4586 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4587 {
4588 // phpcs:enable
4589 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4590 if (empty($noprint)) {
4591 print $out;
4592 } else {
4593 return $out;
4594 }
4595 }
4596
4597
4614 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4615 {
4616 global $langs, $user, $conf;
4617
4618 $out = '';
4619 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4620
4622
4623 // Set default value if not already set by caller
4624 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4625 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4626 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4627 }
4628
4629 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4630 if ($addempty) {
4631 $out .= '<option value="0">&nbsp;</option>';
4632 }
4633
4634 $selectedDepositPercent = null;
4635
4636 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4637 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4638 continue;
4639 }
4640
4641 if ($selected == $id) {
4642 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4643 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4644 } else {
4645 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4646 }
4647 $label = $arrayconditions['label'];
4648
4649 if (!empty($arrayconditions['deposit_percent'])) {
4650 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4651 }
4652
4653 $out .= $label;
4654 $out .= '</option>';
4655 }
4656 $out .= '</select>';
4657 if ($user->admin && empty($noinfoadmin)) {
4658 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4659 }
4660 $out .= ajax_combobox($htmlname);
4661
4662 if ($deposit_percent >= 0) {
4663 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4664 $out .= $langs->trans('DepositPercent') . ' : ';
4665 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4666 $out .= '</span>';
4667 $out .= '
4668 <script nonce="' . getNonce() . '">
4669 $(document).ready(function () {
4670 $("#' . $htmlname . '").change(function () {
4671 let $selected = $(this).find("option:selected");
4672 let depositPercent = $selected.attr("data-deposit_percent");
4673
4674 if (depositPercent.length > 0) {
4675 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4676 } else {
4677 $("#' . $htmlname . '_deposit_percent_container").hide();
4678 }
4679
4680 return true;
4681 });
4682 });
4683 </script>';
4684 }
4685
4686 return $out;
4687 }
4688
4689
4690 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4691
4708 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4709 {
4710 // phpcs:enable
4711 global $langs, $user, $conf;
4712
4713 $out = '';
4714
4715 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4716
4717 $filterarray = array();
4718 if ($filtertype == 'CRDT') {
4719 $filterarray = array(0, 2, 3);
4720 } elseif ($filtertype == 'DBIT') {
4721 $filterarray = array(1, 2, 3);
4722 } elseif ($filtertype != '' && $filtertype != '-1') {
4723 $filterarray = explode(',', $filtertype);
4724 }
4725
4727
4728 // Set default value if not already set by caller
4729 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4730 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4731 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4732 }
4733
4734 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4735 if ($empty) {
4736 $out .= '<option value="">&nbsp;</option>';
4737 }
4738 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4739 // If not good status
4740 if ($active >= 0 && $arraytypes['active'] != $active) {
4741 continue;
4742 }
4743
4744 // We skip of the user requested to filter on specific payment methods
4745 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4746 continue;
4747 }
4748
4749 // We discard empty lines if showempty is on because an empty line has already been output.
4750 if ($empty && empty($arraytypes['code'])) {
4751 continue;
4752 }
4753
4754 if ($format == 0) {
4755 $out .= '<option value="' . $id . '" data-code="'.$arraytypes['code'].'"';
4756 } elseif ($format == 1) {
4757 $out .= '<option value="' . $arraytypes['code'] . '"';
4758 } elseif ($format == 2) {
4759 $out .= '<option value="' . $arraytypes['code'] . '"';
4760 } elseif ($format == 3) {
4761 $out .= '<option value="' . $id . '"';
4762 }
4763 // Print attribute selected or not
4764 if ($format == 1 || $format == 2) {
4765 if ($selected == $arraytypes['code']) {
4766 $out .= ' selected';
4767 }
4768 } else {
4769 if ($selected == $id) {
4770 $out .= ' selected';
4771 }
4772 }
4773 $out .= '>';
4774 $value = '';
4775 if ($format == 0) {
4776 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4777 } elseif ($format == 1) {
4778 $value = $arraytypes['code'];
4779 } elseif ($format == 2) {
4780 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4781 } elseif ($format == 3) {
4782 $value = $arraytypes['code'];
4783 }
4784 $out .= $value ? $value : '&nbsp;';
4785 $out .= '</option>';
4786 }
4787 $out .= '</select>';
4788 if ($user->admin && !$noadmininfo) {
4789 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4790 }
4791 $out .= ajax_combobox('select' . $htmlname);
4792
4793 if (empty($nooutput)) {
4794 print $out;
4795 } else {
4796 return $out;
4797 }
4798 }
4799
4800
4809 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4810 {
4811 global $langs;
4812
4813 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4814 $options = array(
4815 'HT' => $langs->trans("HT"),
4816 'TTC' => $langs->trans("TTC")
4817 );
4818 foreach ($options as $id => $value) {
4819 if ($selected == $id) {
4820 $return .= '<option value="' . $id . '" selected>' . $value;
4821 } else {
4822 $return .= '<option value="' . $id . '">' . $value;
4823 }
4824 $return .= '</option>';
4825 }
4826 $return .= '</select>';
4827 if ($addjscombo) {
4828 $return .= ajax_combobox('select_' . $htmlname);
4829 }
4830
4831 return $return;
4832 }
4833
4834 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4835
4842 {
4843 // phpcs:enable
4844 global $langs;
4845
4846 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4847 if ($num > 0) {
4848 return $num; // Cache already loaded
4849 }
4850
4851 dol_syslog(__METHOD__, LOG_DEBUG);
4852
4853 $this->cache_transport_mode = array();
4854
4855 $sql = "SELECT rowid, code, label, active";
4856 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4857 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4858
4859 $resql = $this->db->query($sql);
4860 if ($resql) {
4861 $num = $this->db->num_rows($resql);
4862 $i = 0;
4863 while ($i < $num) {
4864 $obj = $this->db->fetch_object($resql);
4865
4866 // If traduction exist, we use it else we take the default label
4867 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4868 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4869 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4870 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4871 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4872 $i++;
4873 }
4874
4875 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4876
4877 return $num;
4878 } else {
4879 dol_print_error($this->db);
4880 return -1;
4881 }
4882 }
4883
4897 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4898 {
4899 global $langs, $user;
4900
4901 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4902
4904
4905 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4906 if ($empty) {
4907 print '<option value="">&nbsp;</option>';
4908 }
4909 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4910 // If not good status
4911 if ($active >= 0 && $arraytypes['active'] != $active) {
4912 continue;
4913 }
4914
4915 // We discard empty line if showempty is on because an empty line has already been output.
4916 if ($empty && empty($arraytypes['code'])) {
4917 continue;
4918 }
4919
4920 if ($format == 0) {
4921 print '<option value="' . $id . '"';
4922 } elseif ($format == 1) {
4923 print '<option value="' . $arraytypes['code'] . '"';
4924 } elseif ($format == 2) {
4925 print '<option value="' . $arraytypes['code'] . '"';
4926 } elseif ($format == 3) {
4927 print '<option value="' . $id . '"';
4928 }
4929 // If text is selected, we compare with code, else with id
4930 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4931 print ' selected';
4932 } elseif ($selected == $id) {
4933 print ' selected';
4934 }
4935 print '>';
4936 $value = '';
4937 if ($format == 0) {
4938 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4939 } elseif ($format == 1) {
4940 $value = $arraytypes['code'];
4941 } elseif ($format == 2) {
4942 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4943 } elseif ($format == 3) {
4944 $value = $arraytypes['code'];
4945 }
4946 print $value ? $value : '&nbsp;';
4947 print '</option>';
4948 }
4949 print '</select>';
4950
4951 print ajax_combobox("select".$htmlname);
4952
4953 if ($user->admin && !$noadmininfo) {
4954 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4955 }
4956 }
4957
4970 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4971 {
4972 global $langs, $user;
4973
4974 $langs->load("admin");
4975 $langs->load("deliveries");
4976
4977 $sql = "SELECT rowid, code, libelle as label";
4978 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4979 $sql .= " WHERE active > 0";
4980 if ($filtre) {
4981 $sql .= " AND " . $filtre;
4982 }
4983 $sql .= " ORDER BY libelle ASC";
4984
4985 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4986 $result = $this->db->query($sql);
4987 if ($result) {
4988 $num = $this->db->num_rows($result);
4989 $i = 0;
4990 if ($num) {
4991 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4992 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4993 print '<option value="-1">&nbsp;</option>';
4994 }
4995 while ($i < $num) {
4996 $obj = $this->db->fetch_object($result);
4997 if ($selected == $obj->rowid) {
4998 print '<option value="' . $obj->rowid . '" selected>';
4999 } else {
5000 print '<option value="' . $obj->rowid . '">';
5001 }
5002 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
5003 print '</option>';
5004 $i++;
5005 }
5006 print "</select>";
5007 if ($user->admin && empty($noinfoadmin)) {
5008 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
5009 }
5010
5011 print ajax_combobox('select' . $htmlname);
5012 } else {
5013 print $langs->trans("NoShippingMethodDefined");
5014 }
5015 } else {
5016 dol_print_error($this->db);
5017 }
5018 }
5019
5029 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
5030 {
5031 global $langs;
5032
5033 $langs->load("deliveries");
5034
5035 if ($htmlname != "none") {
5036 print '<form method="POST" action="' . $page . '">';
5037 print '<input type="hidden" name="action" value="setshippingmethod">';
5038 print '<input type="hidden" name="token" value="' . newToken() . '">';
5039 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
5040 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
5041 print '</form>';
5042 } else {
5043 if ($selected) {
5044 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
5045 print $langs->trans("SendingMethod" . strtoupper($code));
5046 } else {
5047 print "&nbsp;";
5048 }
5049 }
5050 }
5051
5060 public function selectSituationInvoices($selected = '', $socid = 0)
5061 {
5062 global $langs;
5063
5064 $langs->load('bills');
5065
5066 $opt = '<option value="" selected></option>';
5067 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
5068 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
5069 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
5070 $sql .= ' AND situation_counter >= 1';
5071 $sql .= ' AND fk_soc = ' . (int) $socid;
5072 $sql .= ' AND type <> 2';
5073 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
5074 $resql = $this->db->query($sql);
5075
5076 if ($resql && $this->db->num_rows($resql) > 0) {
5077 // Last seen cycle
5078 $ref = 0;
5079 while ($obj = $this->db->fetch_object($resql)) {
5080 //Same cycle ?
5081 if ($obj->situation_cycle_ref != $ref) {
5082 // Just seen this cycle
5083 $ref = $obj->situation_cycle_ref;
5084 //not final ?
5085 if ($obj->situation_final != 1) {
5086 //Not prov?
5087 if (substr($obj->ref, 1, 4) != 'PROV') {
5088 if ($selected == $obj->rowid) {
5089 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5090 } else {
5091 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5092 }
5093 }
5094 }
5095 }
5096 }
5097 } else {
5098 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5099 }
5100 if ($opt == '<option value ="" selected></option>') {
5101 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5102 }
5103 return $opt;
5104 }
5105
5115 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5116 {
5117 global $langs;
5118
5119 $langs->load('products');
5120
5121 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5122
5123 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5124 $sql .= ' WHERE active > 0';
5125 if (!empty($unit_type)) {
5126 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5127 }
5128 $sql .= " ORDER BY sortorder";
5129
5130 $resql = $this->db->query($sql);
5131 if ($resql && $this->db->num_rows($resql) > 0) {
5132 if ($showempty) {
5133 $return .= '<option value="-1"></option>';
5134 }
5135
5136 while ($res = $this->db->fetch_object($resql)) {
5137 $unitLabel = $res->label;
5138 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5139 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5140 }
5141
5142 if ($selected == $res->rowid) {
5143 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5144 } else {
5145 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5146 }
5147 }
5148 $return .= '</select>';
5149
5150 $return .= ajax_combobox($htmlname);
5151 }
5152 return $return;
5153 }
5154
5155 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5156
5171 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5172 {
5173 // phpcs:enable
5174 global $langs;
5175
5176 $out = '';
5177
5178 $langs->loadLangs(array("admin", "banks"));
5179 $num = 0;
5180
5181 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5182 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5183 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5184 if ($status != 2) {
5185 $sql .= " AND clos = " . (int) $status;
5186 }
5187 if ($filtre) { // TODO Support USF
5188 $sql .= " AND " . $filtre;
5189 }
5190 $sql .= " ORDER BY label";
5191
5192 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5193 $result = $this->db->query($sql);
5194 if ($result) {
5195 $num = $this->db->num_rows($result);
5196 $i = 0;
5197
5198 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5199
5200 if ($num == 0) {
5201 if ($status == 0) {
5202 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5203 } else {
5204 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5205 }
5206 } else {
5207 if (!empty($useempty) && !is_numeric($useempty)) {
5208 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5209 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5210 $out .= '<option value="-1">&nbsp;</option>';
5211 }
5212 }
5213
5214 while ($i < $num) {
5215 $obj = $this->db->fetch_object($result);
5216
5217 $labeltoshow = trim($obj->label);
5218 $labeltoshowhtml = trim($obj->label);
5219 if ($showcurrency) {
5220 $labeltoshow .= ' (' . $obj->currency_code . ')';
5221 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $obj->currency_code . ')</span>';
5222 }
5223 if ($status == 2 && $obj->status == 1) {
5224 $labeltoshow .= ' (' . $langs->trans("Closed") . ')';
5225 $labeltoshowhtml .= ' <span class="opacitymedium">(' . $langs->trans("Closed") . ')</span>';
5226 }
5227
5228 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5229 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'" selected>';
5230 } else {
5231 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" data-html="'.dolPrintHTMLForAttribute($labeltoshowhtml).'">';
5232 }
5233 $out .= $labeltoshow;
5234 $out .= '</option>';
5235 $i++;
5236 }
5237 $out .= "</select>";
5238 $out .= ajax_combobox('select' . $htmlname);
5239 } else {
5240 dol_print_error($this->db);
5241 }
5242
5243 // Output or return
5244 if (empty($nooutput)) {
5245 print $out;
5246 } else {
5247 return $out;
5248 }
5249
5250 return $num;
5251 }
5252
5266 public function selectRib($selected = '', $htmlname = 'ribcompanyid', $filtre = '', $useempty = 0, $moreattrib = '', $showibanbic = 0, $morecss = '', $nooutput = 0)
5267 {
5268 // phpcs:enable
5269 global $langs;
5270
5271 $out = '';
5272
5273 $langs->loadLangs(array("admin", "banks"));
5274 $num = 0;
5275
5276 $sql = "SELECT rowid, label, bank, status, iban_prefix, bic";
5277 $sql .= " FROM " . $this->db->prefix() . "societe_rib";
5278 $sql.= " WHERE type = 'ban'";
5279 if ($filtre) { // TODO Support USF
5280 $sql .= " AND " . $filtre;
5281 }
5282 $sql .= " ORDER BY label";
5283 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5284 $result = $this->db->query($sql);
5285 if ($result) {
5286 $num = $this->db->num_rows($result);
5287 $i = 0;
5288
5289 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5290
5291 if ($num == 0) {
5292 $out .= '<option class="opacitymedium" value="-1">' . $langs->trans("NoBankAccountDefined") . '</span>';
5293 } else {
5294 if (!empty($useempty) && !is_numeric($useempty)) {
5295 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5296 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5297 $out .= '<option value="-1">&nbsp;</option>';
5298 }
5299 }
5300
5301 while ($i < $num) {
5302 $obj = $this->db->fetch_object($result);
5303 $iban = dolDecrypt($obj->iban_prefix);
5304 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5305 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '" selected>';
5306 } else {
5307 $out .= '<option value="' . $obj->rowid . '" data-iban-prefix="' . $iban . ' data-bic="' . $obj->bic . '">';
5308 }
5309 $out .= trim($obj->label);
5310 if ($showibanbic) {
5311 $out .= ' (' . $iban . '/' .$obj->bic. ')';
5312 }
5313 $out .= '</option>';
5314 $i++;
5315 }
5316 $out .= "</select>";
5317 $out .= ajax_combobox('select' . $htmlname);
5318 } else {
5319 dol_print_error($this->db);
5320 }
5321
5322 // Output or return
5323 if (empty($nooutput)) {
5324 print $out;
5325 } else {
5326 return $out;
5327 }
5328
5329 return $num;
5330 }
5331
5343 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5344 {
5345 global $langs;
5346
5347 $langs->load("admin");
5348 $num = 0;
5349
5350 $sql = "SELECT rowid, name, fk_country, status, entity";
5351 $sql .= " FROM " . $this->db->prefix() . "establishment";
5352 $sql .= " WHERE 1=1";
5353 if ($status != 2) {
5354 $sql .= " AND status = " . (int) $status;
5355 }
5356 if ($filtre) { // TODO Support USF
5357 $sql .= " AND " . $filtre;
5358 }
5359 $sql .= " ORDER BY name";
5360
5361 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5362 $result = $this->db->query($sql);
5363 if ($result) {
5364 $num = $this->db->num_rows($result);
5365 $i = 0;
5366 if ($num) {
5367 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5368 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5369 print '<option value="-1">&nbsp;</option>';
5370 }
5371
5372 while ($i < $num) {
5373 $obj = $this->db->fetch_object($result);
5374 if ($selected == $obj->rowid) {
5375 print '<option value="' . $obj->rowid . '" selected>';
5376 } else {
5377 print '<option value="' . $obj->rowid . '">';
5378 }
5379 print trim($obj->name);
5380 if ($status == 2 && $obj->status == 1) {
5381 print ' (' . $langs->trans("Closed") . ')';
5382 }
5383 print '</option>';
5384 $i++;
5385 }
5386 print "</select>";
5387 } else {
5388 if ($status == 0) {
5389 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5390 } else {
5391 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5392 }
5393 }
5394
5395 return $num;
5396 } else {
5397 dol_print_error($this->db);
5398 return -1;
5399 }
5400 }
5401
5411 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5412 {
5413 global $langs;
5414 if ($htmlname != "none") {
5415 print '<form method="POST" action="' . $page . '">';
5416 print '<input type="hidden" name="action" value="setbankaccount">';
5417 print '<input type="hidden" name="token" value="' . newToken() . '">';
5418 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5419 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5420 if ($nbaccountfound > 0) {
5421 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5422 }
5423 print '</form>';
5424 } else {
5425 $langs->load('banks');
5426
5427 if ($selected) {
5428 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5429 $bankstatic = new Account($this->db);
5430 $result = $bankstatic->fetch($selected);
5431 if ($result) {
5432 print $bankstatic->getNomUrl(1);
5433 }
5434 } else {
5435 print "&nbsp;";
5436 }
5437 }
5438 }
5439
5451 public function formRib($page, $selected = '', $htmlname = 'ribcompanyid', $filtre = '', $addempty = 0, $showibanbic = 0)
5452 {
5453 global $langs;
5454 if ($htmlname != "none") {
5455 print '<form method="POST" action="' . $page . '">';
5456 print '<input type="hidden" name="action" value="setbankaccountcustomer">';
5457 print '<input type="hidden" name="token" value="' . newToken() . '">';
5458 $nbaccountfound = $this->selectRib($selected, $htmlname, $filtre, $addempty, '', $showibanbic);
5459 if ($nbaccountfound > 0) {
5460 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5461 }
5462 print '</form>';
5463 } else {
5464 $langs->load('banks');
5465
5466 if ($selected) {
5467 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
5468 $bankstatic = new CompanyBankAccount($this->db);
5469 $result = $bankstatic->fetch($selected);
5470 if ($result) {
5471 print $bankstatic->label;
5472 if ($showibanbic) print ' (' . $bankstatic->iban . '/' .$bankstatic->bic. ')';
5473 }
5474 } else {
5475 print "&nbsp;";
5476 }
5477 }
5478 }
5479
5480 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5481
5501 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5502 {
5503 // phpcs:enable
5504 global $conf, $langs;
5505 $langs->load("categories");
5506
5507 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5508
5509 // For backward compatibility
5510 if (is_numeric($type)) {
5511 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5512 }
5513
5514 if ($type === Categorie::TYPE_BANK_LINE) {
5515 // TODO Move this into common category feature after migration of llx_category_bankline into llx_categorie_bankline
5516 $cat = new Categorie($this->db);
5517 $cate_arbo = array();
5518 $sql = "SELECT c.label, c.rowid";
5519 $sql .= " FROM " . $this->db->prefix() . "categorie as c";
5520 $sql .= " WHERE entity = " . $conf->entity . " AND type = " . ((int) $cat->getMapId()[$type]);
5521 $sql .= " ORDER BY c.label";
5522 $result = $this->db->query($sql);
5523 if ($result) {
5524 $num = $this->db->num_rows($result);
5525 $i = 0;
5526 while ($i < $num) {
5527 $objp = $this->db->fetch_object($result);
5528 if ($objp) {
5529 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5530 }
5531 $i++;
5532 }
5533 $this->db->free($result);
5534 } else {
5535 dol_print_error($this->db);
5536 }
5537 } else {
5538 $cat = new Categorie($this->db);
5539 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5540 }
5541
5542 $outarray = array();
5543 $outarrayrichhtml = array();
5544
5545
5546 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5547 if (is_array($cate_arbo)) {
5548 $num = count($cate_arbo);
5549
5550 if (!$num) {
5551 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5552 } else {
5553 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5554 $output .= '<option value="-1">&nbsp;</option>';
5555 }
5556 foreach ($cate_arbo as $key => $value) {
5557 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5558 $add = 'selected ';
5559 } else {
5560 $add = '';
5561 }
5562
5563 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5564 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5565
5566 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5567
5568 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5569
5570 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5571 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5572 $output .= '>';
5573 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5574 $output .= '</option>';
5575
5576 $cate_arbo[$key]['data-html'] = $labeltoshow;
5577 }
5578 }
5579 }
5580 $output .= '</select>';
5581 $output .= "\n";
5582
5583 if ($outputmode == 2) {
5584 // TODO: handle error when $cate_arbo is not an array
5585 return $cate_arbo;
5586 } elseif ($outputmode == 1) {
5587 return $outarray;
5588 } elseif ($outputmode == 3) {
5589 return $outarrayrichhtml;
5590 }
5591 return $output;
5592 }
5593
5594 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5595
5614 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5615 {
5616 // phpcs:enable
5617 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5618 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5619 }
5620
5648 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5649 {
5650 global $langs, $conf;
5651
5652 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5653 $formconfirm = '';
5654 $inputok = array();
5655 $inputko = array();
5656
5657 // Clean parameters
5658 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5659 if ($conf->browser->layout == 'phone') {
5660 $width = '95%';
5661 }
5662
5663 // Set height automatically if not defined
5664 if (empty($height)) {
5665 $height = 220;
5666 if (is_array($formquestion) && count($formquestion) > 2) {
5667 $height += ((count($formquestion) - 2) * 24);
5668 }
5669 }
5670
5671 if (is_array($formquestion) && !empty($formquestion)) {
5672 // First add hidden fields and value
5673 foreach ($formquestion as $key => $input) {
5674 if (is_array($input) && !empty($input)) {
5675 if ($input['type'] == 'hidden') {
5676 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5677 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5678
5679 $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";
5680 }
5681 }
5682 }
5683
5684 // Now add questions
5685 $moreonecolumn = '';
5686 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5687 foreach ($formquestion as $key => $input) {
5688 if (is_array($input) && !empty($input)) {
5689 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5690 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5691 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5692
5693 if ($input['type'] == 'text') {
5694 $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";
5695 } elseif ($input['type'] == 'password') {
5696 $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";
5697 } elseif ($input['type'] == 'textarea') {
5698 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5699 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5700 $more .= $input['value'];
5701 $more .= '</textarea>';
5702 $more .= '</div></div>'."\n";*/
5703 $moreonecolumn .= '<div class="margintoponly">';
5704 $moreonecolumn .= $input['label'] . '<br>';
5705 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5706 $moreonecolumn .= $input['value'];
5707 $moreonecolumn .= '</textarea>';
5708 $moreonecolumn .= '</div>';
5709 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5710 if (empty($morecss)) {
5711 $morecss = 'minwidth100';
5712 }
5713
5714 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5715 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5716 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5717 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5718 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5719 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5720 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5721
5722 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5723 if (!empty($input['label'])) {
5724 $more .= $input['label'] . '</div><div class="tagtd left">';
5725 }
5726 if ($input['type'] == 'select') {
5727 $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);
5728 } else {
5729 $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);
5730 }
5731 $more .= '</div></div>' . "\n";
5732 } elseif ($input['type'] == 'checkbox') {
5733 $more .= '<div class="tagtr">';
5734 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5735 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5736 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5737 $more .= ' checked';
5738 }
5739 if (is_bool($input['value']) && $input['value']) {
5740 $more .= ' checked';
5741 }
5742 if (isset($input['disabled'])) {
5743 $more .= ' disabled';
5744 }
5745 $more .= ' /></div>';
5746 $more .= '</div>' . "\n";
5747 } elseif ($input['type'] == 'radio') {
5748 $i = 0;
5749 foreach ($input['values'] as $selkey => $selval) {
5750 $more .= '<div class="tagtr">';
5751 if (isset($input['label'])) {
5752 if ($i == 0) {
5753 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5754 } else {
5755 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5756 }
5757 }
5758 $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;
5759 if (!empty($input['disabled'])) {
5760 $more .= ' disabled';
5761 }
5762 if (isset($input['default']) && $input['default'] === $selkey) {
5763 $more .= ' checked="checked"';
5764 }
5765 $more .= ' /> ';
5766 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5767 $more .= '</div></div>' . "\n";
5768 $i++;
5769 }
5770 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5771 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5772 $more .= '<div class="tagtd">';
5773 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5774 $h = $m = 0;
5775 if ($input['type'] == 'datetime') {
5776 $h = isset($input['hours']) ? $input['hours'] : 1;
5777 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5778 }
5779 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5780 $more .= '</div></div>'."\n";
5781 $formquestion[] = array('name' => $input['name'].'day');
5782 $formquestion[] = array('name' => $input['name'].'month');
5783 $formquestion[] = array('name' => $input['name'].'year');
5784 $formquestion[] = array('name' => $input['name'].'hour');
5785 $formquestion[] = array('name' => $input['name'].'min');
5786 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5787 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5788 if (!empty($input['label'])) {
5789 $more .= $input['label'] . '</div><div class="tagtd">';
5790 }
5791 $more .= $input['value'];
5792 $more .= '</div></div>' . "\n";
5793 } elseif ($input['type'] == 'onecolumn') {
5794 $moreonecolumn .= '<div class="margintoponly">';
5795 $moreonecolumn .= $input['value'];
5796 $moreonecolumn .= '</div>' . "\n";
5797 } elseif ($input['type'] == 'hidden') {
5798 // Do nothing more, already added by a previous loop
5799 } elseif ($input['type'] == 'separator') {
5800 $more .= '<br>';
5801 } else {
5802 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5803 }
5804 }
5805 }
5806 $more .= '</div>' . "\n";
5807 $more .= $moreonecolumn;
5808 }
5809
5810 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5811 // 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
5812 // See page product/card.php for example
5813 if (!empty($conf->dol_use_jmobile)) {
5814 $useajax = 0;
5815 }
5816 if (empty($conf->use_javascript_ajax)) {
5817 $useajax = 0;
5818 }
5819
5820 if ($useajax) {
5821 $autoOpen = true;
5822 $dialogconfirm = 'dialog-confirm';
5823 $button = '';
5824 if (!is_numeric($useajax)) {
5825 $button = $useajax;
5826 $useajax = 1;
5827 $autoOpen = false;
5828 $dialogconfirm .= '-' . $button;
5829 }
5830 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5831 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5832
5833 // Add input fields into list of fields to read during submit (inputok and inputko)
5834 if (is_array($formquestion)) {
5835 foreach ($formquestion as $key => $input) {
5836 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5837 // Add name of fields to propagate with the GET when submitting the form with button OK.
5838 if (is_array($input) && isset($input['name'])) {
5839 if (strpos($input['name'], ',') > 0) {
5840 $inputok = array_merge($inputok, explode(',', $input['name']));
5841 } else {
5842 array_push($inputok, $input['name']);
5843 }
5844 }
5845 // Add name of fields to propagate with the GET when submitting the form with button KO.
5846 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5847 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5848 array_push($inputko, $input['name']);
5849 }
5850 }
5851 }
5852
5853 // Show JQuery confirm box.
5854 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5855 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5856 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5857 }
5858 if (!empty($more)) {
5859 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5860 }
5861 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5862 $formconfirm .= '</div>' . "\n";
5863
5864 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5865 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5866 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5867 $formconfirm .= 'jQuery(document).ready(function() {
5868 $(function() {
5869 $( "#' . $dialogconfirm . '" ).dialog(
5870 {
5871 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5872 if ($newselectedchoice == 'no') {
5873 $formconfirm .= '
5874 open: function() {
5875 $(this).parent().find("button.ui-button:eq(2)").focus();
5876 },';
5877 }
5878
5879 $jsforcursor = '';
5880 if ($useajax == 1) {
5881 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5882 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5883 }
5884
5885 $postconfirmas = 'GET';
5886
5887 $formconfirm .= '
5888 resizable: false,
5889 height: "' . $height . '",
5890 width: "' . $width . '",
5891 modal: true,
5892 closeOnEscape: false,
5893 buttons: {
5894 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5895 var options = "token=' . urlencode(newToken()) . '";
5896 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5897 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5898 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5899
5900 if (inputok.length > 0) {
5901 $.each(inputok, function(i, inputname) {
5902 var more = "";
5903 var inputvalue;
5904 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5905 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5906 } else {
5907 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5908 inputvalue = $("#" + inputname + more).val();
5909 }
5910 if (typeof inputvalue == "undefined") { inputvalue=""; }
5911 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5912 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5913 });
5914 }
5915 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5916 if (pageyes.length > 0) {';
5917 if ($postconfirmas == 'GET') {
5918 $formconfirm .= 'location.href = urljump;';
5919 } else {
5920 $formconfirm .= $jsforcursor;
5921 $formconfirm .= 'var post = $.post(
5922 pageyes,
5923 options,
5924 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5925 );';
5926 }
5927 $formconfirm .= '
5928 console.log("after post ok");
5929 }
5930 $(this).dialog("close");
5931 },
5932 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5933 var options = "token=' . urlencode(newToken()) . '";
5934 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5935 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5936 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5937 if (inputko.length > 0) {
5938 $.each(inputko, function(i, inputname) {
5939 var more = "";
5940 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5941 var inputvalue = $("#" + inputname + more).val();
5942 if (typeof inputvalue == "undefined") { inputvalue=""; }
5943 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5944 });
5945 }
5946 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5947 //alert(urljump);
5948 if (pageno.length > 0) {';
5949 if ($postconfirmas == 'GET') {
5950 $formconfirm .= 'location.href = urljump;';
5951 } else {
5952 $formconfirm .= $jsforcursor;
5953 $formconfirm .= 'var post = $.post(
5954 pageno,
5955 options,
5956 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5957 );';
5958 }
5959 $formconfirm .= '
5960 console.log("after post ko");
5961 }
5962 $(this).dialog("close");
5963 }
5964 }
5965 }
5966 );
5967
5968 var button = "' . $button . '";
5969 if (button.length > 0) {
5970 $( "#" + button ).click(function() {
5971 $("#' . $dialogconfirm . '").dialog("open");
5972 });
5973 }
5974 });
5975 });
5976 </script>';
5977 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5978 } else {
5979 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5980
5981 if (empty($disableformtag)) {
5982 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftnoright">' . "\n";
5983 }
5984
5985 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5986 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5987
5988 $formconfirm .= '<table class="valid centpercent">' . "\n";
5989
5990 // Line title
5991 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5992 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5993 $formconfirm .= '</td></tr>' . "\n";
5994
5995 // Line text
5996 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5997 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5998 }
5999
6000 // Line form fields
6001 if ($more) {
6002 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
6003 $formconfirm .= $more;
6004 $formconfirm .= '</td></tr>' . "\n";
6005 }
6006
6007 // Line with question
6008 $formconfirm .= '<tr class="valid">';
6009 $formconfirm .= '<td class="valid">' . $question . '</td>';
6010 $formconfirm .= '<td class="valid center">';
6011 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
6012 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
6013 $formconfirm .= '</td>';
6014 $formconfirm .= '</tr>' . "\n";
6015
6016 $formconfirm .= '</table>' . "\n";
6017
6018 if (empty($disableformtag)) {
6019 $formconfirm .= "</form>\n";
6020 }
6021 $formconfirm .= '<br>';
6022
6023 if (!empty($conf->use_javascript_ajax)) {
6024 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
6025 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
6026 $formconfirm .= '
6027 $(document).ready(function () {
6028 $(".confirmvalidatebutton").on("click", function() {
6029 console.log("We click on button confirmvalidatebutton");
6030 $(this).attr("disabled", "disabled");
6031 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
6032 //console.log($(this).closest("form"));
6033 $(this).closest("form").submit();
6034 });
6035 });
6036 ';
6037 $formconfirm .= '</script>' . "\n";
6038 }
6039
6040 $formconfirm .= "<!-- end formconfirm -->\n";
6041 }
6042
6043 return $formconfirm;
6044 }
6045
6046
6047 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6048
6064 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
6065 {
6066 // phpcs:enable
6067 global $langs;
6068
6069 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
6070 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
6071
6072 $out = '';
6073
6074 $formproject = new FormProjets($this->db);
6075
6076 $langs->load("project");
6077 if ($htmlname != "none") {
6078 $out .= '<form method="post" action="' . $page . '">';
6079 $out .= '<input type="hidden" name="action" value="classin">';
6080 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6081 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
6082 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6083 $out .= '</form>';
6084 } else {
6085 $out .= '<span class="project_head_block">';
6086 if ($selected) {
6087 $projet = new Project($this->db);
6088 $projet->fetch($selected);
6089 $out .= $projet->getNomUrl(0, '', 1);
6090 } else {
6091 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
6092 }
6093 $out .= '</span>';
6094 }
6095
6096 if (empty($nooutput)) {
6097 print $out;
6098 return '';
6099 }
6100 return $out;
6101 }
6102
6103 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6104
6120 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
6121 {
6122 // phpcs:enable
6123 global $langs;
6124
6125 $out = '';
6126
6127 if ($htmlname != "none") {
6128 $out .= '<form method="POST" action="' . $page . '">';
6129 $out .= '<input type="hidden" name="action" value="setconditions">';
6130 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6131 if ($type) {
6132 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6133 }
6134 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
6135 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
6136 $out .= '</form>';
6137 } else {
6138 if ($selected) {
6140 if (isset($this->cache_conditions_paiements[$selected])) {
6141 $label = $this->cache_conditions_paiements[$selected]['label'];
6142
6143 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
6144 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
6145 }
6146
6147 $out .= $label;
6148 } else {
6149 $langs->load('errors');
6150 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
6151 }
6152 } else {
6153 $out .= '&nbsp;';
6154 }
6155 }
6156
6157 if (empty($nooutput)) {
6158 print $out;
6159 return '';
6160 }
6161 return $out;
6162 }
6163
6164 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6165