dolibarr 20.0.4
html.form.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
7 * Copyright (C) 2005-2017 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
9 * Copyright (C) 2006 Marc Barilley/Ocebo <marc@ocebo.com>
10 * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerker@telenet.be>
11 * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com>
12 * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es>
13 * Copyright (C) 2010-2021 Philippe Grand <philippe.grand@atoo-net.com>
14 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
15 * Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
16 * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
17 * Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
18 * Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
19 * Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
20 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
21 * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
22 * Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
23 * Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
24 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
25 * Copyright (C) 2023 Nick Fragoulis
26 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 3 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program. If not, see <https://www.gnu.org/licenses/>.
40 */
41
55class Form
56{
60 public $db;
61
65 public $error = '';
66
70 public $errors = array();
71
72 // Some properties used to return data by some methods
74 public $result;
76 public $num;
77
78 // Cache arrays
79 public $cache_types_paiements = array();
80 public $cache_conditions_paiements = array();
81 public $cache_transport_mode = array();
82 public $cache_availability = array();
83 public $cache_demand_reason = array();
84 public $cache_types_fees = array();
85 public $cache_vatrates = array();
86 public $cache_invoice_subtype = array();
87
88
94 public function __construct($db)
95 {
96 $this->db = $db;
97 }
98
115 public function editfieldkey($text, $htmlname, $preselected, $object, $perm, $typeofdata = 'string', $moreparam = '', $fieldrequired = 0, $notabletag = 0, $paramid = 'id', $help = '')
116 {
117 global $langs;
118
119 $ret = '';
120
121 // TODO change for compatibility
122 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;/', $typeofdata)) {
123 if (!empty($perm)) {
124 $tmp = explode(':', $typeofdata);
125 $ret .= '<div class="editkey_' . $tmp[0] . (!empty($tmp[1]) ? ' ' . $tmp[1] : '') . '" id="' . $htmlname . '">';
126 if ($fieldrequired) {
127 $ret .= '<span class="fieldrequired">';
128 }
129 if ($help) {
130 $ret .= $this->textwithpicto($langs->trans($text), $help);
131 } else {
132 $ret .= $langs->trans($text);
133 }
134 if ($fieldrequired) {
135 $ret .= '</span>';
136 }
137 $ret .= '</div>' . "\n";
138 } else {
139 if ($fieldrequired) {
140 $ret .= '<span class="fieldrequired">';
141 }
142 if ($help) {
143 $ret .= $this->textwithpicto($langs->trans($text), $help);
144 } else {
145 $ret .= $langs->trans($text);
146 }
147 if ($fieldrequired) {
148 $ret .= '</span>';
149 }
150 }
151 } else {
152 if (empty($notabletag) && $perm) {
153 $ret .= '<table class="nobordernopadding centpercent"><tr><td class="nowrap">';
154 }
155 if ($fieldrequired) {
156 $ret .= '<span class="fieldrequired">';
157 }
158 if ($help) {
159 $ret .= $this->textwithpicto($langs->trans($text), $help);
160 } else {
161 $ret .= $langs->trans($text);
162 }
163 if ($fieldrequired) {
164 $ret .= '</span>';
165 }
166 if (!empty($notabletag)) {
167 $ret .= ' ';
168 }
169 if (empty($notabletag) && $perm) {
170 $ret .= '</td>';
171 }
172 if (empty($notabletag) && $perm) {
173 $ret .= '<td class="right">';
174 }
175 if ($htmlname && GETPOST('action', 'aZ09') != 'edit' . $htmlname && $perm) {
176 $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>';
177 }
178 if (!empty($notabletag) && $notabletag == 1) {
179 if ($text) {
180 $ret .= ' : ';
181 } else {
182 $ret .= ' ';
183 }
184 }
185 if (!empty($notabletag) && $notabletag == 3) {
186 $ret .= ' ';
187 }
188 if (empty($notabletag) && $perm) {
189 $ret .= '</td>';
190 }
191 if (empty($notabletag) && $perm) {
192 $ret .= '</tr></table>';
193 }
194 }
195
196 return $ret;
197 }
198
222 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 = '')
223 {
224 global $conf, $langs;
225
226 $ret = '';
227
228 // Check parameters
229 if (empty($typeofdata)) {
230 return 'ErrorBadParameter typeofdata is empty';
231 }
232 // Clean parameter $typeofdata
233 if ($typeofdata == 'datetime') {
234 $typeofdata = 'dayhour';
235 }
236 $reg = array();
237 if (preg_match('/^(\w+)\‍((\d+)\‍)$/', $typeofdata, $reg)) {
238 if ($reg[1] == 'varchar') {
239 $typeofdata = 'string';
240 } elseif ($reg[1] == 'int') {
241 $typeofdata = 'numeric';
242 } else {
243 return 'ErrorBadParameter ' . $typeofdata;
244 }
245 }
246
247 // When option to edit inline is activated
248 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !preg_match('/^select;|day|datepicker|dayhour|datehourpicker/', $typeofdata)) { // TODO add jquery timepicker and support select
249 $ret .= $this->editInPlace($object, $value, $htmlname, $perm, $typeofdata, $editvalue, $extObject, $custommsg);
250 } else {
251 if ($editaction == '') {
252 $editaction = GETPOST('action', 'aZ09');
253 }
254 $editmode = ($editaction == 'edit' . $htmlname);
255 if ($editmode) { // edit mode
256 $ret .= "\n";
257 $ret .= '<form method="post" action="' . $_SERVER["PHP_SELF"] . ($moreparam ? '?' . $moreparam : '') . '">';
258 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
259 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
260 $ret .= '<input type="hidden" name="' . $paramid . '" value="' . $object->id . '">';
261 if (empty($notabletag)) {
262 $ret .= '<table class="nobordernopadding centpercent">';
263 }
264 if (empty($notabletag)) {
265 $ret .= '<tr><td>';
266 }
267 if (preg_match('/^(string|safehtmlstring|email|phone|url)/', $typeofdata)) {
268 $tmp = explode(':', $typeofdata);
269 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($editvalue ? $editvalue : $value) . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
270 } elseif (preg_match('/^(integer)/', $typeofdata)) {
271 $tmp = explode(':', $typeofdata);
272 $valuetoshow = price2num($editvalue ? $editvalue : $value, 0);
273 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . $valuetoshow . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
274 } elseif (preg_match('/^(numeric|amount)/', $typeofdata)) {
275 $tmp = explode(':', $typeofdata);
276 $valuetoshow = price2num($editvalue ? $editvalue : $value);
277 $ret .= '<input type="text" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($valuetoshow != '' ? price($valuetoshow) : '') . '"' . (empty($tmp[1]) ? '' : ' size="' . $tmp[1] . '"') . ' autofocus>';
278 } elseif (preg_match('/^(checkbox)/', $typeofdata)) {
279 $tmp = explode(':', $typeofdata);
280 $ret .= '<input type="checkbox" id="' . $htmlname . '" name="' . $htmlname . '" value="' . ($value ? $value : 'on') . '"' . ($value ? ' checked' : '') . (empty($tmp[1]) ? '' : $tmp[1]) . '/>';
281 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) { // if wysiwyg is enabled $typeofdata = 'ckeditor'
282 $tmp = explode(':', $typeofdata);
283 $cols = (empty($tmp[2]) ? '' : $tmp[2]);
284 $morealt = '';
285 if (preg_match('/%/', $cols)) {
286 $morealt = ' style="width: ' . $cols . '"';
287 $cols = '';
288 }
289 $valuetoshow = ($editvalue ? $editvalue : $value);
290 $ret .= '<textarea id="' . $htmlname . '" name="' . $htmlname . '" wrap="soft" rows="' . (empty($tmp[1]) ? '20' : $tmp[1]) . '"' . ($cols ? ' cols="' . $cols . '"' : 'class="quatrevingtpercent"') . $morealt . '" autofocus>';
291 // textarea convert automatically entities chars into simple chars.
292 // 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.
293 $valuetoshow = str_replace('&', '&amp;', $valuetoshow);
294 $ret .= dol_htmlwithnojs(dol_string_neverthesehtmltags($valuetoshow, array('textarea')));
295 $ret .= '</textarea><div class="clearboth"></div>';
296 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
297 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
298 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
299 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
300 $ret .= $this->selectDate($value, $htmlname, 0, 0, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
301 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
302 $addnowlink = empty($moreoptions['addnowlink']) ? 0 : $moreoptions['addnowlink'];
303 $adddateof = empty($moreoptions['adddateof']) ? '' : $moreoptions['adddateof'];
304 $labeladddateof = empty($moreoptions['labeladddateof']) ? '' : $moreoptions['labeladddateof'];
305 $ret .= $this->selectDate($value, $htmlname, 1, 1, 1, 'form' . $htmlname, 1, $addnowlink, 0, '', '', $adddateof, '', 1, $labeladddateof, '', $gm);
306 } elseif (preg_match('/^select;/', $typeofdata)) {
307 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
308 $arraylist = array();
309 foreach ($arraydata as $val) {
310 $tmp = explode(':', $val);
311 $tmpkey = str_replace('|', ':', $tmp[0]);
312 $arraylist[$tmpkey] = $tmp[1];
313 }
314 $ret .= $this->selectarray($htmlname, $arraylist, $value);
315 } elseif (preg_match('/^link/', $typeofdata)) {
316 // TODO Not yet implemented. See code for extrafields
317 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
318 $tmp = explode(':', $typeofdata); // Example: ckeditor:dolibarr_zzz:width:height:savemethod:toolbarstartexpanded:rows:cols:uselocalbrowser
319 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
320 $doleditor = new DolEditor($htmlname, ($editvalue ? $editvalue : $value), (empty($tmp[2]) ? '' : $tmp[2]), (empty($tmp[3]) ? '100' : $tmp[3]), (empty($tmp[1]) ? 'dolibarr_notes' : $tmp[1]), 'In', (empty($tmp[5]) ? 0 : $tmp[5]), (isset($tmp[8]) ? ($tmp[8] ? true : false) : true), true, (empty($tmp[6]) ? '20' : $tmp[6]), (empty($tmp[7]) ? '100' : $tmp[7]));
321 $ret .= $doleditor->Create(1);
322 } elseif ($typeofdata == 'asis') {
323 $ret .= ($editvalue ? $editvalue : $value);
324 }
325 if (empty($notabletag)) {
326 $ret .= '</td>';
327 }
328
329 // Button save-cancel
330 if (empty($notabletag)) {
331 $ret .= '<td>';
332 }
333 //else $ret.='<div class="clearboth"></div>';
334 $ret .= '<input type="submit" class="smallpaddingimp button' . (empty($notabletag) ? '' : ' ') . '" name="modify" value="' . $langs->trans("Modify") . '">';
335 if (preg_match('/ckeditor|textarea/', $typeofdata) && empty($notabletag)) {
336 $ret .= '<br>' . "\n";
337 }
338 $ret .= '<input type="submit" class="smallpaddingimp button button-cancel' . (empty($notabletag) ? '' : ' ') . '" name="cancel" value="' . $langs->trans("Cancel") . '">';
339 if (empty($notabletag)) {
340 $ret .= '</td>';
341 }
342
343 if (empty($notabletag)) {
344 $ret .= '</tr></table>' . "\n";
345 }
346 $ret .= '</form>' . "\n";
347 } else { // view mode
348 if (preg_match('/^email/', $typeofdata)) {
349 $ret .= dol_print_email($value, 0, 0, 0, 0, 1);
350 } elseif (preg_match('/^phone/', $typeofdata)) {
351 $ret .= dol_print_phone($value, '_blank', 32, 1);
352 } elseif (preg_match('/^url/', $typeofdata)) {
353 $ret .= dol_print_url($value, '_blank', 32, 1);
354 } elseif (preg_match('/^(amount|numeric)/', $typeofdata)) {
355 $ret .= ($value != '' ? price($value, 0, $langs, 0, -1, -1, $conf->currency) : '');
356 } elseif (preg_match('/^checkbox/', $typeofdata)) {
357 $tmp = explode(':', $typeofdata);
358 $ret .= '<input type="checkbox" disabled id="' . $htmlname . '" name="' . $htmlname . '" value="' . $value . '"' . ($value ? ' checked' : '') . ($tmp[1] ? $tmp[1] : '') . '/>';
359 } elseif (preg_match('/^text/', $typeofdata) || preg_match('/^note/', $typeofdata)) {
361 } elseif (preg_match('/^(safehtmlstring|restricthtml)/', $typeofdata)) { // 'restricthtml' is not an allowed type for editfieldval. Value is 'safehtmlstring'
363 } elseif ($typeofdata == 'day' || $typeofdata == 'datepicker') {
364 $ret .= '<span class="valuedate">' . dol_print_date($value, 'day', $gm) . '</span>';
365 } elseif ($typeofdata == 'dayhour' || $typeofdata == 'datehourpicker') {
366 $ret .= '<span class="valuedate">' . dol_print_date($value, 'dayhour', $gm) . '</span>';
367 } elseif (preg_match('/^select;/', $typeofdata)) {
368 $arraydata = explode(',', preg_replace('/^select;/', '', $typeofdata));
369 $arraylist = array();
370 foreach ($arraydata as $val) {
371 $tmp = explode(':', $val);
372 $arraylist[$tmp[0]] = $tmp[1];
373 }
374 $ret .= $arraylist[$value];
375 if ($htmlname == 'fk_product_type') {
376 if ($value == 0) {
377 $ret = img_picto($langs->trans("Product"), 'product', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
378 } else {
379 $ret = img_picto($langs->trans("Service"), 'service', 'class="paddingleftonly paddingrightonly colorgrey"') . $ret;
380 }
381 }
382 } elseif (preg_match('/^ckeditor/', $typeofdata)) {
383 $tmpcontent = dol_htmlentitiesbr($value);
384 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
385 $firstline = preg_replace('/<br>.*/', '', $tmpcontent);
386 $firstline = preg_replace('/[\n\r].*/', '', $firstline);
387 $tmpcontent = $firstline . ((strlen($firstline) != strlen($tmpcontent)) ? '...' : '');
388 }
389 // We don't use dol_escape_htmltag to get the html formatting active, but this need we must also
390 // clean data from some dangerous html
392 } else {
393 if (empty($moreoptions['valuealreadyhtmlescaped'])) {
394 $ret .= dol_escape_htmltag($value);
395 } else {
396 $ret .= $value; // $value must be already html escaped.
397 }
398 }
399
400 // Custom format if parameter $formatfunc has been provided
401 if ($formatfunc && method_exists($object, $formatfunc)) {
402 $ret = $object->$formatfunc($ret);
403 }
404 }
405 }
406 return $ret;
407 }
408
420 public function widgetForTranslation($fieldname, $object, $perm, $typeofdata = 'string', $check = '', $morecss = '')
421 {
422 global $conf, $langs, $extralanguages;
423
424 $result = '';
425
426 // List of extra languages
427 $arrayoflangcode = array();
428 if (getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE')) {
429 $arrayoflangcode[] = getDolGlobalString('PDF_USE_ALSO_LANGUAGE_CODE');
430 }
431
432 if (is_array($arrayoflangcode) && count($arrayoflangcode)) {
433 if (!is_object($extralanguages)) {
434 include_once DOL_DOCUMENT_ROOT . '/core/class/extralanguages.class.php';
435 $extralanguages = new ExtraLanguages($this->db);
436 }
437 $extralanguages->fetch_name_extralanguages('societe');
438
439 if (!is_array($extralanguages->attributes[$object->element]) || empty($extralanguages->attributes[$object->element][$fieldname])) {
440 return ''; // No extralang field to show
441 }
442
443 $result .= '<!-- Widget for translation -->' . "\n";
444 $result .= '<div class="inline-block paddingleft image-' . $object->element . '-' . $fieldname . '">';
445 $s = img_picto($langs->trans("ShowOtherLanguages"), 'language', '', false, 0, 0, '', 'fa-15 editfieldlang');
446 $result .= $s;
447 $result .= '</div>';
448
449 $result .= '<div class="inline-block hidden field-' . $object->element . '-' . $fieldname . '">';
450
451 $resultforextrlang = '';
452 foreach ($arrayoflangcode as $langcode) {
453 $valuetoshow = GETPOSTISSET('field-' . $object->element . "-" . $fieldname . "-" . $langcode) ? GETPOST('field-' . $object->element . '-' . $fieldname . "-" . $langcode, $check) : '';
454 if (empty($valuetoshow)) {
455 $object->fetchValuesForExtraLanguages();
456 //var_dump($object->array_languages);
457 $valuetoshow = $object->array_languages[$fieldname][$langcode];
458 }
459
460 $s = picto_from_langcode($langcode, 'class="pictoforlang paddingright"');
461 $resultforextrlang .= $s;
462
463 // TODO Use the showInputField() method of ExtraLanguages object
464 if ($typeofdata == 'textarea') {
465 $resultforextrlang .= '<textarea name="field-' . $object->element . "-" . $fieldname . "-" . $langcode . '" id="' . $fieldname . "-" . $langcode . '" class="' . $morecss . '" rows="' . ROWS_2 . '" wrap="soft">';
466 $resultforextrlang .= $valuetoshow;
467 $resultforextrlang .= '</textarea>';
468 } else {
469 $resultforextrlang .= '<input type="text" class="inputfieldforlang ' . ($morecss ? ' ' . $morecss : '') . '" name="field-' . $object->element . '-' . $fieldname . '-' . $langcode . '" value="' . $valuetoshow . '">';
470 }
471 }
472 $result .= $resultforextrlang;
473
474 $result .= '</div>';
475 $result .= '<script nonce="' . getNonce() . '">$(".image-' . $object->element . '-' . $fieldname . '").click(function() { console.log("Toggle lang widget"); jQuery(".field-' . $object->element . '-' . $fieldname . '").toggle(); });</script>';
476 }
477
478 return $result;
479 }
480
494 protected function editInPlace($object, $value, $htmlname, $condition, $inputType = 'textarea', $editvalue = null, $extObject = null, $custommsg = null)
495 {
496 $out = '';
497
498 // Check parameters
499 if (preg_match('/^text/', $inputType)) {
500 $value = dol_nl2br($value);
501 } elseif (preg_match('/^numeric/', $inputType)) {
502 $value = price($value);
503 } elseif ($inputType == 'day' || $inputType == 'datepicker') {
504 $value = dol_print_date($value, 'day');
505 }
506
507 if ($condition) {
508 $element = false;
509 $table_element = false;
510 $fk_element = false;
511 $loadmethod = false;
512 $savemethod = false;
513 $ext_element = false;
514 $button_only = false;
515 $inputOption = '';
516 $rows = '';
517 $cols = '';
518
519 if (is_object($object)) {
520 $element = $object->element;
521 $table_element = $object->table_element;
522 $fk_element = $object->id;
523 }
524
525 if (is_object($extObject)) {
526 $ext_element = $extObject->element;
527 }
528
529 if (preg_match('/^(string|email|numeric)/', $inputType)) {
530 $tmp = explode(':', $inputType);
531 $inputType = $tmp[0];
532 if (!empty($tmp[1])) {
533 $inputOption = $tmp[1];
534 }
535 if (!empty($tmp[2])) {
536 $savemethod = $tmp[2];
537 }
538 $out .= '<input id="width_' . $htmlname . '" value="' . $inputOption . '" type="hidden"/>' . "\n";
539 } elseif ((preg_match('/^day$/', $inputType)) || (preg_match('/^datepicker/', $inputType)) || (preg_match('/^datehourpicker/', $inputType))) {
540 $tmp = explode(':', $inputType);
541 $inputType = $tmp[0];
542 if (!empty($tmp[1])) {
543 $inputOption = $tmp[1];
544 }
545 if (!empty($tmp[2])) {
546 $savemethod = $tmp[2];
547 }
548
549 $out .= '<input id="timestamp" type="hidden"/>' . "\n"; // Use for timestamp format
550 } elseif (preg_match('/^(select|autocomplete)/', $inputType)) {
551 $tmp = explode(':', $inputType);
552 $inputType = $tmp[0];
553 $loadmethod = $tmp[1];
554 if (!empty($tmp[2])) {
555 $savemethod = $tmp[2];
556 }
557 if (!empty($tmp[3])) {
558 $button_only = true;
559 }
560 } elseif (preg_match('/^textarea/', $inputType)) {
561 $tmp = explode(':', $inputType);
562 $inputType = $tmp[0];
563 $rows = (empty($tmp[1]) ? '8' : $tmp[1]);
564 $cols = (empty($tmp[2]) ? '80' : $tmp[2]);
565 } elseif (preg_match('/^ckeditor/', $inputType)) {
566 $tmp = explode(':', $inputType);
567 $inputType = $tmp[0];
568 $toolbar = $tmp[1];
569 if (!empty($tmp[2])) {
570 $width = $tmp[2];
571 }
572 if (!empty($tmp[3])) {
573 $height = $tmp[3];
574 }
575 if (!empty($tmp[4])) {
576 $savemethod = $tmp[4];
577 }
578
579 if (isModEnabled('fckeditor')) {
580 $out .= '<input id="ckeditor_toolbar" value="' . $toolbar . '" type="hidden"/>' . "\n";
581 } else {
582 $inputType = 'textarea';
583 }
584 }
585
586 $out .= '<input id="element_' . $htmlname . '" value="' . $element . '" type="hidden"/>' . "\n";
587 $out .= '<input id="table_element_' . $htmlname . '" value="' . $table_element . '" type="hidden"/>' . "\n";
588 $out .= '<input id="fk_element_' . $htmlname . '" value="' . $fk_element . '" type="hidden"/>' . "\n";
589 $out .= '<input id="loadmethod_' . $htmlname . '" value="' . $loadmethod . '" type="hidden"/>' . "\n";
590 if (!empty($savemethod)) {
591 $out .= '<input id="savemethod_' . $htmlname . '" value="' . $savemethod . '" type="hidden"/>' . "\n";
592 }
593 if (!empty($ext_element)) {
594 $out .= '<input id="ext_element_' . $htmlname . '" value="' . $ext_element . '" type="hidden"/>' . "\n";
595 }
596 if (!empty($custommsg)) {
597 if (is_array($custommsg)) {
598 if (!empty($custommsg['success'])) {
599 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg['success'] . '" type="hidden"/>' . "\n";
600 }
601 if (!empty($custommsg['error'])) {
602 $out .= '<input id="errormsg_' . $htmlname . '" value="' . $custommsg['error'] . '" type="hidden"/>' . "\n";
603 }
604 } else {
605 $out .= '<input id="successmsg_' . $htmlname . '" value="' . $custommsg . '" type="hidden"/>' . "\n";
606 }
607 }
608 if ($inputType == 'textarea') {
609 $out .= '<input id="textarea_' . $htmlname . '_rows" value="' . $rows . '" type="hidden"/>' . "\n";
610 $out .= '<input id="textarea_' . $htmlname . '_cols" value="' . $cols . '" type="hidden"/>' . "\n";
611 }
612 $out .= '<span id="viewval_' . $htmlname . '" class="viewval_' . $inputType . ($button_only ? ' inactive' : ' active') . '">' . $value . '</span>' . "\n";
613 $out .= '<span id="editval_' . $htmlname . '" class="editval_' . $inputType . ($button_only ? ' inactive' : ' active') . ' hideobject">' . (!empty($editvalue) ? $editvalue : $value) . '</span>' . "\n";
614 } else {
615 $out = $value;
616 }
617
618 return $out;
619 }
620
639 public function textwithtooltip($text, $htmltext, $tooltipon = 1, $direction = 0, $img = '', $extracss = '', $notabs = 3, $incbefore = '', $noencodehtmltext = 0, $tooltiptrigger = '', $forcenowrap = 0)
640 {
641 if ($incbefore) {
642 $text = $incbefore . $text;
643 }
644 if (!$htmltext) {
645 return $text;
646 }
647 $direction = (int) $direction; // For backward compatibility when $direction was set to '' instead of 0
648
649 $tag = 'td';
650 if ($notabs == 2) {
651 $tag = 'div';
652 }
653 if ($notabs == 3) {
654 $tag = 'span';
655 }
656 // Sanitize tooltip
657 $htmltext = str_replace(array("\r", "\n"), '', $htmltext);
658
659 $extrastyle = '';
660 if ($direction < 0) {
661 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
662 $extrastyle = 'padding: 0px; padding-left: 2px;';
663 }
664 if ($direction > 0) {
665 $extracss = ($extracss ? $extracss . ' ' : '') . ($notabs != 3 ? 'inline-block' : '');
666 $extrastyle = 'padding: 0px; padding-right: 2px;';
667 }
668
669 $classfortooltip = 'classfortooltip';
670
671 $s = '';
672 $textfordialog = '';
673
674 if ($tooltiptrigger == '') {
675 $htmltext = str_replace('"', '&quot;', $htmltext);
676 } else {
677 $classfortooltip = 'classfortooltiponclick';
678 $textfordialog .= '<div style="display: none;" id="idfortooltiponclick_' . $tooltiptrigger . '" class="classfortooltiponclicktext">' . $htmltext . '</div>';
679 }
680 if ($tooltipon == 2 || $tooltipon == 3) {
681 $paramfortooltipimg = ' class="' . $classfortooltip . ($notabs != 3 ? ' inline-block' : '') . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '"';
682 if ($tooltiptrigger == '') {
683 $paramfortooltipimg .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on img tag to store tooltip
684 } else {
685 $paramfortooltipimg .= ' dolid="' . $tooltiptrigger . '"';
686 }
687 } else {
688 $paramfortooltipimg = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
689 }
690 if ($tooltipon == 1 || $tooltipon == 3) {
691 $paramfortooltiptd = ' class="' . ($tooltipon == 3 ? 'cursorpointer ' : '') . $classfortooltip . ' inline-block' . ($extracss ? ' ' . $extracss : '') . '" style="padding: 0px;' . ($extrastyle ? ' ' . $extrastyle : '') . '" ';
692 if ($tooltiptrigger == '') {
693 $paramfortooltiptd .= ' title="' . ($noencodehtmltext ? $htmltext : dol_escape_htmltag($htmltext, 1)) . '"'; // Attribute to put on td tag to store tooltip
694 } else {
695 $paramfortooltiptd .= ' dolid="' . $tooltiptrigger . '"';
696 }
697 } else {
698 $paramfortooltiptd = ($extracss ? ' class="' . $extracss . '"' : '') . ($extrastyle ? ' style="' . $extrastyle . '"' : ''); // Attribute to put on td text tag
699 }
700 if (empty($notabs)) {
701 $s .= '<table class="nobordernopadding"><tr style="height: auto;">';
702 } elseif ($notabs == 2) {
703 $s .= '<div class="inline-block' . ($forcenowrap ? ' nowrap' : '') . '">';
704 }
705 // Define value if value is before
706 if ($direction < 0) {
707 $s .= '<' . $tag . $paramfortooltipimg;
708 if ($tag == 'td') {
709 $s .= ' class="valigntop" width="14"';
710 }
711 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
712 }
713 // Use another method to help avoid having a space in value in order to use this value with jquery
714 // Define label
715 if ((string) $text != '') {
716 $s .= '<' . $tag . $paramfortooltiptd . '>' . $text . '</' . $tag . '>';
717 }
718 // Define value if value is after
719 if ($direction > 0) {
720 $s .= '<' . $tag . $paramfortooltipimg;
721 if ($tag == 'td') {
722 $s .= ' class="valignmiddle" width="14"';
723 }
724 $s .= '>' . $textfordialog . $img . '</' . $tag . '>';
725 }
726 if (empty($notabs)) {
727 $s .= '</tr></table>';
728 } elseif ($notabs == 2) {
729 $s .= '</div>';
730 }
731
732 return $s;
733 }
734
749 public function textwithpicto($text, $htmltext, $direction = 1, $type = 'help', $extracss = '', $noencodehtmltext = 0, $notabs = 3, $tooltiptrigger = '', $forcenowrap = 0)
750 {
751 global $conf, $langs;
752
753 //For backwards compatibility
754 if ($type == '0') {
755 $type = 'info';
756 } elseif ($type == '1') {
757 $type = 'help';
758 }
759 // Clean parameters
760 $tooltiptrigger = preg_replace('/[^a-z0-9]/i', '', $tooltiptrigger);
761
762 if (preg_match('/onsmartphone$/', $tooltiptrigger) && empty($conf->dol_no_mouse_hover)) {
763 $tooltiptrigger = preg_replace('/^.*onsmartphone$/', '', $tooltiptrigger);
764 }
765 $alt = '';
766 if ($tooltiptrigger) {
767 $alt = $langs->transnoentitiesnoconv("ClickToShowHelp");
768 }
769
770 // If info or help with no javascript, show only text
771 if (empty($conf->use_javascript_ajax)) {
772 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
773 return $text;
774 } else {
775 $alt = $htmltext;
776 $htmltext = '';
777 }
778 }
779
780 // If info or help with smartphone, show only text (tooltip hover can't works)
781 if (!empty($conf->dol_no_mouse_hover) && empty($tooltiptrigger)) {
782 if ($type == 'info' || $type == 'infoclickable' || $type == 'help' || $type == 'helpclickable') {
783 return $text;
784 }
785 }
786 // If info or help with smartphone, show only text (tooltip on click does not works with dialog on smaprtphone)
787 //if (!empty($conf->dol_no_mouse_hover) && !empty($tooltiptrigger))
788 //{
789 //if ($type == 'info' || $type == 'help') return '<a href="'..'">'.$text.'</a>';
790 //}
791
792 $img = '';
793 if ($type == 'info') {
794 $img = img_help(0, $alt);
795 } elseif ($type == 'help') {
796 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
797 } elseif ($type == 'helpclickable') {
798 $img = img_help(($tooltiptrigger != '' ? 2 : 1), $alt);
799 } elseif ($type == 'superadmin') {
800 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
801 $img = img_picto($alt, 'redstar');
802 } elseif ($type == 'admin') {
803 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
804 $img = img_picto($alt, 'star');
805 } elseif ($type == 'warning') {
806 $img = img_warning($alt);
807 } elseif ($type != 'none') {
808 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
809 $img = img_picto($alt, $type); // $type can be an image path
810 }
811
812 return $this->textwithtooltip($text, $htmltext, ((($tooltiptrigger && !$img) || strpos($type, 'clickable')) ? 3 : 2), $direction, $img, $extracss, $notabs, '', $noencodehtmltext, $tooltiptrigger, $forcenowrap);
813 }
814
825 public function selectMassAction($selected, $arrayofaction, $alwaysvisible = 0, $name = 'massaction', $cssclass = 'checkforselect')
826 {
827 global $conf, $langs, $hookmanager;
828
829 $disabled = 0;
830 $ret = '<div class="centpercent center">';
831 $ret .= '<select class="flat' . (empty($conf->use_javascript_ajax) ? '' : ' hideobject') . ' ' . $name . ' ' . $name . 'select valignmiddle alignstart" id="' . $name . '" name="' . $name . '"' . ($disabled ? ' disabled="disabled"' : '') . '>';
832
833 // 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.
834 $parameters = array();
835 $reshook = $hookmanager->executeHooks('addMoreMassActions', $parameters); // Note that $action and $object may have been modified by hook
836 // check if there is a mass action
837
838 if (is_array($arrayofaction) && count($arrayofaction) == 0 && empty($hookmanager->resPrint)) {
839 return;
840 }
841 if (empty($reshook)) {
842 $ret .= '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>-- ' . $langs->trans("SelectAction") . ' --</option>';
843 if (is_array($arrayofaction)) {
844 foreach ($arrayofaction as $code => $label) {
845 $ret .= '<option value="' . $code . '"' . ($disabled ? ' disabled="disabled"' : '') . ' data-html="' . dol_escape_htmltag($label) . '">' . $label . '</option>';
846 }
847 }
848 }
849 $ret .= $hookmanager->resPrint;
850
851 $ret .= '</select>';
852
853 if (empty($conf->dol_optimize_smallscreen)) {
854 $ret .= ajax_combobox('.' . $name . 'select');
855 }
856
857 // 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
858 $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.
859 $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")) . '">';
860 $ret .= '</div>';
861
862 if (!empty($conf->use_javascript_ajax)) {
863 $ret .= '<!-- JS CODE TO ENABLE mass action select -->
864 <script nonce="' . getNonce() . '">
865 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 */
866 {
867 atleastoneselected=0;
868 jQuery("."+cssclass).each(function( index ) {
869 /* console.log( index + ": " + $( this ).text() ); */
870 if ($(this).is(\':checked\')) atleastoneselected++;
871 });
872
873 console.log("initCheckForSelect mode="+mode+" name="+name+" cssclass="+cssclass+" atleastoneselected="+atleastoneselected);
874
875 if (atleastoneselected || ' . $alwaysvisible . ')
876 {
877 jQuery("."+name).show();
878 ' . ($selected ? 'if (atleastoneselected) { jQuery("."+name+"select").val("' . $selected . '").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', false); }' : '') . '
879 ' . ($selected ? 'if (! atleastoneselected) { jQuery("."+name+"select").val("0").trigger(\'change\'); jQuery("."+name+"confirmed").prop(\'disabled\', true); } ' : '') . '
880 }
881 else
882 {
883 jQuery("."+name).hide();
884 jQuery("."+name+"other").hide();
885 }
886 }
887
888 jQuery(document).ready(function () {
889 initCheckForSelect(0, "' . $name . '", "' . $cssclass . '");
890 jQuery(".' . $cssclass . '").click(function() {
891 initCheckForSelect(1, "' . $name . '", "' . $cssclass . '");
892 });
893 jQuery(".' . $name . 'select").change(function() {
894 var massaction = $( this ).val();
895 var urlform = $( this ).closest("form").attr("action").replace("#show_files","");
896 if (massaction == "builddoc")
897 {
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 {
905 jQuery(".' . $name . 'confirmed").prop(\'disabled\', false);
906 jQuery(".' . $name . 'other").hide(); /* To disable if another div was open */
907 jQuery(".' . $name . '"+massaction).show();
908 }
909 else
910 {
911 jQuery(".' . $name . 'confirmed").prop(\'disabled\', true);
912 jQuery(".' . $name . 'other").hide(); /* To disable any div open */
913 }
914 });
915 });
916 </script>
917 ';
918 }
919
920 return $ret;
921 }
922
923 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
924
941 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)
942 {
943 // phpcs:enable
944 global $conf, $langs, $mysoc;
945
946 $langs->load("dict");
947
948 $out = '';
949 $countryArray = array();
950 $favorite = array();
951 $label = array();
952 $atleastonefavorite = 0;
953
954 $sql = "SELECT rowid, code as code_iso, code_iso as code_iso3, label, favorite, eec";
955 $sql .= " FROM " . $this->db->prefix() . "c_country";
956 $sql .= " WHERE active > 0";
957 //$sql.= " ORDER BY code ASC";
958
959 dol_syslog(get_class($this) . "::select_country", LOG_DEBUG);
960 $resql = $this->db->query($sql);
961 if ($resql) {
962 $out .= '<select id="select' . $htmlname . '" class="flat maxwidth200onsmartphone selectcountry' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" ' . $htmloption . '>';
963 $num = $this->db->num_rows($resql);
964 $i = 0;
965 if ($num) {
966 while ($i < $num) {
967 $obj = $this->db->fetch_object($resql);
968
969 $countryArray[$i]['rowid'] = $obj->rowid;
970 $countryArray[$i]['code_iso'] = $obj->code_iso;
971 $countryArray[$i]['code_iso3'] = $obj->code_iso3;
972 $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 : ''));
973 $countryArray[$i]['favorite'] = $obj->favorite;
974 $countryArray[$i]['eec'] = $obj->eec;
975 $favorite[$i] = $obj->favorite;
976 $label[$i] = dol_string_unaccent($countryArray[$i]['label']);
977 $i++;
978 }
979
980 if (empty($disablefavorites)) {
981 $array1_sort_order = SORT_DESC;
982 $array2_sort_order = SORT_ASC;
983 array_multisort($favorite, $array1_sort_order, $label, $array2_sort_order, $countryArray);
984 } else {
985 $countryArray = dol_sort_array($countryArray, 'label');
986 }
987
988 if ($showempty) {
989 if (is_numeric($showempty)) {
990 $out .= '<option value="">&nbsp;</option>' . "\n";
991 } else {
992 $out .= '<option value="-1">' . $langs->trans($showempty) . '</option>' . "\n";
993 }
994 }
995
996 if ($addspecialentries) { // Add dedicated entries for groups of countries
997 //if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
998 $out .= '<option value="special_allnotme"' . ($selected == 'special_allnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
999 $out .= '<option value="special_eec"' . ($selected == 'special_eec' ? ' selected' : '') . '>' . $langs->trans("CountriesInEEC") . '</option>';
1000 if ($mysoc->isInEEC()) {
1001 $out .= '<option value="special_eecnotme"' . ($selected == 'special_eecnotme' ? ' selected' : '') . '>' . $langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country" . $mysoc->country_code)) . '</option>';
1002 }
1003 $out .= '<option value="special_noteec"' . ($selected == 'special_noteec' ? ' selected' : '') . '>' . $langs->trans("CountriesNotInEEC") . '</option>';
1004 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1005 }
1006
1007 foreach ($countryArray as $row) {
1008 //if (empty($showempty) && empty($row['rowid'])) continue;
1009 if (empty($row['rowid'])) {
1010 continue;
1011 }
1012 if (is_array($exclude_country_code) && count($exclude_country_code) && in_array($row['code_iso'], $exclude_country_code)) {
1013 continue; // exclude some countries
1014 }
1015
1016 if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) {
1017 $atleastonefavorite++;
1018 }
1019 if (empty($row['favorite']) && $atleastonefavorite) {
1020 $atleastonefavorite = 0;
1021 $out .= '<option value="" disabled class="selectoptiondisabledwhite">------------</option>';
1022 }
1023
1024 $labeltoshow = '';
1025 if ($row['label']) {
1026 $labeltoshow .= dol_trunc($row['label'], $maxlength, 'middle');
1027 } else {
1028 $labeltoshow .= '&nbsp;';
1029 }
1030 if ($row['code_iso']) {
1031 $labeltoshow .= ' <span class="opacitymedium">(' . $row['code_iso'] . ')</span>';
1032 if (empty($hideflags)) {
1033 $tmpflag = picto_from_langcode($row['code_iso'], 'class="saturatemedium paddingrightonly"', 1);
1034 $labeltoshow = $tmpflag . ' ' . $labeltoshow;
1035 }
1036 }
1037
1038 if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label'])) {
1039 $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']) . '">';
1040 } else {
1041 $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']) . '">';
1042 }
1043 $out .= $labeltoshow;
1044 $out .= '</option>' . "\n";
1045 }
1046 }
1047 $out .= '</select>';
1048 } else {
1049 dol_print_error($this->db);
1050 }
1051
1052 // Make select dynamic
1053 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1054 $out .= ajax_combobox('select' . $htmlname, array(), 0, 0, 'resolve');
1055
1056 return $out;
1057 }
1058
1059 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1060
1074 public function select_incoterms($selected = '', $location_incoterms = '', $page = '', $htmlname = 'incoterm_id', $htmloption = '', $forcecombo = 1, $events = array(), $disableautocomplete = 0)
1075 {
1076 // phpcs:enable
1077 global $conf, $langs;
1078
1079 $langs->load("dict");
1080
1081 $out = '';
1082 $moreattrib = '';
1083 $incotermArray = array();
1084
1085 $sql = "SELECT rowid, code";
1086 $sql .= " FROM " . $this->db->prefix() . "c_incoterms";
1087 $sql .= " WHERE active > 0";
1088 $sql .= " ORDER BY code ASC";
1089
1090 dol_syslog(get_class($this) . "::select_incoterm", LOG_DEBUG);
1091 $resql = $this->db->query($sql);
1092 if ($resql) {
1093 if ($conf->use_javascript_ajax && !$forcecombo) {
1094 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1095 $out .= ajax_combobox($htmlname, $events);
1096 }
1097
1098 if (!empty($page)) {
1099 $out .= '<form method="post" action="' . $page . '">';
1100 $out .= '<input type="hidden" name="action" value="set_incoterms">';
1101 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
1102 }
1103
1104 $out .= '<select id="' . $htmlname . '" class="flat selectincoterm width75" name="' . $htmlname . '" ' . $htmloption . '>';
1105 $out .= '<option value="0">&nbsp;</option>';
1106 $num = $this->db->num_rows($resql);
1107 $i = 0;
1108 if ($num) {
1109 while ($i < $num) {
1110 $obj = $this->db->fetch_object($resql);
1111 $incotermArray[$i]['rowid'] = $obj->rowid;
1112 $incotermArray[$i]['code'] = $obj->code;
1113 $i++;
1114 }
1115
1116 foreach ($incotermArray as $row) {
1117 if ($selected && ($selected == $row['rowid'] || $selected == $row['code'])) {
1118 $out .= '<option value="' . $row['rowid'] . '" selected>';
1119 } else {
1120 $out .= '<option value="' . $row['rowid'] . '">';
1121 }
1122
1123 if ($row['code']) {
1124 $out .= $row['code'];
1125 }
1126
1127 $out .= '</option>';
1128 }
1129 }
1130 $out .= '</select>';
1131
1132 if ($conf->use_javascript_ajax && empty($disableautocomplete)) {
1133 $out .= ajax_multiautocompleter('location_incoterms', array(), DOL_URL_ROOT . '/core/ajax/locationincoterms.php') . "\n";
1134 $moreattrib .= ' autocomplete="off"';
1135 }
1136 $out .= '<input id="location_incoterms" class="maxwidthonsmartphone type="text" name="location_incoterms" value="' . $location_incoterms . '">' . "\n";
1137
1138 if (!empty($page)) {
1139 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp nomargintop nomarginbottom" value="' . $langs->trans("Modify") . '"></form>';
1140 }
1141 } else {
1142 dol_print_error($this->db);
1143 }
1144
1145 return $out;
1146 }
1147
1148 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1149
1162 public function select_type_of_lines($selected = '', $htmlname = 'type', $showempty = 0, $hidetext = 0, $forceall = 0, $morecss = "")
1163 {
1164 // phpcs:enable
1165 global $langs;
1166
1167 // If product & services are enabled or both disabled.
1168 if ($forceall == 1 || (empty($forceall) && isModEnabled("product") && isModEnabled("service"))
1169 || (empty($forceall) && !isModEnabled('product') && !isModEnabled('service'))) {
1170 if (empty($hidetext)) {
1171 print $langs->trans("Type") . ': ';
1172 }
1173 print '<select class="flat'.($morecss ? ' '.$morecss : '').'" id="select_' . $htmlname . '" name="' . $htmlname . '">';
1174 if ($showempty) {
1175 print '<option value="-1"';
1176 if ($selected == -1) {
1177 print ' selected';
1178 }
1179 print '>';
1180 if (is_numeric($showempty)) {
1181 print '&nbsp;';
1182 } else {
1183 print $showempty;
1184 }
1185 print '</option>';
1186 }
1187
1188 print '<option value="0"';
1189 if (0 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'product')) {
1190 print ' selected';
1191 }
1192 print '>' . $langs->trans("Product");
1193
1194 print '<option value="1"';
1195 if (1 == $selected || ($selected == -1 && getDolGlobalString('MAIN_FREE_PRODUCT_CHECKED_BY_DEFAULT') == 'service')) {
1196 print ' selected';
1197 }
1198 print '>' . $langs->trans("Service");
1199
1200 print '</select>';
1201 print ajax_combobox('select_' . $htmlname);
1202 //if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
1203 }
1204 if ((empty($forceall) && !isModEnabled('product') && isModEnabled("service")) || $forceall == 3) {
1205 print $langs->trans("Service");
1206 print '<input type="hidden" name="' . $htmlname . '" value="1">';
1207 }
1208 if ((empty($forceall) && isModEnabled("product") && !isModEnabled('service')) || $forceall == 2) {
1209 print $langs->trans("Product");
1210 print '<input type="hidden" name="' . $htmlname . '" value="0">';
1211 }
1212 if ($forceall < 0) { // This should happened only for contracts when both predefined product and service are disabled.
1213 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
1214 }
1215 }
1216
1217 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1218
1224 public function load_cache_types_fees()
1225 {
1226 // phpcs:enable
1227 global $langs;
1228
1229 $num = count($this->cache_types_fees);
1230 if ($num > 0) {
1231 return 0; // Cache already loaded
1232 }
1233
1234 dol_syslog(__METHOD__, LOG_DEBUG);
1235
1236 $langs->load("trips");
1237
1238 $sql = "SELECT c.code, c.label";
1239 $sql .= " FROM " . $this->db->prefix() . "c_type_fees as c";
1240 $sql .= " WHERE active > 0";
1241
1242 $resql = $this->db->query($sql);
1243 if ($resql) {
1244 $num = $this->db->num_rows($resql);
1245 $i = 0;
1246
1247 while ($i < $num) {
1248 $obj = $this->db->fetch_object($resql);
1249
1250 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
1251 $label = ($obj->code != $langs->trans($obj->code) ? $langs->trans($obj->code) : $langs->trans($obj->label));
1252 $this->cache_types_fees[$obj->code] = $label;
1253 $i++;
1254 }
1255
1256 asort($this->cache_types_fees);
1257
1258 return $num;
1259 } else {
1260 dol_print_error($this->db);
1261 return -1;
1262 }
1263 }
1264
1265 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1266
1275 public function select_type_fees($selected = '', $htmlname = 'type', $showempty = 0)
1276 {
1277 // phpcs:enable
1278 global $user, $langs;
1279
1280 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
1281
1282 $this->load_cache_types_fees();
1283
1284 print '<select id="select_' . $htmlname . '" class="flat" name="' . $htmlname . '">';
1285 if ($showempty) {
1286 print '<option value="-1"';
1287 if ($selected == -1) {
1288 print ' selected';
1289 }
1290 print '>&nbsp;</option>';
1291 }
1292
1293 foreach ($this->cache_types_fees as $key => $value) {
1294 print '<option value="' . $key . '"';
1295 if ($key == $selected) {
1296 print ' selected';
1297 }
1298 print '>';
1299 print $value;
1300 print '</option>';
1301 }
1302
1303 print '</select>';
1304 if ($user->admin) {
1305 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1306 }
1307 }
1308
1309
1310 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1311
1334 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)
1335 {
1336 // phpcs:enable
1337 global $conf, $langs;
1338
1339 $out = '';
1340
1341 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1342 if (is_null($ajaxoptions)) {
1343 $ajaxoptions = array();
1344 }
1345
1346 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1347
1348 // No immediate load of all database
1349 $placeholder = '';
1350 if ($selected && empty($selected_input_value)) {
1351 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
1352 $societetmp = new Societe($this->db);
1353 $societetmp->fetch($selected);
1354 $selected_input_value = $societetmp->name;
1355 unset($societetmp);
1356 }
1357
1358 // mode 1
1359 $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)) : '');
1360
1361 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1362 if (empty($hidelabel)) {
1363 $out .= $langs->trans("RefOrLabel") . ' : ';
1364 } elseif ($hidelabel > 1) {
1365 $placeholder = $langs->trans("RefOrLabel");
1366 if ($hidelabel == 2) {
1367 $out .= img_picto($langs->trans("Search"), 'search');
1368 }
1369 }
1370 $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' : '') . ' />';
1371 if ($hidelabel == 3) {
1372 $out .= img_picto($langs->trans("Search"), 'search');
1373 }
1374
1375 $out .= ajax_event($htmlname, $events);
1376
1377 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/societe/ajax/company.php', $urloption, getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
1378 } else {
1379 // Immediate load of all database
1380 $out .= $this->select_thirdparty_list($selected, $htmlname, $filter, $showempty, $showtype, $forcecombo, $events, '', 0, $limit, $morecss, $moreparam, $multiple, $excludeids, $showcode);
1381 }
1382
1383 return $out;
1384 }
1385
1386
1387 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1388
1414 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 = '')
1415 {
1416 // phpcs:enable
1417
1418 global $conf, $langs;
1419
1420 $out = '';
1421
1422 $sav = getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT');
1423 if ($nokeyifsocid && $socid > 0) {
1424 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = 0;
1425 }
1426
1427 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT') && !$forcecombo) {
1428 if (is_null($events)) {
1429 $events = array();
1430 }
1431
1432 require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1433
1434 // No immediate load of all database
1435 $placeholder = '';
1436 if ($selected && empty($selected_input_value)) {
1437 require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1438 $contacttmp = new Contact($this->db);
1439 $contacttmp->fetch($selected);
1440 $selected_input_value = $contacttmp->getFullName($langs);
1441 unset($contacttmp);
1442 }
1443 if (!is_numeric($showempty)) {
1444 $placeholder = $showempty;
1445 }
1446
1447 // mode 1
1448 $urloption = 'htmlname=' . urlencode((string) (str_replace('.', '_', $htmlname))) . '&outjson=1&filter=' . urlencode((string) ($filter)) . (empty($exclude) ? '' : '&exclude=' . urlencode($exclude)) . ($showsoc ? '&showsoc=' . urlencode((string) ($showsoc)) : '');
1449
1450 $out .= '<!-- force css to be higher than dialog popup --><style type="text/css">.ui-autocomplete { z-index: 1010; }</style>';
1451
1452 $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' : '') . ' />';
1453
1454 $out .= ajax_event($htmlname, $events);
1455
1456 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT.'/contact/ajax/contact.php', $urloption, getDolGlobalString('CONTACT_USE_SEARCH_TO_SELECT'), 0, $events);
1457 } else {
1458 // Immediate load of all database
1459 $multiple = false;
1460 $disableifempty = 0;
1461 $options_only = false;
1462 $limitto = '';
1463
1464 $out .= $this->selectcontacts($socid, $selected, $htmlname, $showempty, $exclude, $limitto, $showfunction, $morecss, $options_only, $showsoc, $forcecombo, $events, $moreparam, $htmlid, $multiple, $disableifempty);
1465 }
1466
1467 $conf->global->CONTACT_USE_SEARCH_TO_SELECT = $sav;
1468
1469 return $out;
1470 }
1471
1472
1473 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1474
1499 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)
1500 {
1501 // phpcs:enable
1502 global $user, $langs;
1503 global $hookmanager;
1504
1505 $out = '';
1506 $num = 0;
1507 $outarray = array();
1508
1509 if ($selected === '') {
1510 $selected = array();
1511 } elseif (!is_array($selected)) {
1512 $selected = array($selected);
1513 }
1514
1515 // Clean $filter that may contains sql conditions so sql code
1516 if (function_exists('testSqlAndScriptInject')) {
1517 if (testSqlAndScriptInject($filter, 3) > 0) {
1518 $filter = '';
1519 return 'SQLInjectionTryDetected';
1520 }
1521 }
1522
1523 if ($filter != '') { // If a filter was provided
1524 if (preg_match('/[\‍(\‍)]/', $filter)) {
1525 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1526 $errormsg = '';
1527 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1528
1529 // Redo clean $filter that may contains sql conditions so sql code
1530 if (function_exists('testSqlAndScriptInject')) {
1531 if (testSqlAndScriptInject($filter, 3) > 0) {
1532 $filter = '';
1533 return 'SQLInjectionTryDetected';
1534 }
1535 }
1536 } else {
1537 // If not, we do nothing. We already know that there is no parenthesis
1538 // TODO Disallow this case in a future.
1539 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Syntax.", LOG_WARNING);
1540 }
1541 }
1542
1543 // We search companies
1544 $sql = "SELECT s.rowid, s.nom as name, s.name_alias, s.tva_intra, s.client, s.fournisseur, s.code_client, s.code_fournisseur";
1545 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1546 $sql .= ", s.address, s.zip, s.town";
1547 $sql .= ", dictp.code as country_code";
1548 }
1549 $sql .= " FROM " . $this->db->prefix() . "societe as s";
1550 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1551 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_country as dictp ON dictp.rowid = s.fk_pays";
1552 }
1553 if (!$user->hasRight('societe', 'client', 'voir')) {
1554 $sql .= ", " . $this->db->prefix() . "societe_commerciaux as sc";
1555 }
1556 $sql .= " WHERE s.entity IN (" . getEntity('societe') . ")";
1557 if (!empty($user->socid)) {
1558 $sql .= " AND s.rowid = " . ((int) $user->socid);
1559 }
1560 if ($filter) {
1561 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1562 // if not, by testSqlAndScriptInject() only.
1563 $sql .= " AND (" . $filter . ")";
1564 }
1565 if (!$user->hasRight('societe', 'client', 'voir')) {
1566 $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . ((int) $user->id);
1567 }
1568 if (getDolGlobalString('COMPANY_HIDE_INACTIVE_IN_COMBOBOX')) {
1569 $sql .= " AND s.status <> 0";
1570 }
1571 if (!empty($excludeids)) {
1572 $sql .= " AND s.rowid NOT IN (" . $this->db->sanitize(implode(',', $excludeids)) . ")";
1573 }
1574 // Add where from hooks
1575 $parameters = array();
1576 $reshook = $hookmanager->executeHooks('selectThirdpartyListWhere', $parameters); // Note that $action and $object may have been modified by hook
1577 $sql .= $hookmanager->resPrint;
1578 // Add criteria
1579 if ($filterkey && $filterkey != '') {
1580 $sql .= " AND (";
1581 $prefix = !getDolGlobalString('COMPANY_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if COMPANY_DONOTSEARCH_ANYWHERE is on
1582 // For natural search
1583 $search_crit = explode(' ', $filterkey);
1584 $i = 0;
1585 if (count($search_crit) > 1) {
1586 $sql .= "(";
1587 }
1588 foreach ($search_crit as $crit) {
1589 if ($i > 0) {
1590 $sql .= " AND ";
1591 }
1592 $sql .= "(s.nom LIKE '" . $this->db->escape($prefix . $crit) . "%')";
1593 $i++;
1594 }
1595 if (count($search_crit) > 1) {
1596 $sql .= ")";
1597 }
1598 if (isModEnabled('barcode')) {
1599 $sql .= " OR s.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1600 }
1601 $sql .= " OR s.code_client LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.code_fournisseur LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1602 $sql .= " OR s.name_alias LIKE '" . $this->db->escape($prefix . $filterkey) . "%' OR s.tva_intra LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
1603 $sql .= ")";
1604 }
1605 $sql .= $this->db->order("nom", "ASC");
1606 $sql .= $this->db->plimit($limit, 0);
1607
1608 // Build output string
1609 dol_syslog(get_class($this)."::select_thirdparty_list", LOG_DEBUG);
1610 $resql = $this->db->query($sql);
1611 if ($resql) {
1612 // Construct $out and $outarray
1613 $out .= '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '"' . ($moreparam ? ' ' . $moreparam : '') . ' name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . '>' . "\n";
1614
1615 $textifempty = (($showempty && !is_numeric($showempty)) ? $langs->trans($showempty) : '');
1616 if (getDolGlobalString('COMPANY_USE_SEARCH_TO_SELECT')) {
1617 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
1618 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
1619 if ($showempty && !is_numeric($showempty)) {
1620 $textifempty = $langs->trans($showempty);
1621 } else {
1622 $textifempty .= $langs->trans("All");
1623 }
1624 }
1625 if ($showempty) {
1626 $out .= '<option value="-1" data-html="' . dol_escape_htmltag('<span class="opacitymedium">' . ($textifempty ? $textifempty : '&nbsp;') . '</span>') . '">' . $textifempty . '</option>' . "\n";
1627 }
1628
1629 $companytemp = new Societe($this->db);
1630
1631 $num = $this->db->num_rows($resql);
1632 $i = 0;
1633 if ($num) {
1634 while ($i < $num) {
1635 $obj = $this->db->fetch_object($resql);
1636 $label = '';
1637 if ($showcode || getDolGlobalString('SOCIETE_ADD_REF_IN_LIST')) {
1638 if (($obj->client) && (!empty($obj->code_client))) {
1639 $label = $obj->code_client . ' - ';
1640 }
1641 if (($obj->fournisseur) && (!empty($obj->code_fournisseur))) {
1642 $label .= $obj->code_fournisseur . ' - ';
1643 }
1644 $label .= ' ' . $obj->name;
1645 } else {
1646 $label = $obj->name;
1647 }
1648
1649 if (!empty($obj->name_alias)) {
1650 $label .= ' (' . $obj->name_alias . ')';
1651 }
1652
1653 if (getDolGlobalString('SOCIETE_SHOW_VAT_IN_LIST') && !empty($obj->tva_intra)) {
1654 $label .= ' - '.$obj->tva_intra;
1655 }
1656
1657 $labelhtml = $label;
1658
1659 if ($showtype) {
1660 $companytemp->id = $obj->rowid;
1661 $companytemp->client = $obj->client;
1662 $companytemp->fournisseur = $obj->fournisseur;
1663 $tmptype = $companytemp->getTypeUrl(1, '', 0, 'span');
1664 if ($tmptype) {
1665 $labelhtml .= ' ' . $tmptype;
1666 }
1667
1668 if ($obj->client || $obj->fournisseur) {
1669 $label .= ' (';
1670 }
1671 if ($obj->client == 1 || $obj->client == 3) {
1672 $label .= $langs->trans("Customer");
1673 }
1674 if ($obj->client == 2 || $obj->client == 3) {
1675 $label .= ($obj->client == 3 ? ', ' : '') . $langs->trans("Prospect");
1676 }
1677 if ($obj->fournisseur) {
1678 $label .= ($obj->client ? ', ' : '') . $langs->trans("Supplier");
1679 }
1680 if ($obj->client || $obj->fournisseur) {
1681 $label .= ')';
1682 }
1683 }
1684
1685 if (getDolGlobalString('COMPANY_SHOW_ADDRESS_SELECTLIST')) {
1686 $s = ($obj->address ? ' - ' . $obj->address : '') . ($obj->zip ? ' - ' . $obj->zip : '') . ($obj->town ? ' ' . $obj->town : '');
1687 if (!empty($obj->country_code)) {
1688 $s .= ', ' . $langs->trans('Country' . $obj->country_code);
1689 }
1690 $label .= $s;
1691 $labelhtml .= $s;
1692 }
1693
1694 if (empty($outputmode)) {
1695 if (in_array($obj->rowid, $selected)) {
1696 $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>';
1697 } else {
1698 $out .= '<option value="' . $obj->rowid . '" data-html="' . dol_escape_htmltag($labelhtml, 0, 0, '', 0, 1) . '">' . dol_escape_htmltag($label, 0, 0, '', 0, 1) . '</option>';
1699 }
1700 } else {
1701 array_push($outarray, array('key' => $obj->rowid, 'value' => $label, 'label' => $label, 'labelhtml' => $labelhtml));
1702 }
1703
1704 $i++;
1705 if (($i % 10) == 0) {
1706 $out .= "\n";
1707 }
1708 }
1709 }
1710 $out .= '</select>' . "\n";
1711 if (!$forcecombo) {
1712 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1713 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("COMPANY_USE_SEARCH_TO_SELECT"));
1714 }
1715 } else {
1716 dol_print_error($this->db);
1717 }
1718
1719 $this->result = array('nbofthirdparties' => $num);
1720
1721 if ($outputmode) {
1722 return $outarray;
1723 }
1724 return $out;
1725 }
1726
1727
1753 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 = '')
1754 {
1755 global $conf, $user, $langs, $hookmanager, $action;
1756
1757 $langs->load('companies');
1758
1759 if (empty($htmlid)) {
1760 $htmlid = $htmlname;
1761 }
1762 $num = 0;
1763 $out = '';
1764 $outarray = array();
1765
1766 if ($selected === '') {
1767 $selected = array();
1768 } elseif (!is_array($selected)) {
1769 $selected = array((int) $selected);
1770 }
1771
1772 // Clean $filter that may contains sql conditions so sql code
1773 if (function_exists('testSqlAndScriptInject')) {
1774 if (testSqlAndScriptInject($filter, 3) > 0) {
1775 $filter = '';
1776 return 'SQLInjectionTryDetected';
1777 }
1778 }
1779
1780 if ($filter != '') { // If a filter was provided
1781 if (preg_match('/[\‍(\‍)]/', $filter)) {
1782 // If there is one parenthesis inside the criteria, we assume it is an Universal Filter Syntax.
1783 $errormsg = '';
1784 $filter = forgeSQLFromUniversalSearchCriteria($filter, $errormsg, 1);
1785
1786 // Redo clean $filter that may contains sql conditions so sql code
1787 if (function_exists('testSqlAndScriptInject')) {
1788 if (testSqlAndScriptInject($filter, 3) > 0) {
1789 $filter = '';
1790 return 'SQLInjectionTryDetected';
1791 }
1792 }
1793 } else {
1794 // If not, we do nothing. We already know that there is no parenthesis
1795 // TODO Disallow this case in a future by returning an error here.
1796 dol_syslog("Warning, select_thirdparty_list was called with a filter criteria not using the Universal Search Filter Syntax.", LOG_WARNING);
1797 }
1798 }
1799
1800 if (!is_object($hookmanager)) {
1801 include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
1802 $hookmanager = new HookManager($this->db);
1803 }
1804
1805 // We search third parties
1806 $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";
1807 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1808 $sql .= ", s.nom as company, s.town AS company_town";
1809 }
1810 $sql .= " FROM " . $this->db->prefix() . "socpeople as sp";
1811 if ($showsoc > 0 || getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1812 $sql .= " LEFT OUTER JOIN " . $this->db->prefix() . "societe as s ON s.rowid=sp.fk_soc";
1813 }
1814 $sql .= " WHERE sp.entity IN (" . getEntity('contact') . ")";
1815 $sql .= " AND ((sp.fk_user_creat = ".((int) $user->id)." AND sp.priv = 1) OR sp.priv = 0)"; // check if this is a private contact
1816 if ($socid > 0 || $socid == -1) {
1817 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1818 }
1819 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1820 $sql .= " AND sp.statut <> 0";
1821 }
1822 if ($filter) {
1823 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1824 // if not, by testSqlAndScriptInject() only.
1825 $sql .= " AND (" . $filter . ")";
1826 }
1827 // Add where from hooks
1828 $parameters = array();
1829 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1830 $sql .= $hookmanager->resPrint;
1831 $sql .= " ORDER BY sp.lastname ASC";
1832
1833 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1834 $resql = $this->db->query($sql);
1835 if ($resql) {
1836 $num = $this->db->num_rows($resql);
1837
1838 if ($htmlname != 'none' && !$options_only) {
1839 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1840 }
1841
1842 if ($showempty && !is_numeric($showempty)) {
1843 $textforempty = $showempty;
1844 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1845 } else {
1846 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1847 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1848 }
1849 if ($showempty == 2) {
1850 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1851 }
1852 }
1853
1854 $i = 0;
1855 if ($num) {
1856 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1857 $contactstatic = new Contact($this->db);
1858
1859 while ($i < $num) {
1860 $obj = $this->db->fetch_object($resql);
1861
1862 // Set email (or phones) and town extended infos
1863 $extendedInfos = '';
1864 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1865 $extendedInfos = array();
1866 $email = trim($obj->email);
1867 if (!empty($email)) {
1868 $extendedInfos[] = $email;
1869 } else {
1870 $phone = trim($obj->phone);
1871 $phone_perso = trim($obj->phone_perso);
1872 $phone_mobile = trim($obj->phone_mobile);
1873 if (!empty($phone)) {
1874 $extendedInfos[] = $phone;
1875 }
1876 if (!empty($phone_perso)) {
1877 $extendedInfos[] = $phone_perso;
1878 }
1879 if (!empty($phone_mobile)) {
1880 $extendedInfos[] = $phone_mobile;
1881 }
1882 }
1883 $contact_town = trim($obj->contact_town);
1884 $company_town = trim($obj->company_town);
1885 if (!empty($contact_town)) {
1886 $extendedInfos[] = $contact_town;
1887 } elseif (!empty($company_town)) {
1888 $extendedInfos[] = $company_town;
1889 }
1890 $extendedInfos = implode(' - ', $extendedInfos);
1891 if (!empty($extendedInfos)) {
1892 $extendedInfos = ' - ' . $extendedInfos;
1893 }
1894 }
1895
1896 $contactstatic->id = $obj->rowid;
1897 $contactstatic->lastname = $obj->lastname;
1898 $contactstatic->firstname = $obj->firstname;
1899 if ($obj->statut == 1) {
1900 $tmplabel = '';
1901 if ($htmlname != 'none') {
1902 $disabled = 0;
1903 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1904 $disabled = 1;
1905 }
1906 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1907 $disabled = 1;
1908 }
1909 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1910 $out .= '<option value="' . $obj->rowid . '"';
1911 if ($disabled) {
1912 $out .= ' disabled';
1913 }
1914 $out .= ' selected>';
1915
1916 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1917 if ($showfunction && $obj->poste) {
1918 $tmplabel .= ' (' . $obj->poste . ')';
1919 }
1920 if (($showsoc > 0) && $obj->company) {
1921 $tmplabel .= ' - (' . $obj->company . ')';
1922 }
1923
1924 $out .= $tmplabel;
1925 $out .= '</option>';
1926 } else {
1927 $out .= '<option value="' . $obj->rowid . '"';
1928 if ($disabled) {
1929 $out .= ' disabled';
1930 }
1931 $out .= '>';
1932
1933 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1934 if ($showfunction && $obj->poste) {
1935 $tmplabel .= ' (' . $obj->poste . ')';
1936 }
1937 if (($showsoc > 0) && $obj->company) {
1938 $tmplabel .= ' - (' . $obj->company . ')';
1939 }
1940
1941 $out .= $tmplabel;
1942 $out .= '</option>';
1943 }
1944 } else {
1945 if (in_array($obj->rowid, $selected)) {
1946 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1947 if ($showfunction && $obj->poste) {
1948 $tmplabel .= ' (' . $obj->poste . ')';
1949 }
1950 if (($showsoc > 0) && $obj->company) {
1951 $tmplabel .= ' - (' . $obj->company . ')';
1952 }
1953
1954 $out .= $tmplabel;
1955 }
1956 }
1957
1958 if ($tmplabel != '') {
1959 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1960 }
1961 }
1962 $i++;
1963 }
1964 } else {
1965 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1966 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1967 $out .= $labeltoshow;
1968 $out .= '</option>';
1969 }
1970
1971 $parameters = array(
1972 'socid' => $socid,
1973 'htmlname' => $htmlname,
1974 'resql' => $resql,
1975 'out' => &$out,
1976 'showfunction' => $showfunction,
1977 'showsoc' => $showsoc,
1978 );
1979
1980 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1981
1982 if ($htmlname != 'none' && !$options_only) {
1983 $out .= '</select>';
1984 }
1985
1986 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1987 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1988 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1989 }
1990
1991 $this->num = $num;
1992
1993 if ($options_only === 2) {
1994 // Return array of options
1995 return $outarray;
1996 } else {
1997 return $out;
1998 }
1999 } else {
2000 dol_print_error($this->db);
2001 return -1;
2002 }
2003 }
2004
2005
2006 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2007
2018 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2019 {
2020 // phpcs:enable
2021 global $langs, $conf;
2022
2023 // On recherche les remises
2024 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2025 $sql .= " re.description, re.fk_facture_source";
2026 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2027 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2028 $sql .= " AND re.entity = " . $conf->entity;
2029 if ($filter) {
2030 $sql .= " AND " . $filter;
2031 }
2032 $sql .= " ORDER BY re.description ASC";
2033
2034 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2035 $resql = $this->db->query($sql);
2036 if ($resql) {
2037 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2038 $num = $this->db->num_rows($resql);
2039
2040 $qualifiedlines = $num;
2041
2042 $i = 0;
2043 if ($num) {
2044 print '<option value="0">&nbsp;</option>';
2045 while ($i < $num) {
2046 $obj = $this->db->fetch_object($resql);
2047 $desc = dol_trunc($obj->description, 40);
2048 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2049 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2050 }
2051 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2052 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2053 }
2054 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2055 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2056 }
2057 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2058 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2059 }
2060
2061 $selectstring = '';
2062 if ($selected > 0 && $selected == $obj->rowid) {
2063 $selectstring = ' selected';
2064 }
2065
2066 $disabled = '';
2067 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2068 $qualifiedlines--;
2069 $disabled = ' disabled';
2070 }
2071
2072 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2073 $tmpfac = new Facture($this->db);
2074 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2075 $desc = $desc . ' - ' . $tmpfac->ref;
2076 }
2077 }
2078
2079 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2080 $i++;
2081 }
2082 }
2083 print '</select>';
2084 print ajax_combobox('select_' . $htmlname);
2085
2086 return $qualifiedlines;
2087 } else {
2088 dol_print_error($this->db);
2089 return -1;
2090 }
2091 }
2092
2093
2094 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2095
2111 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2112 {
2113 // phpcs:enable
2114 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2115 }
2116
2117 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2118
2143 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)
2144 {
2145 // phpcs:enable
2146 global $conf, $user, $langs, $hookmanager;
2147 global $action;
2148
2149 // If no preselected user defined, we take current user
2150 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2151 $selected = $user->id;
2152 }
2153
2154 if ($selected === '') {
2155 $selected = array();
2156 } elseif (!is_array($selected)) {
2157 $selected = array($selected);
2158 }
2159
2160 $excludeUsers = null;
2161 $includeUsers = null;
2162
2163 // Exclude some users
2164 if (is_array($exclude)) {
2165 $excludeUsers = implode(",", $exclude);
2166 }
2167 // Include some uses
2168 if (is_array($include)) {
2169 $includeUsers = implode(",", $include);
2170 } elseif ($include == 'hierarchy') {
2171 // Build list includeUsers to have only hierarchy
2172 $includeUsers = implode(",", $user->getAllChildIds(0));
2173 } elseif ($include == 'hierarchyme') {
2174 // Build list includeUsers to have only hierarchy and current user
2175 $includeUsers = implode(",", $user->getAllChildIds(1));
2176 }
2177
2178 $num = 0;
2179
2180 $out = '';
2181 $outarray = array();
2182 $outarray2 = array();
2183
2184 // Do we want to show the label of entity into the combo list ?
2185 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2186 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2187
2188 // Forge request to select users
2189 $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";
2190 if ($showlabelofentity) {
2191 $sql .= ", e.label";
2192 }
2193 $sql .= " FROM " . $this->db->prefix() . "user as u";
2194 if ($showlabelofentity) {
2195 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2196 }
2197 // Condition here should be the same than into societe->getSalesRepresentatives().
2198 if ($userissuperadminentityone && $force_entity != 'default') {
2199 if (!empty($force_entity)) {
2200 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2201 } else {
2202 $sql .= " WHERE u.entity IS NOT NULL";
2203 }
2204 } else {
2205 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2206 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2207 } else {
2208 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2209 }
2210 }
2211
2212 if (!empty($user->socid)) {
2213 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2214 }
2215 if (is_array($exclude) && $excludeUsers) {
2216 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2217 }
2218 if ($includeUsers) {
2219 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2220 }
2221 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2222 $sql .= " AND u.statut <> 0";
2223 }
2224 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2225 $sql .= " AND u.employee <> 0";
2226 }
2227 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2228 $sql .= " AND u.fk_soc IS NULL";
2229 }
2230 if (!empty($morefilter)) {
2231 $sql .= " " . $morefilter;
2232 }
2233
2234 //Add hook to filter on user (for example on usergroup define in custom modules)
2235 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2236 if (!empty($reshook)) {
2237 $sql .= $hookmanager->resPrint;
2238 }
2239
2240 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2241 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2242 } else {
2243 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2244 }
2245
2246 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2247
2248 $resql = $this->db->query($sql);
2249 if ($resql) {
2250 $num = $this->db->num_rows($resql);
2251 $i = 0;
2252 if ($num) {
2253 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2254 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2255 if ($show_empty && !$multiple) {
2256 $textforempty = ' ';
2257 if (!empty($conf->use_javascript_ajax)) {
2258 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2259 }
2260 if (!is_numeric($show_empty)) {
2261 $textforempty = $show_empty;
2262 }
2263 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2264
2265 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2266 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2267 'id' => ($show_empty < 0 ? $show_empty : -1),
2268 'label' => $textforempty,
2269 'labelhtml' => $textforempty,
2270 'color' => '',
2271 'picto' => ''
2272 );
2273 }
2274 if ($show_every) {
2275 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2276
2277 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2278 $outarray2[-2] = array(
2279 'id' => -2,
2280 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2281 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2282 'color' => '',
2283 'picto' => ''
2284 );
2285 }
2286
2287 $userstatic = new User($this->db);
2288
2289 while ($i < $num) {
2290 $obj = $this->db->fetch_object($resql);
2291
2292 $userstatic->id = $obj->rowid;
2293 $userstatic->lastname = $obj->lastname;
2294 $userstatic->firstname = $obj->firstname;
2295 $userstatic->photo = $obj->photo;
2296 $userstatic->status = $obj->status;
2297 $userstatic->entity = $obj->entity;
2298 $userstatic->admin = $obj->admin;
2299 $userstatic->gender = $obj->gender;
2300
2301 $disableline = '';
2302 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2303 $disableline = ($enableonlytext ? $enableonlytext : '1');
2304 }
2305
2306 $labeltoshow = '';
2307 $labeltoshowhtml = '';
2308
2309 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2310 $fullNameMode = 0;
2311 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2312 $fullNameMode = 1; //Firstname+lastname
2313 }
2314 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2315 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2316 if (empty($obj->firstname) && empty($obj->lastname)) {
2317 $labeltoshow .= $obj->login;
2318 $labeltoshowhtml .= $obj->login;
2319 }
2320
2321 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2322 $moreinfo = '';
2323 $moreinfohtml = '';
2324 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2325 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2326 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2327 $moreinfo .= $obj->login;
2328 $moreinfohtml .= $obj->login;
2329 }
2330 if ($showstatus >= 0) {
2331 if ($obj->status == 1 && $showstatus == 1) {
2332 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2333 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2334 }
2335 if ($obj->status == 0 && $showstatus == 1) {
2336 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2337 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2338 }
2339 }
2340 if ($showlabelofentity) {
2341 if (empty($obj->entity)) {
2342 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2343 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2344 } else {
2345 if ($obj->entity != $conf->entity) {
2346 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2347 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2348 }
2349 }
2350 }
2351 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2352 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2353 if (!empty($disableline) && $disableline != '1') {
2354 // Add text from $enableonlytext parameter
2355 $moreinfo .= ' - ' . $disableline;
2356 $moreinfohtml .= ' - ' . $disableline;
2357 }
2358 $labeltoshow .= $moreinfo;
2359 $labeltoshowhtml .= $moreinfohtml;
2360
2361 $out .= '<option value="' . $obj->rowid . '"';
2362 if (!empty($disableline)) {
2363 $out .= ' disabled';
2364 }
2365 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2366 $out .= ' selected';
2367 }
2368 $out .= ' data-html="';
2369
2370 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2371 if ($showstatus >= 0 && $obj->status == 0) {
2372 $outhtml .= '<strike class="opacitymediumxxx">';
2373 }
2374 $outhtml .= $labeltoshowhtml;
2375 if ($showstatus >= 0 && $obj->status == 0) {
2376 $outhtml .= '</strike>';
2377 }
2378 $labeltoshowhtml = $outhtml;
2379
2380 $out .= dol_escape_htmltag($outhtml);
2381 $out .= '">';
2382 $out .= $labeltoshow;
2383 $out .= '</option>';
2384
2385 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2386 $outarray2[$userstatic->id] = array(
2387 'id' => $userstatic->id,
2388 'label' => $labeltoshow,
2389 'labelhtml' => $labeltoshowhtml,
2390 'color' => '',
2391 'picto' => ''
2392 );
2393
2394 $i++;
2395 }
2396 } else {
2397 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2398 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2399 }
2400 $out .= '</select>';
2401
2402 if ($num && !$forcecombo) {
2403 // Enhance with select2
2404 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2405 $out .= ajax_combobox($htmlname);
2406 }
2407 } else {
2408 dol_print_error($this->db);
2409 }
2410
2411 $this->num = $num;
2412
2413 if ($outputmode == 2) {
2414 return $outarray2;
2415 } elseif ($outputmode) {
2416 return $outarray;
2417 }
2418
2419 return $out;
2420 }
2421
2422
2423 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2446 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())
2447 {
2448 // phpcs:enable
2449 global $langs;
2450
2451 $userstatic = new User($this->db);
2452 $out = '';
2453
2454 if (!empty($_SESSION['assignedtouser'])) {
2455 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2456 if (!is_array($assignedtouser)) {
2457 $assignedtouser = array();
2458 }
2459 } else {
2460 $assignedtouser = array();
2461 }
2462 $nbassignetouser = count($assignedtouser);
2463
2464 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2465 if ($nbassignetouser) {
2466 $out .= '<ul class="attendees">';
2467 }
2468 $i = 0;
2469 $ownerid = 0;
2470 foreach ($assignedtouser as $key => $value) {
2471 if ($value['id'] == $ownerid) {
2472 continue;
2473 }
2474
2475 $out .= '<li>';
2476 $userstatic->fetch($value['id']);
2477 $out .= $userstatic->getNomUrl(-1);
2478 if ($i == 0) {
2479 $ownerid = $value['id'];
2480 $out .= ' (' . $langs->trans("Owner") . ')';
2481 }
2482 if ($nbassignetouser > 1 && $action != 'view') {
2483 $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 . '">';
2484 }
2485 // Show my availability
2486 if ($showproperties) {
2487 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2488 $out .= '<div class="myavailability inline-block">';
2489 $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>';
2490 $out .= '</div>';
2491 }
2492 }
2493 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2494 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2495
2496 $out .= '</li>';
2497 $i++;
2498 }
2499 if ($nbassignetouser) {
2500 $out .= '</ul>';
2501 }
2502
2503 // Method with no ajax
2504 if ($action != 'view') {
2505 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2506 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2507 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2508 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2509 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2510 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2511 $out .= '});';
2512 $out .= '})</script>';
2513 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2514 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2515 $out .= '<br>';
2516 }
2517
2518 return $out;
2519 }
2520
2521 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2541 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())
2542 {
2543 // phpcs:enable
2544 global $langs;
2545
2546 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2547 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2548 $formresources = new FormResource($this->db);
2549 $resourcestatic = new Dolresource($this->db);
2550
2551 $out = '';
2552 if (!empty($_SESSION['assignedtoresource'])) {
2553 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2554 if (!is_array($assignedtoresource)) {
2555 $assignedtoresource = array();
2556 }
2557 } else {
2558 $assignedtoresource = array();
2559 }
2560 $nbassignetoresource = count($assignedtoresource);
2561
2562 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2563 if ($nbassignetoresource) {
2564 $out .= '<ul class="attendees">';
2565 }
2566 $i = 0;
2567
2568 foreach ($assignedtoresource as $key => $value) {
2569 $out .= '<li>';
2570 $resourcestatic->fetch($value['id']);
2571 $out .= $resourcestatic->getNomUrl(-1);
2572 if ($nbassignetoresource > 1 && $action != 'view') {
2573 $out .= ' <input type="image" style="border: 0px;" src="' . img_picto($langs->trans("Remove"), 'delete', '', 0, 1) . '" value="' . $resourcestatic->id . '" class="removedassigned reposition" id="removedassignedresource_' . $resourcestatic->id . '" name="removedassignedresource_' . $resourcestatic->id . '">';
2574 }
2575 // Show my availability
2576 if ($showproperties) {
2577 if (is_array($listofresourceid) && count($listofresourceid)) {
2578 $out .= '<div class="myavailability inline-block">';
2579 $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>';
2580 $out .= '</div>';
2581 }
2582 }
2583 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2584 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2585
2586 $out .= '</li>';
2587 $i++;
2588 }
2589 if ($nbassignetoresource) {
2590 $out .= '</ul>';
2591 }
2592
2593 // Method with no ajax
2594 if ($action != 'view') {
2595 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassignedresource" value="">';
2596 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2597 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2598 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2599 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2600 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2601 $out .= '});';
2602 $out .= '})</script>';
2603
2604 $events = array();
2605 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2606 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2607 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2608 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2609 $out .= '<br>';
2610 }
2611
2612 return $out;
2613 }
2614
2615 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2616
2645 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)
2646 {
2647 // phpcs:enable
2648 global $langs, $conf;
2649
2650 $out = '';
2651
2652 // check parameters
2653 $price_level = (!empty($price_level) ? $price_level : 0);
2654 if (is_null($ajaxoptions)) {
2655 $ajaxoptions = array();
2656 }
2657
2658 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2659 if (isModEnabled("product") && !isModEnabled('service')) {
2660 $filtertype = '0';
2661 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2662 $filtertype = '1';
2663 }
2664 }
2665
2666 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2667 $placeholder = '';
2668
2669 if ($selected && empty($selected_input_value)) {
2670 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2671 $producttmpselect = new Product($this->db);
2672 $producttmpselect->fetch($selected);
2673 $selected_input_value = $producttmpselect->ref;
2674 unset($producttmpselect);
2675 }
2676 // handle case where product or service module is disabled + no filter specified
2677 if ($filtertype == '') {
2678 if (!isModEnabled('product')) { // when product module is disabled, show services only
2679 $filtertype = 1;
2680 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2681 $filtertype = 0;
2682 }
2683 }
2684 // mode=1 means customers products
2685 $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;
2686 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2687
2688 if (isModEnabled('variants') && is_array($selected_combinations)) {
2689 // Code to automatically insert with javascript the select of attributes under the select of product
2690 // when a parent of variant has been selected.
2691 $out .= '
2692 <!-- script to auto show attributes select tags if a variant was selected -->
2693 <script nonce="' . getNonce() . '">
2694 // auto show attributes fields
2695 selected = ' . json_encode($selected_combinations) . ';
2696 combvalues = {};
2697
2698 jQuery(document).ready(function () {
2699
2700 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2701 if (jQuery(this).val() == \'free\') {
2702 jQuery(\'div#attributes_box\').empty();
2703 }
2704 });
2705
2706 jQuery("input#' . $htmlname . '").change(function () {
2707
2708 if (!jQuery(this).val()) {
2709 jQuery(\'div#attributes_box\').empty();
2710 return;
2711 }
2712
2713 console.log("A change has started. We get variants fields to inject html select");
2714
2715 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2716 id: jQuery(this).val()
2717 }, function (data) {
2718 jQuery(\'div#attributes_box\').empty();
2719
2720 jQuery.each(data, function (key, val) {
2721
2722 combvalues[val.id] = val.values;
2723
2724 var span = jQuery(document.createElement(\'div\')).css({
2725 \'display\': \'table-row\'
2726 });
2727
2728 span.append(
2729 jQuery(document.createElement(\'div\')).text(val.label).css({
2730 \'font-weight\': \'bold\',
2731 \'display\': \'table-cell\'
2732 })
2733 );
2734
2735 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2736 \'margin-left\': \'15px\',
2737 \'white-space\': \'pre\'
2738 }).append(
2739 jQuery(document.createElement(\'option\')).val(\'\')
2740 );
2741
2742 jQuery.each(combvalues[val.id], function (key, val) {
2743 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2744
2745 if (selected[val.fk_product_attribute] == val.id) {
2746 tag.attr(\'selected\', \'selected\');
2747 }
2748
2749 html.append(tag);
2750 });
2751
2752 span.append(html);
2753 jQuery(\'div#attributes_box\').append(span);
2754 });
2755 })
2756 });
2757
2758 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2759 });
2760 </script>
2761 ';
2762 }
2763
2764 if (empty($hidelabel)) {
2765 $out .= $langs->trans("RefOrLabel") . ' : ';
2766 } elseif ($hidelabel > 1) {
2767 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2768 if ($hidelabel == 2) {
2769 $out .= img_picto($langs->trans("Search"), 'search');
2770 }
2771 }
2772 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2773 if ($hidelabel == 3) {
2774 $out .= img_picto($langs->trans("Search"), 'search');
2775 }
2776 } else {
2777 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2778 }
2779
2780 if (empty($nooutput)) {
2781 print $out;
2782 } else {
2783 return $out;
2784 }
2785 }
2786
2787 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2788
2804 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2805 {
2806 // phpcs:enable
2807 global $db;
2808
2809 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2810
2811 $error = 0;
2812 $out = '';
2813
2814 if (!$forcecombo) {
2815 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2816 $events = array();
2817 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2818 }
2819
2820 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2821
2822 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2823 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2824 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2825 if (!empty($status)) {
2826 $sql .= ' AND status = ' . (int) $status;
2827 }
2828 if (!empty($type)) {
2829 $sql .= ' AND bomtype = ' . (int) $type;
2830 }
2831 if (!empty($TProducts)) {
2832 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2833 }
2834 if (!empty($limit)) {
2835 $sql .= ' LIMIT ' . (int) $limit;
2836 }
2837 $resql = $db->query($sql);
2838 if ($resql) {
2839 if ($showempty) {
2840 $out .= '<option value="-1"';
2841 if (empty($selected)) {
2842 $out .= ' selected';
2843 }
2844 $out .= '>&nbsp;</option>';
2845 }
2846 while ($obj = $db->fetch_object($resql)) {
2847 $product = new Product($db);
2848 $res = $product->fetch($obj->fk_product);
2849 $out .= '<option value="' . $obj->rowid . '"';
2850 if ($obj->rowid == $selected) {
2851 $out .= 'selected';
2852 }
2853 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2854 }
2855 } else {
2856 $error++;
2857 dol_print_error($db);
2858 }
2859 $out .= '</select>';
2860 if (empty($nooutput)) {
2861 print $out;
2862 } else {
2863 return $out;
2864 }
2865 }
2866
2867 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2868
2894 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)
2895 {
2896 // phpcs:enable
2897 global $langs;
2898 global $hookmanager;
2899
2900 $out = '';
2901 $outarray = array();
2902
2903 // Units
2904 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2905 $langs->load('other');
2906 }
2907
2908 $warehouseStatusArray = array();
2909 if (!empty($warehouseStatus)) {
2910 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2911 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2912 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2913 }
2914 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2915 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2916 }
2917 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2918 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2919 }
2920 }
2921
2922 $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";
2923 if (count($warehouseStatusArray)) {
2924 $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
2925 } else {
2926 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2927 }
2928
2929 $sql = "SELECT ";
2930
2931 // Add select from hooks
2932 $parameters = array();
2933 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2934 if (empty($reshook)) {
2935 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2936 } else {
2937 $sql .= $hookmanager->resPrint;
2938 }
2939
2940 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2941 //Product category
2942 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2943 FROM " . $this->db->prefix() . "categorie_product
2944 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2945 LIMIT 1
2946 ) AS categorie_product_id ";
2947 }
2948
2949 //Price by customer
2950 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2951 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2952 $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';
2953 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2954 }
2955 // Units
2956 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2957 $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";
2958 $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';
2959 }
2960
2961 // Multilang : we add translation
2962 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2963 $sql .= ", pl.label as label_translated";
2964 $sql .= ", pl.description as description_translated";
2965 $selectFields .= ", label_translated";
2966 $selectFields .= ", description_translated";
2967 }
2968 // Price by quantity
2969 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2970 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2971 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2972 $sql .= " AND price_level = " . ((int) $price_level);
2973 }
2974 $sql .= " ORDER BY date_price";
2975 $sql .= " DESC LIMIT 1) as price_rowid";
2976 $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
2977 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2978 $sql .= " AND price_level = " . ((int) $price_level);
2979 }
2980 $sql .= " ORDER BY date_price";
2981 $sql .= " DESC LIMIT 1) as price_by_qty";
2982 $selectFields .= ", price_rowid, price_by_qty";
2983 }
2984
2985 $sql .= " FROM ".$this->db->prefix()."product as p";
2986
2987 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
2988 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
2989 }
2990
2991 // Add from (left join) from hooks
2992 $parameters = array();
2993 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2994 $sql .= $hookmanager->resPrint;
2995
2996 if (count($warehouseStatusArray)) {
2997 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2998 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2999 $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.
3000 }
3001
3002 // include search in supplier ref
3003 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3004 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3005 }
3006
3007 //Price by customer
3008 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
3009 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3010 }
3011 // Units
3012 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3013 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3014 }
3015 // Multilang : we add translation
3016 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3017 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3018 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3019 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3020 $soc = new Societe($this->db);
3021 $result = $soc->fetch($socid);
3022 if ($result > 0 && !empty($soc->default_lang)) {
3023 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3024 } else {
3025 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3026 }
3027 } else {
3028 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3029 }
3030 }
3031
3032 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3033 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3034 }
3035
3036 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3037
3038 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3039 $sql .= " AND pac.rowid IS NULL";
3040 }
3041
3042 if ($finished == 0) {
3043 $sql .= " AND p.finished = " . ((int) $finished);
3044 } elseif ($finished == 1) {
3045 $sql .= " AND p.finished = ".((int) $finished);
3046 }
3047 if ($status >= 0) {
3048 $sql .= " AND p.tosell = ".((int) $status);
3049 }
3050 if ($status_purchase >= 0) {
3051 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3052 }
3053 // Filter by product type
3054 if (strval($filtertype) != '') {
3055 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3056 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3057 $sql .= " AND p.fk_product_type = 1";
3058 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3059 $sql .= " AND p.fk_product_type = 0";
3060 }
3061 // Add where from hooks
3062 $parameters = array();
3063 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3064 $sql .= $hookmanager->resPrint;
3065 // Add criteria on ref/label
3066 if ($filterkey != '') {
3067 $sql .= ' AND (';
3068 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3069 // For natural search
3070 $search_crit = explode(' ', $filterkey);
3071 $i = 0;
3072 if (count($search_crit) > 1) {
3073 $sql .= "(";
3074 }
3075 foreach ($search_crit as $crit) {
3076 if ($i > 0) {
3077 $sql .= " AND ";
3078 }
3079 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3080 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3081 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3082 }
3083 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
3084 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3085 }
3086 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3087 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3088 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3089 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3090 }
3091 }
3092 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3093 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3094 }
3095 $sql .= ")";
3096 $i++;
3097 }
3098 if (count($search_crit) > 1) {
3099 $sql .= ")";
3100 }
3101 if (isModEnabled('barcode')) {
3102 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3103 }
3104 $sql .= ')';
3105 }
3106 if (count($warehouseStatusArray)) {
3107 $sql .= " GROUP BY " . $selectFields;
3108 }
3109
3110 //Sort by category
3111 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3112 $sql .= " ORDER BY categorie_product_id ";
3113 //ASC OR DESC order
3114 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3115 } else {
3116 $sql .= $this->db->order("p.ref");
3117 }
3118
3119 $sql .= $this->db->plimit($limit, 0);
3120
3121 // Build output string
3122 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3123 $result = $this->db->query($sql);
3124 if ($result) {
3125 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3126 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3127 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3128
3129 $num = $this->db->num_rows($result);
3130
3131 $events = array();
3132
3133 if (!$forcecombo) {
3134 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3135 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3136 }
3137
3138 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3139
3140 $textifempty = '';
3141 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3142 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3143 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3144 if ($showempty && !is_numeric($showempty)) {
3145 $textifempty = $langs->trans($showempty);
3146 } else {
3147 $textifempty .= $langs->trans("All");
3148 }
3149 } else {
3150 if ($showempty && !is_numeric($showempty)) {
3151 $textifempty = $langs->trans($showempty);
3152 }
3153 }
3154 if ($showempty) {
3155 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3156 }
3157
3158 $i = 0;
3159 while ($num && $i < $num) {
3160 $opt = '';
3161 $optJson = array();
3162 $objp = $this->db->fetch_object($result);
3163
3164 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
3165 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3166 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3167 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3168 $sql .= " ORDER BY quantity ASC";
3169
3170 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3171 $result2 = $this->db->query($sql);
3172 if ($result2) {
3173 $nb_prices = $this->db->num_rows($result2);
3174 $j = 0;
3175 while ($nb_prices && $j < $nb_prices) {
3176 $objp2 = $this->db->fetch_object($result2);
3177
3178 $objp->price_by_qty_rowid = $objp2->rowid;
3179 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3180 $objp->price_by_qty_quantity = $objp2->quantity;
3181 $objp->price_by_qty_unitprice = $objp2->unitprice;
3182 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3183 // For backward compatibility
3184 $objp->quantity = $objp2->quantity;
3185 $objp->price = $objp2->price;
3186 $objp->unitprice = $objp2->unitprice;
3187 $objp->remise_percent = $objp2->remise_percent;
3188
3189 //$objp->tva_tx is not overwritten by $objp2 value
3190 //$objp->default_vat_code is not overwritten by $objp2 value
3191
3192 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3193
3194 $j++;
3195
3196 // Add new entry
3197 // "key" value of json key array is used by jQuery automatically as selected value
3198 // "label" value of json key array is used by jQuery automatically as text for combo box
3199 $out .= $opt;
3200 array_push($outarray, $optJson);
3201 }
3202 }
3203 } else {
3204 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3205 $price_product = new Product($this->db);
3206 $price_product->fetch($objp->rowid, '', '', 1);
3207
3208 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3209 $priceparser = new PriceParser($this->db);
3210 $price_result = $priceparser->parseProduct($price_product);
3211 if ($price_result >= 0) {
3212 $objp->price = $price_result;
3213 $objp->unitprice = $price_result;
3214 //Calculate the VAT
3215 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3216 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3217 }
3218 }
3219
3220 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3221 // Add new entry
3222 // "key" value of json key array is used by jQuery automatically as selected value
3223 // "label" value of json key array is used by jQuery automatically as text for combo box
3224 $out .= $opt;
3225 array_push($outarray, $optJson);
3226 }
3227
3228 $i++;
3229 }
3230
3231 $out .= '</select>';
3232
3233 $this->db->free($result);
3234
3235 if (empty($outputmode)) {
3236 return $out;
3237 }
3238
3239 return $outarray;
3240 } else {
3241 dol_print_error($this->db);
3242 }
3243
3244 return '';
3245 }
3246
3262 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3263 {
3264 global $langs, $conf, $user;
3265 global $hookmanager;
3266
3267 $outkey = '';
3268 $outval = '';
3269 $outref = '';
3270 $outlabel = '';
3271 $outlabel_translated = '';
3272 $outdesc = '';
3273 $outdesc_translated = '';
3274 $outbarcode = '';
3275 $outorigin = '';
3276 $outtype = '';
3277 $outprice_ht = '';
3278 $outprice_ttc = '';
3279 $outpricebasetype = '';
3280 $outtva_tx = '';
3281 $outdefault_vat_code = '';
3282 $outqty = 1;
3283 $outdiscount = 0;
3284
3285 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3286
3287 $label = $objp->label;
3288 if (!empty($objp->label_translated)) {
3289 $label = $objp->label_translated;
3290 }
3291 if (!empty($filterkey) && $filterkey != '') {
3292 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3293 }
3294
3295 $outkey = $objp->rowid;
3296 $outref = $objp->ref;
3297 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3298 $outlabel = $objp->label;
3299 $outdesc = $objp->description;
3300 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3301 $outlabel_translated = $objp->label_translated;
3302 $outdesc_translated = $objp->description_translated;
3303 }
3304 $outbarcode = $objp->barcode;
3305 $outorigin = $objp->fk_country;
3306 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3307
3308 $outtype = $objp->fk_product_type;
3309 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3310 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3311
3312 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3313 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3314 }
3315
3316 // Units
3317 $outvalUnits = '';
3318 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3319 if (!empty($objp->unit_short)) {
3320 $outvalUnits .= ' - ' . $objp->unit_short;
3321 }
3322 }
3323 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3324 if (!empty($objp->weight) && $objp->weight_units !== null) {
3325 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3326 $outvalUnits .= ' - ' . $unitToShow;
3327 }
3328 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3329 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3330 $outvalUnits .= ' - ' . $unitToShow;
3331 }
3332 if (!empty($objp->surface) && $objp->surface_units !== null) {
3333 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3334 $outvalUnits .= ' - ' . $unitToShow;
3335 }
3336 if (!empty($objp->volume) && $objp->volume_units !== null) {
3337 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3338 $outvalUnits .= ' - ' . $unitToShow;
3339 }
3340 }
3341 if ($outdurationvalue && $outdurationunit) {
3342 $da = array(
3343 'h' => $langs->trans('Hour'),
3344 'd' => $langs->trans('Day'),
3345 'w' => $langs->trans('Week'),
3346 'm' => $langs->trans('Month'),
3347 'y' => $langs->trans('Year')
3348 );
3349 if (isset($da[$outdurationunit])) {
3350 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3351 }
3352 }
3353
3354 $opt = '<option value="' . $objp->rowid . '"';
3355 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3356 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3357 $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 . '"';
3358 }
3359 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3360 if ($user->hasRight('stock', 'lire')) {
3361 if ($objp->stock > 0) {
3362 $opt .= ' class="product_line_stock_ok"';
3363 } elseif ($objp->stock <= 0) {
3364 $opt .= ' class="product_line_stock_too_low"';
3365 }
3366 }
3367 }
3368 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3369 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3370 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3371 }
3372 $opt .= '>';
3373 $opt .= $objp->ref;
3374 if (!empty($objp->custref)) {
3375 $opt .= ' (' . $objp->custref . ')';
3376 }
3377 if ($outbarcode) {
3378 $opt .= ' (' . $outbarcode . ')';
3379 }
3380 $opt .= ' - ' . dol_trunc($label, $maxlengtharticle);
3381 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3382 $opt .= ' (' . getCountry($outorigin, 1) . ')';
3383 }
3384
3385 $objRef = $objp->ref;
3386 if (!empty($objp->custref)) {
3387 $objRef .= ' (' . $objp->custref . ')';
3388 }
3389 if (!empty($filterkey) && $filterkey != '') {
3390 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3391 }
3392 $outval .= $objRef;
3393 if ($outbarcode) {
3394 $outval .= ' (' . $outbarcode . ')';
3395 }
3396 $outval .= ' - ' . dol_trunc($label, $maxlengtharticle);
3397 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3398 $outval .= ' (' . getCountry($outorigin, 1) . ')';
3399 }
3400
3401 // Units
3402 $opt .= $outvalUnits;
3403 $outval .= $outvalUnits;
3404
3405 $found = 0;
3406
3407 // Multiprice
3408 // If we need a particular price level (from 1 to n)
3409 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3410 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3411 $sql .= " FROM " . $this->db->prefix() . "product_price";
3412 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3413 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3414 $sql .= " AND price_level = " . ((int) $price_level);
3415 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3416 $sql .= " LIMIT 1";
3417
3418 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3419 $result2 = $this->db->query($sql);
3420 if ($result2) {
3421 $objp2 = $this->db->fetch_object($result2);
3422 if ($objp2) {
3423 $found = 1;
3424 if ($objp2->price_base_type == 'HT') {
3425 $opt .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3426 $outval .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3427 } else {
3428 $opt .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3429 $outval .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3430 }
3431 $outprice_ht = price($objp2->price);
3432 $outprice_ttc = price($objp2->price_ttc);
3433 $outpricebasetype = $objp2->price_base_type;
3434 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3435 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3436 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3437 } else {
3438 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3439 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3440 }
3441 }
3442 } else {
3443 dol_print_error($this->db);
3444 }
3445 }
3446
3447 // Price by quantity
3448 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3449 $found = 1;
3450 $outqty = $objp->quantity;
3451 $outdiscount = $objp->remise_percent;
3452 if ($objp->quantity == 1) {
3453 $opt .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3454 $outval .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3455 $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3456 $outval .= $langs->transnoentities("Unit");
3457 } else {
3458 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3459 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3460 $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3461 $outval .= $langs->transnoentities("Units");
3462 }
3463
3464 $outprice_ht = price($objp->unitprice);
3465 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3466 $outpricebasetype = $objp->price_base_type;
3467 $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
3468 $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
3469 }
3470 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3471 $opt .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3472 $outval .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3473 }
3474 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3475 $opt .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3476 $outval .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3477 }
3478
3479 // Price by customer
3480 if (empty($hidepriceinlabel) && getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
3481 if (!empty($objp->idprodcustprice)) {
3482 $found = 1;
3483
3484 if ($objp->custprice_base_type == 'HT') {
3485 $opt .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3486 $outval .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3487 } else {
3488 $opt .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3489 $outval .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3490 }
3491
3492 $outprice_ht = price($objp->custprice);
3493 $outprice_ttc = price($objp->custprice_ttc);
3494 $outpricebasetype = $objp->custprice_base_type;
3495 $outtva_tx = $objp->custtva_tx;
3496 $outdefault_vat_code = $objp->custdefault_vat_code;
3497 }
3498 }
3499
3500 // If level no defined or multiprice not found, we used the default price
3501 if (empty($hidepriceinlabel) && !$found) {
3502 if ($objp->price_base_type == 'HT') {
3503 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3504 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3505 } else {
3506 $opt .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3507 $outval .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3508 }
3509 $outprice_ht = price($objp->price);
3510 $outprice_ttc = price($objp->price_ttc);
3511 $outpricebasetype = $objp->price_base_type;
3512 $outtva_tx = $objp->tva_tx;
3513 $outdefault_vat_code = $objp->default_vat_code;
3514 }
3515
3516 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3517 if ($user->hasRight('stock', 'lire')) {
3518 $opt .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'), 0, $langs, 0, 0);
3519
3520 if ($objp->stock > 0) {
3521 $outval .= ' - <span class="product_line_stock_ok">';
3522 } elseif ($objp->stock <= 0) {
3523 $outval .= ' - <span class="product_line_stock_too_low">';
3524 }
3525 $outval .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3526 $outval .= '</span>';
3527 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3528 $langs->load("stocks");
3529
3530 $tmpproduct = new Product($this->db);
3531 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3532 $tmpproduct->load_virtual_stock();
3533 $virtualstock = $tmpproduct->stock_theorique;
3534
3535 $opt .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3536
3537 $outval .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3538 if ($virtualstock > 0) {
3539 $outval .= '<span class="product_line_stock_ok">';
3540 } elseif ($virtualstock <= 0) {
3541 $outval .= '<span class="product_line_stock_too_low">';
3542 }
3543 $outval .= $virtualstock;
3544 $outval .= '</span>';
3545
3546 unset($tmpproduct);
3547 }
3548 }
3549 }
3550
3551 $parameters = array('objp' => $objp);
3552 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3553 if (empty($reshook)) {
3554 $opt .= $hookmanager->resPrint;
3555 } else {
3556 $opt = $hookmanager->resPrint;
3557 }
3558
3559 $opt .= "</option>\n";
3560 $optJson = array(
3561 'key' => $outkey,
3562 'value' => $outref,
3563 'label' => $outval,
3564 'label2' => $outlabel,
3565 'desc' => $outdesc,
3566 'type' => $outtype,
3567 'price_ht' => price2num($outprice_ht),
3568 'price_ttc' => price2num($outprice_ttc),
3569 'price_ht_locale' => price(price2num($outprice_ht)),
3570 'price_ttc_locale' => price(price2num($outprice_ttc)),
3571 'pricebasetype' => $outpricebasetype,
3572 'tva_tx' => $outtva_tx,
3573 'default_vat_code' => $outdefault_vat_code,
3574 'qty' => $outqty,
3575 'discount' => $outdiscount,
3576 'duration_value' => $outdurationvalue,
3577 'duration_unit' => $outdurationunit,
3578 'pbq' => $outpbq,
3579 'labeltrans' => $outlabel_translated,
3580 'desctrans' => $outdesc_translated,
3581 'ref_customer' => $outrefcust
3582 );
3583 }
3584
3585 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3586
3602 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3603 {
3604 // phpcs:enable
3605 global $langs, $conf;
3606 global $price_level, $status, $finished;
3607
3608 if (!isset($status)) {
3609 $status = 1;
3610 }
3611
3612 $selected_input_value = '';
3613 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3614 if ($selected > 0) {
3615 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3616 $producttmpselect = new Product($this->db);
3617 $producttmpselect->fetch($selected);
3618 $selected_input_value = $producttmpselect->ref;
3619 unset($producttmpselect);
3620 }
3621
3622 // mode=2 means suppliers products
3623 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3624 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3625
3626 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3627 } else {
3628 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3629 }
3630 }
3631
3632 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3633
3652 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 = '')
3653 {
3654 // phpcs:enable
3655 global $langs, $conf, $user;
3656 global $hookmanager;
3657
3658 $out = '';
3659 $outarray = array();
3660
3661 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3662
3663 $langs->load('stocks');
3664 // Units
3665 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3666 $langs->load('other');
3667 }
3668
3669 $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,";
3670 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3671 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3672 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3673 $sql .= ", pfp.supplier_reputation";
3674 // if we use supplier description of the products
3675 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3676 $sql .= ", pfp.desc_fourn as description";
3677 } else {
3678 $sql .= ", p.description";
3679 }
3680 // Units
3681 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3682 $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";
3683 }
3684 $sql .= " FROM " . $this->db->prefix() . "product as p";
3685 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3686 if ($socid > 0) {
3687 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3688 }
3689 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3690 // Units
3691 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3692 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3693 }
3694 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3695 if ($statut != -1) {
3696 $sql .= " AND p.tobuy = " . ((int) $statut);
3697 }
3698 if (strval($filtertype) != '') {
3699 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3700 }
3701 if (!empty($filtre)) {
3702 $sql .= " " . $filtre;
3703 }
3704 // Add where from hooks
3705 $parameters = array();
3706 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3707 $sql .= $hookmanager->resPrint;
3708 // Add criteria on ref/label
3709 if ($filterkey != '') {
3710 $sql .= ' AND (';
3711 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3712 // For natural search
3713 $search_crit = explode(' ', $filterkey);
3714 $i = 0;
3715 if (count($search_crit) > 1) {
3716 $sql .= "(";
3717 }
3718 foreach ($search_crit as $crit) {
3719 if ($i > 0) {
3720 $sql .= " AND ";
3721 }
3722 $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) . "%'";
3723 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3724 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3725 }
3726 $sql .= ")";
3727 $i++;
3728 }
3729 if (count($search_crit) > 1) {
3730 $sql .= ")";
3731 }
3732 if (isModEnabled('barcode')) {
3733 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3734 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3735 }
3736 $sql .= ')';
3737 }
3738 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3739 $sql .= $this->db->plimit($limit, 0);
3740
3741 // Build output string
3742
3743 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3744 $result = $this->db->query($sql);
3745 if ($result) {
3746 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3747 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3748
3749 $num = $this->db->num_rows($result);
3750
3751 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3752 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3753 if (!$selected) {
3754 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3755 } else {
3756 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3757 }
3758
3759 $i = 0;
3760 while ($i < $num) {
3761 $objp = $this->db->fetch_object($result);
3762
3763 if (is_null($objp->idprodfournprice)) {
3764 // There is no supplier price found, we will use the vat rate for sale
3765 $objp->tva_tx = $objp->tva_tx_sale;
3766 $objp->default_vat_code = $objp->default_vat_code_sale;
3767 }
3768
3769 $outkey = $objp->idprodfournprice; // id in table of price
3770 if (!$outkey && $alsoproductwithnosupplierprice) {
3771 $outkey = 'idprod_' . $objp->rowid; // id of product
3772 }
3773
3774 $outref = $objp->ref;
3775 $outbarcode = $objp->barcode;
3776 $outqty = 1;
3777 $outdiscount = 0;
3778 $outtype = $objp->fk_product_type;
3779 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3780 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3781
3782 // Units
3783 $outvalUnits = '';
3784 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3785 if (!empty($objp->unit_short)) {
3786 $outvalUnits .= ' - ' . $objp->unit_short;
3787 }
3788 if (!empty($objp->weight) && $objp->weight_units !== null) {
3789 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3790 $outvalUnits .= ' - ' . $unitToShow;
3791 }
3792 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3793 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3794 $outvalUnits .= ' - ' . $unitToShow;
3795 }
3796 if (!empty($objp->surface) && $objp->surface_units !== null) {
3797 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3798 $outvalUnits .= ' - ' . $unitToShow;
3799 }
3800 if (!empty($objp->volume) && $objp->volume_units !== null) {
3801 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3802 $outvalUnits .= ' - ' . $unitToShow;
3803 }
3804 if ($outdurationvalue && $outdurationunit) {
3805 $da = array(
3806 'h' => $langs->trans('Hour'),
3807 'd' => $langs->trans('Day'),
3808 'w' => $langs->trans('Week'),
3809 'm' => $langs->trans('Month'),
3810 'y' => $langs->trans('Year')
3811 );
3812 if (isset($da[$outdurationunit])) {
3813 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3814 }
3815 }
3816 }
3817
3818 $objRef = $objp->ref;
3819 if ($filterkey && $filterkey != '') {
3820 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3821 }
3822 $objRefFourn = $objp->ref_fourn;
3823 if ($filterkey && $filterkey != '') {
3824 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3825 }
3826 $label = $objp->label;
3827 if ($filterkey && $filterkey != '') {
3828 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3829 }
3830
3831 switch ($objp->fk_product_type) {
3833 $picto = 'product';
3834 break;
3836 $picto = 'service';
3837 break;
3838 default:
3839 $picto = '';
3840 break;
3841 }
3842
3843 if (empty($picto)) {
3844 $optlabel = '';
3845 } else {
3846 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3847 }
3848
3849 $optlabel .= $objp->ref;
3850 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3851 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3852 }
3853 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3854 $optlabel .= ' (' . $outbarcode . ')';
3855 }
3856 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3857
3858 $outvallabel = $objRef;
3859 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3860 $outvallabel .= ' (' . $objRefFourn . ')';
3861 }
3862 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3863 $outvallabel .= ' (' . $outbarcode . ')';
3864 }
3865 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3866
3867 // Units
3868 $optlabel .= $outvalUnits;
3869 $outvallabel .= $outvalUnits;
3870
3871 if (!empty($objp->idprodfournprice)) {
3872 $outqty = $objp->quantity;
3873 $outdiscount = $objp->remise_percent;
3874 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3875 $prod_supplier = new ProductFournisseur($this->db);
3876 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3877 $prod_supplier->id = $objp->fk_product;
3878 $prod_supplier->fourn_qty = $objp->quantity;
3879 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3880 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3881
3882 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3883 $priceparser = new PriceParser($this->db);
3884 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3885 if ($price_result >= 0) {
3886 $objp->fprice = $price_result;
3887 if ($objp->quantity >= 1) {
3888 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3889 }
3890 }
3891 }
3892 if ($objp->quantity == 1) {
3893 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3894 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3895 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3896 $outvallabel .= $langs->transnoentities("Unit");
3897 } else {
3898 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3899 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3900 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3901 $outvallabel .= ' ' . $langs->transnoentities("Units");
3902 }
3903
3904 if ($objp->quantity > 1) {
3905 $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
3906 $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
3907 }
3908 if ($objp->remise_percent >= 1) {
3909 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3910 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3911 }
3912 if ($objp->duration) {
3913 $optlabel .= " - " . $objp->duration;
3914 $outvallabel .= " - " . $objp->duration;
3915 }
3916 if (!$socid) {
3917 $optlabel .= " - " . dol_trunc($objp->name, 8);
3918 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3919 }
3920 if ($objp->supplier_reputation) {
3921 //TODO dictionary
3922 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3923
3924 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3925 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3926 }
3927 } else {
3928 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3929 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3930 }
3931
3932 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3933 $novirtualstock = ($showstockinlist == 2);
3934
3935 if ($user->hasRight('stock', 'lire')) {
3936 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3937
3938 if ($objp->stock > 0) {
3939 $optlabel .= ' - <span class="product_line_stock_ok">';
3940 } elseif ($objp->stock <= 0) {
3941 $optlabel .= ' - <span class="product_line_stock_too_low">';
3942 }
3943 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3944 $optlabel .= '</span>';
3945 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3946 $langs->load("stocks");
3947
3948 $tmpproduct = new Product($this->db);
3949 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3950 $tmpproduct->load_virtual_stock();
3951 $virtualstock = $tmpproduct->stock_theorique;
3952
3953 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3954
3955 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3956 if ($virtualstock > 0) {
3957 $optlabel .= '<span class="product_line_stock_ok">';
3958 } elseif ($virtualstock <= 0) {
3959 $optlabel .= '<span class="product_line_stock_too_low">';
3960 }
3961 $optlabel .= $virtualstock;
3962 $optlabel .= '</span>';
3963
3964 unset($tmpproduct);
3965 }
3966 }
3967 }
3968
3969 $optstart = '<option value="' . $outkey . '"';
3970 if ($selected && $selected == $objp->idprodfournprice) {
3971 $optstart .= ' selected';
3972 }
3973 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3974 $optstart .= ' disabled';
3975 }
3976
3977 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3978 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
3979 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
3980 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
3981 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
3982 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
3983 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
3984 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
3985 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
3986 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
3987 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
3988 if (isModEnabled('multicurrency')) {
3989 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
3990 $optstart .= ' data-multicurrency-up="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
3991 }
3992 }
3993 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
3994
3995 $outarrayentry = array(
3996 'key' => $outkey,
3997 'value' => $outref,
3998 'label' => $outvallabel,
3999 'qty' => $outqty,
4000 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4001 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4002 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4003 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4004 'tva_tx' => price2num($objp->tva_tx),
4005 'default_vat_code' => $objp->default_vat_code,
4006 'supplier_ref' => $objp->ref_fourn,
4007 'discount' => $outdiscount,
4008 'type' => $outtype,
4009 'duration_value' => $outdurationvalue,
4010 'duration_unit' => $outdurationunit,
4011 'disabled' => empty($objp->idprodfournprice),
4012 'description' => $objp->description
4013 );
4014 if (isModEnabled('multicurrency')) {
4015 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4016 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4017 }
4018
4019 $parameters = array(
4020 'objp' => &$objp,
4021 'optstart' => &$optstart,
4022 'optlabel' => &$optlabel,
4023 'outvallabel' => &$outvallabel,
4024 'outarrayentry' => &$outarrayentry
4025 );
4026 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4027
4028
4029 // Add new entry
4030 // "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
4031 // "label" value of json key array is used by jQuery automatically as text for combo box
4032 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4033 $outarraypush = array(
4034 'key' => $outkey,
4035 'value' => $outref,
4036 'label' => $outvallabel,
4037 'qty' => $outqty,
4038 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4039 'price_qty_ht_locale' => price($objp->fprice),
4040 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4041 'price_unit_ht_locale' => price($objp->unitprice),
4042 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4043 'tva_tx_formated' => price($objp->tva_tx),
4044 'tva_tx' => price2num($objp->tva_tx),
4045 'default_vat_code' => $objp->default_vat_code,
4046 'supplier_ref' => $objp->ref_fourn,
4047 'discount' => $outdiscount,
4048 'type' => $outtype,
4049 'duration_value' => $outdurationvalue,
4050 'duration_unit' => $outdurationunit,
4051 'disabled' => (empty($objp->idprodfournprice) ? true : false),
4052 'description' => $objp->description
4053 );
4054 if (isModEnabled('multicurrency')) {
4055 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4056 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4057 }
4058 array_push($outarray, $outarraypush);
4059
4060 // Example of var_dump $outarray
4061 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4062 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4063 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4064 //}
4065 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4066 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4067 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4068
4069 $i++;
4070 }
4071 $out .= '</select>';
4072
4073 $this->db->free($result);
4074
4075 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4076 $out .= ajax_combobox($htmlname);
4077 } else {
4078 dol_print_error($this->db);
4079 }
4080
4081 if (empty($outputmode)) {
4082 return $out;
4083 }
4084 return $outarray;
4085 }
4086
4087 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4088
4097 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4098 {
4099 // phpcs:enable
4100 global $langs, $conf;
4101
4102 $langs->load('stocks');
4103
4104 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4105 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4106 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4107 $sql .= " FROM " . $this->db->prefix() . "product as p";
4108 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4109 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4110 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4111 $sql .= " AND p.tobuy = 1";
4112 $sql .= " AND s.fournisseur = 1";
4113 $sql .= " AND p.rowid = " . ((int) $productid);
4114 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4115 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4116 } else {
4117 $sql .= " ORDER BY pfp.unitprice ASC";
4118 }
4119
4120 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4121 $result = $this->db->query($sql);
4122
4123 if ($result) {
4124 $num = $this->db->num_rows($result);
4125
4126 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4127
4128 if (!$num) {
4129 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4130 } else {
4131 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4132 $form .= '<option value="0">&nbsp;</option>';
4133
4134 $i = 0;
4135 while ($i < $num) {
4136 $objp = $this->db->fetch_object($result);
4137
4138 $opt = '<option value="' . $objp->idprodfournprice . '"';
4139 //if there is only one supplier, preselect it
4140 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4141 $opt .= ' selected';
4142 }
4143 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4144
4145 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4146 $prod_supplier = new ProductFournisseur($this->db);
4147 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4148 $prod_supplier->id = $productid;
4149 $prod_supplier->fourn_qty = $objp->quantity;
4150 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4151 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4152
4153 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4154 $priceparser = new PriceParser($this->db);
4155 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4156 if ($price_result >= 0) {
4157 $objp->fprice = $price_result;
4158 if ($objp->quantity >= 1) {
4159 $objp->unitprice = $objp->fprice / $objp->quantity;
4160 }
4161 }
4162 }
4163 if ($objp->quantity == 1) {
4164 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4165 }
4166
4167 $opt .= $objp->quantity . ' ';
4168
4169 if ($objp->quantity == 1) {
4170 $opt .= $langs->trans("Unit");
4171 } else {
4172 $opt .= $langs->trans("Units");
4173 }
4174 if ($objp->quantity > 1) {
4175 $opt .= " - ";
4176 $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");
4177 }
4178 if ($objp->duration) {
4179 $opt .= " - " . $objp->duration;
4180 }
4181 $opt .= "</option>\n";
4182
4183 $form .= $opt;
4184 $i++;
4185 }
4186 }
4187
4188 $form .= '</select>';
4189 $this->db->free($result);
4190 return $form;
4191 } else {
4192 dol_print_error($this->db);
4193 return '';
4194 }
4195 }
4196
4197
4198 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4205 {
4206 // phpcs:enable
4207 global $langs;
4208
4209 $num = count($this->cache_conditions_paiements);
4210 if ($num > 0) {
4211 return 0; // Cache already loaded
4212 }
4213
4214 dol_syslog(__METHOD__, LOG_DEBUG);
4215
4216 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4217 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4218 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4219 $sql .= " AND active > 0";
4220 $sql .= " ORDER BY sortorder";
4221
4222 $resql = $this->db->query($sql);
4223 if ($resql) {
4224 $num = $this->db->num_rows($resql);
4225 $i = 0;
4226 while ($i < $num) {
4227 $obj = $this->db->fetch_object($resql);
4228
4229 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4230 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4231 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4232 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4233 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4234 $i++;
4235 }
4236
4237 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4238
4239 return $num;
4240 } else {
4241 dol_print_error($this->db);
4242 return -1;
4243 }
4244 }
4245
4246 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4247
4253 public function load_cache_availability()
4254 {
4255 // phpcs:enable
4256 global $langs;
4257
4258 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4259 if ($num > 0) {
4260 return 0; // Cache already loaded
4261 }
4262
4263 dol_syslog(__METHOD__, LOG_DEBUG);
4264
4265 $langs->load('propal');
4266
4267 $sql = "SELECT rowid, code, label, position";
4268 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4269 $sql .= " WHERE active > 0";
4270
4271 $resql = $this->db->query($sql);
4272 if ($resql) {
4273 $num = $this->db->num_rows($resql);
4274 $i = 0;
4275 while ($i < $num) {
4276 $obj = $this->db->fetch_object($resql);
4277
4278 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4279 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4280 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4281 $this->cache_availability[$obj->rowid]['label'] = $label;
4282 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4283 $i++;
4284 }
4285
4286 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4287
4288 return $num;
4289 } else {
4290 dol_print_error($this->db);
4291 return -1;
4292 }
4293 }
4294
4305 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4306 {
4307 global $langs, $user;
4308
4309 $this->load_cache_availability();
4310
4311 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4312
4313 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4314 if ($addempty) {
4315 print '<option value="0">&nbsp;</option>';
4316 }
4317 foreach ($this->cache_availability as $id => $arrayavailability) {
4318 if ($selected == $id) {
4319 print '<option value="' . $id . '" selected>';
4320 } else {
4321 print '<option value="' . $id . '">';
4322 }
4323 print dol_escape_htmltag($arrayavailability['label']);
4324 print '</option>';
4325 }
4326 print '</select>';
4327 if ($user->admin) {
4328 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4329 }
4330 print ajax_combobox($htmlname);
4331 }
4332
4338 public function loadCacheInputReason()
4339 {
4340 global $langs;
4341
4342 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4343 if ($num > 0) {
4344 return 0; // Cache already loaded
4345 }
4346
4347 $sql = "SELECT rowid, code, label";
4348 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4349 $sql .= " WHERE active > 0";
4350
4351 $resql = $this->db->query($sql);
4352 if ($resql) {
4353 $num = $this->db->num_rows($resql);
4354 $i = 0;
4355 $tmparray = array();
4356 while ($i < $num) {
4357 $obj = $this->db->fetch_object($resql);
4358
4359 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4360 $label = ($obj->label != '-' ? $obj->label : '');
4361 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4362 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4363 }
4364 if ($langs->trans($obj->code) != $obj->code) {
4365 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4366 }
4367
4368 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4369 $tmparray[$obj->rowid]['code'] = $obj->code;
4370 $tmparray[$obj->rowid]['label'] = $label;
4371 $i++;
4372 }
4373
4374 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4375
4376 unset($tmparray);
4377 return $num;
4378 } else {
4379 dol_print_error($this->db);
4380 return -1;
4381 }
4382 }
4383
4396 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4397 {
4398 global $langs, $user;
4399
4400 $this->loadCacheInputReason();
4401
4402 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4403 if ($addempty) {
4404 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4405 }
4406 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4407 if ($arraydemandreason['code'] == $exclude) {
4408 continue;
4409 }
4410
4411 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4412 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4413 } else {
4414 print '<option value="' . $arraydemandreason['id'] . '">';
4415 }
4416 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4417 print $langs->trans($label);
4418 print '</option>';
4419 }
4420 print '</select>';
4421 if ($user->admin && empty($notooltip)) {
4422 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4423 }
4424 print ajax_combobox('select_' . $htmlname);
4425 }
4426
4427 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4428
4435 {
4436 // phpcs:enable
4437 global $langs;
4438
4439 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4440 if ($num > 0) {
4441 return $num; // Cache already loaded
4442 }
4443
4444 dol_syslog(__METHOD__, LOG_DEBUG);
4445
4446 $this->cache_types_paiements = array();
4447
4448 $sql = "SELECT id, code, libelle as label, type, active";
4449 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4450 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4451
4452 $resql = $this->db->query($sql);
4453 if ($resql) {
4454 $num = $this->db->num_rows($resql);
4455 $i = 0;
4456 while ($i < $num) {
4457 $obj = $this->db->fetch_object($resql);
4458
4459 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4460 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4461 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4462 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4463 $this->cache_types_paiements[$obj->id]['label'] = $label;
4464 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4465 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4466 $i++;
4467 }
4468
4469 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4470
4471 return $num;
4472 } else {
4473 dol_print_error($this->db);
4474 return -1;
4475 }
4476 }
4477
4478
4479 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4480
4499 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4500 {
4501 // phpcs:enable
4502 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4503 if (empty($noprint)) {
4504 print $out;
4505 } else {
4506 return $out;
4507 }
4508 }
4509
4510
4527 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4528 {
4529 global $langs, $user, $conf;
4530
4531 $out = '';
4532 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4533
4535
4536 // Set default value if not already set by caller
4537 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4538 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4539 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4540 }
4541
4542 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4543 if ($addempty) {
4544 $out .= '<option value="0">&nbsp;</option>';
4545 }
4546
4547 $selectedDepositPercent = null;
4548
4549 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4550 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4551 continue;
4552 }
4553
4554 if ($selected == $id) {
4555 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4556 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4557 } else {
4558 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4559 }
4560 $label = $arrayconditions['label'];
4561
4562 if (!empty($arrayconditions['deposit_percent'])) {
4563 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4564 }
4565
4566 $out .= $label;
4567 $out .= '</option>';
4568 }
4569 $out .= '</select>';
4570 if ($user->admin && empty($noinfoadmin)) {
4571 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4572 }
4573 $out .= ajax_combobox($htmlname);
4574
4575 if ($deposit_percent >= 0) {
4576 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4577 $out .= $langs->trans('DepositPercent') . ' : ';
4578 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4579 $out .= '</span>';
4580 $out .= '
4581 <script nonce="' . getNonce() . '">
4582 $(document).ready(function () {
4583 $("#' . $htmlname . '").change(function () {
4584 let $selected = $(this).find("option:selected");
4585 let depositPercent = $selected.attr("data-deposit_percent");
4586
4587 if (depositPercent.length > 0) {
4588 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4589 } else {
4590 $("#' . $htmlname . '_deposit_percent_container").hide();
4591 }
4592
4593 return true;
4594 });
4595 });
4596 </script>';
4597 }
4598
4599 return $out;
4600 }
4601
4602
4603 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4604
4621 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4622 {
4623 // phpcs:enable
4624 global $langs, $user, $conf;
4625
4626 $out = '';
4627
4628 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4629
4630 $filterarray = array();
4631 if ($filtertype == 'CRDT') {
4632 $filterarray = array(0, 2, 3);
4633 } elseif ($filtertype == 'DBIT') {
4634 $filterarray = array(1, 2, 3);
4635 } elseif ($filtertype != '' && $filtertype != '-1') {
4636 $filterarray = explode(',', $filtertype);
4637 }
4638
4640
4641 // Set default value if not already set by caller
4642 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4643 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4644 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4645 }
4646
4647 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4648 if ($empty) {
4649 $out .= '<option value="">&nbsp;</option>';
4650 }
4651 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4652 // If not good status
4653 if ($active >= 0 && $arraytypes['active'] != $active) {
4654 continue;
4655 }
4656
4657 // We skip of the user requested to filter on specific payment methods
4658 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4659 continue;
4660 }
4661
4662 // We discard empty lines if showempty is on because an empty line has already been output.
4663 if ($empty && empty($arraytypes['code'])) {
4664 continue;
4665 }
4666
4667 if ($format == 0) {
4668 $out .= '<option value="' . $id . '"';
4669 } elseif ($format == 1) {
4670 $out .= '<option value="' . $arraytypes['code'] . '"';
4671 } elseif ($format == 2) {
4672 $out .= '<option value="' . $arraytypes['code'] . '"';
4673 } elseif ($format == 3) {
4674 $out .= '<option value="' . $id . '"';
4675 }
4676 // Print attribute selected or not
4677 if ($format == 1 || $format == 2) {
4678 if ($selected == $arraytypes['code']) {
4679 $out .= ' selected';
4680 }
4681 } else {
4682 if ($selected == $id) {
4683 $out .= ' selected';
4684 }
4685 }
4686 $out .= '>';
4687 $value = '';
4688 if ($format == 0) {
4689 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4690 } elseif ($format == 1) {
4691 $value = $arraytypes['code'];
4692 } elseif ($format == 2) {
4693 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4694 } elseif ($format == 3) {
4695 $value = $arraytypes['code'];
4696 }
4697 $out .= $value ? $value : '&nbsp;';
4698 $out .= '</option>';
4699 }
4700 $out .= '</select>';
4701 if ($user->admin && !$noadmininfo) {
4702 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4703 }
4704 $out .= ajax_combobox('select' . $htmlname);
4705
4706 if (empty($nooutput)) {
4707 print $out;
4708 } else {
4709 return $out;
4710 }
4711 }
4712
4713
4722 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4723 {
4724 global $langs;
4725
4726 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4727 $options = array(
4728 'HT' => $langs->trans("HT"),
4729 'TTC' => $langs->trans("TTC")
4730 );
4731 foreach ($options as $id => $value) {
4732 if ($selected == $id) {
4733 $return .= '<option value="' . $id . '" selected>' . $value;
4734 } else {
4735 $return .= '<option value="' . $id . '">' . $value;
4736 }
4737 $return .= '</option>';
4738 }
4739 $return .= '</select>';
4740 if ($addjscombo) {
4741 $return .= ajax_combobox('select_' . $htmlname);
4742 }
4743
4744 return $return;
4745 }
4746
4747 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4748
4755 {
4756 // phpcs:enable
4757 global $langs;
4758
4759 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4760 if ($num > 0) {
4761 return $num; // Cache already loaded
4762 }
4763
4764 dol_syslog(__METHOD__, LOG_DEBUG);
4765
4766 $this->cache_transport_mode = array();
4767
4768 $sql = "SELECT rowid, code, label, active";
4769 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4770 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4771
4772 $resql = $this->db->query($sql);
4773 if ($resql) {
4774 $num = $this->db->num_rows($resql);
4775 $i = 0;
4776 while ($i < $num) {
4777 $obj = $this->db->fetch_object($resql);
4778
4779 // If traduction exist, we use it else we take the default label
4780 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4781 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4782 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4783 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4784 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4785 $i++;
4786 }
4787
4788 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4789
4790 return $num;
4791 } else {
4792 dol_print_error($this->db);
4793 return -1;
4794 }
4795 }
4796
4810 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4811 {
4812 global $langs, $user;
4813
4814 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4815
4817
4818 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4819 if ($empty) {
4820 print '<option value="">&nbsp;</option>';
4821 }
4822 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4823 // If not good status
4824 if ($active >= 0 && $arraytypes['active'] != $active) {
4825 continue;
4826 }
4827
4828 // We discard empty line if showempty is on because an empty line has already been output.
4829 if ($empty && empty($arraytypes['code'])) {
4830 continue;
4831 }
4832
4833 if ($format == 0) {
4834 print '<option value="' . $id . '"';
4835 } elseif ($format == 1) {
4836 print '<option value="' . $arraytypes['code'] . '"';
4837 } elseif ($format == 2) {
4838 print '<option value="' . $arraytypes['code'] . '"';
4839 } elseif ($format == 3) {
4840 print '<option value="' . $id . '"';
4841 }
4842 // If text is selected, we compare with code, else with id
4843 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4844 print ' selected';
4845 } elseif ($selected == $id) {
4846 print ' selected';
4847 }
4848 print '>';
4849 $value = '';
4850 if ($format == 0) {
4851 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4852 } elseif ($format == 1) {
4853 $value = $arraytypes['code'];
4854 } elseif ($format == 2) {
4855 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4856 } elseif ($format == 3) {
4857 $value = $arraytypes['code'];
4858 }
4859 print $value ? $value : '&nbsp;';
4860 print '</option>';
4861 }
4862 print '</select>';
4863 if ($user->admin && !$noadmininfo) {
4864 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4865 }
4866 }
4867
4880 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4881 {
4882 global $langs, $user;
4883
4884 $langs->load("admin");
4885 $langs->load("deliveries");
4886
4887 $sql = "SELECT rowid, code, libelle as label";
4888 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4889 $sql .= " WHERE active > 0";
4890 if ($filtre) {
4891 $sql .= " AND " . $filtre;
4892 }
4893 $sql .= " ORDER BY libelle ASC";
4894
4895 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4896 $result = $this->db->query($sql);
4897 if ($result) {
4898 $num = $this->db->num_rows($result);
4899 $i = 0;
4900 if ($num) {
4901 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4902 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4903 print '<option value="-1">&nbsp;</option>';
4904 }
4905 while ($i < $num) {
4906 $obj = $this->db->fetch_object($result);
4907 if ($selected == $obj->rowid) {
4908 print '<option value="' . $obj->rowid . '" selected>';
4909 } else {
4910 print '<option value="' . $obj->rowid . '">';
4911 }
4912 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4913 print '</option>';
4914 $i++;
4915 }
4916 print "</select>";
4917 if ($user->admin && empty($noinfoadmin)) {
4918 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4919 }
4920
4921 print ajax_combobox('select' . $htmlname);
4922 } else {
4923 print $langs->trans("NoShippingMethodDefined");
4924 }
4925 } else {
4926 dol_print_error($this->db);
4927 }
4928 }
4929
4939 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4940 {
4941 global $langs;
4942
4943 $langs->load("deliveries");
4944
4945 if ($htmlname != "none") {
4946 print '<form method="POST" action="' . $page . '">';
4947 print '<input type="hidden" name="action" value="setshippingmethod">';
4948 print '<input type="hidden" name="token" value="' . newToken() . '">';
4949 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4950 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4951 print '</form>';
4952 } else {
4953 if ($selected) {
4954 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4955 print $langs->trans("SendingMethod" . strtoupper($code));
4956 } else {
4957 print "&nbsp;";
4958 }
4959 }
4960 }
4961
4970 public function selectSituationInvoices($selected = '', $socid = 0)
4971 {
4972 global $langs;
4973
4974 $langs->load('bills');
4975
4976 $opt = '<option value="" selected></option>';
4977 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4978 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
4979 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
4980 $sql .= ' AND situation_counter >= 1';
4981 $sql .= ' AND fk_soc = ' . (int) $socid;
4982 $sql .= ' AND type <> 2';
4983 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4984 $resql = $this->db->query($sql);
4985
4986 if ($resql && $this->db->num_rows($resql) > 0) {
4987 // Last seen cycle
4988 $ref = 0;
4989 while ($obj = $this->db->fetch_object($resql)) {
4990 //Same cycle ?
4991 if ($obj->situation_cycle_ref != $ref) {
4992 // Just seen this cycle
4993 $ref = $obj->situation_cycle_ref;
4994 //not final ?
4995 if ($obj->situation_final != 1) {
4996 //Not prov?
4997 if (substr($obj->ref, 1, 4) != 'PROV') {
4998 if ($selected == $obj->rowid) {
4999 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
5000 } else {
5001 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5002 }
5003 }
5004 }
5005 }
5006 }
5007 } else {
5008 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5009 }
5010 if ($opt == '<option value ="" selected></option>') {
5011 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5012 }
5013 return $opt;
5014 }
5015
5025 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5026 {
5027 global $langs;
5028
5029 $langs->load('products');
5030
5031 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5032
5033 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5034 $sql .= ' WHERE active > 0';
5035 if (!empty($unit_type)) {
5036 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5037 }
5038 $sql .= " ORDER BY sortorder";
5039
5040 $resql = $this->db->query($sql);
5041 if ($resql && $this->db->num_rows($resql) > 0) {
5042 if ($showempty) {
5043 $return .= '<option value="none"></option>';
5044 }
5045
5046 while ($res = $this->db->fetch_object($resql)) {
5047 $unitLabel = $res->label;
5048 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5049 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5050 }
5051
5052 if ($selected == $res->rowid) {
5053 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5054 } else {
5055 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5056 }
5057 }
5058 $return .= '</select>';
5059 }
5060 return $return;
5061 }
5062
5063 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5064
5079 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5080 {
5081 // phpcs:enable
5082 global $langs;
5083
5084 $out = '';
5085
5086 $langs->load("admin");
5087 $num = 0;
5088
5089 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5090 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5091 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5092 if ($status != 2) {
5093 $sql .= " AND clos = " . (int) $status;
5094 }
5095 if ($filtre) { // TODO Support USF
5096 $sql .= " AND " . $filtre;
5097 }
5098 $sql .= " ORDER BY label";
5099
5100 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5101 $result = $this->db->query($sql);
5102 if ($result) {
5103 $num = $this->db->num_rows($result);
5104 $i = 0;
5105 if ($num) {
5106 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5107
5108 if (!empty($useempty) && !is_numeric($useempty)) {
5109 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5110 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5111 $out .= '<option value="-1">&nbsp;</option>';
5112 }
5113
5114 while ($i < $num) {
5115 $obj = $this->db->fetch_object($result);
5116 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5117 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
5118 } else {
5119 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
5120 }
5121 $out .= trim($obj->label);
5122 if ($showcurrency) {
5123 $out .= ' (' . $obj->currency_code . ')';
5124 }
5125 if ($status == 2 && $obj->status == 1) {
5126 $out .= ' (' . $langs->trans("Closed") . ')';
5127 }
5128 $out .= '</option>';
5129 $i++;
5130 }
5131 $out .= "</select>";
5132 $out .= ajax_combobox('select' . $htmlname);
5133 } else {
5134 if ($status == 0) {
5135 $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5136 } else {
5137 $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
5138 }
5139 }
5140 } else {
5141 dol_print_error($this->db);
5142 }
5143
5144 // Output or return
5145 if (empty($nooutput)) {
5146 print $out;
5147 } else {
5148 return $out;
5149 }
5150
5151 return $num;
5152 }
5153
5165 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5166 {
5167 global $langs;
5168
5169 $langs->load("admin");
5170 $num = 0;
5171
5172 $sql = "SELECT rowid, name, fk_country, status, entity";
5173 $sql .= " FROM " . $this->db->prefix() . "establishment";
5174 $sql .= " WHERE 1=1";
5175 if ($status != 2) {
5176 $sql .= " AND status = " . (int) $status;
5177 }
5178 if ($filtre) { // TODO Support USF
5179 $sql .= " AND " . $filtre;
5180 }
5181 $sql .= " ORDER BY name";
5182
5183 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5184 $result = $this->db->query($sql);
5185 if ($result) {
5186 $num = $this->db->num_rows($result);
5187 $i = 0;
5188 if ($num) {
5189 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5190 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5191 print '<option value="-1">&nbsp;</option>';
5192 }
5193
5194 while ($i < $num) {
5195 $obj = $this->db->fetch_object($result);
5196 if ($selected == $obj->rowid) {
5197 print '<option value="' . $obj->rowid . '" selected>';
5198 } else {
5199 print '<option value="' . $obj->rowid . '">';
5200 }
5201 print trim($obj->name);
5202 if ($status == 2 && $obj->status == 1) {
5203 print ' (' . $langs->trans("Closed") . ')';
5204 }
5205 print '</option>';
5206 $i++;
5207 }
5208 print "</select>";
5209 } else {
5210 if ($status == 0) {
5211 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5212 } else {
5213 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5214 }
5215 }
5216
5217 return $num;
5218 } else {
5219 dol_print_error($this->db);
5220 return -1;
5221 }
5222 }
5223
5233 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5234 {
5235 global $langs;
5236 if ($htmlname != "none") {
5237 print '<form method="POST" action="' . $page . '">';
5238 print '<input type="hidden" name="action" value="setbankaccount">';
5239 print '<input type="hidden" name="token" value="' . newToken() . '">';
5240 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5241 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5242 if ($nbaccountfound > 0) {
5243 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5244 }
5245 print '</form>';
5246 } else {
5247 $langs->load('banks');
5248
5249 if ($selected) {
5250 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5251 $bankstatic = new Account($this->db);
5252 $result = $bankstatic->fetch($selected);
5253 if ($result) {
5254 print $bankstatic->getNomUrl(1);
5255 }
5256 } else {
5257 print "&nbsp;";
5258 }
5259 }
5260 }
5261
5262 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5263
5283 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5284 {
5285 // phpcs:enable
5286 global $conf, $langs;
5287 $langs->load("categories");
5288
5289 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5290
5291 // For backward compatibility
5292 if (is_numeric($type)) {
5293 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5294 }
5295
5296 if ($type === Categorie::TYPE_BANK_LINE) {
5297 // TODO Move this into common category feature
5298 $cate_arbo = array();
5299 $sql = "SELECT c.label, c.rowid";
5300 $sql .= " FROM " . $this->db->prefix() . "bank_categ as c";
5301 $sql .= " WHERE entity = " . $conf->entity;
5302 $sql .= " ORDER BY c.label";
5303 $result = $this->db->query($sql);
5304 if ($result) {
5305 $num = $this->db->num_rows($result);
5306 $i = 0;
5307 while ($i < $num) {
5308 $objp = $this->db->fetch_object($result);
5309 if ($objp) {
5310 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5311 }
5312 $i++;
5313 }
5314 $this->db->free($result);
5315 } else {
5316 dol_print_error($this->db);
5317 }
5318 } else {
5319 $cat = new Categorie($this->db);
5320 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5321 }
5322
5323 $outarray = array();
5324 $outarrayrichhtml = array();
5325
5326
5327 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5328 if (is_array($cate_arbo)) {
5329 $num = count($cate_arbo);
5330
5331 if (!$num) {
5332 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5333 } else {
5334 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5335 $output .= '<option value="-1">&nbsp;</option>';
5336 }
5337 foreach ($cate_arbo as $key => $value) {
5338 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5339 $add = 'selected ';
5340 } else {
5341 $add = '';
5342 }
5343
5344 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5345 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5346
5347 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5348
5349 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5350
5351 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5352 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5353 $output .= '>';
5354 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5355 $output .= '</option>';
5356
5357 $cate_arbo[$key]['data-html'] = $labeltoshow;
5358 }
5359 }
5360 }
5361 $output .= '</select>';
5362 $output .= "\n";
5363
5364 if ($outputmode == 2) {
5365 // TODO: handle error when $cate_arbo is not an array
5366 return $cate_arbo;
5367 } elseif ($outputmode == 1) {
5368 return $outarray;
5369 } elseif ($outputmode == 3) {
5370 return $outarrayrichhtml;
5371 }
5372 return $output;
5373 }
5374
5375 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5376
5393 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5394 {
5395 // phpcs:enable
5396 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5397 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5398 }
5399
5427 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5428 {
5429 global $langs, $conf;
5430
5431 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5432 $formconfirm = '';
5433 $inputok = array();
5434 $inputko = array();
5435
5436 // Clean parameters
5437 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5438 if ($conf->browser->layout == 'phone') {
5439 $width = '95%';
5440 }
5441
5442 // Set height automatically if not defined
5443 if (empty($height)) {
5444 $height = 220;
5445 if (is_array($formquestion) && count($formquestion) > 2) {
5446 $height += ((count($formquestion) - 2) * 24);
5447 }
5448 }
5449
5450 if (is_array($formquestion) && !empty($formquestion)) {
5451 // First add hidden fields and value
5452 foreach ($formquestion as $key => $input) {
5453 if (is_array($input) && !empty($input)) {
5454 if ($input['type'] == 'hidden') {
5455 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5456 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5457
5458 $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";
5459 }
5460 }
5461 }
5462
5463 // Now add questions
5464 $moreonecolumn = '';
5465 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5466 foreach ($formquestion as $key => $input) {
5467 if (is_array($input) && !empty($input)) {
5468 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5469 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5470 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5471
5472 if ($input['type'] == 'text') {
5473 $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";
5474 } elseif ($input['type'] == 'password') {
5475 $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";
5476 } elseif ($input['type'] == 'textarea') {
5477 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5478 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5479 $more .= $input['value'];
5480 $more .= '</textarea>';
5481 $more .= '</div></div>'."\n";*/
5482 $moreonecolumn .= '<div class="margintoponly">';
5483 $moreonecolumn .= $input['label'] . '<br>';
5484 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5485 $moreonecolumn .= $input['value'];
5486 $moreonecolumn .= '</textarea>';
5487 $moreonecolumn .= '</div>';
5488 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5489 if (empty($morecss)) {
5490 $morecss = 'minwidth100';
5491 }
5492
5493 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5494 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5495 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5496 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5497 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5498 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5499 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5500
5501 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5502 if (!empty($input['label'])) {
5503 $more .= $input['label'] . '</div><div class="tagtd left">';
5504 }
5505 if ($input['type'] == 'select') {
5506 $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);
5507 } else {
5508 $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);
5509 }
5510 $more .= '</div></div>' . "\n";
5511 } elseif ($input['type'] == 'checkbox') {
5512 $more .= '<div class="tagtr">';
5513 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5514 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5515 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5516 $more .= ' checked';
5517 }
5518 if (is_bool($input['value']) && $input['value']) {
5519 $more .= ' checked';
5520 }
5521 if (isset($input['disabled'])) {
5522 $more .= ' disabled';
5523 }
5524 $more .= ' /></div>';
5525 $more .= '</div>' . "\n";
5526 } elseif ($input['type'] == 'radio') {
5527 $i = 0;
5528 foreach ($input['values'] as $selkey => $selval) {
5529 $more .= '<div class="tagtr">';
5530 if (isset($input['label'])) {
5531 if ($i == 0) {
5532 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5533 } else {
5534 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5535 }
5536 }
5537 $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;
5538 if (!empty($input['disabled'])) {
5539 $more .= ' disabled';
5540 }
5541 if (isset($input['default']) && $input['default'] === $selkey) {
5542 $more .= ' checked="checked"';
5543 }
5544 $more .= ' /> ';
5545 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5546 $more .= '</div></div>' . "\n";
5547 $i++;
5548 }
5549 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5550 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5551 $more .= '<div class="tagtd">';
5552 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5553 $h = $m = 0;
5554 if ($input['type'] == 'datetime') {
5555 $h = isset($input['hours']) ? $input['hours'] : 1;
5556 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5557 }
5558 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5559 $more .= '</div></div>'."\n";
5560 $formquestion[] = array('name' => $input['name'].'day');
5561 $formquestion[] = array('name' => $input['name'].'month');
5562 $formquestion[] = array('name' => $input['name'].'year');
5563 $formquestion[] = array('name' => $input['name'].'hour');
5564 $formquestion[] = array('name' => $input['name'].'min');
5565 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5566 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5567 if (!empty($input['label'])) {
5568 $more .= $input['label'] . '</div><div class="tagtd">';
5569 }
5570 $more .= $input['value'];
5571 $more .= '</div></div>' . "\n";
5572 } elseif ($input['type'] == 'onecolumn') {
5573 $moreonecolumn .= '<div class="margintoponly">';
5574 $moreonecolumn .= $input['value'];
5575 $moreonecolumn .= '</div>' . "\n";
5576 } elseif ($input['type'] == 'hidden') {
5577 // Do nothing more, already added by a previous loop
5578 } elseif ($input['type'] == 'separator') {
5579 $more .= '<br>';
5580 } else {
5581 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5582 }
5583 }
5584 }
5585 $more .= '</div>' . "\n";
5586 $more .= $moreonecolumn;
5587 }
5588
5589 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5590 // 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
5591 // See page product/card.php for example
5592 if (!empty($conf->dol_use_jmobile)) {
5593 $useajax = 0;
5594 }
5595 if (empty($conf->use_javascript_ajax)) {
5596 $useajax = 0;
5597 }
5598
5599 if ($useajax) {
5600 $autoOpen = true;
5601 $dialogconfirm = 'dialog-confirm';
5602 $button = '';
5603 if (!is_numeric($useajax)) {
5604 $button = $useajax;
5605 $useajax = 1;
5606 $autoOpen = false;
5607 $dialogconfirm .= '-' . $button;
5608 }
5609 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5610 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5611
5612 // Add input fields into list of fields to read during submit (inputok and inputko)
5613 if (is_array($formquestion)) {
5614 foreach ($formquestion as $key => $input) {
5615 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5616 // Add name of fields to propagate with the GET when submitting the form with button OK.
5617 if (is_array($input) && isset($input['name'])) {
5618 if (strpos($input['name'], ',') > 0) {
5619 $inputok = array_merge($inputok, explode(',', $input['name']));
5620 } else {
5621 array_push($inputok, $input['name']);
5622 }
5623 }
5624 // Add name of fields to propagate with the GET when submitting the form with button KO.
5625 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5626 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5627 array_push($inputko, $input['name']);
5628 }
5629 }
5630 }
5631
5632 // Show JQuery confirm box.
5633 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5634 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5635 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5636 }
5637 if (!empty($more)) {
5638 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5639 }
5640 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5641 $formconfirm .= '</div>' . "\n";
5642
5643 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5644 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5645 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5646 $formconfirm .= 'jQuery(document).ready(function() {
5647 $(function() {
5648 $( "#' . $dialogconfirm . '" ).dialog(
5649 {
5650 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5651 if ($newselectedchoice == 'no') {
5652 $formconfirm .= '
5653 open: function() {
5654 $(this).parent().find("button.ui-button:eq(2)").focus();
5655 },';
5656 }
5657
5658 $jsforcursor = '';
5659 if ($useajax == 1) {
5660 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5661 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5662 }
5663
5664 $postconfirmas = 'GET';
5665
5666 $formconfirm .= '
5667 resizable: false,
5668 height: "' . $height . '",
5669 width: "' . $width . '",
5670 modal: true,
5671 closeOnEscape: false,
5672 buttons: {
5673 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5674 var options = "token=' . urlencode(newToken()) . '";
5675 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5676 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5677 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5678
5679 if (inputok.length > 0) {
5680 $.each(inputok, function(i, inputname) {
5681 var more = "";
5682 var inputvalue;
5683 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5684 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5685 } else {
5686 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5687 inputvalue = $("#" + inputname + more).val();
5688 }
5689 if (typeof inputvalue == "undefined") { inputvalue=""; }
5690 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5691 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5692 });
5693 }
5694 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5695 if (pageyes.length > 0) {';
5696 if ($postconfirmas == 'GET') {
5697 $formconfirm .= 'location.href = urljump;';
5698 } else {
5699 $formconfirm .= $jsforcursor;
5700 $formconfirm .= 'var post = $.post(
5701 pageyes,
5702 options,
5703 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5704 );';
5705 }
5706 $formconfirm .= '
5707 console.log("after post ok");
5708 }
5709 $(this).dialog("close");
5710 },
5711 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5712 var options = "token=' . urlencode(newToken()) . '";
5713 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5714 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5715 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5716 if (inputko.length > 0) {
5717 $.each(inputko, function(i, inputname) {
5718 var more = "";
5719 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5720 var inputvalue = $("#" + inputname + more).val();
5721 if (typeof inputvalue == "undefined") { inputvalue=""; }
5722 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5723 });
5724 }
5725 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5726 //alert(urljump);
5727 if (pageno.length > 0) {';
5728 if ($postconfirmas == 'GET') {
5729 $formconfirm .= 'location.href = urljump;';
5730 } else {
5731 $formconfirm .= $jsforcursor;
5732 $formconfirm .= 'var post = $.post(
5733 pageno,
5734 options,
5735 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5736 );';
5737 }
5738 $formconfirm .= '
5739 console.log("after post ko");
5740 }
5741 $(this).dialog("close");
5742 }
5743 }
5744 }
5745 );
5746
5747 var button = "' . $button . '";
5748 if (button.length > 0) {
5749 $( "#" + button ).click(function() {
5750 $("#' . $dialogconfirm . '").dialog("open");
5751 });
5752 }
5753 });
5754 });
5755 </script>';
5756 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5757 } else {
5758 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5759
5760 if (empty($disableformtag)) {
5761 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5762 }
5763
5764 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5765 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5766
5767 $formconfirm .= '<table class="valid centpercent">' . "\n";
5768
5769 // Line title
5770 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5771 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5772 $formconfirm .= '</td></tr>' . "\n";
5773
5774 // Line text
5775 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5776 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5777 }
5778
5779 // Line form fields
5780 if ($more) {
5781 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5782 $formconfirm .= $more;
5783 $formconfirm .= '</td></tr>' . "\n";
5784 }
5785
5786 // Line with question
5787 $formconfirm .= '<tr class="valid">';
5788 $formconfirm .= '<td class="valid">' . $question . '</td>';
5789 $formconfirm .= '<td class="valid center">';
5790 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5791 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5792 $formconfirm .= '</td>';
5793 $formconfirm .= '</tr>' . "\n";
5794
5795 $formconfirm .= '</table>' . "\n";
5796
5797 if (empty($disableformtag)) {
5798 $formconfirm .= "</form>\n";
5799 }
5800 $formconfirm .= '<br>';
5801
5802 if (!empty($conf->use_javascript_ajax)) {
5803 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5804 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5805 $formconfirm .= '
5806 $(document).ready(function () {
5807 $(".confirmvalidatebutton").on("click", function() {
5808 console.log("We click on button confirmvalidatebutton");
5809 $(this).attr("disabled", "disabled");
5810 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5811 //console.log($(this).closest("form"));
5812 $(this).closest("form").submit();
5813 });
5814 });
5815 ';
5816 $formconfirm .= '</script>' . "\n";
5817 }
5818
5819 $formconfirm .= "<!-- end formconfirm -->\n";
5820 }
5821
5822 return $formconfirm;
5823 }
5824
5825
5826 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5827
5843 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5844 {
5845 // phpcs:enable
5846 global $langs;
5847
5848 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5849 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5850
5851 $out = '';
5852
5853 $formproject = new FormProjets($this->db);
5854
5855 $langs->load("project");
5856 if ($htmlname != "none") {
5857 $out .= '<form method="post" action="' . $page . '">';
5858 $out .= '<input type="hidden" name="action" value="classin">';
5859 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5860 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5861 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5862 $out .= '</form>';
5863 } else {
5864 $out .= '<span class="project_head_block">';
5865 if ($selected) {
5866 $projet = new Project($this->db);
5867 $projet->fetch($selected);
5868 $out .= $projet->getNomUrl(0, '', 1);
5869 } else {
5870 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5871 }
5872 $out .= '</span>';
5873 }
5874
5875 if (empty($nooutput)) {
5876 print $out;
5877 return '';
5878 }
5879 return $out;
5880 }
5881
5882 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5883
5899 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5900 {
5901 // phpcs:enable
5902 global $langs;
5903
5904 $out = '';
5905
5906 if ($htmlname != "none") {
5907 $out .= '<form method="POST" action="' . $page . '">';
5908 $out .= '<input type="hidden" name="action" value="setconditions">';
5909 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5910 if ($type) {
5911 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5912 }
5913 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5914 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5915 $out .= '</form>';
5916 } else {
5917 if ($selected) {
5919 if (isset($this->cache_conditions_paiements[$selected])) {
5920 $label = $this->cache_conditions_paiements[$selected]['label'];
5921
5922 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5923 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5924 }
5925
5926 $out .= $label;
5927 } else {
5928 $langs->load('errors');
5929 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5930 }
5931 } else {
5932 $out .= '&nbsp;';
5933 }
5934 }
5935
5936 if (empty($nooutput)) {
5937 print $out;
5938 return '';
5939 }
5940 return $out;
5941 }
5942
5943 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5944
5954 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5955 {
5956 // phpcs:enable
5957 global $langs;
5958 if ($htmlname != "none") {
5959 print '<form method="post" action="' . $page . '">';
5960 print '<input type="hidden" name="action" value="setavailability">';
5961 print '<input type="hidden" name="token" value="' . newToken() . '">';
5962 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5963 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5964 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5965 print '</form>';
5966 } else {
5967 if ($selected) {
5968 $this->load_cache_availability();
5969 print $this->cache_availability[$selected]['label'];
5970 } else {
5971 print "&nbsp;";
5972 }
5973 }
5974 }
5975
5986 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5987 {
5988 global $langs;
5989 if ($htmlname != "none") {
5990 print '<form method="post" action="' . $page . '">';
5991 print '<input type="hidden" name="action" value="setdemandreason">';
5992 print '<input type="hidden" name="token" value="' . newToken() . '">';
5993 $this->selectInputReason($selected, $htmlname, -1, $addempty);
5994 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5995 print '</form>';
5996 } else {
5997 if ($selected) {
5998 $this->loadCacheInputReason();
5999 foreach ($this->cache_demand_reason as $key => $val) {
6000 if ($val['id'] == $selected) {
6001 print $val['label'];
6002 break;
6003 }
6004 }
6005 } else {
6006 print "&nbsp;";
6007 }
6008 }
6009 }
6010
6011 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6012
6026 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6027 {
6028 // phpcs:enable
6029 global $langs;
6030
6031 $ret = '';
6032
6033 if ($htmlname != "none") {
6034 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6035 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6036 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6037 if ($type) {
6038 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6039 }
6040 $ret .= '<table class="nobordernopadding">';
6041 $ret .= '<tr><td>';
6042 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6043 $ret .= '</td>';
6044 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6045 $ret .= '</tr></table></form>';
6046 } else {
6047 if ($displayhour) {
6048 $ret .= dol_print_date($selected, 'dayhour');
6049 } else {
6050 $ret .= dol_print_date($selected, 'day');
6051 }
6052 }
6053
6054 if (empty($nooutput)) {
6055 print $ret;
6056 }
6057 return $ret;
6058 }
6059
6060
6061 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6062
6073 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6074 {
6075 // phpcs:enable
6076 global $langs;
6077
6078 if ($htmlname != "none") {
6079 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6080 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6081 print '<input type="hidden" name="token" value="' . newToken() . '">';
6082 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6083 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6084 print '</form>';
6085 } else {
6086 if ($selected) {
6087 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6088 $theuser = new User($this->db);
6089 $theuser->fetch($selected);
6090 print $theuser->getNomUrl(1);
6091 } else {
6092 print "&nbsp;";
6093 }
6094 }
6095 }
6096
6097
6098 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6099
6113 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6114 {
6115 // phpcs:enable
6116 global $langs;
6117
6118 $out = '';
6119 if ($htmlname != "none") {
6120 $out .= '<form method="POST" action="' . $page . '">';
6121 $out .= '<input type="hidden" name="action" value="setmode">';
6122 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6123 if ($type) {
6124 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6125 }
6126 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6127 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6128 $out .= '</form>';
6129 } else {
6130 if ($selected) {
6132 $out .= $this->cache_types_paiements[$selected]['label'];
6133 } else {
6134 $out .= "&nbsp;";
6135 }
6136 }
6137
6138 if ($nooutput) {
6139 return $out;
6140 } else {
6141 print $out;
6142 }
6143 return '';
6144 }
6145
6156 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6157 {
6158 global $langs;
6159 if ($htmlname != "none") {
6160 print '<form method="POST" action="' . $page . '">';
6161 print '<input type="hidden" name="action" value="settransportmode">';
6162 print '<input type="hidden" name="token" value="' . newToken() . '">';
6163 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6164 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6165 print '</form>';
6166 } else {
6167 if ($selected) {
6169 print $this->cache_transport_mode[$selected]['label'];
6170 } else {
6171 print "&nbsp;";
6172 }
6173 }
6174 }
6175
6176 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6177
6186 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6187 {
6188 // phpcs:enable
6189 global $langs;
6190 if ($htmlname != "none") {
6191 print '<form method="POST" action="' . $page . '">';
6192 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6193 print '<input type="hidden" name="token" value="' . newToken() . '">';
6194 print $this->selectMultiCurrency($selected, $htmlname, 0);
6195 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6196 print '</form>';
6197 } else {
6198 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6199 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6200 }
6201 }
6202
6203 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6204
6214 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6215 {
6216 // phpcs:enable
6217 global $langs, $mysoc, $conf;
6218
6219 if ($htmlname != "none") {
6220 print '<form method="POST" action="' . $page . '">';
6221 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6222 print '<input type="hidden" name="token" value="' . newToken() . '">';
6223 print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6224 print '<select name="calculation_mode">';
6225 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6226 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6227 print '</select> ';
6228 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6229 print '</form>';
6230 } else {
6231 if (!empty($rate)) {
6232 print price($rate, 1, $langs, 0, 0);
6233 if ($currency && $rate != 1) {
6234 print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
6235 }
6236 } else {
6237 print 1;
6238 }
6239 }
6240 }
6241
6242
6243 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6244
6260 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6261 {
6262 // phpcs:enable
6263 global $conf, $langs;
6264 if ($htmlname != "none") {
6265 print '<form method="post" action="' . $page . '">';
6266 print '<input type="hidden" name="action" value="setabsolutediscount">';
6267 print '<input type="hidden" name="token" value="' . newToken() . '">';
6268 print '<div class="inline-block">';
6269 if (!empty($discount_type)) {
6270 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6271 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6272 $translationKey = 'HasAbsoluteDiscountFromSupplier';