dolibarr 20.0.0
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 print $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, $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 if ($socid > 0 || $socid == -1) {
1816 $sql .= " AND sp.fk_soc = " . ((int) $socid);
1817 }
1818 if (getDolGlobalString('CONTACT_HIDE_INACTIVE_IN_COMBOBOX')) {
1819 $sql .= " AND sp.statut <> 0";
1820 }
1821 if ($filter) {
1822 // $filter is safe because, if it contains '(' or ')', it has been sanitized by testSqlAndScriptInject() and forgeSQLFromUniversalSearchCriteria()
1823 // if not, by testSqlAndScriptInject() only.
1824 $sql .= " AND (" . $filter . ")";
1825 }
1826 // Add where from hooks
1827 $parameters = array();
1828 $reshook = $hookmanager->executeHooks('selectContactListWhere', $parameters); // Note that $action and $object may have been modified by hook
1829 $sql .= $hookmanager->resPrint;
1830 $sql .= " ORDER BY sp.lastname ASC";
1831
1832 dol_syslog(get_class($this) . "::selectcontacts", LOG_DEBUG);
1833 $resql = $this->db->query($sql);
1834 if ($resql) {
1835 $num = $this->db->num_rows($resql);
1836
1837 if ($htmlname != 'none' && !$options_only) {
1838 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlid . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . (($num || empty($disableifempty)) ? '' : ' disabled') . ($multiple ? 'multiple' : '') . ' ' . (!empty($moreparam) ? $moreparam : '') . '>';
1839 }
1840
1841 if ($showempty && !is_numeric($showempty)) {
1842 $textforempty = $showempty;
1843 $out .= '<option class="optiongrey" value="-1"' . (in_array(-1, $selected) ? ' selected' : '') . '>' . $textforempty . '</option>';
1844 } else {
1845 if (($showempty == 1 || ($showempty == 3 && $num > 1)) && !$multiple) {
1846 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>&nbsp;</option>';
1847 }
1848 if ($showempty == 2) {
1849 $out .= '<option value="0"' . (in_array(0, $selected) ? ' selected' : '') . '>-- ' . $langs->trans("Internal") . ' --</option>';
1850 }
1851 }
1852
1853 $i = 0;
1854 if ($num) {
1855 include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
1856 $contactstatic = new Contact($this->db);
1857
1858 while ($i < $num) {
1859 $obj = $this->db->fetch_object($resql);
1860
1861 // Set email (or phones) and town extended infos
1862 $extendedInfos = '';
1863 if (getDolGlobalString('CONTACT_SHOW_EMAIL_PHONE_TOWN_SELECTLIST')) {
1864 $extendedInfos = array();
1865 $email = trim($obj->email);
1866 if (!empty($email)) {
1867 $extendedInfos[] = $email;
1868 } else {
1869 $phone = trim($obj->phone);
1870 $phone_perso = trim($obj->phone_perso);
1871 $phone_mobile = trim($obj->phone_mobile);
1872 if (!empty($phone)) {
1873 $extendedInfos[] = $phone;
1874 }
1875 if (!empty($phone_perso)) {
1876 $extendedInfos[] = $phone_perso;
1877 }
1878 if (!empty($phone_mobile)) {
1879 $extendedInfos[] = $phone_mobile;
1880 }
1881 }
1882 $contact_town = trim($obj->contact_town);
1883 $company_town = trim($obj->company_town);
1884 if (!empty($contact_town)) {
1885 $extendedInfos[] = $contact_town;
1886 } elseif (!empty($company_town)) {
1887 $extendedInfos[] = $company_town;
1888 }
1889 $extendedInfos = implode(' - ', $extendedInfos);
1890 if (!empty($extendedInfos)) {
1891 $extendedInfos = ' - ' . $extendedInfos;
1892 }
1893 }
1894
1895 $contactstatic->id = $obj->rowid;
1896 $contactstatic->lastname = $obj->lastname;
1897 $contactstatic->firstname = $obj->firstname;
1898 if ($obj->statut == 1) {
1899 $tmplabel = '';
1900 if ($htmlname != 'none') {
1901 $disabled = 0;
1902 if (is_array($exclude) && count($exclude) && in_array($obj->rowid, $exclude)) {
1903 $disabled = 1;
1904 }
1905 if (is_array($limitto) && count($limitto) && !in_array($obj->rowid, $limitto)) {
1906 $disabled = 1;
1907 }
1908 if (!empty($selected) && in_array($obj->rowid, $selected)) {
1909 $out .= '<option value="' . $obj->rowid . '"';
1910 if ($disabled) {
1911 $out .= ' disabled';
1912 }
1913 $out .= ' selected>';
1914
1915 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1916 if ($showfunction && $obj->poste) {
1917 $tmplabel .= ' (' . $obj->poste . ')';
1918 }
1919 if (($showsoc > 0) && $obj->company) {
1920 $tmplabel .= ' - (' . $obj->company . ')';
1921 }
1922
1923 $out .= $tmplabel;
1924 $out .= '</option>';
1925 } else {
1926 $out .= '<option value="' . $obj->rowid . '"';
1927 if ($disabled) {
1928 $out .= ' disabled';
1929 }
1930 $out .= '>';
1931
1932 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1933 if ($showfunction && $obj->poste) {
1934 $tmplabel .= ' (' . $obj->poste . ')';
1935 }
1936 if (($showsoc > 0) && $obj->company) {
1937 $tmplabel .= ' - (' . $obj->company . ')';
1938 }
1939
1940 $out .= $tmplabel;
1941 $out .= '</option>';
1942 }
1943 } else {
1944 if (in_array($obj->rowid, $selected)) {
1945 $tmplabel = $contactstatic->getFullName($langs) . $extendedInfos;
1946 if ($showfunction && $obj->poste) {
1947 $tmplabel .= ' (' . $obj->poste . ')';
1948 }
1949 if (($showsoc > 0) && $obj->company) {
1950 $tmplabel .= ' - (' . $obj->company . ')';
1951 }
1952
1953 $out .= $tmplabel;
1954 }
1955 }
1956
1957 if ($tmplabel != '') {
1958 array_push($outarray, array('key' => $obj->rowid, 'value' => $tmplabel, 'label' => $tmplabel, 'labelhtml' => $tmplabel));
1959 }
1960 }
1961 $i++;
1962 }
1963 } else {
1964 $labeltoshow = ($socid != -1) ? ($langs->trans($socid ? "NoContactDefinedForThirdParty" : "NoContactDefined")) : $langs->trans('SelectAThirdPartyFirst');
1965 $out .= '<option class="disabled" value="-1"' . (($showempty == 2 || $multiple) ? '' : ' selected') . ' disabled="disabled">';
1966 $out .= $labeltoshow;
1967 $out .= '</option>';
1968 }
1969
1970 $parameters = array(
1971 'socid' => $socid,
1972 'htmlname' => $htmlname,
1973 'resql' => $resql,
1974 'out' => &$out,
1975 'showfunction' => $showfunction,
1976 'showsoc' => $showsoc,
1977 );
1978
1979 $reshook = $hookmanager->executeHooks('afterSelectContactOptions', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
1980
1981 if ($htmlname != 'none' && !$options_only) {
1982 $out .= '</select>';
1983 }
1984
1985 if ($conf->use_javascript_ajax && !$forcecombo && !$options_only) {
1986 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
1987 $out .= ajax_combobox($htmlid, $events, getDolGlobalInt("CONTACT_USE_SEARCH_TO_SELECT"));
1988 }
1989
1990 $this->num = $num;
1991
1992 if ($options_only === 2) {
1993 // Return array of options
1994 return $outarray;
1995 } else {
1996 return $out;
1997 }
1998 } else {
1999 dol_print_error($this->db);
2000 return -1;
2001 }
2002 }
2003
2004
2005 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2006
2017 public function select_remises($selected, $htmlname, $filter, $socid, $maxvalue = 0)
2018 {
2019 // phpcs:enable
2020 global $langs, $conf;
2021
2022 // On recherche les remises
2023 $sql = "SELECT re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc,";
2024 $sql .= " re.description, re.fk_facture_source";
2025 $sql .= " FROM " . $this->db->prefix() . "societe_remise_except as re";
2026 $sql .= " WHERE re.fk_soc = " . (int) $socid;
2027 $sql .= " AND re.entity = " . $conf->entity;
2028 if ($filter) {
2029 $sql .= " AND " . $filter;
2030 }
2031 $sql .= " ORDER BY re.description ASC";
2032
2033 dol_syslog(get_class($this) . "::select_remises", LOG_DEBUG);
2034 $resql = $this->db->query($sql);
2035 if ($resql) {
2036 print '<select id="select_' . $htmlname . '" class="flat maxwidthonsmartphone" name="' . $htmlname . '">';
2037 $num = $this->db->num_rows($resql);
2038
2039 $qualifiedlines = $num;
2040
2041 $i = 0;
2042 if ($num) {
2043 print '<option value="0">&nbsp;</option>';
2044 while ($i < $num) {
2045 $obj = $this->db->fetch_object($resql);
2046 $desc = dol_trunc($obj->description, 40);
2047 if (preg_match('/\‍(CREDIT_NOTE\‍)/', $desc)) {
2048 $desc = preg_replace('/\‍(CREDIT_NOTE\‍)/', $langs->trans("CreditNote"), $desc);
2049 }
2050 if (preg_match('/\‍(DEPOSIT\‍)/', $desc)) {
2051 $desc = preg_replace('/\‍(DEPOSIT\‍)/', $langs->trans("Deposit"), $desc);
2052 }
2053 if (preg_match('/\‍(EXCESS RECEIVED\‍)/', $desc)) {
2054 $desc = preg_replace('/\‍(EXCESS RECEIVED\‍)/', $langs->trans("ExcessReceived"), $desc);
2055 }
2056 if (preg_match('/\‍(EXCESS PAID\‍)/', $desc)) {
2057 $desc = preg_replace('/\‍(EXCESS PAID\‍)/', $langs->trans("ExcessPaid"), $desc);
2058 }
2059
2060 $selectstring = '';
2061 if ($selected > 0 && $selected == $obj->rowid) {
2062 $selectstring = ' selected';
2063 }
2064
2065 $disabled = '';
2066 if ($maxvalue > 0 && $obj->amount_ttc > $maxvalue) {
2067 $qualifiedlines--;
2068 $disabled = ' disabled';
2069 }
2070
2071 if (getDolGlobalString('MAIN_SHOW_FACNUMBER_IN_DISCOUNT_LIST') && !empty($obj->fk_facture_source)) {
2072 $tmpfac = new Facture($this->db);
2073 if ($tmpfac->fetch($obj->fk_facture_source) > 0) {
2074 $desc = $desc . ' - ' . $tmpfac->ref;
2075 }
2076 }
2077
2078 print '<option value="' . $obj->rowid . '"' . $selectstring . $disabled . '>' . $desc . ' (' . price($obj->amount_ht) . ' ' . $langs->trans("HT") . ' - ' . price($obj->amount_ttc) . ' ' . $langs->trans("TTC") . ')</option>';
2079 $i++;
2080 }
2081 }
2082 print '</select>';
2083 print ajax_combobox('select_' . $htmlname);
2084
2085 return $qualifiedlines;
2086 } else {
2087 dol_print_error($this->db);
2088 return -1;
2089 }
2090 }
2091
2092
2093 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2094
2110 public function select_users($selected = '', $htmlname = 'userid', $show_empty = 0, $exclude = null, $disabled = 0, $include = '', $enableonly = array(), $force_entity = '0')
2111 {
2112 // phpcs:enable
2113 print $this->select_dolusers($selected, $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity);
2114 }
2115
2116 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2117
2142 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)
2143 {
2144 // phpcs:enable
2145 global $conf, $user, $langs, $hookmanager;
2146 global $action;
2147
2148 // If no preselected user defined, we take current user
2149 if ((is_numeric($selected) && ($selected < -2 || empty($selected))) && !getDolGlobalString('SOCIETE_DISABLE_DEFAULT_SALESREPRESENTATIVE')) {
2150 $selected = $user->id;
2151 }
2152
2153 if ($selected === '') {
2154 $selected = array();
2155 } elseif (!is_array($selected)) {
2156 $selected = array($selected);
2157 }
2158
2159 $excludeUsers = null;
2160 $includeUsers = null;
2161
2162 // Exclude some users
2163 if (is_array($exclude)) {
2164 $excludeUsers = implode(",", $exclude);
2165 }
2166 // Include some uses
2167 if (is_array($include)) {
2168 $includeUsers = implode(",", $include);
2169 } elseif ($include == 'hierarchy') {
2170 // Build list includeUsers to have only hierarchy
2171 $includeUsers = implode(",", $user->getAllChildIds(0));
2172 } elseif ($include == 'hierarchyme') {
2173 // Build list includeUsers to have only hierarchy and current user
2174 $includeUsers = implode(",", $user->getAllChildIds(1));
2175 }
2176
2177 $num = 0;
2178
2179 $out = '';
2180 $outarray = array();
2181 $outarray2 = array();
2182
2183 // Do we want to show the label of entity into the combo list ?
2184 $showlabelofentity = isModEnabled('multicompany') && !getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE') && $conf->entity == 1 && !empty($user->admin) && empty($user->entity);
2185 $userissuperadminentityone = isModEnabled('multicompany') && $conf->entity == 1 && $user->admin && empty($user->entity);
2186
2187 // Forge request to select users
2188 $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";
2189 if ($showlabelofentity) {
2190 $sql .= ", e.label";
2191 }
2192 $sql .= " FROM " . $this->db->prefix() . "user as u";
2193 if ($showlabelofentity) {
2194 $sql .= " LEFT JOIN " . $this->db->prefix() . "entity as e ON e.rowid = u.entity";
2195 }
2196 // Condition here should be the same than into societe->getSalesRepresentatives().
2197 if ($userissuperadminentityone && $force_entity != 'default') {
2198 if (!empty($force_entity)) {
2199 $sql .= " WHERE u.entity IN (0, " . $this->db->sanitize($force_entity) . ")";
2200 } else {
2201 $sql .= " WHERE u.entity IS NOT NULL";
2202 }
2203 } else {
2204 if (isModEnabled('multicompany') && getDolGlobalInt('MULTICOMPANY_TRANSVERSE_MODE')) {
2205 $sql .= " WHERE u.rowid IN (SELECT ug.fk_user FROM ".$this->db->prefix()."usergroup_user as ug WHERE ug.entity IN (".getEntity('usergroup')."))";
2206 } else {
2207 $sql .= " WHERE u.entity IN (" . getEntity('user') . ")";
2208 }
2209 }
2210
2211 if (!empty($user->socid)) {
2212 $sql .= " AND u.fk_soc = " . ((int) $user->socid);
2213 }
2214 if (is_array($exclude) && $excludeUsers) {
2215 $sql .= " AND u.rowid NOT IN (" . $this->db->sanitize($excludeUsers) . ")";
2216 }
2217 if ($includeUsers) {
2218 $sql .= " AND u.rowid IN (" . $this->db->sanitize($includeUsers) . ")";
2219 }
2220 if (getDolGlobalString('USER_HIDE_INACTIVE_IN_COMBOBOX') || $notdisabled) {
2221 $sql .= " AND u.statut <> 0";
2222 }
2223 if (getDolGlobalString('USER_HIDE_NONEMPLOYEE_IN_COMBOBOX') || $notdisabled) {
2224 $sql .= " AND u.employee <> 0";
2225 }
2226 if (getDolGlobalString('USER_HIDE_EXTERNAL_IN_COMBOBOX') || $notdisabled) {
2227 $sql .= " AND u.fk_soc IS NULL";
2228 }
2229 if (!empty($morefilter)) {
2230 $sql .= " " . $morefilter;
2231 }
2232
2233 //Add hook to filter on user (for example on usergroup define in custom modules)
2234 $reshook = $hookmanager->executeHooks('addSQLWhereFilterOnSelectUsers', array(), $this, $action);
2235 if (!empty($reshook)) {
2236 $sql .= $hookmanager->resPrint;
2237 }
2238
2239 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { // MAIN_FIRSTNAME_NAME_POSITION is 0 means firstname+lastname
2240 $sql .= " ORDER BY u.statut DESC, u.firstname ASC, u.lastname ASC";
2241 } else {
2242 $sql .= " ORDER BY u.statut DESC, u.lastname ASC, u.firstname ASC";
2243 }
2244
2245 dol_syslog(get_class($this) . "::select_dolusers", LOG_DEBUG);
2246
2247 $resql = $this->db->query($sql);
2248 if ($resql) {
2249 $num = $this->db->num_rows($resql);
2250 $i = 0;
2251 if ($num) {
2252 // do not use maxwidthonsmartphone by default. Set it by caller so auto size to 100% will work when not defined
2253 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : ' minwidth200') . '" id="' . $htmlname . '" name="' . $htmlname . ($multiple ? '[]' : '') . '" ' . ($multiple ? 'multiple' : '') . ' ' . ($disabled ? ' disabled' : '') . '>';
2254 if ($show_empty && !$multiple) {
2255 $textforempty = ' ';
2256 if (!empty($conf->use_javascript_ajax)) {
2257 $textforempty = '&nbsp;'; // If we use ajaxcombo, we need &nbsp; here to avoid to have an empty element that is too small.
2258 }
2259 if (!is_numeric($show_empty)) {
2260 $textforempty = $show_empty;
2261 }
2262 $out .= '<option class="optiongrey" value="' . ($show_empty < 0 ? $show_empty : -1) . '"' . ((empty($selected) || in_array(-1, $selected)) ? ' selected' : '') . '>' . $textforempty . '</option>' . "\n";
2263
2264 $outarray[($show_empty < 0 ? $show_empty : -1)] = $textforempty;
2265 $outarray2[($show_empty < 0 ? $show_empty : -1)] = array(
2266 'id' => ($show_empty < 0 ? $show_empty : -1),
2267 'label' => $textforempty,
2268 'labelhtml' => $textforempty,
2269 'color' => '',
2270 'picto' => ''
2271 );
2272 }
2273 if ($show_every) {
2274 $out .= '<option value="-2"' . ((in_array(-2, $selected)) ? ' selected' : '') . '>-- ' . $langs->trans("Everybody") . ' --</option>' . "\n";
2275
2276 $outarray[-2] = '-- ' . $langs->trans("Everybody") . ' --';
2277 $outarray2[-2] = array(
2278 'id' => -2,
2279 'label' => '-- ' . $langs->trans("Everybody") . ' --',
2280 'labelhtml' => '-- ' . $langs->trans("Everybody") . ' --',
2281 'color' => '',
2282 'picto' => ''
2283 );
2284 }
2285
2286 $userstatic = new User($this->db);
2287
2288 while ($i < $num) {
2289 $obj = $this->db->fetch_object($resql);
2290
2291 $userstatic->id = $obj->rowid;
2292 $userstatic->lastname = $obj->lastname;
2293 $userstatic->firstname = $obj->firstname;
2294 $userstatic->photo = $obj->photo;
2295 $userstatic->status = $obj->status;
2296 $userstatic->entity = $obj->entity;
2297 $userstatic->admin = $obj->admin;
2298 $userstatic->gender = $obj->gender;
2299
2300 $disableline = '';
2301 if (is_array($enableonly) && count($enableonly) && !in_array($obj->rowid, $enableonly)) {
2302 $disableline = ($enableonlytext ? $enableonlytext : '1');
2303 }
2304
2305 $labeltoshow = '';
2306 $labeltoshowhtml = '';
2307
2308 // $fullNameMode is 0=Lastname+Firstname (MAIN_FIRSTNAME_NAME_POSITION=1), 1=Firstname+Lastname (MAIN_FIRSTNAME_NAME_POSITION=0)
2309 $fullNameMode = 0;
2310 if (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) {
2311 $fullNameMode = 1; //Firstname+lastname
2312 }
2313 $labeltoshow .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2314 $labeltoshowhtml .= $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength);
2315 if (empty($obj->firstname) && empty($obj->lastname)) {
2316 $labeltoshow .= $obj->login;
2317 $labeltoshowhtml .= $obj->login;
2318 }
2319
2320 // Complete name with a more info string like: ' (info1 - info2 - ...)'
2321 $moreinfo = '';
2322 $moreinfohtml = '';
2323 if (getDolGlobalString('MAIN_SHOW_LOGIN')) {
2324 $moreinfo .= ($moreinfo ? ' - ' : ' (');
2325 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(');
2326 $moreinfo .= $obj->login;
2327 $moreinfohtml .= $obj->login;
2328 }
2329 if ($showstatus >= 0) {
2330 if ($obj->status == 1 && $showstatus == 1) {
2331 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Enabled');
2332 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Enabled');
2333 }
2334 if ($obj->status == 0 && $showstatus == 1) {
2335 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans('Disabled');
2336 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans('Disabled');
2337 }
2338 }
2339 if ($showlabelofentity) {
2340 if (empty($obj->entity)) {
2341 $moreinfo .= ($moreinfo ? ' - ' : ' (') . $langs->trans("AllEntities");
2342 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(') . $langs->trans("AllEntities");
2343 } else {
2344 if ($obj->entity != $conf->entity) {
2345 $moreinfo .= ($moreinfo ? ' - ' : ' (') . ($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2346 $moreinfohtml .= ($moreinfohtml ? ' - ' : ' <span class="opacitymedium">(').($obj->label ? $obj->label : $langs->trans("EntityNameNotDefined"));
2347 }
2348 }
2349 }
2350 $moreinfo .= (!empty($moreinfo) ? ')' : '');
2351 $moreinfohtml .= (!empty($moreinfohtml) ? ')</span>' : '');
2352 if (!empty($disableline) && $disableline != '1') {
2353 // Add text from $enableonlytext parameter
2354 $moreinfo .= ' - ' . $disableline;
2355 $moreinfohtml .= ' - ' . $disableline;
2356 }
2357 $labeltoshow .= $moreinfo;
2358 $labeltoshowhtml .= $moreinfohtml;
2359
2360 $out .= '<option value="' . $obj->rowid . '"';
2361 if (!empty($disableline)) {
2362 $out .= ' disabled';
2363 }
2364 if ((!empty($selected[0]) && is_object($selected[0])) ? $selected[0]->id == $obj->rowid : in_array($obj->rowid, $selected)) {
2365 $out .= ' selected';
2366 }
2367 $out .= ' data-html="';
2368
2369 $outhtml = $userstatic->getNomUrl(-3, '', 0, 1, 24, 1, 'login', '', 1) . ' ';
2370 if ($showstatus >= 0 && $obj->status == 0) {
2371 $outhtml .= '<strike class="opacitymediumxxx">';
2372 }
2373 $outhtml .= $labeltoshowhtml;
2374 if ($showstatus >= 0 && $obj->status == 0) {
2375 $outhtml .= '</strike>';
2376 }
2377 $labeltoshowhtml = $outhtml;
2378
2379 $out .= dol_escape_htmltag($outhtml);
2380 $out .= '">';
2381 $out .= $labeltoshow;
2382 $out .= '</option>';
2383
2384 $outarray[$userstatic->id] = $userstatic->getFullName($langs, $fullNameMode, -1, $maxlength) . $moreinfo;
2385 $outarray2[$userstatic->id] = array(
2386 'id' => $userstatic->id,
2387 'label' => $labeltoshow,
2388 'labelhtml' => $labeltoshowhtml,
2389 'color' => '',
2390 'picto' => ''
2391 );
2392
2393 $i++;
2394 }
2395 } else {
2396 $out .= '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '" disabled>';
2397 $out .= '<option value="">' . $langs->trans("None") . '</option>';
2398 }
2399 $out .= '</select>';
2400
2401 if ($num && !$forcecombo) {
2402 // Enhance with select2
2403 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2404 $out .= ajax_combobox($htmlname);
2405 }
2406 } else {
2407 dol_print_error($this->db);
2408 }
2409
2410 $this->num = $num;
2411
2412 if ($outputmode == 2) {
2413 return $outarray2;
2414 } elseif ($outputmode) {
2415 return $outarray;
2416 }
2417
2418 return $out;
2419 }
2420
2421
2422 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2445 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())
2446 {
2447 // phpcs:enable
2448 global $langs;
2449
2450 $userstatic = new User($this->db);
2451 $out = '';
2452
2453 if (!empty($_SESSION['assignedtouser'])) {
2454 $assignedtouser = json_decode($_SESSION['assignedtouser'], true);
2455 if (!is_array($assignedtouser)) {
2456 $assignedtouser = array();
2457 }
2458 } else {
2459 $assignedtouser = array();
2460 }
2461 $nbassignetouser = count($assignedtouser);
2462
2463 //if ($nbassignetouser && $action != 'view') $out .= '<br>';
2464 if ($nbassignetouser) {
2465 $out .= '<ul class="attendees">';
2466 }
2467 $i = 0;
2468 $ownerid = 0;
2469 foreach ($assignedtouser as $key => $value) {
2470 if ($value['id'] == $ownerid) {
2471 continue;
2472 }
2473
2474 $out .= '<li>';
2475 $userstatic->fetch($value['id']);
2476 $out .= $userstatic->getNomUrl(-1);
2477 if ($i == 0) {
2478 $ownerid = $value['id'];
2479 $out .= ' (' . $langs->trans("Owner") . ')';
2480 }
2481 if ($nbassignetouser > 1 && $action != 'view') {
2482 $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 . '">';
2483 }
2484 // Show my availability
2485 if ($showproperties) {
2486 if ($ownerid == $value['id'] && is_array($listofuserid) && count($listofuserid) && in_array($ownerid, array_keys($listofuserid))) {
2487 $out .= '<div class="myavailability inline-block">';
2488 $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>';
2489 $out .= '</div>';
2490 }
2491 }
2492 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2493 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2494
2495 $out .= '</li>';
2496 $i++;
2497 }
2498 if ($nbassignetouser) {
2499 $out .= '</ul>';
2500 }
2501
2502 // Method with no ajax
2503 if ($action != 'view') {
2504 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassigned" value="">';
2505 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2506 $out .= 'jQuery(".removedassigned").click(function() { jQuery(".removedassignedhidden").val(jQuery(this).val()); });';
2507 $out .= 'jQuery(".assignedtouser").change(function() { console.log(jQuery(".assignedtouser option:selected").val());';
2508 $out .= ' if (jQuery(".assignedtouser option:selected").val() > 0) { jQuery("#' . $action . 'assignedtouser").attr("disabled", false); }';
2509 $out .= ' else { jQuery("#' . $action . 'assignedtouser").attr("disabled", true); }';
2510 $out .= '});';
2511 $out .= '})</script>';
2512 $out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2513 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtouser" name="' . $action . 'assignedtouser" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2514 $out .= '<br>';
2515 }
2516
2517 return $out;
2518 }
2519
2520 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2540 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())
2541 {
2542 // phpcs:enable
2543 global $langs;
2544
2545 require_once DOL_DOCUMENT_ROOT.'/resource/class/html.formresource.class.php';
2546 require_once DOL_DOCUMENT_ROOT.'/resource/class/dolresource.class.php';
2547 $formresources = new FormResource($this->db);
2548 $resourcestatic = new Dolresource($this->db);
2549
2550 $out = '';
2551 if (!empty($_SESSION['assignedtoresource'])) {
2552 $assignedtoresource = json_decode($_SESSION['assignedtoresource'], true);
2553 if (!is_array($assignedtoresource)) {
2554 $assignedtoresource = array();
2555 }
2556 } else {
2557 $assignedtoresource = array();
2558 }
2559 $nbassignetoresource = count($assignedtoresource);
2560
2561 //if ($nbassignetoresource && $action != 'view') $out .= '<br>';
2562 if ($nbassignetoresource) {
2563 $out .= '<ul class="attendees">';
2564 }
2565 $i = 0;
2566
2567 foreach ($assignedtoresource as $key => $value) {
2568 $out .= '<li>';
2569 $resourcestatic->fetch($value['id']);
2570 $out .= $resourcestatic->getNomUrl(-1);
2571 if ($nbassignetoresource > 1 && $action != 'view') {
2572 $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 . '">';
2573 }
2574 // Show my availability
2575 if ($showproperties) {
2576 if (is_array($listofresourceid) && count($listofresourceid)) {
2577 $out .= '<div class="myavailability inline-block">';
2578 $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>';
2579 $out .= '</div>';
2580 }
2581 }
2582 //$out.=' '.($value['mandatory']?$langs->trans("Mandatory"):$langs->trans("Optional"));
2583 //$out.=' '.($value['transparency']?$langs->trans("Busy"):$langs->trans("NotBusy"));
2584
2585 $out .= '</li>';
2586 $i++;
2587 }
2588 if ($nbassignetoresource) {
2589 $out .= '</ul>';
2590 }
2591
2592 // Method with no ajax
2593 if ($action != 'view') {
2594 $out .= '<input type="hidden" class="removedassignedhidden" name="removedassignedresource" value="">';
2595 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">jQuery(document).ready(function () {';
2596 $out .= 'jQuery(".removedassignedresource").click(function() { jQuery(".removedassignedresourcehidden").val(jQuery(this).val()); });';
2597 $out .= 'jQuery(".assignedtoresource").change(function() { console.log(jQuery(".assignedtoresource option:selected").val());';
2598 $out .= ' if (jQuery(".assignedtoresource option:selected").val() > 0) { jQuery("#' . $action . 'assignedtoresource").attr("disabled", false); }';
2599 $out .= ' else { jQuery("#' . $action . 'assignedtoresource").attr("disabled", true); }';
2600 $out .= '});';
2601 $out .= '})</script>';
2602
2603 $events = array();
2604 $out .= img_picto('', 'resource', 'class="pictofixedwidth"');
2605 $out .= $formresources->select_resource_list(0, $htmlname, [], 1, 1, 0, $events, array(), 2, 0);
2606 //$out .= $this->select_dolusers('', $htmlname, $show_empty, $exclude, $disabled, $include, $enableonly, $force_entity, $maxlength, $showstatus, $morefilter);
2607 $out .= ' <input type="submit" disabled class="button valignmiddle smallpaddingimp reposition" id="' . $action . 'assignedtoresource" name="' . $action . 'assignedtoresource" value="' . dol_escape_htmltag($langs->trans("Add")) . '">';
2608 $out .= '<br>';
2609 }
2610
2611 return $out;
2612 }
2613
2614 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2615
2644 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)
2645 {
2646 // phpcs:enable
2647 global $langs, $conf;
2648
2649 $out = '';
2650
2651 // check parameters
2652 $price_level = (!empty($price_level) ? $price_level : 0);
2653 if (is_null($ajaxoptions)) {
2654 $ajaxoptions = array();
2655 }
2656
2657 if (strval($filtertype) === '' && (isModEnabled("product") || isModEnabled("service"))) {
2658 if (isModEnabled("product") && !isModEnabled('service')) {
2659 $filtertype = '0';
2660 } elseif (!isModEnabled('product') && isModEnabled("service")) {
2661 $filtertype = '1';
2662 }
2663 }
2664
2665 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
2666 $placeholder = '';
2667
2668 if ($selected && empty($selected_input_value)) {
2669 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2670 $producttmpselect = new Product($this->db);
2671 $producttmpselect->fetch($selected);
2672 $selected_input_value = $producttmpselect->ref;
2673 unset($producttmpselect);
2674 }
2675 // handle case where product or service module is disabled + no filter specified
2676 if ($filtertype == '') {
2677 if (!isModEnabled('product')) { // when product module is disabled, show services only
2678 $filtertype = 1;
2679 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
2680 $filtertype = 0;
2681 }
2682 }
2683 // mode=1 means customers products
2684 $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;
2685 $out .= ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, $conf->global->PRODUIT_USE_SEARCH_TO_SELECT, 1, $ajaxoptions);
2686
2687 if (isModEnabled('variants') && is_array($selected_combinations)) {
2688 // Code to automatically insert with javascript the select of attributes under the select of product
2689 // when a parent of variant has been selected.
2690 $out .= '
2691 <!-- script to auto show attributes select tags if a variant was selected -->
2692 <script nonce="' . getNonce() . '">
2693 // auto show attributes fields
2694 selected = ' . json_encode($selected_combinations) . ';
2695 combvalues = {};
2696
2697 jQuery(document).ready(function () {
2698
2699 jQuery("input[name=\'prod_entry_mode\']").change(function () {
2700 if (jQuery(this).val() == \'free\') {
2701 jQuery(\'div#attributes_box\').empty();
2702 }
2703 });
2704
2705 jQuery("input#' . $htmlname . '").change(function () {
2706
2707 if (!jQuery(this).val()) {
2708 jQuery(\'div#attributes_box\').empty();
2709 return;
2710 }
2711
2712 console.log("A change has started. We get variants fields to inject html select");
2713
2714 jQuery.getJSON("' . DOL_URL_ROOT . '/variants/ajax/getCombinations.php", {
2715 id: jQuery(this).val()
2716 }, function (data) {
2717 jQuery(\'div#attributes_box\').empty();
2718
2719 jQuery.each(data, function (key, val) {
2720
2721 combvalues[val.id] = val.values;
2722
2723 var span = jQuery(document.createElement(\'div\')).css({
2724 \'display\': \'table-row\'
2725 });
2726
2727 span.append(
2728 jQuery(document.createElement(\'div\')).text(val.label).css({
2729 \'font-weight\': \'bold\',
2730 \'display\': \'table-cell\'
2731 })
2732 );
2733
2734 var html = jQuery(document.createElement(\'select\')).attr(\'name\', \'combinations[\' + val.id + \']\').css({
2735 \'margin-left\': \'15px\',
2736 \'white-space\': \'pre\'
2737 }).append(
2738 jQuery(document.createElement(\'option\')).val(\'\')
2739 );
2740
2741 jQuery.each(combvalues[val.id], function (key, val) {
2742 var tag = jQuery(document.createElement(\'option\')).val(val.id).html(val.value);
2743
2744 if (selected[val.fk_product_attribute] == val.id) {
2745 tag.attr(\'selected\', \'selected\');
2746 }
2747
2748 html.append(tag);
2749 });
2750
2751 span.append(html);
2752 jQuery(\'div#attributes_box\').append(span);
2753 });
2754 })
2755 });
2756
2757 ' . ($selected ? 'jQuery("input#' . $htmlname . '").change();' : '') . '
2758 });
2759 </script>
2760 ';
2761 }
2762
2763 if (empty($hidelabel)) {
2764 $out .= $langs->trans("RefOrLabel") . ' : ';
2765 } elseif ($hidelabel > 1) {
2766 $placeholder = ' placeholder="' . $langs->trans("RefOrLabel") . '"';
2767 if ($hidelabel == 2) {
2768 $out .= img_picto($langs->trans("Search"), 'search');
2769 }
2770 }
2771 $out .= '<input type="text" class="minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . $placeholder . ' ' . (getDolGlobalString('PRODUCT_SEARCH_AUTOFOCUS') ? 'autofocus' : '') . ' />';
2772 if ($hidelabel == 3) {
2773 $out .= img_picto($langs->trans("Search"), 'search');
2774 }
2775 } else {
2776 $out .= $this->select_produits_list($selected, $htmlname, $filtertype, $limit, $price_level, '', $status, $finished, 0, $socid, $showempty, $forcecombo, $morecss, $hidepriceinlabel, $warehouseStatus, $status_purchase);
2777 }
2778
2779 if (empty($nooutput)) {
2780 print $out;
2781 } else {
2782 return $out;
2783 }
2784 }
2785
2786 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2787
2803 public function select_bom($selected = '', $htmlname = 'bom_id', $limit = 0, $status = 1, $type = 0, $showempty = '1', $morecss = '', $nooutput = '', $forcecombo = 0, $TProducts = [])
2804 {
2805 // phpcs:enable
2806 global $db;
2807
2808 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
2809
2810 $error = 0;
2811 $out = '';
2812
2813 if (!$forcecombo) {
2814 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
2815 $events = array();
2816 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
2817 }
2818
2819 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
2820
2821 $sql = 'SELECT b.rowid, b.ref, b.label, b.fk_product';
2822 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'bom_bom as b';
2823 $sql .= ' WHERE b.entity IN (' . getEntity('bom') . ')';
2824 if (!empty($status)) {
2825 $sql .= ' AND status = ' . (int) $status;
2826 }
2827 if (!empty($type)) {
2828 $sql .= ' AND bomtype = ' . (int) $type;
2829 }
2830 if (!empty($TProducts)) {
2831 $sql .= ' AND fk_product IN (' . $this->db->sanitize(implode(',', $TProducts)) . ')';
2832 }
2833 if (!empty($limit)) {
2834 $sql .= ' LIMIT ' . (int) $limit;
2835 }
2836 $resql = $db->query($sql);
2837 if ($resql) {
2838 if ($showempty) {
2839 $out .= '<option value="-1"';
2840 if (empty($selected)) {
2841 $out .= ' selected';
2842 }
2843 $out .= '>&nbsp;</option>';
2844 }
2845 while ($obj = $db->fetch_object($resql)) {
2846 $product = new Product($db);
2847 $res = $product->fetch($obj->fk_product);
2848 $out .= '<option value="' . $obj->rowid . '"';
2849 if ($obj->rowid == $selected) {
2850 $out .= 'selected';
2851 }
2852 $out .= '>' . $obj->ref . ' - ' . $product->label . ' - ' . $obj->label . '</option>';
2853 }
2854 } else {
2855 $error++;
2856 dol_print_error($db);
2857 }
2858 $out .= '</select>';
2859 if (empty($nooutput)) {
2860 print $out;
2861 } else {
2862 return $out;
2863 }
2864 }
2865
2866 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2867
2893 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)
2894 {
2895 // phpcs:enable
2896 global $langs;
2897 global $hookmanager;
2898
2899 $out = '';
2900 $outarray = array();
2901
2902 // Units
2903 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2904 $langs->load('other');
2905 }
2906
2907 $warehouseStatusArray = array();
2908 if (!empty($warehouseStatus)) {
2909 require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
2910 if (preg_match('/warehouseclosed/', $warehouseStatus)) {
2911 $warehouseStatusArray[] = Entrepot::STATUS_CLOSED;
2912 }
2913 if (preg_match('/warehouseopen/', $warehouseStatus)) {
2914 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_ALL;
2915 }
2916 if (preg_match('/warehouseinternal/', $warehouseStatus)) {
2917 $warehouseStatusArray[] = Entrepot::STATUS_OPEN_INTERNAL;
2918 }
2919 }
2920
2921 $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";
2922 if (count($warehouseStatusArray)) {
2923 $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
2924 } else {
2925 $selectFieldsGrouped = ", " . $this->db->ifsql("p.stock IS NULL", 0, "p.stock") . " AS stock";
2926 }
2927
2928 $sql = "SELECT ";
2929
2930 // Add select from hooks
2931 $parameters = array();
2932 $reshook = $hookmanager->executeHooks('selectProductsListSelect', $parameters); // Note that $action and $object may have been modified by hook
2933 if (empty($reshook)) {
2934 $sql .= $selectFields.$selectFieldsGrouped.$hookmanager->resPrint;
2935 } else {
2936 $sql .= $hookmanager->resPrint;
2937 }
2938
2939 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
2940 //Product category
2941 $sql .= ", (SELECT " . $this->db->prefix() . "categorie_product.fk_categorie
2942 FROM " . $this->db->prefix() . "categorie_product
2943 WHERE " . $this->db->prefix() . "categorie_product.fk_product=p.rowid
2944 LIMIT 1
2945 ) AS categorie_product_id ";
2946 }
2947
2948 //Price by customer
2949 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
2950 $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,';
2951 $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';
2952 $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref";
2953 }
2954 // Units
2955 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
2956 $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";
2957 $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';
2958 }
2959
2960 // Multilang : we add translation
2961 if (getDolGlobalInt('MAIN_MULTILANGS')) {
2962 $sql .= ", pl.label as label_translated";
2963 $sql .= ", pl.description as description_translated";
2964 $selectFields .= ", label_translated";
2965 $selectFields .= ", description_translated";
2966 }
2967 // Price by quantity
2968 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2969 $sql .= ", (SELECT pp.rowid FROM " . $this->db->prefix() . "product_price as pp WHERE pp.fk_product = p.rowid";
2970 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2971 $sql .= " AND price_level = " . ((int) $price_level);
2972 }
2973 $sql .= " ORDER BY date_price";
2974 $sql .= " DESC LIMIT 1) as price_rowid";
2975 $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
2976 if ($price_level >= 1 && getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
2977 $sql .= " AND price_level = " . ((int) $price_level);
2978 }
2979 $sql .= " ORDER BY date_price";
2980 $sql .= " DESC LIMIT 1) as price_by_qty";
2981 $selectFields .= ", price_rowid, price_by_qty";
2982 }
2983
2984 $sql .= " FROM ".$this->db->prefix()."product as p";
2985
2986 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_FORCE_INDEX')) {
2987 $sql .= " USE INDEX (" . $this->db->sanitize(getDolGlobalString('MAIN_PRODUCT_FORCE_INDEX')) . ")";
2988 }
2989
2990 // Add from (left join) from hooks
2991 $parameters = array();
2992 $reshook = $hookmanager->executeHooks('selectProductsListFrom', $parameters); // Note that $action and $object may have been modified by hook
2993 $sql .= $hookmanager->resPrint;
2994
2995 if (count($warehouseStatusArray)) {
2996 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_stock as ps on ps.fk_product = p.rowid";
2997 $sql .= " LEFT JOIN " . $this->db->prefix() . "entrepot as e on ps.fk_entrepot = e.rowid AND e.entity IN (" . getEntity('stock') . ")";
2998 $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.
2999 }
3000
3001 // include search in supplier ref
3002 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3003 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
3004 }
3005
3006 //Price by customer
3007 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
3008 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid";
3009 }
3010 // Units
3011 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3012 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3013 }
3014 // Multilang : we add translation
3015 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3016 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_lang as pl ON pl.fk_product = p.rowid ";
3017 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE') && !empty($socid)) {
3018 require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
3019 $soc = new Societe($this->db);
3020 $result = $soc->fetch($socid);
3021 if ($result > 0 && !empty($soc->default_lang)) {
3022 $sql .= " AND pl.lang = '" . $this->db->escape($soc->default_lang) . "'";
3023 } else {
3024 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3025 }
3026 } else {
3027 $sql .= " AND pl.lang = '" . $this->db->escape($langs->getDefaultLang()) . "'";
3028 }
3029 }
3030
3031 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3032 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_attribute_combination pac ON pac.fk_product_child = p.rowid";
3033 }
3034
3035 $sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
3036
3037 if (getDolGlobalString('PRODUIT_ATTRIBUTES_HIDECHILD')) {
3038 $sql .= " AND pac.rowid IS NULL";
3039 }
3040
3041 if ($finished == 0) {
3042 $sql .= " AND p.finished = " . ((int) $finished);
3043 } elseif ($finished == 1) {
3044 $sql .= " AND p.finished = ".((int) $finished);
3045 }
3046 if ($status >= 0) {
3047 $sql .= " AND p.tosell = ".((int) $status);
3048 }
3049 if ($status_purchase >= 0) {
3050 $sql .= " AND p.tobuy = " . ((int) $status_purchase);
3051 }
3052 // Filter by product type
3053 if (strval($filtertype) != '') {
3054 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3055 } elseif (!isModEnabled('product')) { // when product module is disabled, show services only
3056 $sql .= " AND p.fk_product_type = 1";
3057 } elseif (!isModEnabled('service')) { // when service module is disabled, show products only
3058 $sql .= " AND p.fk_product_type = 0";
3059 }
3060 // Add where from hooks
3061 $parameters = array();
3062 $reshook = $hookmanager->executeHooks('selectProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3063 $sql .= $hookmanager->resPrint;
3064 // Add criteria on ref/label
3065 if ($filterkey != '') {
3066 $sql .= ' AND (';
3067 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3068 // For natural search
3069 $search_crit = explode(' ', $filterkey);
3070 $i = 0;
3071 if (count($search_crit) > 1) {
3072 $sql .= "(";
3073 }
3074 foreach ($search_crit as $crit) {
3075 if ($i > 0) {
3076 $sql .= " AND ";
3077 }
3078 $sql .= "(p.ref LIKE '" . $this->db->escape($prefix . $crit) . "%' OR p.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3079 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3080 $sql .= " OR pl.label LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3081 }
3082 if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') && !empty($socid)) {
3083 $sql .= " OR pcp.ref_customer LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3084 }
3085 if (getDolGlobalString('PRODUCT_AJAX_SEARCH_ON_DESCRIPTION')) {
3086 $sql .= " OR p.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3087 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3088 $sql .= " OR pl.description LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3089 }
3090 }
3091 if (getDolGlobalString('MAIN_SEARCH_PRODUCT_BY_FOURN_REF')) {
3092 $sql .= " OR pfp.ref_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3093 }
3094 $sql .= ")";
3095 $i++;
3096 }
3097 if (count($search_crit) > 1) {
3098 $sql .= ")";
3099 }
3100 if (isModEnabled('barcode')) {
3101 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3102 }
3103 $sql .= ')';
3104 }
3105 if (count($warehouseStatusArray)) {
3106 $sql .= " GROUP BY " . $selectFields;
3107 }
3108
3109 //Sort by category
3110 if (getDolGlobalString('PRODUCT_SORT_BY_CATEGORY')) {
3111 $sql .= " ORDER BY categorie_product_id ";
3112 //ASC OR DESC order
3113 (getDolGlobalInt('PRODUCT_SORT_BY_CATEGORY') == 1) ? $sql .= "ASC" : $sql .= "DESC";
3114 } else {
3115 $sql .= $this->db->order("p.ref");
3116 }
3117
3118 $sql .= $this->db->plimit($limit, 0);
3119
3120 // Build output string
3121 dol_syslog(get_class($this) . "::select_produits_list search products", LOG_DEBUG);
3122 $result = $this->db->query($sql);
3123 if ($result) {
3124 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3125 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3126 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3127
3128 $num = $this->db->num_rows($result);
3129
3130 $events = array();
3131
3132 if (!$forcecombo) {
3133 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
3134 $out .= ajax_combobox($htmlname, $events, getDolGlobalInt("PRODUIT_USE_SEARCH_TO_SELECT"));
3135 }
3136
3137 $out .= '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
3138
3139 $textifempty = '';
3140 // Do not use textifempty = ' ' or '&nbsp;' here, or search on key will search on ' key'.
3141 //if (!empty($conf->use_javascript_ajax) || $forcecombo) $textifempty='';
3142 if (getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3143 if ($showempty && !is_numeric($showempty)) {
3144 $textifempty = $langs->trans($showempty);
3145 } else {
3146 $textifempty .= $langs->trans("All");
3147 }
3148 } else {
3149 if ($showempty && !is_numeric($showempty)) {
3150 $textifempty = $langs->trans($showempty);
3151 }
3152 }
3153 if ($showempty) {
3154 $out .= '<option value="-1" selected>' . ($textifempty ? $textifempty : '&nbsp;') . '</option>';
3155 }
3156
3157 $i = 0;
3158 while ($num && $i < $num) {
3159 $opt = '';
3160 $optJson = array();
3161 $objp = $this->db->fetch_object($result);
3162
3163 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
3164 $sql = "SELECT rowid, quantity, price, unitprice, remise_percent, remise, price_base_type";
3165 $sql .= " FROM " . $this->db->prefix() . "product_price_by_qty";
3166 $sql .= " WHERE fk_product_price = " . ((int) $objp->price_rowid);
3167 $sql .= " ORDER BY quantity ASC";
3168
3169 dol_syslog(get_class($this) . "::select_produits_list search prices by qty", LOG_DEBUG);
3170 $result2 = $this->db->query($sql);
3171 if ($result2) {
3172 $nb_prices = $this->db->num_rows($result2);
3173 $j = 0;
3174 while ($nb_prices && $j < $nb_prices) {
3175 $objp2 = $this->db->fetch_object($result2);
3176
3177 $objp->price_by_qty_rowid = $objp2->rowid;
3178 $objp->price_by_qty_price_base_type = $objp2->price_base_type;
3179 $objp->price_by_qty_quantity = $objp2->quantity;
3180 $objp->price_by_qty_unitprice = $objp2->unitprice;
3181 $objp->price_by_qty_remise_percent = $objp2->remise_percent;
3182 // For backward compatibility
3183 $objp->quantity = $objp2->quantity;
3184 $objp->price = $objp2->price;
3185 $objp->unitprice = $objp2->unitprice;
3186 $objp->remise_percent = $objp2->remise_percent;
3187
3188 //$objp->tva_tx is not overwritten by $objp2 value
3189 //$objp->default_vat_code is not overwritten by $objp2 value
3190
3191 $this->constructProductListOption($objp, $opt, $optJson, 0, $selected, $hidepriceinlabel, $filterkey);
3192
3193 $j++;
3194
3195 // Add new entry
3196 // "key" value of json key array is used by jQuery automatically as selected value
3197 // "label" value of json key array is used by jQuery automatically as text for combo box
3198 $out .= $opt;
3199 array_push($outarray, $optJson);
3200 }
3201 }
3202 } else {
3203 if (isModEnabled('dynamicprices') && !empty($objp->fk_price_expression)) {
3204 $price_product = new Product($this->db);
3205 $price_product->fetch($objp->rowid, '', '', 1);
3206
3207 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3208 $priceparser = new PriceParser($this->db);
3209 $price_result = $priceparser->parseProduct($price_product);
3210 if ($price_result >= 0) {
3211 $objp->price = $price_result;
3212 $objp->unitprice = $price_result;
3213 //Calculate the VAT
3214 $objp->price_ttc = (float) price2num($objp->price) * (1 + ($objp->tva_tx / 100));
3215 $objp->price_ttc = price2num($objp->price_ttc, 'MU');
3216 }
3217 }
3218
3219 $this->constructProductListOption($objp, $opt, $optJson, $price_level, $selected, $hidepriceinlabel, $filterkey);
3220 // Add new entry
3221 // "key" value of json key array is used by jQuery automatically as selected value
3222 // "label" value of json key array is used by jQuery automatically as text for combo box
3223 $out .= $opt;
3224 array_push($outarray, $optJson);
3225 }
3226
3227 $i++;
3228 }
3229
3230 $out .= '</select>';
3231
3232 $this->db->free($result);
3233
3234 if (empty($outputmode)) {
3235 return $out;
3236 }
3237
3238 return $outarray;
3239 } else {
3240 dol_print_error($this->db);
3241 }
3242
3243 return '';
3244 }
3245
3261 protected function constructProductListOption(&$objp, &$opt, &$optJson, $price_level, $selected, $hidepriceinlabel = 0, $filterkey = '', $novirtualstock = 0)
3262 {
3263 global $langs, $conf, $user;
3264 global $hookmanager;
3265
3266 $outkey = '';
3267 $outval = '';
3268 $outref = '';
3269 $outlabel = '';
3270 $outlabel_translated = '';
3271 $outdesc = '';
3272 $outdesc_translated = '';
3273 $outbarcode = '';
3274 $outorigin = '';
3275 $outtype = '';
3276 $outprice_ht = '';
3277 $outprice_ttc = '';
3278 $outpricebasetype = '';
3279 $outtva_tx = '';
3280 $outdefault_vat_code = '';
3281 $outqty = 1;
3282 $outdiscount = 0;
3283
3284 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3285
3286 $label = $objp->label;
3287 if (!empty($objp->label_translated)) {
3288 $label = $objp->label_translated;
3289 }
3290 if (!empty($filterkey) && $filterkey != '') {
3291 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3292 }
3293
3294 $outkey = $objp->rowid;
3295 $outref = $objp->ref;
3296 $outrefcust = empty($objp->custref) ? '' : $objp->custref;
3297 $outlabel = $objp->label;
3298 $outdesc = $objp->description;
3299 if (getDolGlobalInt('MAIN_MULTILANGS')) {
3300 $outlabel_translated = $objp->label_translated;
3301 $outdesc_translated = $objp->description_translated;
3302 }
3303 $outbarcode = $objp->barcode;
3304 $outorigin = $objp->fk_country;
3305 $outpbq = empty($objp->price_by_qty_rowid) ? '' : $objp->price_by_qty_rowid;
3306
3307 $outtype = $objp->fk_product_type;
3308 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3309 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3310
3311 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3312 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
3313 }
3314
3315 // Units
3316 $outvalUnits = '';
3317 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3318 if (!empty($objp->unit_short)) {
3319 $outvalUnits .= ' - ' . $objp->unit_short;
3320 }
3321 }
3322 if (getDolGlobalString('PRODUCT_SHOW_DIMENSIONS_IN_COMBO')) {
3323 if (!empty($objp->weight) && $objp->weight_units !== null) {
3324 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3325 $outvalUnits .= ' - ' . $unitToShow;
3326 }
3327 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3328 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3329 $outvalUnits .= ' - ' . $unitToShow;
3330 }
3331 if (!empty($objp->surface) && $objp->surface_units !== null) {
3332 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3333 $outvalUnits .= ' - ' . $unitToShow;
3334 }
3335 if (!empty($objp->volume) && $objp->volume_units !== null) {
3336 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3337 $outvalUnits .= ' - ' . $unitToShow;
3338 }
3339 }
3340 if ($outdurationvalue && $outdurationunit) {
3341 $da = array(
3342 'h' => $langs->trans('Hour'),
3343 'd' => $langs->trans('Day'),
3344 'w' => $langs->trans('Week'),
3345 'm' => $langs->trans('Month'),
3346 'y' => $langs->trans('Year')
3347 );
3348 if (isset($da[$outdurationunit])) {
3349 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3350 }
3351 }
3352
3353 $opt = '<option value="' . $objp->rowid . '"';
3354 $opt .= ($objp->rowid == $selected) ? ' selected' : '';
3355 if (!empty($objp->price_by_qty_rowid) && $objp->price_by_qty_rowid > 0) {
3356 $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 . '"';
3357 }
3358 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3359 if ($user->hasRight('stock', 'lire')) {
3360 if ($objp->stock > 0) {
3361 $opt .= ' class="product_line_stock_ok"';
3362 } elseif ($objp->stock <= 0) {
3363 $opt .= ' class="product_line_stock_too_low"';
3364 }
3365 }
3366 }
3367 if (getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3368 $opt .= ' data-labeltrans="' . $outlabel_translated . '"';
3369 $opt .= ' data-desctrans="' . dol_escape_htmltag($outdesc_translated) . '"';
3370 }
3371 $opt .= '>';
3372 $opt .= $objp->ref;
3373 if (!empty($objp->custref)) {
3374 $opt .= ' (' . $objp->custref . ')';
3375 }
3376 if ($outbarcode) {
3377 $opt .= ' (' . $outbarcode . ')';
3378 }
3379 $opt .= ' - ' . dol_trunc($label, $maxlengtharticle);
3380 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3381 $opt .= ' (' . getCountry($outorigin, 1) . ')';
3382 }
3383
3384 $objRef = $objp->ref;
3385 if (!empty($objp->custref)) {
3386 $objRef .= ' (' . $objp->custref . ')';
3387 }
3388 if (!empty($filterkey) && $filterkey != '') {
3389 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3390 }
3391 $outval .= $objRef;
3392 if ($outbarcode) {
3393 $outval .= ' (' . $outbarcode . ')';
3394 }
3395 $outval .= ' - ' . dol_trunc($label, $maxlengtharticle);
3396 if ($outorigin && getDolGlobalString('PRODUCT_SHOW_ORIGIN_IN_COMBO')) {
3397 $outval .= ' (' . getCountry($outorigin, 1) . ')';
3398 }
3399
3400 // Units
3401 $opt .= $outvalUnits;
3402 $outval .= $outvalUnits;
3403
3404 $found = 0;
3405
3406 // Multiprice
3407 // If we need a particular price level (from 1 to n)
3408 if (empty($hidepriceinlabel) && $price_level >= 1 && (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3409 $sql = "SELECT price, price_ttc, price_base_type, tva_tx, default_vat_code";
3410 $sql .= " FROM " . $this->db->prefix() . "product_price";
3411 $sql .= " WHERE fk_product = " . ((int) $objp->rowid);
3412 $sql .= " AND entity IN (" . getEntity('productprice') . ")";
3413 $sql .= " AND price_level = " . ((int) $price_level);
3414 $sql .= " ORDER BY date_price DESC, rowid DESC"; // Warning DESC must be both on date_price and rowid.
3415 $sql .= " LIMIT 1";
3416
3417 dol_syslog(get_class($this) . '::constructProductListOption search price for product ' . $objp->rowid . ' AND level ' . $price_level, LOG_DEBUG);
3418 $result2 = $this->db->query($sql);
3419 if ($result2) {
3420 $objp2 = $this->db->fetch_object($result2);
3421 if ($objp2) {
3422 $found = 1;
3423 if ($objp2->price_base_type == 'HT') {
3424 $opt .= ' - ' . price($objp2->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3425 $outval .= ' - ' . price($objp2->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3426 } else {
3427 $opt .= ' - ' . price($objp2->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3428 $outval .= ' - ' . price($objp2->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3429 }
3430 $outprice_ht = price($objp2->price);
3431 $outprice_ttc = price($objp2->price_ttc);
3432 $outpricebasetype = $objp2->price_base_type;
3433 if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
3434 $outtva_tx = $objp2->tva_tx; // We use the vat rate on line of multiprice
3435 $outdefault_vat_code = $objp2->default_vat_code; // We use the vat code on line of multiprice
3436 } else {
3437 $outtva_tx = $objp->tva_tx; // We use the vat rate of product, not the one on line of multiprice
3438 $outdefault_vat_code = $objp->default_vat_code; // We use the vat code or product, not the one on line of multiprice
3439 }
3440 }
3441 } else {
3442 dol_print_error($this->db);
3443 }
3444 }
3445
3446 // Price by quantity
3447 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1 && (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES'))) {
3448 $found = 1;
3449 $outqty = $objp->quantity;
3450 $outdiscount = $objp->remise_percent;
3451 if ($objp->quantity == 1) {
3452 $opt .= ' - ' . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/";
3453 $outval .= ' - ' . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/";
3454 $opt .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3455 $outval .= $langs->transnoentities("Unit");
3456 } else {
3457 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3458 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3459 $opt .= $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3460 $outval .= $langs->transnoentities("Units");
3461 }
3462
3463 $outprice_ht = price($objp->unitprice);
3464 $outprice_ttc = price($objp->unitprice * (1 + ($objp->tva_tx / 100)));
3465 $outpricebasetype = $objp->price_base_type;
3466 $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
3467 $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
3468 }
3469 if (empty($hidepriceinlabel) && !empty($objp->quantity) && $objp->quantity >= 1) {
3470 $opt .= " (" . price($objp->unitprice, 1, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->trans("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3471 $outval .= " (" . price($objp->unitprice, 0, $langs, 0, 0, -1, $conf->currency) . "/" . $langs->transnoentities("Unit") . ")"; // Do not use strtolower because it breaks utf8 encoding
3472 }
3473 if (empty($hidepriceinlabel) && !empty($objp->remise_percent) && $objp->remise_percent >= 1) {
3474 $opt .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3475 $outval .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3476 }
3477
3478 // Price by customer
3479 if (empty($hidepriceinlabel) && getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
3480 if (!empty($objp->idprodcustprice)) {
3481 $found = 1;
3482
3483 if ($objp->custprice_base_type == 'HT') {
3484 $opt .= ' - ' . price($objp->custprice, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3485 $outval .= ' - ' . price($objp->custprice, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3486 } else {
3487 $opt .= ' - ' . price($objp->custprice_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3488 $outval .= ' - ' . price($objp->custprice_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3489 }
3490
3491 $outprice_ht = price($objp->custprice);
3492 $outprice_ttc = price($objp->custprice_ttc);
3493 $outpricebasetype = $objp->custprice_base_type;
3494 $outtva_tx = $objp->custtva_tx;
3495 $outdefault_vat_code = $objp->custdefault_vat_code;
3496 }
3497 }
3498
3499 // If level no defined or multiprice not found, we used the default price
3500 if (empty($hidepriceinlabel) && !$found) {
3501 if ($objp->price_base_type == 'HT') {
3502 $opt .= ' - ' . price($objp->price, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("HT");
3503 $outval .= ' - ' . price($objp->price, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("HT");
3504 } else {
3505 $opt .= ' - ' . price($objp->price_ttc, 1, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->trans("TTC");
3506 $outval .= ' - ' . price($objp->price_ttc, 0, $langs, 0, 0, -1, $conf->currency) . ' ' . $langs->transnoentities("TTC");
3507 }
3508 $outprice_ht = price($objp->price);
3509 $outprice_ttc = price($objp->price_ttc);
3510 $outpricebasetype = $objp->price_base_type;
3511 $outtva_tx = $objp->tva_tx;
3512 $outdefault_vat_code = $objp->default_vat_code;
3513 }
3514
3515 if (isModEnabled('stock') && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3516 if ($user->hasRight('stock', 'lire')) {
3517 $opt .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3518
3519 if ($objp->stock > 0) {
3520 $outval .= ' - <span class="product_line_stock_ok">';
3521 } elseif ($objp->stock <= 0) {
3522 $outval .= ' - <span class="product_line_stock_too_low">';
3523 }
3524 $outval .= $langs->transnoentities("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3525 $outval .= '</span>';
3526 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3527 $langs->load("stocks");
3528
3529 $tmpproduct = new Product($this->db);
3530 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3531 $tmpproduct->load_virtual_stock();
3532 $virtualstock = $tmpproduct->stock_theorique;
3533
3534 $opt .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3535
3536 $outval .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3537 if ($virtualstock > 0) {
3538 $outval .= '<span class="product_line_stock_ok">';
3539 } elseif ($virtualstock <= 0) {
3540 $outval .= '<span class="product_line_stock_too_low">';
3541 }
3542 $outval .= $virtualstock;
3543 $outval .= '</span>';
3544
3545 unset($tmpproduct);
3546 }
3547 }
3548 }
3549
3550 $parameters = array('objp' => $objp);
3551 $reshook = $hookmanager->executeHooks('constructProductListOption', $parameters); // Note that $action and $object may have been modified by hook
3552 if (empty($reshook)) {
3553 $opt .= $hookmanager->resPrint;
3554 } else {
3555 $opt = $hookmanager->resPrint;
3556 }
3557
3558 $opt .= "</option>\n";
3559 $optJson = array(
3560 'key' => $outkey,
3561 'value' => $outref,
3562 'label' => $outval,
3563 'label2' => $outlabel,
3564 'desc' => $outdesc,
3565 'type' => $outtype,
3566 'price_ht' => price2num($outprice_ht),
3567 'price_ttc' => price2num($outprice_ttc),
3568 'price_ht_locale' => price(price2num($outprice_ht)),
3569 'price_ttc_locale' => price(price2num($outprice_ttc)),
3570 'pricebasetype' => $outpricebasetype,
3571 'tva_tx' => $outtva_tx,
3572 'default_vat_code' => $outdefault_vat_code,
3573 'qty' => $outqty,
3574 'discount' => $outdiscount,
3575 'duration_value' => $outdurationvalue,
3576 'duration_unit' => $outdurationunit,
3577 'pbq' => $outpbq,
3578 'labeltrans' => $outlabel_translated,
3579 'desctrans' => $outdesc_translated,
3580 'ref_customer' => $outrefcust
3581 );
3582 }
3583
3584 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3585
3601 public function select_produits_fournisseurs($socid, $selected = '', $htmlname = 'productid', $filtertype = '', $filtre = '', $ajaxoptions = array(), $hidelabel = 0, $alsoproductwithnosupplierprice = 0, $morecss = '', $placeholder = '')
3602 {
3603 // phpcs:enable
3604 global $langs, $conf;
3605 global $price_level, $status, $finished;
3606
3607 if (!isset($status)) {
3608 $status = 1;
3609 }
3610
3611 $selected_input_value = '';
3612 if (!empty($conf->use_javascript_ajax) && getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT')) {
3613 if ($selected > 0) {
3614 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
3615 $producttmpselect = new Product($this->db);
3616 $producttmpselect->fetch($selected);
3617 $selected_input_value = $producttmpselect->ref;
3618 unset($producttmpselect);
3619 }
3620
3621 // mode=2 means suppliers products
3622 $urloption = ($socid > 0 ? 'socid=' . $socid . '&' : '') . 'htmlname=' . $htmlname . '&outjson=1&price_level=' . $price_level . '&type=' . $filtertype . '&mode=2&status=' . $status . '&finished=' . $finished . '&alsoproductwithnosupplierprice=' . $alsoproductwithnosupplierprice;
3623 print ajax_autocompleter($selected, $htmlname, DOL_URL_ROOT . '/product/ajax/products.php', $urloption, getDolGlobalString('PRODUIT_USE_SEARCH_TO_SELECT'), 0, $ajaxoptions);
3624
3625 print($hidelabel ? '' : $langs->trans("RefOrLabel") . ' : ') . '<input type="text" class="'.$morecss.'" name="search_' . $htmlname . '" id="search_' . $htmlname . '" value="' . $selected_input_value . '"' . ($placeholder ? ' placeholder="' . $placeholder . '"' : '') . '>';
3626 } else {
3627 print $this->select_produits_fournisseurs_list($socid, $selected, $htmlname, $filtertype, $filtre, '', $status, 0, 0, $alsoproductwithnosupplierprice, $morecss, 0, $placeholder);
3628 }
3629 }
3630
3631 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3632
3651 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 = '')
3652 {
3653 // phpcs:enable
3654 global $langs, $conf, $user;
3655 global $hookmanager;
3656
3657 $out = '';
3658 $outarray = array();
3659
3660 $maxlengtharticle = (!getDolGlobalString('PRODUCT_MAX_LENGTH_COMBO') ? 48 : $conf->global->PRODUCT_MAX_LENGTH_COMBO);
3661
3662 $langs->load('stocks');
3663 // Units
3664 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3665 $langs->load('other');
3666 }
3667
3668 $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,";
3669 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.quantity, pfp.remise_percent, pfp.remise, pfp.unitprice, pfp.barcode";
3670 $sql .= ", pfp.multicurrency_code, pfp.multicurrency_unitprice";
3671 $sql .= ", pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, pfp.default_vat_code, pfp.fk_soc, s.nom as name";
3672 $sql .= ", pfp.supplier_reputation";
3673 // if we use supplier description of the products
3674 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3675 $sql .= ", pfp.desc_fourn as description";
3676 } else {
3677 $sql .= ", p.description";
3678 }
3679 // Units
3680 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3681 $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";
3682 }
3683 $sql .= " FROM " . $this->db->prefix() . "product as p";
3684 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON ( p.rowid = pfp.fk_product AND pfp.entity IN (" . getEntity('product') . ") )";
3685 if ($socid > 0) {
3686 $sql .= " AND pfp.fk_soc = " . ((int) $socid);
3687 }
3688 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
3689 // Units
3690 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3691 $sql .= " LEFT JOIN " . $this->db->prefix() . "c_units u ON u.rowid = p.fk_unit";
3692 }
3693 $sql .= " WHERE p.entity IN (" . getEntity('product') . ")";
3694 if ($statut != -1) {
3695 $sql .= " AND p.tobuy = " . ((int) $statut);
3696 }
3697 if (strval($filtertype) != '') {
3698 $sql .= " AND p.fk_product_type = " . ((int) $filtertype);
3699 }
3700 if (!empty($filtre)) {
3701 $sql .= " " . $filtre;
3702 }
3703 // Add where from hooks
3704 $parameters = array();
3705 $reshook = $hookmanager->executeHooks('selectSuppliersProductsListWhere', $parameters); // Note that $action and $object may have been modified by hook
3706 $sql .= $hookmanager->resPrint;
3707 // Add criteria on ref/label
3708 if ($filterkey != '') {
3709 $sql .= ' AND (';
3710 $prefix = !getDolGlobalString('PRODUCT_DONOTSEARCH_ANYWHERE') ? '%' : ''; // Can use index if PRODUCT_DONOTSEARCH_ANYWHERE is on
3711 // For natural search
3712 $search_crit = explode(' ', $filterkey);
3713 $i = 0;
3714 if (count($search_crit) > 1) {
3715 $sql .= "(";
3716 }
3717 foreach ($search_crit as $crit) {
3718 if ($i > 0) {
3719 $sql .= " AND ";
3720 }
3721 $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) . "%'";
3722 if (getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
3723 $sql .= " OR pfp.desc_fourn LIKE '" . $this->db->escape($prefix . $crit) . "%'";
3724 }
3725 $sql .= ")";
3726 $i++;
3727 }
3728 if (count($search_crit) > 1) {
3729 $sql .= ")";
3730 }
3731 if (isModEnabled('barcode')) {
3732 $sql .= " OR p.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3733 $sql .= " OR pfp.barcode LIKE '" . $this->db->escape($prefix . $filterkey) . "%'";
3734 }
3735 $sql .= ')';
3736 }
3737 $sql .= " ORDER BY pfp.ref_fourn DESC, pfp.quantity ASC";
3738 $sql .= $this->db->plimit($limit, 0);
3739
3740 // Build output string
3741
3742 dol_syslog(get_class($this) . "::select_produits_fournisseurs_list", LOG_DEBUG);
3743 $result = $this->db->query($sql);
3744 if ($result) {
3745 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3746 require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
3747
3748 $num = $this->db->num_rows($result);
3749
3750 //$out.='<select class="flat" id="select'.$htmlname.'" name="'.$htmlname.'">'; // remove select to have id same with combo and ajax
3751 $out .= '<select class="flat ' . ($morecss ? ' ' . $morecss : '') . '" id="' . $htmlname . '" name="' . $htmlname . '">';
3752 if (!$selected) {
3753 $out .= '<option value="-1" selected>' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3754 } else {
3755 $out .= '<option value="-1">' . ($placeholder ? $placeholder : '&nbsp;') . '</option>';
3756 }
3757
3758 $i = 0;
3759 while ($i < $num) {
3760 $objp = $this->db->fetch_object($result);
3761
3762 if (is_null($objp->idprodfournprice)) {
3763 // There is no supplier price found, we will use the vat rate for sale
3764 $objp->tva_tx = $objp->tva_tx_sale;
3765 $objp->default_vat_code = $objp->default_vat_code_sale;
3766 }
3767
3768 $outkey = $objp->idprodfournprice; // id in table of price
3769 if (!$outkey && $alsoproductwithnosupplierprice) {
3770 $outkey = 'idprod_' . $objp->rowid; // id of product
3771 }
3772
3773 $outref = $objp->ref;
3774 $outbarcode = $objp->barcode;
3775 $outqty = 1;
3776 $outdiscount = 0;
3777 $outtype = $objp->fk_product_type;
3778 $outdurationvalue = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, 0, dol_strlen($objp->duration) - 1) : '';
3779 $outdurationunit = $outtype == Product::TYPE_SERVICE ? substr($objp->duration, -1) : '';
3780
3781 // Units
3782 $outvalUnits = '';
3783 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
3784 if (!empty($objp->unit_short)) {
3785 $outvalUnits .= ' - ' . $objp->unit_short;
3786 }
3787 if (!empty($objp->weight) && $objp->weight_units !== null) {
3788 $unitToShow = showDimensionInBestUnit($objp->weight, $objp->weight_units, 'weight', $langs);
3789 $outvalUnits .= ' - ' . $unitToShow;
3790 }
3791 if ((!empty($objp->length) || !empty($objp->width) || !empty($objp->height)) && $objp->length_units !== null) {
3792 $unitToShow = $objp->length . ' x ' . $objp->width . ' x ' . $objp->height . ' ' . measuringUnitString(0, 'size', $objp->length_units);
3793 $outvalUnits .= ' - ' . $unitToShow;
3794 }
3795 if (!empty($objp->surface) && $objp->surface_units !== null) {
3796 $unitToShow = showDimensionInBestUnit($objp->surface, $objp->surface_units, 'surface', $langs);
3797 $outvalUnits .= ' - ' . $unitToShow;
3798 }
3799 if (!empty($objp->volume) && $objp->volume_units !== null) {
3800 $unitToShow = showDimensionInBestUnit($objp->volume, $objp->volume_units, 'volume', $langs);
3801 $outvalUnits .= ' - ' . $unitToShow;
3802 }
3803 if ($outdurationvalue && $outdurationunit) {
3804 $da = array(
3805 'h' => $langs->trans('Hour'),
3806 'd' => $langs->trans('Day'),
3807 'w' => $langs->trans('Week'),
3808 'm' => $langs->trans('Month'),
3809 'y' => $langs->trans('Year')
3810 );
3811 if (isset($da[$outdurationunit])) {
3812 $outvalUnits .= ' - ' . $outdurationvalue . ' ' . $langs->transnoentities($da[$outdurationunit] . ($outdurationvalue > 1 ? 's' : ''));
3813 }
3814 }
3815 }
3816
3817 $objRef = $objp->ref;
3818 if ($filterkey && $filterkey != '') {
3819 $objRef = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRef, 1);
3820 }
3821 $objRefFourn = $objp->ref_fourn;
3822 if ($filterkey && $filterkey != '') {
3823 $objRefFourn = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $objRefFourn, 1);
3824 }
3825 $label = $objp->label;
3826 if ($filterkey && $filterkey != '') {
3827 $label = preg_replace('/(' . preg_quote($filterkey, '/') . ')/i', '<strong>$1</strong>', $label, 1);
3828 }
3829
3830 switch ($objp->fk_product_type) {
3832 $picto = 'product';
3833 break;
3835 $picto = 'service';
3836 break;
3837 default:
3838 $picto = '';
3839 break;
3840 }
3841
3842 if (empty($picto)) {
3843 $optlabel = '';
3844 } else {
3845 $optlabel = img_object('', $picto, 'class="paddingright classfortooltip"', 0, 0, 1);
3846 }
3847
3848 $optlabel .= $objp->ref;
3849 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3850 $optlabel .= ' <span class="opacitymedium">(' . $objp->ref_fourn . ')</span>';
3851 }
3852 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3853 $optlabel .= ' (' . $outbarcode . ')';
3854 }
3855 $optlabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3856
3857 $outvallabel = $objRef;
3858 if (!empty($objp->idprodfournprice) && ($objp->ref != $objp->ref_fourn)) {
3859 $outvallabel .= ' (' . $objRefFourn . ')';
3860 }
3861 if (isModEnabled('barcode') && !empty($objp->barcode)) {
3862 $outvallabel .= ' (' . $outbarcode . ')';
3863 }
3864 $outvallabel .= ' - ' . dol_trunc($label, $maxlengtharticle);
3865
3866 // Units
3867 $optlabel .= $outvalUnits;
3868 $outvallabel .= $outvalUnits;
3869
3870 if (!empty($objp->idprodfournprice)) {
3871 $outqty = $objp->quantity;
3872 $outdiscount = $objp->remise_percent;
3873 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
3874 $prod_supplier = new ProductFournisseur($this->db);
3875 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
3876 $prod_supplier->id = $objp->fk_product;
3877 $prod_supplier->fourn_qty = $objp->quantity;
3878 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
3879 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
3880
3881 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
3882 $priceparser = new PriceParser($this->db);
3883 $price_result = $priceparser->parseProductSupplier($prod_supplier);
3884 if ($price_result >= 0) {
3885 $objp->fprice = $price_result;
3886 if ($objp->quantity >= 1) {
3887 $objp->unitprice = $objp->fprice / $objp->quantity; // Replace dynamically unitprice
3888 }
3889 }
3890 }
3891 if ($objp->quantity == 1) {
3892 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
3893 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/";
3894 $optlabel .= $langs->trans("Unit"); // Do not use strtolower because it breaks utf8 encoding
3895 $outvallabel .= $langs->transnoentities("Unit");
3896 } else {
3897 $optlabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3898 $outvallabel .= ' - ' . price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 0, $langs, 0, 0, -1, $conf->currency) . "/" . $objp->quantity;
3899 $optlabel .= ' ' . $langs->trans("Units"); // Do not use strtolower because it breaks utf8 encoding
3900 $outvallabel .= ' ' . $langs->transnoentities("Units");
3901 }
3902
3903 if ($objp->quantity > 1) {
3904 $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
3905 $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
3906 }
3907 if ($objp->remise_percent >= 1) {
3908 $optlabel .= " - " . $langs->trans("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3909 $outvallabel .= " - " . $langs->transnoentities("Discount") . " : " . vatrate($objp->remise_percent) . ' %';
3910 }
3911 if ($objp->duration) {
3912 $optlabel .= " - " . $objp->duration;
3913 $outvallabel .= " - " . $objp->duration;
3914 }
3915 if (!$socid) {
3916 $optlabel .= " - " . dol_trunc($objp->name, 8);
3917 $outvallabel .= " - " . dol_trunc($objp->name, 8);
3918 }
3919 if ($objp->supplier_reputation) {
3920 //TODO dictionary
3921 $reputations = array('' => $langs->trans('Standard'), 'FAVORITE' => $langs->trans('Favorite'), 'NOTTHGOOD' => $langs->trans('NotTheGoodQualitySupplier'), 'DONOTORDER' => $langs->trans('DoNotOrderThisProductToThisSupplier'));
3922
3923 $optlabel .= " - " . $reputations[$objp->supplier_reputation];
3924 $outvallabel .= " - " . $reputations[$objp->supplier_reputation];
3925 }
3926 } else {
3927 $optlabel .= " - <span class='opacitymedium'>" . $langs->trans("NoPriceDefinedForThisSupplier") . '</span>';
3928 $outvallabel .= ' - ' . $langs->transnoentities("NoPriceDefinedForThisSupplier");
3929 }
3930
3931 if (isModEnabled('stock') && $showstockinlist && isset($objp->stock) && ($objp->fk_product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
3932 $novirtualstock = ($showstockinlist == 2);
3933
3934 if ($user->hasRight('stock', 'lire')) {
3935 $outvallabel .= ' - ' . $langs->trans("Stock") . ': ' . price(price2num($objp->stock, 'MS'));
3936
3937 if ($objp->stock > 0) {
3938 $optlabel .= ' - <span class="product_line_stock_ok">';
3939 } elseif ($objp->stock <= 0) {
3940 $optlabel .= ' - <span class="product_line_stock_too_low">';
3941 }
3942 $optlabel .= $langs->transnoentities("Stock") . ':' . price(price2num($objp->stock, 'MS'));
3943 $optlabel .= '</span>';
3944 if (empty($novirtualstock) && getDolGlobalString('STOCK_SHOW_VIRTUAL_STOCK_IN_PRODUCTS_COMBO')) { // Warning, this option may slow down combo list generation
3945 $langs->load("stocks");
3946
3947 $tmpproduct = new Product($this->db);
3948 $tmpproduct->fetch($objp->rowid, '', '', '', 1, 1, 1); // Load product without lang and prices arrays (we just need to make ->virtual_stock() after)
3949 $tmpproduct->load_virtual_stock();
3950 $virtualstock = $tmpproduct->stock_theorique;
3951
3952 $outvallabel .= ' - ' . $langs->trans("VirtualStock") . ':' . $virtualstock;
3953
3954 $optlabel .= ' - ' . $langs->transnoentities("VirtualStock") . ':';
3955 if ($virtualstock > 0) {
3956 $optlabel .= '<span class="product_line_stock_ok">';
3957 } elseif ($virtualstock <= 0) {
3958 $optlabel .= '<span class="product_line_stock_too_low">';
3959 }
3960 $optlabel .= $virtualstock;
3961 $optlabel .= '</span>';
3962
3963 unset($tmpproduct);
3964 }
3965 }
3966 }
3967
3968 $optstart = '<option value="' . $outkey . '"';
3969 if ($selected && $selected == $objp->idprodfournprice) {
3970 $optstart .= ' selected';
3971 }
3972 if (empty($objp->idprodfournprice) && empty($alsoproductwithnosupplierprice)) {
3973 $optstart .= ' disabled';
3974 }
3975
3976 if (!empty($objp->idprodfournprice) && $objp->idprodfournprice > 0) {
3977 $optstart .= ' data-product-id="' . dol_escape_htmltag($objp->rowid) . '"';
3978 $optstart .= ' data-price-id="' . dol_escape_htmltag($objp->idprodfournprice) . '"';
3979 $optstart .= ' data-qty="' . dol_escape_htmltag($objp->quantity) . '"';
3980 $optstart .= ' data-up="' . dol_escape_htmltag(price2num($objp->unitprice)) . '"';
3981 $optstart .= ' data-up-locale="' . dol_escape_htmltag(price($objp->unitprice)) . '"';
3982 $optstart .= ' data-discount="' . dol_escape_htmltag($outdiscount) . '"';
3983 $optstart .= ' data-tvatx="' . dol_escape_htmltag(price2num($objp->tva_tx)) . '"';
3984 $optstart .= ' data-tvatx-formated="' . dol_escape_htmltag(price($objp->tva_tx, 0, $langs, 1, -1, 2)) . '"';
3985 $optstart .= ' data-default-vat-code="' . dol_escape_htmltag($objp->default_vat_code) . '"';
3986 $optstart .= ' data-supplier-ref="' . dol_escape_htmltag($objp->ref_fourn) . '"';
3987 if (isModEnabled('multicurrency')) {
3988 $optstart .= ' data-multicurrency-code="' . dol_escape_htmltag($objp->multicurrency_code) . '"';
3989 $optstart .= ' data-multicurrency-up="' . dol_escape_htmltag($objp->multicurrency_unitprice) . '"';
3990 }
3991 }
3992 $optstart .= ' data-description="' . dol_escape_htmltag($objp->description, 0, 1) . '"';
3993
3994 $outarrayentry = array(
3995 'key' => $outkey,
3996 'value' => $outref,
3997 'label' => $outvallabel,
3998 'qty' => $outqty,
3999 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4000 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4001 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4002 'tva_tx_formated' => price($objp->tva_tx, 0, $langs, 1, -1, 2),
4003 'tva_tx' => price2num($objp->tva_tx),
4004 'default_vat_code' => $objp->default_vat_code,
4005 'supplier_ref' => $objp->ref_fourn,
4006 'discount' => $outdiscount,
4007 'type' => $outtype,
4008 'duration_value' => $outdurationvalue,
4009 'duration_unit' => $outdurationunit,
4010 'disabled' => empty($objp->idprodfournprice),
4011 'description' => $objp->description
4012 );
4013 if (isModEnabled('multicurrency')) {
4014 $outarrayentry['multicurrency_code'] = $objp->multicurrency_code;
4015 $outarrayentry['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4016 }
4017
4018 $parameters = array(
4019 'objp' => &$objp,
4020 'optstart' => &$optstart,
4021 'optlabel' => &$optlabel,
4022 'outvallabel' => &$outvallabel,
4023 'outarrayentry' => &$outarrayentry
4024 );
4025 $reshook = $hookmanager->executeHooks('selectProduitsFournisseurListOption', $parameters, $this);
4026
4027
4028 // Add new entry
4029 // "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
4030 // "label" value of json key array is used by jQuery automatically as text for combo box
4031 $out .= $optstart . ' data-html="' . dol_escape_htmltag($optlabel) . '">' . $optlabel . "</option>\n";
4032 $outarraypush = array(
4033 'key' => $outkey,
4034 'value' => $outref,
4035 'label' => $outvallabel,
4036 'qty' => $outqty,
4037 'price_qty_ht' => price2num($objp->fprice, 'MU'), // Keep higher resolution for price for the min qty
4038 'price_qty_ht_locale' => price($objp->fprice),
4039 'price_unit_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price
4040 'price_unit_ht_locale' => price($objp->unitprice),
4041 'price_ht' => price2num($objp->unitprice, 'MU'), // This is used to fill the Unit Price (for compatibility)
4042 'tva_tx_formated' => price($objp->tva_tx),
4043 'tva_tx' => price2num($objp->tva_tx),
4044 'default_vat_code' => $objp->default_vat_code,
4045 'supplier_ref' => $objp->ref_fourn,
4046 'discount' => $outdiscount,
4047 'type' => $outtype,
4048 'duration_value' => $outdurationvalue,
4049 'duration_unit' => $outdurationunit,
4050 'disabled' => (empty($objp->idprodfournprice) ? true : false),
4051 'description' => $objp->description
4052 );
4053 if (isModEnabled('multicurrency')) {
4054 $outarraypush['multicurrency_code'] = $objp->multicurrency_code;
4055 $outarraypush['multicurrency_unitprice'] = price2num($objp->multicurrency_unitprice, 'MU');
4056 }
4057 array_push($outarray, $outarraypush);
4058
4059 // Example of var_dump $outarray
4060 // array(1) {[0]=>array(6) {[key"]=>string(1) "2" ["value"]=>string(3) "ppp"
4061 // ["label"]=>string(76) "ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/1unité (20,00 Euros/unité)"
4062 // ["qty"]=>string(1) "1" ["discount"]=>string(1) "0" ["disabled"]=>bool(false)
4063 //}
4064 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4065 //$outval=array('label'=>'ppp (<strong>f</strong>ff2) - ppp - 20,00 Euros/ Unité (20,00 Euros/unité)');
4066 //var_dump($outval); var_dump(utf8_check($outval)); var_dump(json_encode($outval));
4067
4068 $i++;
4069 }
4070 $out .= '</select>';
4071
4072 $this->db->free($result);
4073
4074 include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php';
4075 $out .= ajax_combobox($htmlname);
4076 } else {
4077 dol_print_error($this->db);
4078 }
4079
4080 if (empty($outputmode)) {
4081 return $out;
4082 }
4083 return $outarray;
4084 }
4085
4086 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4087
4096 public function select_product_fourn_price($productid, $htmlname = 'productfournpriceid', $selected_supplier = 0)
4097 {
4098 // phpcs:enable
4099 global $langs, $conf;
4100
4101 $langs->load('stocks');
4102
4103 $sql = "SELECT p.rowid, p.ref, p.label, p.price, p.duration, pfp.fk_soc,";
4104 $sql .= " pfp.ref_fourn, pfp.rowid as idprodfournprice, pfp.price as fprice, pfp.remise_percent, pfp.quantity, pfp.unitprice,";
4105 $sql .= " pfp.fk_supplier_price_expression, pfp.fk_product, pfp.tva_tx, s.nom as name";
4106 $sql .= " FROM " . $this->db->prefix() . "product as p";
4107 $sql .= " LEFT JOIN " . $this->db->prefix() . "product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
4108 $sql .= " LEFT JOIN " . $this->db->prefix() . "societe as s ON pfp.fk_soc = s.rowid";
4109 $sql .= " WHERE pfp.entity IN (" . getEntity('productsupplierprice') . ")";
4110 $sql .= " AND p.tobuy = 1";
4111 $sql .= " AND s.fournisseur = 1";
4112 $sql .= " AND p.rowid = " . ((int) $productid);
4113 if (!getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED')) {
4114 $sql .= " ORDER BY s.nom, pfp.ref_fourn DESC";
4115 } else {
4116 $sql .= " ORDER BY pfp.unitprice ASC";
4117 }
4118
4119 dol_syslog(get_class($this) . "::select_product_fourn_price", LOG_DEBUG);
4120 $result = $this->db->query($sql);
4121
4122 if ($result) {
4123 $num = $this->db->num_rows($result);
4124
4125 $form = '<select class="flat" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4126
4127 if (!$num) {
4128 $form .= '<option value="0">-- ' . $langs->trans("NoSupplierPriceDefinedForThisProduct") . ' --</option>';
4129 } else {
4130 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4131 $form .= '<option value="0">&nbsp;</option>';
4132
4133 $i = 0;
4134 while ($i < $num) {
4135 $objp = $this->db->fetch_object($result);
4136
4137 $opt = '<option value="' . $objp->idprodfournprice . '"';
4138 //if there is only one supplier, preselect it
4139 if ($num == 1 || ($selected_supplier > 0 && $objp->fk_soc == $selected_supplier) || ($i == 0 && getDolGlobalString('PRODUCT_BEST_SUPPLIER_PRICE_PRESELECTED'))) {
4140 $opt .= ' selected';
4141 }
4142 $opt .= '>' . $objp->name . ' - ' . $objp->ref_fourn . ' - ';
4143
4144 if (isModEnabled('dynamicprices') && !empty($objp->fk_supplier_price_expression)) {
4145 $prod_supplier = new ProductFournisseur($this->db);
4146 $prod_supplier->product_fourn_price_id = $objp->idprodfournprice;
4147 $prod_supplier->id = $productid;
4148 $prod_supplier->fourn_qty = $objp->quantity;
4149 $prod_supplier->fourn_tva_tx = $objp->tva_tx;
4150 $prod_supplier->fk_supplier_price_expression = $objp->fk_supplier_price_expression;
4151
4152 require_once DOL_DOCUMENT_ROOT . '/product/dynamic_price/class/price_parser.class.php';
4153 $priceparser = new PriceParser($this->db);
4154 $price_result = $priceparser->parseProductSupplier($prod_supplier);
4155 if ($price_result >= 0) {
4156 $objp->fprice = $price_result;
4157 if ($objp->quantity >= 1) {
4158 $objp->unitprice = $objp->fprice / $objp->quantity;
4159 }
4160 }
4161 }
4162 if ($objp->quantity == 1) {
4163 $opt .= price($objp->fprice * (getDolGlobalString('DISPLAY_DISCOUNTED_SUPPLIER_PRICE') ? (1 - $objp->remise_percent / 100) : 1), 1, $langs, 0, 0, -1, $conf->currency) . "/";
4164 }
4165
4166 $opt .= $objp->quantity . ' ';
4167
4168 if ($objp->quantity == 1) {
4169 $opt .= $langs->trans("Unit");
4170 } else {
4171 $opt .= $langs->trans("Units");
4172 }
4173 if ($objp->quantity > 1) {
4174 $opt .= " - ";
4175 $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");
4176 }
4177 if ($objp->duration) {
4178 $opt .= " - " . $objp->duration;
4179 }
4180 $opt .= "</option>\n";
4181
4182 $form .= $opt;
4183 $i++;
4184 }
4185 }
4186
4187 $form .= '</select>';
4188 $this->db->free($result);
4189 return $form;
4190 } else {
4191 dol_print_error($this->db);
4192 return '';
4193 }
4194 }
4195
4196
4197 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4204 {
4205 // phpcs:enable
4206 global $langs;
4207
4208 $num = count($this->cache_conditions_paiements);
4209 if ($num > 0) {
4210 return 0; // Cache already loaded
4211 }
4212
4213 dol_syslog(__METHOD__, LOG_DEBUG);
4214
4215 $sql = "SELECT rowid, code, libelle as label, deposit_percent";
4216 $sql .= " FROM " . $this->db->prefix() . 'c_payment_term';
4217 $sql .= " WHERE entity IN (" . getEntity('c_payment_term') . ")";
4218 $sql .= " AND active > 0";
4219 $sql .= " ORDER BY sortorder";
4220
4221 $resql = $this->db->query($sql);
4222 if ($resql) {
4223 $num = $this->db->num_rows($resql);
4224 $i = 0;
4225 while ($i < $num) {
4226 $obj = $this->db->fetch_object($resql);
4227
4228 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4229 $label = ($langs->trans("PaymentConditionShort" . $obj->code) != "PaymentConditionShort" . $obj->code ? $langs->trans("PaymentConditionShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4230 $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code;
4231 $this->cache_conditions_paiements[$obj->rowid]['label'] = $label;
4232 $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent;
4233 $i++;
4234 }
4235
4236 //$this->cache_conditions_paiements=dol_sort_array($this->cache_conditions_paiements, 'label', 'asc', 0, 0, 1); // We use the field sortorder of table
4237
4238 return $num;
4239 } else {
4240 dol_print_error($this->db);
4241 return -1;
4242 }
4243 }
4244
4245 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4246
4252 public function load_cache_availability()
4253 {
4254 // phpcs:enable
4255 global $langs;
4256
4257 $num = count($this->cache_availability); // TODO Use $conf->cache['availability'] instead of $this->cache_availability
4258 if ($num > 0) {
4259 return 0; // Cache already loaded
4260 }
4261
4262 dol_syslog(__METHOD__, LOG_DEBUG);
4263
4264 $langs->load('propal');
4265
4266 $sql = "SELECT rowid, code, label, position";
4267 $sql .= " FROM " . $this->db->prefix() . 'c_availability';
4268 $sql .= " WHERE active > 0";
4269
4270 $resql = $this->db->query($sql);
4271 if ($resql) {
4272 $num = $this->db->num_rows($resql);
4273 $i = 0;
4274 while ($i < $num) {
4275 $obj = $this->db->fetch_object($resql);
4276
4277 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4278 $label = ($langs->trans("AvailabilityType" . $obj->code) != "AvailabilityType" . $obj->code ? $langs->trans("AvailabilityType" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4279 $this->cache_availability[$obj->rowid]['code'] = $obj->code;
4280 $this->cache_availability[$obj->rowid]['label'] = $label;
4281 $this->cache_availability[$obj->rowid]['position'] = $obj->position;
4282 $i++;
4283 }
4284
4285 $this->cache_availability = dol_sort_array($this->cache_availability, 'position', 'asc', 0, 0, 1);
4286
4287 return $num;
4288 } else {
4289 dol_print_error($this->db);
4290 return -1;
4291 }
4292 }
4293
4304 public function selectAvailabilityDelay($selected = '', $htmlname = 'availid', $filtertype = '', $addempty = 0, $morecss = '')
4305 {
4306 global $langs, $user;
4307
4308 $this->load_cache_availability();
4309
4310 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4311
4312 print '<select id="' . $htmlname . '" class="flat' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4313 if ($addempty) {
4314 print '<option value="0">&nbsp;</option>';
4315 }
4316 foreach ($this->cache_availability as $id => $arrayavailability) {
4317 if ($selected == $id) {
4318 print '<option value="' . $id . '" selected>';
4319 } else {
4320 print '<option value="' . $id . '">';
4321 }
4322 print dol_escape_htmltag($arrayavailability['label']);
4323 print '</option>';
4324 }
4325 print '</select>';
4326 if ($user->admin) {
4327 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4328 }
4329 print ajax_combobox($htmlname);
4330 }
4331
4337 public function loadCacheInputReason()
4338 {
4339 global $langs;
4340
4341 $num = count($this->cache_demand_reason); // TODO Use $conf->cache['input_reason'] instead of $this->cache_demand_reason
4342 if ($num > 0) {
4343 return 0; // Cache already loaded
4344 }
4345
4346 $sql = "SELECT rowid, code, label";
4347 $sql .= " FROM " . $this->db->prefix() . 'c_input_reason';
4348 $sql .= " WHERE active > 0";
4349
4350 $resql = $this->db->query($sql);
4351 if ($resql) {
4352 $num = $this->db->num_rows($resql);
4353 $i = 0;
4354 $tmparray = array();
4355 while ($i < $num) {
4356 $obj = $this->db->fetch_object($resql);
4357
4358 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4359 $label = ($obj->label != '-' ? $obj->label : '');
4360 if ($langs->trans("DemandReasonType" . $obj->code) != "DemandReasonType" . $obj->code) {
4361 $label = $langs->trans("DemandReasonType" . $obj->code); // So translation key DemandReasonTypeSRC_XXX will work
4362 }
4363 if ($langs->trans($obj->code) != $obj->code) {
4364 $label = $langs->trans($obj->code); // So translation key SRC_XXX will work
4365 }
4366
4367 $tmparray[$obj->rowid]['id'] = $obj->rowid;
4368 $tmparray[$obj->rowid]['code'] = $obj->code;
4369 $tmparray[$obj->rowid]['label'] = $label;
4370 $i++;
4371 }
4372
4373 $this->cache_demand_reason = dol_sort_array($tmparray, 'label', 'asc', 0, 0, 1);
4374
4375 unset($tmparray);
4376 return $num;
4377 } else {
4378 dol_print_error($this->db);
4379 return -1;
4380 }
4381 }
4382
4395 public function selectInputReason($selected = '', $htmlname = 'demandreasonid', $exclude = '', $addempty = 0, $morecss = '', $notooltip = 0)
4396 {
4397 global $langs, $user;
4398
4399 $this->loadCacheInputReason();
4400
4401 print '<select class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4402 if ($addempty) {
4403 print '<option value="0"' . (empty($selected) ? ' selected' : '') . '>&nbsp;</option>';
4404 }
4405 foreach ($this->cache_demand_reason as $id => $arraydemandreason) {
4406 if ($arraydemandreason['code'] == $exclude) {
4407 continue;
4408 }
4409
4410 if ($selected && ($selected == $arraydemandreason['id'] || $selected == $arraydemandreason['code'])) {
4411 print '<option value="' . $arraydemandreason['id'] . '" selected>';
4412 } else {
4413 print '<option value="' . $arraydemandreason['id'] . '">';
4414 }
4415 $label = $arraydemandreason['label']; // Translation of label was already done into the ->loadCacheInputReason
4416 print $langs->trans($label);
4417 print '</option>';
4418 }
4419 print '</select>';
4420 if ($user->admin && empty($notooltip)) {
4421 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4422 }
4423 print ajax_combobox('select_' . $htmlname);
4424 }
4425
4426 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4427
4434 {
4435 // phpcs:enable
4436 global $langs;
4437
4438 $num = count($this->cache_types_paiements); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_types_paiements
4439 if ($num > 0) {
4440 return $num; // Cache already loaded
4441 }
4442
4443 dol_syslog(__METHOD__, LOG_DEBUG);
4444
4445 $this->cache_types_paiements = array();
4446
4447 $sql = "SELECT id, code, libelle as label, type, active";
4448 $sql .= " FROM " . $this->db->prefix() . "c_paiement";
4449 $sql .= " WHERE entity IN (" . getEntity('c_paiement') . ")";
4450
4451 $resql = $this->db->query($sql);
4452 if ($resql) {
4453 $num = $this->db->num_rows($resql);
4454 $i = 0;
4455 while ($i < $num) {
4456 $obj = $this->db->fetch_object($resql);
4457
4458 // Si traduction existe, on l'utilise, sinon on prend le libelle par default
4459 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4460 $this->cache_types_paiements[$obj->id]['id'] = $obj->id;
4461 $this->cache_types_paiements[$obj->id]['code'] = $obj->code;
4462 $this->cache_types_paiements[$obj->id]['label'] = $label;
4463 $this->cache_types_paiements[$obj->id]['type'] = $obj->type;
4464 $this->cache_types_paiements[$obj->id]['active'] = $obj->active;
4465 $i++;
4466 }
4467
4468 $this->cache_types_paiements = dol_sort_array($this->cache_types_paiements, 'label', 'asc', 0, 0, 1);
4469
4470 return $num;
4471 } else {
4472 dol_print_error($this->db);
4473 return -1;
4474 }
4475 }
4476
4477
4478 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4479
4498 public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1, $noprint = 0)
4499 {
4500 // phpcs:enable
4501 $out = $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, $noinfoadmin, $morecss, $deposit_percent);
4502 if (empty($noprint)) {
4503 print $out;
4504 } else {
4505 return $out;
4506 }
4507 }
4508
4509
4526 public function getSelectConditionsPaiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = -1)
4527 {
4528 global $langs, $user, $conf;
4529
4530 $out = '';
4531 dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG);
4532
4534
4535 // Set default value if not already set by caller
4536 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID')) {
4537 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TERM_ID", LOG_NOTICE);
4538 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TERM_ID');
4539 }
4540
4541 $out .= '<select id="' . $htmlname . '" class="flat selectpaymentterms' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4542 if ($addempty) {
4543 $out .= '<option value="0">&nbsp;</option>';
4544 }
4545
4546 $selectedDepositPercent = null;
4547
4548 foreach ($this->cache_conditions_paiements as $id => $arrayconditions) {
4549 if ($filtertype <= 0 && !empty($arrayconditions['deposit_percent'])) {
4550 continue;
4551 }
4552
4553 if ($selected == $id) {
4554 $selectedDepositPercent = $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'];
4555 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '" selected>';
4556 } else {
4557 $out .= '<option value="' . $id . '" data-deposit_percent="' . $arrayconditions['deposit_percent'] . '">';
4558 }
4559 $label = $arrayconditions['label'];
4560
4561 if (!empty($arrayconditions['deposit_percent'])) {
4562 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $arrayconditions['deposit_percent'], $label);
4563 }
4564
4565 $out .= $label;
4566 $out .= '</option>';
4567 }
4568 $out .= '</select>';
4569 if ($user->admin && empty($noinfoadmin)) {
4570 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4571 }
4572 $out .= ajax_combobox($htmlname);
4573
4574 if ($deposit_percent >= 0) {
4575 $out .= ' <span id="' . $htmlname . '_deposit_percent_container"' . (empty($selectedDepositPercent) ? ' style="display: none"' : '') . '>';
4576 $out .= $langs->trans('DepositPercent') . ' : ';
4577 $out .= '<input id="' . $htmlname . '_deposit_percent" name="' . $htmlname . '_deposit_percent" class="maxwidth50" value="' . $deposit_percent . '" />';
4578 $out .= '</span>';
4579 $out .= '
4580 <script nonce="' . getNonce() . '">
4581 $(document).ready(function () {
4582 $("#' . $htmlname . '").change(function () {
4583 let $selected = $(this).find("option:selected");
4584 let depositPercent = $selected.attr("data-deposit_percent");
4585
4586 if (depositPercent.length > 0) {
4587 $("#' . $htmlname . '_deposit_percent_container").show().find("#' . $htmlname . '_deposit_percent").val(depositPercent);
4588 } else {
4589 $("#' . $htmlname . '_deposit_percent_container").hide();
4590 }
4591
4592 return true;
4593 });
4594 });
4595 </script>';
4596 }
4597
4598 return $out;
4599 }
4600
4601
4602 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4603
4620 public function select_types_paiements($selected = '', $htmlname = 'paiementtype', $filtertype = '', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '', $nooutput = 0)
4621 {
4622 // phpcs:enable
4623 global $langs, $user, $conf;
4624
4625 $out = '';
4626
4627 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $filtertype . ", " . $format, LOG_DEBUG);
4628
4629 $filterarray = array();
4630 if ($filtertype == 'CRDT') {
4631 $filterarray = array(0, 2, 3);
4632 } elseif ($filtertype == 'DBIT') {
4633 $filterarray = array(1, 2, 3);
4634 } elseif ($filtertype != '' && $filtertype != '-1') {
4635 $filterarray = explode(',', $filtertype);
4636 }
4637
4639
4640 // Set default value if not already set by caller
4641 if (empty($selected) && getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID')) {
4642 dol_syslog(__METHOD__ . "Using deprecated option MAIN_DEFAULT_PAYMENT_TYPE_ID", LOG_NOTICE);
4643 $selected = getDolGlobalString('MAIN_DEFAULT_PAYMENT_TYPE_ID');
4644 }
4645
4646 $out .= '<select id="select' . $htmlname . '" class="flat selectpaymenttypes' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4647 if ($empty) {
4648 $out .= '<option value="">&nbsp;</option>';
4649 }
4650 foreach ($this->cache_types_paiements as $id => $arraytypes) {
4651 // If not good status
4652 if ($active >= 0 && $arraytypes['active'] != $active) {
4653 continue;
4654 }
4655
4656 // We skip of the user requested to filter on specific payment methods
4657 if (count($filterarray) && !in_array($arraytypes['type'], $filterarray)) {
4658 continue;
4659 }
4660
4661 // We discard empty lines if showempty is on because an empty line has already been output.
4662 if ($empty && empty($arraytypes['code'])) {
4663 continue;
4664 }
4665
4666 if ($format == 0) {
4667 $out .= '<option value="' . $id . '"';
4668 } elseif ($format == 1) {
4669 $out .= '<option value="' . $arraytypes['code'] . '"';
4670 } elseif ($format == 2) {
4671 $out .= '<option value="' . $arraytypes['code'] . '"';
4672 } elseif ($format == 3) {
4673 $out .= '<option value="' . $id . '"';
4674 }
4675 // Print attribute selected or not
4676 if ($format == 1 || $format == 2) {
4677 if ($selected == $arraytypes['code']) {
4678 $out .= ' selected';
4679 }
4680 } else {
4681 if ($selected == $id) {
4682 $out .= ' selected';
4683 }
4684 }
4685 $out .= '>';
4686 $value = '';
4687 if ($format == 0) {
4688 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4689 } elseif ($format == 1) {
4690 $value = $arraytypes['code'];
4691 } elseif ($format == 2) {
4692 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4693 } elseif ($format == 3) {
4694 $value = $arraytypes['code'];
4695 }
4696 $out .= $value ? $value : '&nbsp;';
4697 $out .= '</option>';
4698 }
4699 $out .= '</select>';
4700 if ($user->admin && !$noadmininfo) {
4701 $out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4702 }
4703 $out .= ajax_combobox('select' . $htmlname);
4704
4705 if (empty($nooutput)) {
4706 print $out;
4707 } else {
4708 return $out;
4709 }
4710 }
4711
4712
4721 public function selectPriceBaseType($selected = '', $htmlname = 'price_base_type', $addjscombo = 0)
4722 {
4723 global $langs;
4724
4725 $return = '<select class="flat maxwidth100" id="select_' . $htmlname . '" name="' . $htmlname . '">';
4726 $options = array(
4727 'HT' => $langs->trans("HT"),
4728 'TTC' => $langs->trans("TTC")
4729 );
4730 foreach ($options as $id => $value) {
4731 if ($selected == $id) {
4732 $return .= '<option value="' . $id . '" selected>' . $value;
4733 } else {
4734 $return .= '<option value="' . $id . '">' . $value;
4735 }
4736 $return .= '</option>';
4737 }
4738 $return .= '</select>';
4739 if ($addjscombo) {
4740 $return .= ajax_combobox('select_' . $htmlname);
4741 }
4742
4743 return $return;
4744 }
4745
4746 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4747
4754 {
4755 // phpcs:enable
4756 global $langs;
4757
4758 $num = count($this->cache_transport_mode); // TODO Use $conf->cache['payment_mode'] instead of $this->cache_transport_mode
4759 if ($num > 0) {
4760 return $num; // Cache already loaded
4761 }
4762
4763 dol_syslog(__METHOD__, LOG_DEBUG);
4764
4765 $this->cache_transport_mode = array();
4766
4767 $sql = "SELECT rowid, code, label, active";
4768 $sql .= " FROM " . $this->db->prefix() . "c_transport_mode";
4769 $sql .= " WHERE entity IN (" . getEntity('c_transport_mode') . ")";
4770
4771 $resql = $this->db->query($sql);
4772 if ($resql) {
4773 $num = $this->db->num_rows($resql);
4774 $i = 0;
4775 while ($i < $num) {
4776 $obj = $this->db->fetch_object($resql);
4777
4778 // If traduction exist, we use it else we take the default label
4779 $label = ($langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) != "PaymentTypeShort" . $obj->code ? $langs->transnoentitiesnoconv("PaymentTypeShort" . $obj->code) : ($obj->label != '-' ? $obj->label : ''));
4780 $this->cache_transport_mode[$obj->rowid]['rowid'] = $obj->rowid;
4781 $this->cache_transport_mode[$obj->rowid]['code'] = $obj->code;
4782 $this->cache_transport_mode[$obj->rowid]['label'] = $label;
4783 $this->cache_transport_mode[$obj->rowid]['active'] = $obj->active;
4784 $i++;
4785 }
4786
4787 $this->cache_transport_mode = dol_sort_array($this->cache_transport_mode, 'label', 'asc', 0, 0, 1);
4788
4789 return $num;
4790 } else {
4791 dol_print_error($this->db);
4792 return -1;
4793 }
4794 }
4795
4809 public function selectTransportMode($selected = '', $htmlname = 'transportmode', $format = 0, $empty = 1, $noadmininfo = 0, $maxlength = 0, $active = 1, $morecss = '')
4810 {
4811 global $langs, $user;
4812
4813 dol_syslog(__METHOD__ . " " . $selected . ", " . $htmlname . ", " . $format, LOG_DEBUG);
4814
4816
4817 print '<select id="select' . $htmlname . '" class="flat selectmodetransport' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
4818 if ($empty) {
4819 print '<option value="">&nbsp;</option>';
4820 }
4821 foreach ($this->cache_transport_mode as $id => $arraytypes) {
4822 // If not good status
4823 if ($active >= 0 && $arraytypes['active'] != $active) {
4824 continue;
4825 }
4826
4827 // We discard empty line if showempty is on because an empty line has already been output.
4828 if ($empty && empty($arraytypes['code'])) {
4829 continue;
4830 }
4831
4832 if ($format == 0) {
4833 print '<option value="' . $id . '"';
4834 } elseif ($format == 1) {
4835 print '<option value="' . $arraytypes['code'] . '"';
4836 } elseif ($format == 2) {
4837 print '<option value="' . $arraytypes['code'] . '"';
4838 } elseif ($format == 3) {
4839 print '<option value="' . $id . '"';
4840 }
4841 // If text is selected, we compare with code, else with id
4842 if (preg_match('/[a-z]/i', $selected) && $selected == $arraytypes['code']) {
4843 print ' selected';
4844 } elseif ($selected == $id) {
4845 print ' selected';
4846 }
4847 print '>';
4848 $value = '';
4849 if ($format == 0) {
4850 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4851 } elseif ($format == 1) {
4852 $value = $arraytypes['code'];
4853 } elseif ($format == 2) {
4854 $value = ($maxlength ? dol_trunc($arraytypes['label'], $maxlength) : $arraytypes['label']);
4855 } elseif ($format == 3) {
4856 $value = $arraytypes['code'];
4857 }
4858 print $value ? $value : '&nbsp;';
4859 print '</option>';
4860 }
4861 print '</select>';
4862 if ($user->admin && !$noadmininfo) {
4863 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4864 }
4865 }
4866
4879 public function selectShippingMethod($selected = '', $htmlname = 'shipping_method_id', $filtre = '', $useempty = 0, $moreattrib = '', $noinfoadmin = 0, $morecss = '')
4880 {
4881 global $langs, $user;
4882
4883 $langs->load("admin");
4884 $langs->load("deliveries");
4885
4886 $sql = "SELECT rowid, code, libelle as label";
4887 $sql .= " FROM " . $this->db->prefix() . "c_shipment_mode";
4888 $sql .= " WHERE active > 0";
4889 if ($filtre) {
4890 $sql .= " AND " . $filtre;
4891 }
4892 $sql .= " ORDER BY libelle ASC";
4893
4894 dol_syslog(get_class($this) . "::selectShippingMode", LOG_DEBUG);
4895 $result = $this->db->query($sql);
4896 if ($result) {
4897 $num = $this->db->num_rows($result);
4898 $i = 0;
4899 if ($num) {
4900 print '<select id="select' . $htmlname . '" class="flat selectshippingmethod' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
4901 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
4902 print '<option value="-1">&nbsp;</option>';
4903 }
4904 while ($i < $num) {
4905 $obj = $this->db->fetch_object($result);
4906 if ($selected == $obj->rowid) {
4907 print '<option value="' . $obj->rowid . '" selected>';
4908 } else {
4909 print '<option value="' . $obj->rowid . '">';
4910 }
4911 print ($langs->trans("SendingMethod" . strtoupper($obj->code)) != "SendingMethod" . strtoupper($obj->code)) ? $langs->trans("SendingMethod" . strtoupper($obj->code)) : $obj->label;
4912 print '</option>';
4913 $i++;
4914 }
4915 print "</select>";
4916 if ($user->admin && empty($noinfoadmin)) {
4917 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
4918 }
4919
4920 print ajax_combobox('select' . $htmlname);
4921 } else {
4922 print $langs->trans("NoShippingMethodDefined");
4923 }
4924 } else {
4925 dol_print_error($this->db);
4926 }
4927 }
4928
4938 public function formSelectShippingMethod($page, $selected = '', $htmlname = 'shipping_method_id', $addempty = 0)
4939 {
4940 global $langs;
4941
4942 $langs->load("deliveries");
4943
4944 if ($htmlname != "none") {
4945 print '<form method="POST" action="' . $page . '">';
4946 print '<input type="hidden" name="action" value="setshippingmethod">';
4947 print '<input type="hidden" name="token" value="' . newToken() . '">';
4948 $this->selectShippingMethod($selected, $htmlname, '', $addempty);
4949 print '<input type="submit" class="button valignmiddle" value="' . $langs->trans("Modify") . '">';
4950 print '</form>';
4951 } else {
4952 if ($selected) {
4953 $code = $langs->getLabelFromKey($this->db, $selected, 'c_shipment_mode', 'rowid', 'code');
4954 print $langs->trans("SendingMethod" . strtoupper($code));
4955 } else {
4956 print "&nbsp;";
4957 }
4958 }
4959 }
4960
4969 public function selectSituationInvoices($selected = '', $socid = 0)
4970 {
4971 global $langs;
4972
4973 $langs->load('bills');
4974
4975 $opt = '<option value="" selected></option>';
4976 $sql = "SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc";
4977 $sql .= ' FROM ' . $this->db->prefix() . 'facture';
4978 $sql .= ' WHERE entity IN (' . getEntity('invoice') . ')';
4979 $sql .= ' AND situation_counter >= 1';
4980 $sql .= ' AND fk_soc = ' . (int) $socid;
4981 $sql .= ' AND type <> 2';
4982 $sql .= ' ORDER by situation_cycle_ref, situation_counter desc';
4983 $resql = $this->db->query($sql);
4984
4985 if ($resql && $this->db->num_rows($resql) > 0) {
4986 // Last seen cycle
4987 $ref = 0;
4988 while ($obj = $this->db->fetch_object($resql)) {
4989 //Same cycle ?
4990 if ($obj->situation_cycle_ref != $ref) {
4991 // Just seen this cycle
4992 $ref = $obj->situation_cycle_ref;
4993 //not final ?
4994 if ($obj->situation_final != 1) {
4995 //Not prov?
4996 if (substr($obj->ref, 1, 4) != 'PROV') {
4997 if ($selected == $obj->rowid) {
4998 $opt .= '<option value="' . $obj->rowid . '" selected>' . $obj->ref . '</option>';
4999 } else {
5000 $opt .= '<option value="' . $obj->rowid . '">' . $obj->ref . '</option>';
5001 }
5002 }
5003 }
5004 }
5005 }
5006 } else {
5007 dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR);
5008 }
5009 if ($opt == '<option value ="" selected></option>') {
5010 $opt = '<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>';
5011 }
5012 return $opt;
5013 }
5014
5024 public function selectUnits($selected = '', $htmlname = 'units', $showempty = 0, $unit_type = '')
5025 {
5026 global $langs;
5027
5028 $langs->load('products');
5029
5030 $return = '<select class="flat" id="' . $htmlname . '" name="' . $htmlname . '">';
5031
5032 $sql = "SELECT rowid, label, code FROM " . $this->db->prefix() . "c_units";
5033 $sql .= ' WHERE active > 0';
5034 if (!empty($unit_type)) {
5035 $sql .= " AND unit_type = '" . $this->db->escape($unit_type) . "'";
5036 }
5037 $sql .= " ORDER BY sortorder";
5038
5039 $resql = $this->db->query($sql);
5040 if ($resql && $this->db->num_rows($resql) > 0) {
5041 if ($showempty) {
5042 $return .= '<option value="none"></option>';
5043 }
5044
5045 while ($res = $this->db->fetch_object($resql)) {
5046 $unitLabel = $res->label;
5047 if (!empty($langs->tab_translate['unit' . $res->code])) { // check if Translation is available before
5048 $unitLabel = $langs->trans('unit' . $res->code) != $res->label ? $langs->trans('unit' . $res->code) : $res->label;
5049 }
5050
5051 if ($selected == $res->rowid) {
5052 $return .= '<option value="' . $res->rowid . '" selected>' . $unitLabel . '</option>';
5053 } else {
5054 $return .= '<option value="' . $res->rowid . '">' . $unitLabel . '</option>';
5055 }
5056 }
5057 $return .= '</select>';
5058 }
5059 return $return;
5060 }
5061
5062 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5063
5078 public function select_comptes($selected = '', $htmlname = 'accountid', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '', $showcurrency = 0, $morecss = '', $nooutput = 0)
5079 {
5080 // phpcs:enable
5081 global $langs;
5082
5083 $out = '';
5084
5085 $langs->load("admin");
5086 $num = 0;
5087
5088 $sql = "SELECT rowid, label, bank, clos as status, currency_code";
5089 $sql .= " FROM " . $this->db->prefix() . "bank_account";
5090 $sql .= " WHERE entity IN (" . getEntity('bank_account') . ")";
5091 if ($status != 2) {
5092 $sql .= " AND clos = " . (int) $status;
5093 }
5094 if ($filtre) { // TODO Support USF
5095 $sql .= " AND " . $filtre;
5096 }
5097 $sql .= " ORDER BY label";
5098
5099 dol_syslog(get_class($this) . "::select_comptes", LOG_DEBUG);
5100 $result = $this->db->query($sql);
5101 if ($result) {
5102 $num = $this->db->num_rows($result);
5103 $i = 0;
5104 if ($num) {
5105 $out .= '<select id="select' . $htmlname . '" class="flat selectbankaccount' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5106
5107 if (!empty($useempty) && !is_numeric($useempty)) {
5108 $out .= '<option value="-1">'.$langs->trans($useempty).'</option>';
5109 } elseif ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5110 $out .= '<option value="-1">&nbsp;</option>';
5111 }
5112
5113 while ($i < $num) {
5114 $obj = $this->db->fetch_object($result);
5115 if ($selected == $obj->rowid || ($useempty == 2 && $num == 1 && empty($selected))) {
5116 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '" selected>';
5117 } else {
5118 $out .= '<option value="' . $obj->rowid . '" data-currency-code="' . $obj->currency_code . '">';
5119 }
5120 $out .= trim($obj->label);
5121 if ($showcurrency) {
5122 $out .= ' (' . $obj->currency_code . ')';
5123 }
5124 if ($status == 2 && $obj->status == 1) {
5125 $out .= ' (' . $langs->trans("Closed") . ')';
5126 }
5127 $out .= '</option>';
5128 $i++;
5129 }
5130 $out .= "</select>";
5131 $out .= ajax_combobox('select' . $htmlname);
5132 } else {
5133 if ($status == 0) {
5134 $out .= '<span class="opacitymedium">' . $langs->trans("NoActiveBankAccountDefined") . '</span>';
5135 } else {
5136 $out .= '<span class="opacitymedium">' . $langs->trans("NoBankAccountFound") . '</span>';
5137 }
5138 }
5139 } else {
5140 dol_print_error($this->db);
5141 }
5142
5143 // Output or return
5144 if (empty($nooutput)) {
5145 print $out;
5146 } else {
5147 return $out;
5148 }
5149
5150 return $num;
5151 }
5152
5164 public function selectEstablishments($selected = '', $htmlname = 'entity', $status = 0, $filtre = '', $useempty = 0, $moreattrib = '')
5165 {
5166 global $langs;
5167
5168 $langs->load("admin");
5169 $num = 0;
5170
5171 $sql = "SELECT rowid, name, fk_country, status, entity";
5172 $sql .= " FROM " . $this->db->prefix() . "establishment";
5173 $sql .= " WHERE 1=1";
5174 if ($status != 2) {
5175 $sql .= " AND status = " . (int) $status;
5176 }
5177 if ($filtre) { // TODO Support USF
5178 $sql .= " AND " . $filtre;
5179 }
5180 $sql .= " ORDER BY name";
5181
5182 dol_syslog(get_class($this) . "::select_establishment", LOG_DEBUG);
5183 $result = $this->db->query($sql);
5184 if ($result) {
5185 $num = $this->db->num_rows($result);
5186 $i = 0;
5187 if ($num) {
5188 print '<select id="select' . $htmlname . '" class="flat selectestablishment" name="' . $htmlname . '"' . ($moreattrib ? ' ' . $moreattrib : '') . '>';
5189 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5190 print '<option value="-1">&nbsp;</option>';
5191 }
5192
5193 while ($i < $num) {
5194 $obj = $this->db->fetch_object($result);
5195 if ($selected == $obj->rowid) {
5196 print '<option value="' . $obj->rowid . '" selected>';
5197 } else {
5198 print '<option value="' . $obj->rowid . '">';
5199 }
5200 print trim($obj->name);
5201 if ($status == 2 && $obj->status == 1) {
5202 print ' (' . $langs->trans("Closed") . ')';
5203 }
5204 print '</option>';
5205 $i++;
5206 }
5207 print "</select>";
5208 } else {
5209 if ($status == 0) {
5210 print '<span class="opacitymedium">' . $langs->trans("NoActiveEstablishmentDefined") . '</span>';
5211 } else {
5212 print '<span class="opacitymedium">' . $langs->trans("NoEstablishmentFound") . '</span>';
5213 }
5214 }
5215
5216 return $num;
5217 } else {
5218 dol_print_error($this->db);
5219 return -1;
5220 }
5221 }
5222
5232 public function formSelectAccount($page, $selected = '', $htmlname = 'fk_account', $addempty = 0)
5233 {
5234 global $langs;
5235 if ($htmlname != "none") {
5236 print '<form method="POST" action="' . $page . '">';
5237 print '<input type="hidden" name="action" value="setbankaccount">';
5238 print '<input type="hidden" name="token" value="' . newToken() . '">';
5239 print img_picto('', 'bank_account', 'class="pictofixedwidth"');
5240 $nbaccountfound = $this->select_comptes($selected, $htmlname, 0, '', $addempty);
5241 if ($nbaccountfound > 0) {
5242 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
5243 }
5244 print '</form>';
5245 } else {
5246 $langs->load('banks');
5247
5248 if ($selected) {
5249 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
5250 $bankstatic = new Account($this->db);
5251 $result = $bankstatic->fetch($selected);
5252 if ($result) {
5253 print $bankstatic->getNomUrl(1);
5254 }
5255 } else {
5256 print "&nbsp;";
5257 }
5258 }
5259 }
5260
5261 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5262
5282 public function select_all_categories($type, $selected = '', $htmlname = "parent", $maxlength = 64, $fromid = 0, $outputmode = 0, $include = 0, $morecss = '', $useempty = 1)
5283 {
5284 // phpcs:enable
5285 global $conf, $langs;
5286 $langs->load("categories");
5287
5288 include_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
5289
5290 // For backward compatibility
5291 if (is_numeric($type)) {
5292 dol_syslog(__METHOD__ . ': using numeric value for parameter type is deprecated. Use string code instead.', LOG_WARNING);
5293 }
5294
5295 if ($type === Categorie::TYPE_BANK_LINE) {
5296 // TODO Move this into common category feature
5297 $cate_arbo = array();
5298 $sql = "SELECT c.label, c.rowid";
5299 $sql .= " FROM " . $this->db->prefix() . "bank_categ as c";
5300 $sql .= " WHERE entity = " . $conf->entity;
5301 $sql .= " ORDER BY c.label";
5302 $result = $this->db->query($sql);
5303 if ($result) {
5304 $num = $this->db->num_rows($result);
5305 $i = 0;
5306 while ($i < $num) {
5307 $objp = $this->db->fetch_object($result);
5308 if ($objp) {
5309 $cate_arbo[$objp->rowid] = array('id' => $objp->rowid, 'fulllabel' => $objp->label, 'color' => '', 'picto' => 'category');
5310 }
5311 $i++;
5312 }
5313 $this->db->free($result);
5314 } else {
5315 dol_print_error($this->db);
5316 }
5317 } else {
5318 $cat = new Categorie($this->db);
5319 $cate_arbo = $cat->get_full_arbo($type, $fromid, $include);
5320 }
5321
5322 $outarray = array();
5323 $outarrayrichhtml = array();
5324
5325
5326 $output = '<select class="flat minwidth100' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '" id="' . $htmlname . '">';
5327 if (is_array($cate_arbo)) {
5328 $num = count($cate_arbo);
5329
5330 if (!$num) {
5331 $output .= '<option value="-1" disabled>' . $langs->trans("NoCategoriesDefined") . '</option>';
5332 } else {
5333 if ($useempty == 1 || ($useempty == 2 && $num > 1)) {
5334 $output .= '<option value="-1">&nbsp;</option>';
5335 }
5336 foreach ($cate_arbo as $key => $value) {
5337 if ($cate_arbo[$key]['id'] == $selected || ($selected === 'auto' && count($cate_arbo) == 1)) {
5338 $add = 'selected ';
5339 } else {
5340 $add = '';
5341 }
5342
5343 $labeltoshow = img_picto('', 'category', 'class="pictofixedwidth" style="color: #' . $cate_arbo[$key]['color'] . '"');
5344 $labeltoshow .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5345
5346 $outarray[$cate_arbo[$key]['id']] = $cate_arbo[$key]['fulllabel'];
5347
5348 $outarrayrichhtml[$cate_arbo[$key]['id']] = $labeltoshow;
5349
5350 $output .= '<option ' . $add . 'value="' . $cate_arbo[$key]['id'] . '"';
5351 $output .= ' data-html="' . dol_escape_htmltag($labeltoshow) . '"';
5352 $output .= '>';
5353 $output .= dol_trunc($cate_arbo[$key]['fulllabel'], $maxlength, 'middle');
5354 $output .= '</option>';
5355
5356 $cate_arbo[$key]['data-html'] = $labeltoshow;
5357 }
5358 }
5359 }
5360 $output .= '</select>';
5361 $output .= "\n";
5362
5363 if ($outputmode == 2) {
5364 // TODO: handle error when $cate_arbo is not an array
5365 return $cate_arbo;
5366 } elseif ($outputmode == 1) {
5367 return $outarray;
5368 } elseif ($outputmode == 3) {
5369 return $outarrayrichhtml;
5370 }
5371 return $output;
5372 }
5373
5374 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5375
5392 public function form_confirm($page, $title, $question, $action, $formquestion = array(), $selectedchoice = "", $useajax = 0, $height = 170, $width = 500)
5393 {
5394 // phpcs:enable
5395 dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
5396 print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
5397 }
5398
5426 public function formconfirm($page, $title, $question, $action, $formquestion = '', $selectedchoice = '', $useajax = 0, $height = 0, $width = 500, $disableformtag = 0, $labelbuttonyes = 'Yes', $labelbuttonno = 'No')
5427 {
5428 global $langs, $conf;
5429
5430 $more = '<!-- formconfirm - before call, page=' . dol_escape_htmltag($page) . ' -->';
5431 $formconfirm = '';
5432 $inputok = array();
5433 $inputko = array();
5434
5435 // Clean parameters
5436 $newselectedchoice = empty($selectedchoice) ? "no" : $selectedchoice;
5437 if ($conf->browser->layout == 'phone') {
5438 $width = '95%';
5439 }
5440
5441 // Set height automatically if not defined
5442 if (empty($height)) {
5443 $height = 220;
5444 if (is_array($formquestion) && count($formquestion) > 2) {
5445 $height += ((count($formquestion) - 2) * 24);
5446 }
5447 }
5448
5449 if (is_array($formquestion) && !empty($formquestion)) {
5450 // First add hidden fields and value
5451 foreach ($formquestion as $key => $input) {
5452 if (is_array($input) && !empty($input)) {
5453 if ($input['type'] == 'hidden') {
5454 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5455 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5456
5457 $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";
5458 }
5459 }
5460 }
5461
5462 // Now add questions
5463 $moreonecolumn = '';
5464 $more .= '<div class="tagtable paddingtopbottomonly centpercent noborderspacing">' . "\n";
5465 foreach ($formquestion as $key => $input) {
5466 if (is_array($input) && !empty($input)) {
5467 $size = (!empty($input['size']) ? ' size="' . $input['size'] . '"' : ''); // deprecated. Use morecss instead.
5468 $moreattr = (!empty($input['moreattr']) ? ' ' . $input['moreattr'] : '');
5469 $morecss = (!empty($input['morecss']) ? ' ' . $input['morecss'] : '');
5470
5471 if ($input['type'] == 'text') {
5472 $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";
5473 } elseif ($input['type'] == 'password') {
5474 $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";
5475 } elseif ($input['type'] == 'textarea') {
5476 /*$more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">'.$input['label'].'</div><div class="tagtd">';
5477 $more .= '<textarea name="'.$input['name'].'" class="'.$morecss.'"'.$moreattr.'>';
5478 $more .= $input['value'];
5479 $more .= '</textarea>';
5480 $more .= '</div></div>'."\n";*/
5481 $moreonecolumn .= '<div class="margintoponly">';
5482 $moreonecolumn .= $input['label'] . '<br>';
5483 $moreonecolumn .= '<textarea name="' . dol_escape_htmltag($input['name']) . '" id="' . dol_escape_htmltag($input['name']) . '" class="' . $morecss . '"' . $moreattr . '>';
5484 $moreonecolumn .= $input['value'];
5485 $moreonecolumn .= '</textarea>';
5486 $moreonecolumn .= '</div>';
5487 } elseif (in_array($input['type'], ['select', 'multiselect'])) {
5488 if (empty($morecss)) {
5489 $morecss = 'minwidth100';
5490 }
5491
5492 $show_empty = isset($input['select_show_empty']) ? $input['select_show_empty'] : 1;
5493 $key_in_label = isset($input['select_key_in_label']) ? $input['select_key_in_label'] : 0;
5494 $value_as_key = isset($input['select_value_as_key']) ? $input['select_value_as_key'] : 0;
5495 $translate = isset($input['select_translate']) ? $input['select_translate'] : 0;
5496 $maxlen = isset($input['select_maxlen']) ? $input['select_maxlen'] : 0;
5497 $disabled = isset($input['select_disabled']) ? $input['select_disabled'] : 0;
5498 $sort = isset($input['select_sort']) ? $input['select_sort'] : '';
5499
5500 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">';
5501 if (!empty($input['label'])) {
5502 $more .= $input['label'] . '</div><div class="tagtd left">';
5503 }
5504 if ($input['type'] == 'select') {
5505 $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);
5506 } else {
5507 $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);
5508 }
5509 $more .= '</div></div>' . "\n";
5510 } elseif ($input['type'] == 'checkbox') {
5511 $more .= '<div class="tagtr">';
5512 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '"><label for="' . dol_escape_htmltag($input['name']) . '">' . $input['label'] . '</label></div><div class="tagtd">';
5513 $more .= '<input type="checkbox" class="flat' . ($morecss ? ' ' . $morecss : '') . '" id="' . dol_escape_htmltag($input['name']) . '" name="' . dol_escape_htmltag($input['name']) . '"' . $moreattr;
5514 if (!is_bool($input['value']) && $input['value'] != 'false' && $input['value'] != '0' && $input['value'] != '') {
5515 $more .= ' checked';
5516 }
5517 if (is_bool($input['value']) && $input['value']) {
5518 $more .= ' checked';
5519 }
5520 if (isset($input['disabled'])) {
5521 $more .= ' disabled';
5522 }
5523 $more .= ' /></div>';
5524 $more .= '</div>' . "\n";
5525 } elseif ($input['type'] == 'radio') {
5526 $i = 0;
5527 foreach ($input['values'] as $selkey => $selval) {
5528 $more .= '<div class="tagtr">';
5529 if (isset($input['label'])) {
5530 if ($i == 0) {
5531 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? ' tdtop' : (' tdtop ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5532 } else {
5533 $more .= '<div class="tagtd' . (empty($input['tdclass']) ? '' : (' "' . $input['tdclass'])) . '">&nbsp;</div>';
5534 }
5535 }
5536 $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;
5537 if (!empty($input['disabled'])) {
5538 $more .= ' disabled';
5539 }
5540 if (isset($input['default']) && $input['default'] === $selkey) {
5541 $more .= ' checked="checked"';
5542 }
5543 $more .= ' /> ';
5544 $more .= '<label for="' . dol_escape_htmltag($input['name'] . $selkey) . '" class="valignmiddle">' . $selval . '</label>';
5545 $more .= '</div></div>' . "\n";
5546 $i++;
5547 }
5548 } elseif ($input['type'] == 'date' || $input['type'] == 'datetime') {
5549 $more .= '<div class="tagtr"><div class="tagtd' . (empty($input['tdclass']) ? '' : (' ' . $input['tdclass'])) . '">' . $input['label'] . '</div>';
5550 $more .= '<div class="tagtd">';
5551 $addnowlink = (empty($input['datenow']) ? 0 : 1);
5552 $h = $m = 0;
5553 if ($input['type'] == 'datetime') {
5554 $h = isset($input['hours']) ? $input['hours'] : 1;
5555 $m = isset($input['minutes']) ? $input['minutes'] : 1;
5556 }
5557 $more .= $this->selectDate(isset($input['value']) ? $input['value'] : -1, $input['name'], $h, $m, 0, '', 1, $addnowlink);
5558 $more .= '</div></div>'."\n";
5559 $formquestion[] = array('name' => $input['name'].'day');
5560 $formquestion[] = array('name' => $input['name'].'month');
5561 $formquestion[] = array('name' => $input['name'].'year');
5562 $formquestion[] = array('name' => $input['name'].'hour');
5563 $formquestion[] = array('name' => $input['name'].'min');
5564 } elseif ($input['type'] == 'other') { // can be 1 column or 2 depending if label is set or not
5565 $more .= '<div class="tagtr"><div class="tagtd'.(empty($input['tdclass']) ? '' : (' '.$input['tdclass'])).'">';
5566 if (!empty($input['label'])) {
5567 $more .= $input['label'] . '</div><div class="tagtd">';
5568 }
5569 $more .= $input['value'];
5570 $more .= '</div></div>' . "\n";
5571 } elseif ($input['type'] == 'onecolumn') {
5572 $moreonecolumn .= '<div class="margintoponly">';
5573 $moreonecolumn .= $input['value'];
5574 $moreonecolumn .= '</div>' . "\n";
5575 } elseif ($input['type'] == 'hidden') {
5576 // Do nothing more, already added by a previous loop
5577 } elseif ($input['type'] == 'separator') {
5578 $more .= '<br>';
5579 } else {
5580 $more .= 'Error type ' . $input['type'] . ' for the confirm box is not a supported type';
5581 }
5582 }
5583 }
5584 $more .= '</div>' . "\n";
5585 $more .= $moreonecolumn;
5586 }
5587
5588 // JQUERY method dialog is broken with smartphone, we use standard HTML.
5589 // 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
5590 // See page product/card.php for example
5591 if (!empty($conf->dol_use_jmobile)) {
5592 $useajax = 0;
5593 }
5594 if (empty($conf->use_javascript_ajax)) {
5595 $useajax = 0;
5596 }
5597
5598 if ($useajax) {
5599 $autoOpen = true;
5600 $dialogconfirm = 'dialog-confirm';
5601 $button = '';
5602 if (!is_numeric($useajax)) {
5603 $button = $useajax;
5604 $useajax = 1;
5605 $autoOpen = false;
5606 $dialogconfirm .= '-' . $button;
5607 }
5608 $pageyes = $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=yes';
5609 $pageno = ($useajax == 2 ? $page . (preg_match('/\?/', $page) ? '&' : '?') . 'action=' . urlencode($action) . '&confirm=no' : '');
5610
5611 // Add input fields into list of fields to read during submit (inputok and inputko)
5612 if (is_array($formquestion)) {
5613 foreach ($formquestion as $key => $input) {
5614 //print "xx ".$key." rr ".is_array($input)."<br>\n";
5615 // Add name of fields to propagate with the GET when submitting the form with button OK.
5616 if (is_array($input) && isset($input['name'])) {
5617 if (strpos($input['name'], ',') > 0) {
5618 $inputok = array_merge($inputok, explode(',', $input['name']));
5619 } else {
5620 array_push($inputok, $input['name']);
5621 }
5622 }
5623 // Add name of fields to propagate with the GET when submitting the form with button KO.
5624 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
5625 if (is_array($input) && isset($input['inputko']) && $input['inputko'] == 1 && isset($input['name'])) {
5626 array_push($inputko, $input['name']);
5627 }
5628 }
5629 }
5630
5631 // Show JQuery confirm box.
5632 $formconfirm .= '<div id="' . $dialogconfirm . '" title="' . dol_escape_htmltag($title) . '" style="display: none;">';
5633 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5634 $formconfirm .= '<div class="confirmtext">' . $formquestion['text'] . '</div>' . "\n";
5635 }
5636 if (!empty($more)) {
5637 $formconfirm .= '<div class="confirmquestions">' . $more . '</div>' . "\n";
5638 }
5639 $formconfirm .= ($question ? '<div class="confirmmessage">' . img_help(0, '') . ' ' . $question . '</div>' : '');
5640 $formconfirm .= '</div>' . "\n";
5641
5642 $formconfirm .= "\n<!-- begin code of popup for formconfirm page=" . $page . " -->\n";
5643 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5644 $formconfirm .= "/* Code for the jQuery('#dialogforpopup').dialog() */\n";
5645 $formconfirm .= 'jQuery(document).ready(function() {
5646 $(function() {
5647 $( "#' . $dialogconfirm . '" ).dialog(
5648 {
5649 autoOpen: ' . ($autoOpen ? "true" : "false") . ',';
5650 if ($newselectedchoice == 'no') {
5651 $formconfirm .= '
5652 open: function() {
5653 $(this).parent().find("button.ui-button:eq(2)").focus();
5654 },';
5655 }
5656
5657 $jsforcursor = '';
5658 if ($useajax == 1) {
5659 $jsforcursor = '// The call to urljump can be slow, so we set the wait cursor' . "\n";
5660 $jsforcursor .= 'jQuery("html,body,#id-container").addClass("cursorwait");' . "\n";
5661 }
5662
5663 $postconfirmas = 'GET';
5664
5665 $formconfirm .= '
5666 resizable: false,
5667 height: "' . $height . '",
5668 width: "' . $width . '",
5669 modal: true,
5670 closeOnEscape: false,
5671 buttons: {
5672 "' . dol_escape_js($langs->transnoentities($labelbuttonyes)) . '": function() {
5673 var options = "token=' . urlencode(newToken()) . '";
5674 var inputok = ' . json_encode($inputok) . '; /* List of fields into form */
5675 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5676 var pageyes = "' . dol_escape_js(!empty($pageyes) ? $pageyes : '') . '";
5677
5678 if (inputok.length > 0) {
5679 $.each(inputok, function(i, inputname) {
5680 var more = "";
5681 var inputvalue;
5682 if ($("input[name=\'" + inputname + "\']").attr("type") == "radio") {
5683 inputvalue = $("input[name=\'" + inputname + "\']:checked").val();
5684 } else {
5685 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5686 inputvalue = $("#" + inputname + more).val();
5687 }
5688 if (typeof inputvalue == "undefined") { inputvalue=""; }
5689 console.log("formconfirm check inputname="+inputname+" inputvalue="+inputvalue);
5690 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5691 });
5692 }
5693 var urljump = pageyes + (pageyes.indexOf("?") < 0 ? "?" : "&") + options;
5694 if (pageyes.length > 0) {';
5695 if ($postconfirmas == 'GET') {
5696 $formconfirm .= 'location.href = urljump;';
5697 } else {
5698 $formconfirm .= $jsforcursor;
5699 $formconfirm .= 'var post = $.post(
5700 pageyes,
5701 options,
5702 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5703 );';
5704 }
5705 $formconfirm .= '
5706 console.log("after post ok");
5707 }
5708 $(this).dialog("close");
5709 },
5710 "' . dol_escape_js($langs->transnoentities($labelbuttonno)) . '": function() {
5711 var options = "token=' . urlencode(newToken()) . '";
5712 var inputko = ' . json_encode($inputko) . '; /* List of fields into form */
5713 var page = "' . dol_escape_js(!empty($page) ? $page : '') . '";
5714 var pageno="' . dol_escape_js(!empty($pageno) ? $pageno : '') . '";
5715 if (inputko.length > 0) {
5716 $.each(inputko, function(i, inputname) {
5717 var more = "";
5718 if ($("#" + inputname).attr("type") == "checkbox") { more = ":checked"; }
5719 var inputvalue = $("#" + inputname + more).val();
5720 if (typeof inputvalue == "undefined") { inputvalue=""; }
5721 options += "&" + inputname + "=" + encodeURIComponent(inputvalue);
5722 });
5723 }
5724 var urljump=pageno + (pageno.indexOf("?") < 0 ? "?" : "&") + options;
5725 //alert(urljump);
5726 if (pageno.length > 0) {';
5727 if ($postconfirmas == 'GET') {
5728 $formconfirm .= 'location.href = urljump;';
5729 } else {
5730 $formconfirm .= $jsforcursor;
5731 $formconfirm .= 'var post = $.post(
5732 pageno,
5733 options,
5734 function(data) { $("body").html(data); jQuery("html,body,#id-container").removeClass("cursorwait"); }
5735 );';
5736 }
5737 $formconfirm .= '
5738 console.log("after post ko");
5739 }
5740 $(this).dialog("close");
5741 }
5742 }
5743 }
5744 );
5745
5746 var button = "' . $button . '";
5747 if (button.length > 0) {
5748 $( "#" + button ).click(function() {
5749 $("#' . $dialogconfirm . '").dialog("open");
5750 });
5751 }
5752 });
5753 });
5754 </script>';
5755 $formconfirm .= "<!-- end ajax formconfirm -->\n";
5756 } else {
5757 $formconfirm .= "\n<!-- begin formconfirm page=" . dol_escape_htmltag($page) . " -->\n";
5758
5759 if (empty($disableformtag)) {
5760 $formconfirm .= '<form method="POST" action="' . $page . '" class="notoptoleftroright">' . "\n";
5761 }
5762
5763 $formconfirm .= '<input type="hidden" name="action" value="' . $action . '">' . "\n";
5764 $formconfirm .= '<input type="hidden" name="token" value="' . newToken() . '">' . "\n";
5765
5766 $formconfirm .= '<table class="valid centpercent">' . "\n";
5767
5768 // Line title
5769 $formconfirm .= '<tr class="validtitre"><td class="validtitre" colspan="2">';
5770 $formconfirm .= img_picto('', 'pictoconfirm') . ' ' . $title;
5771 $formconfirm .= '</td></tr>' . "\n";
5772
5773 // Line text
5774 if (is_array($formquestion) && array_key_exists('text', $formquestion) && !empty($formquestion['text'])) {
5775 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . $formquestion['text'] . '</td></tr>' . "\n";
5776 }
5777
5778 // Line form fields
5779 if ($more) {
5780 $formconfirm .= '<tr class="valid"><td class="valid" colspan="2">' . "\n";
5781 $formconfirm .= $more;
5782 $formconfirm .= '</td></tr>' . "\n";
5783 }
5784
5785 // Line with question
5786 $formconfirm .= '<tr class="valid">';
5787 $formconfirm .= '<td class="valid">' . $question . '</td>';
5788 $formconfirm .= '<td class="valid center">';
5789 $formconfirm .= $this->selectyesno("confirm", $newselectedchoice, 0, false, 0, 0, 'marginleftonly marginrightonly', $labelbuttonyes, $labelbuttonno);
5790 $formconfirm .= '<input class="button valignmiddle confirmvalidatebutton small" type="submit" value="' . $langs->trans("Validate") . '">';
5791 $formconfirm .= '</td>';
5792 $formconfirm .= '</tr>' . "\n";
5793
5794 $formconfirm .= '</table>' . "\n";
5795
5796 if (empty($disableformtag)) {
5797 $formconfirm .= "</form>\n";
5798 }
5799 $formconfirm .= '<br>';
5800
5801 if (!empty($conf->use_javascript_ajax)) {
5802 $formconfirm .= '<!-- code to disable button to avoid double clic -->';
5803 $formconfirm .= '<script nonce="' . getNonce() . '" type="text/javascript">' . "\n";
5804 $formconfirm .= '
5805 $(document).ready(function () {
5806 $(".confirmvalidatebutton").on("click", function() {
5807 console.log("We click on button confirmvalidatebutton");
5808 $(this).attr("disabled", "disabled");
5809 setTimeout(\'$(".confirmvalidatebutton").removeAttr("disabled")\', 3000);
5810 //console.log($(this).closest("form"));
5811 $(this).closest("form").submit();
5812 });
5813 });
5814 ';
5815 $formconfirm .= '</script>' . "\n";
5816 }
5817
5818 $formconfirm .= "<!-- end formconfirm -->\n";
5819 }
5820
5821 return $formconfirm;
5822 }
5823
5824
5825 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5826
5842 public function form_project($page, $socid, $selected = '', $htmlname = 'projectid', $discard_closed = 0, $maxlength = 20, $forcefocus = 0, $nooutput = 0, $textifnoproject = '', $morecss = '')
5843 {
5844 // phpcs:enable
5845 global $langs;
5846
5847 require_once DOL_DOCUMENT_ROOT . '/core/lib/project.lib.php';
5848 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
5849
5850 $out = '';
5851
5852 $formproject = new FormProjets($this->db);
5853
5854 $langs->load("project");
5855 if ($htmlname != "none") {
5856 $out .= '<form method="post" action="' . $page . '">';
5857 $out .= '<input type="hidden" name="action" value="classin">';
5858 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5859 $out .= $formproject->select_projects($socid, $selected, $htmlname, $maxlength, 0, 1, $discard_closed, $forcefocus, 0, 0, '', 1, 0, $morecss);
5860 $out .= '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5861 $out .= '</form>';
5862 } else {
5863 $out .= '<span class="project_head_block">';
5864 if ($selected) {
5865 $projet = new Project($this->db);
5866 $projet->fetch($selected);
5867 $out .= $projet->getNomUrl(0, '', 1);
5868 } else {
5869 $out .= '<span class="opacitymedium">' . $textifnoproject . '</span>';
5870 }
5871 $out .= '</span>';
5872 }
5873
5874 if (empty($nooutput)) {
5875 print $out;
5876 return '';
5877 }
5878 return $out;
5879 }
5880
5881 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5882
5898 public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $type = '', $filtertype = -1, $deposit_percent = -1, $nooutput = 0)
5899 {
5900 // phpcs:enable
5901 global $langs;
5902
5903 $out = '';
5904
5905 if ($htmlname != "none") {
5906 $out .= '<form method="POST" action="' . $page . '">';
5907 $out .= '<input type="hidden" name="action" value="setconditions">';
5908 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
5909 if ($type) {
5910 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
5911 }
5912 $out .= $this->getSelectConditionsPaiements($selected, $htmlname, $filtertype, $addempty, 0, '', $deposit_percent);
5913 $out .= '<input type="submit" class="button valignmiddle smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5914 $out .= '</form>';
5915 } else {
5916 if ($selected) {
5918 if (isset($this->cache_conditions_paiements[$selected])) {
5919 $label = $this->cache_conditions_paiements[$selected]['label'];
5920
5921 if (!empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) {
5922 $label = str_replace('__DEPOSIT_PERCENT__', $deposit_percent > 0 ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent'], $label);
5923 }
5924
5925 $out .= $label;
5926 } else {
5927 $langs->load('errors');
5928 $out .= $langs->trans('ErrorNotInDictionaryPaymentConditions');
5929 }
5930 } else {
5931 $out .= '&nbsp;';
5932 }
5933 }
5934
5935 if (empty($nooutput)) {
5936 print $out;
5937 return '';
5938 }
5939 return $out;
5940 }
5941
5942 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
5943
5953 public function form_availability($page, $selected = '', $htmlname = 'availability', $addempty = 0)
5954 {
5955 // phpcs:enable
5956 global $langs;
5957 if ($htmlname != "none") {
5958 print '<form method="post" action="' . $page . '">';
5959 print '<input type="hidden" name="action" value="setavailability">';
5960 print '<input type="hidden" name="token" value="' . newToken() . '">';
5961 $this->selectAvailabilityDelay($selected, $htmlname, -1, $addempty);
5962 print '<input type="submit" name="modify" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5963 print '<input type="submit" name="cancel" class="button smallpaddingimp" value="' . $langs->trans("Cancel") . '">';
5964 print '</form>';
5965 } else {
5966 if ($selected) {
5967 $this->load_cache_availability();
5968 print $this->cache_availability[$selected]['label'];
5969 } else {
5970 print "&nbsp;";
5971 }
5972 }
5973 }
5974
5985 public function formInputReason($page, $selected = '', $htmlname = 'demandreason', $addempty = 0)
5986 {
5987 global $langs;
5988 if ($htmlname != "none") {
5989 print '<form method="post" action="' . $page . '">';
5990 print '<input type="hidden" name="action" value="setdemandreason">';
5991 print '<input type="hidden" name="token" value="' . newToken() . '">';
5992 $this->selectInputReason($selected, $htmlname, -1, $addempty);
5993 print '<input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '">';
5994 print '</form>';
5995 } else {
5996 if ($selected) {
5997 $this->loadCacheInputReason();
5998 foreach ($this->cache_demand_reason as $key => $val) {
5999 if ($val['id'] == $selected) {
6000 print $val['label'];
6001 break;
6002 }
6003 }
6004 } else {
6005 print "&nbsp;";
6006 }
6007 }
6008 }
6009
6010 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6011
6025 public function form_date($page, $selected, $htmlname, $displayhour = 0, $displaymin = 0, $nooutput = 0, $type = '')
6026 {
6027 // phpcs:enable
6028 global $langs;
6029
6030 $ret = '';
6031
6032 if ($htmlname != "none") {
6033 $ret .= '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6034 $ret .= '<input type="hidden" name="action" value="set' . $htmlname . '">';
6035 $ret .= '<input type="hidden" name="token" value="' . newToken() . '">';
6036 if ($type) {
6037 $ret .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6038 }
6039 $ret .= '<table class="nobordernopadding">';
6040 $ret .= '<tr><td>';
6041 $ret .= $this->selectDate($selected, $htmlname, $displayhour, $displaymin, 1, 'form' . $htmlname, 1, 0);
6042 $ret .= '</td>';
6043 $ret .= '<td class="left"><input type="submit" class="button smallpaddingimp" value="' . $langs->trans("Modify") . '"></td>';
6044 $ret .= '</tr></table></form>';
6045 } else {
6046 if ($displayhour) {
6047 $ret .= dol_print_date($selected, 'dayhour');
6048 } else {
6049 $ret .= dol_print_date($selected, 'day');
6050 }
6051 }
6052
6053 if (empty($nooutput)) {
6054 print $ret;
6055 }
6056 return $ret;
6057 }
6058
6059
6060 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6061
6072 public function form_users($page, $selected = '', $htmlname = 'userid', $exclude = array(), $include = array())
6073 {
6074 // phpcs:enable
6075 global $langs;
6076
6077 if ($htmlname != "none") {
6078 print '<form method="POST" action="' . $page . '" name="form' . $htmlname . '">';
6079 print '<input type="hidden" name="action" value="set' . $htmlname . '">';
6080 print '<input type="hidden" name="token" value="' . newToken() . '">';
6081 print $this->select_dolusers($selected, $htmlname, 1, $exclude, 0, $include);
6082 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6083 print '</form>';
6084 } else {
6085 if ($selected) {
6086 require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
6087 $theuser = new User($this->db);
6088 $theuser->fetch($selected);
6089 print $theuser->getNomUrl(1);
6090 } else {
6091 print "&nbsp;";
6092 }
6093 }
6094 }
6095
6096
6097 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6098
6112 public function form_modes_reglement($page, $selected = '', $htmlname = 'mode_reglement_id', $filtertype = '', $active = 1, $addempty = 0, $type = '', $nooutput = 0)
6113 {
6114 // phpcs:enable
6115 global $langs;
6116
6117 $out = '';
6118 if ($htmlname != "none") {
6119 $out .= '<form method="POST" action="' . $page . '">';
6120 $out .= '<input type="hidden" name="action" value="setmode">';
6121 $out .= '<input type="hidden" name="token" value="' . newToken() . '">';
6122 if ($type) {
6123 $out .= '<input type="hidden" name="type" value="' . dol_escape_htmltag($type) . '">';
6124 }
6125 $out .= $this->select_types_paiements($selected, $htmlname, $filtertype, 0, $addempty, 0, 0, $active, '', 1);
6126 $out .= '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6127 $out .= '</form>';
6128 } else {
6129 if ($selected) {
6131 $out .= $this->cache_types_paiements[$selected]['label'];
6132 } else {
6133 $out .= "&nbsp;";
6134 }
6135 }
6136
6137 if ($nooutput) {
6138 return $out;
6139 } else {
6140 print $out;
6141 }
6142 return '';
6143 }
6144
6155 public function formSelectTransportMode($page, $selected = '', $htmlname = 'transport_mode_id', $active = 1, $addempty = 0)
6156 {
6157 global $langs;
6158 if ($htmlname != "none") {
6159 print '<form method="POST" action="' . $page . '">';
6160 print '<input type="hidden" name="action" value="settransportmode">';
6161 print '<input type="hidden" name="token" value="' . newToken() . '">';
6162 $this->selectTransportMode($selected, $htmlname, 0, $addempty, 0, 0, $active);
6163 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6164 print '</form>';
6165 } else {
6166 if ($selected) {
6168 print $this->cache_transport_mode[$selected]['label'];
6169 } else {
6170 print "&nbsp;";
6171 }
6172 }
6173 }
6174
6175 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6176
6185 public function form_multicurrency_code($page, $selected = '', $htmlname = 'multicurrency_code')
6186 {
6187 // phpcs:enable
6188 global $langs;
6189 if ($htmlname != "none") {
6190 print '<form method="POST" action="' . $page . '">';
6191 print '<input type="hidden" name="action" value="setmulticurrencycode">';
6192 print '<input type="hidden" name="token" value="' . newToken() . '">';
6193 print $this->selectMultiCurrency($selected, $htmlname, 0);
6194 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6195 print '</form>';
6196 } else {
6197 require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
6198 print !empty($selected) ? currency_name($selected, 1) : '&nbsp;';
6199 }
6200 }
6201
6202 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6203
6213 public function form_multicurrency_rate($page, $rate = 0.0, $htmlname = 'multicurrency_tx', $currency = '')
6214 {
6215 // phpcs:enable
6216 global $langs, $mysoc, $conf;
6217
6218 if ($htmlname != "none") {
6219 print '<form method="POST" action="' . $page . '">';
6220 print '<input type="hidden" name="action" value="setmulticurrencyrate">';
6221 print '<input type="hidden" name="token" value="' . newToken() . '">';
6222 print '<input type="text" class="maxwidth100" name="' . $htmlname . '" value="' . (!empty($rate) ? price(price2num($rate, 'CU')) : 1) . '" /> ';
6223 print '<select name="calculation_mode">';
6224 print '<option value="1">Change ' . $langs->trans("PriceUHT") . ' of lines</option>';
6225 print '<option value="2">Change ' . $langs->trans("PriceUHTCurrency") . ' of lines</option>';
6226 print '</select> ';
6227 print '<input type="submit" class="button smallpaddingimp valignmiddle" value="' . $langs->trans("Modify") . '">';
6228 print '</form>';
6229 } else {
6230 if (!empty($rate)) {
6231 print price($rate, 1, $langs, 0, 0);
6232 if ($currency && $rate != 1) {
6233 print ' &nbsp; (' . price($rate, 1, $langs, 0, 0) . ' ' . $currency . ' = 1 ' . $conf->currency . ')';
6234 }
6235 } else {
6236 print 1;
6237 }
6238 }
6239 }
6240
6241
6242 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
6243
6259 public function form_remise_dispo($page, $selected, $htmlname, $socid, $amount, $filter = '', $maxvalue = 0, $more = '', $hidelist = 0, $discount_type = 0)
6260 {
6261 // phpcs:enable
6262 global $conf, $langs;
6263 if ($htmlname != "none") {
6264 print '<form method="post" action="' . $page . '">';
6265 print '<input type="hidden" name="action" value="setabsolutediscount">';
6266 print '<input type="hidden" name="token" value="' . newToken() . '">';
6267 print '<div class="inline-block">';
6268 if (!empty($discount_type)) {
6269 if (getDolGlobalString('FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS')) {
6270 if (!$filter || $filter == "fk_invoice_supplier_source IS NULL") {
6271 $translationKey = 'HasAbsoluteDiscountFromSupplier'; // If we want deposit to be subtracted to payments only and not to total of final invoice
6272 } else {
6273 $translationK